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