2
2
// SoftDebuggerAdaptor.cs
5
// Lluis Sanchez Gual <lluis@novell.com>
4
// Authors: Lluis Sanchez Gual <lluis@novell.com>
5
// Jeffrey Stedfast <jeff@xamarin.com>
7
7
// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
8
// Copyright (c) 2011,2012 Xamain Inc. (http://www.xamarin.com)
9
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
11
// of this software and associated documentation files (the "Software"), to deal
73
74
if (obj is StringMirror)
74
75
return ((StringMirror)obj).Value;
75
else if (obj is EnumMirror) {
76
EnumMirror eob = (EnumMirror) obj;
77
return eob.StringValue;
79
else if (obj is PrimitiveValue)
77
if (obj is EnumMirror)
78
return ((EnumMirror) obj).StringValue;
80
if (obj is PrimitiveValue)
80
81
return ((PrimitiveValue)obj).Value.ToString ();
81
else if (obj is PointerValue)
83
if (obj is PointerValue)
82
84
return string.Format ("0x{0:x}", ((PointerValue)obj).Address);
83
else if ((obj is StructMirror) && ((StructMirror)obj).Type.IsPrimitive) {
86
if ((obj is StructMirror) && ((StructMirror)obj).Type.IsPrimitive) {
85
88
StructMirror sm = (StructMirror) obj;
86
89
if (sm.Fields.Length > 0 && (sm.Fields[0] is PrimitiveValue))
87
90
return ((PrimitiveValue)sm.Fields[0]).Value.ToString ();
89
else if ((obj is ObjectMirror) && cx.Options.AllowTargetInvoke) {
91
} else if ((obj is ObjectMirror) && cx.Options.AllowTargetInvoke) {
90
92
ObjectMirror ob = (ObjectMirror) obj;
91
93
MethodMirror method = OverloadResolve (cx, "ToString", ob.Type, new TypeMirror[0], true, false, false);
92
94
if (method != null && method.DeclaringType.FullName != "System.Object") {
93
95
StringMirror res = cx.RuntimeInvoke (method, obj, new Value[0]) as StringMirror;
94
96
return res != null ? res.Value : null;
97
else if ((obj is StructMirror) && cx.Options.AllowTargetInvoke) {
98
} else if ((obj is StructMirror) && cx.Options.AllowTargetInvoke) {
98
99
StructMirror ob = (StructMirror) obj;
99
100
MethodMirror method = OverloadResolve (cx, "ToString", ob.Type, new TypeMirror[0], true, false, false);
100
101
if (method != null && method.DeclaringType.FullName != "System.ValueType") {
246
247
return cx.RuntimeInvoke (method, obj, new Value[0]);
249
if (fromType.IsGenericType && fromType.FullName.StartsWith ("System.Nullable`")) {
250
if (fromType.IsGenericType && fromType.FullName.StartsWith ("System.Nullable`1", StringComparison.Ordinal)) {
250
251
method = OverloadResolve (cx, "get_Value", fromType, new TypeMirror[0], true, false, false);
251
252
if (method != null) {
252
253
obj = cx.RuntimeInvoke (method, obj, new Value[0]);
333
334
TypeMirror t = (TypeMirror) type;
335
336
TypeMirror[] types = new TypeMirror [args.Length];
336
for (int n=0; n<args.Length; n++)
337
types [n] = ToTypeMirror (ctx, GetValueType (ctx, args [n]));
339
337
Value[] values = new Value[args.Length];
340
for (int n=0; n<args.Length; n++)
341
values[n] = (Value) args [n];
338
for (int n = 0; n < args.Length; n++) {
339
types[n] = ToTypeMirror (ctx, GetValueType (ctx, args[n]));
340
values[n] = (Value) args[n];
343
343
MethodMirror ctor = OverloadResolve (cx, ".ctor", t, types, true, true, true);
344
344
if (ctor == null)
364
public override bool NullableHasValue (EvaluationContext ctx, object type, object obj)
366
ValueReference hasValue = GetMember (ctx, type, obj, "has_value");
368
return (bool) hasValue.ObjectValue;
371
public override ValueReference NullableGetValue (EvaluationContext ctx, object type, object obj)
373
return GetMember (ctx, type, obj, "value");
364
376
public override object GetEnclosingType (EvaluationContext ctx)
366
378
SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
382
394
public override ValueReference GetIndexerReference (EvaluationContext ctx, object target, object[] indices)
384
TypeMirror targetType = GetValueType (ctx, target) as TypeMirror;
396
object valueType = GetValueType (ctx, target);
397
TypeMirror targetType = null;
399
if (valueType is Type)
400
targetType = (TypeMirror) ForceLoadType (ctx, ((Type) valueType).FullName);
401
else if (valueType is TypeMirror)
402
targetType = (TypeMirror) valueType;
386
406
Value[] values = new Value [indices.Length];
387
407
TypeMirror[] types = new TypeMirror [indices.Length];
450
470
static bool IsHoistedThisReference (FieldInfoMirror field)
452
// mcs is "<>f__this"
472
// mcs is "<>f__this" or "$this" (if in an async compiler generated type)
453
473
// csc is "<>4__this"
454
return field.Name.StartsWith ("<>") && field.Name.EndsWith ("__this");
474
return field.Name == "$this" ||
475
(field.Name.StartsWith ("<>", StringComparison.Ordinal) &&
476
field.Name.EndsWith ("__this", StringComparison.Ordinal));
457
479
static bool IsClosureReferenceField (FieldInfoMirror field)
459
481
// mcs is "<>f__ref"
460
482
// csc is "CS$<>"
461
return field.Name.StartsWith ("CS$<>") || field.Name.StartsWith ("<>f__ref");
483
return field.Name.StartsWith ("CS$<>", StringComparison.Ordinal) ||
484
field.Name.StartsWith ("<>f__ref", StringComparison.Ordinal);
464
487
static bool IsClosureReferenceLocal (LocalVariable local)
466
489
if (local.Name == null)
471
local.Name.Length == 0 || local.Name[0] == '<' || local.Name.StartsWith ("$locvar")
473
|| local.Name.StartsWith ("CS$<>");
492
// mcs is "$locvar" or starts with '<'
494
return local.Name.Length == 0 || local.Name[0] == '<' || local.Name.StartsWith ("$locvar", StringComparison.Ordinal) ||
495
local.Name.StartsWith ("CS$<>", StringComparison.Ordinal);
476
498
static bool IsGeneratedTemporaryLocal (LocalVariable local)
478
return local.Name != null && local.Name.StartsWith ("CS$");
500
return local.Name != null && local.Name.StartsWith ("CS$", StringComparison.Ordinal);
481
503
static string GetHoistedIteratorLocalName (FieldInfoMirror field)
483
505
//mcs captured args, of form <$>name
484
if (field.Name.StartsWith ("<$>")) {
506
if (field.Name.StartsWith ("<$>", StringComparison.Ordinal)) {
485
507
return field.Name.Substring (3);
488
510
// csc, mcs locals of form <name>__0
489
if (field.Name.StartsWith ("<")) {
511
if (field.Name.StartsWith ("<", StringComparison.Ordinal)) {
490
512
int i = field.Name.IndexOf ('>');
492
514
return field.Name.Substring (1, i - 1);
516
538
list.AddRange (GetHoistedLocalVariables (cx, new FieldValueReference (cx, field, val, type)));
519
if (field.Name.StartsWith ("<")) {
541
if (field.Name.StartsWith ("<", StringComparison.Ordinal)) {
520
542
if (isIterator) {
521
543
var name = GetHoistedIteratorLocalName (field);
522
544
if (!string.IsNullOrEmpty (name)) {
575
596
LocalVariable local = null;
576
597
if (!cx.SourceCodeAvailable) {
577
if (name.StartsWith ("loc")) {
598
if (name.StartsWith ("loc", StringComparison.Ordinal)) {
579
600
if (int.TryParse (name.Substring (3), out idx))
580
601
local = cx.Frame.Method.GetLocals ().FirstOrDefault (loc => loc.Index == idx);
587
608
if (local != null) {
588
609
return new VariableValueReference (ctx, GetLocalName (cx, local), local);
590
return FindByName (OnGetLocalVariables (ctx), v => v.Name, name, ctx.CaseSensitive);;
611
return FindByName (OnGetLocalVariables (ctx), v => v.Name, name, ctx.CaseSensitive);
591
612
} catch (AbsentInformationException) {
674
static bool IsAnonymousType (TypeMirror type)
676
return type.Name.StartsWith ("<>__AnonType", StringComparison.Ordinal);
653
679
protected override ValueReference GetMember (EvaluationContext ctx, object t, object co, string name)
655
TypeMirror type = (TypeMirror) t;
681
TypeMirror type = t as TypeMirror;
657
683
while (type != null) {
658
FieldInfoMirror field = FindByName (type.GetFields(), f => f.Name, name, ctx.CaseSensitive);
684
FieldInfoMirror field = FindByName (type.GetFields (), f => f.Name, name, ctx.CaseSensitive);
659
685
if (field != null && (field.IsStatic || co != null))
660
686
return new FieldValueReference (ctx, field, co, type);
662
PropertyInfoMirror prop = FindByName (type.GetProperties(), p => p.Name, name, ctx.CaseSensitive);
688
PropertyInfoMirror prop = FindByName (type.GetProperties (), p => p.Name, name, ctx.CaseSensitive);
663
689
if (prop != null && (IsStatic (prop) || co != null)) {
664
690
// Optimization: if the property has a CompilerGenerated backing field, use that instead.
665
691
// This way we avoid overhead of invoking methods on the debugee when the value is requested.
666
string cgFieldName = string.Format ("<{0}>k__BackingField", prop.Name);
692
string cgFieldName = string.Format ("<{0}>{1}", prop.Name, IsAnonymousType (type) ? "" : "k__BackingField");
667
693
if ((field = FindByName (type.GetFields (), f => f.Name, cgFieldName, true)) != null && IsCompilerGenerated (field))
668
694
return new FieldValueReference (ctx, field, co, type, prop.Name, ObjectValueFlags.Property);
780
806
HashSet<string> namespaces = new HashSet<string> ();
781
807
string namspacePrefix = namspace.Length > 0 ? namspace + "." : "";
782
808
foreach (TypeMirror type in cx.Session.GetAllTypes ()) {
783
if (type.Namespace == namspace || type.Namespace.StartsWith (namspacePrefix)) {
809
if (type.Namespace == namspace || type.Namespace.StartsWith (namspacePrefix, StringComparison.InvariantCulture)) {
784
810
namespaces.Add (type.Namespace);
785
811
types.Add (type.FullName);
815
841
SoftEvaluationContext cx = (SoftEvaluationContext) ctx;
816
842
if (InGeneratedClosureOrIteratorType (cx))
817
843
return GetHoistedThisReference (cx);
819
return GetThisReference (cx);
845
return GetThisReference (cx);
822
848
ValueReference GetThisReference (SoftEvaluationContext cx)
871
897
object[] types = new object [names.Count];
872
898
for (int n=0; n<names.Count; n++) {
873
899
string tn = names [n];
874
if (tn.StartsWith ("["))
900
if (tn.StartsWith ("[", StringComparison.Ordinal))
875
901
tn = tn.Substring (1, tn.Length - 2);
876
902
types [n] = GetType (ctx, tn);
877
903
if (types [n] == null)
962
public override object GetParentType (EvaluationContext ctx, object type)
964
TypeMirror tm = type as TypeMirror;
967
int plus = tm.FullName.LastIndexOf ('+');
969
return plus != -1 ? GetType (ctx, tm.FullName.Substring (0, plus)) : null;
972
return ((Type) type).DeclaringType;
936
975
public override IEnumerable<object> GetNestedTypes (EvaluationContext ctx, object type)
938
977
TypeMirror t = (TypeMirror) type;
943
public override string GetTypeName (EvaluationContext ctx, object val)
982
public override string GetTypeName (EvaluationContext ctx, object type)
945
TypeMirror tm = val as TypeMirror;
984
TypeMirror tm = type as TypeMirror;
946
985
if (tm != null) {
947
986
if (IsGeneratedType (tm)) {
948
987
// Return the name of the container-type.
1024
1064
return val is ArrayMirror;
1067
public override bool IsValueType (object type)
1069
TypeMirror t = type as TypeMirror;
1070
return t != null && t.IsValueType;
1027
1073
public override bool IsClass (object type)
1029
1075
TypeMirror t = type as TypeMirror;
1117
1163
return default(T);
1120
public override object ForceLoadType (EvaluationContext gctx, string typeName)
1122
// Shortcut to avoid a target invoke in case the type is already loaded
1123
object t = GetType (gctx, typeName);
1127
SoftEvaluationContext ctx = (SoftEvaluationContext) gctx;
1128
if (!ctx.Options.AllowTargetInvoke)
1131
TypeMirror tm = (TypeMirror) ctx.Thread.Type.GetTypeObject ().Type;
1132
TypeMirror stype = ctx.Session.GetType ("System.String");
1133
if (stype == null) {
1134
// If the string type is not loaded, we need to get it in another way
1135
StringMirror ss = ctx.Thread.Domain.CreateString ("");
1139
TypeMirror[] ats = new TypeMirror[] { stype };
1140
MethodMirror met = OverloadResolve (ctx, "GetType", tm, ats, false, true, true);
1166
public override bool IsTypeLoaded (EvaluationContext gctx, string typeName)
1168
SoftEvaluationContext ctx = (SoftEvaluationContext) gctx;
1170
return ctx.Session.GetType (typeName) != null;
1173
public override bool IsTypeLoaded (EvaluationContext ctx, object type)
1175
TypeMirror tm = (TypeMirror) type;
1177
if (tm.VirtualMachine.Version.AtLeast (2, 23))
1178
return tm.IsInitialized;
1180
return IsTypeLoaded (ctx, tm.FullName);
1183
public override bool ForceLoadType (EvaluationContext gctx, object type)
1185
SoftEvaluationContext ctx = (SoftEvaluationContext) gctx;
1186
TypeMirror tm = (TypeMirror) type;
1188
if (!tm.VirtualMachine.Version.AtLeast (2, 23))
1189
return IsTypeLoaded (gctx, tm.FullName);
1191
if (tm.IsInitialized)
1194
if (!tm.Attributes.HasFlag (TypeAttributes.BeforeFieldInit))
1197
MethodMirror cctor = OverloadResolve (ctx, ".cctor", tm, new TypeMirror[0], false, true, false);
1143
tm.InvokeMethod (ctx.Thread, met, new Value[] {(Value) CreateValue (ctx, typeName)}, InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded);
1202
tm.InvokeMethod (ctx.Thread, cctor, new Value[0], InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded);
1147
1206
ctx.Session.StackVersion++;
1150
return GetType (ctx, typeName);
1154
1212
static T BuildAttribute<T> (CustomAttributeDataMirror attr)
1292
1350
static MethodMirror OverloadResolve (SoftEvaluationContext ctx, string typeName, string methodName, TypeMirror[] argtypes, List<MethodMirror> candidates, bool throwIfNotFound)
1294
1352
if (candidates.Count == 0) {
1295
if (throwIfNotFound)
1353
if (throwIfNotFound) {
1354
if (methodName == null)
1355
throw new EvaluatorException ("Indexer not found in type `{0}'.", typeName);
1296
1357
throw new EvaluatorException ("Method `{0}' not found in type `{1}'.", methodName, typeName);
1389
1450
return ((PrimitiveValue)obj).Value;
1390
1451
} else if (obj is PointerValue) {
1391
1452
return new IntPtr (((PointerValue)obj).Address);
1392
} else if ((obj is StructMirror) && ((StructMirror)obj).Type.IsPrimitive) {
1453
} else if (obj is StructMirror) {
1394
1454
StructMirror sm = (StructMirror) obj;
1395
if (sm.Type.FullName == "System.IntPtr")
1396
return new IntPtr ((long)((PrimitiveValue)sm.Fields[0]).Value);
1397
if (sm.Fields.Length > 0 && (sm.Fields[0] is PrimitiveValue))
1398
return ((PrimitiveValue)sm.Fields[0]).Value;
1456
if (sm.Type.IsPrimitive) {
1458
if (sm.Type.FullName == "System.IntPtr")
1459
return new IntPtr ((long)((PrimitiveValue)sm.Fields[0]).Value);
1460
if (sm.Fields.Length > 0 && (sm.Fields[0] is PrimitiveValue))
1461
return ((PrimitiveValue)sm.Fields[0]).Value;
1462
} else if (sm.Type.FullName == "System.Decimal") {
1463
SoftEvaluationContext ctx = (SoftEvaluationContext) gctx;
1464
MethodMirror method = OverloadResolve (ctx, "GetBits", sm.Type, new TypeMirror[1] { sm.Type }, false, true, false);
1465
if (method != null) {
1469
array = sm.Type.InvokeMethod (ctx.Thread, method, new Value[1] { sm }, InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded) as ArrayMirror;
1473
ctx.Session.StackVersion++;
1476
if (array != null) {
1477
int[] bits = new int [4];
1478
for (int i = 0; i < 4; i++)
1479
bits[i] = (int) TargetObjectToObject (gctx, array[i]);
1481
return new decimal (bits);
1400
1486
return base.TargetObjectToObject (gctx, obj);