mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-13 01:28:40 +00:00
Track provenance of native ints (#14)
This commit is contained in:
@@ -462,7 +462,12 @@ module IlMachineState =
|
||||
else
|
||||
let args = ImmutableArray.CreateBuilder (methodToCall.Parameters.Length + 1)
|
||||
let poppedArg, afterPop = threadState.MethodState |> MethodState.popFromStack
|
||||
args.Add (EvalStackValue.toCliTypeCoerced (CliType.ObjectRef None) poppedArg)
|
||||
// it only matters that the RuntimePointer is a RuntimePointer, so that the coercion has a target of the
|
||||
// right shape
|
||||
args.Add (
|
||||
EvalStackValue.toCliTypeCoerced (CliType.RuntimePointer (CliRuntimePointer.Unmanaged ())) poppedArg
|
||||
)
|
||||
|
||||
let mutable afterPop = afterPop
|
||||
|
||||
for i = 1 to methodToCall.Parameters.Length do
|
||||
@@ -1106,8 +1111,7 @@ module AbstractMachine =
|
||||
failwith "TODO: Clt NativeInt vs Int32 comparison unimplemented"
|
||||
| other, EvalStackValue.Int32 var2 -> failwith $"invalid comparison, {other} vs int32 {var2}"
|
||||
| EvalStackValue.NativeInt var1, EvalStackValue.NativeInt var2 -> if var1 < var2 then 1 else 0
|
||||
| EvalStackValue.NativeInt var1, other ->
|
||||
failwith $"invalid comparison, nativeint %i{var1} vs %O{other}"
|
||||
| EvalStackValue.NativeInt var1, other -> failwith $"invalid comparison, nativeint {var1} vs %O{other}"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource, NativeInt int64 ->
|
||||
failwith "TODO: Clt ManagedPointer vs NativeInt comparison unimplemented"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource, ManagedPointer pointerSource ->
|
||||
@@ -1221,10 +1225,12 @@ module AbstractMachine =
|
||||
| Some conv ->
|
||||
// > If overflow occurs when converting one integer type to another, the high-order bits are silently truncated.
|
||||
let conv =
|
||||
if conv > uint64 System.Int64.MaxValue then
|
||||
(conv % uint64 System.Int64.MaxValue) |> int64
|
||||
else
|
||||
int64 conv
|
||||
match conv with
|
||||
| UnsignedNativeIntSource.Verbatim conv ->
|
||||
if conv > uint64 System.Int64.MaxValue then
|
||||
(conv % uint64 System.Int64.MaxValue) |> int64 |> NativeIntSource.Verbatim
|
||||
else
|
||||
int64 conv |> NativeIntSource.Verbatim
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' (EvalStackValue.NativeInt conv) currentThread
|
||||
@@ -1520,7 +1526,8 @@ module AbstractMachine =
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer source ->
|
||||
match source with
|
||||
| ManagedPointerSource.LocalVariable -> failwith "TODO: Stsfld LocalVariable storage unimplemented"
|
||||
| ManagedPointerSource.LocalVariable _ ->
|
||||
failwith "TODO: Stsfld LocalVariable storage unimplemented"
|
||||
| ManagedPointerSource.Heap addr -> CliType.ObjectRef (Some addr)
|
||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||
| _ -> failwith "TODO: Stsfld non-managed pointer storage unimplemented"
|
||||
@@ -1706,7 +1713,7 @@ module AbstractMachine =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i <> 0
|
||||
| EvalStackValue.Int64 i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i)
|
||||
| EvalStackValue.Float f -> failwith "TODO: Brtrue_s float semantics undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
|
||||
| EvalStackValue.ManagedPointer _ -> true
|
||||
@@ -1728,7 +1735,7 @@ module AbstractMachine =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i = 0
|
||||
| EvalStackValue.Int64 i -> i = 0L
|
||||
| EvalStackValue.NativeInt i -> i = 0L
|
||||
| EvalStackValue.NativeInt i -> NativeIntSource.isZero i
|
||||
| EvalStackValue.Float f -> failwith "TODO: Brfalse float semantics undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> true
|
||||
| EvalStackValue.ManagedPointer _ -> false
|
||||
@@ -1750,7 +1757,7 @@ module AbstractMachine =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i <> 0
|
||||
| EvalStackValue.Int64 i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i)
|
||||
| EvalStackValue.Float f -> failwith "TODO: Brtrue float semantics undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
|
||||
| EvalStackValue.ManagedPointer _ -> true
|
||||
@@ -1790,7 +1797,7 @@ module AbstractMachine =
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack'
|
||||
(EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable))
|
||||
(EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable ((), uint16<uint8> b)))
|
||||
currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
|
@@ -325,6 +325,7 @@ module Assembly =
|
||||
builder.Add (
|
||||
c,
|
||||
MemberReference.make<MetadataToken>
|
||||
metadataReader.GetBlobReader
|
||||
metadataReader.GetString
|
||||
MetadataToken.ofEntityHandle
|
||||
(metadataReader.GetMemberReference c)
|
||||
|
@@ -59,9 +59,12 @@ type CliValueType =
|
||||
| Float32 of float32
|
||||
| Float64 of float
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type CliRuntimePointerSource = | LocalVariable of source : unit * whichVar : uint16
|
||||
|
||||
type CliRuntimePointer =
|
||||
| Unmanaged of unit
|
||||
| Managed of unit
|
||||
| Managed of CliRuntimePointerSource
|
||||
|
||||
/// This is the kind of type that can be stored in arguments, local variables, statics, array elements, fields.
|
||||
type CliType =
|
||||
|
@@ -3,15 +3,31 @@ namespace WoofWare.PawPrint
|
||||
open Microsoft.FSharp.Core
|
||||
|
||||
type ManagedPointerSource =
|
||||
| LocalVariable
|
||||
| LocalVariable of source : unit * whichVar : uint16
|
||||
| Heap of ManagedHeapAddress
|
||||
| Null
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type NativeIntSource = | Verbatim of int64
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module NativeIntSource =
|
||||
let isZero (n : NativeIntSource) : bool =
|
||||
match n with
|
||||
| NativeIntSource.Verbatim i -> i = 0L
|
||||
|
||||
let isNonnegative (n : NativeIntSource) : bool =
|
||||
match n with
|
||||
| NativeIntSource.Verbatim i -> i >= 0L
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type UnsignedNativeIntSource = | Verbatim of uint64
|
||||
|
||||
/// See I.12.3.2.1 for definition
|
||||
type EvalStackValue =
|
||||
| Int32 of int32
|
||||
| Int64 of int64
|
||||
| NativeInt of int64
|
||||
| NativeInt of NativeIntSource
|
||||
| Float of float
|
||||
| ManagedPointer of ManagedPointerSource
|
||||
| ObjectRef of ManagedHeapAddress
|
||||
@@ -22,17 +38,27 @@ type EvalStackValue =
|
||||
[<RequireQualifiedAccess>]
|
||||
module EvalStackValue =
|
||||
/// The conversion performed by Conv_u.
|
||||
let toUnsignedNativeInt (value : EvalStackValue) : uint64 option =
|
||||
let toUnsignedNativeInt (value : EvalStackValue) : UnsignedNativeIntSource option =
|
||||
// Table III.8
|
||||
match value with
|
||||
| EvalStackValue.Int32 i ->
|
||||
if i >= 0 then
|
||||
Some (uint64 i)
|
||||
Some (uint64 i |> UnsignedNativeIntSource.Verbatim)
|
||||
else
|
||||
// Zero-extend.
|
||||
failwith "todo"
|
||||
| EvalStackValue.Int64 i -> if i >= 0L then Some (uint64 i) else failwith "todo"
|
||||
| EvalStackValue.NativeInt i -> if i >= 0L then Some (uint64 i) else failwith "todo"
|
||||
| EvalStackValue.Int64 i ->
|
||||
if i >= 0L then
|
||||
Some (uint64 i |> UnsignedNativeIntSource.Verbatim)
|
||||
else
|
||||
failwith "todo"
|
||||
| EvalStackValue.NativeInt i ->
|
||||
match i with
|
||||
| NativeIntSource.Verbatim i ->
|
||||
if i >= 0L then
|
||||
uint64 i |> UnsignedNativeIntSource.Verbatim |> Some
|
||||
else
|
||||
failwith "todo"
|
||||
| EvalStackValue.Float f -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||
@@ -62,10 +88,14 @@ module EvalStackValue =
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer ptrSource ->
|
||||
match ptrSource with
|
||||
| ManagedPointerSource.LocalVariable ->
|
||||
| ManagedPointerSource.LocalVariable _ ->
|
||||
failwith "TODO: trying to fit a local variable address into an ObjectRef"
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> CliType.ObjectRef (Some managedHeapAddress)
|
||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||
| EvalStackValue.NativeInt nativeIntSource ->
|
||||
match nativeIntSource with
|
||||
| NativeIntSource.Verbatim 0L -> CliType.ObjectRef None
|
||||
| NativeIntSource.Verbatim i -> failwith $"refusing to interpret verbatim native int {i} as a pointer"
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliType.Bool _ ->
|
||||
match popped with
|
||||
@@ -75,7 +105,18 @@ module EvalStackValue =
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
failwith $"unexpectedly tried to convert a managed pointer (%O{src}) into a bool"
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliType.RuntimePointer _ ->
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
match src with
|
||||
| ManagedPointerSource.Heap addr -> CliType.OfManagedObject addr
|
||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||
| ManagedPointerSource.LocalVariable (source, var) ->
|
||||
CliType.RuntimePointer (
|
||||
CliRuntimePointer.Managed (CliRuntimePointerSource.LocalVariable (source, var))
|
||||
)
|
||||
| _ -> failwith $"TODO: %O{popped}"
|
||||
| CliType.Char _ -> failwith "TODO: char"
|
||||
|
||||
type EvalStack =
|
||||
{
|
||||
@@ -129,6 +170,12 @@ type EvalStack =
|
||||
// Zero-extend bool/char
|
||||
| CliType.Bool b -> int32 b |> EvalStackValue.Int32
|
||||
| CliType.Char (high, low) -> int32 high * 256 + int32 low |> EvalStackValue.Int32
|
||||
| CliType.RuntimePointer cliRuntimePointer -> failwith "todo"
|
||||
| CliType.RuntimePointer ptr ->
|
||||
match ptr with
|
||||
| CliRuntimePointer.Unmanaged () -> failwith "todo: unmanaged"
|
||||
| CliRuntimePointer.Managed ptr ->
|
||||
match ptr with
|
||||
| CliRuntimePointerSource.LocalVariable (source, var) ->
|
||||
EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable (source, var))
|
||||
|
||||
EvalStack.Push' v stack
|
||||
|
@@ -47,6 +47,7 @@ type MemberRefSigSwitch =
|
||||
[<RequireQualifiedAccess>]
|
||||
module MemberReference =
|
||||
let make<'parent>
|
||||
(blobReader : BlobHandle -> BlobReader)
|
||||
(getString : StringHandle -> string)
|
||||
(makeParent : EntityHandle -> 'parent)
|
||||
(mr : System.Reflection.Metadata.MemberReference)
|
||||
@@ -54,11 +55,17 @@ module MemberReference =
|
||||
=
|
||||
let name = StringToken.String mr.Name
|
||||
|
||||
let br = blobReader mr.Signature
|
||||
let header = br.ReadSignatureHeader ()
|
||||
|
||||
let signature =
|
||||
try
|
||||
mr.DecodeMethodSignature (TypeDefn.typeProvider, ()) |> Choice1Of2
|
||||
with :? BadImageFormatException ->
|
||||
mr.DecodeFieldSignature (TypeDefn.typeProvider, ()) |> Choice2Of2
|
||||
match header.Kind with
|
||||
| SignatureKind.Method -> mr.DecodeMethodSignature (TypeDefn.typeProvider, ()) |> Choice1Of2
|
||||
| SignatureKind.Field -> mr.DecodeFieldSignature (TypeDefn.typeProvider, ()) |> Choice2Of2
|
||||
| SignatureKind.LocalVariables -> failwith "TODO: LocalVariables"
|
||||
| SignatureKind.Property -> failwith "TODO: Property"
|
||||
| SignatureKind.MethodSpecification -> failwith "TODO: MethodSpec"
|
||||
| i -> raise (ArgumentOutOfRangeException $"{i}")
|
||||
|
||||
let signature =
|
||||
match signature with
|
||||
|
@@ -2,7 +2,6 @@ namespace WoofWare.PawPrint
|
||||
|
||||
#nowarn "9"
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open System.Reflection
|
||||
open System.Reflection.Metadata
|
||||
@@ -34,17 +33,22 @@ type Parameter =
|
||||
[<RequireQualifiedAccess>]
|
||||
module Parameter =
|
||||
let readAll (metadata : MetadataReader) (param : ParameterHandleCollection) : Parameter ImmutableArray =
|
||||
param
|
||||
|> Seq.map (fun param ->
|
||||
let result = ImmutableArray.CreateBuilder ()
|
||||
|
||||
for param in param do
|
||||
let param = metadata.GetParameter param
|
||||
|
||||
{
|
||||
Name = metadata.GetString param.Name
|
||||
DefaultValue = metadata.GetConstant (param.GetDefaultValue ())
|
||||
SequenceNumber = param.SequenceNumber
|
||||
}
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
// The spec doesn't seem to mention this behaviour, but a sequence number of 0 (and an unnamed parameter)
|
||||
// seems to correspond with a ref return.
|
||||
if param.SequenceNumber <> 0 then
|
||||
{
|
||||
Name = metadata.GetString param.Name
|
||||
DefaultValue = metadata.GetConstant (param.GetDefaultValue ())
|
||||
SequenceNumber = param.SequenceNumber
|
||||
}
|
||||
|> result.Add
|
||||
|
||||
result.ToImmutable ()
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic type or method parameter definition.
|
||||
@@ -187,13 +191,12 @@ module MethodInfo =
|
||||
let methodBody = peReader.GetMethodBody methodDef.RelativeVirtualAddress
|
||||
|
||||
let localSig =
|
||||
let s = methodBody.LocalSignature |> metadataReader.GetStandaloneSignature
|
||||
// :sob: why are all the useful methods internal
|
||||
try
|
||||
s.Signature |> ignore<BlobHandle> |> Some
|
||||
with :? BadImageFormatException ->
|
||||
if methodBody.LocalSignature.IsNil then
|
||||
None
|
||||
|> Option.map (fun () -> s.DecodeLocalSignature (TypeDefn.typeProvider, ()))
|
||||
else
|
||||
|
||||
let s = methodBody.LocalSignature |> metadataReader.GetStandaloneSignature
|
||||
s.DecodeLocalSignature (TypeDefn.typeProvider, ()) |> Some
|
||||
|
||||
let ilBytes = methodBody.GetILBytes ()
|
||||
use bytes = fixed ilBytes
|
||||
@@ -505,6 +508,8 @@ module MethodInfo =
|
||||
None
|
||||
| Some methodBody ->
|
||||
|
||||
let typeSig = TypeMethodSignature.make methodSig
|
||||
|
||||
let methodParams = Parameter.readAll metadataReader (methodDef.GetParameters ())
|
||||
|
||||
let methodGenericParams =
|
||||
@@ -518,7 +523,7 @@ module MethodInfo =
|
||||
Locations = methodBody.Instructions |> List.map (fun (a, b) -> b, a) |> Map.ofList
|
||||
Parameters = methodParams
|
||||
Generics = methodGenericParams
|
||||
Signature = TypeMethodSignature.make methodSig
|
||||
Signature = typeSig
|
||||
IsPinvokeImpl = methodDef.Attributes.HasFlag MethodAttributes.PinvokeImpl
|
||||
LocalsInit = methodBody.LocalInit
|
||||
LocalVars = methodBody.LocalSig
|
||||
|
Reference in New Issue
Block a user