Revert "[mono][debugger] First PR to implement iCorDebug on mono (#20757)"
[mono-project.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / VirtualMachine.cs
blobb77f5f46b221e2405ee77a2f54a0d5eece8968bf
1 using System;
2 using System.IO;
3 using System.Threading;
4 using System.Net;
5 using System.Diagnostics;
6 using System.Collections;
7 using System.Collections.Generic;
9 namespace Mono.Debugger.Soft
11 public class VirtualMachine : Mirror
13 Queue queue;
14 object queue_monitor;
15 object startup_monitor;
16 AppDomainMirror root_domain;
17 Dictionary<int, EventRequest> requests;
18 ITargetProcess process;
20 internal Connection conn;
22 VersionInfo version;
24 internal VirtualMachine (ITargetProcess process, Connection conn) : base () {
25 SetVirtualMachine (this);
26 queue = new Queue ();
27 queue_monitor = new Object ();
28 startup_monitor = new Object ();
29 requests = new Dictionary <int, EventRequest> ();
30 this.conn = conn;
31 this.process = process;
32 conn.ErrorHandler += ErrorHandler;
35 // The standard output of the process is available normally through Process
36 public StreamReader StandardOutput { get; set; }
37 public StreamReader StandardError { get; set; }
40 public Process Process {
41 get {
42 ProcessWrapper pw = process as ProcessWrapper;
43 if (pw == null)
44 throw new InvalidOperationException ("Process instance not available");
45 return pw.Process;
49 public ITargetProcess TargetProcess {
50 get {
51 return process;
55 public AppDomainMirror RootDomain {
56 get {
57 return root_domain;
61 public EndPoint EndPoint {
62 get {
63 var tcpConn = conn as TcpConnection;
64 if (tcpConn != null)
65 return tcpConn.EndPoint;
66 return null;
70 public VersionInfo Version {
71 get {
72 return version;
76 EventSet current_es;
77 int current_es_index;
80 * It is impossible to determine when to resume when using this method, since
81 * the debuggee is suspended only once per event-set, not event.
83 [Obsolete ("Use GetNextEventSet () instead")]
84 public Event GetNextEvent () {
85 lock (queue_monitor) {
86 if (current_es == null || current_es_index == current_es.Events.Length) {
87 if (queue.Count == 0)
88 Monitor.Wait (queue_monitor);
89 current_es = (EventSet)queue.Dequeue ();
90 current_es_index = 0;
92 return current_es.Events [current_es_index ++];
96 public Event GetNextEvent (int timeout) {
97 throw new NotImplementedException ();
100 public EventSet GetNextEventSet () {
101 lock (queue_monitor) {
102 if (queue.Count == 0)
103 Monitor.Wait (queue_monitor);
105 current_es = null;
106 current_es_index = 0;
108 return (EventSet)queue.Dequeue ();
112 public EventSet GetNextEventSet (int timeoutInMilliseconds) {
113 lock (queue_monitor) {
114 if (queue.Count == 0) {
115 if (!Monitor.Wait (queue_monitor, timeoutInMilliseconds)) {
116 return null;
120 current_es = null;
121 current_es_index = 0;
123 return (EventSet)queue.Dequeue ();
127 [Obsolete ("Use GetNextEventSet () instead")]
128 public T GetNextEvent<T> () where T : Event {
129 return GetNextEvent () as T;
132 public void Suspend () {
133 conn.VM_Suspend ();
136 public void Resume () {
137 try {
138 InvalidateThreadAndFrameCaches ();
139 conn.VM_Resume ();
140 } catch (CommandException ex) {
141 if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
142 throw new VMNotSuspendedException ();
144 throw;
148 public void Exit (int exitCode) {
149 conn.VM_Exit (exitCode);
152 public void Detach () {
153 // Notify the application that we are detaching
154 conn.VM_Dispose ();
155 // Close the connection. No further messages can be sent
156 // over the connection after this point.
157 conn.Close ();
158 notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, 0, 0, null, 0);
161 [Obsolete ("This method was poorly named; use the Detach() method instead")]
162 public void Dispose ()
164 Detach ();
167 public void ForceDisconnect ()
169 conn.ForceDisconnect ();
172 HashSet<ThreadMirror> threadsToInvalidate = new HashSet<ThreadMirror> ();
173 ThreadMirror[] threadCache;
175 void InvalidateThreadAndFrameCaches () {
176 lock (threadsToInvalidate) {
177 foreach (var thread in threadsToInvalidate)
178 thread.InvalidateFrames ();
179 threadsToInvalidate.Clear ();
181 threadCache = null;
184 internal void InvalidateThreadCache () {
185 threadCache = null;
188 internal void AddThreadToInvalidateList (ThreadMirror threadMirror)
190 lock (threadsToInvalidate) {
191 threadsToInvalidate.Add (threadMirror);
195 public IList<ThreadMirror> GetThreads () {
196 var threads = threadCache;
197 if (threads == null) {
198 long[] ids = null;
199 var fetchingEvent = new ManualResetEvent (false);
200 vm.conn.VM_GetThreads ((threadsIds) => {
201 ids = threadsIds;
202 threads = new ThreadMirror [threadsIds.Length];
203 fetchingEvent.Set ();
205 if (WaitHandle.WaitAny (new []{ vm.conn.DisconnectedEvent, fetchingEvent }) == 0) {
206 throw new VMDisconnectedException ();
208 for (int i = 0; i < ids.Length; ++i)
209 threads [i] = GetThread (ids [i]);
210 //Uncomment lines below if you want to re-fetch threads if new threads were started/stopped while
211 //featching threads... This is probably more correct but might cause deadlock of this method if runtime
212 //is starting/stopping threads nonstop, need way to prevent this(counting number of recursions?)
213 //possiblity before uncommenting
214 //if (threadCache != threads) {//While fetching threads threadCache was invalidated(thread was created/destoyed)
215 // return GetThreads ();
217 Thread.MemoryBarrier ();
218 threadCache = threads;
219 return threads;
220 } else {
221 return threads;
225 // Same as the mirrorOf methods in JDI
226 public PrimitiveValue CreateValue (object value) {
227 if (value == null)
228 return new PrimitiveValue (vm, null);
230 if (!value.GetType ().IsPrimitive)
231 throw new ArgumentException ("value must be of a primitive type instead of '" + value.GetType () + "'", "value");
233 return new PrimitiveValue (vm, value);
236 public EnumMirror CreateEnumMirror (TypeMirror type, PrimitiveValue value) {
237 return new EnumMirror (this, type, value);
241 // Enable send and receive timeouts on the connection and send a keepalive event
242 // every 'keepalive_interval' milliseconds.
245 public void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
247 conn.SetSocketTimeouts (send_timeout, receive_timeout, keepalive_interval);
251 // Methods to create event request objects
253 public BreakpointEventRequest CreateBreakpointRequest (MethodMirror method, long il_offset) {
254 return new BreakpointEventRequest (this, method, il_offset);
257 public BreakpointEventRequest CreateBreakpointRequest (Location loc) {
258 if (loc == null)
259 throw new ArgumentNullException ("loc");
260 CheckMirror (loc);
261 return new BreakpointEventRequest (this, loc.Method, loc.ILOffset);
264 public StepEventRequest CreateStepRequest (ThreadMirror thread) {
265 return new StepEventRequest (this, thread);
268 public MethodEntryEventRequest CreateMethodEntryRequest () {
269 return new MethodEntryEventRequest (this);
272 public MethodExitEventRequest CreateMethodExitRequest () {
273 return new MethodExitEventRequest (this);
276 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type) {
277 return new ExceptionEventRequest (this, exc_type, true, true);
280 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught) {
281 return new ExceptionEventRequest (this, exc_type, caught, uncaught);
284 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught, bool everything_else) {
285 if (Version.AtLeast (2, 54))
286 return new ExceptionEventRequest (this, exc_type, caught, uncaught, true, everything_else);
287 else
288 return new ExceptionEventRequest (this, exc_type, caught, uncaught);
291 public AssemblyLoadEventRequest CreateAssemblyLoadRequest () {
292 return new AssemblyLoadEventRequest (this);
295 public TypeLoadEventRequest CreateTypeLoadRequest () {
296 return new TypeLoadEventRequest (this);
299 public void EnableEvents (params EventType[] events) {
300 EnableEvents (events, SuspendPolicy.All);
303 public void EnableEvents (EventType[] events, SuspendPolicy suspendPolicy) {
304 foreach (EventType etype in events) {
305 if (etype == EventType.Breakpoint)
306 throw new ArgumentException ("Breakpoint events cannot be requested using EnableEvents", "events");
307 conn.EnableEvent (etype, suspendPolicy, null);
311 public BreakpointEventRequest SetBreakpoint (MethodMirror method, long il_offset) {
312 BreakpointEventRequest req = CreateBreakpointRequest (method, il_offset);
314 req.Enable ();
316 return req;
319 public void ClearAllBreakpoints () {
320 conn.ClearAllBreakpoints ();
323 public void Disconnect () {
324 conn.Close ();
328 // Return a list of TypeMirror objects for all loaded types which reference the
329 // source file FNAME. Might return false positives.
330 // Since protocol version 2.7.
332 public IList<TypeMirror> GetTypesForSourceFile (string fname, bool ignoreCase) {
333 long[] ids = conn.VM_GetTypesForSourceFile (fname, ignoreCase);
334 var res = new TypeMirror [ids.Length];
335 for (int i = 0; i < ids.Length; ++i)
336 res [i] = GetType (ids [i]);
337 return res;
341 // Return a list of TypeMirror objects for all loaded types named 'NAME'.
342 // NAME should be in the the same for as with Assembly.GetType ().
343 // Since protocol version 2.9.
345 public IList<TypeMirror> GetTypes (string name, bool ignoreCase) {
346 long[] ids = conn.VM_GetTypes (name, ignoreCase);
347 var res = new TypeMirror [ids.Length];
348 for (int i = 0; i < ids.Length; ++i)
349 res [i] = GetType (ids [i]);
350 return res;
353 internal void queue_event_set (EventSet es) {
354 lock (queue_monitor) {
355 queue.Enqueue (es);
356 Monitor.Pulse (queue_monitor);
360 internal void ErrorHandler (object sender, ErrorHandlerEventArgs args) {
361 switch (args.ErrorCode) {
362 case ErrorCode.INVALID_OBJECT:
363 throw new ObjectCollectedException ();
364 case ErrorCode.INVALID_FRAMEID:
365 throw new InvalidStackFrameException ();
366 case ErrorCode.NOT_SUSPENDED:
367 throw new VMNotSuspendedException ();
368 case ErrorCode.NOT_IMPLEMENTED:
369 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
370 case ErrorCode.ABSENT_INFORMATION:
371 throw new AbsentInformationException ();
372 case ErrorCode.NO_SEQ_POINT_AT_IL_OFFSET:
373 throw new ArgumentException ("Cannot set breakpoint on the specified IL offset.");
374 default:
375 throw new CommandException (args.ErrorCode, args.ErrorMessage);
379 /* Wait for the debuggee to start up and connect to it */
380 internal void connect () {
381 conn.Connect ();
383 // Test the connection
384 version = conn.Version;
385 if (version.MajorVersion != Connection.MAJOR_VERSION)
386 throw new NotSupportedException (String.Format ("The debuggee implements protocol version {0}.{1}, while {2}.{3} is required.", version.MajorVersion, version.MinorVersion, Connection.MAJOR_VERSION, Connection.MINOR_VERSION));
388 long root_domain_id = conn.RootDomain;
389 root_domain = GetDomain (root_domain_id);
392 internal void notify_vm_event (EventType evtype, SuspendPolicy spolicy, int req_id, long thread_id, string vm_uri, int exit_code) {
393 //Console.WriteLine ("Event: " + evtype + "(" + vm_uri + ")");
395 switch (evtype) {
396 case EventType.VMStart:
397 /* Notify the main thread that the debuggee started up */
398 lock (startup_monitor) {
399 Monitor.Pulse (startup_monitor);
401 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMStartEvent (vm, req_id, thread_id) }));
402 break;
403 case EventType.VMDeath:
404 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDeathEvent (vm, req_id, exit_code) }));
405 break;
406 case EventType.VMDisconnect:
407 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDisconnectEvent (vm, req_id) }));
408 break;
409 default:
410 throw new Exception ();
415 // Methods to create instances of mirror objects
419 class MirrorCache<T> {
420 static Dictionary <long, T> mirrors;
421 static object mirror_lock = new object ();
423 internal static T GetMirror (VirtualMachine vm, long id) {
424 lock (mirror_lock) {
425 if (mirrors == null)
426 mirrors = new Dictionary <long, T> ();
427 T obj;
428 if (!mirrors.TryGetValue (id, out obj)) {
429 obj = CreateMirror (vm, id);
430 mirrors [id] = obj;
432 return obj;
436 internal static T CreateMirror (VirtualMachine vm, long id) {
441 // FIXME: When to remove items from the cache ?
443 Dictionary <long, MethodMirror> methods;
444 object methods_lock = new object ();
446 internal MethodMirror GetMethod (long id) {
447 lock (methods_lock) {
448 if (methods == null)
449 methods = new Dictionary <long, MethodMirror> ();
450 MethodMirror obj;
451 if (id == 0)
452 return null;
453 if (!methods.TryGetValue (id, out obj)) {
454 obj = new MethodMirror (this, id);
455 methods [id] = obj;
457 return obj;
461 Dictionary <long, AssemblyMirror> assemblies;
462 object assemblies_lock = new object ();
464 internal AssemblyMirror GetAssembly (long id) {
465 lock (assemblies_lock) {
466 if (assemblies == null)
467 assemblies = new Dictionary <long, AssemblyMirror> ();
468 AssemblyMirror obj;
469 if (id == 0)
470 return null;
471 if (!assemblies.TryGetValue (id, out obj)) {
472 obj = new AssemblyMirror (this, id);
473 assemblies [id] = obj;
475 return obj;
479 Dictionary <long, ModuleMirror> modules;
480 object modules_lock = new object ();
482 internal ModuleMirror GetModule (long id) {
483 lock (modules_lock) {
484 if (modules == null)
485 modules = new Dictionary <long, ModuleMirror> ();
486 ModuleMirror obj;
487 if (id == 0)
488 return null;
489 if (!modules.TryGetValue (id, out obj)) {
490 obj = new ModuleMirror (this, id);
491 modules [id] = obj;
493 return obj;
497 Dictionary <long, AppDomainMirror> domains;
498 object domains_lock = new object ();
500 internal AppDomainMirror GetDomain (long id) {
501 lock (domains_lock) {
502 if (domains == null)
503 domains = new Dictionary <long, AppDomainMirror> ();
504 AppDomainMirror obj;
505 if (id == 0)
506 return null;
507 if (!domains.TryGetValue (id, out obj)) {
508 obj = new AppDomainMirror (this, id);
509 domains [id] = obj;
511 return obj;
515 internal void InvalidateAssemblyCaches () {
516 lock (domains_lock) {
517 foreach (var d in domains.Values)
518 d.InvalidateAssembliesCache ();
522 Dictionary <long, TypeMirror> types;
523 object types_lock = new object ();
525 internal TypeMirror GetType (long id) {
526 lock (types_lock) {
527 if (types == null)
528 types = new Dictionary <long, TypeMirror> ();
529 TypeMirror obj;
530 if (id == 0)
531 return null;
532 if (!types.TryGetValue (id, out obj)) {
533 obj = new TypeMirror (this, id);
534 types [id] = obj;
536 return obj;
540 internal TypeMirror[] GetTypes (long[] ids) {
541 var res = new TypeMirror [ids.Length];
542 for (int i = 0; i < ids.Length; ++i)
543 res [i] = GetType (ids [i]);
544 return res;
547 Dictionary <long, ObjectMirror> objects;
548 object objects_lock = new object ();
550 // Return a mirror if it exists
551 // Does not call into the debuggee
552 internal T TryGetObject<T> (long id) where T : ObjectMirror {
553 lock (objects_lock) {
554 if (objects == null)
555 objects = new Dictionary <long, ObjectMirror> ();
556 ObjectMirror obj;
557 objects.TryGetValue (id, out obj);
558 return (T)obj;
562 internal T GetObject<T> (long id, long domain_id, long type_id) where T : ObjectMirror {
563 ObjectMirror obj = null;
564 lock (objects_lock) {
565 if (objects == null)
566 objects = new Dictionary <long, ObjectMirror> ();
567 objects.TryGetValue (id, out obj);
570 if (obj == null) {
572 * Obtain the domain/type of the object to determine the type of
573 * object we need to create. Do this outside the lock.
575 if (domain_id == 0 || type_id == 0) {
576 if (conn.Version.AtLeast (2, 5)) {
577 var info = conn.Object_GetInfo (id);
578 domain_id = info.domain_id;
579 type_id = info.type_id;
580 } else {
581 if (domain_id == 0)
582 domain_id = conn.Object_GetDomain (id);
583 if (type_id == 0)
584 type_id = conn.Object_GetType (id);
587 AppDomainMirror d = GetDomain (domain_id);
588 TypeMirror t = GetType (type_id);
590 if (t.Assembly == d.Corlib && t.Namespace == "System.Threading" && t.Name == "Thread")
591 obj = new ThreadMirror (this, id, t, d);
592 else if (t.Assembly == d.Corlib && t.Namespace == "System" && t.Name == "String")
593 obj = new StringMirror (this, id, t, d);
594 else if (typeof (T) == typeof (ArrayMirror))
595 obj = new ArrayMirror (this, id, t, d);
596 else
597 obj = new ObjectMirror (this, id, t, d);
599 // Publish
600 lock (objects_lock) {
601 ObjectMirror prev_obj;
602 if (objects.TryGetValue (id, out prev_obj))
603 obj = prev_obj;
604 else
605 objects [id] = obj;
608 return (T)obj;
611 internal T GetObject<T> (long id) where T : ObjectMirror {
612 return GetObject<T> (id, 0, 0);
615 internal ObjectMirror GetObject (long objid) {
616 return GetObject<ObjectMirror> (objid);
619 internal ThreadMirror GetThread (long id) {
620 return GetObject <ThreadMirror> (id);
623 internal ThreadMirror TryGetThread (long id) {
624 return TryGetObject <ThreadMirror> (id);
627 Dictionary <long, FieldInfoMirror> fields;
628 object fields_lock = new object ();
630 internal FieldInfoMirror GetField (long id) {
631 lock (fields_lock) {
632 if (fields == null)
633 fields = new Dictionary <long, FieldInfoMirror> ();
634 FieldInfoMirror obj;
635 if (id == 0)
636 return null;
637 if (!fields.TryGetValue (id, out obj)) {
638 obj = new FieldInfoMirror (this, id);
639 fields [id] = obj;
641 return obj;
645 object requests_lock = new object ();
647 internal void AddRequest (EventRequest req, int id) {
648 lock (requests_lock) {
649 requests [id] = req;
653 internal void RemoveRequest (EventRequest req, int id) {
654 lock (requests_lock) {
655 requests.Remove (id);
659 internal EventRequest GetRequest (int id) {
660 lock (requests_lock) {
661 EventRequest obj;
662 requests.TryGetValue (id, out obj);
663 return obj;
667 internal Value DecodeValue (ValueImpl v) {
668 return DecodeValue (v, null);
671 internal Value DecodeValue (ValueImpl v, Dictionary<int, Value> parent_vtypes) {
672 if (v.Value != null) {
673 if (Version.AtLeast (2, 46) && (v.Type == ElementType.Ptr || v.Type == ElementType.FnPtr))
674 return new PointerValue(this, GetType(v.Klass), (long)v.Value);
675 return new PrimitiveValue (this, v.Value);
678 switch (v.Type) {
679 case ElementType.Void:
680 return null;
681 case ElementType.SzArray:
682 case ElementType.Array:
683 return GetObject<ArrayMirror> (v.Objid);
684 case ElementType.String:
685 return GetObject<StringMirror> (v.Objid);
686 case ElementType.Class:
687 case ElementType.Object:
688 return GetObject (v.Objid);
689 case ElementType.ValueType:
690 if (parent_vtypes == null)
691 parent_vtypes = new Dictionary<int, Value> ();
692 StructMirror vtype;
693 if (v.IsEnum)
694 vtype = new EnumMirror (this, GetType (v.Klass), (Value[])null);
695 else
696 vtype = new StructMirror (this, GetType (v.Klass), (Value[])null);
697 parent_vtypes [parent_vtypes.Count] = vtype;
698 vtype.SetFields (DecodeValues (v.Fields, parent_vtypes));
699 parent_vtypes.Remove (parent_vtypes.Count - 1);
700 return vtype;
701 case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
702 return new PrimitiveValue (this, null);
703 case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE:
704 return parent_vtypes [v.Index];
705 default:
706 throw new NotImplementedException ("" + v.Type);
710 internal Value[] DecodeValues (ValueImpl[] values) {
711 Value[] res = new Value [values.Length];
712 for (int i = 0; i < values.Length; ++i)
713 res [i] = DecodeValue (values [i]);
714 return res;
717 internal Value[] DecodeValues (ValueImpl[] values, Dictionary<int, Value> parent_vtypes) {
718 Value[] res = new Value [values.Length];
719 for (int i = 0; i < values.Length; ++i)
720 res [i] = DecodeValue (values [i], parent_vtypes);
721 return res;
724 internal ValueImpl EncodeValue (Value v, List<Value> duplicates = null) {
725 if (v is PrimitiveValue) {
726 object val = (v as PrimitiveValue).Value;
727 if (val == null)
728 return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
729 else
730 return new ValueImpl { Value = val };
731 } else if (v is ObjectMirror) {
732 return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
733 } else if (v is StructMirror) {
734 if (duplicates == null)
735 duplicates = new List<Value> ();
736 if (duplicates.Contains (v))
737 return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
738 duplicates.Add (v);
740 return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeFieldValues ((v as StructMirror).Fields, (v as StructMirror).Type.GetFields (), duplicates, 1) };
741 } else if (v is PointerValue) {
742 PointerValue val = (PointerValue)v;
743 return new ValueImpl { Type = ElementType.Ptr, Klass = val.Type.Id, Value = val.Address };
744 } else {
745 throw new NotSupportedException ("Value of type " + v.GetType());
749 internal ValueImpl EncodeValueFixedSize (Value v, List<Value> duplicates, int len_fixed_size) {
750 if (v is PrimitiveValue) {
751 object val = (v as PrimitiveValue).Value;
752 if (val == null)
753 return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
754 else
755 return new ValueImpl { Value = val , FixedSize = len_fixed_size};
756 } else if (v is ObjectMirror) {
757 return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
758 } else if (v is StructMirror) {
759 if (duplicates == null)
760 duplicates = new List<Value> ();
761 if (duplicates.Contains (v))
762 return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
763 duplicates.Add (v);
765 return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeFieldValues ((v as StructMirror).Fields, (v as StructMirror).Type.GetFields (), duplicates, len_fixed_size) };
766 } else if (v is PointerValue) {
767 PointerValue val = (PointerValue)v;
768 return new ValueImpl { Type = ElementType.Ptr, Klass = val.Type.Id, Value = val.Address };
769 } else {
770 throw new NotSupportedException ("Value of type " + v.GetType());
774 internal ValueImpl[] EncodeValues (IList<Value> values, List<Value> duplicates = null) {
775 ValueImpl[] res = new ValueImpl [values.Count];
776 for (int i = 0; i < values.Count; ++i)
777 res [i] = EncodeValue (values [i], duplicates);
778 return res;
781 internal ValueImpl[] EncodeFieldValues (IList<Value> values, FieldInfoMirror[] field_info, List<Value> duplicates, int fixedSize) {
782 ValueImpl[] res = new ValueImpl [values.Count];
783 for (int i = 0; i < values.Count; ++i) {
784 if (fixedSize > 1 || field_info [i].FixedSize > 1)
785 res [i] = EncodeValueFixedSize (values [i], duplicates, fixedSize > 1 ? fixedSize : field_info [i].FixedSize);
786 else
787 res [i] = EncodeValue (values [i], duplicates);
789 return res;
792 internal void CheckProtocolVersion (int major, int minor) {
793 if (!conn.Version.AtLeast (major, minor))
794 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
798 class EventHandler : MarshalByRefObject, IEventHandler
800 VirtualMachine vm;
802 public EventHandler (VirtualMachine vm) {
803 this.vm = vm;
806 public void Events (SuspendPolicy suspend_policy, EventInfo[] events) {
807 var l = new List<Event> ();
809 for (int i = 0; i < events.Length; ++i) {
810 EventInfo ei = events [i];
811 int req_id = ei.ReqId;
812 long thread_id = ei.ThreadId;
813 long id = ei.Id;
814 long loc = ei.Location;
816 switch (ei.EventType) {
817 case EventType.VMStart:
818 vm.notify_vm_event (EventType.VMStart, suspend_policy, req_id, thread_id, null, 0);
819 break;
820 case EventType.VMDeath:
821 vm.notify_vm_event (EventType.VMDeath, suspend_policy, req_id, thread_id, null, ei.ExitCode);
822 break;
823 case EventType.ThreadStart:
824 vm.InvalidateThreadCache ();
825 l.Add (new ThreadStartEvent (vm, req_id, id));
826 break;
827 case EventType.ThreadDeath:
828 // Avoid calling GetThread () since it might call into the debuggee
829 // and we can't do that in the event handler
830 var thread = vm.TryGetThread (id);
831 if (thread != null)
832 thread.InvalidateFrames ();
833 vm.InvalidateThreadCache ();
834 l.Add (new ThreadDeathEvent (vm, req_id, id));
835 break;
836 case EventType.AssemblyLoad:
837 vm.InvalidateAssemblyCaches ();
838 l.Add (new AssemblyLoadEvent (vm, req_id, thread_id, id));
839 break;
840 case EventType.AssemblyUnload:
841 vm.InvalidateAssemblyCaches ();
842 l.Add (new AssemblyUnloadEvent (vm, req_id, thread_id, id));
843 break;
844 case EventType.TypeLoad:
845 l.Add (new TypeLoadEvent (vm, req_id, thread_id, id));
846 break;
847 case EventType.MethodEntry:
848 l.Add (new MethodEntryEvent (vm, req_id, thread_id, id));
849 break;
850 case EventType.MethodExit:
851 l.Add (new MethodExitEvent (vm, req_id, thread_id, id));
852 break;
853 case EventType.Breakpoint:
854 l.Add (new BreakpointEvent (vm, req_id, thread_id, id, loc));
855 break;
856 case EventType.Step:
857 l.Add (new StepEvent (vm, req_id, thread_id, id, loc));
858 break;
859 case EventType.Exception:
860 l.Add (new ExceptionEvent (vm, req_id, thread_id, id, loc));
861 break;
862 case EventType.AppDomainCreate:
863 l.Add (new AppDomainCreateEvent (vm, req_id, thread_id, id));
864 break;
865 case EventType.AppDomainUnload:
866 l.Add (new AppDomainUnloadEvent (vm, req_id, thread_id, id));
867 break;
868 case EventType.UserBreak:
869 l.Add (new UserBreakEvent (vm, req_id, thread_id));
870 break;
871 case EventType.UserLog:
872 l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message));
873 break;
874 case EventType.Crash:
875 l.Add (new CrashEvent (vm, req_id, thread_id, ei.Dump, ei.Hash));
876 break;
880 if (l.Count > 0)
881 vm.queue_event_set (new EventSet (vm, suspend_policy, l.ToArray ()));
884 public void VMDisconnect (int req_id, long thread_id, string vm_uri) {
885 vm.notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, req_id, thread_id, vm_uri, 0);
889 public class CommandException : Exception {
891 internal CommandException (ErrorCode error_code, string error_message) : base ("Debuggee returned error code " + error_code + (error_message == null || error_message.Length == 0 ? "." : " - " + error_message + ".")) {
892 ErrorCode = error_code;
893 ErrorMessage = error_message;
896 public ErrorCode ErrorCode {
897 get; set;
900 public string ErrorMessage {
901 get; internal set;
905 public class VMNotSuspendedException : InvalidOperationException
907 public VMNotSuspendedException () : base ("The vm is not suspended.")