3 using System.Threading;
5 using System.Diagnostics;
6 using System.Collections;
7 using System.Collections.Generic;
8 using Mono.Cecil.Metadata;
10 namespace Mono.Debugger.Soft
12 public class VirtualMachine : Mirror
16 object startup_monitor;
17 AppDomainMirror root_domain;
18 Dictionary<int, EventRequest> requests;
21 internal Connection conn;
23 internal VirtualMachine (IProcess process, Connection conn) : base () {
24 SetVirtualMachine (this);
26 queue_monitor = new Object ();
27 startup_monitor = new Object ();
28 requests = new Dictionary <int, EventRequest> ();
30 this.process = process;
31 conn.ErrorHandler += ErrorHandler;
34 // The standard output of the process is available normally through Process
35 public StreamReader StandardOutput { get; set; }
36 public StreamReader StandardError { get; set; }
38 public IProcess Process {
44 public AppDomainMirror RootDomain {
50 public EndPoint EndPoint {
56 public Event GetNextEvent () {
57 lock (queue_monitor) {
59 Monitor.Wait (queue_monitor);
60 return (Event)queue.Dequeue ();
64 public Event GetNextEvent (int timeout) {
65 throw new NotImplementedException ();
68 public T GetNextEvent<T> () where T : Event {
69 return GetNextEvent () as T;
72 public void Suspend () {
76 public void Resume () {
79 } catch (CommandException ex) {
80 if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
81 throw new InvalidOperationException ("The vm is not suspended.");
87 public void Exit (int exitCode) {
88 conn.VM_Exit (exitCode);
91 public void Dispose () {
94 notify_vm_event (EventType.VMDisconnect, 0, 0, null);
97 public IList<ThreadMirror> GetThreads () {
98 long[] ids = vm.conn.VM_GetThreads ();
99 ThreadMirror[] res = new ThreadMirror [ids.Length];
100 for (int i = 0; i < ids.Length; ++i)
101 res [i] = GetThread (ids [i]);
105 // Same as the mirrorOf methods in JDI
106 public PrimitiveValue CreateValue (object value) {
108 return new PrimitiveValue (vm, null);
110 if (!value.GetType ().IsPrimitive)
111 throw new ArgumentException ("value must be of a primitive type instead of '" + value.GetType () + "'", "value");
113 return new PrimitiveValue (vm, value);
116 public EnumMirror CreateEnumMirror (TypeMirror type, PrimitiveValue value) {
117 return new EnumMirror (this, type, value);
121 // Methods to create event request objects
123 public BreakpointEventRequest CreateBreakpointRequest (MethodMirror method, long il_offset) {
124 return new BreakpointEventRequest (this, method, il_offset);
127 public BreakpointEventRequest CreateBreakpointRequest (Location loc) {
129 throw new ArgumentNullException ("loc");
131 return new BreakpointEventRequest (this, loc.Method, loc.ILOffset);
134 public StepEventRequest CreateStepRequest (ThreadMirror thread) {
135 return new StepEventRequest (this, thread);
138 public MethodEntryEventRequest CreateMethodEntryRequest () {
139 return new MethodEntryEventRequest (this);
142 public MethodExitEventRequest CreateMethodExitRequest () {
143 return new MethodExitEventRequest (this);
146 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type) {
147 return new ExceptionEventRequest (this, exc_type, true, true);
150 public ExceptionEventRequest CreateExceptionRequest (TypeMirror exc_type, bool caught, bool uncaught) {
151 return new ExceptionEventRequest (this, exc_type, caught, uncaught);
154 public void EnableEvents (params EventType[] events) {
155 foreach (EventType etype in events)
156 conn.EnableEvent (etype, SuspendPolicy.All, null);
159 public BreakpointEventRequest SetBreakpoint (MethodMirror method, long il_offset) {
160 BreakpointEventRequest req = CreateBreakpointRequest (method, il_offset);
167 public void ClearAllBreakpoints () {
168 conn.ClearAllBreakpoints ();
171 internal void queue_event (Event e) {
172 lock (queue_monitor) {
174 Monitor.Pulse (queue_monitor);
178 internal void ErrorHandler (object sender, ErrorHandlerEventArgs args) {
179 switch (args.ErrorCode) {
180 case ErrorCode.INVALID_OBJECT:
181 throw new ObjectCollectedException ();
182 case ErrorCode.INVALID_FRAMEID:
183 throw new InvalidStackFrameException ();
184 case ErrorCode.NOT_SUSPENDED:
185 throw new InvalidOperationException ("The vm is not suspended.");
186 case ErrorCode.NOT_IMPLEMENTED:
187 throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
189 throw new CommandException (args.ErrorCode);
193 /* Wait for the debuggee to start up and connect to it */
194 internal void connect () {
197 // Test the connection
198 VersionInfo ver = conn.Version;
199 if (ver.MajorVersion != Connection.MAJOR_VERSION)
200 throw new NotSupportedException (String.Format ("The debuggee implements protocol version {0}.{1}, while {2}.{3} is required.", ver.MajorVersion, ver.MinorVersion, Connection.MAJOR_VERSION, Connection.MINOR_VERSION));
202 long root_domain_id = conn.RootDomain;
203 root_domain = GetDomain (root_domain_id);
206 internal void notify_vm_event (EventType evtype, int req_id, long thread_id, string vm_uri) {
207 //Console.WriteLine ("Event: " + evtype + "(" + vm_uri + ")");
210 case EventType.VMStart:
211 /* Notify the main thread that the debuggee started up */
212 lock (startup_monitor) {
213 Monitor.Pulse (startup_monitor);
215 queue_event (new VMStartEvent (vm, req_id, thread_id));
217 case EventType.VMDeath:
218 queue_event (new VMDeathEvent (vm, req_id));
220 case EventType.VMDisconnect:
221 queue_event (new VMDisconnectEvent (vm, req_id));
224 throw new Exception ();
229 // Methods to create instances of mirror objects
233 class MirrorCache<T> {
234 static Dictionary <long, T> mirrors;
235 static object mirror_lock = new object ();
237 internal static T GetMirror (VirtualMachine vm, long id) {
240 mirrors = new Dictionary <long, T> ();
242 if (!mirrors.TryGetValue (id, out obj)) {
243 obj = CreateMirror (vm, id);
250 internal static T CreateMirror (VirtualMachine vm, long id) {
255 // FIXME: When to remove items from the cache ?
257 Dictionary <long, MethodMirror> methods;
258 object methods_lock = new object ();
260 internal MethodMirror GetMethod (long id) {
261 lock (methods_lock) {
263 methods = new Dictionary <long, MethodMirror> ();
267 if (!methods.TryGetValue (id, out obj)) {
268 obj = new MethodMirror (this, id);
275 Dictionary <long, AssemblyMirror> assemblies;
276 object assemblies_lock = new object ();
278 internal AssemblyMirror GetAssembly (long id) {
279 lock (assemblies_lock) {
280 if (assemblies == null)
281 assemblies = new Dictionary <long, AssemblyMirror> ();
285 if (!assemblies.TryGetValue (id, out obj)) {
286 obj = new AssemblyMirror (this, id);
287 assemblies [id] = obj;
293 Dictionary <long, ModuleMirror> modules;
294 object modules_lock = new object ();
296 internal ModuleMirror GetModule (long id) {
297 lock (modules_lock) {
299 modules = new Dictionary <long, ModuleMirror> ();
303 if (!modules.TryGetValue (id, out obj)) {
304 obj = new ModuleMirror (this, id);
311 Dictionary <long, AppDomainMirror> domains;
312 object domains_lock = new object ();
314 internal AppDomainMirror GetDomain (long id) {
315 lock (domains_lock) {
317 domains = new Dictionary <long, AppDomainMirror> ();
321 if (!domains.TryGetValue (id, out obj)) {
322 obj = new AppDomainMirror (this, id);
329 Dictionary <long, TypeMirror> types;
330 object types_lock = new object ();
332 internal TypeMirror GetType (long id) {
335 types = new Dictionary <long, TypeMirror> ();
339 if (!types.TryGetValue (id, out obj)) {
340 obj = new TypeMirror (this, id);
347 Dictionary <long, ObjectMirror> objects;
348 object objects_lock = new object ();
350 internal T GetObject<T> (long id, long domain_id, long type_id) where T : ObjectMirror {
351 lock (objects_lock) {
353 objects = new Dictionary <long, ObjectMirror> ();
355 if (!objects.TryGetValue (id, out obj)) {
357 * Obtain the domain/type of the object to determine the type of
358 * object we need to create.
361 domain_id = conn.Object_GetDomain (id);
362 AppDomainMirror d = GetDomain (domain_id);
365 type_id = conn.Object_GetType (id);
366 TypeMirror t = GetType (type_id);
368 if (t.Assembly == d.Corlib && t.Namespace == "System.Threading" && t.Name == "Thread")
369 obj = new ThreadMirror (this, id);
370 else if (t.Assembly == d.Corlib && t.Namespace == "System" && t.Name == "String")
371 obj = new StringMirror (this, id);
372 else if (typeof (T) == typeof (ArrayMirror))
373 obj = new ArrayMirror (this, id);
375 obj = new ObjectMirror (this, id);
382 internal T GetObject<T> (long id) where T : ObjectMirror {
383 return GetObject<T> (id, 0, 0);
386 internal ObjectMirror GetObject (long objid) {
387 return GetObject<ObjectMirror> (objid);
390 internal ThreadMirror GetThread (long id) {
391 return GetObject <ThreadMirror> (id);
394 object requests_lock = new object ();
396 internal void AddRequest (EventRequest req, int id) {
397 lock (requests_lock) {
402 internal void RemoveRequest (EventRequest req, int id) {
403 lock (requests_lock) {
404 requests.Remove (id);
408 internal EventRequest GetRequest (int id) {
409 lock (requests_lock) {
410 return requests [id];
414 internal Value DecodeValue (ValueImpl v) {
416 return new PrimitiveValue (this, v.Value);
419 case ElementType.Void:
421 case ElementType.SzArray:
422 case ElementType.Array:
423 return GetObject<ArrayMirror> (v.Objid);
424 case ElementType.String:
425 return GetObject<StringMirror> (v.Objid);
426 case ElementType.Class:
427 case ElementType.Object:
428 return GetObject (v.Objid);
429 case ElementType.ValueType:
431 return new EnumMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
433 return new StructMirror (this, GetType (v.Klass), DecodeValues (v.Fields));
434 case (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL:
435 return new PrimitiveValue (this, null);
437 throw new NotImplementedException ("" + v.Type);
441 internal Value[] DecodeValues (ValueImpl[] values) {
442 Value[] res = new Value [values.Length];
443 for (int i = 0; i < values.Length; ++i)
444 res [i] = DecodeValue (values [i]);
448 internal ValueImpl EncodeValue (Value v) {
449 if (v is PrimitiveValue) {
450 object val = (v as PrimitiveValue).Value;
452 return new ValueImpl { Type = (ElementType)ValueTypeId.VALUE_TYPE_ID_NULL, Objid = 0 };
454 return new ValueImpl { Value = val };
455 } else if (v is ObjectMirror) {
456 return new ValueImpl { Type = ElementType.Object, Objid = (v as ObjectMirror).Id };
457 } else if (v is StructMirror) {
458 return new ValueImpl { Type = ElementType.ValueType, Klass = (v as StructMirror).Type.Id, Fields = EncodeValues ((v as StructMirror).Fields) };
460 throw new NotSupportedException ();
464 internal ValueImpl[] EncodeValues (IList<Value> values) {
465 ValueImpl[] res = new ValueImpl [values.Count];
466 for (int i = 0; i < values.Count; ++i)
467 res [i] = EncodeValue (values [i]);
472 class EventHandler : MarshalByRefObject, IEventHandler
476 public EventHandler (VirtualMachine vm) {
480 public void VMStart (int req_id, long thread_id, string vm_uri) {
481 vm.notify_vm_event (EventType.VMStart, req_id, thread_id, vm_uri);
484 public void VMDeath (int req_id, long thread_id, string vm_uri) {
485 vm.notify_vm_event (EventType.VMDeath, req_id, thread_id, vm_uri);
488 public void VMDisconnect (int req_id, long thread_id, string vm_uri) {
489 vm.notify_vm_event (EventType.VMDisconnect, req_id, thread_id, vm_uri);
492 public void ThreadStart (int req_id, long thread_id, long id) {
493 vm.queue_event (new ThreadStartEvent (vm, req_id, id));
496 public void ThreadDeath (int req_id, long thread_id, long id) {
497 vm.queue_event (new ThreadDeathEvent (vm, req_id, id));
500 public void AssemblyLoad (int req_id, long thread_id, long id) {
501 vm.queue_event (new AssemblyLoadEvent (vm, req_id, thread_id, id));
504 public void AssemblyUnload (int req_id, long thread_id, long id) {
505 vm.queue_event (new AssemblyUnloadEvent (vm, req_id, thread_id, id));
508 public void TypeLoad (int req_id, long thread_id, long id) {
509 vm.queue_event (new TypeLoadEvent (vm, req_id, thread_id, id));
512 public void MethodEntry (int req_id, long thread_id, long id) {
513 vm.queue_event (new MethodEntryEvent (vm, req_id, thread_id, id));
516 public void MethodExit (int req_id, long thread_id, long id) {
517 vm.queue_event (new MethodExitEvent (vm, req_id, thread_id, id));
520 public void Breakpoint (int req_id, long thread_id, long id, long loc) {
521 vm.queue_event (new BreakpointEvent (vm, req_id, thread_id, id, loc));
524 public void Step (int req_id, long thread_id, long id, long loc) {
525 vm.queue_event (new StepEvent (vm, req_id, thread_id, id, loc));
528 public void Exception (int req_id, long thread_id, long id, long loc) {
529 vm.queue_event (new ExceptionEvent (vm, req_id, thread_id, id, loc));
532 public void AppDomainCreate (int req_id, long thread_id, long id) {
533 vm.queue_event (new AppDomainCreateEvent (vm, req_id, thread_id, id));
536 public void AppDomainUnload (int req_id, long thread_id, long id) {
537 vm.queue_event (new AppDomainUnloadEvent (vm, req_id, thread_id, id));
541 internal class CommandException : Exception {
543 public CommandException (ErrorCode error_code) : base ("Debuggee returned error code " + error_code + ".") {
544 ErrorCode = error_code;
547 public ErrorCode ErrorCode {