Merge pull request #121 from LogosBible/processfixes
[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                                 return conn.EndPoint;
65                         }
66                 }
67
68                 public VersionInfo Version {
69                         get {
70                                 return version;
71                         }
72                 }
73
74                 EventSet current_es;
75                 int current_es_index;
76
77                 /*
78                  * It is impossible to determine when to resume when using this method, since
79                  * the debuggee is suspended only once per event-set, not event.
80                  */
81                 [Obsolete ("Use GetNextEventSet () instead")]
82                 public Event GetNextEvent () {
83                         lock (queue_monitor) {
84                                 if (current_es == null || current_es_index == current_es.Events.Length) {
85                                         if (queue.Count == 0)
86                                                 Monitor.Wait (queue_monitor);
87                                         current_es = (EventSet)queue.Dequeue ();
88                                         current_es_index = 0;
89                                 }
90                                 return current_es.Events [current_es_index ++];
91                         }
92                 }
93
94                 public Event GetNextEvent (int timeout) {
95                         throw new NotImplementedException ();
96                 }
97
98                 public EventSet GetNextEventSet () {
99                         lock (queue_monitor) {
100                                 if (queue.Count == 0)
101                                         Monitor.Wait (queue_monitor);
102
103                                 current_es = null;
104                                 current_es_index = 0;
105
106                                 return (EventSet)queue.Dequeue ();
107                         }
108                 }
109
110                 [Obsolete ("Use GetNextEventSet () instead")]
111                 public T GetNextEvent<T> () where T : Event {
112                         return GetNextEvent () as T;
113                 }
114
115                 public void Suspend () {
116                         conn.VM_Suspend ();
117             }
118
119                 public void Resume () {
120                         try {
121                                 conn.VM_Resume ();
122                         } catch (CommandException ex) {
123                                 if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
124                                         throw new InvalidOperationException ("The vm is not suspended.");
125                                 else
126                                         throw;
127                         }
128             }
129
130                 public void Exit (int exitCode) {
131                         conn.VM_Exit (exitCode);
132                 }
133
134                 public void Dispose () {
135                         conn.VM_Dispose ();
136                         conn.Close ();
137                         notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, 0, 0, null);
138                 }
139
140                 public IList<ThreadMirror> GetThreads () {
141                         long[] ids = vm.conn.VM_GetThreads ();
142                         ThreadMirror[] res = new ThreadMirror [ids.Length];
143                         for (int i = 0; i < ids.Length; ++i)
144                                 res [i] = GetThread (ids [i]);
145                         return res;
146                 }
147
148                 // Same as the mirrorOf methods in JDI
149                 public PrimitiveValue CreateValue (object value) {
150                         if (value == null)
151                                 return new PrimitiveValue (vm, null);
152
153                         if (!value.GetType ().IsPrimitive)
154                                 throw new ArgumentException ("value must be of a primitive type instead of '" + value.GetType () + "'", "value");
155
156                         return new PrimitiveValue (vm, value);
157                 }
158
159                 public EnumMirror CreateEnumMirror (TypeMirror type, PrimitiveValue value) {
160                         return new EnumMirror (this, type, value);
161                 }
162
163                 //
164                 // Enable send and receive timeouts on the connection and send a keepalive event
165                 // every 'keepalive_interval' milliseconds.
166                 //
167
168                 public void SetSocketTimeouts (int send_timeout, int receive_timeout, int keepalive_interval)
169                 {
170                         conn.SetSocketTimeouts (send_timeout, receive_timeout, keepalive_interval);
171                 }
172
173                 //
174                 // Methods to create event request objects
175                 //
176                 public BreakpointEventRequest CreateBreakpointRequest (MethodMirror method, long il_offset) {
177                         return new BreakpointEventRequest (this, method, il_offset);
178                 }
179
180                 public BreakpointEventRequest CreateBreakpointRequest (Location loc) {
181                         if (loc == null)
182                                 throw new ArgumentNullException ("loc");
183                         CheckMirror (loc);
184                         return new BreakpointEventRequest (this, loc.Method, loc.ILOffset);
185                 }
186
187                 public StepEventRequest CreateStepRequest (ThreadMirror thread) {
188                         return new StepEventRequest (this, thread);
189                 }
190
191                 public MethodEntryEventRequest CreateMethodEntryRequest () {
192                         return new MethodEntryEventRequest (this);
193                 }
194
195                 public MethodExitEventRequest CreateMethodExitRequest () {
196                         return new MethodExitEventRequest (this);
197                 }
198
199                 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type) {
200                         return new ExceptionEventRequest (this, exc_type, true, true);
201                 }
202
203                 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught) {
204                         return new ExceptionEventRequest (this, exc_type, caught, uncaught);
205                 }
206
207                 public AssemblyLoadEventRequest CreateAssemblyLoadRequest () {
208                         return new AssemblyLoadEventRequest (this);
209                 }
210
211                 public void EnableEvents (params EventType[] events) {
212                         foreach (EventType etype in events) {
213                                 if (etype == EventType.Breakpoint)
214                                         throw new ArgumentException ("Breakpoint events cannot be requested using EnableEvents", "events");
215                                 conn.EnableEvent (etype, SuspendPolicy.All, null);
216                         }
217                 }
218
219                 public BreakpointEventRequest SetBreakpoint (MethodMirror method, long il_offset) {
220                         BreakpointEventRequest req = CreateBreakpointRequest (method, il_offset);
221
222                         req.Enable ();
223
224                         return req;
225                 }
226
227                 public void ClearAllBreakpoints () {
228                         conn.ClearAllBreakpoints ();
229                 }
230                 
231                 public void Disconnect () {
232                         conn.Close ();
233                 }
234                 
235                 internal void queue_event_set (EventSet es) {
236                         lock (queue_monitor) {
237                                 queue.Enqueue (es);
238                                 Monitor.Pulse (queue_monitor);
239                         }
240                 }
241
242                 internal void ErrorHandler (object sender, ErrorHandlerEventArgs args) {
243                         switch (args.ErrorCode) {
244                         case ErrorCode.INVALID_OBJECT:
245                                 throw new ObjectCollectedException ();
246                         case ErrorCode.INVALID_FRAMEID:
247                                 throw new InvalidStackFrameException ();
248                         case ErrorCode.NOT_SUSPENDED:
249                                 throw new InvalidOperationException ("The vm is not suspended.");
250                         case ErrorCode.NOT_IMPLEMENTED:
251                                 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
252                         case ErrorCode.ABSENT_INFORMATION:
253                                 throw new AbsentInformationException ();
254                         case ErrorCode.NO_SEQ_POINT_AT_IL_OFFSET:
255                                 throw new ArgumentException ("Cannot set breakpoint on the specified IL offset.");
256                         default:
257                                 throw new CommandException (args.ErrorCode);
258                         }
259                 }
260
261                 /* Wait for the debuggee to start up and connect to it */
262                 internal void connect () {
263                         conn.Connect ();
264
265                         // Test the connection
266                         version = conn.Version;
267                         if (version.MajorVersion != Connection.MAJOR_VERSION)
268                                 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));
269
270                         long root_domain_id = conn.RootDomain;
271                         root_domain = GetDomain (root_domain_id);
272                 }
273
274                 internal void notify_vm_event (EventType evtype, SuspendPolicy spolicy, int req_id, long thread_id, string vm_uri) {
275                         //Console.WriteLine ("Event: " + evtype + "(" + vm_uri + ")");
276
277                         switch (evtype) {
278                         case EventType.VMStart:
279                                 /* Notify the main thread that the debuggee started up */
280                                 lock (startup_monitor) {
281                                         Monitor.Pulse (startup_monitor);
282                                 }
283                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMStartEvent (vm, req_id, thread_id) }));
284                                 break;
285                         case EventType.VMDeath:
286                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDeathEvent (vm, req_id) }));
287                                 break;
288                         case EventType.VMDisconnect:
289                                 queue_event_set (new EventSet (this, spolicy, new Event[] { new VMDisconnectEvent (vm, req_id) }));
290                                 break;
291                         default:
292                                 throw new Exception ();
293                         }
294                 }
295
296                 //
297                 // Methods to create instances of mirror objects
298                 //
299
300                 /*
301                 class MirrorCache<T> {
302                         static Dictionary <long, T> mirrors;
303                         static object mirror_lock = new object ();
304
305                         internal static T GetMirror (VirtualMachine vm, long id) {
306                                 lock (mirror_lock) {
307                                 if (mirrors == null)
308                                         mirrors = new Dictionary <long, T> ();
309                                 T obj;
310                                 if (!mirrors.TryGetValue (id, out obj)) {
311                                         obj = CreateMirror (vm, id);
312                                         mirrors [id] = obj;
313                                 }
314                                 return obj;
315                                 }
316                         }
317
318                         internal static T CreateMirror (VirtualMachine vm, long id) {
319                         }
320                 }
321                 */
322
323                 // FIXME: When to remove items from the cache ?
324
325                 Dictionary <long, MethodMirror> methods;
326                 object methods_lock = new object ();
327
328                 internal MethodMirror GetMethod (long id) {
329                         lock (methods_lock) {
330                                 if (methods == null)
331                                         methods = new Dictionary <long, MethodMirror> ();
332                                 MethodMirror obj;
333                                 if (id == 0)
334                                         return null;
335                                 if (!methods.TryGetValue (id, out obj)) {
336                                         obj = new MethodMirror (this, id);
337                                         methods [id] = obj;
338                                 }
339                                 return obj;
340                         }
341             }
342
343                 Dictionary <long, AssemblyMirror> assemblies;
344                 object assemblies_lock = new object ();
345
346                 internal AssemblyMirror GetAssembly (long id) {
347                         lock (assemblies_lock) {
348                                 if (assemblies == null)
349                                         assemblies = new Dictionary <long, AssemblyMirror> ();
350                                 AssemblyMirror obj;
351                                 if (id == 0)
352                                         return null;
353                                 if (!assemblies.TryGetValue (id, out obj)) {
354                                         obj = new AssemblyMirror (this, id);
355                                         assemblies [id] = obj;
356                                 }
357                                 return obj;
358                         }
359             }
360
361                 Dictionary <long, ModuleMirror> modules;
362                 object modules_lock = new object ();
363
364                 internal ModuleMirror GetModule (long id) {
365                         lock (modules_lock) {
366                                 if (modules == null)
367                                         modules = new Dictionary <long, ModuleMirror> ();
368                                 ModuleMirror obj;
369                                 if (id == 0)
370                                         return null;
371                                 if (!modules.TryGetValue (id, out obj)) {
372                                         obj = new ModuleMirror (this, id);
373                                         modules [id] = obj;
374                                 }
375                                 return obj;
376                         }
377             }
378
379                 Dictionary <long, AppDomainMirror> domains;
380                 object domains_lock = new object ();
381
382                 internal AppDomainMirror GetDomain (long id) {
383                         lock (domains_lock) {
384                                 if (domains == null)
385                                         domains = new Dictionary <long, AppDomainMirror> ();
386                                 AppDomainMirror obj;
387                                 if (id == 0)
388                                         return null;
389                                 if (!domains.TryGetValue (id, out obj)) {
390                                         obj = new AppDomainMirror (this, id);
391                                         domains [id] = obj;
392                                 }
393                                 return obj;
394                         }
395             }
396
397                 Dictionary <long, TypeMirror> types;
398                 object types_lock = new object ();
399
400                 internal TypeMirror GetType (long id) {
401                         lock (types_lock) {
402                                 if (types == null)
403                                         types = new Dictionary <long, TypeMirror> ();
404                                 TypeMirror obj;
405                                 if (id == 0)
406                                         return null;
407                                 if (!types.TryGetValue (id, out obj)) {
408                                         obj = new TypeMirror (this, id);
409                                         types [id] = obj;
410                                 }
411                                 return obj;
412                         }
413             }
414
415                 Dictionary <long, ObjectMirror> objects;
416                 object objects_lock = new object ();
417
418                 internal T GetObject<T> (long id, long domain_id, long type_id) where T : ObjectMirror {
419                         lock (objects_lock) {
420                                 if (objects == null)
421                                         objects = new Dictionary <long, ObjectMirror> ();
422                                 ObjectMirror obj;
423                                 if (!objects.TryGetValue (id, out obj)) {
424                                         /*
425                                          * Obtain the domain/type of the object to determine the type of
426                                          * object we need to create.
427                                          */
428                                         if (domain_id == 0)
429                                                 domain_id = conn.Object_GetDomain (id);
430                                         AppDomainMirror d = GetDomain (domain_id);
431
432                                         if (type_id == 0)
433                                                 type_id = conn.Object_GetType (id);
434                                         TypeMirror t = GetType (type_id);
435
436                                         if (t.Assembly == d.Corlib && t.Namespace == "System.Threading" && t.Name == "Thread")
437                                                 obj = new ThreadMirror (this, id);
438                                         else if (t.Assembly == d.Corlib && t.Namespace == "System" && t.Name == "String")
439                                                 obj = new StringMirror (this, id);
440                                         else if (typeof (T) == typeof (ArrayMirror))
441                                                 obj = new ArrayMirror (this, id);
442                                         else
443                                                 obj = new ObjectMirror (this, id);
444                                         objects [id] = obj;
445                                 }
446                                 return (T)obj;
447                         }
448             }
449
450                 internal T GetObject<T> (long id) where T : ObjectMirror {
451                         return GetObject<T> (id, 0, 0);
452                 }
453
454                 internal ObjectMirror GetObject (long objid) {
455                         return GetObject<ObjectMirror> (objid);
456                 }
457
458                 internal ThreadMirror GetThread (long id) {
459                         return GetObject <ThreadMirror> (id);
460                 }
461
462                 object requests_lock = new object ();
463
464                 internal void AddRequest (EventRequest req, int id) {
465                         lock (requests_lock) {
466                                 requests [id] = req;
467                         }
468                 }
469
470                 internal void RemoveRequest (EventRequest req, int id) {
471                         lock (requests_lock) {
472                                 requests.Remove (id);
473                         }
474                 }
475
476                 internal EventRequest GetRequest (int id) {
477                         lock (requests_lock) {
478                                 return requests [id];
479                         }
480                 }
481
482                 internal Value DecodeValue (ValueImpl v) {
483                         if (v.Value != null)
484                                 return new PrimitiveValue (this, v.Value);
485
486                         switch (v.Type) {
487                         case ElementType.Void:
488                                 return null;
489                         case ElementType.SzArray:
490                         case ElementType.Array:
491                                 return GetObject<ArrayMirror> (v.Objid);
492                         case ElementType.String:
493                                 return GetObject<StringMirror> (v.Objid);
494                         case ElementType.Class:
495                         case ElementType.Object:
496                                 return GetObject (v.Objid);
497                         case ElementType.ValueType:
498                                 if (v.IsEnum)
499                                         return new EnumMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
500                                 else
501                                         return new StructMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
502                         case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
503                                 return new PrimitiveValue (this, null);
504                         default:
505                                 throw new NotImplementedException ("" + v.Type);
506                         }
507                 }
508
509                 internal Value[] DecodeValues (ValueImpl[] values) {
510                         Value[] res = new Value [values.Length];
511                         for (int i = 0; i < values.Length; ++i)
512                                 res [i] = DecodeValue (values [i]);
513                         return res;
514                 }
515
516                 internal ValueImpl EncodeValue (Value v) {
517                         if (v is PrimitiveValue) {
518                                 object val = (v as PrimitiveValue).Value;
519                                 if (val == null)
520                                         return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
521                                 else
522                                         return new ValueImpl { Value = val };
523                         } else if (v is ObjectMirror) {
524                                 return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
525                         } else if (v is StructMirror) {
526                                 return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields) };
527                         } else {
528                                 throw new NotSupportedException ();
529                         }
530                 }
531
532                 internal ValueImpl[] EncodeValues (IList<Value> values) {
533                         ValueImpl[] res = new ValueImpl [values.Count];
534                         for (int i = 0; i < values.Count; ++i)
535                                 res [i] = EncodeValue (values [i]);
536                         return res;
537                 }
538     }
539
540         class EventHandler : MarshalByRefObject, IEventHandler
541         {               
542                 VirtualMachine vm;
543
544                 public EventHandler (VirtualMachine vm) {
545                         this.vm = vm;
546                 }
547
548                 public void Events (SuspendPolicy suspend_policy, EventInfo[] events) {
549                         var l = new List<Event> ();
550
551                         for (int i = 0; i < events.Length; ++i) {
552                                 EventInfo ei = events [i];
553                                 int req_id = ei.ReqId;
554                                 long thread_id = ei.ThreadId;
555                                 long id = ei.Id;
556                                 long loc = ei.Location;
557
558                                 switch (ei.EventType) {
559                                 case EventType.VMStart:
560                                         vm.notify_vm_event (EventType.VMStart, suspend_policy, req_id, thread_id, null);
561                                         break;
562                                 case EventType.VMDeath:
563                                         vm.notify_vm_event (EventType.VMDeath, suspend_policy, req_id, thread_id, null);
564                                         break;
565                                 case EventType.ThreadStart:
566                                         l.Add (new ThreadStartEvent (vm, req_id, id));
567                                         break;
568                                 case EventType.ThreadDeath:
569                                         l.Add (new ThreadDeathEvent (vm, req_id, id));
570                                         break;
571                                 case EventType.AssemblyLoad:
572                                         l.Add (new AssemblyLoadEvent (vm, req_id, thread_id, id));
573                                         break;
574                                 case EventType.AssemblyUnload:
575                                         l.Add (new AssemblyUnloadEvent (vm, req_id, thread_id, id));
576                                         break;
577                                 case EventType.TypeLoad:
578                                         l.Add (new TypeLoadEvent (vm, req_id, thread_id, id));
579                                         break;
580                                 case EventType.MethodEntry:
581                                         l.Add (new MethodEntryEvent (vm, req_id, thread_id, id));
582                                         break;
583                                 case EventType.MethodExit:
584                                         l.Add (new MethodExitEvent (vm, req_id, thread_id, id));
585                                         break;
586                                 case EventType.Breakpoint:
587                                         l.Add (new BreakpointEvent (vm, req_id, thread_id, id, loc));
588                                         break;
589                                 case EventType.Step:
590                                         l.Add (new StepEvent (vm, req_id, thread_id, id, loc));
591                                         break;
592                                 case EventType.Exception:
593                                         l.Add (new ExceptionEvent (vm, req_id, thread_id, id, loc));
594                                         break;
595                                 case EventType.AppDomainCreate:
596                                         l.Add (new AppDomainCreateEvent (vm, req_id, thread_id, id));
597                                         break;
598                                 case EventType.AppDomainUnload:
599                                         l.Add (new AppDomainUnloadEvent (vm, req_id, thread_id, id));
600                                         break;
601                                 case EventType.UserBreak:
602                                         l.Add (new UserBreakEvent (vm, req_id, thread_id));
603                                         break;
604                                 case EventType.UserLog:
605                                         l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message));
606                                         break;
607                                 default:
608                                         break;
609                                 }
610                         }
611                         
612                         if (l.Count > 0)
613                                 vm.queue_event_set (new EventSet (vm, suspend_policy, l.ToArray ()));
614                 }
615
616                 public void VMDisconnect (int req_id, long thread_id, string vm_uri) {
617                         vm.notify_vm_event (EventType.VMDisconnect, SuspendPolicy.None, req_id, thread_id, vm_uri);
618         }
619     }
620
621         internal class CommandException : Exception {
622
623                 public CommandException (ErrorCode error_code) : base ("Debuggee returned error code " + error_code + ".") {
624                         ErrorCode = error_code;
625                 }
626
627                 public ErrorCode ErrorCode {
628                         get; set;
629                 }
630         }
631 }