Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ObjCRuntime] Improve the debug logging in the Runtime.CoreCLR.cs file. #14920

Merged
merged 6 commits into from
May 12, 2022
61 changes: 48 additions & 13 deletions src/ObjCRuntime/Runtime.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
// which must be set for tracking to work.
//#define TRACK_MONOOBJECTS

// Uncomment VERBOSE_LOG to enable verbose logging
// #define VERBOSE_LOG

#if NET && !COREBUILD

using System;
Expand Down Expand Up @@ -77,13 +80,45 @@ unsafe struct MonoMethodSignature {
static bool? track_monoobject_with_stacktraces;
#endif

// Comment out the attribute to get all printfs
[System.Diagnostics.Conditional ("UNDEFINED")]
// Define VERBOSE_LOG at the top of this file to get all printfs
[System.Diagnostics.Conditional ("VERBOSE_LOG")]
static void log_coreclr (string message)
{
NSLog (message);
}

// Define VERBOSE_LOG at the top of this file to get all printfs
[System.Diagnostics.Conditional ("VERBOSE_LOG")]
static void log_coreclr_render (string message, params object[] argumentsToRender)
{
var args = new string[argumentsToRender.Length];
for (var i = 0; i < args.Length; i++) {
string arg;
var obj = argumentsToRender [i];
if (obj is null) {
arg = "<null>";
} else if (obj is IntPtr ptr) {
arg = $"0x{ptr.ToString ("x")} (IntPtr)";
} else if (obj.GetType ().IsValueType) {
arg = $"{obj.ToString ()} ({obj.GetType ()})";
} else if (obj is INativeObject inativeobj) {
// Don't call ToString on an INativeObject, we may end up with infinite recursion.
arg = $"{inativeobj.Handle.ToString ()} ({obj.GetType ()})";
} else {
var toString = obj.ToString();
var eol = toString.IndexOf ('\n');
if (eol != -1)
toString = toString.Substring (0, eol - 1) + " [...]";
if (toString.Length > 256)
toString = toString.Substring (0, 256) + " [...]";

arg = $"{toString} ({obj.GetType ()})";
}
args [i] = arg;
}
log_coreclr (string.Format (message, args));
}

static unsafe void InitializeCoreCLRBridge (InitializationOptions* options)
{
if (options->xamarin_objc_msgsend != IntPtr.Zero)
Expand Down Expand Up @@ -573,7 +608,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
}

// Log our input
log_coreclr ($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {instance}, 0x{native_parameters.ToString ("x")})");
log_coreclr ($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {(instance is null ? "<null>" : instance.GetType ().FullName)}, 0x{native_parameters.ToString ("x")})");
for (var i = 0; i < methodParameters.Length; i++) {
var nativeParam = nativeParameters [i];
var p = methodParameters [i];
Expand All @@ -591,7 +626,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
log_coreclr ($" Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName} [...]");
log_coreclr ($" Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName}");

if (paramType == typeof (IntPtr)) {
log_coreclr ($" IntPtr");
Expand All @@ -604,7 +639,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
} else {
parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr (nativeParam);
}
log_coreclr ($" => 0x{((IntPtr) parameters [i]).ToString ("x")}");
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsClass || paramType.IsInterface || (paramType.IsValueType && IsNullable (paramType))) {
log_coreclr ($" IsClass/IsInterface/IsNullable IsByRef: {isByRef} IsOut: {p.IsOut} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero) {
Expand All @@ -617,7 +652,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
parameters [i] = GetMonoObjectTarget (mono_obj);
}
}
log_coreclr ($" => {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");
log_coreclr_render (" => {0}", parameters [i]);
} else if (paramType.IsValueType) {
log_coreclr ($" IsValueType IsByRef: {isByRef} IsOut: {p.IsOut} nativeParam: 0x{nativeParam.ToString ("x")} ParameterType: {paramType}");
if (nativeParam != IntPtr.Zero) {
Expand All @@ -637,7 +672,7 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa
vt = Enum.ToObject (enumType, vt);
parameters [i] = vt;
}
log_coreclr ($" => {(parameters [i] == null ? "<null>" : parameters [i].ToString ())}");
log_coreclr_render (" => {0}", parameters [i]);
} else {
throw ErrorHelper.CreateError (8037, Errors.MX8037 /* Don't know how to marshal the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
}
Expand Down Expand Up @@ -668,13 +703,13 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa

byrefParameterCount++;

log_coreclr ($" Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) value: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");

var parameterType = p.ParameterType.GetElementType ();
var isMonoObject = parameterType.IsClass || parameterType.IsInterface || (parameterType.IsValueType && IsNullable (parameterType));

var nativeParam = nativeParameters [i];

log_coreclr_render ($" Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) nativeParam: 0x{nativeParam.ToString ("x")} value: {{0}}", parameters [i]);

if (nativeParam == IntPtr.Zero) {
log_coreclr ($" No output pointer was provided.");
continue;
Expand All @@ -691,21 +726,21 @@ static object InvokeMethod (MethodBase method, object instance, IntPtr native_pa

if (parameterType == typeof (IntPtr)) {
Marshal.WriteIntPtr (nativeParam, (IntPtr) parameters [i]);
log_coreclr ($" IntPtr: 0x{((IntPtr) parameters [i]).ToString ("x")} => Type: {parameters [i]?.GetType ()} nativeParam: 0x{nativeParam.ToString ("x")}");
log_coreclr ($" IntPtr");
} else if (isMonoObject) {
var ptr = GetMonoObject (parameters [i]);
Marshal.WriteIntPtr (nativeParam, ptr);
log_coreclr ($" IsClass/IsInterface/IsNullable: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)} nativeParam: 0x{nativeParam.ToString ("x")} -> MonoObject: 0x{ptr.ToString ("x")}");
log_coreclr ($" IsClass/IsInterface/IsNullable MonoObject: 0x{ptr.ToString ("x")}");
} else if (parameterType.IsValueType) {
StructureToPtr (parameters [i], nativeParam);
log_coreclr ($" IsValueType: {(parameters [i] == null ? "<null>" : parameters [i].ToString ())} nativeParam: 0x{nativeParam.ToString ("x")}");
log_coreclr ($" IsValueType");
} else {
throw ErrorHelper.CreateError (8038, Errors.MX8038 /* Don't know how to marshal back the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
}
}

// we're done!
log_coreclr ($" Invoke complete with {byrefParameterCount} ref parameters and return value of type {rv?.GetType ()}");
log_coreclr_render ($" Invoke complete with {byrefParameterCount} ref parameters and return value: {{0}}", rv);

return rv;
}
Expand Down