mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-11 00:38:40 +00:00
Add hook for non-IL methods (#15)
This commit is contained in:
@@ -51,7 +51,9 @@ and MethodState =
|
||||
}
|
||||
|
||||
static member advanceProgramCounter (state : MethodState) =
|
||||
MethodState.jumpProgramCounter (IlOp.NumberOfBytes state.ExecutingMethod.Locations.[state.IlOpIndex]) state
|
||||
MethodState.jumpProgramCounter
|
||||
(IlOp.NumberOfBytes state.ExecutingMethod.Instructions.Value.Locations.[state.IlOpIndex])
|
||||
state
|
||||
|
||||
static member peekEvalStack (state : MethodState) : EvalStackValue option = EvalStack.Peek state.EvaluationStack
|
||||
|
||||
@@ -132,14 +134,21 @@ and MethodState =
|
||||
$"Non-static method {method.Name} should have had %i{method.Parameters.Length + 1} parameters, but was given %i{args.Length}"
|
||||
|
||||
let localVariableSig =
|
||||
match method.LocalVars with
|
||||
match method.Instructions with
|
||||
| None -> ImmutableArray.Empty
|
||||
| Some vars -> vars
|
||||
| Some method ->
|
||||
match method.LocalVars with
|
||||
| None -> ImmutableArray.Empty
|
||||
| Some vars -> vars
|
||||
// I think valid code should remain valid if we unconditionally localsInit - it should be undefined
|
||||
// to use an uninitialised value? Not checked this; TODO.
|
||||
let localVars =
|
||||
localVariableSig |> Seq.map CliType.zeroOf |> ImmutableArray.CreateRange
|
||||
|
||||
do
|
||||
let args = args |> Seq.map string<CliType> |> String.concat " ; "
|
||||
System.Console.Error.WriteLine $"Setting args list in {method.Name}: {args}"
|
||||
|
||||
{
|
||||
EvaluationStack = EvalStack.Empty
|
||||
LocalVariables = localVars
|
||||
@@ -518,6 +527,8 @@ module IlMachineState =
|
||||
afterPop <- afterPop'
|
||||
args.Add poppedArg
|
||||
|
||||
args.Reverse ()
|
||||
|
||||
let newFrame =
|
||||
MethodState.Empty
|
||||
methodToCall
|
||||
@@ -534,12 +545,6 @@ module IlMachineState =
|
||||
else
|
||||
let args = ImmutableArray.CreateBuilder (methodToCall.Parameters.Length + 1)
|
||||
let poppedArg, afterPop = activeMethodState |> MethodState.popFromStack
|
||||
// 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
|
||||
@@ -549,6 +554,14 @@ module IlMachineState =
|
||||
afterPop <- afterPop'
|
||||
args.Add 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
|
||||
)
|
||||
|
||||
args.Reverse ()
|
||||
|
||||
let newFrame =
|
||||
MethodState.Empty
|
||||
methodToCall
|
||||
@@ -1055,6 +1068,10 @@ module AbstractMachine =
|
||||
currentThread
|
||||
{ threadStateAtEndOfMethod with
|
||||
ActiveMethodState = returnState.JumpTo
|
||||
ActiveAssembly =
|
||||
snd
|
||||
threadStateAtEndOfMethod.MethodStates.[returnState.JumpTo].ExecutingMethod
|
||||
.DeclaringType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1315,7 +1332,36 @@ module AbstractMachine =
|
||||
| Ldind_i2 -> failwith "TODO: Ldind_i2 unimplemented"
|
||||
| Ldind_i4 -> failwith "TODO: Ldind_i4 unimplemented"
|
||||
| Ldind_i8 -> failwith "TODO: Ldind_i8 unimplemented"
|
||||
| Ldind_u1 -> failwith "TODO: Ldind_u1 unimplemented"
|
||||
| Ldind_u1 ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let value =
|
||||
match popped with
|
||||
| EvalStackValue.NativeInt nativeIntSource -> failwith $"TODO: in Ldind_u1, {nativeIntSource}"
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
match src with
|
||||
| ManagedPointerSource.Null -> failwith "unexpected null pointer in Ldind_u1"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
let methodState =
|
||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables
|
||||
.[int<uint16> whichVar]
|
||||
|
||||
match methodState with
|
||||
| CliType.Bool b -> b
|
||||
| CliType.Numeric numeric -> failwith $"tried to load a Numeric as a u8: {numeric}"
|
||||
| CliType.Char _ -> failwith "tried to load a Char as a u8"
|
||||
| CliType.ObjectRef _ -> failwith "tried to load an ObjectRef as a u8"
|
||||
| CliType.RuntimePointer _ -> failwith "tried to load a RuntimePointer as a u8"
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||
| popped -> failwith $"unexpected Ldind_u1 input: {popped}"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.UInt8 value)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| Ldind_u2 -> failwith "TODO: Ldind_u2 unimplemented"
|
||||
| Ldind_u4 -> failwith "TODO: Ldind_u4 unimplemented"
|
||||
| Ldind_u8 -> failwith "TODO: Ldind_u8 unimplemented"
|
||||
@@ -1467,7 +1513,12 @@ module AbstractMachine =
|
||||
| Choice2Of2 _field -> failwith "tried to Call a field"
|
||||
| Choice1Of2 method -> state, method
|
||||
|
||||
| MetadataToken.MethodDef defn -> state, (state.ActiveAssembly thread).Methods.[defn]
|
||||
| MetadataToken.MethodDef defn ->
|
||||
let activeAssy = state.ActiveAssembly thread
|
||||
|
||||
match activeAssy.Methods.TryGetValue defn with
|
||||
| true, method -> state, method
|
||||
| false, _ -> failwith $"could not find method in {activeAssy.Name}"
|
||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||
|
||||
state.WithThreadSwitchedToAssembly (snd methodToCall.DeclaringType) thread
|
||||
@@ -1645,8 +1696,12 @@ module AbstractMachine =
|
||||
| EvalStackValue.Float f -> failwith "todo: float"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource ->
|
||||
match managedPointerSource with
|
||||
| ManagedPointerSource.LocalVariable (source, whichVar) ->
|
||||
failwith $"todo: local variable {whichVar}"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
let currentValue =
|
||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables
|
||||
.[int<uint16> whichVar]
|
||||
|
||||
failwith $"todo: local variable {currentValue} {field}"
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith $"todo: heap addr {managedHeapAddress}"
|
||||
| ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException"
|
||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith $"todo: {managedHeapAddress}"
|
||||
@@ -1818,7 +1873,28 @@ module AbstractMachine =
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> IlMachineState.jumpProgramCounter currentThread (int b)
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Brfalse_s b -> failwith "TODO: Brfalse_s unimplemented"
|
||||
| Brfalse_s b ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let isTrue =
|
||||
match popped with
|
||||
| EvalStackValue.Int32 i -> i <> 0
|
||||
| EvalStackValue.Int64 i -> i <> 0L
|
||||
| EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i)
|
||||
| EvalStackValue.Float f -> failwith "TODO: Brfalse_s float semantics undocumented"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
|
||||
| EvalStackValue.ManagedPointer _ -> true
|
||||
| EvalStackValue.ObjectRef _ -> failwith "TODO: Brfalse_s ObjectRef comparison unimplemented"
|
||||
| EvalStackValue.UserDefinedValueType ->
|
||||
failwith "TODO: Brfalse_s UserDefinedValueType comparison unimplemented"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> if isTrue then
|
||||
id
|
||||
else
|
||||
IlMachineState.jumpProgramCounter currentThread (int b)
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Brtrue_s b ->
|
||||
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
@@ -1908,12 +1984,17 @@ module AbstractMachine =
|
||||
| Ldloc_s b -> failwith "TODO: Ldloc_s unimplemented"
|
||||
| Ldloca_s b ->
|
||||
let threadState = state.ThreadState.[currentThread]
|
||||
let methodState = threadState.MethodStates.[threadState.ActiveMethodState]
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack'
|
||||
(EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable ((), uint16<uint8> b)))
|
||||
(EvalStackValue.ManagedPointer (
|
||||
ManagedPointerSource.LocalVariable (
|
||||
currentThread,
|
||||
threadState.ActiveMethodState,
|
||||
uint16<uint8> b
|
||||
)
|
||||
))
|
||||
currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
@@ -1940,7 +2021,14 @@ module AbstractMachine =
|
||||
let logger = loggerFactory.CreateLogger typeof<Dummy>.DeclaringType
|
||||
let instruction = state.ThreadState.[thread].MethodState
|
||||
|
||||
match instruction.ExecutingMethod.Locations.TryGetValue instruction.IlOpIndex with
|
||||
match instruction.ExecutingMethod.Instructions with
|
||||
| None ->
|
||||
failwith
|
||||
$"TODO: tried to IL-interpret a method in {snd(instruction.ExecutingMethod.DeclaringType).Name} named {instruction.ExecutingMethod.Name} with no implementation"
|
||||
|
||||
| Some instructions ->
|
||||
|
||||
match instructions.Locations.TryGetValue instruction.IlOpIndex with
|
||||
| false, _ -> failwith "Wanted to execute a nonexistent instruction"
|
||||
| true, executingInstruction ->
|
||||
|
||||
@@ -1960,7 +2048,7 @@ module AbstractMachine =
|
||||
executingInstruction
|
||||
)
|
||||
|
||||
match instruction.ExecutingMethod.Locations.[instruction.IlOpIndex] with
|
||||
match instruction.ExecutingMethod.Instructions.Value.Locations.[instruction.IlOpIndex] with
|
||||
| IlOp.Nullary op -> executeNullary state thread op
|
||||
| IlOp.UnaryConst unaryConstIlOp -> executeUnaryConst state thread unaryConstIlOp |> ExecutionResult.Stepped
|
||||
| IlOp.UnaryMetadataToken (unaryMetadataTokenIlOp, bytes) ->
|
||||
|
@@ -402,14 +402,17 @@ module Assembly =
|
||||
|
||||
let print (main : MethodDefinitionHandle) (dumped : DumpedAssembly) : unit =
|
||||
for KeyValue (_, typ) in dumped.TypeDefs do
|
||||
printfn "\nType: %s.%s" typ.Namespace typ.Name
|
||||
Console.WriteLine $"\nType: %s{typ.Namespace}.%s{typ.Name}"
|
||||
|
||||
for method in typ.Methods do
|
||||
if method.Handle = main then
|
||||
printfn "Entry point!"
|
||||
Console.WriteLine "Entry point!"
|
||||
|
||||
printfn "\nMethod: %s" method.Name
|
||||
Console.WriteLine $"\nMethod: %s{method.Name}"
|
||||
|
||||
method.Instructions
|
||||
|> List.map (fun (op, index) -> IlOp.Format op index)
|
||||
|> List.iter Console.WriteLine
|
||||
match method.Instructions with
|
||||
| None -> Console.WriteLine "<no IL instructions>"
|
||||
| Some instructions ->
|
||||
instructions.Instructions
|
||||
|> List.map (fun (op, index) -> IlOp.Format op index)
|
||||
|> List.iter Console.WriteLine
|
||||
|
@@ -60,7 +60,7 @@ type CliValueType =
|
||||
| Float64 of float
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type CliRuntimePointerSource = | LocalVariable of source : unit * whichVar : uint16
|
||||
type CliRuntimePointerSource = | LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||
|
||||
type CliRuntimePointer =
|
||||
| Unmanaged of unit
|
||||
|
@@ -3,9 +3,7 @@ namespace WoofWare.PawPrint
|
||||
open Microsoft.FSharp.Core
|
||||
|
||||
type ManagedPointerSource =
|
||||
// TODO: need to somehow obtain a "pointer" to the dynamically-updating contents of that stack frame.
|
||||
// Perhaps we should store it as a list of historical values?
|
||||
| LocalVariable of source : unit * whichVar : uint16
|
||||
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||
| Heap of ManagedHeapAddress
|
||||
| Null
|
||||
|
||||
@@ -90,8 +88,13 @@ module EvalStackValue =
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer ptrSource ->
|
||||
match ptrSource with
|
||||
| ManagedPointerSource.LocalVariable _ ->
|
||||
failwith "TODO: trying to fit a local variable address into an ObjectRef"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
CliType.RuntimePointer (
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, whichVar)
|
||||
)
|
||||
)
|
||||
// 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 ->
|
||||
@@ -113,9 +116,11 @@ module EvalStackValue =
|
||||
match src with
|
||||
| ManagedPointerSource.Heap addr -> CliType.OfManagedObject addr
|
||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||
| ManagedPointerSource.LocalVariable (source, var) ->
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, var) ->
|
||||
CliType.RuntimePointer (
|
||||
CliRuntimePointer.Managed (CliRuntimePointerSource.LocalVariable (source, var))
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var)
|
||||
)
|
||||
)
|
||||
| _ -> failwith $"TODO: %O{popped}"
|
||||
| CliType.Char _ -> failwith "TODO: char"
|
||||
@@ -131,7 +136,7 @@ type EvalStack =
|
||||
}
|
||||
|
||||
static member Pop (stack : EvalStack) : EvalStackValue * EvalStack =
|
||||
eprintfn $"Popping value from stack"
|
||||
System.Console.Error.WriteLine "Popping value from stack"
|
||||
|
||||
match stack.Values with
|
||||
| [] -> failwith "eval stack was empty on pop instruction"
|
||||
@@ -146,7 +151,7 @@ type EvalStack =
|
||||
static member Peek (stack : EvalStack) : EvalStackValue option = stack.Values |> List.tryHead
|
||||
|
||||
static member Push' (v : EvalStackValue) (stack : EvalStack) : EvalStack =
|
||||
eprintfn $"Pushing value {v} to stack"
|
||||
System.Console.Error.WriteLine $"Pushing value {v} to stack"
|
||||
|
||||
{
|
||||
Values = v :: stack.Values
|
||||
@@ -181,7 +186,9 @@ type EvalStack =
|
||||
| CliRuntimePointer.Unmanaged () -> failwith "todo: unmanaged"
|
||||
| CliRuntimePointer.Managed ptr ->
|
||||
match ptr with
|
||||
| CliRuntimePointerSource.LocalVariable (source, var) ->
|
||||
EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable (source, var))
|
||||
| CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var) ->
|
||||
EvalStackValue.ManagedPointer (
|
||||
ManagedPointerSource.LocalVariable (sourceThread, methodFrame, var)
|
||||
)
|
||||
|
||||
EvalStack.Push' v stack
|
||||
|
@@ -84,6 +84,29 @@ module GenericParameter =
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
type MethodInstructions =
|
||||
{
|
||||
/// <summary>
|
||||
/// The IL instructions that compose the method body, along with their offset positions.
|
||||
/// Each tuple contains the instruction and its offset in the method body.
|
||||
/// </summary>
|
||||
Instructions : (IlOp * int) list
|
||||
|
||||
/// <summary>
|
||||
/// A map from instruction offset (program counter) to the corresponding IL operation.
|
||||
/// This is the inverse of Instructions for efficient lookup.
|
||||
/// </summary>
|
||||
Locations : Map<int, IlOp>
|
||||
|
||||
/// <summary>
|
||||
/// Whether local variables in this method should be initialized to their default values.
|
||||
/// This corresponds to the localsinit flag in the method header.
|
||||
/// </summary>
|
||||
LocalsInit : bool
|
||||
|
||||
LocalVars : ImmutableArray<TypeDefn> option
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents detailed information about a method in a .NET assembly.
|
||||
/// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata.
|
||||
@@ -104,16 +127,11 @@ type MethodInfo =
|
||||
Name : string
|
||||
|
||||
/// <summary>
|
||||
/// The IL instructions that comprise the method body, along with their offset positions.
|
||||
/// Each tuple contains the instruction and its offset in the method body.
|
||||
/// The IL instructions that compose the method body, along with their offset positions.
|
||||
///
|
||||
/// There may be no instructions for this method, e.g. if it's an `InternalCall`.
|
||||
/// </summary>
|
||||
Instructions : (IlOp * int) list
|
||||
|
||||
/// <summary>
|
||||
/// A map from instruction offset (program counter) to the corresponding IL operation.
|
||||
/// This is the inverse of Instructions for efficient lookup.
|
||||
/// </summary>
|
||||
Locations : Map<int, IlOp>
|
||||
Instructions : MethodInstructions option
|
||||
|
||||
/// <summary>
|
||||
/// The parameters of this method.
|
||||
@@ -131,17 +149,13 @@ type MethodInfo =
|
||||
Signature : TypeMethodSignature<TypeDefn>
|
||||
|
||||
/// <summary>
|
||||
/// Whether this method is implemented as a platform invoke (P/Invoke) to unmanaged code.
|
||||
/// Custom attributes defined on the method. I've never yet seen one of these in practice.
|
||||
/// </summary>
|
||||
IsPinvokeImpl : bool
|
||||
CustomAttributes : WoofWare.PawPrint.CustomAttribute ImmutableArray
|
||||
|
||||
/// <summary>
|
||||
/// Whether local variables in this method should be initialized to their default values.
|
||||
/// This corresponds to the localsinit flag in the method header.
|
||||
/// </summary>
|
||||
LocalsInit : bool
|
||||
MethodAttributes : MethodAttributes
|
||||
|
||||
LocalVars : ImmutableArray<TypeDefn> option
|
||||
ImplAttributes : MethodImplAttributes
|
||||
|
||||
/// <summary>
|
||||
/// Whether this method is static (true) or an instance method (false).
|
||||
@@ -149,6 +163,19 @@ type MethodInfo =
|
||||
IsStatic : bool
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this method's implementation is directly supplied by the CLI, rather than being loaded
|
||||
/// from an assembly as IL.
|
||||
/// </summary>
|
||||
member this.IsCliInternal : bool =
|
||||
this.ImplAttributes.HasFlag MethodImplAttributes.InternalCall
|
||||
|
||||
/// <summary>
|
||||
/// Whether this method is implemented as a platform invoke (P/Invoke) to unmanaged code.
|
||||
/// </summary>
|
||||
member this.IsPinvokeImpl : bool =
|
||||
this.MethodAttributes.HasFlag MethodAttributes.PinvokeImpl
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module MethodInfo =
|
||||
type private Dummy = class end
|
||||
@@ -494,19 +521,47 @@ module MethodInfo =
|
||||
(methodHandle : MethodDefinitionHandle)
|
||||
: MethodInfo option
|
||||
=
|
||||
let logger = loggerFactory.CreateLogger "MethodInfo"
|
||||
let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName ()
|
||||
let methodDef = metadataReader.GetMethodDefinition methodHandle
|
||||
let methodName = metadataReader.GetString methodDef.Name
|
||||
let methodSig = methodDef.DecodeSignature (TypeDefn.typeProvider, ())
|
||||
let methodBody = readMethodBody peReader metadataReader methodDef
|
||||
let implAttrs = methodDef.ImplAttributes
|
||||
|
||||
let methodBody =
|
||||
if
|
||||
implAttrs.HasFlag MethodImplAttributes.InternalCall
|
||||
|| implAttrs.HasFlag MethodImplAttributes.Runtime
|
||||
then
|
||||
None
|
||||
elif methodDef.Attributes.HasFlag MethodAttributes.PinvokeImpl then
|
||||
None
|
||||
else
|
||||
match readMethodBody peReader metadataReader methodDef with
|
||||
| None ->
|
||||
logger.LogDebug $"no method body in {assemblyName.Name} {methodName}"
|
||||
None
|
||||
| Some body ->
|
||||
{
|
||||
MethodInstructions.Instructions = body.Instructions
|
||||
Locations = body.Instructions |> List.map (fun (a, b) -> b, a) |> Map.ofList
|
||||
LocalsInit = body.LocalInit
|
||||
LocalVars = body.LocalSig
|
||||
}
|
||||
|> Some
|
||||
|
||||
let declaringType = methodDef.GetDeclaringType ()
|
||||
|
||||
match methodBody with
|
||||
| None ->
|
||||
let logger = loggerFactory.CreateLogger typeof<Dummy>.DeclaringType
|
||||
logger.LogDebug ("No method body for {MethodWithoutBody}", metadataReader.GetString methodDef.Name)
|
||||
None
|
||||
| Some methodBody ->
|
||||
let attrs =
|
||||
let result = ImmutableArray.CreateBuilder ()
|
||||
let attrs = methodDef.GetCustomAttributes ()
|
||||
|
||||
for attr in attrs do
|
||||
metadataReader.GetCustomAttribute attr
|
||||
|> CustomAttribute.make attr
|
||||
|> result.Add
|
||||
|
||||
result.ToImmutable ()
|
||||
|
||||
let typeSig = TypeMethodSignature.make methodSig
|
||||
|
||||
@@ -519,14 +574,13 @@ module MethodInfo =
|
||||
DeclaringType = (declaringType, assemblyName)
|
||||
Handle = methodHandle
|
||||
Name = methodName
|
||||
Instructions = methodBody.Instructions
|
||||
Locations = methodBody.Instructions |> List.map (fun (a, b) -> b, a) |> Map.ofList
|
||||
Instructions = methodBody
|
||||
Parameters = methodParams
|
||||
Generics = methodGenericParams
|
||||
Signature = typeSig
|
||||
IsPinvokeImpl = methodDef.Attributes.HasFlag MethodAttributes.PinvokeImpl
|
||||
LocalsInit = methodBody.LocalInit
|
||||
LocalVars = methodBody.LocalSig
|
||||
MethodAttributes = methodDef.Attributes
|
||||
CustomAttributes = attrs
|
||||
IsStatic = not methodSig.Header.IsInstance
|
||||
ImplAttributes = implAttrs
|
||||
}
|
||||
|> Some
|
||||
|
@@ -109,12 +109,19 @@ module Program =
|
||||
| TypeDefn.PrimitiveType PrimitiveType.Int32 -> ()
|
||||
| _ -> failwith "Main method must return int32; other types not currently supported"
|
||||
|
||||
// TODO: now overwrite the main thread which we used for object initialisation. The below is not right.
|
||||
let state, mainThread =
|
||||
state
|
||||
|> IlMachineState.addThread
|
||||
(MethodState.Empty mainMethod (ImmutableArray.Create (CliType.OfManagedObject arrayAllocation)) None)
|
||||
dumped.Name
|
||||
// Now that BCL initialisation has taken place, overwrite the main thread completely.
|
||||
let methodState =
|
||||
MethodState.Empty mainMethod (ImmutableArray.Create (CliType.OfManagedObject arrayAllocation)) None
|
||||
|
||||
let threadState =
|
||||
{ state.ThreadState.[mainThread] with
|
||||
MethodStates = ImmutableArray.Create methodState
|
||||
}
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
ThreadState = state.ThreadState |> Map.add mainThread threadState
|
||||
}
|
||||
|
||||
let rec go (state : IlMachineState) =
|
||||
match AbstractMachine.executeOneStep loggerFactory baseClassTypes state mainThread with
|
||||
@@ -122,7 +129,9 @@ module Program =
|
||||
| ExecutionResult.Stepped (state', whatWeDid) ->
|
||||
|
||||
match whatWeDid with
|
||||
| WhatWeDid.Executed -> logger.LogInformation "Executed one step."
|
||||
| WhatWeDid.Executed ->
|
||||
logger.LogInformation
|
||||
$"Executed one step; active assembly: {state'.ActiveAssembly(mainThread).Name.Name}."
|
||||
| WhatWeDid.SuspendedForClassInit ->
|
||||
logger.LogInformation "Suspended execution of current method for class initialisation."
|
||||
| WhatWeDid.BlockedOnClassInit threadBlockingUs ->
|
||||
|
@@ -21,9 +21,9 @@
|
||||
<Compile Include="TypeInfo.fs" />
|
||||
<Compile Include="Assembly.fs" />
|
||||
<Compile Include="Corelib.fs" />
|
||||
<Compile Include="AbstractMachineDomain.fs" />
|
||||
<Compile Include="BasicCliType.fs" />
|
||||
<Compile Include="ManagedHeap.fs" />
|
||||
<Compile Include="AbstractMachineDomain.fs" />
|
||||
<Compile Include="TypeInitialisation.fs" />
|
||||
<Compile Include="EvalStack.fs" />
|
||||
<Compile Include="AbstractMachine.fs" />
|
||||
|
Reference in New Issue
Block a user