Changed API for fetching StackFrames in bulk on multiple threads ThreadMirror.FetchFr...
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / VirtualMachine.cs
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;
8 using Mono.Cecil.Metadata;
9
10 namespace Mono.Debugger.Soft
11 {
12         public class VirtualMachine : Mirror
13         {
14                 Queue queue;
15                 object queue_monitor;
16                 object startup_monitor;
17                 AppDomainMirror root_domain;
18                 Dictionary<int, EventRequest> requests;
19                 ITargetProcess process;
20
21                 internal Connection conn;
22
23                 VersionInfo version;
24
25                 internal VirtualMachine (ITargetProcess process, Connection conn) : base () {
26                         SetVirtualMachine (this);
27                         queue = new Queue ();
28                         queue_monitor = new Object ();
29                         startup_monitor = new Object ();
30                         requests = new Dictionary <int, EventRequest> ();
31                         this.conn = conn;
32                         this.process = process;
33                         conn.ErrorHandler += ErrorHandler;
34                 }
35
36                 // The standard output of the process is available normally through Process
37                 public StreamReader StandardOutput { get; set; }
38                 public StreamReader StandardError { get; set; }
39
40                 
41                 public Process Process {
42                         get {
43                                 ProcessWrapper pw = process as ProcessWrapper;
44                                 if (pw == null)
45                                     throw new InvalidOperationException ("Process instance not available");
46                                 return pw.Process;
47                         }
48                 }
49
50                 public ITargetProcess TargetProcess {
51                         get {
52                                 return process;
53                         }
54                 }
55
56                 public AppDomainMirror RootDomain {
57                         get {
58                                 return root_domain;
59                         }
60             }
61
62                 public EndPoint EndPoint {
63                         get {
64                                 var tcpConn = conn as TcpConnection;
65                                 if (tcpConn != null)
66                                         return tcpConn.EndPoint;
67                                 return null;
68                         }
69                 }
70
71                 public VersionInfo Version {
72                         get {
73                                 return version;
74                         }
75                 }
76
77                 EventSet current_es;
78                 int current_es_index;
79
80                 /*
81                  * It is impossible to determine when to resume when using this method, since
82                  * the debuggee is suspended only once per event-set, not event.
83                  */
84                 [Obsolete ("Use GetNextEventSet () instead")]
85                 public Event GetNextEvent () {
86                         lock (queue_monitor) {
87                                 if (current_es == null || current_es_index == current_es.Events.Length) {
88                                         if (queue.Count == 0)
89                                                 Monitor.Wait (queue_monitor);
90                                         current_es = (EventSet)queue.Dequeue ();
91                                         current_es_index = 0;
92                                 }
93                                 return current_es.Events [current_es_index ++];
94                         }
95                 }
96
97                 public Event GetNextEvent (int timeout) {
98                         throw new NotImplementedException ();
99                 }
100
101                 public EventSet GetNextEventSet () {
102                         lock (queue_monitor) {
103                                 if (queue.Count == 0)
104                                         Monitor.Wait (queue_monitor);
105
106                                 current_es = null;
107                                 current_es_index = 0;
108
109                                 return (EventSet)queue.Dequeue ();
110                         }
111                 }
112
113                 [Obsolete ("Use GetNextEventSet () instead")]
114                 public T GetNextEvent<T> () where T : Event {
115                         return GetNextEvent () as T;
116                 }
117
118                 public void Suspend () {
119                         conn.VM_Suspend ();
120             }
121
122                 public void Resume () {
123                         try {
124                                 InvalidateThreadsAndFramesCache ();
125                                 conn.VM_Resume ();
126                         } catch (CommandException ex) {
127                                 if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
128                                         throw new VMNotSuspendedException ();
129                                 else
130                                         throw;
131                         }
132             }
133
134                 public void Exit (int exitCode) {
135                         conn.VM_Exit (exitCode);
136                 }
137
138                 public void Detach () {
139                         conn.VM_Dispose ();
140                         conn.Close ();
141                         notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, 0, 0, null, 0);
142                 }
143
144                 [Obsolete ("This method was poorly named; use the Detach() method instead")]
145                 public void Dispose ()
146                 {
147                         Detach ();
148                 }
149
150                 public void ForceDisconnect ()
151                 {
152                         conn.ForceDisconnect ();
153                 }
154
155                 HashSet<ThreadMirror> threadsToInvalidate = new HashSet<ThreadMirror> ();
156                 ThreadMirror[] threadsCache;
157                 object threadCacheLocker=new object();
158
159                 internal void InvalidateThreadsAndFramesCache () {
160                         lock (threadsToInvalidate) {
161                                 foreach (var thread in threadsToInvalidate)
162                                         thread.InvalidateFrames ();
163                                 threadsToInvalidate.Clear ();
164                         }
165                         lock (threadCacheLocker) {
166                                 threadsCache = null;
167                         }
168                 }
169
170                 internal void InvalidateThreadsCache () {
171                         lock (threadCacheLocker) {
172                                 threadsCache = null;
173                         }
174                 }
175
176                 internal void AddThreadToInvalidateList (ThreadMirror threadMirror)
177                 {
178                         lock (threadsToInvalidate) {
179                                 threadsToInvalidate.Add (threadMirror);
180                         }
181                 }
182
183                 public IList<ThreadMirror> GetThreads () {
184                         lock (threadCacheLocker) {
185                                 if (threadsCache == null) {
186                                         long[] ids = vm.conn.VM_GetThreads ();
187                                         threadsCache = new ThreadMirror [ids.Length];
188                                         for (int i = 0; i < ids.Length; ++i)
189                                                 threadsCache [i] = GetThread (ids [i]);
190                                 }
191                                 return threadsCache;
192                         }
193                 }
194
195                 // Same as the mirrorOf methods in JDI
196                 public PrimitiveValue CreateValue (object value) {
197                         if (value == null)
198                                 return new PrimitiveValue (vm, null);
199
200                         if (!value.GetType ().IsPrimitive)
201                                 throw new ArgumentException ("value must be of a primitive type instead of '" + value.GetType () + "'", "value");
202
203                         return new PrimitiveValue (vm, value);
204                 }
205
206                 public EnumMirror CreateEnumMirror (TypeMirror type, PrimitiveValue value) {
207                         return new EnumMirror (this, type, value);
208                 }
209
210                 //
211                 // Enable send and receive timeouts on the connection and send a keepalive event
212                 // every 'keepalive_interval' milliseconds.
213                 //
214
215                 public void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
216                 {
217                         conn.SetSocketTimeouts (send_timeout, receive_timeout, keepalive_interval);
218                 }
219
220                 //
221                 // Methods to create event request objects
222                 //
223                 public BreakpointEventRequest CreateBreakpointRequest (MethodMirror method, long il_offset) {
224                         return new BreakpointEventRequest (this, method, il_offset);
225                 }
226
227                 public BreakpointEventRequest CreateBreakpointRequest (Location loc) {
228                         if (loc == null)
229                                 throw new ArgumentNullException ("loc");
230                         CheckMirror (loc);
231                         return new BreakpointEventRequest (this, loc.Method, loc.ILOffset);
232                 }
233
234                 public StepEventRequest CreateStepRequest (ThreadMirror thread) {
235                         return new StepEventRequest (this, thread);
236                 }
237
238                 public MethodEntryEventRequest CreateMethodEntryRequest () {
239                         return new MethodEntryEventRequest (this);
240                 }
241
242                 public MethodExitEventRequest CreateMethodExitRequest () {
243                         return new MethodExitEventRequest (this);
244                 }
245
246                 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type) {
247                         return new ExceptionEventRequest (this, exc_type, true, true);
248                 }
249
250                 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught) {
251                         return new ExceptionEventRequest (this, exc_type, caught, uncaught);
252                 }
253
254                 public AssemblyLoadEventRequest CreateAssemblyLoadRequest () {
255                         return new AssemblyLoadEventRequest (this);
256                 }
257
258                 public TypeLoadEventRequest CreateTypeLoadRequest () {
259                         return new TypeLoadEventRequest (this);
260                 }
261
262                 public void EnableEvents (params EventType[] events) {
263                         EnableEvents (events, SuspendPolicy.All);
264                 }
265
266                 public void EnableEvents (EventType[] events, SuspendPolicy suspendPolicy) {
267                         foreach (EventType etype in events) {
268                                 if (etype == EventType.Breakpoint)
269                                         throw new ArgumentException ("Breakpoint events cannot be requested using EnableEvents", "events");
270                                 conn.EnableEvent (etype, suspendPolicy, null);
271                         }
272                 }
273
274                 public BreakpointEventRequest SetBreakpoint (MethodMirror method, long il_offset) {
275                         BreakpointEventRequest req = CreateBreakpointRequest (method, il_offset);
276
277                         req.Enable ();
278
279                         return req;
280                 }
281
282                 public void ClearAllBreakpoints () {
283                         conn.ClearAllBreakpoints ();
284                 }
285                 
286                 public void Disconnect () {
287                         conn.Close ();
288                 }
289
290                 //
291                 // Return a list of TypeMirror objects for all loaded types which reference the
292                 // source file FNAME. Might return false positives.
293                 // Since protocol version 2.7.
294                 //
295                 public IList<TypeMirror> GetTypesForSourceFile (string fname, bool ignoreCase) {
296                         long[] ids = conn.VM_GetTypesForSourceFile (fname, ignoreCase);
297                         var res = new TypeMirror [ids.Length];
298                         for (int i = 0; i < ids.Length; ++i)
299                                 res [i] = GetType (ids [i]);
300                         return res;
301                 }
302
303                 //
304                 // Return a list of TypeMirror objects for all loaded types named 'NAME'.
305                 // NAME should be in the the same for as with Assembly.GetType ().
306                 // Since protocol version 2.9.
307                 //
308                 public IList<TypeMirror> GetTypes (string name, bool ignoreCase) {
309                         long[] ids = conn.VM_GetTypes (name, ignoreCase);
310                         var res = new TypeMirror [ids.Length];
311                         for (int i = 0; i < ids.Length; ++i)
312                                 res [i] = GetType (ids [i]);
313                         return res;
314                 }
315                 
316                 internal void queue_event_set (EventSet es) {
317                         lock (queue_monitor) {
318                                 queue.Enqueue (es);
319                                 Monitor.Pulse (queue_monitor);
320                         }
321                 }
322
323                 internal void ErrorHandler (object sender, ErrorHandlerEventArgs args) {
324                         switch (args.ErrorCode) {
325                         case ErrorCode.INVALID_OBJECT:
326                                 throw new ObjectCollectedException ();
327                         case ErrorCode.INVALID_FRAMEID:
328                                 throw new InvalidStackFrameException ();
329                         case ErrorCode.NOT_SUSPENDED:
330                                 throw new VMNotSuspendedException ();
331                         case ErrorCode.NOT_IMPLEMENTED:
332                                 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
333                         case ErrorCode.ABSENT_INFORMATION:
334                                 throw new AbsentInformationException ();
335                         case ErrorCode.NO_SEQ_POINT_AT_IL_OFFSET:
336                                 throw new ArgumentException ("Cannot set breakpoint on the specified IL offset.");
337                         default:
338                                 throw new CommandException (args.ErrorCode);
339                         }
340                 }
341
342                 /* Wait for the debuggee to start up and connect to it */
343                 internal void connect () {
344                         conn.Connect ();
345
346                         // Test the connection
347                         version = conn.Version;
348                         if (version.MajorVersion != Connection.MAJOR_VERSION)
349                                 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));
350
351                         long root_domain_id = conn.RootDomain;
352                         root_domain = GetDomain (root_domain_id);
353                 }
354
355                 internal void notify_vm_event (EventType evtype, SuspendPolicy spolicy, int req_id, long thread_id, string vm_uri, int exit_code) {
356                         //Console.WriteLine ("Event: " + evtype + "(" + vm_uri + ")");
357
358                         switch (evtype) {
359                         case EventType.VMStart:
360                                 /* Notify the main thread that the debuggee started up */
361                                 lock (startup_monitor) {
362                                         Monitor.Pulse (startup_monitor);
363                                 }
364                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMStartEvent (vm, req_id, thread_id) }));
365                                 break;
366                         case EventType.VMDeath:
367                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDeathEvent (vm, req_id, exit_code) }));
368                                 break;
369                         case EventType.VMDisconnect:
370                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDisconnectEvent (vm, req_id) }));
371                                 break;
372                         default:
373                                 throw new Exception ();
374                         }
375                 }
376
377                 //
378                 // Methods to create instances of mirror objects
379                 //
380
381                 /*
382                 class MirrorCache<T> {
383                         static Dictionary <long, T> mirrors;
384                         static object mirror_lock = new object ();
385
386                         internal static T GetMirror (VirtualMachine vm, long id) {
387                                 lock (mirror_lock) {
388                                 if (mirrors == null)
389                                         mirrors = new Dictionary <long, T> ();
390                                 T obj;
391                                 if (!mirrors.TryGetValue (id, out obj)) {
392                                         obj = CreateMirror (vm, id);
393                                         mirrors [id] = obj;
394                                 }
395                                 return obj;
396                                 }
397                         }
398
399                         internal static T CreateMirror (VirtualMachine vm, long id) {
400                         }
401                 }
402                 */
403
404                 // FIXME: When to remove items from the cache ?
405
406                 Dictionary <long, MethodMirror> methods;
407                 object methods_lock = new object ();
408
409                 internal MethodMirror GetMethod (long id) {
410                         lock (methods_lock) {
411                                 if (methods == null)
412                                         methods = new Dictionary <long, MethodMirror> ();
413                                 MethodMirror obj;
414                                 if (id == 0)
415                                         return null;
416                                 if (!methods.TryGetValue (id, out obj)) {
417                                         obj = new MethodMirror (this, id);
418                                         methods [id] = obj;
419                                 }
420                                 return obj;
421                         }
422             }
423
424                 Dictionary <long, AssemblyMirror> assemblies;
425                 object assemblies_lock = new object ();
426
427                 internal AssemblyMirror GetAssembly (long id) {
428                         lock (assemblies_lock) {
429                                 if (assemblies == null)
430                                         assemblies = new Dictionary <long, AssemblyMirror> ();
431                                 AssemblyMirror obj;
432                                 if (id == 0)
433                                         return null;
434                                 if (!assemblies.TryGetValue (id, out obj)) {
435                                         obj = new AssemblyMirror (this, id);
436                                         assemblies [id] = obj;
437                                 }
438                                 return obj;
439                         }
440             }
441
442                 Dictionary <long, ModuleMirror> modules;
443                 object modules_lock = new object ();
444
445                 internal ModuleMirror GetModule (long id) {
446                         lock (modules_lock) {
447                                 if (modules == null)
448                                         modules = new Dictionary <long, ModuleMirror> ();
449                                 ModuleMirror obj;
450                                 if (id == 0)
451                                         return null;
452                                 if (!modules.TryGetValue (id, out obj)) {
453                                         obj = new ModuleMirror (this, id);
454                                         modules [id] = obj;
455                                 }
456                                 return obj;
457                         }
458             }
459
460                 Dictionary <long, AppDomainMirror> domains;
461                 object domains_lock = new object ();
462
463                 internal AppDomainMirror GetDomain (long id) {
464                         lock (domains_lock) {
465                                 if (domains == null)
466                                         domains = new Dictionary <long, AppDomainMirror> ();
467                                 AppDomainMirror obj;
468                                 if (id == 0)
469                                         return null;
470                                 if (!domains.TryGetValue (id, out obj)) {
471                                         obj = new AppDomainMirror (this, id);
472                                         domains [id] = obj;
473                                 }
474                                 return obj;
475                         }
476             }
477
478                 internal void InvalidateAssemblyCaches () {
479                         lock (domains_lock) {
480                                 foreach (var d in domains.Values)
481                                         d.InvalidateAssembliesCache ();
482                         }
483                 }
484
485                 Dictionary <long, TypeMirror> types;
486                 object types_lock = new object ();
487
488                 internal TypeMirror GetType (long id) {
489                         lock (types_lock) {
490                                 if (types == null)
491                                         types = new Dictionary <long, TypeMirror> ();
492                                 TypeMirror obj;
493                                 if (id == 0)
494                                         return null;
495                                 if (!types.TryGetValue (id, out obj)) {
496                                         obj = new TypeMirror (this, id);
497                                         types [id] = obj;
498                                 }
499                                 return obj;
500                         }
501             }
502
503                 internal TypeMirror[] GetTypes (long[] ids) {
504                         var res = new TypeMirror [ids.Length];
505                         for (int i = 0; i < ids.Length; ++i)
506                                 res [i] = GetType (ids [i]);
507                         return res;
508                 }
509
510                 Dictionary <long, ObjectMirror> objects;
511                 object objects_lock = new object ();
512
513                 internal T GetObject<T> (long id, long domain_id, long type_id) where T : ObjectMirror {
514                         lock (objects_lock) {
515                                 if (objects == null)
516                                         objects = new Dictionary <long, ObjectMirror> ();
517                                 ObjectMirror obj;
518                                 if (!objects.TryGetValue (id, out obj)) {
519                                         /*
520                                          * Obtain the domain/type of the object to determine the type of
521                                          * object we need to create.
522                                          */
523                                         if (domain_id == 0 || type_id == 0) {
524                                                 if (conn.Version.AtLeast (2, 5)) {
525                                                         var info = conn.Object_GetInfo (id);
526                                                         domain_id = info.domain_id;
527                                                         type_id = info.type_id;
528                                                 } else {
529                                                         if (domain_id == 0)
530                                                                 domain_id = conn.Object_GetDomain (id);
531                                                         if (type_id == 0)
532                                                                 type_id = conn.Object_GetType (id);
533                                                 }
534                                         }
535                                         AppDomainMirror d = GetDomain (domain_id);
536                                         TypeMirror t = GetType (type_id);
537
538                                         if (t.Assembly == d.Corlib && t.Namespace == "System.Threading" && t.Name == "Thread")
539                                                 obj = new ThreadMirror (this, id, t, d);
540                                         else if (t.Assembly == d.Corlib && t.Namespace == "System" && t.Name == "String")
541                                                 obj = new StringMirror (this, id, t, d);
542                                         else if (typeof (T) == typeof (ArrayMirror))
543                                                 obj = new ArrayMirror (this, id, t, d);
544                                         else
545                                                 obj = new ObjectMirror (this, id, t, d);
546                                         objects [id] = obj;
547                                 }
548                                 return (T)obj;
549                         }
550             }
551
552                 internal T GetObject<T> (long id) where T : ObjectMirror {
553                         return GetObject<T> (id, 0, 0);
554                 }
555
556                 internal ObjectMirror GetObject (long objid) {
557                         return GetObject<ObjectMirror> (objid);
558                 }
559
560                 internal ThreadMirror GetThread (long id) {
561                         return GetObject <ThreadMirror> (id);
562                 }
563
564                 Dictionary <long, FieldInfoMirror> fields;
565                 object fields_lock = new object ();
566
567                 internal FieldInfoMirror GetField (long id) {
568                         lock (fields_lock) {
569                                 if (fields == null)
570                                         fields = new Dictionary <long, FieldInfoMirror> ();
571                                 FieldInfoMirror obj;
572                                 if (id == 0)
573                                         return null;
574                                 if (!fields.TryGetValue (id, out obj)) {
575                                         obj = new FieldInfoMirror (this, id);
576                                         fields [id] = obj;
577                                 }
578                                 return obj;
579                         }
580             }
581
582                 object requests_lock = new object ();
583
584                 internal void AddRequest (EventRequest req, int id) {
585                         lock (requests_lock) {
586                                 requests [id] = req;
587                         }
588                 }
589
590                 internal void RemoveRequest (EventRequest req, int id) {
591                         lock (requests_lock) {
592                                 requests.Remove (id);
593                         }
594                 }
595
596                 internal EventRequest GetRequest (int id) {
597                         lock (requests_lock) {
598                                 return requests [id];
599                         }
600                 }
601
602                 internal Value DecodeValue (ValueImpl v) {
603                         return DecodeValue (v, null);
604                 }
605
606                 internal Value DecodeValue (ValueImpl v, Dictionary<int, Value> parent_vtypes) {
607                         if (v.Value != null)
608                                 return new PrimitiveValue (this, v.Value);
609
610                         switch (v.Type) {
611                         case ElementType.Void:
612                                 return null;
613                         case ElementType.SzArray:
614                         case ElementType.Array:
615                                 return GetObject<ArrayMirror> (v.Objid);
616                         case ElementType.String:
617                                 return GetObject<StringMirror> (v.Objid);
618                         case ElementType.Class:
619                         case ElementType.Object:
620                                 return GetObject (v.Objid);
621                         case ElementType.ValueType:
622                                 if (parent_vtypes == null)
623                                         parent_vtypes = new Dictionary<int, Value> ();
624                                 StructMirror vtype;
625                                 if (v.IsEnum)
626                                         vtype = new EnumMirror (this, GetType (v.Klass), (Value[])null);
627                                 else
628                                         vtype = new StructMirror (this, GetType (v.Klass), (Value[])null);
629                                 parent_vtypes [parent_vtypes.Count] = vtype;
630                                 vtype.SetFields (DecodeValues (v.Fields, parent_vtypes));
631                                 parent_vtypes.Remove (parent_vtypes.Count - 1);
632                                 return vtype;
633                         case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
634                                 return new PrimitiveValue (this, null);
635                         case (ElementType)ValueTypeId.VALUE_TYPE_ID_PARENT_VTYPE:
636                                 return parent_vtypes [v.Index];
637                         default:
638                                 throw new NotImplementedException ("" + v.Type);
639                         }
640                 }
641
642                 internal Value[] DecodeValues (ValueImpl[] values) {
643                         Value[] res = new Value [values.Length];
644                         for (int i = 0; i < values.Length; ++i)
645                                 res [i] = DecodeValue (values [i]);
646                         return res;
647                 }
648
649                 internal Value[] DecodeValues (ValueImpl[] values, Dictionary<int, Value> parent_vtypes) {
650                         Value[] res = new Value [values.Length];
651                         for (int i = 0; i < values.Length; ++i)
652                                 res [i] = DecodeValue (values [i], parent_vtypes);
653                         return res;
654                 }
655
656                 internal ValueImpl EncodeValue (Value v) {
657                         if (v is PrimitiveValue) {
658                                 object val = (v as PrimitiveValue).Value;
659                                 if (val == null)
660                                         return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
661                                 else
662                                         return new ValueImpl { Value = val };
663                         } else if (v is ObjectMirror) {
664                                 return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
665                         } else if (v is StructMirror) {
666                                 return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields) };
667                         } else {
668                                 throw new NotSupportedException ();
669                         }
670                 }
671
672                 internal ValueImpl[] EncodeValues (IList<Value> values) {
673                         ValueImpl[] res = new ValueImpl [values.Count];
674                         for (int i = 0; i < values.Count; ++i)
675                                 res [i] = EncodeValue (values [i]);
676                         return res;
677                 }
678
679                 internal void CheckProtocolVersion (int major, int minor) {
680                         if (!conn.Version.AtLeast (major, minor))
681                                 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
682                 }
683     }
684
685         class EventHandler : MarshalByRefObject, IEventHandler
686         {               
687                 VirtualMachine vm;
688
689                 public EventHandler (VirtualMachine vm) {
690                         this.vm = vm;
691                 }
692
693                 public void Events (SuspendPolicy suspend_policy, EventInfo[] events) {
694                         var l = new List<Event> ();
695
696                         for (int i = 0; i < events.Length; ++i) {
697                                 EventInfo ei = events [i];
698                                 int req_id = ei.ReqId;
699                                 long thread_id = ei.ThreadId;
700                                 long id = ei.Id;
701                                 long loc = ei.Location;
702
703                                 switch (ei.EventType) {
704                                 case EventType.VMStart:
705                                         vm.notify_vm_event (EventType.VMStart, suspend_policy, req_id, thread_id, null, 0);
706                                         break;
707                                 case EventType.VMDeath:
708                                         vm.notify_vm_event (EventType.VMDeath, suspend_policy, req_id, thread_id, null, ei.ExitCode);
709                                         break;
710                                 case EventType.ThreadStart:
711                                         vm.InvalidateThreadsCache ();
712                                         l.Add (new ThreadStartEvent (vm, req_id, id));
713                                         break;
714                                 case EventType.ThreadDeath:
715                                         vm.InvalidateThreadsCache ();
716                                         l.Add (new ThreadDeathEvent (vm, req_id, id));
717                                         break;
718                                 case EventType.AssemblyLoad:
719                                         vm.InvalidateAssemblyCaches ();
720                                         l.Add (new AssemblyLoadEvent (vm, req_id, thread_id, id));
721                                         break;
722                                 case EventType.AssemblyUnload:
723                                         vm.InvalidateAssemblyCaches ();
724                                         l.Add (new AssemblyUnloadEvent (vm, req_id, thread_id, id));
725                                         break;
726                                 case EventType.TypeLoad:
727                                         l.Add (new TypeLoadEvent (vm, req_id, thread_id, id));
728                                         break;
729                                 case EventType.MethodEntry:
730                                         l.Add (new MethodEntryEvent (vm, req_id, thread_id, id));
731                                         break;
732                                 case EventType.MethodExit:
733                                         l.Add (new MethodExitEvent (vm, req_id, thread_id, id));
734                                         break;
735                                 case EventType.Breakpoint:
736                                         l.Add (new BreakpointEvent (vm, req_id, thread_id, id, loc));
737                                         break;
738                                 case EventType.Step:
739                                         l.Add (new StepEvent (vm, req_id, thread_id, id, loc));
740                                         break;
741                                 case EventType.Exception:
742                                         l.Add (new ExceptionEvent (vm, req_id, thread_id, id, loc));
743                                         break;
744                                 case EventType.AppDomainCreate:
745                                         l.Add (new AppDomainCreateEvent (vm, req_id, thread_id, id));
746                                         break;
747                                 case EventType.AppDomainUnload:
748                                         l.Add (new AppDomainUnloadEvent (vm, req_id, thread_id, id));
749                                         break;
750                                 case EventType.UserBreak:
751                                         l.Add (new UserBreakEvent (vm, req_id, thread_id));
752                                         break;
753                                 case EventType.UserLog:
754                                         l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message));
755                                         break;
756                                 default:
757                                         break;
758                                 }
759                         }
760                         
761                         if (l.Count > 0)
762                                 vm.queue_event_set (new EventSet (vm, suspend_policy, l.ToArray ()));
763                 }
764
765                 public void VMDisconnect (int req_id, long thread_id, string vm_uri) {
766                         vm.notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, req_id, thread_id, vm_uri, 0);
767         }
768     }
769
770         public class CommandException : Exception {
771
772                 internal CommandException (ErrorCode error_code) : base ("Debuggee returned error code " + error_code + ".") {
773                         ErrorCode = error_code;
774                 }
775
776                 public ErrorCode ErrorCode {
777                         get; set;
778                 }
779         }
780
781         public class VMNotSuspendedException : InvalidOperationException
782         {
783                 public VMNotSuspendedException () : base ("The vm is not suspended.")
784                 {
785                 }
786         }
787 }