[interp] Small fixes (#11667)
[mono-project.git] / mono / mini / debugger-agent.c
blob32f2870e46788aae8208eaea10f1ca02beeda022
1 /**
2 * \file
3 * Soft Debugger back-end module
5 * Author:
6 * Zoltan Varga (vargaz@gmail.com)
8 * Copyright 2009-2010 Novell, Inc.
9 * Copyright 2011 Xamarin Inc.
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
19 #endif
20 #ifdef HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23 #ifdef HAVE_SYS_SOCKET_H
24 #include <sys/socket.h>
25 #endif
26 #ifdef HAVE_NETINET_TCP_H
27 #include <netinet/tcp.h>
28 #endif
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #include <errno.h>
36 #include <glib.h>
38 #ifdef HAVE_PTHREAD_H
39 #include <pthread.h>
40 #endif
42 #ifdef HOST_WIN32
43 #ifdef _MSC_VER
44 #include <winsock2.h>
45 #include <process.h>
46 #endif
47 #include <ws2tcpip.h>
48 #endif
50 #ifdef HOST_ANDROID
51 #include <linux/in.h>
52 #include <linux/tcp.h>
53 #include <sys/endian.h>
54 #endif
56 #include <mono/metadata/mono-debug.h>
57 #include <mono/metadata/debug-internals.h>
58 #include <mono/metadata/gc-internals.h>
59 #include <mono/metadata/environment.h>
60 #include <mono/metadata/threads-types.h>
61 #include <mono/metadata/threadpool.h>
62 #include <mono/metadata/assembly.h>
63 #include <mono/metadata/assembly-internals.h>
64 #include <mono/metadata/runtime.h>
65 #include <mono/metadata/verify-internals.h>
66 #include <mono/metadata/reflection-internals.h>
67 #include <mono/metadata/w32socket.h>
68 #include <mono/utils/mono-coop-mutex.h>
69 #include <mono/utils/mono-coop-semaphore.h>
70 #include <mono/utils/mono-error-internals.h>
71 #include <mono/utils/mono-stack-unwinding.h>
72 #include <mono/utils/mono-time.h>
73 #include <mono/utils/mono-threads.h>
74 #include <mono/utils/networking.h>
75 #include <mono/utils/mono-proclib.h>
76 #include <mono/utils/w32api.h>
77 #include "debugger-state-machine.h"
78 #include "debugger-agent.h"
79 #include "mini.h"
80 #include "seq-points.h"
81 #include "aot-runtime.h"
82 #include "mini-runtime.h"
83 #include "interp/interp.h"
84 #include "debugger-engine.h"
85 #include "mono/metadata/debug-mono-ppdb.h"
88 * On iOS we can't use System.Environment.Exit () as it will do the wrong
89 * shutdown sequence.
91 #if !defined (TARGET_IOS)
92 #define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
93 #endif
95 #ifndef DISABLE_SDB
97 #include <mono/utils/mono-os-mutex.h>
99 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
101 typedef struct {
102 gboolean enabled;
103 char *transport;
104 char *address;
105 int log_level;
106 char *log_file;
107 gboolean suspend;
108 gboolean server;
109 gboolean onuncaught;
110 GSList *onthrow;
111 int timeout;
112 char *launch;
113 gboolean embedding;
114 gboolean defer;
115 int keepalive;
116 gboolean setpgid;
117 } AgentConfig;
119 typedef struct
121 //Must be the first field to ensure pointer equivalence
122 DbgEngineStackFrame de;
123 int id;
124 guint32 il_offset;
126 * If method is gshared, this is the actual instance, otherwise this is equal to
127 * method.
129 MonoMethod *actual_method;
131 * This is the method which is visible to debugger clients. Same as method,
132 * except for native-to-managed wrappers.
134 MonoMethod *api_method;
135 MonoContext ctx;
136 MonoDebugMethodJitInfo *jit;
137 MonoInterpFrameHandle interp_frame;
138 gpointer frame_addr;
139 int flags;
140 host_mgreg_t *reg_locations [MONO_MAX_IREGS];
142 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
143 * the frame can become invalid.
145 gboolean has_ctx;
146 } StackFrame;
148 typedef struct _InvokeData InvokeData;
150 struct _InvokeData
152 int id;
153 int flags;
154 guint8 *p;
155 guint8 *endp;
156 /* This is the context which needs to be restored after the invoke */
157 MonoContext ctx;
158 gboolean has_ctx;
160 * If this is set, invoke this method with the arguments given by ARGS.
162 MonoMethod *method;
163 gpointer *args;
164 guint32 suspend_count;
165 int nmethods;
167 InvokeData *last_invoke;
170 struct _DebuggerTlsData {
171 MonoThreadUnwindState context;
173 /* This is computed on demand when it is requested using the wire protocol */
174 /* It is freed up when the thread is resumed */
175 int frame_count;
176 StackFrame **frames;
178 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
179 * re-compute it.
181 gboolean frames_up_to_date;
183 * Points to data about a pending invoke which needs to be executed after the thread
184 * resumes.
186 InvokeData *pending_invoke;
188 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
189 * native code.
191 gboolean suspended;
193 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
194 * within a finite amount of time.
196 gboolean suspending;
198 * Set to TRUE if this thread is suspended in suspend_current ().
200 gboolean really_suspended;
201 /* Used to pass the context to the breakpoint/single step handler */
202 MonoContext handler_ctx;
203 /* Whenever thread_stop () was called for this thread */
204 gboolean terminated;
206 /* Whenever to disable breakpoints (used during invokes) */
207 gboolean disable_breakpoints;
210 * Number of times this thread has been resumed using resume_thread ().
212 guint32 resume_count;
214 MonoInternalThread *thread;
215 intptr_t thread_id;
218 * Information about the frame which transitioned to native code for running
219 * threads.
221 StackFrameInfo async_last_frame;
224 * The context where the stack walk can be started for running threads.
226 MonoThreadUnwindState async_state;
229 * The context used for filter clauses
231 MonoThreadUnwindState filter_state;
233 gboolean abort_requested;
236 * The current mono_runtime_invoke_checked invocation.
238 InvokeData *invoke;
240 StackFrameInfo catch_frame;
241 gboolean has_catch_frame;
244 * The context which needs to be restored after handling a single step/breakpoint
245 * event. This is the same as the ctx at step/breakpoint site, but includes changes
246 * to caller saved registers done by set_var ().
248 MonoThreadUnwindState restore_state;
249 /* Frames computed from restore_state */
250 int restore_frame_count;
251 StackFrame **restore_frames;
253 /* The currently unloading appdomain */
254 MonoDomain *domain_unloading;
256 // The state that the debugger expects the thread to be in
257 MonoDebuggerThreadState thread_state;
260 typedef struct {
261 const char *name;
262 void (*connect) (const char *address);
263 void (*close1) (void);
264 void (*close2) (void);
265 gboolean (*send) (void *buf, int len);
266 int (*recv) (void *buf, int len);
267 } DebuggerTransport;
270 * Wire Protocol definitions
273 #define HEADER_LENGTH 11
275 #define MAJOR_VERSION 2
276 #define MINOR_VERSION 49
278 typedef enum {
279 CMD_SET_VM = 1,
280 CMD_SET_OBJECT_REF = 9,
281 CMD_SET_STRING_REF = 10,
282 CMD_SET_THREAD = 11,
283 CMD_SET_ARRAY_REF = 13,
284 CMD_SET_EVENT_REQUEST = 15,
285 CMD_SET_STACK_FRAME = 16,
286 CMD_SET_APPDOMAIN = 20,
287 CMD_SET_ASSEMBLY = 21,
288 CMD_SET_METHOD = 22,
289 CMD_SET_TYPE = 23,
290 CMD_SET_MODULE = 24,
291 CMD_SET_FIELD = 25,
292 CMD_SET_EVENT = 64,
293 CMD_SET_POINTER = 65
294 } CommandSet;
296 typedef enum {
297 SUSPEND_POLICY_NONE = 0,
298 SUSPEND_POLICY_EVENT_THREAD = 1,
299 SUSPEND_POLICY_ALL = 2
300 } SuspendPolicy;
302 typedef enum {
303 ERR_NONE = 0,
304 ERR_INVALID_OBJECT = 20,
305 ERR_INVALID_FIELDID = 25,
306 ERR_INVALID_FRAMEID = 30,
307 ERR_NOT_IMPLEMENTED = 100,
308 ERR_NOT_SUSPENDED = 101,
309 ERR_INVALID_ARGUMENT = 102,
310 ERR_UNLOADED = 103,
311 ERR_NO_INVOCATION = 104,
312 ERR_ABSENT_INFORMATION = 105,
313 ERR_NO_SEQ_POINT_AT_IL_OFFSET = 106,
314 ERR_INVOKE_ABORTED = 107,
315 ERR_LOADER_ERROR = 200, /*XXX extend the protocol to pass this information down the pipe */
316 } ErrorCode;
318 typedef enum {
319 TOKEN_TYPE_STRING = 0,
320 TOKEN_TYPE_TYPE = 1,
321 TOKEN_TYPE_FIELD = 2,
322 TOKEN_TYPE_METHOD = 3,
323 TOKEN_TYPE_UNKNOWN = 4
324 } DebuggerTokenType;
326 typedef enum {
327 VALUE_TYPE_ID_NULL = 0xf0,
328 VALUE_TYPE_ID_TYPE = 0xf1,
329 VALUE_TYPE_ID_PARENT_VTYPE = 0xf2
330 } ValueTypeId;
332 typedef enum {
333 FRAME_FLAG_DEBUGGER_INVOKE = 1,
334 FRAME_FLAG_NATIVE_TRANSITION = 2
335 } StackFrameFlags;
337 typedef enum {
338 INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
339 INVOKE_FLAG_SINGLE_THREADED = 2,
340 INVOKE_FLAG_RETURN_OUT_THIS = 4,
341 INVOKE_FLAG_RETURN_OUT_ARGS = 8,
342 INVOKE_FLAG_VIRTUAL = 16
343 } InvokeFlags;
345 typedef enum {
346 BINDING_FLAGS_IGNORE_CASE = 0x70000000,
347 } BindingFlagsExtensions;
349 typedef enum {
350 CMD_VM_VERSION = 1,
351 CMD_VM_ALL_THREADS = 2,
352 CMD_VM_SUSPEND = 3,
353 CMD_VM_RESUME = 4,
354 CMD_VM_EXIT = 5,
355 CMD_VM_DISPOSE = 6,
356 CMD_VM_INVOKE_METHOD = 7,
357 CMD_VM_SET_PROTOCOL_VERSION = 8,
358 CMD_VM_ABORT_INVOKE = 9,
359 CMD_VM_SET_KEEPALIVE = 10,
360 CMD_VM_GET_TYPES_FOR_SOURCE_FILE = 11,
361 CMD_VM_GET_TYPES = 12,
362 CMD_VM_INVOKE_METHODS = 13,
363 CMD_VM_START_BUFFERING = 14,
364 CMD_VM_STOP_BUFFERING = 15
365 } CmdVM;
367 typedef enum {
368 CMD_THREAD_GET_FRAME_INFO = 1,
369 CMD_THREAD_GET_NAME = 2,
370 CMD_THREAD_GET_STATE = 3,
371 CMD_THREAD_GET_INFO = 4,
372 CMD_THREAD_GET_ID = 5,
373 CMD_THREAD_GET_TID = 6,
374 CMD_THREAD_SET_IP = 7
375 } CmdThread;
377 typedef enum {
378 CMD_EVENT_REQUEST_SET = 1,
379 CMD_EVENT_REQUEST_CLEAR = 2,
380 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS = 3
381 } CmdEvent;
383 typedef enum {
384 CMD_COMPOSITE = 100
385 } CmdComposite;
387 typedef enum {
388 CMD_APPDOMAIN_GET_ROOT_DOMAIN = 1,
389 CMD_APPDOMAIN_GET_FRIENDLY_NAME = 2,
390 CMD_APPDOMAIN_GET_ASSEMBLIES = 3,
391 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY = 4,
392 CMD_APPDOMAIN_CREATE_STRING = 5,
393 CMD_APPDOMAIN_GET_CORLIB = 6,
394 CMD_APPDOMAIN_CREATE_BOXED_VALUE = 7
395 } CmdAppDomain;
397 typedef enum {
398 CMD_ASSEMBLY_GET_LOCATION = 1,
399 CMD_ASSEMBLY_GET_ENTRY_POINT = 2,
400 CMD_ASSEMBLY_GET_MANIFEST_MODULE = 3,
401 CMD_ASSEMBLY_GET_OBJECT = 4,
402 CMD_ASSEMBLY_GET_TYPE = 5,
403 CMD_ASSEMBLY_GET_NAME = 6,
404 CMD_ASSEMBLY_GET_DOMAIN = 7,
405 CMD_ASSEMBLY_GET_METADATA_BLOB = 8,
406 CMD_ASSEMBLY_GET_IS_DYNAMIC = 9,
407 CMD_ASSEMBLY_GET_PDB_BLOB = 10,
408 CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN = 11,
409 CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN = 12
410 } CmdAssembly;
412 typedef enum {
413 CMD_MODULE_GET_INFO = 1,
414 } CmdModule;
416 typedef enum {
417 CMD_FIELD_GET_INFO = 1,
418 } CmdField;
420 typedef enum {
421 CMD_METHOD_GET_NAME = 1,
422 CMD_METHOD_GET_DECLARING_TYPE = 2,
423 CMD_METHOD_GET_DEBUG_INFO = 3,
424 CMD_METHOD_GET_PARAM_INFO = 4,
425 CMD_METHOD_GET_LOCALS_INFO = 5,
426 CMD_METHOD_GET_INFO = 6,
427 CMD_METHOD_GET_BODY = 7,
428 CMD_METHOD_RESOLVE_TOKEN = 8,
429 CMD_METHOD_GET_CATTRS = 9,
430 CMD_METHOD_MAKE_GENERIC_METHOD = 10
431 } CmdMethod;
433 typedef enum {
434 CMD_TYPE_GET_INFO = 1,
435 CMD_TYPE_GET_METHODS = 2,
436 CMD_TYPE_GET_FIELDS = 3,
437 CMD_TYPE_GET_VALUES = 4,
438 CMD_TYPE_GET_OBJECT = 5,
439 CMD_TYPE_GET_SOURCE_FILES = 6,
440 CMD_TYPE_SET_VALUES = 7,
441 CMD_TYPE_IS_ASSIGNABLE_FROM = 8,
442 CMD_TYPE_GET_PROPERTIES = 9,
443 CMD_TYPE_GET_CATTRS = 10,
444 CMD_TYPE_GET_FIELD_CATTRS = 11,
445 CMD_TYPE_GET_PROPERTY_CATTRS = 12,
446 CMD_TYPE_GET_SOURCE_FILES_2 = 13,
447 CMD_TYPE_GET_VALUES_2 = 14,
448 CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
449 CMD_TYPE_GET_INTERFACES = 16,
450 CMD_TYPE_GET_INTERFACE_MAP = 17,
451 CMD_TYPE_IS_INITIALIZED = 18,
452 CMD_TYPE_CREATE_INSTANCE = 19,
453 CMD_TYPE_GET_VALUE_SIZE = 20
454 } CmdType;
456 typedef enum {
457 CMD_STACK_FRAME_GET_VALUES = 1,
458 CMD_STACK_FRAME_GET_THIS = 2,
459 CMD_STACK_FRAME_SET_VALUES = 3,
460 CMD_STACK_FRAME_GET_DOMAIN = 4,
461 CMD_STACK_FRAME_SET_THIS = 5,
462 } CmdStackFrame;
464 typedef enum {
465 CMD_ARRAY_REF_GET_LENGTH = 1,
466 CMD_ARRAY_REF_GET_VALUES = 2,
467 CMD_ARRAY_REF_SET_VALUES = 3,
468 } CmdArray;
470 typedef enum {
471 CMD_STRING_REF_GET_VALUE = 1,
472 CMD_STRING_REF_GET_LENGTH = 2,
473 CMD_STRING_REF_GET_CHARS = 3
474 } CmdString;
476 typedef enum {
477 CMD_POINTER_GET_VALUE = 1
478 } CmdPointer;
480 typedef enum {
481 CMD_OBJECT_REF_GET_TYPE = 1,
482 CMD_OBJECT_REF_GET_VALUES = 2,
483 CMD_OBJECT_REF_IS_COLLECTED = 3,
484 CMD_OBJECT_REF_GET_ADDRESS = 4,
485 CMD_OBJECT_REF_GET_DOMAIN = 5,
486 CMD_OBJECT_REF_SET_VALUES = 6,
487 CMD_OBJECT_REF_GET_INFO = 7,
488 } CmdObject;
491 * Contains additional information for an event
493 typedef struct {
494 /* For EVENT_KIND_EXCEPTION */
495 MonoObject *exc;
496 MonoContext catch_ctx;
497 gboolean caught;
498 /* For EVENT_KIND_USER_LOG */
499 int level;
500 char *category, *message;
501 /* For EVENT_KIND_TYPE_LOAD */
502 MonoClass *klass;
503 /* For EVENT_KIND_CRASH */
504 char *dump;
505 MonoStackHash *hashes;
506 } EventInfo;
508 typedef struct {
509 guint8 *buf, *p, *end;
510 } Buffer;
512 typedef struct ReplyPacket {
513 int id;
514 int error;
515 Buffer *data;
516 } ReplyPacket;
518 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
520 #ifdef HOST_ANDROID
521 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { g_print (__VA_ARGS__); } } while (0)
522 #else
523 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (log_file, __VA_ARGS__); fflush (log_file); } } while (0)
524 #endif
526 #ifdef HOST_WIN32
527 #define get_last_sock_error() WSAGetLastError()
528 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
529 #define MONO_EINTR WSAEINTR
530 #else
531 #define get_last_sock_error() errno
532 #define MONO_EWOULDBLOCK EWOULDBLOCK
533 #define MONO_EINTR EINTR
534 #endif
536 #define CHECK_PROTOCOL_VERSION(major,minor) \
537 (protocol_version_set && (major_version > (major) || (major_version == (major) && minor_version >= (minor))))
540 * Globals
543 static AgentConfig agent_config;
546 * Whenever the agent is fully initialized.
547 * When using the onuncaught or onthrow options, only some parts of the agent are
548 * initialized on startup, and the full initialization which includes connection
549 * establishment and the startup of the agent thread is only done in response to
550 * an event.
552 static gint32 inited;
554 #ifndef DISABLE_SOCKET_TRANSPORT
555 static int conn_fd;
556 static int listen_fd;
557 #endif
559 static int packet_id = 0;
561 static int objref_id = 0;
563 static int event_request_id = 0;
565 static int frame_id = 0;
567 static GPtrArray *event_requests;
569 static MonoNativeTlsKey debugger_tls_id;
571 static gboolean vm_start_event_sent, vm_death_event_sent, disconnected;
573 /* Maps MonoInternalThread -> DebuggerTlsData */
574 /* Protected by the loader lock */
575 static MonoGHashTable *thread_to_tls;
577 /* Maps tid -> MonoInternalThread */
578 /* Protected by the loader lock */
579 static MonoGHashTable *tid_to_thread;
581 /* Maps tid -> MonoThread (not MonoInternalThread) */
582 /* Protected by the loader lock */
583 static MonoGHashTable *tid_to_thread_obj;
585 static MonoNativeThreadId debugger_thread_id;
587 static MonoThreadHandle *debugger_thread_handle;
589 static int log_level;
591 static gboolean embedding;
593 static FILE *log_file;
595 /* Assemblies whose assembly load event has no been sent yet */
596 /* Protected by the dbg lock */
597 static GPtrArray *pending_assembly_loads;
599 /* Whenever the debugger thread has exited */
600 static gboolean debugger_thread_exited;
602 /* Cond variable used to wait for debugger_thread_exited becoming true */
603 static MonoCoopCond debugger_thread_exited_cond;
605 /* Mutex for the cond var above */
606 static MonoCoopMutex debugger_thread_exited_mutex;
608 /* The protocol version of the client */
609 static int major_version, minor_version;
611 /* Whenever the variables above are set by the client */
612 static gboolean protocol_version_set;
614 /* The number of times the runtime is suspended */
615 static gint32 suspend_count;
617 /* Whenever to buffer reply messages and send them together */
618 static gboolean buffer_replies;
620 /* Buffered reply packets */
621 static ReplyPacket reply_packets [128];
622 static int nreply_packets;
624 #define dbg_lock mono_de_lock
625 #define dbg_unlock mono_de_unlock
627 static void transport_init (void);
628 static void transport_connect (const char *address);
629 static gboolean transport_handshake (void);
630 static void register_transport (DebuggerTransport *trans);
632 static gsize WINAPI debugger_thread (void *arg);
634 static void runtime_initialized (MonoProfiler *prof);
636 static void runtime_shutdown (MonoProfiler *prof);
638 static void thread_startup (MonoProfiler *prof, uintptr_t tid);
640 static void thread_end (MonoProfiler *prof, uintptr_t tid);
642 static void appdomain_load (MonoProfiler *prof, MonoDomain *domain);
644 static void appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain);
646 static void appdomain_unload (MonoProfiler *prof, MonoDomain *domain);
648 static void emit_appdomain_load (gpointer key, gpointer value, gpointer user_data);
650 static void emit_thread_start (gpointer key, gpointer value, gpointer user_data);
652 static void invalidate_each_thread (gpointer key, gpointer value, gpointer user_data);
654 static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly);
656 static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly);
658 static void emit_assembly_load (gpointer assembly, gpointer user_data);
660 static void emit_type_load (gpointer key, gpointer type, gpointer user_data);
662 static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
664 static void jit_failed (MonoProfiler *prof, MonoMethod *method);
666 static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
668 static void suspend_current (void);
670 static void clear_event_requests_for_assembly (MonoAssembly *assembly);
672 static void clear_types_for_assembly (MonoAssembly *assembly);
674 static void process_profiler_event (EventKind event, gpointer arg);
676 /* Submodule init/cleanup */
677 static void event_requests_cleanup (void);
679 static void objrefs_init (void);
680 static void objrefs_cleanup (void);
682 static void ids_init (void);
683 static void ids_cleanup (void);
685 static void suspend_init (void);
687 static void start_debugger_thread (void);
688 static void stop_debugger_thread (void);
690 static void finish_agent_init (gboolean on_startup);
692 static void process_profiler_event (EventKind event, gpointer arg);
694 static void invalidate_frames (DebuggerTlsData *tls);
696 /* Callbacks used by debugger-engine */
697 static MonoContext* tls_get_restore_state (void *the_tls);
698 static gboolean try_process_suspend (void *tls, MonoContext *ctx);
699 static gboolean begin_breakpoint_processing (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
700 static void begin_single_step_processing (MonoContext *ctx, gboolean from_signal);
701 static void ss_discard_frame_context (void *the_tls);
702 static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes);
703 static gboolean ensure_jit (DbgEngineStackFrame* the_frame);
704 static int ensure_runtime_is_suspended (void);
705 static int get_this_async_id (DbgEngineStackFrame *frame);
706 static gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame);
707 static MonoMethod* get_notify_debugger_of_wait_completion_method (void);
708 static void* create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind);
709 static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset);
710 static int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args);
711 static void ss_args_destroy (SingleStepArgs *ss_args);
713 #ifndef DISABLE_SOCKET_TRANSPORT
714 static void
715 register_socket_transport (void);
716 #endif
718 static inline gboolean
719 is_debugger_thread (void)
721 MonoInternalThread *internal;
723 internal = mono_thread_internal_current ();
724 if (!internal)
725 return FALSE;
727 return internal->debugger_thread;
730 static int
731 parse_address (char *address, char **host, int *port)
733 char *pos = strchr (address, ':');
735 if (pos == NULL || pos == address)
736 return 1;
738 size_t len = pos - address;
739 *host = (char *)g_malloc (len + 1);
740 memcpy (*host, address, len);
741 (*host) [len] = '\0';
743 *port = atoi (pos + 1);
745 return 0;
748 static void
749 print_usage (void)
751 g_printerr ("Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
752 g_printerr ("Available options:\n");
753 g_printerr (" transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
754 g_printerr (" address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
755 g_printerr (" loglevel=<n>\t\t\tLog level (defaults to 0)\n");
756 g_printerr (" logfile=<file>\t\tFile to log to (defaults to stdout)\n");
757 g_printerr (" suspend=y/n\t\t\tWhether to suspend after startup.\n");
758 g_printerr (" timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
759 g_printerr (" server=y/n\t\t\tWhether to listen for a client connection.\n");
760 g_printerr (" keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
761 g_printerr (" setpgid=y/n\t\t\tWhether to call setpid(0, 0) after startup.\n");
762 g_printerr (" help\t\t\t\tPrint this help.\n");
765 static gboolean
766 parse_flag (const char *option, char *flag)
768 if (!strcmp (flag, "y"))
769 return TRUE;
770 else if (!strcmp (flag, "n"))
771 return FALSE;
772 else {
773 g_printerr ("debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option);
774 exit (1);
775 return FALSE;
779 static void
780 debugger_agent_parse_options (char *options)
782 char **args, **ptr;
783 char *host;
784 int port;
785 char *extra;
787 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
788 g_printerr ("--debugger-agent is not supported on this platform.\n");
789 exit (1);
790 #endif
792 extra = g_getenv ("MONO_SDB_ENV_OPTIONS");
793 if (extra) {
794 options = g_strdup_printf ("%s,%s", options, extra);
795 g_free (extra);
798 agent_config.enabled = TRUE;
799 agent_config.suspend = TRUE;
800 agent_config.server = FALSE;
801 agent_config.defer = FALSE;
802 agent_config.address = NULL;
804 //agent_config.log_level = 10;
806 args = g_strsplit (options, ",", -1);
807 for (ptr = args; ptr && *ptr; ptr ++) {
808 char *arg = *ptr;
810 if (strncmp (arg, "transport=", 10) == 0) {
811 agent_config.transport = g_strdup (arg + 10);
812 } else if (strncmp (arg, "address=", 8) == 0) {
813 agent_config.address = g_strdup (arg + 8);
814 } else if (strncmp (arg, "loglevel=", 9) == 0) {
815 agent_config.log_level = atoi (arg + 9);
816 } else if (strncmp (arg, "logfile=", 8) == 0) {
817 agent_config.log_file = g_strdup (arg + 8);
818 } else if (strncmp (arg, "suspend=", 8) == 0) {
819 agent_config.suspend = parse_flag ("suspend", arg + 8);
820 } else if (strncmp (arg, "server=", 7) == 0) {
821 agent_config.server = parse_flag ("server", arg + 7);
822 } else if (strncmp (arg, "onuncaught=", 11) == 0) {
823 agent_config.onuncaught = parse_flag ("onuncaught", arg + 11);
824 } else if (strncmp (arg, "onthrow=", 8) == 0) {
825 /* We support multiple onthrow= options */
826 agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (arg + 8));
827 } else if (strncmp (arg, "onthrow", 7) == 0) {
828 agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (""));
829 } else if (strncmp (arg, "help", 4) == 0) {
830 print_usage ();
831 exit (0);
832 } else if (strncmp (arg, "timeout=", 8) == 0) {
833 agent_config.timeout = atoi (arg + 8);
834 } else if (strncmp (arg, "launch=", 7) == 0) {
835 agent_config.launch = g_strdup (arg + 7);
836 } else if (strncmp (arg, "embedding=", 10) == 0) {
837 agent_config.embedding = atoi (arg + 10) == 1;
838 } else if (strncmp (arg, "keepalive=", 10) == 0) {
839 agent_config.keepalive = atoi (arg + 10);
840 } else if (strncmp (arg, "setpgid=", 8) == 0) {
841 agent_config.setpgid = parse_flag ("setpgid", arg + 8);
842 } else {
843 print_usage ();
844 exit (1);
848 if (agent_config.server && !agent_config.suspend) {
849 /* Waiting for deferred attachment */
850 agent_config.defer = TRUE;
851 if (agent_config.address == NULL) {
852 agent_config.address = g_strdup_printf ("0.0.0.0:%u", 56000 + (mono_process_current_pid () % 1000));
856 //agent_config.log_level = 0;
858 if (agent_config.transport == NULL) {
859 g_printerr ("debugger-agent: The 'transport' option is mandatory.\n");
860 exit (1);
863 if (agent_config.address == NULL && !agent_config.server) {
864 g_printerr ("debugger-agent: The 'address' option is mandatory.\n");
865 exit (1);
868 // FIXME:
869 if (!strcmp (agent_config.transport, "dt_socket")) {
870 if (agent_config.address && parse_address (agent_config.address, &host, &port)) {
871 g_printerr ("debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
872 exit (1);
877 void
878 mono_debugger_set_thread_state (DebuggerTlsData *tls, MonoDebuggerThreadState expected, MonoDebuggerThreadState set)
880 g_assertf (tls, "Cannot get state of null thread", NULL);
882 g_assert (tls->thread_state == expected);
884 tls->thread_state = set;
886 return;
889 MonoDebuggerThreadState
890 mono_debugger_get_thread_state (DebuggerTlsData *tls)
892 g_assertf (tls, "Cannot get state of null thread", NULL);
894 return tls->thread_state;
897 gsize
898 mono_debugger_tls_thread_id (DebuggerTlsData *tls)
900 if (!tls)
901 return 0;
903 return tls->thread_id;
906 // Only call this function with the loader lock held
907 MonoGHashTable *
908 mono_debugger_get_thread_states (void)
910 return thread_to_tls;
913 gboolean
914 mono_debugger_is_disconnected (void)
916 return disconnected;
919 static void
920 debugger_agent_init (void)
922 if (!agent_config.enabled)
923 return;
925 DebuggerEngineCallbacks cbs;
926 memset (&cbs, 0, sizeof (cbs));
927 cbs.tls_get_restore_state = tls_get_restore_state;
928 cbs.try_process_suspend = try_process_suspend;
929 cbs.begin_breakpoint_processing = begin_breakpoint_processing;
930 cbs.begin_single_step_processing = begin_single_step_processing;
931 cbs.ss_discard_frame_context = ss_discard_frame_context;
932 cbs.ss_calculate_framecount = ss_calculate_framecount;
933 cbs.ensure_jit = ensure_jit;
934 cbs.ensure_runtime_is_suspended = ensure_runtime_is_suspended;
935 cbs.get_this_async_id = get_this_async_id;
936 cbs.set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag;
937 cbs.get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method;
938 cbs.create_breakpoint_events = create_breakpoint_events;
939 cbs.process_breakpoint_events = process_breakpoint_events;
940 cbs.ss_create_init_args = ss_create_init_args;
941 cbs.ss_args_destroy = ss_args_destroy;
943 mono_de_init (&cbs);
945 transport_init ();
947 /* Need to know whenever a thread has acquired the loader mutex */
948 mono_loader_lock_track_ownership (TRUE);
950 event_requests = g_ptr_array_new ();
952 mono_coop_mutex_init (&debugger_thread_exited_mutex);
953 mono_coop_cond_init (&debugger_thread_exited_cond);
955 MonoProfilerHandle prof = mono_profiler_create (NULL);
956 mono_profiler_set_runtime_shutdown_end_callback (prof, runtime_shutdown);
957 mono_profiler_set_runtime_initialized_callback (prof, runtime_initialized);
958 mono_profiler_set_domain_loaded_callback (prof, appdomain_load);
959 mono_profiler_set_domain_unloading_callback (prof, appdomain_start_unload);
960 mono_profiler_set_domain_unloaded_callback (prof, appdomain_unload);
961 mono_profiler_set_thread_started_callback (prof, thread_startup);
962 mono_profiler_set_thread_stopped_callback (prof, thread_end);
963 mono_profiler_set_assembly_loaded_callback (prof, assembly_load);
964 mono_profiler_set_assembly_unloading_callback (prof, assembly_unload);
965 mono_profiler_set_jit_done_callback (prof, jit_done);
966 mono_profiler_set_jit_failed_callback (prof, jit_failed);
968 mono_native_tls_alloc (&debugger_tls_id, NULL);
970 /* Needed by the hash_table_new_type () call below */
971 mono_gc_base_init ();
973 thread_to_tls = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger TLS Table");
975 tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Table");
977 tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Object Table");
979 pending_assembly_loads = g_ptr_array_new ();
981 log_level = agent_config.log_level;
983 embedding = agent_config.embedding;
984 disconnected = TRUE;
986 if (agent_config.log_file) {
987 log_file = fopen (agent_config.log_file, "w+");
988 if (!log_file) {
989 g_printerr ("Unable to create log file '%s': %s.\n", agent_config.log_file, strerror (errno));
990 exit (1);
992 } else {
993 log_file = stdout;
995 mono_de_set_log_level (log_level, log_file);
997 ids_init ();
998 objrefs_init ();
999 suspend_init ();
1001 mini_get_debug_options ()->gen_sdb_seq_points = TRUE;
1003 * This is needed because currently we don't handle liveness info.
1005 mini_get_debug_options ()->mdb_optimizations = TRUE;
1007 #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
1008 /* This is needed because we can't set local variables in registers yet */
1009 mono_disable_optimizations (MONO_OPT_LINEARS);
1010 #endif
1013 * The stack walk done from thread_interrupt () needs to be signal safe, but it
1014 * isn't, since it can call into mono_aot_find_jit_info () which is not signal
1015 * safe (#3411). So load AOT info eagerly when the debugger is running as a
1016 * workaround.
1018 mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE;
1020 #ifdef HAVE_SETPGID
1021 if (agent_config.setpgid)
1022 setpgid (0, 0);
1023 #endif
1025 if (!agent_config.onuncaught && !agent_config.onthrow)
1026 finish_agent_init (TRUE);
1030 * finish_agent_init:
1032 * Finish the initialization of the agent. This involves connecting the transport
1033 * and starting the agent thread. This is either done at startup, or
1034 * in response to some event like an unhandled exception.
1036 static void
1037 finish_agent_init (gboolean on_startup)
1039 int res;
1041 if (mono_atomic_cas_i32 (&inited, 1, 0) == 1)
1042 return;
1044 if (agent_config.launch) {
1045 char *argv [16];
1047 // FIXME: Generated address
1048 // FIXME: Races with transport_connect ()
1050 argv [0] = agent_config.launch;
1051 argv [1] = agent_config.transport;
1052 argv [2] = agent_config.address;
1053 argv [3] = NULL;
1055 res = g_spawn_async_with_pipes (NULL, argv, NULL, (GSpawnFlags)0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1056 if (!res) {
1057 g_printerr ("Failed to execute '%s'.\n", agent_config.launch);
1058 exit (1);
1062 transport_connect (agent_config.address);
1064 if (!on_startup) {
1065 /* Do some which is usually done after sending the VMStart () event */
1066 vm_start_event_sent = TRUE;
1067 start_debugger_thread ();
1071 static void
1072 mono_debugger_agent_cleanup (void)
1074 if (!inited)
1075 return;
1077 stop_debugger_thread ();
1079 event_requests_cleanup ();
1080 objrefs_cleanup ();
1081 ids_cleanup ();
1083 mono_de_cleanup ();
1087 * SOCKET TRANSPORT
1090 #ifndef DISABLE_SOCKET_TRANSPORT
1093 * recv_length:
1095 * recv() + handle incomplete reads and EINTR
1097 static int
1098 socket_transport_recv (void *buf, int len)
1100 int res;
1101 int total = 0;
1102 int fd = conn_fd;
1103 int flags = 0;
1104 static gint64 last_keepalive;
1105 gint64 msecs;
1107 MONO_ENTER_GC_SAFE;
1109 do {
1110 again:
1111 res = recv (fd, (char *) buf + total, len - total, flags);
1112 if (res > 0)
1113 total += res;
1114 if (agent_config.keepalive) {
1115 gboolean need_keepalive = FALSE;
1116 if (res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) {
1117 need_keepalive = TRUE;
1118 } else if (res == -1) {
1119 /* This could happen if recv () is interrupted repeatedly */
1120 msecs = mono_msec_ticks ();
1121 if (msecs - last_keepalive >= agent_config.keepalive) {
1122 need_keepalive = TRUE;
1123 last_keepalive = msecs;
1126 if (need_keepalive) {
1127 process_profiler_event (EVENT_KIND_KEEPALIVE, NULL);
1128 goto again;
1131 } while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR));
1133 MONO_EXIT_GC_SAFE;
1135 return total;
1138 static void
1139 set_keepalive (void)
1141 struct timeval tv;
1142 int result;
1144 if (!agent_config.keepalive || !conn_fd)
1145 return;
1147 tv.tv_sec = agent_config.keepalive / 1000;
1148 tv.tv_usec = (agent_config.keepalive % 1000) * 1000;
1150 result = setsockopt (conn_fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(struct timeval));
1151 g_assert (result >= 0);
1154 static int
1155 socket_transport_accept (int socket_fd)
1157 MONO_ENTER_GC_SAFE;
1158 conn_fd = accept (socket_fd, NULL, NULL);
1159 MONO_EXIT_GC_SAFE;
1161 if (conn_fd == -1) {
1162 g_printerr ("debugger-agent: Unable to listen on %d\n", socket_fd);
1163 } else {
1164 DEBUG_PRINTF (1, "Accepted connection from client, connection fd=%d.\n", conn_fd);
1167 return conn_fd;
1170 static gboolean
1171 socket_transport_send (void *data, int len)
1173 int res;
1175 MONO_ENTER_GC_SAFE;
1177 do {
1178 res = send (conn_fd, (const char*)data, len, 0);
1179 } while (res == -1 && get_last_sock_error () == MONO_EINTR);
1181 MONO_EXIT_GC_SAFE;
1183 if (res != len)
1184 return FALSE;
1185 else
1186 return TRUE;
1190 * socket_transport_connect:
1192 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
1194 static void
1195 socket_transport_connect (const char *address)
1197 MonoAddressInfo *result;
1198 MonoAddressEntry *rp;
1199 int sfd = -1, s, res;
1200 char *host;
1201 int port;
1203 if (agent_config.address) {
1204 res = parse_address (agent_config.address, &host, &port);
1205 g_assert (res == 0);
1206 } else {
1207 host = NULL;
1208 port = 0;
1211 conn_fd = -1;
1212 listen_fd = -1;
1214 if (host) {
1216 mono_network_init ();
1218 /* Obtain address(es) matching host/port */
1219 s = mono_get_address_info (host, port, MONO_HINT_UNSPECIFIED, &result);
1220 if (s != 0) {
1221 g_printerr ("debugger-agent: Unable to resolve %s:%d: %d\n", host, port, s); // FIXME add portable error conversion functions
1222 exit (1);
1226 if (agent_config.server) {
1227 /* Wait for a connection */
1228 if (!host) {
1229 struct sockaddr_in addr;
1230 socklen_t addrlen;
1232 /* No address, generate one */
1233 sfd = socket (AF_INET, SOCK_STREAM, 0);
1234 g_assert (sfd);
1236 /* This will bind the socket to a random port */
1237 res = listen (sfd, 16);
1238 if (res == -1) {
1239 g_printerr ("debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
1240 exit (1);
1242 listen_fd = sfd;
1244 addrlen = sizeof (addr);
1245 memset (&addr, 0, sizeof (addr));
1246 res = getsockname (sfd, (struct sockaddr*)&addr, &addrlen);
1247 g_assert (res == 0);
1249 host = (char*)"127.0.0.1";
1250 port = ntohs (addr.sin_port);
1252 /* Emit the address to stdout */
1253 /* FIXME: Should print another interface, not localhost */
1254 printf ("%s:%d\n", host, port);
1255 } else {
1256 /* Listen on the provided address */
1257 for (rp = result->entries; rp != NULL; rp = rp->next) {
1258 MonoSocketAddress sockaddr;
1259 socklen_t sock_len;
1260 int n = 1;
1262 mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
1264 sfd = socket (rp->family, rp->socktype,
1265 rp->protocol);
1266 if (sfd == -1)
1267 continue;
1269 if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&n, sizeof(n)) == -1)
1270 continue;
1272 res = bind (sfd, &sockaddr.addr, sock_len);
1273 if (res == -1)
1274 continue;
1276 res = listen (sfd, 16);
1277 if (res == -1)
1278 continue;
1279 listen_fd = sfd;
1280 break;
1283 mono_free_address_info (result);
1286 if (agent_config.defer)
1287 return;
1289 DEBUG_PRINTF (1, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout);
1291 if (agent_config.timeout) {
1292 fd_set readfds;
1293 struct timeval tv;
1295 tv.tv_sec = 0;
1296 tv.tv_usec = agent_config.timeout * 1000;
1297 FD_ZERO (&readfds);
1298 FD_SET (sfd, &readfds);
1300 MONO_ENTER_GC_SAFE;
1301 res = select (sfd + 1, &readfds, NULL, NULL, &tv);
1302 MONO_EXIT_GC_SAFE;
1304 if (res == 0) {
1305 g_printerr ("debugger-agent: Timed out waiting to connect.\n");
1306 exit (1);
1310 conn_fd = socket_transport_accept (sfd);
1311 if (conn_fd == -1)
1312 exit (1);
1314 DEBUG_PRINTF (1, "Accepted connection from client, socket fd=%d.\n", conn_fd);
1315 } else {
1316 /* Connect to the specified address */
1317 /* FIXME: Respect the timeout */
1318 for (rp = result->entries; rp != NULL; rp = rp->next) {
1319 MonoSocketAddress sockaddr;
1320 socklen_t sock_len;
1322 mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
1324 sfd = socket (rp->family, rp->socktype,
1325 rp->protocol);
1326 if (sfd == -1)
1327 continue;
1329 MONO_ENTER_GC_SAFE;
1330 res = connect (sfd, &sockaddr.addr, sock_len);
1331 MONO_EXIT_GC_SAFE;
1333 if (res != -1)
1334 break; /* Success */
1336 MONO_ENTER_GC_SAFE;
1337 #ifdef HOST_WIN32
1338 closesocket (sfd);
1339 #else
1340 close (sfd);
1341 #endif
1342 MONO_EXIT_GC_SAFE;
1345 if (rp == 0) {
1346 g_printerr ("debugger-agent: Unable to connect to %s:%d\n", host, port);
1347 exit (1);
1350 conn_fd = sfd;
1352 mono_free_address_info (result);
1355 if (!transport_handshake ())
1356 exit (1);
1359 static void
1360 socket_transport_close1 (void)
1362 /* This will interrupt the agent thread */
1363 /* Close the read part only so it can still send back replies */
1364 /* Also shut down the connection listener so that we can exit normally */
1365 #ifdef HOST_WIN32
1366 /* SD_RECEIVE doesn't break the recv in the debugger thread */
1367 shutdown (conn_fd, SD_BOTH);
1368 shutdown (listen_fd, SD_BOTH);
1369 closesocket (listen_fd);
1370 #else
1371 shutdown (conn_fd, SHUT_RD);
1372 shutdown (listen_fd, SHUT_RDWR);
1373 MONO_ENTER_GC_SAFE;
1374 close (listen_fd);
1375 MONO_EXIT_GC_SAFE;
1376 #endif
1379 static void
1380 socket_transport_close2 (void)
1382 #ifdef HOST_WIN32
1383 shutdown (conn_fd, SD_BOTH);
1384 #else
1385 shutdown (conn_fd, SHUT_RDWR);
1386 #endif
1389 static void
1390 register_socket_transport (void)
1392 DebuggerTransport trans;
1394 trans.name = "dt_socket";
1395 trans.connect = socket_transport_connect;
1396 trans.close1 = socket_transport_close1;
1397 trans.close2 = socket_transport_close2;
1398 trans.send = socket_transport_send;
1399 trans.recv = socket_transport_recv;
1401 register_transport (&trans);
1405 * socket_fd_transport_connect:
1408 static void
1409 socket_fd_transport_connect (const char *address)
1411 int res;
1413 res = sscanf (address, "%d", &conn_fd);
1414 if (res != 1) {
1415 g_printerr ("debugger-agent: socket-fd transport address is invalid: '%s'\n", address);
1416 exit (1);
1419 if (!transport_handshake ())
1420 exit (1);
1423 static void
1424 register_socket_fd_transport (void)
1426 DebuggerTransport trans;
1428 /* This is the same as the 'dt_socket' transport, but receives an already connected socket fd */
1429 trans.name = "socket-fd";
1430 trans.connect = socket_fd_transport_connect;
1431 trans.close1 = socket_transport_close1;
1432 trans.close2 = socket_transport_close2;
1433 trans.send = socket_transport_send;
1434 trans.recv = socket_transport_recv;
1436 register_transport (&trans);
1439 #endif /* DISABLE_SOCKET_TRANSPORT */
1442 * TRANSPORT CODE
1445 #define MAX_TRANSPORTS 16
1447 static DebuggerTransport *transport;
1449 static DebuggerTransport transports [MAX_TRANSPORTS];
1450 static int ntransports;
1452 MONO_API void
1453 mono_debugger_agent_register_transport (DebuggerTransport *trans);
1455 void
1456 mono_debugger_agent_register_transport (DebuggerTransport *trans)
1458 register_transport (trans);
1461 static void
1462 register_transport (DebuggerTransport *trans)
1464 g_assert (ntransports < MAX_TRANSPORTS);
1466 memcpy (&transports [ntransports], trans, sizeof (DebuggerTransport));
1467 ntransports ++;
1470 static void
1471 transport_init (void)
1473 int i;
1475 #ifndef DISABLE_SOCKET_TRANSPORT
1476 register_socket_transport ();
1477 register_socket_fd_transport ();
1478 #endif
1480 for (i = 0; i < ntransports; ++i) {
1481 if (!strcmp (agent_config.transport, transports [i].name))
1482 break;
1484 if (i == ntransports) {
1485 g_printerr ("debugger-agent: The supported values for the 'transport' option are: ");
1486 for (i = 0; i < ntransports; ++i)
1487 g_printerr ("%s'%s'", i > 0 ? ", " : "", transports [i].name);
1488 g_printerr ("\n");
1489 exit (1);
1491 transport = &transports [i];
1494 void
1495 transport_connect (const char *address)
1497 transport->connect (address);
1500 static void
1501 transport_close1 (void)
1503 transport->close1 ();
1506 static void
1507 transport_close2 (void)
1509 transport->close2 ();
1512 static int
1513 transport_send (void *buf, int len)
1515 return transport->send (buf, len);
1518 static int
1519 transport_recv (void *buf, int len)
1521 return transport->recv (buf, len);
1524 gboolean
1525 mono_debugger_agent_transport_handshake (void)
1527 return transport_handshake ();
1530 static gboolean
1531 transport_handshake (void)
1533 char handshake_msg [128];
1534 guint8 buf [128];
1535 int res;
1537 disconnected = TRUE;
1539 /* Write handshake message */
1540 sprintf (handshake_msg, "DWP-Handshake");
1542 do {
1543 res = transport_send (handshake_msg, strlen (handshake_msg));
1544 } while (res == -1 && get_last_sock_error () == MONO_EINTR);
1546 g_assert (res != -1);
1548 /* Read answer */
1549 res = transport_recv (buf, strlen (handshake_msg));
1550 if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
1551 g_printerr ("debugger-agent: DWP handshake failed.\n");
1552 return FALSE;
1556 * To support older clients, the client sends its protocol version after connecting
1557 * using a command. Until that is received, default to our protocol version.
1559 major_version = MAJOR_VERSION;
1560 minor_version = MINOR_VERSION;
1561 protocol_version_set = FALSE;
1563 #ifndef DISABLE_SOCKET_TRANSPORT
1564 // FIXME: Move this somewhere else
1566 * Set TCP_NODELAY on the socket so the client receives events/command
1567 * results immediately.
1569 if (conn_fd) {
1570 int flag = 1;
1571 int result = setsockopt (conn_fd,
1572 IPPROTO_TCP,
1573 TCP_NODELAY,
1574 (char *) &flag,
1575 sizeof(int));
1576 g_assert (result >= 0);
1579 set_keepalive ();
1580 #endif
1582 disconnected = FALSE;
1583 return TRUE;
1586 static void
1587 stop_debugger_thread (void)
1589 if (!inited)
1590 return;
1592 transport_close1 ();
1595 * Wait for the thread to exit.
1597 * If we continue with the shutdown without waiting for it, then the client might
1598 * not receive an answer to its last command like a resume.
1600 if (!is_debugger_thread ()) {
1601 do {
1602 mono_coop_mutex_lock (&debugger_thread_exited_mutex);
1603 if (!debugger_thread_exited)
1604 mono_coop_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
1605 mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
1606 } while (!debugger_thread_exited);
1608 if (debugger_thread_handle)
1609 mono_thread_info_wait_one_handle (debugger_thread_handle, MONO_INFINITE_WAIT, TRUE);
1612 transport_close2 ();
1615 static void
1616 start_debugger_thread (void)
1618 ERROR_DECL (error);
1619 MonoInternalThread *thread;
1621 thread = mono_thread_create_internal (mono_get_root_domain (), (gpointer)debugger_thread, NULL, MONO_THREAD_CREATE_FLAGS_DEBUGGER, error);
1622 mono_error_assert_ok (error);
1624 debugger_thread_handle = mono_threads_open_thread_handle (thread->handle);
1625 g_assert (debugger_thread_handle);
1629 * Functions to decode protocol data
1632 static inline int
1633 decode_byte (guint8 *buf, guint8 **endbuf, guint8 *limit)
1635 *endbuf = buf + 1;
1636 g_assert (*endbuf <= limit);
1637 return buf [0];
1640 static inline int
1641 decode_int (guint8 *buf, guint8 **endbuf, guint8 *limit)
1643 *endbuf = buf + 4;
1644 g_assert (*endbuf <= limit);
1646 return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0);
1649 static inline gint64
1650 decode_long (guint8 *buf, guint8 **endbuf, guint8 *limit)
1652 guint32 high = decode_int (buf, &buf, limit);
1653 guint32 low = decode_int (buf, &buf, limit);
1655 *endbuf = buf;
1657 return ((((guint64)high) << 32) | ((guint64)low));
1660 static inline int
1661 decode_id (guint8 *buf, guint8 **endbuf, guint8 *limit)
1663 return decode_int (buf, endbuf, limit);
1666 static inline char*
1667 decode_string (guint8 *buf, guint8 **endbuf, guint8 *limit)
1669 int len = decode_int (buf, &buf, limit);
1670 char *s;
1672 if (len < 0) {
1673 *endbuf = buf;
1674 return NULL;
1677 s = (char *)g_malloc (len + 1);
1678 g_assert (s);
1680 memcpy (s, buf, len);
1681 s [len] = '\0';
1682 buf += len;
1683 *endbuf = buf;
1685 return s;
1689 * Functions to encode protocol data
1692 static inline void
1693 buffer_init (Buffer *buf, int size)
1695 buf->buf = (guint8 *)g_malloc (size);
1696 buf->p = buf->buf;
1697 buf->end = buf->buf + size;
1700 static inline int
1701 buffer_len (Buffer *buf)
1703 return buf->p - buf->buf;
1706 static inline void
1707 buffer_make_room (Buffer *buf, int size)
1709 if (buf->end - buf->p < size) {
1710 int new_size = buf->end - buf->buf + size + 32;
1711 guint8 *p = (guint8 *)g_realloc (buf->buf, new_size);
1712 size = buf->p - buf->buf;
1713 buf->buf = p;
1714 buf->p = p + size;
1715 buf->end = buf->buf + new_size;
1719 static inline void
1720 buffer_add_byte (Buffer *buf, guint8 val)
1722 buffer_make_room (buf, 1);
1723 buf->p [0] = val;
1724 buf->p++;
1727 static inline void
1728 buffer_add_short (Buffer *buf, guint32 val)
1730 buffer_make_room (buf, 2);
1731 buf->p [0] = (val >> 8) & 0xff;
1732 buf->p [1] = (val >> 0) & 0xff;
1733 buf->p += 2;
1736 static inline void
1737 buffer_add_int (Buffer *buf, guint32 val)
1739 buffer_make_room (buf, 4);
1740 buf->p [0] = (val >> 24) & 0xff;
1741 buf->p [1] = (val >> 16) & 0xff;
1742 buf->p [2] = (val >> 8) & 0xff;
1743 buf->p [3] = (val >> 0) & 0xff;
1744 buf->p += 4;
1747 static inline void
1748 buffer_add_long (Buffer *buf, guint64 l)
1750 buffer_add_int (buf, (l >> 32) & 0xffffffff);
1751 buffer_add_int (buf, (l >> 0) & 0xffffffff);
1754 static inline void
1755 buffer_add_id (Buffer *buf, int id)
1757 buffer_add_int (buf, (guint64)id);
1760 static inline void
1761 buffer_add_data (Buffer *buf, guint8 *data, int len)
1763 buffer_make_room (buf, len);
1764 memcpy (buf->p, data, len);
1765 buf->p += len;
1768 static inline void
1769 buffer_add_string (Buffer *buf, const char *str)
1771 int len;
1773 if (str == NULL) {
1774 buffer_add_int (buf, 0);
1775 } else {
1776 len = strlen (str);
1777 buffer_add_int (buf, len);
1778 buffer_add_data (buf, (guint8*)str, len);
1782 static inline void
1783 buffer_add_byte_array (Buffer *buf, guint8 *bytes, guint32 arr_len)
1785 buffer_add_int (buf, arr_len);
1786 buffer_add_data (buf, bytes, arr_len);
1789 static inline void
1790 buffer_add_buffer (Buffer *buf, Buffer *data)
1792 buffer_add_data (buf, data->buf, buffer_len (data));
1795 static inline void
1796 buffer_free (Buffer *buf)
1798 g_free (buf->buf);
1801 static gboolean
1802 send_packet (int command_set, int command, Buffer *data)
1804 Buffer buf;
1805 int len, id;
1806 gboolean res;
1808 id = mono_atomic_inc_i32 (&packet_id);
1810 len = data->p - data->buf + 11;
1811 buffer_init (&buf, len);
1812 buffer_add_int (&buf, len);
1813 buffer_add_int (&buf, id);
1814 buffer_add_byte (&buf, 0); /* flags */
1815 buffer_add_byte (&buf, command_set);
1816 buffer_add_byte (&buf, command);
1817 memcpy (buf.buf + 11, data->buf, data->p - data->buf);
1819 res = transport_send (buf.buf, len);
1821 buffer_free (&buf);
1823 return res;
1826 static gboolean
1827 send_reply_packets (int npackets, ReplyPacket *packets)
1829 Buffer buf;
1830 int i, len;
1831 gboolean res;
1833 len = 0;
1834 for (i = 0; i < npackets; ++i)
1835 len += buffer_len (packets [i].data) + 11;
1836 buffer_init (&buf, len);
1837 for (i = 0; i < npackets; ++i) {
1838 buffer_add_int (&buf, buffer_len (packets [i].data) + 11);
1839 buffer_add_int (&buf, packets [i].id);
1840 buffer_add_byte (&buf, 0x80); /* flags */
1841 buffer_add_byte (&buf, (packets [i].error >> 8) & 0xff);
1842 buffer_add_byte (&buf, packets [i].error);
1843 buffer_add_buffer (&buf, packets [i].data);
1846 res = transport_send (buf.buf, len);
1848 buffer_free (&buf);
1850 return res;
1853 static gboolean
1854 send_reply_packet (int id, int error, Buffer *data)
1856 ReplyPacket packet;
1858 memset (&packet, 0, sizeof (ReplyPacket));
1859 packet.id = id;
1860 packet.error = error;
1861 packet.data = data;
1863 return send_reply_packets (1, &packet);
1866 static void
1867 send_buffered_reply_packets (void)
1869 int i;
1871 send_reply_packets (nreply_packets, reply_packets);
1872 for (i = 0; i < nreply_packets; ++i)
1873 buffer_free (reply_packets [i].data);
1874 DEBUG_PRINTF (1, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets, (long)mono_100ns_ticks () / 10000);
1875 nreply_packets = 0;
1878 static void
1879 buffer_reply_packet (int id, int error, Buffer *data)
1881 ReplyPacket *p;
1883 if (nreply_packets == 128)
1884 send_buffered_reply_packets ();
1886 p = &reply_packets [nreply_packets];
1887 p->id = id;
1888 p->error = error;
1889 p->data = g_new0 (Buffer, 1);
1890 buffer_init (p->data, buffer_len (data));
1891 buffer_add_buffer (p->data, data);
1892 nreply_packets ++;
1896 * OBJECT IDS
1900 * Represents an object accessible by the debugger client.
1902 typedef struct {
1903 /* Unique id used in the wire protocol to refer to objects */
1904 int id;
1906 * A weakref gc handle pointing to the object. The gc handle is used to
1907 * detect if the object was garbage collected.
1909 guint32 handle;
1910 } ObjRef;
1912 /* Maps objid -> ObjRef */
1913 /* Protected by the loader lock */
1914 static GHashTable *objrefs;
1915 /* Protected by the loader lock */
1916 static GHashTable *obj_to_objref;
1917 /* Protected by the dbg lock */
1918 static MonoGHashTable *suspended_objs;
1920 static void
1921 free_objref (gpointer value)
1923 ObjRef *o = (ObjRef *)value;
1925 mono_gchandle_free_internal (o->handle);
1927 g_free (o);
1930 static void
1931 objrefs_init (void)
1933 objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref);
1934 obj_to_objref = g_hash_table_new (NULL, NULL);
1935 suspended_objs = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Suspended Object Table");
1938 static void
1939 objrefs_cleanup (void)
1941 g_hash_table_destroy (objrefs);
1942 objrefs = NULL;
1946 * Return an ObjRef for OBJ.
1948 static ObjRef*
1949 get_objref (MonoObject *obj)
1951 ObjRef *ref;
1952 GSList *reflist = NULL, *l;
1953 int hash = 0;
1955 if (obj == NULL)
1956 return NULL;
1958 if (suspend_count) {
1960 * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
1962 dbg_lock ();
1963 mono_g_hash_table_insert (suspended_objs, obj, NULL);
1964 dbg_unlock ();
1967 mono_loader_lock ();
1969 /* FIXME: The tables can grow indefinitely */
1971 if (mono_gc_is_moving ()) {
1973 * Objects can move, so use a hash table mapping hash codes to lists of
1974 * ObjRef structures.
1976 hash = mono_object_hash_internal (obj);
1978 reflist = (GSList *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (hash));
1979 for (l = reflist; l; l = l->next) {
1980 ref = (ObjRef *)l->data;
1981 if (ref && mono_gchandle_get_target_internal (ref->handle) == obj) {
1982 mono_loader_unlock ();
1983 return ref;
1986 } else {
1987 /* Use a hash table with masked pointers to internalize object references */
1988 ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
1989 /* ref might refer to a different object with the same addr which was GCd */
1990 if (ref && mono_gchandle_get_target_internal (ref->handle) == obj) {
1991 mono_loader_unlock ();
1992 return ref;
1996 ref = g_new0 (ObjRef, 1);
1997 ref->id = mono_atomic_inc_i32 (&objref_id);
1998 ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE);
2000 g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
2002 if (mono_gc_is_moving ()) {
2003 reflist = g_slist_append (reflist, ref);
2004 g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (hash), reflist);
2005 } else {
2006 g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
2009 mono_loader_unlock ();
2011 return ref;
2014 static gboolean
2015 true_pred (gpointer key, gpointer value, gpointer user_data)
2017 return TRUE;
2020 static void
2021 clear_suspended_objs (void)
2023 dbg_lock ();
2024 mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL);
2025 dbg_unlock ();
2028 static inline int
2029 get_objid (MonoObject *obj)
2031 if (!obj)
2032 return 0;
2033 else
2034 return get_objref (obj)->id;
2038 * Set OBJ to the object identified by OBJID.
2039 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
2040 * collected.
2042 static ErrorCode
2043 get_object_allow_null (int objid, MonoObject **obj)
2045 ObjRef *ref;
2047 if (objid == 0) {
2048 *obj = NULL;
2049 return ERR_NONE;
2052 if (!objrefs)
2053 return ERR_INVALID_OBJECT;
2055 mono_loader_lock ();
2057 ref = (ObjRef *)g_hash_table_lookup (objrefs, GINT_TO_POINTER (objid));
2059 if (ref) {
2060 *obj = mono_gchandle_get_target_internal (ref->handle);
2061 mono_loader_unlock ();
2062 if (!(*obj))
2063 return ERR_INVALID_OBJECT;
2064 return ERR_NONE;
2065 } else {
2066 mono_loader_unlock ();
2067 return ERR_INVALID_OBJECT;
2071 static ErrorCode
2072 get_object (int objid, MonoObject **obj)
2074 ErrorCode err = get_object_allow_null (objid, obj);
2076 if (err != ERR_NONE)
2077 return err;
2078 if (!(*obj))
2079 return ERR_INVALID_OBJECT;
2080 return ERR_NONE;
2083 static inline int
2084 decode_objid (guint8 *buf, guint8 **endbuf, guint8 *limit)
2086 return decode_id (buf, endbuf, limit);
2089 static inline void
2090 buffer_add_objid (Buffer *buf, MonoObject *o)
2092 buffer_add_id (buf, get_objid (o));
2096 * IDS
2099 typedef enum {
2100 ID_ASSEMBLY = 0,
2101 ID_MODULE = 1,
2102 ID_TYPE = 2,
2103 ID_METHOD = 3,
2104 ID_FIELD = 4,
2105 ID_DOMAIN = 5,
2106 ID_PROPERTY = 6,
2107 ID_NUM
2108 } IdType;
2111 * Represents a runtime structure accessible to the debugger client
2113 typedef struct {
2114 /* Unique id used in the wire protocol */
2115 int id;
2116 /* Domain of the runtime structure, NULL if the domain was unloaded */
2117 MonoDomain *domain;
2118 union {
2119 gpointer val;
2120 MonoClass *klass;
2121 MonoMethod *method;
2122 MonoImage *image;
2123 MonoAssembly *assembly;
2124 MonoClassField *field;
2125 MonoDomain *domain;
2126 MonoProperty *property;
2127 } data;
2128 } Id;
2130 typedef struct {
2131 /* Maps runtime structure -> Id */
2132 /* Protected by the dbg lock */
2133 GHashTable *val_to_id [ID_NUM];
2134 /* Classes whose class load event has been sent */
2135 /* Protected by the loader lock */
2136 GHashTable *loaded_classes;
2137 /* Maps MonoClass->GPtrArray of file names */
2138 GHashTable *source_files;
2139 /* Maps source file basename -> GSList of classes */
2140 GHashTable *source_file_to_class;
2141 /* Same with ignore-case */
2142 GHashTable *source_file_to_class_ignorecase;
2143 } AgentDomainInfo;
2145 /* Maps id -> Id */
2146 /* Protected by the dbg lock */
2147 static GPtrArray *ids [ID_NUM];
2149 static void
2150 ids_init (void)
2152 int i;
2154 for (i = 0; i < ID_NUM; ++i)
2155 ids [i] = g_ptr_array_new ();
2158 static void
2159 ids_cleanup (void)
2161 int i, j;
2163 for (i = 0; i < ID_NUM; ++i) {
2164 if (ids [i]) {
2165 for (j = 0; j < ids [i]->len; ++j)
2166 g_free (g_ptr_array_index (ids [i], j));
2167 g_ptr_array_free (ids [i], TRUE);
2169 ids [i] = NULL;
2173 static void
2174 debugger_agent_free_domain_info (MonoDomain *domain)
2176 AgentDomainInfo *info = (AgentDomainInfo *)domain_jit_info (domain)->agent_info;
2177 int i, j;
2178 GHashTableIter iter;
2179 GPtrArray *file_names;
2180 char *basename;
2181 GSList *l;
2183 if (info) {
2184 for (i = 0; i < ID_NUM; ++i)
2185 g_hash_table_destroy (info->val_to_id [i]);
2186 g_hash_table_destroy (info->loaded_classes);
2188 g_hash_table_iter_init (&iter, info->source_files);
2189 while (g_hash_table_iter_next (&iter, NULL, (void**)&file_names)) {
2190 for (i = 0; i < file_names->len; ++i)
2191 g_free (g_ptr_array_index (file_names, i));
2192 g_ptr_array_free (file_names, TRUE);
2195 g_hash_table_iter_init (&iter, info->source_file_to_class);
2196 while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
2197 g_free (basename);
2198 g_slist_free (l);
2201 g_hash_table_iter_init (&iter, info->source_file_to_class_ignorecase);
2202 while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
2203 g_free (basename);
2204 g_slist_free (l);
2207 g_free (info);
2210 domain_jit_info (domain)->agent_info = NULL;
2212 /* Clear ids referencing structures in the domain */
2213 dbg_lock ();
2214 for (i = 0; i < ID_NUM; ++i) {
2215 if (ids [i]) {
2216 for (j = 0; j < ids [i]->len; ++j) {
2217 Id *id = (Id *)g_ptr_array_index (ids [i], j);
2218 if (id->domain == domain)
2219 id->domain = NULL;
2223 dbg_unlock ();
2225 mono_de_domain_remove (domain);
2228 static AgentDomainInfo*
2229 get_agent_domain_info (MonoDomain *domain)
2231 AgentDomainInfo *info = NULL;
2233 mono_domain_lock (domain);
2235 info = (AgentDomainInfo *)domain_jit_info (domain)->agent_info;
2236 if (!info) {
2237 info = g_new0 (AgentDomainInfo, 1);
2238 domain_jit_info (domain)->agent_info = info;
2239 info->loaded_classes = g_hash_table_new (mono_aligned_addr_hash, NULL);
2240 info->source_files = g_hash_table_new (mono_aligned_addr_hash, NULL);
2241 info->source_file_to_class = g_hash_table_new (g_str_hash, g_str_equal);
2242 info->source_file_to_class_ignorecase = g_hash_table_new (g_str_hash, g_str_equal);
2245 mono_domain_unlock (domain);
2247 return info;
2250 static int
2251 get_id (MonoDomain *domain, IdType type, gpointer val)
2253 Id *id;
2254 AgentDomainInfo *info;
2256 if (val == NULL)
2257 return 0;
2259 info = get_agent_domain_info (domain);
2261 dbg_lock ();
2263 if (info->val_to_id [type] == NULL)
2264 info->val_to_id [type] = g_hash_table_new (mono_aligned_addr_hash, NULL);
2266 id = (Id *)g_hash_table_lookup (info->val_to_id [type], val);
2267 if (id) {
2268 dbg_unlock ();
2269 return id->id;
2272 id = g_new0 (Id, 1);
2273 /* Reserve id 0 */
2274 id->id = ids [type]->len + 1;
2275 id->domain = domain;
2276 id->data.val = val;
2278 g_hash_table_insert (info->val_to_id [type], val, id);
2279 g_ptr_array_add (ids [type], id);
2281 dbg_unlock ();
2283 return id->id;
2286 static inline gpointer
2287 decode_ptr_id (guint8 *buf, guint8 **endbuf, guint8 *limit, IdType type, MonoDomain **domain, ErrorCode *err)
2289 Id *res;
2291 int id = decode_id (buf, endbuf, limit);
2293 *err = ERR_NONE;
2294 if (domain)
2295 *domain = NULL;
2297 if (id == 0)
2298 return NULL;
2300 // FIXME: error handling
2301 dbg_lock ();
2302 g_assert (id > 0 && id <= ids [type]->len);
2304 res = (Id *)g_ptr_array_index (ids [type], GPOINTER_TO_INT (id - 1));
2305 dbg_unlock ();
2307 if (res->domain == NULL || res->domain->state == MONO_APPDOMAIN_UNLOADED) {
2308 DEBUG_PRINTF (1, "ERR_UNLOADED, id=%d, type=%d.\n", id, type);
2309 *err = ERR_UNLOADED;
2310 return NULL;
2313 if (domain)
2314 *domain = res->domain;
2316 return res->data.val;
2319 static inline int
2320 buffer_add_ptr_id (Buffer *buf, MonoDomain *domain, IdType type, gpointer val)
2322 int id = get_id (domain, type, val);
2324 buffer_add_id (buf, id);
2325 return id;
2328 static inline MonoClass*
2329 decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2331 MonoClass *klass;
2333 klass = (MonoClass *)decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err);
2334 if (G_UNLIKELY (log_level >= 2) && klass) {
2335 char *s;
2337 s = mono_type_full_name (m_class_get_byval_arg (klass));
2338 DEBUG_PRINTF (2, "[dbg] recv class [%s]\n", s);
2339 g_free (s);
2341 return klass;
2344 static inline MonoAssembly*
2345 decode_assemblyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2347 return (MonoAssembly *)decode_ptr_id (buf, endbuf, limit, ID_ASSEMBLY, domain, err);
2350 static inline MonoImage*
2351 decode_moduleid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2353 return (MonoImage *)decode_ptr_id (buf, endbuf, limit, ID_MODULE, domain, err);
2356 static inline MonoMethod*
2357 decode_methodid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2359 MonoMethod *m;
2361 m = (MonoMethod *)decode_ptr_id (buf, endbuf, limit, ID_METHOD, domain, err);
2362 if (G_UNLIKELY (log_level >= 2) && m) {
2363 char *s;
2365 s = mono_method_full_name (m, TRUE);
2366 DEBUG_PRINTF (2, "[dbg] recv method [%s]\n", s);
2367 g_free (s);
2369 return m;
2372 static inline MonoClassField*
2373 decode_fieldid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2375 return (MonoClassField *)decode_ptr_id (buf, endbuf, limit, ID_FIELD, domain, err);
2378 static inline MonoDomain*
2379 decode_domainid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2381 return (MonoDomain *)decode_ptr_id (buf, endbuf, limit, ID_DOMAIN, domain, err);
2384 static inline MonoProperty*
2385 decode_propertyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2387 return (MonoProperty *)decode_ptr_id (buf, endbuf, limit, ID_PROPERTY, domain, err);
2390 static inline void
2391 buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
2393 buffer_add_ptr_id (buf, domain, ID_TYPE, klass);
2394 if (G_UNLIKELY (log_level >= 2) && klass) {
2395 char *s;
2397 s = mono_type_full_name (m_class_get_byval_arg (klass));
2398 if (is_debugger_thread ())
2399 DEBUG_PRINTF (2, "[dbg] send class [%s]\n", s);
2400 else
2401 DEBUG_PRINTF (2, "[%p] send class [%s]\n", (gpointer) (gsize) mono_native_thread_id_get (), s);
2402 g_free (s);
2406 static inline void
2407 buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method)
2409 buffer_add_ptr_id (buf, domain, ID_METHOD, method);
2410 if (G_UNLIKELY (log_level >= 2) && method) {
2411 char *s;
2413 s = mono_method_full_name (method, 1);
2414 if (is_debugger_thread ())
2415 DEBUG_PRINTF (2, "[dbg] send method [%s]\n", s);
2416 else
2417 DEBUG_PRINTF (2, "[%p] send method [%s]\n", (gpointer) (gsize) mono_native_thread_id_get (), s);
2418 g_free (s);
2422 static inline void
2423 buffer_add_assemblyid (Buffer *buf, MonoDomain *domain, MonoAssembly *assembly)
2425 int id;
2427 id = buffer_add_ptr_id (buf, domain, ID_ASSEMBLY, assembly);
2428 if (G_UNLIKELY (log_level >= 2) && assembly)
2429 DEBUG_PRINTF (2, "[dbg] send assembly [%s][%s][%d]\n", assembly->aname.name, domain->friendly_name, id);
2432 static inline void
2433 buffer_add_moduleid (Buffer *buf, MonoDomain *domain, MonoImage *image)
2435 buffer_add_ptr_id (buf, domain, ID_MODULE, image);
2438 static inline void
2439 buffer_add_fieldid (Buffer *buf, MonoDomain *domain, MonoClassField *field)
2441 buffer_add_ptr_id (buf, domain, ID_FIELD, field);
2444 static inline void
2445 buffer_add_propertyid (Buffer *buf, MonoDomain *domain, MonoProperty *property)
2447 buffer_add_ptr_id (buf, domain, ID_PROPERTY, property);
2450 static inline void
2451 buffer_add_domainid (Buffer *buf, MonoDomain *domain)
2453 buffer_add_ptr_id (buf, domain, ID_DOMAIN, domain);
2456 static void invoke_method (void);
2459 * SUSPEND/RESUME
2462 static MonoJitInfo*
2463 get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip)
2465 MonoJitInfo *ji;
2467 if (out_ip)
2468 *out_ip = ip;
2470 ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain);
2471 if (!ji) {
2472 /* Could be an interpreter method */
2474 MonoLMF *lmf = mono_get_lmf ();
2475 MonoInterpFrameHandle *frame;
2477 g_assert (((gsize)lmf->previous_lmf) & 2);
2478 MonoLMFExt *ext = (MonoLMFExt*)lmf;
2480 g_assert (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX);
2481 frame = (MonoInterpFrameHandle*)ext->interp_exit_data;
2482 ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame);
2483 if (domain)
2484 *domain = mono_domain_get ();
2485 if (out_ip)
2486 *out_ip = mini_get_interp_callbacks ()->frame_get_ip (frame);
2488 return ji;
2492 * save_thread_context:
2494 * Set CTX as the current threads context which is used for computing stack traces.
2495 * This function is signal-safe.
2497 static void
2498 save_thread_context (MonoContext *ctx)
2500 DebuggerTlsData *tls;
2502 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
2503 g_assert (tls);
2505 if (ctx)
2506 mono_thread_state_init_from_monoctx (&tls->context, ctx);
2507 else
2508 mono_thread_state_init_from_current (&tls->context);
2511 /* Number of threads suspended */
2513 * If this is equal to the size of thread_to_tls, the runtime is considered
2514 * suspended.
2516 static gint32 threads_suspend_count;
2518 static MonoCoopMutex suspend_mutex;
2520 /* Cond variable used to wait for suspend_count becoming 0 */
2521 static MonoCoopCond suspend_cond;
2523 /* Semaphore used to wait for a thread becoming suspended */
2524 static MonoCoopSem suspend_sem;
2526 static void
2527 suspend_init (void)
2529 mono_coop_mutex_init (&suspend_mutex);
2530 mono_coop_cond_init (&suspend_cond);
2531 mono_coop_sem_init (&suspend_sem, 0);
2534 typedef struct
2536 StackFrameInfo last_frame;
2537 gboolean last_frame_set;
2538 MonoContext ctx;
2539 gpointer lmf;
2540 MonoDomain *domain;
2541 } GetLastFrameUserData;
2543 static gboolean
2544 get_last_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
2546 GetLastFrameUserData *data = (GetLastFrameUserData *)user_data;
2548 if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE || info->type == FRAME_TYPE_TRAMPOLINE)
2549 return FALSE;
2551 if (!data->last_frame_set) {
2552 /* Store the last frame */
2553 memcpy (&data->last_frame, info, sizeof (StackFrameInfo));
2554 data->last_frame_set = TRUE;
2555 return FALSE;
2556 } else {
2557 /* Store the context/lmf for the frame above the last frame */
2558 memcpy (&data->ctx, ctx, sizeof (MonoContext));
2559 data->lmf = info->lmf;
2560 data->domain = info->domain;
2561 return TRUE;
2565 static void
2566 copy_unwind_state_from_frame_data (MonoThreadUnwindState *to, GetLastFrameUserData *data, gpointer jit_tls)
2568 memcpy (&to->ctx, &data->ctx, sizeof (MonoContext));
2570 to->unwind_data [MONO_UNWIND_DATA_DOMAIN] = data->domain;
2571 to->unwind_data [MONO_UNWIND_DATA_LMF] = data->lmf;
2572 to->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
2573 to->valid = TRUE;
2577 * thread_interrupt:
2579 * Process interruption of a thread. This should be signal safe.
2581 * This always runs in the debugger thread.
2583 static void
2584 thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
2586 gpointer ip;
2587 MonoNativeThreadId tid;
2589 g_assert (info);
2591 ip = MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx);
2592 tid = mono_thread_info_get_tid (info);
2594 // FIXME: Races when the thread leaves managed code before hitting a single step
2595 // event.
2597 if (ji && !ji->is_trampoline) {
2598 /* Running managed code, will be suspended by the single step code */
2599 DEBUG_PRINTF (1, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip);
2600 } else {
2602 * Running native code, will be suspended when it returns to/enters
2603 * managed code. Treat it as already suspended.
2604 * This might interrupt the code in mono_de_process_single_step (), we use the
2605 * tls->suspending flag to avoid races when that happens.
2607 if (!tls->suspended && !tls->suspending) {
2608 GetLastFrameUserData data;
2610 // FIXME: printf is not signal safe, but this is only used during
2611 // debugger debugging
2612 if (ip)
2613 DEBUG_PRINTF (1, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)(gsize)tid, ip);
2614 //save_thread_context (&ctx);
2616 if (!tls->thread)
2617 /* Already terminated */
2618 return;
2621 * We are in a difficult position: we want to be able to provide stack
2622 * traces for this thread, but we can't use the current ctx+lmf, since
2623 * the thread is still running, so it might return to managed code,
2624 * making these invalid.
2625 * So we start a stack walk and save the first frame, along with the
2626 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
2627 * suspended when it returns to managed code, so the parent's ctx should
2628 * remain valid.
2630 MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info);
2632 data.last_frame_set = FALSE;
2633 mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, MONO_UNWIND_SIGNAL_SAFE, &data);
2634 if (data.last_frame_set) {
2635 gpointer jit_tls = tls->thread->thread_info->jit_data;
2637 memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
2639 if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED || data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
2641 * Store the current lmf instead of the parent one, since that
2642 * contains the interp exit data.
2644 data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF];
2647 copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
2648 /* Don't set tls->context, it could race with the thread processing a breakpoint etc. */
2649 } else {
2650 tls->async_state.valid = FALSE;
2653 mono_memory_barrier ();
2655 tls->suspended = TRUE;
2656 mono_coop_sem_post (&suspend_sem);
2662 * reset_native_thread_suspend_state:
2664 * Reset the suspended flag and state on native threads
2666 static void
2667 reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_data)
2669 DebuggerTlsData *tls = (DebuggerTlsData *)value;
2671 if (!tls->really_suspended && tls->suspended) {
2672 tls->suspended = FALSE;
2674 * The thread might still be running if it was executing native code, so the state won't be invalided by
2675 * suspend_current ().
2677 tls->context.valid = FALSE;
2678 tls->async_state.valid = FALSE;
2679 invalidate_frames (tls);
2683 typedef struct {
2684 DebuggerTlsData *tls;
2685 gboolean valid_info;
2686 } InterruptData;
2688 static SuspendThreadResult
2689 debugger_interrupt_critical (MonoThreadInfo *info, gpointer user_data)
2691 InterruptData *data = (InterruptData *)user_data;
2692 MonoJitInfo *ji;
2694 data->valid_info = TRUE;
2695 ji = mono_jit_info_table_find_internal (
2696 (MonoDomain *)mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN],
2697 MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx),
2698 TRUE,
2699 TRUE);
2701 /* This is signal safe */
2702 thread_interrupt (data->tls, info, ji);
2703 return MonoResumeThread;
2707 * notify_thread:
2709 * Notify a thread that it needs to suspend.
2711 static void
2712 notify_thread (gpointer key, gpointer value, gpointer user_data)
2714 MonoInternalThread *thread = (MonoInternalThread *)key;
2715 DebuggerTlsData *tls = (DebuggerTlsData *)value;
2716 MonoNativeThreadId tid = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
2718 if (mono_thread_internal_is_current (thread) || tls->terminated)
2719 return;
2721 DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer) (gsize) mono_native_thread_id_get (), (gpointer)tid);
2723 /* This is _not_ equivalent to mono_thread_internal_abort () */
2724 InterruptData interrupt_data = { 0 };
2725 interrupt_data.tls = tls;
2727 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, debugger_interrupt_critical, &interrupt_data);
2728 if (!interrupt_data.valid_info) {
2729 DEBUG_PRINTF (1, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer) (gsize) mono_native_thread_id_get (), (gpointer)tid);
2731 * Attached thread which died without detaching.
2733 tls->terminated = TRUE;
2737 static void
2738 process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
2740 guint8 *ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
2741 MonoJitInfo *ji;
2742 MonoMethod *method;
2744 if (mono_loader_lock_is_owned_by_self ()) {
2746 * Shortcut for the check in suspend_current (). This speeds up processing
2747 * when executing long running code inside the loader lock, i.e. assembly load
2748 * hooks.
2750 return;
2753 if (is_debugger_thread ())
2754 return;
2756 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2757 if (suspend_count - tls->resume_count > 0)
2758 tls->suspending = TRUE;
2760 DEBUG_PRINTF (1, "[%p] Received single step event for suspending.\n", (gpointer) (gsize) mono_native_thread_id_get ());
2762 if (suspend_count - tls->resume_count == 0) {
2764 * We are executing a single threaded invoke but the single step for
2765 * suspending is still active.
2766 * FIXME: This slows down single threaded invokes.
2768 DEBUG_PRINTF (1, "[%p] Ignored during single threaded invoke.\n", (gpointer) (gsize) mono_native_thread_id_get ());
2769 return;
2772 ji = get_top_method_ji (ip, NULL, NULL);
2773 g_assert (ji);
2774 /* Can't suspend in these methods */
2775 method = jinfo_get_method (ji);
2776 if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
2777 return;
2779 save_thread_context (ctx);
2781 suspend_current ();
2785 /* Conditionally call process_suspend depending oh the current state */
2786 static gboolean
2787 try_process_suspend (void *the_tls, MonoContext *ctx)
2789 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
2791 if (suspend_count > 0) {
2792 /* Fastpath during invokes, see in process_suspend () */
2793 if (suspend_count - tls->resume_count == 0)
2794 return FALSE;
2795 process_suspend (tls, ctx);
2796 return TRUE;
2798 return FALSE;
2802 * suspend_vm:
2804 * Increase the suspend count of the VM. While the suspend count is greater
2805 * than 0, runtime threads are suspended at certain points during execution.
2807 static void
2808 suspend_vm (void)
2810 gboolean tp_suspend = FALSE;
2811 mono_loader_lock ();
2813 mono_coop_mutex_lock (&suspend_mutex);
2815 suspend_count ++;
2817 DEBUG_PRINTF (1, "[%p] Suspending vm...\n", (gpointer) (gsize) mono_native_thread_id_get ());
2819 if (suspend_count == 1) {
2820 // FIXME: Is it safe to call this inside the lock ?
2821 mono_de_start_single_stepping ();
2822 mono_g_hash_table_foreach (thread_to_tls, notify_thread, NULL);
2825 mono_coop_mutex_unlock (&suspend_mutex);
2827 if (suspend_count == 1)
2829 * Suspend creation of new threadpool threads, since they cannot run
2831 tp_suspend = TRUE;
2832 mono_loader_unlock ();
2834 if (tp_suspend)
2835 mono_threadpool_suspend ();
2839 * resume_vm:
2841 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2842 * are resumed.
2844 static void
2845 resume_vm (void)
2847 g_assert (is_debugger_thread ());
2848 gboolean tp_resume = FALSE;
2850 mono_loader_lock ();
2852 mono_coop_mutex_lock (&suspend_mutex);
2854 g_assert (suspend_count > 0);
2855 suspend_count --;
2857 DEBUG_PRINTF (1, "[%p] Resuming vm, suspend count=%d...\n", (gpointer) (gsize) mono_native_thread_id_get (), suspend_count);
2859 if (suspend_count == 0) {
2860 // FIXME: Is it safe to call this inside the lock ?
2861 mono_de_stop_single_stepping ();
2862 mono_g_hash_table_foreach (thread_to_tls, reset_native_thread_suspend_state, NULL);
2865 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2866 mono_coop_cond_broadcast (&suspend_cond);
2868 mono_coop_mutex_unlock (&suspend_mutex);
2869 //g_assert (err == 0);
2871 if (suspend_count == 0)
2872 tp_resume = TRUE;
2873 mono_loader_unlock ();
2875 if (tp_resume)
2876 mono_threadpool_resume ();
2880 * resume_thread:
2882 * Resume just one thread.
2884 static void
2885 resume_thread (MonoInternalThread *thread)
2887 DebuggerTlsData *tls;
2889 g_assert (is_debugger_thread ());
2891 mono_loader_lock ();
2893 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
2894 g_assert (tls);
2896 mono_coop_mutex_lock (&suspend_mutex);
2898 g_assert (suspend_count > 0);
2900 DEBUG_PRINTF (1, "[sdb] Resuming thread %p...\n", (gpointer)(gssize)thread->tid);
2902 tls->resume_count += suspend_count;
2905 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2906 * but only the one whose resume_count field is > 0 will be resumed.
2908 mono_coop_cond_broadcast (&suspend_cond);
2910 mono_coop_mutex_unlock (&suspend_mutex);
2911 //g_assert (err == 0);
2913 mono_loader_unlock ();
2916 static void
2917 free_frames (StackFrame **frames, int nframes)
2919 int i;
2921 for (i = 0; i < nframes; ++i) {
2922 if (frames [i]->jit)
2923 mono_debug_free_method_jit_info (frames [i]->jit);
2924 g_free (frames [i]);
2926 g_free (frames);
2929 static void
2930 invalidate_frames (DebuggerTlsData *tls)
2932 mono_loader_lock ();
2934 if (!tls)
2935 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
2936 g_assert (tls);
2938 free_frames (tls->frames, tls->frame_count);
2939 tls->frame_count = 0;
2940 tls->frames = NULL;
2942 free_frames (tls->restore_frames, tls->restore_frame_count);
2943 tls->restore_frame_count = 0;
2944 tls->restore_frames = NULL;
2946 mono_loader_unlock ();
2950 * suspend_current:
2952 * Suspend the current thread until the runtime is resumed. If the thread has a
2953 * pending invoke, then the invoke is executed before this function returns.
2955 static void
2956 suspend_current (void)
2958 DebuggerTlsData *tls;
2960 g_assert (!is_debugger_thread ());
2962 if (mono_loader_lock_is_owned_by_self ()) {
2964 * If we own the loader mutex, can't suspend until we release it, since the
2965 * whole runtime can deadlock otherwise.
2967 return;
2970 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
2971 g_assert (tls);
2973 mono_coop_mutex_lock (&suspend_mutex);
2975 tls->suspending = FALSE;
2976 tls->really_suspended = TRUE;
2978 if (!tls->suspended) {
2979 tls->suspended = TRUE;
2980 mono_coop_sem_post (&suspend_sem);
2983 mono_debugger_log_suspend (tls);
2984 DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer) (gsize) mono_native_thread_id_get ());
2986 while (suspend_count - tls->resume_count > 0) {
2987 mono_coop_cond_wait (&suspend_cond, &suspend_mutex);
2990 tls->suspended = FALSE;
2991 tls->really_suspended = FALSE;
2993 threads_suspend_count --;
2995 mono_coop_mutex_unlock (&suspend_mutex);
2997 mono_debugger_log_resume (tls);
2998 DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer) (gsize) mono_native_thread_id_get ());
3000 if (tls->pending_invoke) {
3001 /* Save the original context */
3002 tls->pending_invoke->has_ctx = TRUE;
3003 tls->pending_invoke->ctx = tls->context.ctx;
3005 invoke_method ();
3008 /* The frame info becomes invalid after a resume */
3009 tls->context.valid = FALSE;
3010 tls->async_state.valid = FALSE;
3011 invalidate_frames (tls);
3014 static void
3015 count_thread (gpointer key, gpointer value, gpointer user_data)
3017 DebuggerTlsData *tls = (DebuggerTlsData *)value;
3019 if (!tls->suspended && !tls->terminated && !mono_thread_internal_is_current (tls->thread))
3020 *(int*)user_data = *(int*)user_data + 1;
3023 static int
3024 count_threads_to_wait_for (void)
3026 int count = 0;
3028 mono_loader_lock ();
3029 mono_g_hash_table_foreach (thread_to_tls, count_thread, &count);
3030 mono_loader_unlock ();
3032 return count;
3036 * wait_for_suspend:
3038 * Wait until the runtime is completely suspended.
3040 static void
3041 wait_for_suspend (void)
3043 int nthreads, nwait, err;
3044 gboolean waited = FALSE;
3046 // FIXME: Threads starting/stopping ?
3047 mono_loader_lock ();
3048 nthreads = mono_g_hash_table_size (thread_to_tls);
3049 mono_loader_unlock ();
3051 while (TRUE) {
3052 nwait = count_threads_to_wait_for ();
3053 if (nwait) {
3054 DEBUG_PRINTF (1, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads);
3055 err = mono_coop_sem_wait (&suspend_sem, MONO_SEM_FLAGS_NONE);
3056 g_assert (err == 0);
3057 waited = TRUE;
3058 } else {
3059 break;
3063 if (waited)
3064 DEBUG_PRINTF (1, "%d threads suspended.\n", nthreads);
3068 * is_suspended:
3070 * Return whenever the runtime is suspended.
3072 static gboolean
3073 is_suspended (void)
3075 return count_threads_to_wait_for () == 0;
3078 static void
3079 no_seq_points_found (MonoMethod *method, int offset)
3082 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
3084 printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method, TRUE), offset);
3087 typedef struct {
3088 DebuggerTlsData *tls;
3089 GSList *frames;
3090 gboolean set_debugger_flag;
3091 } ComputeFramesUserData;
3093 static gboolean
3094 process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
3096 ComputeFramesUserData *ud = (ComputeFramesUserData *)user_data;
3097 StackFrame *frame;
3098 MonoMethod *method, *actual_method, *api_method;
3099 SeqPoint sp;
3100 int flags = 0;
3102 mono_loader_lock ();
3103 if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP && info->type != FRAME_TYPE_MANAGED_TO_NATIVE) {
3104 if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
3105 /* Mark the last frame as an invoke frame */
3106 if (ud->frames)
3107 ((StackFrame*)g_slist_last (ud->frames)->data)->flags |= FRAME_FLAG_DEBUGGER_INVOKE;
3108 else
3109 ud->set_debugger_flag = TRUE;
3111 mono_loader_unlock ();
3112 return FALSE;
3115 if (info->ji)
3116 method = jinfo_get_method (info->ji);
3117 else
3118 method = info->method;
3119 actual_method = info->actual_method;
3120 api_method = method;
3122 if (!method) {
3123 mono_loader_unlock ();
3124 return FALSE;
3127 if (!method || (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)) {
3128 mono_loader_unlock ();
3129 return FALSE;
3132 if (info->il_offset == -1) {
3133 /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
3134 if (ud->frames == NULL) {
3135 if (mono_find_prev_seq_point_for_native_offset (info->domain, method, info->native_offset, NULL, &sp))
3136 info->il_offset = sp.il_offset;
3138 if (info->il_offset == -1)
3139 info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
3142 DEBUG_PRINTF (1, "\tFrame: %s:[il=0x%x, native=0x%x] %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed);
3144 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
3145 if (!CHECK_PROTOCOL_VERSION (2, 17)) {
3146 /* Older clients can't handle this flag */
3147 mono_loader_unlock ();
3148 return FALSE;
3150 api_method = mono_marshal_method_from_wrapper (method);
3151 if (!api_method) {
3152 mono_loader_unlock ();
3153 return FALSE;
3155 actual_method = api_method;
3156 flags |= FRAME_FLAG_NATIVE_TRANSITION;
3159 if (ud->set_debugger_flag) {
3160 g_assert (g_slist_length (ud->frames) == 0);
3161 flags |= FRAME_FLAG_DEBUGGER_INVOKE;
3162 ud->set_debugger_flag = FALSE;
3165 frame = g_new0 (StackFrame, 1);
3166 frame->de.ji = info->ji;
3167 frame->de.domain = info->domain;
3168 frame->de.method = method;
3169 frame->de.native_offset = info->native_offset;
3171 frame->actual_method = actual_method;
3172 frame->api_method = api_method;
3173 frame->il_offset = info->il_offset;
3174 frame->flags = flags;
3175 frame->interp_frame = info->interp_frame;
3176 frame->frame_addr = info->frame_addr;
3177 if (info->reg_locations)
3178 memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
3179 if (ctx) {
3180 frame->ctx = *ctx;
3181 frame->has_ctx = TRUE;
3184 ud->frames = g_slist_append (ud->frames, frame);
3186 mono_loader_unlock ();
3187 return FALSE;
3190 static gboolean
3191 process_filter_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
3193 ComputeFramesUserData *ud = (ComputeFramesUserData *)user_data;
3196 * 'tls->filter_ctx' is the location of the throw site.
3198 * mono_walk_stack() will never actually hit the throw site, but unwind
3199 * directly from the filter to the call site; we abort stack unwinding here
3200 * once this happens and resume from the throw site.
3202 if (info->frame_addr >= MONO_CONTEXT_GET_SP (&ud->tls->filter_state.ctx))
3203 return TRUE;
3205 return process_frame (info, ctx, user_data);
3209 * Return a malloc-ed list of StackFrame structures.
3211 static StackFrame**
3212 compute_frame_info_from (MonoInternalThread *thread, DebuggerTlsData *tls, MonoThreadUnwindState *state, int *out_nframes)
3214 ComputeFramesUserData user_data;
3215 MonoUnwindOptions opts = (MonoUnwindOptions)(MONO_UNWIND_DEFAULT | MONO_UNWIND_REG_LOCATIONS);
3216 StackFrame **res;
3217 int i, nframes;
3218 GSList *l;
3220 user_data.tls = tls;
3221 user_data.frames = NULL;
3223 mono_walk_stack_with_state (process_frame, state, opts, &user_data);
3225 nframes = g_slist_length (user_data.frames);
3226 res = g_new0 (StackFrame*, nframes);
3227 l = user_data.frames;
3228 for (i = 0; i < nframes; ++i) {
3229 res [i] = (StackFrame *)l->data;
3230 l = l->next;
3232 *out_nframes = nframes;
3234 return res;
3237 static void
3238 compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls)
3240 ComputeFramesUserData user_data;
3241 GSList *tmp;
3242 int i, findex, new_frame_count;
3243 StackFrame **new_frames, *f;
3244 MonoUnwindOptions opts = (MonoUnwindOptions)(MONO_UNWIND_DEFAULT | MONO_UNWIND_REG_LOCATIONS);
3246 // FIXME: Locking on tls
3247 if (tls->frames && tls->frames_up_to_date)
3248 return;
3250 DEBUG_PRINTF (1, "Frames for %p(tid=%lx):\n", thread, (glong)thread->tid);
3252 user_data.tls = tls;
3253 user_data.frames = NULL;
3254 if (tls->terminated) {
3255 tls->frame_count = 0;
3256 return;
3257 } if (!tls->really_suspended && tls->async_state.valid) {
3258 /* Have to use the state saved by the signal handler */
3259 process_frame (&tls->async_last_frame, NULL, &user_data);
3260 mono_walk_stack_with_state (process_frame, &tls->async_state, opts, &user_data);
3261 } else if (tls->filter_state.valid) {
3263 * We are inside an exception filter.
3265 * First we add all the frames from inside the filter; 'tls->ctx' has the current context.
3267 if (tls->context.valid) {
3268 mono_walk_stack_with_state (process_filter_frame, &tls->context, opts, &user_data);
3269 DEBUG_PRINTF (1, "\tFrame: <call filter>\n");
3272 * After that, we resume unwinding from the location where the exception has been thrown.
3274 mono_walk_stack_with_state (process_frame, &tls->filter_state, opts, &user_data);
3275 } else if (tls->context.valid) {
3276 mono_walk_stack_with_state (process_frame, &tls->context, opts, &user_data);
3277 } else {
3278 // FIXME:
3279 tls->frame_count = 0;
3280 return;
3283 new_frame_count = g_slist_length (user_data.frames);
3284 new_frames = g_new0 (StackFrame*, new_frame_count);
3285 findex = 0;
3286 for (tmp = user_data.frames; tmp; tmp = tmp->next) {
3287 f = (StackFrame *)tmp->data;
3290 * Reuse the id for already existing stack frames, so invokes don't invalidate
3291 * the still valid stack frames.
3293 for (i = 0; i < tls->frame_count; ++i) {
3294 if (tls->frames [i]->frame_addr == f->frame_addr) {
3295 f->id = tls->frames [i]->id;
3296 break;
3300 if (i >= tls->frame_count)
3301 f->id = mono_atomic_inc_i32 (&frame_id);
3303 new_frames [findex ++] = f;
3306 g_slist_free (user_data.frames);
3308 invalidate_frames (tls);
3310 tls->frames = new_frames;
3311 tls->frame_count = new_frame_count;
3312 tls->frames_up_to_date = TRUE;
3316 * GHFunc to emit an appdomain creation event
3317 * @param key Don't care
3318 * @param value A loaded appdomain
3319 * @param user_data Don't care
3321 static void
3322 emit_appdomain_load (gpointer key, gpointer value, gpointer user_data)
3324 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE, value);
3325 g_hash_table_foreach (get_agent_domain_info ((MonoDomain *)value)->loaded_classes, emit_type_load, NULL);
3329 * GHFunc to emit a thread start event
3330 * @param key A thread id
3331 * @param value A thread object
3332 * @param user_data Don't care
3334 static void
3335 emit_thread_start (gpointer key, gpointer value, gpointer user_data)
3337 g_assert (!mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (key)), debugger_thread_id));
3338 process_profiler_event (EVENT_KIND_THREAD_START, value);
3342 * GFunc to emit an assembly load event
3343 * @param value A loaded assembly
3344 * @param user_data Don't care
3346 static void
3347 emit_assembly_load (gpointer value, gpointer user_data)
3349 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, value);
3353 * GFunc to emit a type load event
3354 * @param value A loaded type
3355 * @param user_data Don't care
3357 static void
3358 emit_type_load (gpointer key, gpointer value, gpointer user_data)
3360 process_profiler_event (EVENT_KIND_TYPE_LOAD, value);
3363 static char*
3364 strdup_tolower (char *s)
3366 char *s2, *p;
3368 s2 = g_strdup (s);
3369 for (p = s2; *p; ++p)
3370 *p = tolower (*p);
3371 return s2;
3375 * Same as g_path_get_basename () but handles windows paths as well,
3376 * which can occur in .mdb files created by pdb2mdb.
3378 static char*
3379 dbg_path_get_basename (const char *filename)
3381 char *r;
3383 if (!filename || strchr (filename, '/') || !strchr (filename, '\\'))
3384 return g_path_get_basename (filename);
3386 /* From gpath.c */
3388 /* No separator -> filename */
3389 r = (char*)strrchr (filename, '\\');
3390 if (r == NULL)
3391 return g_strdup (filename);
3393 /* Trailing slash, remove component */
3394 if (r [1] == 0){
3395 char *copy = g_strdup (filename);
3396 copy [r-filename] = 0;
3397 r = strrchr (copy, '\\');
3399 if (r == NULL){
3400 g_free (copy);
3401 return g_strdup ("/");
3403 r = g_strdup (&r[1]);
3404 g_free (copy);
3405 return r;
3408 return g_strdup (&r[1]);
3411 static void
3412 init_jit_info_dbg_attrs (MonoJitInfo *ji)
3414 static MonoClass *hidden_klass, *step_through_klass, *non_user_klass;
3415 ERROR_DECL (error);
3416 MonoCustomAttrInfo *ainfo;
3418 if (ji->dbg_attrs_inited)
3419 return;
3421 if (!hidden_klass)
3422 hidden_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerHiddenAttribute");
3424 if (!step_through_klass)
3425 step_through_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerStepThroughAttribute");
3427 if (!non_user_klass)
3428 non_user_klass = mono_class_load_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggerNonUserCodeAttribute");
3430 ainfo = mono_custom_attrs_from_method_checked (jinfo_get_method (ji), error);
3431 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3432 if (ainfo) {
3433 if (mono_custom_attrs_has_attr (ainfo, hidden_klass))
3434 ji->dbg_hidden = TRUE;
3435 if (mono_custom_attrs_has_attr (ainfo, step_through_klass))
3436 ji->dbg_step_through = TRUE;
3437 if (mono_custom_attrs_has_attr (ainfo, non_user_klass))
3438 ji->dbg_non_user_code = TRUE;
3439 mono_custom_attrs_free (ainfo);
3442 ainfo = mono_custom_attrs_from_class_checked (jinfo_get_method (ji)->klass, error);
3443 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3444 if (ainfo) {
3445 if (mono_custom_attrs_has_attr (ainfo, step_through_klass))
3446 ji->dbg_step_through = TRUE;
3447 if (mono_custom_attrs_has_attr (ainfo, non_user_klass))
3448 ji->dbg_non_user_code = TRUE;
3449 mono_custom_attrs_free (ainfo);
3452 mono_memory_barrier ();
3453 ji->dbg_attrs_inited = TRUE;
3457 * EVENT HANDLING
3461 * create_event_list:
3463 * Return a list of event request ids matching EVENT, starting from REQS, which
3464 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
3465 * policy.
3466 * We return request ids, instead of requests, to simplify threading, since
3467 * requests could be deleted anytime when the loader lock is not held.
3468 * LOCKING: Assumes the loader lock is held.
3470 static GSList*
3471 create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo *ei, int *suspend_policy)
3473 int i, j;
3474 GSList *events = NULL;
3476 *suspend_policy = SUSPEND_POLICY_NONE;
3478 if (!reqs)
3479 reqs = event_requests;
3481 if (!reqs)
3482 return NULL;
3484 for (i = 0; i < reqs->len; ++i) {
3485 EventRequest *req = (EventRequest *)g_ptr_array_index (reqs, i);
3486 if (req->event_kind == event) {
3487 gboolean filtered = FALSE;
3489 /* Apply filters */
3490 for (j = 0; j < req->nmodifiers; ++j) {
3491 Modifier *mod = &req->modifiers [j];
3493 if (mod->kind == MOD_KIND_COUNT) {
3494 filtered = TRUE;
3495 if (mod->data.count > 0) {
3496 if (mod->data.count > 0) {
3497 mod->data.count --;
3498 if (mod->data.count == 0)
3499 filtered = FALSE;
3502 } else if (mod->kind == MOD_KIND_THREAD_ONLY) {
3503 if (mod->data.thread != mono_thread_internal_current ())
3504 filtered = TRUE;
3505 } else if (mod->kind == MOD_KIND_EXCEPTION_ONLY && ei) {
3506 if (mod->data.exc_class && mod->subclasses && !mono_class_is_assignable_from_internal (mod->data.exc_class, ei->exc->vtable->klass))
3507 filtered = TRUE;
3508 if (mod->data.exc_class && !mod->subclasses && mod->data.exc_class != ei->exc->vtable->klass)
3509 filtered = TRUE;
3510 if (ei->caught && !mod->caught)
3511 filtered = TRUE;
3512 if (!ei->caught && !mod->uncaught)
3513 filtered = TRUE;
3514 } else if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && ji) {
3515 int k;
3516 gboolean found = FALSE;
3517 MonoAssembly **assemblies = mod->data.assemblies;
3519 if (assemblies) {
3520 for (k = 0; assemblies [k]; ++k)
3521 if (assemblies [k] == m_class_get_image (jinfo_get_method (ji)->klass)->assembly)
3522 found = TRUE;
3524 if (!found)
3525 filtered = TRUE;
3526 } else if (mod->kind == MOD_KIND_SOURCE_FILE_ONLY && ei && ei->klass) {
3527 gpointer iter = NULL;
3528 MonoMethod *method;
3529 MonoDebugSourceInfo *sinfo;
3530 char *source_file, *s;
3531 gboolean found = FALSE;
3532 int i;
3533 GPtrArray *source_file_list;
3535 while ((method = mono_class_get_methods (ei->klass, &iter))) {
3536 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
3538 if (minfo) {
3539 mono_debug_get_seq_points (minfo, &source_file, &source_file_list, NULL, NULL, NULL);
3540 for (i = 0; i < source_file_list->len; ++i) {
3541 sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
3543 * Do a case-insesitive match by converting the file name to
3544 * lowercase.
3546 s = strdup_tolower (sinfo->source_file);
3547 if (g_hash_table_lookup (mod->data.source_files, s))
3548 found = TRUE;
3549 else {
3550 char *s2 = dbg_path_get_basename (sinfo->source_file);
3551 char *s3 = strdup_tolower (s2);
3553 if (g_hash_table_lookup (mod->data.source_files, s3))
3554 found = TRUE;
3555 g_free (s2);
3556 g_free (s3);
3558 g_free (s);
3560 g_ptr_array_free (source_file_list, TRUE);
3563 if (!found)
3564 filtered = TRUE;
3565 } else if (mod->kind == MOD_KIND_TYPE_NAME_ONLY && ei && ei->klass) {
3566 char *s;
3568 s = mono_type_full_name (m_class_get_byval_arg (ei->klass));
3569 if (!g_hash_table_lookup (mod->data.type_names, s))
3570 filtered = TRUE;
3571 g_free (s);
3572 } else if (mod->kind == MOD_KIND_STEP) {
3573 if ((mod->data.filter & STEP_FILTER_STATIC_CTOR) && ji &&
3574 (jinfo_get_method (ji)->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
3575 !strcmp (jinfo_get_method (ji)->name, ".cctor") &&
3576 (jinfo_get_method (ji) != ((SingleStepReq*)req->info)->start_method))
3577 filtered = TRUE;
3578 if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) {
3579 init_jit_info_dbg_attrs (ji);
3580 if (ji->dbg_hidden)
3581 filtered = TRUE;
3583 if ((mod->data.filter & STEP_FILTER_DEBUGGER_STEP_THROUGH) && ji) {
3584 init_jit_info_dbg_attrs (ji);
3585 if (ji->dbg_step_through)
3586 filtered = TRUE;
3588 if ((mod->data.filter & STEP_FILTER_DEBUGGER_NON_USER_CODE) && ji) {
3589 init_jit_info_dbg_attrs (ji);
3590 if (ji->dbg_non_user_code)
3591 filtered = TRUE;
3596 if (!filtered) {
3597 *suspend_policy = MAX (*suspend_policy, req->suspend_policy);
3598 events = g_slist_append (events, GINT_TO_POINTER (req->id));
3603 /* Send a VM START/DEATH event by default */
3604 if (event == EVENT_KIND_VM_START)
3605 events = g_slist_append (events, GINT_TO_POINTER (0));
3606 if (event == EVENT_KIND_VM_DEATH)
3607 events = g_slist_append (events, GINT_TO_POINTER (0));
3609 return events;
3612 static G_GNUC_UNUSED const char*
3613 event_to_string (EventKind event)
3615 switch (event) {
3616 case EVENT_KIND_VM_START: return "VM_START";
3617 case EVENT_KIND_VM_DEATH: return "VM_DEATH";
3618 case EVENT_KIND_THREAD_START: return "THREAD_START";
3619 case EVENT_KIND_THREAD_DEATH: return "THREAD_DEATH";
3620 case EVENT_KIND_APPDOMAIN_CREATE: return "APPDOMAIN_CREATE";
3621 case EVENT_KIND_APPDOMAIN_UNLOAD: return "APPDOMAIN_UNLOAD";
3622 case EVENT_KIND_METHOD_ENTRY: return "METHOD_ENTRY";
3623 case EVENT_KIND_METHOD_EXIT: return "METHOD_EXIT";
3624 case EVENT_KIND_ASSEMBLY_LOAD: return "ASSEMBLY_LOAD";
3625 case EVENT_KIND_ASSEMBLY_UNLOAD: return "ASSEMBLY_UNLOAD";
3626 case EVENT_KIND_BREAKPOINT: return "BREAKPOINT";
3627 case EVENT_KIND_STEP: return "STEP";
3628 case EVENT_KIND_TYPE_LOAD: return "TYPE_LOAD";
3629 case EVENT_KIND_EXCEPTION: return "EXCEPTION";
3630 case EVENT_KIND_KEEPALIVE: return "KEEPALIVE";
3631 case EVENT_KIND_USER_BREAK: return "USER_BREAK";
3632 case EVENT_KIND_USER_LOG: return "USER_LOG";
3633 case EVENT_KIND_CRASH: return "CRASH";
3634 default:
3635 g_assert_not_reached ();
3636 return "";
3641 * process_event:
3643 * Send an event to the client, suspending the vm if needed.
3644 * LOCKING: Since this can suspend the calling thread, no locks should be held
3645 * by the caller.
3646 * The EVENTS list is freed by this function.
3648 static void
3649 process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx, GSList *events, int suspend_policy)
3651 Buffer buf;
3652 GSList *l;
3653 MonoDomain *domain = mono_domain_get ();
3654 MonoThread *thread = NULL;
3655 MonoObject *keepalive_obj = NULL;
3656 gboolean send_success = FALSE;
3657 static int ecount;
3658 int nevents;
3660 if (!inited) {
3661 DEBUG_PRINTF (2, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event));
3662 return;
3665 if (!vm_start_event_sent && event != EVENT_KIND_VM_START) {
3666 // FIXME: We miss those events
3667 DEBUG_PRINTF (2, "VM start event not sent yet: dropping %s\n", event_to_string (event));
3668 return;
3671 if (vm_death_event_sent) {
3672 DEBUG_PRINTF (2, "VM death event has been sent: dropping %s\n", event_to_string (event));
3673 return;
3676 if (mono_runtime_is_shutting_down () && event != EVENT_KIND_VM_DEATH) {
3677 DEBUG_PRINTF (2, "Mono runtime is shutting down: dropping %s\n", event_to_string (event));
3678 return;
3681 if (disconnected) {
3682 DEBUG_PRINTF (2, "Debugger client is not connected: dropping %s\n", event_to_string (event));
3683 return;
3686 if (event == EVENT_KIND_KEEPALIVE)
3687 suspend_policy = SUSPEND_POLICY_NONE;
3688 else {
3689 if (events == NULL)
3690 return;
3692 if (agent_config.defer) {
3693 if (is_debugger_thread ()) {
3694 /* Don't suspend on events from the debugger thread */
3695 suspend_policy = SUSPEND_POLICY_NONE;
3697 } else {
3698 if (is_debugger_thread () && event != EVENT_KIND_VM_DEATH)
3699 // FIXME: Send these with a NULL thread, don't suspend the current thread
3700 return;
3704 nevents = g_slist_length (events);
3705 buffer_init (&buf, 128);
3706 buffer_add_byte (&buf, suspend_policy);
3707 buffer_add_int (&buf, nevents);
3709 for (l = events; l; l = l->next) {
3710 buffer_add_byte (&buf, event); // event kind
3711 buffer_add_int (&buf, GPOINTER_TO_INT (l->data)); // request id
3713 ecount ++;
3715 if (event == EVENT_KIND_VM_DEATH) {
3716 thread = NULL;
3717 } else {
3718 if (!thread)
3719 thread = is_debugger_thread () ? mono_thread_get_main () : mono_thread_current ();
3721 if (event == EVENT_KIND_VM_START && arg != NULL)
3722 thread = (MonoThread *)arg;
3725 buffer_add_objid (&buf, (MonoObject*)thread); // thread
3727 switch (event) {
3728 case EVENT_KIND_THREAD_START:
3729 case EVENT_KIND_THREAD_DEATH:
3730 break;
3731 case EVENT_KIND_APPDOMAIN_CREATE:
3732 case EVENT_KIND_APPDOMAIN_UNLOAD:
3733 buffer_add_domainid (&buf, (MonoDomain *)arg);
3734 break;
3735 case EVENT_KIND_METHOD_ENTRY:
3736 case EVENT_KIND_METHOD_EXIT:
3737 buffer_add_methodid (&buf, domain, (MonoMethod *)arg);
3738 break;
3739 case EVENT_KIND_ASSEMBLY_LOAD:
3740 buffer_add_assemblyid (&buf, domain, (MonoAssembly *)arg);
3741 break;
3742 case EVENT_KIND_ASSEMBLY_UNLOAD: {
3743 DebuggerTlsData *tls;
3745 /* The domain the assembly belonged to is not equal to the current domain */
3746 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3747 g_assert (tls);
3748 g_assert (tls->domain_unloading);
3750 buffer_add_assemblyid (&buf, tls->domain_unloading, (MonoAssembly *)arg);
3751 break;
3753 case EVENT_KIND_TYPE_LOAD:
3754 buffer_add_typeid (&buf, domain, (MonoClass *)arg);
3755 break;
3756 case EVENT_KIND_BREAKPOINT:
3757 case EVENT_KIND_STEP: {
3758 MonoMethod *method = (MonoMethod *)arg;
3760 buffer_add_methodid (&buf, domain, method);
3761 buffer_add_long (&buf, il_offset);
3762 break;
3764 case EVENT_KIND_VM_START:
3765 buffer_add_domainid (&buf, mono_get_root_domain ());
3766 break;
3767 case EVENT_KIND_VM_DEATH:
3768 if (CHECK_PROTOCOL_VERSION (2, 27))
3769 buffer_add_int (&buf, mono_environment_exitcode_get ());
3770 break;
3771 case EVENT_KIND_CRASH: {
3772 EventInfo *ei = (EventInfo *)arg;
3773 buffer_add_long (&buf, ei->hashes->offset_free_hash);
3774 buffer_add_string (&buf, ei->dump);
3775 break;
3777 case EVENT_KIND_EXCEPTION: {
3778 EventInfo *ei = (EventInfo *)arg;
3779 buffer_add_objid (&buf, ei->exc);
3781 * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it
3782 * later after the suspension. (#12494).
3784 keepalive_obj = ei->exc;
3785 break;
3787 case EVENT_KIND_USER_BREAK:
3788 break;
3789 case EVENT_KIND_USER_LOG: {
3790 EventInfo *ei = (EventInfo *)arg;
3791 buffer_add_int (&buf, ei->level);
3792 buffer_add_string (&buf, ei->category ? ei->category : "");
3793 buffer_add_string (&buf, ei->message ? ei->message : "");
3794 break;
3796 case EVENT_KIND_KEEPALIVE:
3797 suspend_policy = SUSPEND_POLICY_NONE;
3798 break;
3799 default:
3800 g_assert_not_reached ();
3804 if (event == EVENT_KIND_VM_START) {
3805 suspend_policy = agent_config.suspend ? SUSPEND_POLICY_ALL : SUSPEND_POLICY_NONE;
3806 if (!agent_config.defer)
3807 start_debugger_thread ();
3810 if (event == EVENT_KIND_VM_DEATH) {
3811 vm_death_event_sent = TRUE;
3812 suspend_policy = SUSPEND_POLICY_NONE;
3815 if (mono_runtime_is_shutting_down ())
3816 suspend_policy = SUSPEND_POLICY_NONE;
3818 if (suspend_policy != SUSPEND_POLICY_NONE) {
3820 * Save the thread context and start suspending before sending the packet,
3821 * since we could be receiving the resume request before send_packet ()
3822 * returns.
3824 save_thread_context (ctx);
3825 suspend_vm ();
3827 if (keepalive_obj)
3828 /* This will keep this object alive */
3829 get_objref (keepalive_obj);
3832 send_success = send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf);
3834 if (send_success) {
3835 DebuggerTlsData *tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3836 mono_debugger_log_event (tls, event_to_string (event), buf.buf, buffer_len (&buf));
3839 buffer_free (&buf);
3841 g_slist_free (events);
3842 events = NULL;
3844 if (!send_success) {
3845 DEBUG_PRINTF (2, "Sending command %s failed.\n", event_to_string (event));
3846 return;
3849 if (event == EVENT_KIND_VM_START) {
3850 vm_start_event_sent = TRUE;
3853 DEBUG_PRINTF (1, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer) (gsize) mono_native_thread_id_get (), nevents, event_to_string (event), ecount, suspend_policy);
3855 switch (suspend_policy) {
3856 case SUSPEND_POLICY_NONE:
3857 break;
3858 case SUSPEND_POLICY_ALL:
3859 suspend_current ();
3860 break;
3861 case SUSPEND_POLICY_EVENT_THREAD:
3862 NOT_IMPLEMENTED;
3863 break;
3864 default:
3865 g_assert_not_reached ();
3869 static void
3870 process_profiler_event (EventKind event, gpointer arg)
3872 int suspend_policy;
3873 GSList *events;
3874 EventInfo ei, *ei_arg = NULL;
3876 if (event == EVENT_KIND_TYPE_LOAD) {
3877 ei.klass = (MonoClass *)arg;
3878 ei_arg = &ei;
3881 mono_loader_lock ();
3882 events = create_event_list (event, NULL, NULL, ei_arg, &suspend_policy);
3883 mono_loader_unlock ();
3885 process_event (event, arg, 0, NULL, events, suspend_policy);
3888 static void
3889 runtime_initialized (MonoProfiler *prof)
3891 process_profiler_event (EVENT_KIND_VM_START, mono_thread_current ());
3892 if (agent_config.defer)
3893 start_debugger_thread ();
3896 static void
3897 runtime_shutdown (MonoProfiler *prof)
3899 process_profiler_event (EVENT_KIND_VM_DEATH, NULL);
3901 mono_debugger_agent_cleanup ();
3904 static void
3905 thread_startup (MonoProfiler *prof, uintptr_t tid)
3907 MonoInternalThread *thread = mono_thread_internal_current ();
3908 MonoInternalThread *old_thread;
3909 DebuggerTlsData *tls;
3911 if (is_debugger_thread ())
3912 return;
3914 g_assert (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid)));
3916 mono_loader_lock ();
3917 old_thread = (MonoInternalThread *)mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
3918 mono_loader_unlock ();
3919 if (old_thread) {
3920 if (thread == old_thread) {
3922 * For some reason, thread_startup () might be called for the same thread
3923 * multiple times (attach ?).
3925 DEBUG_PRINTF (1, "[%p] thread_start () called multiple times for %p, ignored.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
3926 return;
3927 } else {
3929 * thread_end () might not be called for some threads, and the tid could
3930 * get reused.
3932 DEBUG_PRINTF (1, "[%p] Removing stale data for tid %p.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
3933 mono_loader_lock ();
3934 mono_g_hash_table_remove (thread_to_tls, old_thread);
3935 mono_g_hash_table_remove (tid_to_thread, GUINT_TO_POINTER (tid));
3936 mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
3937 mono_loader_unlock ();
3941 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3942 g_assert (!tls);
3943 // FIXME: Free this somewhere
3944 tls = g_new0 (DebuggerTlsData, 1);
3945 MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Reference");
3946 tls->thread = thread;
3947 // Do so we have thread id even after termination
3948 tls->thread_id = (intptr_t) thread->tid;
3949 mono_native_tls_set_value (debugger_tls_id, tls);
3951 DEBUG_PRINTF (1, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls);
3953 mono_loader_lock ();
3954 mono_g_hash_table_insert (thread_to_tls, thread, tls);
3955 mono_g_hash_table_insert (tid_to_thread, (gpointer)tid, thread);
3956 mono_g_hash_table_insert (tid_to_thread_obj, GUINT_TO_POINTER (tid), mono_thread_current ());
3957 mono_loader_unlock ();
3959 process_profiler_event (EVENT_KIND_THREAD_START, thread);
3962 * suspend_vm () could have missed this thread, so wait for a resume.
3964 suspend_current ();
3967 static void
3968 thread_end (MonoProfiler *prof, uintptr_t tid)
3970 MonoInternalThread *thread;
3971 DebuggerTlsData *tls = NULL;
3973 mono_loader_lock ();
3974 thread = (MonoInternalThread *)mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
3975 if (thread) {
3976 mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
3977 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
3978 if (tls) {
3979 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
3980 tls->terminated = TRUE;
3981 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
3982 MONO_GC_UNREGISTER_ROOT (tls->thread);
3983 tls->thread = NULL;
3986 mono_loader_unlock ();
3988 /* We might be called for threads started before we registered the start callback */
3989 if (thread) {
3990 DEBUG_PRINTF (1, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls);
3992 if (mono_thread_internal_is_current (thread) && !mono_native_tls_get_value (debugger_tls_id)
3995 * This can happen on darwin since we deregister threads using pthread dtors.
3996 * process_profiler_event () and the code it calls cannot handle a null TLS value.
3998 return;
4001 process_profiler_event (EVENT_KIND_THREAD_DEATH, thread);
4005 static void
4006 appdomain_load (MonoProfiler *prof, MonoDomain *domain)
4008 mono_de_domain_add (domain);
4010 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE, domain);
4013 static void
4014 appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain)
4016 DebuggerTlsData *tls;
4018 /* This might be called during shutdown on the debugger thread from the CMD_VM_EXIT code */
4019 if (is_debugger_thread ())
4020 return;
4023 * Remember the currently unloading appdomain as it is needed to generate
4024 * proper ids for unloading assemblies.
4026 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4027 g_assert (tls);
4028 tls->domain_unloading = domain;
4031 static void
4032 appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
4034 DebuggerTlsData *tls;
4036 if (is_debugger_thread ())
4037 return;
4039 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4040 g_assert (tls);
4041 tls->domain_unloading = NULL;
4043 mono_de_clear_breakpoints_for_domain (domain);
4045 mono_loader_lock ();
4046 /* Invalidate each thread's frame stack */
4047 mono_g_hash_table_foreach (thread_to_tls, invalidate_each_thread, NULL);
4048 mono_loader_unlock ();
4050 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD, domain);
4054 * invalidate_each_thread:
4056 * A GHFunc to invalidate frames.
4057 * value must be a DebuggerTlsData*
4059 static void
4060 invalidate_each_thread (gpointer key, gpointer value, gpointer user_data)
4062 invalidate_frames ((DebuggerTlsData *)value);
4065 static void
4066 assembly_load (MonoProfiler *prof, MonoAssembly *assembly)
4068 /* Sent later in jit_end () */
4069 dbg_lock ();
4070 g_ptr_array_add (pending_assembly_loads, assembly);
4071 dbg_unlock ();
4074 static void
4075 assembly_unload (MonoProfiler *prof, MonoAssembly *assembly)
4077 if (is_debugger_thread ())
4078 return;
4080 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
4082 clear_event_requests_for_assembly (assembly);
4083 clear_types_for_assembly (assembly);
4086 static void
4087 send_type_load (MonoClass *klass)
4089 gboolean type_load = FALSE;
4090 MonoDomain *domain = mono_domain_get ();
4091 AgentDomainInfo *info = NULL;
4093 info = get_agent_domain_info (domain);
4095 mono_loader_lock ();
4097 if (!g_hash_table_lookup (info->loaded_classes, klass)) {
4098 type_load = TRUE;
4099 g_hash_table_insert (info->loaded_classes, klass, klass);
4102 mono_loader_unlock ();
4104 if (type_load)
4105 emit_type_load (klass, klass, NULL);
4109 * Emit load events for all types currently loaded in the domain.
4110 * Takes the loader and domain locks.
4111 * user_data is unused.
4113 static void
4114 send_types_for_domain (MonoDomain *domain, void *user_data)
4116 MonoDomain* old_domain;
4117 AgentDomainInfo *info = NULL;
4119 info = get_agent_domain_info (domain);
4120 g_assert (info);
4122 old_domain = mono_domain_get ();
4124 mono_domain_set (domain, TRUE);
4126 mono_loader_lock ();
4127 g_hash_table_foreach (info->loaded_classes, emit_type_load, NULL);
4128 mono_loader_unlock ();
4130 mono_domain_set (old_domain, TRUE);
4133 static void
4134 send_assemblies_for_domain (MonoDomain *domain, void *user_data)
4136 GSList *tmp;
4137 MonoDomain* old_domain;
4139 old_domain = mono_domain_get ();
4141 mono_domain_set (domain, TRUE);
4143 mono_domain_assemblies_lock (domain);
4144 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
4145 MonoAssembly* ass = (MonoAssembly *)tmp->data;
4146 emit_assembly_load (ass, NULL);
4148 mono_domain_assemblies_unlock (domain);
4150 mono_domain_set (old_domain, TRUE);
4153 static void
4154 jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
4156 jit_end (prof, method, jinfo);
4159 static void
4160 jit_failed (MonoProfiler *prof, MonoMethod *method)
4162 jit_end (prof, method, NULL);
4165 static void
4166 jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
4169 * We emit type load events when the first method of the type is JITted,
4170 * since the class load profiler callbacks might be called with the
4171 * loader lock held. They could also occur in the debugger thread.
4172 * Same for assembly load events.
4174 while (TRUE) {
4175 MonoAssembly *assembly = NULL;
4177 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
4178 dbg_lock ();
4179 if (pending_assembly_loads->len > 0) {
4180 assembly = (MonoAssembly *)g_ptr_array_index (pending_assembly_loads, 0);
4181 g_ptr_array_remove_index (pending_assembly_loads, 0);
4183 dbg_unlock ();
4185 if (assembly) {
4186 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly);
4187 } else {
4188 break;
4192 send_type_load (method->klass);
4194 if (jinfo)
4195 mono_de_add_pending_breakpoints (method, jinfo);
4199 * SINGLE STEPPING
4202 static void
4203 event_requests_cleanup (void)
4205 mono_loader_lock ();
4206 int i = 0;
4207 while (i < event_requests->len) {
4208 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
4210 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
4211 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
4212 g_ptr_array_remove_index_fast (event_requests, i);
4213 g_free (req);
4214 } else {
4215 i ++;
4218 mono_loader_unlock ();
4222 * ss_calculate_framecount:
4224 * Ensure DebuggerTlsData fields are filled out.
4226 static void
4227 ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes)
4229 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4231 if (force_use_ctx || !tls->context.valid)
4232 mono_thread_state_init_from_monoctx (&tls->context, ctx);
4233 compute_frame_info (tls->thread, tls);
4234 if (frames)
4235 *frames = (DbgEngineStackFrame**)tls->frames;
4236 if (nframes)
4237 *nframes = tls->frame_count;
4241 * ss_discard_frame_data:
4243 * Discard frame data and invalidate any context
4245 static void
4246 ss_discard_frame_context (void *the_tls)
4248 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4249 tls->context.valid = FALSE;
4250 tls->async_state.valid = FALSE;
4251 invalidate_frames (tls);
4254 static MonoContext*
4255 tls_get_restore_state (void *the_tls)
4257 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4259 return &tls->restore_state.ctx;
4262 static gboolean
4263 ensure_jit (DbgEngineStackFrame* the_frame)
4265 StackFrame *frame = (StackFrame*)the_frame;
4266 if (!frame->jit) {
4267 frame->jit = mono_debug_find_method (frame->api_method, frame->de.domain);
4268 if (!frame->jit && frame->api_method->is_inflated)
4269 frame->jit = mono_debug_find_method(mono_method_get_declaring_generic_method (frame->api_method), frame->de.domain);
4270 if (!frame->jit) {
4271 char *s;
4273 /* This could happen for aot images with no jit debug info */
4274 s = mono_method_full_name (frame->api_method, TRUE);
4275 DEBUG_PRINTF(1, "[dbg] No debug information found for '%s'.\n", s);
4276 g_free (s);
4277 return FALSE;
4280 return TRUE;
4283 static gboolean
4284 breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
4286 return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly;
4289 static gpointer
4290 get_this_addr (DbgEngineStackFrame *the_frame)
4292 StackFrame *frame = (StackFrame *)the_frame;
4293 if (frame->de.ji->is_interp)
4294 return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
4296 MonoDebugVarInfo *var = frame->jit->this_var;
4297 if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET)
4298 return NULL;
4300 guint8 *addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS);
4301 addr += (gint32)var->offset;
4302 return addr;
4305 static MonoMethod*
4306 get_set_notification_method (MonoClass* async_builder_class)
4308 ERROR_DECL (error);
4309 GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, 1, FALSE, error);
4310 mono_error_assert_ok (error);
4311 if (array->len == 0) {
4312 g_ptr_array_free (array, TRUE);
4313 return NULL;
4315 MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0);
4316 g_ptr_array_free (array, TRUE);
4317 return set_notification_method;
4320 static MonoMethod*
4321 get_object_id_for_debugger_method (MonoClass* async_builder_class)
4323 ERROR_DECL (error);
4324 GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error);
4325 mono_error_assert_ok (error);
4326 g_assert (array->len == 1);
4327 MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
4328 g_ptr_array_free (array, TRUE);
4329 return method;
4332 /* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */
4333 static gpointer
4334 get_async_method_builder (DbgEngineStackFrame *frame)
4336 MonoObject *this_obj;
4337 MonoClassField *builder_field;
4338 gpointer builder;
4339 gpointer this_addr;
4341 builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
4342 g_assert (builder_field);
4344 this_addr = get_this_addr (frame);
4345 if (!this_addr)
4346 return NULL;
4348 if (m_class_is_valuetype (frame->method->klass)) {
4349 builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field);
4350 } else {
4351 this_obj = *(MonoObject**)this_addr;
4352 builder = (char*)this_obj + builder_field->offset;
4355 return builder;
4358 //This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
4359 //since thread probably changed...
4360 static int
4361 get_this_async_id (DbgEngineStackFrame *frame)
4363 MonoClassField *builder_field;
4364 gpointer builder;
4365 MonoMethod *method;
4366 MonoObject *ex;
4367 ERROR_DECL (error);
4368 MonoObject *obj;
4369 gboolean old_disable_breakpoints = FALSE;
4370 DebuggerTlsData *tls;
4373 * FRAME points to a method in a state machine class/struct.
4374 * Call the ObjectIdForDebugger method of the associated method builder type.
4376 builder = get_async_method_builder (frame);
4377 if (!builder)
4378 return 0;
4380 builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
4381 g_assert (builder_field);
4383 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4384 if (tls) {
4385 old_disable_breakpoints = tls->disable_breakpoints;
4386 tls->disable_breakpoints = TRUE;
4389 method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type));
4390 obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error);
4391 mono_error_assert_ok (error);
4393 if (tls)
4394 tls->disable_breakpoints = old_disable_breakpoints;
4396 return get_objid (obj);
4399 // Returns true if TaskBuilder has NotifyDebuggerOfWaitCompletion method
4400 // false if not(AsyncVoidBuilder)
4401 static gboolean
4402 set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
4404 MonoClassField *builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL);
4405 g_assert (builder_field);
4406 gpointer builder = get_async_method_builder (frame);
4407 g_assert (builder);
4409 void* args [1];
4410 gboolean arg = TRUE;
4411 ERROR_DECL (error);
4412 args [0] = &arg;
4413 MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type));
4414 if (method == NULL)
4415 return FALSE;
4416 mono_runtime_invoke_checked (method, builder, args, error);
4417 mono_error_assert_ok (error);
4418 return TRUE;
4421 static MonoMethod* notify_debugger_of_wait_completion_method_cache;
4423 static MonoMethod*
4424 get_notify_debugger_of_wait_completion_method (void)
4426 if (notify_debugger_of_wait_completion_method_cache != NULL)
4427 return notify_debugger_of_wait_completion_method_cache;
4428 ERROR_DECL (error);
4429 MonoClass* task_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading.Tasks", "Task");
4430 GPtrArray* array = mono_class_get_methods_by_name (task_class, "NotifyDebuggerOfWaitCompletion", 0x24, 1, FALSE, error);
4431 mono_error_assert_ok (error);
4432 g_assert (array->len == 1);
4433 notify_debugger_of_wait_completion_method_cache = (MonoMethod *)g_ptr_array_index (array, 0);
4434 g_ptr_array_free (array, TRUE);
4435 return notify_debugger_of_wait_completion_method_cache;
4438 static gboolean
4439 begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
4441 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4444 * Skip the instruction causing the breakpoint signal.
4446 if (from_signal)
4447 mono_arch_skip_breakpoint (ctx, ji);
4449 if (tls->disable_breakpoints)
4450 return FALSE;
4451 return TRUE;
4454 typedef struct {
4455 GSList *bp_events, *ss_events, *enter_leave_events;
4456 EventKind kind;
4457 int suspend_policy;
4458 } BreakPointEvents;
4460 static void*
4461 create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind)
4463 int suspend_policy = 0;
4464 BreakPointEvents *evts = g_new0 (BreakPointEvents, 1);
4465 if (ss_reqs && ss_reqs->len > 0)
4466 evts->ss_events = create_event_list (EVENT_KIND_STEP, ss_reqs, ji, NULL, &suspend_policy);
4467 else if (bp_reqs && bp_reqs->len > 0)
4468 evts->bp_events = create_event_list (EVENT_KIND_BREAKPOINT, bp_reqs, ji, NULL, &suspend_policy);
4469 else if (kind != EVENT_KIND_BREAKPOINT)
4470 evts->enter_leave_events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
4472 evts->kind = kind;
4473 evts->suspend_policy = suspend_policy;
4474 return evts;
4477 static void
4478 process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset)
4480 BreakPointEvents *evts = (BreakPointEvents*)_evts;
4482 * FIXME: The first event will suspend, so the second will only be sent after the
4483 * resume.
4485 if (evts->ss_events)
4486 process_event (EVENT_KIND_STEP, method, il_offset, ctx, evts->ss_events, evts->suspend_policy);
4487 if (evts->bp_events)
4488 process_event (evts->kind, method, il_offset, ctx, evts->bp_events, evts->suspend_policy);
4489 if (evts->enter_leave_events)
4490 process_event (evts->kind, method, il_offset, ctx, evts->enter_leave_events, evts->suspend_policy);
4492 g_free (evts);
4495 /* Process a breakpoint/single step event after resuming from a signal handler */
4496 static void
4497 process_signal_event (void (*func) (void*, gboolean))
4499 DebuggerTlsData *tls;
4500 MonoThreadUnwindState orig_restore_state;
4501 MonoContext ctx;
4503 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4504 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4505 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4506 mono_thread_state_init_from_monoctx (&tls->restore_state, &tls->handler_ctx);
4508 func (tls, TRUE);
4510 /* This is called when resuming from a signal handler, so it shouldn't return */
4511 memcpy (&ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4512 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4513 mono_restore_context (&ctx);
4514 g_assert_not_reached ();
4517 static void
4518 process_breakpoint_from_signal (void)
4520 process_signal_event (mono_de_process_breakpoint);
4523 static void
4524 resume_from_signal_handler (void *sigctx, void *func)
4526 DebuggerTlsData *tls;
4527 MonoContext ctx;
4529 /* Save the original context in TLS */
4530 // FIXME: This might not work on an altstack ?
4531 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4532 if (!tls)
4533 g_printerr ("Thread %p is not attached to the JIT.\n", (gpointer) (gsize) mono_native_thread_id_get ());
4534 g_assert (tls);
4536 // FIXME: MonoContext usually doesn't include the fp registers, so these are
4537 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
4538 // clob:c could be added to op_seq_point.
4540 mono_sigctx_to_monoctx (sigctx, &ctx);
4541 memcpy (&tls->handler_ctx, &ctx, sizeof (MonoContext));
4542 #ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
4543 mono_arch_setup_resume_sighandler_ctx (&ctx, func);
4544 #else
4545 MONO_CONTEXT_SET_IP (&ctx, func);
4546 #endif
4547 mono_monoctx_to_sigctx (&ctx, sigctx);
4550 static void
4551 debugger_agent_breakpoint_hit (void *sigctx)
4554 * We are called from a signal handler, and running code there causes all kinds of
4555 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
4556 * So set up the signal context to return to the real breakpoint handler function.
4558 resume_from_signal_handler (sigctx, (gpointer)process_breakpoint_from_signal);
4561 typedef struct {
4562 gboolean found;
4563 MonoContext *ctx;
4564 } UserBreakCbData;
4566 static gboolean
4567 user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data)
4569 UserBreakCbData *data = (UserBreakCbData*)user_data;
4571 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
4572 data->found = TRUE;
4573 return TRUE;
4575 if (frame->managed) {
4576 data->found = TRUE;
4577 *data->ctx = *ctx;
4579 return TRUE;
4581 return FALSE;
4585 * Called by System.Diagnostics.Debugger:Break ().
4587 static void
4588 debugger_agent_user_break (void)
4590 if (agent_config.enabled) {
4591 MonoContext ctx;
4592 int suspend_policy;
4593 GSList *events;
4594 UserBreakCbData data;
4596 memset (&data, 0, sizeof (UserBreakCbData));
4597 data.ctx = &ctx;
4599 /* Obtain a context */
4600 MONO_CONTEXT_SET_IP (&ctx, NULL);
4601 mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data);
4602 g_assert (data.found);
4604 mono_loader_lock ();
4605 events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy);
4606 mono_loader_unlock ();
4608 process_event (EVENT_KIND_USER_BREAK, NULL, 0, &ctx, events, suspend_policy);
4609 } else if (mini_debug_options.native_debugger_break) {
4610 G_BREAKPOINT ();
4614 static void
4615 begin_single_step_processing (MonoContext *ctx, gboolean from_signal)
4617 if (from_signal)
4618 mono_arch_skip_single_step (ctx);
4621 static void
4622 process_single_step (void)
4624 process_signal_event (mono_de_process_single_step);
4628 * debugger_agent_single_step_event:
4630 * Called from a signal handler to handle a single step event.
4632 static void
4633 debugger_agent_single_step_event (void *sigctx)
4635 /* Resume to process_single_step through the signal context */
4637 // FIXME: Since step out/over is implemented using step in, the step in case should
4638 // be as fast as possible. Move the relevant code from mono_de_process_single_step ()
4639 // here
4641 if (is_debugger_thread ()) {
4643 * This could happen despite our best effors when the runtime calls
4644 * assembly/type resolve hooks.
4645 * FIXME: Breakpoints too.
4647 MonoContext ctx;
4649 mono_sigctx_to_monoctx (sigctx, &ctx);
4650 mono_arch_skip_single_step (&ctx);
4651 mono_monoctx_to_sigctx (&ctx, sigctx);
4652 return;
4655 resume_from_signal_handler (sigctx, (gpointer)process_single_step);
4658 static void
4659 debugger_agent_single_step_from_context (MonoContext *ctx)
4661 DebuggerTlsData *tls;
4662 MonoThreadUnwindState orig_restore_state;
4664 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4665 /* Fastpath during invokes, see in process_suspend () */
4666 if (tls && suspend_count && suspend_count - tls->resume_count == 0)
4667 return;
4669 if (is_debugger_thread ())
4670 return;
4672 g_assert (tls);
4674 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4675 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4676 mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
4677 memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
4679 mono_de_process_single_step (tls, FALSE);
4681 memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4682 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4685 static void
4686 debugger_agent_breakpoint_from_context (MonoContext *ctx)
4688 DebuggerTlsData *tls;
4689 MonoThreadUnwindState orig_restore_state;
4690 guint8 *orig_ip;
4692 if (is_debugger_thread ())
4693 return;
4695 orig_ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
4696 MONO_CONTEXT_SET_IP (ctx, orig_ip - 1);
4698 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4699 g_assert (tls);
4700 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4701 mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
4702 memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
4704 mono_de_process_breakpoint (tls, FALSE);
4706 memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4707 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4708 if (MONO_CONTEXT_GET_IP (ctx) == orig_ip - 1)
4709 MONO_CONTEXT_SET_IP (ctx, orig_ip);
4712 static void
4713 ss_args_destroy (SingleStepArgs *ss_args)
4715 if (ss_args->frames)
4716 free_frames ((StackFrame**)ss_args->frames, ss_args->nframes);
4719 static int
4720 ensure_runtime_is_suspended (void)
4722 if (suspend_count == 0)
4723 return ERR_NOT_SUSPENDED;
4725 wait_for_suspend ();
4727 return ERR_NONE;
4730 static int
4731 ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args)
4733 MonoSeqPointInfo *info = NULL;
4734 gboolean found_sp;
4735 MonoMethod *method = NULL;
4736 MonoDebugMethodInfo *minfo;
4737 gboolean step_to_catch = FALSE;
4738 gboolean set_ip = FALSE;
4739 StackFrame **frames = NULL;
4740 int nframes = 0;
4742 mono_loader_lock ();
4743 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, ss_req->thread);
4744 mono_loader_unlock ();
4745 g_assert (tls);
4746 if (!tls->context.valid) {
4747 DEBUG_PRINTF (1, "Received a single step request on a thread with no managed frames.");
4748 return ERR_INVALID_ARGUMENT;
4751 if (tls->restore_state.valid && MONO_CONTEXT_GET_IP (&tls->context.ctx) != MONO_CONTEXT_GET_IP (&tls->restore_state.ctx)) {
4753 * Need to start single stepping from restore_state and not from the current state
4755 set_ip = TRUE;
4756 frames = compute_frame_info_from (ss_req->thread, tls, &tls->restore_state, &nframes);
4759 ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx);
4761 if (tls->has_catch_frame) {
4762 StackFrameInfo frame;
4765 * We are stopped at a throw site. Stepping should go to the catch site.
4767 frame = tls->catch_frame;
4768 g_assert (frame.type == FRAME_TYPE_MANAGED || frame.type == FRAME_TYPE_INTERP);
4771 * Find the seq point corresponding to the landing site ip, which is the first seq
4772 * point after ip.
4774 found_sp = mono_find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &args->sp);
4775 if (!found_sp)
4776 no_seq_points_found (frame.method, frame.native_offset);
4777 g_assert (found_sp);
4779 method = frame.method;
4781 step_to_catch = TRUE;
4782 /* This make sure the seq point is not skipped by process_single_step () */
4783 ss_req->last_sp = NULL;
4786 if (!step_to_catch) {
4787 StackFrame *frame = NULL;
4789 if (set_ip) {
4790 if (frames && nframes)
4791 frame = frames [0];
4792 } else {
4793 compute_frame_info (ss_req->thread, tls);
4795 if (tls->frame_count)
4796 frame = tls->frames [0];
4799 if (ss_req->size == STEP_SIZE_LINE) {
4800 if (frame) {
4801 ss_req->last_method = frame->de.method;
4802 ss_req->last_line = -1;
4804 minfo = mono_debug_lookup_method (frame->de.method);
4805 if (minfo && frame->il_offset != -1) {
4806 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, frame->il_offset);
4808 if (loc) {
4809 ss_req->last_line = loc->row;
4810 g_free (loc);
4816 if (frame) {
4817 if (!method && frame->il_offset != -1) {
4818 /* FIXME: Sort the table and use a binary search */
4819 found_sp = mono_find_prev_seq_point_for_native_offset (frame->de.domain, frame->de.method, frame->de.native_offset, &info, &args->sp);
4820 if (!found_sp)
4821 no_seq_points_found (frame->de.method, frame->de.native_offset);
4822 g_assert (found_sp);
4823 method = frame->de.method;
4828 ss_req->start_method = method;
4830 args->method = method;
4831 args->ctx = set_ip ? &tls->restore_state.ctx : &tls->context.ctx;
4832 args->tls = tls;
4833 args->step_to_catch = step_to_catch;
4834 args->info = info;
4835 args->frames = (DbgEngineStackFrame**)frames;
4836 args->nframes = nframes;
4838 return ERR_NONE;
4841 static void
4842 ss_clear_for_assembly (SingleStepReq *req, MonoAssembly *assembly)
4844 GSList *l;
4845 gboolean found = TRUE;
4847 while (found) {
4848 found = FALSE;
4849 for (l = req->bps; l; l = l->next) {
4850 if (breakpoint_matches_assembly ((MonoBreakpoint *)l->data, assembly)) {
4851 mono_de_clear_breakpoint ((MonoBreakpoint *)l->data);
4852 req->bps = g_slist_delete_link (req->bps, l);
4853 found = TRUE;
4854 break;
4861 * This takes a lot of locks and stuff. Do this at the end, after
4862 * other things have dumped us, so that getting stuck here won't
4863 * prevent seeing other crash information
4865 static void
4866 mono_debugger_agent_send_crash (char *json_dump, MonoStackHash *hashes, int pause)
4868 #ifndef DISABLE_CRASH_REPORTING
4869 int suspend_policy;
4870 GSList *events;
4871 EventInfo ei;
4873 if (!agent_config.enabled)
4874 return;
4876 // Don't send the event if the client doesn't expect it
4877 if (!CHECK_PROTOCOL_VERSION (2, 49))
4878 return;
4880 // It doesn't make sense to wait for lldb/gdb to finish if we're not
4881 // actually enabled. Therefore we do the wait here.
4882 sleep (pause);
4884 // Don't heap allocate when we can avoid it
4885 EventRequest request;
4886 memset (&request, 0, sizeof (request));
4887 request.event_kind = EVENT_KIND_CRASH;
4889 gpointer pdata [1];
4890 pdata [0] = &request;
4891 GPtrArray array;
4892 memset (&array, 0, sizeof (array));
4893 array.pdata = pdata;
4894 array.len = 1;
4896 mono_loader_lock ();
4897 events = create_event_list (EVENT_KIND_CRASH, &array, NULL, NULL, &suspend_policy);
4898 mono_loader_unlock ();
4900 ei.dump = json_dump;
4901 ei.hashes = hashes;
4903 g_assert (events != NULL);
4905 process_event (EVENT_KIND_CRASH, &ei, 0, NULL, events, suspend_policy);
4907 // Don't die before it is sent.
4908 sleep (4);
4909 #endif
4913 * Called from metadata by the icall for System.Diagnostics.Debugger:Log ().
4915 static void
4916 debugger_agent_debug_log (int level, MonoStringHandle category, MonoStringHandle message)
4918 ERROR_DECL (error);
4919 int suspend_policy;
4920 GSList *events;
4921 EventInfo ei;
4923 if (!agent_config.enabled)
4924 return;
4926 mono_loader_lock ();
4927 events = create_event_list (EVENT_KIND_USER_LOG, NULL, NULL, NULL, &suspend_policy);
4928 mono_loader_unlock ();
4930 ei.level = level;
4931 ei.category = NULL;
4932 if (!MONO_HANDLE_IS_NULL (category)) {
4933 ei.category = mono_string_handle_to_utf8 (category, error);
4934 mono_error_cleanup (error);
4936 ei.message = NULL;
4937 if (!MONO_HANDLE_IS_NULL (message)) {
4938 ei.message = mono_string_handle_to_utf8 (message, error);
4939 mono_error_cleanup (error);
4942 process_event (EVENT_KIND_USER_LOG, &ei, 0, NULL, events, suspend_policy);
4944 g_free (ei.category);
4945 g_free (ei.message);
4948 static gboolean
4949 debugger_agent_debug_log_is_enabled (void)
4951 /* Treat this as true even if there is no event request for EVENT_KIND_USER_LOG */
4952 return agent_config.enabled;
4955 static void
4956 debugger_agent_unhandled_exception (MonoException *exc)
4958 int suspend_policy;
4959 GSList *events;
4960 EventInfo ei;
4962 if (!inited)
4963 return;
4965 memset (&ei, 0, sizeof (EventInfo));
4966 ei.exc = (MonoObject*)exc;
4968 mono_loader_lock ();
4969 events = create_event_list (EVENT_KIND_EXCEPTION, NULL, NULL, &ei, &suspend_policy);
4970 mono_loader_unlock ();
4972 process_event (EVENT_KIND_EXCEPTION, &ei, 0, NULL, events, suspend_policy);
4975 static void
4976 debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx,
4977 MonoContext *catch_ctx, StackFrameInfo *catch_frame)
4979 int i, j, suspend_policy;
4980 GSList *events;
4981 MonoJitInfo *ji, *catch_ji;
4982 EventInfo ei;
4983 DebuggerTlsData *tls = NULL;
4985 if (thread_to_tls != NULL) {
4986 MonoInternalThread *thread = mono_thread_internal_current ();
4988 mono_loader_lock ();
4989 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
4990 mono_loader_unlock ();
4992 if (tls && tls->abort_requested)
4993 return;
4994 if (tls && tls->disable_breakpoints)
4995 return;
4998 memset (&ei, 0, sizeof (EventInfo));
5000 /* Just-In-Time debugging */
5001 if (!catch_ctx) {
5002 if (agent_config.onuncaught && !inited) {
5003 finish_agent_init (FALSE);
5006 * Send an unsolicited EXCEPTION event with a dummy request id.
5008 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
5009 ei.exc = (MonoObject*)exc;
5010 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, SUSPEND_POLICY_ALL);
5011 return;
5013 } else if (agent_config.onthrow && !inited) {
5014 GSList *l;
5015 gboolean found = FALSE;
5017 for (l = agent_config.onthrow; l; l = l->next) {
5018 char *ex_type = (char *)l->data;
5019 char *f = mono_type_full_name (m_class_get_byval_arg (exc->object.vtable->klass));
5021 if (!strcmp (ex_type, "") || !strcmp (ex_type, f))
5022 found = TRUE;
5024 g_free (f);
5027 if (found) {
5028 finish_agent_init (FALSE);
5031 * Send an unsolicited EXCEPTION event with a dummy request id.
5033 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
5034 ei.exc = (MonoObject*)exc;
5035 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, SUSPEND_POLICY_ALL);
5036 return;
5040 if (!inited)
5041 return;
5043 ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_CONTEXT_GET_IP (throw_ctx), NULL);
5044 if (catch_frame)
5045 catch_ji = catch_frame->ji;
5046 else
5047 catch_ji = NULL;
5049 ei.exc = (MonoObject*)exc;
5050 ei.caught = catch_ctx != NULL;
5052 mono_loader_lock ();
5054 /* Treat exceptions which are caught in non-user code as unhandled */
5055 for (i = 0; i < event_requests->len; ++i) {
5056 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
5057 if (req->event_kind != EVENT_KIND_EXCEPTION)
5058 continue;
5060 for (j = 0; j < req->nmodifiers; ++j) {
5061 Modifier *mod = &req->modifiers [j];
5063 if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && catch_ji) {
5064 int k;
5065 gboolean found = FALSE;
5066 MonoAssembly **assemblies = mod->data.assemblies;
5068 if (assemblies) {
5069 for (k = 0; assemblies [k]; ++k)
5070 if (assemblies [k] == m_class_get_image (jinfo_get_method (catch_ji)->klass)->assembly)
5071 found = TRUE;
5073 if (!found)
5074 ei.caught = FALSE;
5079 events = create_event_list (EVENT_KIND_EXCEPTION, NULL, ji, &ei, &suspend_policy);
5080 mono_loader_unlock ();
5082 if (tls && ei.caught && catch_ctx) {
5083 if (catch_frame) {
5084 tls->has_catch_frame = TRUE;
5085 tls->catch_frame = *catch_frame;
5086 } else {
5087 memset (&tls->catch_frame, 0, sizeof (tls->catch_frame));
5091 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, suspend_policy);
5093 if (tls)
5094 tls->has_catch_frame = FALSE;
5097 static void
5098 debugger_agent_begin_exception_filter (MonoException *exc, MonoContext *ctx, MonoContext *orig_ctx)
5100 DebuggerTlsData *tls;
5102 if (!inited)
5103 return;
5105 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
5106 if (!tls)
5107 return;
5110 * We're about to invoke an exception filter during the first pass of exception handling.
5112 * 'ctx' is the context that'll get passed to the filter ('call_filter (ctx, ei->data.filter)'),
5113 * 'orig_ctx' is the context where the exception has been thrown.
5116 * See mcs/class/Mono.Debugger.Soft/Tests/dtest-excfilter.il for an example.
5118 * If we're stopped in Filter(), normal stack unwinding would first unwind to
5119 * the call site (line 37) and then continue to Main(), but it would never
5120 * include the throw site (line 32).
5122 * Since exception filters are invoked during the first pass of exception handling,
5123 * the stack frames of the throw site are still intact, so we should include them
5124 * in a stack trace.
5126 * We do this here by saving the context of the throw site in 'tls->filter_state'.
5128 * Exception filters are used by MonoDroid, where we want to stop inside a call filter,
5129 * but report the location of the 'throw' to the user.
5133 g_assert (mono_thread_state_init_from_monoctx (&tls->filter_state, orig_ctx));
5136 static void
5137 debugger_agent_end_exception_filter (MonoException *exc, MonoContext *ctx, MonoContext *orig_ctx)
5139 DebuggerTlsData *tls;
5141 if (!inited)
5142 return;
5144 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
5145 if (!tls)
5146 return;
5148 tls->filter_state.valid = FALSE;
5152 * buffer_add_value_full:
5154 * Add the encoding of the value at ADDR described by T to the buffer.
5155 * AS_VTYPE determines whenever to treat primitive types as primitive types or
5156 * vtypes.
5158 static void
5159 buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
5160 gboolean as_vtype, GHashTable *parent_vtypes)
5162 MonoObject *obj;
5163 gboolean boxed_vtype = FALSE;
5165 if (t->byref) {
5166 if (!(*(void**)addr)) {
5167 /* This can happen with compiler generated locals */
5168 //printf ("%s\n", mono_type_full_name (t));
5169 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5170 return;
5172 g_assert (*(void**)addr);
5173 addr = *(void**)addr;
5176 if (as_vtype) {
5177 switch (t->type) {
5178 case MONO_TYPE_BOOLEAN:
5179 case MONO_TYPE_I1:
5180 case MONO_TYPE_U1:
5181 case MONO_TYPE_CHAR:
5182 case MONO_TYPE_I2:
5183 case MONO_TYPE_U2:
5184 case MONO_TYPE_I4:
5185 case MONO_TYPE_U4:
5186 case MONO_TYPE_R4:
5187 case MONO_TYPE_I8:
5188 case MONO_TYPE_U8:
5189 case MONO_TYPE_R8:
5190 case MONO_TYPE_I:
5191 case MONO_TYPE_U:
5192 case MONO_TYPE_PTR:
5193 goto handle_vtype;
5194 break;
5195 default:
5196 break;
5200 switch (t->type) {
5201 case MONO_TYPE_VOID:
5202 buffer_add_byte (buf, t->type);
5203 break;
5204 case MONO_TYPE_BOOLEAN:
5205 case MONO_TYPE_I1:
5206 case MONO_TYPE_U1:
5207 buffer_add_byte (buf, t->type);
5208 buffer_add_int (buf, *(gint8*)addr);
5209 break;
5210 case MONO_TYPE_CHAR:
5211 case MONO_TYPE_I2:
5212 case MONO_TYPE_U2:
5213 buffer_add_byte (buf, t->type);
5214 buffer_add_int (buf, *(gint16*)addr);
5215 break;
5216 case MONO_TYPE_I4:
5217 case MONO_TYPE_U4:
5218 case MONO_TYPE_R4:
5219 buffer_add_byte (buf, t->type);
5220 buffer_add_int (buf, *(gint32*)addr);
5221 break;
5222 case MONO_TYPE_I8:
5223 case MONO_TYPE_U8:
5224 case MONO_TYPE_R8:
5225 buffer_add_byte (buf, t->type);
5226 buffer_add_long (buf, *(gint64*)addr);
5227 break;
5228 case MONO_TYPE_I:
5229 case MONO_TYPE_U:
5230 /* Treat it as a vtype */
5231 goto handle_vtype;
5232 case MONO_TYPE_PTR: {
5233 gssize val = *(gssize*)addr;
5235 buffer_add_byte (buf, t->type);
5236 buffer_add_long (buf, val);
5237 if (CHECK_PROTOCOL_VERSION(2, 46))
5238 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t));
5239 break;
5241 handle_ref:
5242 case MONO_TYPE_STRING:
5243 case MONO_TYPE_SZARRAY:
5244 case MONO_TYPE_OBJECT:
5245 case MONO_TYPE_CLASS:
5246 case MONO_TYPE_ARRAY:
5247 obj = *(MonoObject**)addr;
5249 if (!obj) {
5250 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5251 } else {
5252 if (m_class_is_valuetype (obj->vtable->klass)) {
5253 t = m_class_get_byval_arg (obj->vtable->klass);
5254 addr = mono_object_unbox_internal (obj);
5255 boxed_vtype = TRUE;
5256 goto handle_vtype;
5257 } else if (m_class_get_rank (obj->vtable->klass)) {
5258 buffer_add_byte (buf, m_class_get_byval_arg (obj->vtable->klass)->type);
5259 } else if (m_class_get_byval_arg (obj->vtable->klass)->type == MONO_TYPE_GENERICINST) {
5260 buffer_add_byte (buf, MONO_TYPE_CLASS);
5261 } else {
5262 buffer_add_byte (buf, m_class_get_byval_arg (obj->vtable->klass)->type);
5264 buffer_add_objid (buf, obj);
5266 break;
5267 handle_vtype:
5268 case MONO_TYPE_VALUETYPE:
5269 case MONO_TYPE_TYPEDBYREF: {
5270 int nfields;
5271 gpointer iter;
5272 MonoClassField *f;
5273 MonoClass *klass = mono_class_from_mono_type_internal (t);
5274 int vtype_index;
5276 if (boxed_vtype) {
5278 * Handle boxed vtypes recursively referencing themselves using fields.
5280 if (!parent_vtypes)
5281 parent_vtypes = g_hash_table_new (NULL, NULL);
5282 vtype_index = GPOINTER_TO_INT (g_hash_table_lookup (parent_vtypes, addr));
5283 if (vtype_index) {
5284 if (CHECK_PROTOCOL_VERSION (2, 33)) {
5285 buffer_add_byte (buf, VALUE_TYPE_ID_PARENT_VTYPE);
5286 buffer_add_int (buf, vtype_index - 1);
5287 } else {
5288 /* The client can't handle PARENT_VTYPE */
5289 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5291 break;
5292 } else {
5293 g_hash_table_insert (parent_vtypes, addr, GINT_TO_POINTER (g_hash_table_size (parent_vtypes) + 1));
5297 buffer_add_byte (buf, MONO_TYPE_VALUETYPE);
5298 buffer_add_byte (buf, m_class_is_enumtype (klass));
5299 buffer_add_typeid (buf, domain, klass);
5301 nfields = 0;
5302 iter = NULL;
5303 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5304 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5305 continue;
5306 if (mono_field_is_deleted (f))
5307 continue;
5308 nfields ++;
5310 buffer_add_int (buf, nfields);
5312 iter = NULL;
5313 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5314 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5315 continue;
5316 if (mono_field_is_deleted (f))
5317 continue;
5318 buffer_add_value_full (buf, f->type, mono_vtype_get_field_addr (addr, f), domain, FALSE, parent_vtypes);
5321 if (boxed_vtype) {
5322 g_hash_table_remove (parent_vtypes, addr);
5323 if (g_hash_table_size (parent_vtypes) == 0) {
5324 g_hash_table_destroy (parent_vtypes);
5325 parent_vtypes = NULL;
5328 break;
5330 case MONO_TYPE_GENERICINST:
5331 if (mono_type_generic_inst_is_valuetype (t)) {
5332 goto handle_vtype;
5333 } else {
5334 goto handle_ref;
5336 break;
5337 default:
5338 NOT_IMPLEMENTED;
5342 static void
5343 buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
5345 buffer_add_value_full (buf, t, addr, domain, FALSE, NULL);
5348 static gboolean
5349 obj_is_of_type (MonoObject *obj, MonoType *t)
5351 MonoClass *klass = obj->vtable->klass;
5352 if (!mono_class_is_assignable_from_internal (mono_class_from_mono_type_internal (t), klass)) {
5353 if (mono_class_is_transparent_proxy (klass)) {
5354 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5355 if (mono_class_is_assignable_from_internal (mono_class_from_mono_type_internal (t), klass)) {
5356 return TRUE;
5359 return FALSE;
5361 return TRUE;
5364 static ErrorCode
5365 decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit);
5367 static ErrorCode
5368 decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit)
5370 guint8 *addr = (guint8*)void_addr;
5371 guint8 *buf = (guint8*)void_buf;
5372 gboolean is_enum;
5373 MonoClass *klass;
5374 MonoClassField *f;
5375 int nfields;
5376 gpointer iter = NULL;
5377 MonoDomain *d;
5378 ErrorCode err;
5380 is_enum = decode_byte (buf, &buf, limit);
5381 /* Enums are sent as a normal vtype */
5382 if (is_enum)
5383 return ERR_NOT_IMPLEMENTED;
5384 klass = decode_typeid (buf, &buf, limit, &d, &err);
5385 if (err != ERR_NONE)
5386 return err;
5388 if (t && klass != mono_class_from_mono_type_internal (t)) {
5389 char *name = mono_type_full_name (t);
5390 char *name2 = mono_type_full_name (m_class_get_byval_arg (klass));
5391 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got %s.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, name2);
5392 g_free (name);
5393 g_free (name2);
5394 return ERR_INVALID_ARGUMENT;
5397 nfields = decode_int (buf, &buf, limit);
5398 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5399 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5400 continue;
5401 if (mono_field_is_deleted (f))
5402 continue;
5403 err = decode_value (f->type, domain, mono_vtype_get_field_addr (addr, f), buf, &buf, limit);
5404 if (err != ERR_NONE)
5405 return err;
5406 nfields --;
5408 g_assert (nfields == 0);
5410 *endbuf = buf;
5412 return ERR_NONE;
5415 static ErrorCode
5416 decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
5418 ErrorCode err;
5420 if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) &&
5421 !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
5422 !(t->type == MONO_TYPE_U && type == MONO_TYPE_VALUETYPE) &&
5423 !(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8) &&
5424 !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) &&
5425 !(t->type == MONO_TYPE_VALUETYPE && type == MONO_TYPE_OBJECT)) {
5426 char *name = mono_type_full_name (t);
5427 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type);
5428 g_free (name);
5429 return ERR_INVALID_ARGUMENT;
5432 switch (t->type) {
5433 case MONO_TYPE_BOOLEAN:
5434 *(guint8*)addr = decode_int (buf, &buf, limit);
5435 break;
5436 case MONO_TYPE_CHAR:
5437 *(gunichar2*)addr = decode_int (buf, &buf, limit);
5438 break;
5439 case MONO_TYPE_I1:
5440 *(gint8*)addr = decode_int (buf, &buf, limit);
5441 break;
5442 case MONO_TYPE_U1:
5443 *(guint8*)addr = decode_int (buf, &buf, limit);
5444 break;
5445 case MONO_TYPE_I2:
5446 *(gint16*)addr = decode_int (buf, &buf, limit);
5447 break;
5448 case MONO_TYPE_U2:
5449 *(guint16*)addr = decode_int (buf, &buf, limit);
5450 break;
5451 case MONO_TYPE_I4:
5452 *(gint32*)addr = decode_int (buf, &buf, limit);
5453 break;
5454 case MONO_TYPE_U4:
5455 *(guint32*)addr = decode_int (buf, &buf, limit);
5456 break;
5457 case MONO_TYPE_I8:
5458 *(gint64*)addr = decode_long (buf, &buf, limit);
5459 break;
5460 case MONO_TYPE_U8:
5461 *(guint64*)addr = decode_long (buf, &buf, limit);
5462 break;
5463 case MONO_TYPE_R4:
5464 *(guint32*)addr = decode_int (buf, &buf, limit);
5465 break;
5466 case MONO_TYPE_R8:
5467 *(guint64*)addr = decode_long (buf, &buf, limit);
5468 break;
5469 case MONO_TYPE_PTR:
5470 /* We send these as I8, so we get them back as such */
5471 g_assert (type == MONO_TYPE_I8);
5472 *(gssize*)addr = decode_long (buf, &buf, limit);
5473 break;
5474 case MONO_TYPE_GENERICINST:
5475 if (MONO_TYPE_ISSTRUCT (t)) {
5476 /* The client sends these as a valuetype */
5477 goto handle_vtype;
5478 } else {
5479 goto handle_ref;
5481 break;
5482 case MONO_TYPE_I:
5483 case MONO_TYPE_U:
5484 /* We send these as vtypes, so we get them back as such */
5485 g_assert (type == MONO_TYPE_VALUETYPE);
5486 /* Fall through */
5487 handle_vtype:
5488 case MONO_TYPE_VALUETYPE:
5489 if (type == MONO_TYPE_OBJECT) {
5490 /* Boxed vtype */
5491 int objid = decode_objid (buf, &buf, limit);
5492 ErrorCode err;
5493 MonoObject *obj;
5495 err = get_object (objid, (MonoObject**)&obj);
5496 if (err != ERR_NONE)
5497 return err;
5498 if (!obj)
5499 return ERR_INVALID_ARGUMENT;
5500 if (obj->vtable->klass != mono_class_from_mono_type_internal (t)) {
5501 DEBUG_PRINTF (1, "Expected type '%s', got object '%s'\n", mono_type_full_name (t), m_class_get_name (obj->vtable->klass));
5502 return ERR_INVALID_ARGUMENT;
5504 memcpy (addr, mono_object_unbox_internal (obj), mono_class_value_size (obj->vtable->klass, NULL));
5505 } else {
5506 err = decode_vtype (t, domain, addr, buf, &buf, limit);
5507 if (err != ERR_NONE)
5508 return err;
5510 break;
5511 handle_ref:
5512 default:
5513 if (MONO_TYPE_IS_REFERENCE (t)) {
5514 if (type == MONO_TYPE_OBJECT) {
5515 int objid = decode_objid (buf, &buf, limit);
5516 ErrorCode err;
5517 MonoObject *obj;
5519 err = get_object (objid, (MonoObject**)&obj);
5520 if (err != ERR_NONE)
5521 return err;
5523 if (obj) {
5524 if (!obj_is_of_type (obj, t)) {
5525 DEBUG_PRINTF (1, "Expected type '%s', got '%s'\n", mono_type_full_name (t), m_class_get_name (obj->vtable->klass));
5526 return ERR_INVALID_ARGUMENT;
5529 if (obj && obj->vtable->domain != domain)
5530 return ERR_INVALID_ARGUMENT;
5532 mono_gc_wbarrier_generic_store_internal (addr, obj);
5533 } else if (type == VALUE_TYPE_ID_NULL) {
5534 *(MonoObject**)addr = NULL;
5535 } else if (type == MONO_TYPE_VALUETYPE) {
5536 ERROR_DECL (error);
5537 guint8 *buf2;
5538 gboolean is_enum;
5539 MonoClass *klass;
5540 MonoDomain *d;
5541 guint8 *vtype_buf;
5542 int vtype_buf_size;
5544 /* This can happen when round-tripping boxed vtypes */
5546 * Obtain vtype class.
5547 * Same as the beginning of the handle_vtype case above.
5549 buf2 = buf;
5550 is_enum = decode_byte (buf, &buf, limit);
5551 if (is_enum)
5552 return ERR_NOT_IMPLEMENTED;
5553 klass = decode_typeid (buf, &buf, limit, &d, &err);
5554 if (err != ERR_NONE)
5555 return err;
5557 /* Decode the vtype into a temporary buffer, then box it. */
5558 vtype_buf_size = mono_class_value_size (klass, NULL);
5559 vtype_buf = (guint8 *)g_malloc0 (vtype_buf_size);
5560 g_assert (vtype_buf);
5562 buf = buf2;
5563 err = decode_vtype (NULL, domain, vtype_buf, buf, &buf, limit);
5564 if (err != ERR_NONE) {
5565 g_free (vtype_buf);
5566 return err;
5568 *(MonoObject**)addr = mono_value_box_checked (d, klass, vtype_buf, error);
5569 mono_error_cleanup (error);
5570 g_free (vtype_buf);
5571 } else {
5572 char *name = mono_type_full_name (t);
5573 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type);
5574 g_free (name);
5575 return ERR_INVALID_ARGUMENT;
5577 } else {
5578 NOT_IMPLEMENTED;
5580 break;
5583 *endbuf = buf;
5585 return ERR_NONE;
5588 static ErrorCode
5589 decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit)
5591 guint8 *addr = (guint8*)void_addr;
5592 guint8 *buf = (guint8*)void_buf;
5594 ERROR_DECL (error);
5595 ErrorCode err;
5596 int type = decode_byte (buf, &buf, limit);
5598 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
5599 MonoType *targ = t->data.generic_class->context.class_inst->type_argv [0];
5600 guint8 *nullable_buf;
5603 * First try decoding it as a Nullable`1
5605 err = decode_value_internal (t, type, domain, addr, buf, endbuf, limit);
5606 if (err == ERR_NONE)
5607 return err;
5610 * Then try decoding as a primitive value or null.
5612 if (targ->type == type) {
5613 nullable_buf = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (targ)));
5614 err = decode_value_internal (targ, type, domain, nullable_buf, buf, endbuf, limit);
5615 if (err != ERR_NONE) {
5616 g_free (nullable_buf);
5617 return err;
5619 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (targ), nullable_buf, error);
5620 if (!is_ok (error)) {
5621 mono_error_cleanup (error);
5622 return ERR_INVALID_OBJECT;
5624 mono_nullable_init (addr, boxed, mono_class_from_mono_type_internal (t));
5625 g_free (nullable_buf);
5626 *endbuf = buf;
5627 return ERR_NONE;
5628 } else if (type == VALUE_TYPE_ID_NULL) {
5629 mono_nullable_init (addr, NULL, mono_class_from_mono_type_internal (t));
5630 *endbuf = buf;
5631 return ERR_NONE;
5635 return decode_value_internal (t, type, domain, addr, buf, endbuf, limit);
5638 static void
5639 add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
5641 guint32 flags;
5642 int reg;
5643 guint8 *addr, *gaddr;
5644 host_mgreg_t reg_val;
5646 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5647 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5649 switch (flags) {
5650 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
5651 reg_val = mono_arch_context_get_int_reg (ctx, reg);
5653 buffer_add_value_full (buf, t, &reg_val, domain, as_vtype, NULL);
5654 break;
5655 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
5656 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5657 addr += (gint32)var->offset;
5659 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
5661 buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL);
5662 break;
5663 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
5664 NOT_IMPLEMENTED;
5665 break;
5666 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
5667 case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR:
5668 /* Same as regoffset, but with an indirection */
5669 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5670 addr += (gint32)var->offset;
5672 gaddr = (guint8 *)*(gpointer*)addr;
5673 g_assert (gaddr);
5674 buffer_add_value_full (buf, t, gaddr, domain, as_vtype, NULL);
5675 break;
5676 case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: {
5677 MonoDebugVarInfo *info_var = jit->gsharedvt_info_var;
5678 MonoDebugVarInfo *locals_var = jit->gsharedvt_locals_var;
5679 MonoGSharedVtMethodRuntimeInfo *info;
5680 guint8 *locals;
5681 int idx;
5683 idx = reg;
5685 g_assert (info_var);
5686 g_assert (locals_var);
5688 flags = info_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5689 reg = info_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5690 if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
5691 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5692 addr += (gint32)info_var->offset;
5693 info = (MonoGSharedVtMethodRuntimeInfo *)*(gpointer*)addr;
5694 } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
5695 info = (MonoGSharedVtMethodRuntimeInfo *)mono_arch_context_get_int_reg (ctx, reg);
5696 } else {
5697 g_assert_not_reached ();
5699 g_assert (info);
5701 flags = locals_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5702 reg = locals_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5703 if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
5704 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5705 addr += (gint32)locals_var->offset;
5706 locals = (guint8 *)*(gpointer*)addr;
5707 } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
5708 locals = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5709 } else {
5710 g_assert_not_reached ();
5712 g_assert (locals);
5714 addr = locals + GPOINTER_TO_INT (info->entries [idx]);
5716 buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL);
5717 break;
5720 default:
5721 g_assert_not_reached ();
5725 static void
5726 set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, guint8 *val, host_mgreg_t **reg_locations, MonoContext *restore_ctx)
5728 guint32 flags;
5729 int reg, size;
5730 guint8 *addr, *gaddr;
5732 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5733 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5735 if (MONO_TYPE_IS_REFERENCE (t))
5736 size = sizeof (gpointer);
5737 else
5738 size = mono_class_value_size (mono_class_from_mono_type_internal (t), NULL);
5740 switch (flags) {
5741 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER: {
5742 #ifdef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
5743 host_mgreg_t v;
5744 gboolean is_signed = FALSE;
5746 if (t->byref) {
5747 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5749 if (addr) {
5750 // FIXME: Write barriers
5751 mono_gc_memmove_atomic (addr, val, size);
5753 break;
5756 if (!t->byref && (t->type == MONO_TYPE_I1 || t->type == MONO_TYPE_I2 || t->type == MONO_TYPE_I4 || t->type == MONO_TYPE_I8))
5757 is_signed = TRUE;
5759 switch (size) {
5760 case 1:
5761 v = is_signed ? *(gint8*)val : *(guint8*)val;
5762 break;
5763 case 2:
5764 v = is_signed ? *(gint16*)val : *(guint16*)val;
5765 break;
5766 case 4:
5767 v = is_signed ? *(gint32*)val : *(guint32*)val;
5768 break;
5769 case 8:
5770 v = is_signed ? *(gint64*)val : *(guint64*)val;
5771 break;
5772 default:
5773 g_assert_not_reached ();
5776 /* Set value on the stack or in the return ctx */
5777 if (reg_locations [reg]) {
5778 /* Saved on the stack */
5779 DEBUG_PRINTF (1, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations [reg], reg, (gpointer)v);
5780 *(reg_locations [reg]) = v;
5781 } else {
5782 /* Not saved yet */
5783 DEBUG_PRINTF (1, "[dbg] Setting context location for reg %x to %p.\n", reg, (gpointer)v);
5784 mono_arch_context_set_int_reg (restore_ctx, reg, v);
5787 // FIXME: Move these to mono-context.h/c.
5788 mono_arch_context_set_int_reg (ctx, reg, v);
5789 #else
5790 // FIXME: Can't set registers, so we disable linears
5791 NOT_IMPLEMENTED;
5792 #endif
5793 break;
5795 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
5796 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5797 addr += (gint32)var->offset;
5799 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
5801 if (t->byref) {
5802 addr = *(guint8**)addr;
5804 if (!addr)
5805 break;
5808 // FIXME: Write barriers
5809 mono_gc_memmove_atomic (addr, val, size);
5810 break;
5811 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
5812 /* Same as regoffset, but with an indirection */
5813 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5814 addr += (gint32)var->offset;
5816 gaddr = (guint8 *)*(gpointer*)addr;
5817 g_assert (gaddr);
5818 // FIXME: Write barriers
5819 mono_gc_memmove_atomic (gaddr, val, size);
5820 break;
5821 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
5822 NOT_IMPLEMENTED;
5823 break;
5824 default:
5825 g_assert_not_reached ();
5829 static void
5830 set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf)
5832 int size;
5834 if (t->byref) {
5835 addr = *(gpointer*)addr;
5836 g_assert (addr);
5839 if (MONO_TYPE_IS_REFERENCE (t))
5840 size = sizeof (gpointer);
5841 else
5842 size = mono_class_value_size (mono_class_from_mono_type_internal (t), NULL);
5844 memcpy (addr, val_buf, size);
5847 static void
5848 clear_event_request (int req_id, int etype)
5850 int i;
5852 mono_loader_lock ();
5853 for (i = 0; i < event_requests->len; ++i) {
5854 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
5856 if (req->id == req_id && req->event_kind == etype) {
5857 if (req->event_kind == EVENT_KIND_BREAKPOINT)
5858 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
5859 if (req->event_kind == EVENT_KIND_STEP) {
5860 mono_de_cancel_ss ();
5862 if (req->event_kind == EVENT_KIND_METHOD_ENTRY)
5863 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
5864 if (req->event_kind == EVENT_KIND_METHOD_EXIT)
5865 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
5866 g_ptr_array_remove_index_fast (event_requests, i);
5867 g_free (req);
5868 break;
5871 mono_loader_unlock ();
5874 static void
5875 clear_assembly_from_modifier (EventRequest *req, Modifier *m, MonoAssembly *assembly)
5877 int i;
5879 if (m->kind == MOD_KIND_EXCEPTION_ONLY && m->data.exc_class && m_class_get_image (m->data.exc_class)->assembly == assembly)
5880 m->kind = MOD_KIND_NONE;
5881 if (m->kind == MOD_KIND_ASSEMBLY_ONLY && m->data.assemblies) {
5882 int count = 0, match_count = 0, pos;
5883 MonoAssembly **newassemblies;
5885 for (i = 0; m->data.assemblies [i]; ++i) {
5886 count ++;
5887 if (m->data.assemblies [i] == assembly)
5888 match_count ++;
5891 if (match_count) {
5892 // +1 because we don't know length and we use last element to check for end
5893 newassemblies = g_new0 (MonoAssembly*, count - match_count + 1);
5895 pos = 0;
5896 for (i = 0; i < count; ++i)
5897 if (m->data.assemblies [i] != assembly)
5898 newassemblies [pos ++] = m->data.assemblies [i];
5899 g_assert (pos == count - match_count);
5900 g_free (m->data.assemblies);
5901 m->data.assemblies = newassemblies;
5906 static void
5907 clear_assembly_from_modifiers (EventRequest *req, MonoAssembly *assembly)
5909 int i;
5911 for (i = 0; i < req->nmodifiers; ++i) {
5912 Modifier *m = &req->modifiers [i];
5914 clear_assembly_from_modifier (req, m, assembly);
5919 * clear_event_requests_for_assembly:
5921 * Clear all events requests which reference ASSEMBLY.
5923 static void
5924 clear_event_requests_for_assembly (MonoAssembly *assembly)
5926 int i;
5927 gboolean found;
5929 mono_loader_lock ();
5930 found = TRUE;
5931 while (found) {
5932 found = FALSE;
5933 for (i = 0; i < event_requests->len; ++i) {
5934 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
5936 clear_assembly_from_modifiers (req, assembly);
5938 if (req->event_kind == EVENT_KIND_BREAKPOINT && breakpoint_matches_assembly ((MonoBreakpoint *)req->info, assembly)) {
5939 clear_event_request (req->id, req->event_kind);
5940 found = TRUE;
5941 break;
5944 if (req->event_kind == EVENT_KIND_STEP)
5945 ss_clear_for_assembly ((SingleStepReq *)req->info, assembly);
5948 mono_loader_unlock ();
5952 * type_comes_from_assembly:
5954 * GHRFunc that returns TRUE if klass comes from assembly
5956 static gboolean
5957 type_comes_from_assembly (gpointer klass, gpointer also_klass, gpointer assembly)
5959 return mono_type_in_image (m_class_get_byval_arg ((MonoClass*)klass), mono_assembly_get_image_internal ((MonoAssembly*)assembly));
5963 * clear_types_for_assembly:
5965 * Clears types from loaded_classes for a given assembly
5967 static void
5968 clear_types_for_assembly (MonoAssembly *assembly)
5970 MonoDomain *domain = mono_domain_get ();
5971 AgentDomainInfo *info = NULL;
5973 if (!domain || !domain_jit_info (domain))
5974 /* Can happen during shutdown */
5975 return;
5977 info = get_agent_domain_info (domain);
5979 mono_loader_lock ();
5980 g_hash_table_foreach_remove (info->loaded_classes, type_comes_from_assembly, assembly);
5981 mono_loader_unlock ();
5984 static void
5985 add_thread (gpointer key, gpointer value, gpointer user_data)
5987 MonoInternalThread *thread = (MonoInternalThread *)value;
5988 Buffer *buf = (Buffer *)user_data;
5990 buffer_add_objid (buf, (MonoObject*)thread);
5993 static ErrorCode
5994 do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp)
5996 ERROR_DECL (error);
5997 guint8 *end = invoke->endp;
5998 MonoMethod *m;
5999 int i, nargs;
6000 ErrorCode err;
6001 MonoMethodSignature *sig;
6002 guint8 **arg_buf;
6003 void **args;
6004 MonoObject *this_arg, *res, *exc = NULL;
6005 MonoDomain *domain;
6006 guint8 *this_buf;
6007 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6008 MonoLMFExt ext;
6009 #endif
6010 MonoStopwatch watch;
6012 if (invoke->method) {
6014 * Invoke this method directly, currently only Environment.Exit () is supported.
6016 this_arg = NULL;
6017 DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (invoke->method, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : "<null>");
6019 mono_runtime_try_invoke (invoke->method, NULL, invoke->args, &exc, error);
6020 mono_error_assert_ok (error);
6022 g_assert_not_reached ();
6025 m = decode_methodid (p, &p, end, &domain, &err);
6026 if (err != ERR_NONE)
6027 return err;
6028 sig = mono_method_signature_internal (m);
6030 if (m_class_is_valuetype (m->klass))
6031 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6032 else
6033 this_buf = (guint8 *)g_alloca (sizeof (MonoObject*));
6035 if (m->is_generic) {
6036 DEBUG_PRINTF (1, "[%p] Error: Attempting to invoke uninflated generic method %s.\n", (gpointer)(gsize)mono_native_thread_id_get (), mono_method_full_name (m, TRUE));
6037 return ERR_INVALID_ARGUMENT;
6038 } else if (m_class_is_valuetype (m->klass) && (m->flags & METHOD_ATTRIBUTE_STATIC)) {
6039 /* Should be null */
6040 int type = decode_byte (p, &p, end);
6041 if (type != VALUE_TYPE_ID_NULL) {
6042 DEBUG_PRINTF (1, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6043 return ERR_INVALID_ARGUMENT;
6045 memset (this_buf, 0, mono_class_instance_size (m->klass));
6046 } else if (m_class_is_valuetype (m->klass) && !strcmp (m->name, ".ctor")) {
6047 /* Could be null */
6048 guint8 *tmp_p;
6050 int type = decode_byte (p, &tmp_p, end);
6051 if (type == VALUE_TYPE_ID_NULL) {
6052 memset (this_buf, 0, mono_class_instance_size (m->klass));
6053 p = tmp_p;
6054 } else {
6055 err = decode_value (m_class_get_byval_arg (m->klass), domain, this_buf, p, &p, end);
6056 if (err != ERR_NONE)
6057 return err;
6059 } else {
6060 err = decode_value (m_class_get_byval_arg (m->klass), domain, this_buf, p, &p, end);
6061 if (err != ERR_NONE)
6062 return err;
6065 if (!m_class_is_valuetype (m->klass))
6066 this_arg = *(MonoObject**)this_buf;
6067 else
6068 this_arg = NULL;
6070 if (MONO_CLASS_IS_INTERFACE_INTERNAL (m->klass)) {
6071 if (!this_arg) {
6072 DEBUG_PRINTF (1, "[%p] Error: Interface method invoked without this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6073 return ERR_INVALID_ARGUMENT;
6075 m = mono_object_get_virtual_method_internal (this_arg, m);
6076 /* Transform this to the format the rest of the code expects it to be */
6077 if (m_class_is_valuetype (m->klass)) {
6078 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6079 memcpy (this_buf, mono_object_unbox_internal (this_arg), mono_class_instance_size (m->klass));
6081 } else if ((m->flags & METHOD_ATTRIBUTE_VIRTUAL) && !m_class_is_valuetype (m->klass) && invoke->flags & INVOKE_FLAG_VIRTUAL) {
6082 if (!this_arg) {
6083 DEBUG_PRINTF (1, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6084 return ERR_INVALID_ARGUMENT;
6086 m = mono_object_get_virtual_method_internal (this_arg, m);
6087 if (m_class_is_valuetype (m->klass)) {
6088 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6089 memcpy (this_buf, mono_object_unbox_internal (this_arg), mono_class_instance_size (m->klass));
6093 DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (m, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : "<null>");
6095 if (this_arg && this_arg->vtable->domain != domain)
6096 NOT_IMPLEMENTED;
6098 if (!m_class_is_valuetype (m->klass) && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this_arg) {
6099 if (!strcmp (m->name, ".ctor")) {
6100 if (mono_class_is_abstract (m->klass))
6101 return ERR_INVALID_ARGUMENT;
6102 else {
6103 ERROR_DECL (error);
6104 this_arg = mono_object_new_checked (domain, m->klass, error);
6105 mono_error_assert_ok (error);
6107 } else {
6108 return ERR_INVALID_ARGUMENT;
6112 if (this_arg && !obj_is_of_type (this_arg, m_class_get_byval_arg (m->klass)))
6113 return ERR_INVALID_ARGUMENT;
6115 nargs = decode_int (p, &p, end);
6116 if (nargs != sig->param_count)
6117 return ERR_INVALID_ARGUMENT;
6118 /* Use alloca to get gc tracking */
6119 arg_buf = (guint8 **)g_alloca (nargs * sizeof (gpointer));
6120 memset (arg_buf, 0, nargs * sizeof (gpointer));
6121 args = (gpointer *)g_alloca (nargs * sizeof (gpointer));
6122 for (i = 0; i < nargs; ++i) {
6123 if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
6124 err = decode_value (sig->params [i], domain, (guint8*)&args [i], p, &p, end);
6125 if (err != ERR_NONE)
6126 break;
6127 if (args [i] && ((MonoObject*)args [i])->vtable->domain != domain)
6128 NOT_IMPLEMENTED;
6130 if (sig->params [i]->byref) {
6131 arg_buf [i] = g_newa (guint8, sizeof (gpointer));
6132 *(gpointer*)arg_buf [i] = args [i];
6133 args [i] = arg_buf [i];
6135 } else {
6136 MonoClass *arg_class = mono_class_from_mono_type_internal (sig->params [i]);
6137 arg_buf [i] = (guint8 *)g_alloca (mono_class_instance_size (arg_class));
6138 err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end);
6139 if (err != ERR_NONE)
6140 break;
6141 if (mono_class_is_nullable (arg_class)) {
6142 args [i] = mono_nullable_box (arg_buf [i], arg_class, error);
6143 mono_error_assert_ok (error);
6144 } else {
6145 args [i] = arg_buf [i];
6150 if (i < nargs)
6151 return err;
6153 if (invoke->flags & INVOKE_FLAG_DISABLE_BREAKPOINTS)
6154 tls->disable_breakpoints = TRUE;
6155 else
6156 tls->disable_breakpoints = FALSE;
6159 * Add an LMF frame to link the stack frames on the invoke method with our caller.
6161 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6162 if (invoke->has_ctx) {
6163 /* Setup our lmf */
6164 memset (&ext, 0, sizeof (ext));
6165 ext.kind = MONO_LMFEXT_DEBUGGER_INVOKE;
6166 memcpy (&ext.ctx, &invoke->ctx, sizeof (MonoContext));
6168 mono_push_lmf (&ext);
6170 #endif
6172 mono_stopwatch_start (&watch);
6173 res = mono_runtime_try_invoke (m, m_class_is_valuetype (m->klass) ? (gpointer) this_buf : (gpointer) this_arg, args, &exc, error);
6174 if (!mono_error_ok (error) && exc == NULL) {
6175 exc = (MonoObject*) mono_error_convert_to_exception (error);
6176 } else {
6177 mono_error_cleanup (error); /* FIXME report error */
6179 mono_stopwatch_stop (&watch);
6180 DEBUG_PRINTF (1, "[%p] Invoke result: %p, exc: %s, time: %ld ms.\n", (gpointer) (gsize) mono_native_thread_id_get (), res, exc ? m_class_get_name (exc->vtable->klass) : NULL, (long)mono_stopwatch_elapsed_ms (&watch));
6181 if (exc) {
6182 buffer_add_byte (buf, 0);
6183 buffer_add_value (buf, mono_get_object_type (), &exc, domain);
6184 } else {
6185 gboolean out_this = FALSE;
6186 gboolean out_args = FALSE;
6188 if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_THIS) && CHECK_PROTOCOL_VERSION (2, 35))
6189 out_this = TRUE;
6190 if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_ARGS) && CHECK_PROTOCOL_VERSION (2, 35))
6191 out_args = TRUE;
6192 buffer_add_byte (buf, 1 + (out_this ? 2 : 0) + (out_args ? 4 : 0));
6193 if (m->string_ctor) {
6194 buffer_add_value (buf, m_class_get_byval_arg (mono_get_string_class ()), &res, domain);
6195 } else if (sig->ret->type == MONO_TYPE_VOID && !m->string_ctor) {
6196 if (!strcmp (m->name, ".ctor")) {
6197 if (!m_class_is_valuetype (m->klass))
6198 buffer_add_value (buf, mono_get_object_type (), &this_arg, domain);
6199 else
6200 buffer_add_value (buf, m_class_get_byval_arg (m->klass), this_buf, domain);
6201 } else {
6202 buffer_add_value (buf, mono_get_void_type (), NULL, domain);
6204 } else if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
6205 if (sig->ret->byref) {
6206 MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret));
6207 buffer_add_value (buf, ret_byval, &res, domain);
6208 } else {
6209 buffer_add_value (buf, sig->ret, &res, domain);
6211 } else if (m_class_is_valuetype (mono_class_from_mono_type_internal (sig->ret)) || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) {
6212 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig->ret))) {
6213 MonoClass *k = mono_class_from_mono_type_internal (sig->ret);
6214 guint8 *nullable_buf = (guint8 *)g_alloca (mono_class_value_size (k, NULL));
6216 g_assert (nullable_buf);
6217 mono_nullable_init (nullable_buf, res, k);
6218 buffer_add_value (buf, sig->ret, nullable_buf, domain);
6219 } else {
6220 g_assert (res);
6222 if (sig->ret->byref) {
6223 MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret));
6224 buffer_add_value (buf, ret_byval, mono_object_unbox_internal (res), domain);
6225 } else {
6226 buffer_add_value (buf, sig->ret, mono_object_unbox_internal (res), domain);
6229 } else {
6230 NOT_IMPLEMENTED;
6232 if (out_this)
6233 /* Return the new value of the receiver after the call */
6234 buffer_add_value (buf, m_class_get_byval_arg (m->klass), this_buf, domain);
6235 if (out_args) {
6236 buffer_add_int (buf, nargs);
6237 for (i = 0; i < nargs; ++i) {
6238 if (MONO_TYPE_IS_REFERENCE (sig->params [i]))
6239 buffer_add_value (buf, sig->params [i], &args [i], domain);
6240 else if (sig->params [i]->byref)
6241 /* add_value () does an indirection */
6242 buffer_add_value (buf, sig->params [i], &arg_buf [i], domain);
6243 else
6244 buffer_add_value (buf, sig->params [i], arg_buf [i], domain);
6249 tls->disable_breakpoints = FALSE;
6251 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6252 if (invoke->has_ctx)
6253 mono_pop_lmf ((MonoLMF*)&ext);
6254 #endif
6256 *endp = p;
6257 // FIXME: byref arguments
6258 // FIXME: varargs
6259 return ERR_NONE;
6263 * invoke_method:
6265 * Invoke the method given by tls->pending_invoke in the current thread.
6267 static void
6268 invoke_method (void)
6270 DebuggerTlsData *tls;
6271 InvokeData *invoke;
6272 int id;
6273 int i, mindex;
6274 ErrorCode err;
6275 Buffer buf;
6276 MonoContext restore_ctx;
6277 guint8 *p;
6279 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
6280 g_assert (tls);
6283 * Store the `InvokeData *' in `tls->invoke' until we're done with
6284 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
6287 mono_loader_lock ();
6289 invoke = tls->pending_invoke;
6290 g_assert (invoke);
6291 tls->pending_invoke = NULL;
6293 invoke->last_invoke = tls->invoke;
6294 tls->invoke = invoke;
6296 mono_loader_unlock ();
6298 tls->frames_up_to_date = FALSE;
6300 id = invoke->id;
6302 p = invoke->p;
6303 err = ERR_NONE;
6304 for (mindex = 0; mindex < invoke->nmethods; ++mindex) {
6305 buffer_init (&buf, 128);
6307 if (err) {
6308 /* Fail the other invokes as well */
6309 } else {
6310 err = do_invoke_method (tls, &buf, invoke, p, &p);
6313 if (tls->abort_requested) {
6314 if (CHECK_PROTOCOL_VERSION (2, 42))
6315 err = ERR_INVOKE_ABORTED;
6318 /* Start suspending before sending the reply */
6319 if (mindex == invoke->nmethods - 1) {
6320 if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) {
6321 for (i = 0; i < invoke->suspend_count; ++i)
6322 suspend_vm ();
6326 send_reply_packet (id, err, &buf);
6328 buffer_free (&buf);
6331 memcpy (&restore_ctx, &invoke->ctx, sizeof (MonoContext));
6333 if (invoke->has_ctx)
6334 save_thread_context (&restore_ctx);
6336 if (invoke->flags & INVOKE_FLAG_SINGLE_THREADED) {
6337 g_assert (tls->resume_count);
6338 tls->resume_count -= invoke->suspend_count;
6341 DEBUG_PRINTF (1, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer) (gsize) mono_native_thread_id_get (), err, tls->resume_count);
6344 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
6346 * It is possible that mono_thread_internal_abort () was called
6347 * after the mono_runtime_invoke_checked() already returned, but it doesn't matter
6348 * because we reset the abort here.
6351 mono_loader_lock ();
6353 if (tls->abort_requested)
6354 mono_thread_internal_reset_abort (tls->thread);
6356 tls->invoke = tls->invoke->last_invoke;
6357 tls->abort_requested = FALSE;
6359 mono_loader_unlock ();
6361 g_free (invoke->p);
6362 g_free (invoke);
6364 suspend_current ();
6367 static gboolean
6368 is_really_suspended (gpointer key, gpointer value, gpointer user_data)
6370 MonoThread *thread = (MonoThread *)value;
6371 DebuggerTlsData *tls;
6372 gboolean res;
6374 mono_loader_lock ();
6375 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
6376 g_assert (tls);
6377 res = tls->really_suspended;
6378 mono_loader_unlock ();
6380 return res;
6383 static GPtrArray*
6384 get_source_files_for_type (MonoClass *klass)
6386 gpointer iter = NULL;
6387 MonoMethod *method;
6388 MonoDebugSourceInfo *sinfo;
6389 GPtrArray *files;
6390 int i, j;
6392 files = g_ptr_array_new ();
6394 while ((method = mono_class_get_methods (klass, &iter))) {
6395 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
6396 GPtrArray *source_file_list;
6398 if (minfo) {
6399 mono_debug_get_seq_points (minfo, NULL, &source_file_list, NULL, NULL, NULL);
6400 for (j = 0; j < source_file_list->len; ++j) {
6401 sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, j);
6402 for (i = 0; i < files->len; ++i)
6403 if (!strcmp ((const char*)g_ptr_array_index (files, i), (const char*)sinfo->source_file))
6404 break;
6405 if (i == files->len)
6406 g_ptr_array_add (files, g_strdup (sinfo->source_file));
6408 g_ptr_array_free (source_file_list, TRUE);
6412 return files;
6416 typedef struct {
6417 MonoTypeNameParse *info;
6418 gboolean ignore_case;
6419 GPtrArray *res_classes;
6420 GPtrArray *res_domains;
6421 } GetTypesArgs;
6423 static void
6424 get_types (gpointer key, gpointer value, gpointer user_data)
6426 MonoAssembly *ass;
6427 gboolean type_resolve;
6428 MonoType *t;
6429 GSList *tmp;
6430 MonoDomain *domain = (MonoDomain*)key;
6431 GetTypesArgs *ud = (GetTypesArgs*)user_data;
6433 mono_domain_assemblies_lock (domain);
6434 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
6435 ass = (MonoAssembly *)tmp->data;
6437 if (ass->image) {
6438 ERROR_DECL_VALUE (probe_type_error);
6439 /* FIXME really okay to call while holding locks? */
6440 t = mono_reflection_get_type_checked (ass->image, ass->image, ud->info, ud->ignore_case, &type_resolve, &probe_type_error);
6441 mono_error_cleanup (&probe_type_error);
6442 if (t) {
6443 g_ptr_array_add (ud->res_classes, mono_type_get_class (t));
6444 g_ptr_array_add (ud->res_domains, domain);
6448 mono_domain_assemblies_unlock (domain);
6451 typedef struct {
6452 gboolean ignore_case;
6453 char *basename;
6454 GPtrArray *res_classes;
6455 GPtrArray *res_domains;
6456 } GetTypesForSourceFileArgs;
6458 static void
6459 get_types_for_source_file (gpointer key, gpointer value, gpointer user_data)
6461 GHashTableIter iter;
6462 GSList *class_list = NULL;
6463 MonoClass *klass = NULL;
6464 GPtrArray *files = NULL;
6466 GetTypesForSourceFileArgs *ud = (GetTypesForSourceFileArgs*)user_data;
6467 MonoDomain *domain = (MonoDomain*)key;
6469 AgentDomainInfo *info = (AgentDomainInfo *)domain_jit_info (domain)->agent_info;
6471 /* Update 'source_file_to_class' cache */
6472 g_hash_table_iter_init (&iter, info->loaded_classes);
6473 while (g_hash_table_iter_next (&iter, NULL, (void**)&klass)) {
6474 if (!g_hash_table_lookup (info->source_files, klass)) {
6475 files = get_source_files_for_type (klass);
6476 g_hash_table_insert (info->source_files, klass, files);
6478 for (int i = 0; i < files->len; ++i) {
6479 char *s = (char *)g_ptr_array_index (files, i);
6480 char *s2 = dbg_path_get_basename (s);
6481 char *s3;
6483 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class, s2);
6484 if (!class_list) {
6485 class_list = g_slist_prepend (class_list, klass);
6486 g_hash_table_insert (info->source_file_to_class, g_strdup (s2), class_list);
6487 } else {
6488 class_list = g_slist_prepend (class_list, klass);
6489 g_hash_table_insert (info->source_file_to_class, s2, class_list);
6492 /* The _ignorecase hash contains the lowercase path */
6493 s3 = strdup_tolower (s2);
6494 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class_ignorecase, s3);
6495 if (!class_list) {
6496 class_list = g_slist_prepend (class_list, klass);
6497 g_hash_table_insert (info->source_file_to_class_ignorecase, g_strdup (s3), class_list);
6498 } else {
6499 class_list = g_slist_prepend (class_list, klass);
6500 g_hash_table_insert (info->source_file_to_class_ignorecase, s3, class_list);
6503 g_free (s2);
6504 g_free (s3);
6509 if (ud->ignore_case) {
6510 char *s;
6512 s = strdup_tolower (ud->basename);
6513 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class_ignorecase, s);
6514 g_free (s);
6515 } else {
6516 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class, ud->basename);
6519 for (GSList *l = class_list; l; l = l->next) {
6520 klass = (MonoClass *)l->data;
6522 g_ptr_array_add (ud->res_classes, klass);
6523 g_ptr_array_add (ud->res_domains, domain);
6527 static ErrorCode
6528 vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
6530 switch (command) {
6531 case CMD_VM_VERSION: {
6532 char *build_info, *version;
6534 build_info = mono_get_runtime_build_info ();
6535 version = g_strdup_printf ("mono %s", build_info);
6537 buffer_add_string (buf, version); /* vm version */
6538 buffer_add_int (buf, MAJOR_VERSION);
6539 buffer_add_int (buf, MINOR_VERSION);
6540 g_free (build_info);
6541 g_free (version);
6542 break;
6544 case CMD_VM_SET_PROTOCOL_VERSION: {
6545 major_version = decode_int (p, &p, end);
6546 minor_version = decode_int (p, &p, end);
6547 protocol_version_set = TRUE;
6548 DEBUG_PRINTF (1, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION, MINOR_VERSION, major_version, minor_version);
6549 break;
6551 case CMD_VM_ALL_THREADS: {
6552 // FIXME: Domains
6553 mono_loader_lock ();
6554 buffer_add_int (buf, mono_g_hash_table_size (tid_to_thread_obj));
6555 mono_g_hash_table_foreach (tid_to_thread_obj, add_thread, buf);
6556 mono_loader_unlock ();
6557 break;
6559 case CMD_VM_SUSPEND:
6560 suspend_vm ();
6561 wait_for_suspend ();
6562 break;
6563 case CMD_VM_RESUME:
6564 if (suspend_count == 0)
6565 return ERR_NOT_SUSPENDED;
6566 resume_vm ();
6567 clear_suspended_objs ();
6568 break;
6569 case CMD_VM_DISPOSE:
6570 /* Clear all event requests */
6571 mono_loader_lock ();
6572 while (event_requests->len > 0) {
6573 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, 0);
6575 clear_event_request (req->id, req->event_kind);
6577 mono_loader_unlock ();
6579 while (suspend_count > 0)
6580 resume_vm ();
6581 disconnected = TRUE;
6582 vm_start_event_sent = FALSE;
6583 break;
6584 case CMD_VM_EXIT: {
6585 MonoInternalThread *thread;
6586 DebuggerTlsData *tls;
6587 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6588 MonoClass *env_class;
6589 #endif
6590 MonoMethod *exit_method = NULL;
6591 gpointer *args;
6592 int exit_code;
6594 exit_code = decode_int (p, &p, end);
6596 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
6598 /* Have to send a reply before exiting */
6599 send_reply_packet (id, 0, buf);
6601 /* Clear all event requests */
6602 mono_loader_lock ();
6603 while (event_requests->len > 0) {
6604 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, 0);
6606 clear_event_request (req->id, req->event_kind);
6608 mono_loader_unlock ();
6611 * The JDWP documentation says that the shutdown is not orderly. It doesn't
6612 * specify whenever a VM_DEATH event is sent. We currently do an orderly
6613 * shutdown by hijacking a thread to execute Environment.Exit (). This is
6614 * better than doing the shutdown ourselves, since it avoids various races.
6617 suspend_vm ();
6618 wait_for_suspend ();
6620 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6621 env_class = mono_class_try_load_from_name (mono_defaults.corlib, "System", "Environment");
6622 if (env_class) {
6623 ERROR_DECL (error);
6624 exit_method = mono_class_get_method_from_name_checked (env_class, "Exit", 1, 0, error);
6625 mono_error_assert_ok (error);
6627 #endif
6629 mono_loader_lock ();
6630 thread = (MonoInternalThread *)mono_g_hash_table_find (tid_to_thread, is_really_suspended, NULL);
6631 mono_loader_unlock ();
6633 if (thread && exit_method) {
6634 mono_loader_lock ();
6635 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
6636 mono_loader_unlock ();
6638 args = g_new0 (gpointer, 1);
6639 args [0] = g_malloc (sizeof (int));
6640 *(int*)(args [0]) = exit_code;
6642 tls->pending_invoke = g_new0 (InvokeData, 1);
6643 tls->pending_invoke->method = exit_method;
6644 tls->pending_invoke->args = args;
6645 tls->pending_invoke->nmethods = 1;
6647 while (suspend_count > 0)
6648 resume_vm ();
6649 } else {
6651 * No thread found, do it ourselves.
6652 * FIXME: This can race with normal shutdown etc.
6654 while (suspend_count > 0)
6655 resume_vm ();
6657 if (!mono_runtime_try_shutdown ())
6658 break;
6660 mono_environment_exitcode_set (exit_code);
6662 /* Suspend all managed threads since the runtime is going away */
6663 DEBUG_PRINTF (1, "Suspending all threads...\n");
6664 mono_thread_suspend_all_other_threads ();
6665 DEBUG_PRINTF (1, "Shutting down the runtime...\n");
6666 mono_runtime_quit ();
6667 transport_close2 ();
6668 DEBUG_PRINTF (1, "Exiting...\n");
6670 exit (exit_code);
6672 break;
6674 case CMD_VM_INVOKE_METHOD:
6675 case CMD_VM_INVOKE_METHODS: {
6676 int objid = decode_objid (p, &p, end);
6677 MonoThread *thread;
6678 DebuggerTlsData *tls;
6679 int i, count, flags, nmethods;
6680 ErrorCode err;
6682 err = get_object (objid, (MonoObject**)&thread);
6683 if (err != ERR_NONE)
6684 return err;
6686 flags = decode_int (p, &p, end);
6688 if (command == CMD_VM_INVOKE_METHODS)
6689 nmethods = decode_int (p, &p, end);
6690 else
6691 nmethods = 1;
6693 // Wait for suspending if it already started
6694 if (suspend_count)
6695 wait_for_suspend ();
6696 if (!is_suspended ())
6697 return ERR_NOT_SUSPENDED;
6699 mono_loader_lock ();
6700 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL (thread));
6701 mono_loader_unlock ();
6702 g_assert (tls);
6704 if (!tls->really_suspended)
6705 /* The thread is still running native code, can't do invokes */
6706 return ERR_NOT_SUSPENDED;
6709 * Store the invoke data into tls, the thread will execute it after it is
6710 * resumed.
6712 if (tls->pending_invoke)
6713 return ERR_NOT_SUSPENDED;
6714 tls->pending_invoke = g_new0 (InvokeData, 1);
6715 tls->pending_invoke->id = id;
6716 tls->pending_invoke->flags = flags;
6717 tls->pending_invoke->p = (guint8 *)g_malloc (end - p);
6718 memcpy (tls->pending_invoke->p, p, end - p);
6719 tls->pending_invoke->endp = tls->pending_invoke->p + (end - p);
6720 tls->pending_invoke->suspend_count = suspend_count;
6721 tls->pending_invoke->nmethods = nmethods;
6723 if (flags & INVOKE_FLAG_SINGLE_THREADED) {
6724 resume_thread (THREAD_TO_INTERNAL (thread));
6726 else {
6727 count = suspend_count;
6728 for (i = 0; i < count; ++i)
6729 resume_vm ();
6731 break;
6733 case CMD_VM_ABORT_INVOKE: {
6734 int objid = decode_objid (p, &p, end);
6735 MonoThread *thread;
6736 DebuggerTlsData *tls;
6737 int invoke_id;
6738 ErrorCode err;
6740 err = get_object (objid, (MonoObject**)&thread);
6741 if (err != ERR_NONE)
6742 return err;
6744 invoke_id = decode_int (p, &p, end);
6746 mono_loader_lock ();
6747 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL (thread));
6748 g_assert (tls);
6750 if (tls->abort_requested) {
6751 DEBUG_PRINTF (1, "Abort already requested.\n");
6752 mono_loader_unlock ();
6753 break;
6757 * Check whether we're still inside the mono_runtime_invoke_checked() and that it's
6758 * actually the correct invocation.
6760 * Careful, we do not stop the thread that's doing the invocation, so we can't
6761 * inspect its stack. However, invoke_method() also acquires the loader lock
6762 * when it's done, so we're safe here.
6766 if (!tls->invoke || (tls->invoke->id != invoke_id)) {
6767 mono_loader_unlock ();
6768 return ERR_NO_INVOCATION;
6771 tls->abort_requested = TRUE;
6773 mono_thread_internal_abort (THREAD_TO_INTERNAL (thread), FALSE);
6774 mono_loader_unlock ();
6775 break;
6778 case CMD_VM_SET_KEEPALIVE: {
6779 int timeout = decode_int (p, &p, end);
6780 agent_config.keepalive = timeout;
6781 // FIXME:
6782 #ifndef DISABLE_SOCKET_TRANSPORT
6783 set_keepalive ();
6784 #else
6785 NOT_IMPLEMENTED;
6786 #endif
6787 break;
6789 case CMD_VM_GET_TYPES_FOR_SOURCE_FILE: {
6790 int i;
6791 char *fname, *basename;
6792 gboolean ignore_case;
6793 GPtrArray *res_classes, *res_domains;
6795 fname = decode_string (p, &p, end);
6796 ignore_case = decode_byte (p, &p, end);
6798 basename = dbg_path_get_basename (fname);
6800 res_classes = g_ptr_array_new ();
6801 res_domains = g_ptr_array_new ();
6803 mono_loader_lock ();
6804 GetTypesForSourceFileArgs args;
6805 memset (&args, 0, sizeof (args));
6806 args.ignore_case = ignore_case;
6807 args.basename = basename;
6808 args.res_classes = res_classes;
6809 args.res_domains = res_domains;
6810 mono_de_foreach_domain (get_types_for_source_file, &args);
6811 mono_loader_unlock ();
6813 g_free (fname);
6814 g_free (basename);
6816 buffer_add_int (buf, res_classes->len);
6817 for (i = 0; i < res_classes->len; ++i)
6818 buffer_add_typeid (buf, (MonoDomain *)g_ptr_array_index (res_domains, i), (MonoClass *)g_ptr_array_index (res_classes, i));
6819 g_ptr_array_free (res_classes, TRUE);
6820 g_ptr_array_free (res_domains, TRUE);
6821 break;
6823 case CMD_VM_GET_TYPES: {
6824 ERROR_DECL (error);
6825 int i;
6826 char *name;
6827 gboolean ignore_case;
6828 GPtrArray *res_classes, *res_domains;
6829 MonoTypeNameParse info;
6831 name = decode_string (p, &p, end);
6832 ignore_case = decode_byte (p, &p, end);
6834 if (!mono_reflection_parse_type_checked (name, &info, error)) {
6835 mono_error_cleanup (error);
6836 g_free (name);
6837 mono_reflection_free_type_info (&info);
6838 return ERR_INVALID_ARGUMENT;
6841 res_classes = g_ptr_array_new ();
6842 res_domains = g_ptr_array_new ();
6844 mono_loader_lock ();
6846 GetTypesArgs args;
6847 memset (&args, 0, sizeof (args));
6848 args.info = &info;
6849 args.ignore_case = ignore_case;
6850 args.res_classes = res_classes;
6851 args.res_domains = res_domains;
6853 mono_de_foreach_domain (get_types, &args);
6855 mono_loader_unlock ();
6857 g_free (name);
6858 mono_reflection_free_type_info (&info);
6860 buffer_add_int (buf, res_classes->len);
6861 for (i = 0; i < res_classes->len; ++i)
6862 buffer_add_typeid (buf, (MonoDomain *)g_ptr_array_index (res_domains, i), (MonoClass *)g_ptr_array_index (res_classes, i));
6863 g_ptr_array_free (res_classes, TRUE);
6864 g_ptr_array_free (res_domains, TRUE);
6865 break;
6867 case CMD_VM_START_BUFFERING:
6868 case CMD_VM_STOP_BUFFERING:
6869 /* Handled in the main loop */
6870 break;
6871 default:
6872 return ERR_NOT_IMPLEMENTED;
6875 return ERR_NONE;
6878 static ErrorCode
6879 event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
6881 ErrorCode err;
6882 ERROR_DECL (error);
6884 switch (command) {
6885 case CMD_EVENT_REQUEST_SET: {
6886 EventRequest *req;
6887 int i, event_kind, suspend_policy, nmodifiers;
6888 ModifierKind mod;
6889 MonoMethod *method;
6890 long location = 0;
6891 MonoThread *step_thread;
6892 int step_thread_id = 0;
6893 StepDepth depth = STEP_DEPTH_INTO;
6894 StepSize size = STEP_SIZE_MIN;
6895 StepFilter filter = STEP_FILTER_NONE;
6896 MonoDomain *domain;
6897 Modifier *modifier;
6899 event_kind = decode_byte (p, &p, end);
6900 suspend_policy = decode_byte (p, &p, end);
6901 nmodifiers = decode_byte (p, &p, end);
6903 req = (EventRequest *)g_malloc0 (sizeof (EventRequest) + (nmodifiers * sizeof (Modifier)));
6904 req->id = mono_atomic_inc_i32 (&event_request_id);
6905 req->event_kind = event_kind;
6906 req->suspend_policy = suspend_policy;
6907 req->nmodifiers = nmodifiers;
6909 method = NULL;
6910 for (i = 0; i < nmodifiers; ++i) {
6911 mod = (ModifierKind)decode_byte (p, &p, end);
6913 req->modifiers [i].kind = mod;
6914 if (mod == MOD_KIND_COUNT) {
6915 req->modifiers [i].data.count = decode_int (p, &p, end);
6916 } else if (mod == MOD_KIND_LOCATION_ONLY) {
6917 method = decode_methodid (p, &p, end, &domain, &err);
6918 if (err != ERR_NONE)
6919 return err;
6920 location = decode_long (p, &p, end);
6921 } else if (mod == MOD_KIND_STEP) {
6922 step_thread_id = decode_id (p, &p, end);
6923 size = (StepSize)decode_int (p, &p, end);
6924 depth = (StepDepth)decode_int (p, &p, end);
6925 if (CHECK_PROTOCOL_VERSION (2, 16))
6926 filter = (StepFilter)decode_int (p, &p, end);
6927 req->modifiers [i].data.filter = filter;
6928 if (!CHECK_PROTOCOL_VERSION (2, 26) && (req->modifiers [i].data.filter & STEP_FILTER_DEBUGGER_HIDDEN))
6929 /* Treat STEP_THOUGH the same as HIDDEN */
6930 req->modifiers [i].data.filter = (StepFilter)(req->modifiers [i].data.filter | STEP_FILTER_DEBUGGER_STEP_THROUGH);
6931 } else if (mod == MOD_KIND_THREAD_ONLY) {
6932 int id = decode_id (p, &p, end);
6934 err = get_object (id, (MonoObject**)&req->modifiers [i].data.thread);
6935 if (err != ERR_NONE) {
6936 g_free (req);
6937 return err;
6939 } else if (mod == MOD_KIND_EXCEPTION_ONLY) {
6940 MonoClass *exc_class = decode_typeid (p, &p, end, &domain, &err);
6942 if (err != ERR_NONE)
6943 return err;
6944 req->modifiers [i].caught = decode_byte (p, &p, end);
6945 req->modifiers [i].uncaught = decode_byte (p, &p, end);
6946 if (CHECK_PROTOCOL_VERSION (2, 25))
6947 req->modifiers [i].subclasses = decode_byte (p, &p, end);
6948 else
6949 req->modifiers [i].subclasses = TRUE;
6950 DEBUG_PRINTF (1, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class ? m_class_get_name (exc_class) : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : "");
6951 if (exc_class) {
6952 req->modifiers [i].data.exc_class = exc_class;
6954 if (!mono_class_is_assignable_from_internal (mono_defaults.exception_class, exc_class)) {
6955 g_free (req);
6956 return ERR_INVALID_ARGUMENT;
6959 } else if (mod == MOD_KIND_ASSEMBLY_ONLY) {
6960 int n = decode_int (p, &p, end);
6961 int j;
6963 // +1 because we don't know length and we use last element to check for end
6964 req->modifiers [i].data.assemblies = g_new0 (MonoAssembly*, n + 1);
6965 for (j = 0; j < n; ++j) {
6966 req->modifiers [i].data.assemblies [j] = decode_assemblyid (p, &p, end, &domain, &err);
6967 if (err != ERR_NONE) {
6968 g_free (req->modifiers [i].data.assemblies);
6969 return err;
6972 } else if (mod == MOD_KIND_SOURCE_FILE_ONLY) {
6973 int n = decode_int (p, &p, end);
6974 int j;
6976 modifier = &req->modifiers [i];
6977 modifier->data.source_files = g_hash_table_new (g_str_hash, g_str_equal);
6978 for (j = 0; j < n; ++j) {
6979 char *s = decode_string (p, &p, end);
6980 char *s2;
6982 if (s) {
6983 s2 = strdup_tolower (s);
6984 g_hash_table_insert (modifier->data.source_files, s2, s2);
6985 g_free (s);
6988 } else if (mod == MOD_KIND_TYPE_NAME_ONLY) {
6989 int n = decode_int (p, &p, end);
6990 int j;
6992 modifier = &req->modifiers [i];
6993 modifier->data.type_names = g_hash_table_new (g_str_hash, g_str_equal);
6994 for (j = 0; j < n; ++j) {
6995 char *s = decode_string (p, &p, end);
6997 if (s)
6998 g_hash_table_insert (modifier->data.type_names, s, s);
7000 } else {
7001 g_free (req);
7002 return ERR_NOT_IMPLEMENTED;
7006 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
7007 g_assert (method);
7009 req->info = mono_de_set_breakpoint (method, location, req, error);
7010 if (!mono_error_ok (error)) {
7011 g_free (req);
7012 DEBUG_PRINTF (1, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (error));
7013 mono_error_cleanup (error);
7014 return ERR_NO_SEQ_POINT_AT_IL_OFFSET;
7016 } else if (req->event_kind == EVENT_KIND_STEP) {
7017 g_assert (step_thread_id);
7019 err = get_object (step_thread_id, (MonoObject**)&step_thread);
7020 if (err != ERR_NONE) {
7021 g_free (req);
7022 return err;
7025 err = (ErrorCode)mono_de_ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, filter, req);
7026 if (err != ERR_NONE) {
7027 g_free (req);
7028 return err;
7030 } else if (req->event_kind == EVENT_KIND_METHOD_ENTRY) {
7031 req->info = mono_de_set_breakpoint (NULL, METHOD_ENTRY_IL_OFFSET, req, NULL);
7032 } else if (req->event_kind == EVENT_KIND_METHOD_EXIT) {
7033 req->info = mono_de_set_breakpoint (NULL, METHOD_EXIT_IL_OFFSET, req, NULL);
7034 } else if (req->event_kind == EVENT_KIND_EXCEPTION) {
7035 } else if (req->event_kind == EVENT_KIND_TYPE_LOAD) {
7036 } else {
7037 if (req->nmodifiers) {
7038 g_free (req);
7039 return ERR_NOT_IMPLEMENTED;
7043 mono_loader_lock ();
7044 g_ptr_array_add (event_requests, req);
7046 if (agent_config.defer) {
7047 /* Transmit cached data to the client on receipt of the event request */
7048 switch (req->event_kind) {
7049 case EVENT_KIND_APPDOMAIN_CREATE:
7050 /* Emit load events for currently loaded domains */
7051 mono_de_foreach_domain (emit_appdomain_load, NULL);
7052 break;
7053 case EVENT_KIND_ASSEMBLY_LOAD:
7054 /* Emit load events for currently loaded assemblies */
7055 mono_domain_foreach (send_assemblies_for_domain, NULL);
7056 break;
7057 case EVENT_KIND_THREAD_START:
7058 /* Emit start events for currently started threads */
7059 mono_g_hash_table_foreach (tid_to_thread, emit_thread_start, NULL);
7060 break;
7061 case EVENT_KIND_TYPE_LOAD:
7062 /* Emit type load events for currently loaded types */
7063 mono_domain_foreach (send_types_for_domain, NULL);
7064 break;
7065 default:
7066 break;
7069 mono_loader_unlock ();
7071 buffer_add_int (buf, req->id);
7072 break;
7074 case CMD_EVENT_REQUEST_CLEAR: {
7075 int etype = decode_byte (p, &p, end);
7076 int req_id = decode_int (p, &p, end);
7078 // FIXME: Make a faster mapping from req_id to request
7079 mono_loader_lock ();
7080 clear_event_request (req_id, etype);
7081 mono_loader_unlock ();
7082 break;
7084 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS: {
7085 int i;
7087 mono_loader_lock ();
7088 i = 0;
7089 while (i < event_requests->len) {
7090 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
7092 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
7093 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
7095 g_ptr_array_remove_index_fast (event_requests, i);
7096 g_free (req);
7097 } else {
7098 i ++;
7101 mono_loader_unlock ();
7102 break;
7104 default:
7105 return ERR_NOT_IMPLEMENTED;
7108 return ERR_NONE;
7111 static ErrorCode
7112 domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7114 ErrorCode err;
7115 MonoDomain *domain;
7117 switch (command) {
7118 case CMD_APPDOMAIN_GET_ROOT_DOMAIN: {
7119 buffer_add_domainid (buf, mono_get_root_domain ());
7120 break;
7122 case CMD_APPDOMAIN_GET_FRIENDLY_NAME: {
7123 domain = decode_domainid (p, &p, end, NULL, &err);
7124 if (err != ERR_NONE)
7125 return err;
7126 buffer_add_string (buf, domain->friendly_name);
7127 break;
7129 case CMD_APPDOMAIN_GET_ASSEMBLIES: {
7130 GSList *tmp;
7131 MonoAssembly *ass;
7132 int count;
7134 domain = decode_domainid (p, &p, end, NULL, &err);
7135 if (err != ERR_NONE)
7136 return err;
7137 mono_loader_lock ();
7138 count = 0;
7139 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
7140 count ++;
7142 buffer_add_int (buf, count);
7143 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
7144 ass = (MonoAssembly *)tmp->data;
7145 buffer_add_assemblyid (buf, domain, ass);
7147 mono_loader_unlock ();
7148 break;
7150 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY: {
7151 domain = decode_domainid (p, &p, end, NULL, &err);
7152 if (err != ERR_NONE)
7153 return err;
7155 buffer_add_assemblyid (buf, domain, domain->entry_assembly);
7156 break;
7158 case CMD_APPDOMAIN_GET_CORLIB: {
7159 domain = decode_domainid (p, &p, end, NULL, &err);
7160 if (err != ERR_NONE)
7161 return err;
7163 buffer_add_assemblyid (buf, domain, m_class_get_image (domain->domain->mbr.obj.vtable->klass)->assembly);
7164 break;
7166 case CMD_APPDOMAIN_CREATE_STRING: {
7167 char *s;
7168 MonoString *o;
7169 ERROR_DECL (error);
7171 domain = decode_domainid (p, &p, end, NULL, &err);
7172 if (err != ERR_NONE)
7173 return err;
7174 s = decode_string (p, &p, end);
7176 o = mono_string_new_checked (domain, s, error);
7177 if (!is_ok (error)) {
7178 DEBUG_PRINTF (1, "[dbg] Failed to allocate String object '%s': %s\n", s, mono_error_get_message (error));
7179 mono_error_cleanup (error);
7180 return ERR_INVALID_OBJECT;
7182 buffer_add_objid (buf, (MonoObject*)o);
7183 break;
7185 case CMD_APPDOMAIN_CREATE_BOXED_VALUE: {
7186 ERROR_DECL (error);
7187 MonoClass *klass;
7188 MonoDomain *domain2;
7189 MonoObject *o;
7191 domain = decode_domainid (p, &p, end, NULL, &err);
7192 if (err != ERR_NONE)
7193 return err;
7194 klass = decode_typeid (p, &p, end, &domain2, &err);
7195 if (err != ERR_NONE)
7196 return err;
7198 // FIXME:
7199 g_assert (domain == domain2);
7201 o = mono_object_new_checked (domain, klass, error);
7202 mono_error_assert_ok (error);
7204 err = decode_value (m_class_get_byval_arg (klass), domain, (guint8 *)mono_object_unbox_internal (o), p, &p, end);
7205 if (err != ERR_NONE)
7206 return err;
7208 buffer_add_objid (buf, o);
7209 break;
7211 default:
7212 return ERR_NOT_IMPLEMENTED;
7215 return ERR_NONE;
7218 static ErrorCode
7219 get_assembly_object_command (MonoDomain *domain, MonoAssembly *ass, Buffer *buf, MonoError *error)
7221 HANDLE_FUNCTION_ENTER();
7222 ErrorCode err = ERR_NONE;
7223 error_init (error);
7224 MonoReflectionAssemblyHandle o = mono_assembly_get_object_handle (domain, ass, error);
7225 if (MONO_HANDLE_IS_NULL (o)) {
7226 err = ERR_INVALID_OBJECT;
7227 goto leave;
7229 buffer_add_objid (buf, MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, o)));
7230 leave:
7231 HANDLE_FUNCTION_RETURN_VAL (err);
7235 static ErrorCode
7236 assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7238 ErrorCode err;
7239 MonoAssembly *ass;
7240 MonoDomain *domain;
7242 ass = decode_assemblyid (p, &p, end, &domain, &err);
7243 if (err != ERR_NONE)
7244 return err;
7246 switch (command) {
7247 case CMD_ASSEMBLY_GET_LOCATION: {
7248 buffer_add_string (buf, mono_image_get_filename (ass->image));
7249 break;
7251 case CMD_ASSEMBLY_GET_ENTRY_POINT: {
7252 guint32 token;
7253 MonoMethod *m;
7255 if (ass->image->dynamic) {
7256 buffer_add_id (buf, 0);
7257 } else {
7258 token = mono_image_get_entry_point (ass->image);
7259 if (token == 0) {
7260 buffer_add_id (buf, 0);
7261 } else {
7262 ERROR_DECL (error);
7263 m = mono_get_method_checked (ass->image, token, NULL, NULL, error);
7264 if (!m)
7265 mono_error_cleanup (error); /* FIXME don't swallow the error */
7266 buffer_add_methodid (buf, domain, m);
7269 break;
7271 case CMD_ASSEMBLY_GET_MANIFEST_MODULE: {
7272 buffer_add_moduleid (buf, domain, ass->image);
7273 break;
7275 case CMD_ASSEMBLY_GET_OBJECT: {
7276 ERROR_DECL (error);
7277 err = get_assembly_object_command (domain, ass, buf, error);
7278 mono_error_cleanup (error);
7279 return err;
7281 case CMD_ASSEMBLY_GET_DOMAIN: {
7282 buffer_add_domainid (buf, domain);
7283 break;
7285 case CMD_ASSEMBLY_GET_TYPE: {
7286 ERROR_DECL (error);
7287 char *s = decode_string (p, &p, end);
7288 gboolean ignorecase = decode_byte (p, &p, end);
7289 MonoTypeNameParse info;
7290 MonoType *t;
7291 gboolean type_resolve, res;
7292 MonoDomain *d = mono_domain_get ();
7294 /* This is needed to be able to find referenced assemblies */
7295 res = mono_domain_set (domain, FALSE);
7296 g_assert (res);
7298 if (!mono_reflection_parse_type_checked (s, &info, error)) {
7299 mono_error_cleanup (error);
7300 t = NULL;
7301 } else {
7302 if (info.assembly.name)
7303 NOT_IMPLEMENTED;
7304 t = mono_reflection_get_type_checked (ass->image, ass->image, &info, ignorecase, &type_resolve, error);
7305 if (!is_ok (error)) {
7306 mono_error_cleanup (error); /* FIXME don't swallow the error */
7307 mono_reflection_free_type_info (&info);
7308 g_free (s);
7309 return ERR_INVALID_ARGUMENT;
7312 buffer_add_typeid (buf, domain, t ? mono_class_from_mono_type_internal (t) : NULL);
7313 mono_reflection_free_type_info (&info);
7314 g_free (s);
7316 mono_domain_set (d, TRUE);
7318 break;
7320 case CMD_ASSEMBLY_GET_NAME: {
7321 gchar *name;
7322 MonoAssembly *mass = ass;
7324 name = g_strdup_printf (
7325 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
7326 mass->aname.name,
7327 mass->aname.major, mass->aname.minor, mass->aname.build, mass->aname.revision,
7328 mass->aname.culture && *mass->aname.culture? mass->aname.culture: "neutral",
7329 mass->aname.public_key_token [0] ? (char *)mass->aname.public_key_token : "null",
7330 (mass->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
7332 buffer_add_string (buf, name);
7333 g_free (name);
7334 break;
7336 case CMD_ASSEMBLY_GET_METADATA_BLOB: {
7337 MonoImage* image = ass->image;
7338 if (ass->dynamic) {
7339 return ERR_NOT_IMPLEMENTED;
7341 buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
7342 break;
7344 case CMD_ASSEMBLY_GET_IS_DYNAMIC: {
7345 buffer_add_byte (buf, ass->dynamic);
7346 break;
7348 case CMD_ASSEMBLY_GET_PDB_BLOB: {
7349 MonoImage* image = ass->image;
7350 MonoDebugHandle* handle = mono_debug_get_handle (image);
7351 if (!handle) {
7352 return ERR_INVALID_ARGUMENT;
7354 MonoPPDBFile* ppdb = handle->ppdb;
7355 if (ppdb) {
7356 image = mono_ppdb_get_image (ppdb);
7357 buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
7358 } else {
7359 buffer_add_byte_array (buf, NULL, 0);
7361 break;
7363 case CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN: {
7364 if (ass->dynamic) {
7365 return ERR_NOT_IMPLEMENTED;
7367 guint32 token = decode_int (p, &p, end);
7368 ERROR_DECL (error);
7369 error_init (error);
7370 MonoClass* mono_class = mono_class_get_checked (ass->image, token, error);
7371 if (!is_ok (error)) {
7372 mono_error_cleanup (error);
7373 return ERR_INVALID_ARGUMENT;
7375 buffer_add_typeid (buf, domain, mono_class);
7376 mono_error_cleanup (error);
7377 break;
7379 case CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN: {
7380 if (ass->dynamic) {
7381 return ERR_NOT_IMPLEMENTED;
7383 guint32 token = decode_int (p, &p, end);
7384 ERROR_DECL (error);
7385 error_init (error);
7386 MonoMethod* mono_method = mono_get_method_checked (ass->image, token, NULL, NULL, error);
7387 if (!is_ok (error)) {
7388 mono_error_cleanup (error);
7389 return ERR_INVALID_ARGUMENT;
7391 buffer_add_methodid (buf, domain, mono_method);
7392 mono_error_cleanup (error);
7393 break;
7395 default:
7396 return ERR_NOT_IMPLEMENTED;
7399 return ERR_NONE;
7402 static ErrorCode
7403 module_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7405 ErrorCode err;
7406 MonoDomain *domain;
7408 switch (command) {
7409 case CMD_MODULE_GET_INFO: {
7410 MonoImage *image = decode_moduleid (p, &p, end, &domain, &err);
7411 char *basename, *sourcelink = NULL;
7413 if (CHECK_PROTOCOL_VERSION (2, 48))
7414 sourcelink = mono_debug_image_get_sourcelink (image);
7416 basename = g_path_get_basename (image->name);
7417 buffer_add_string (buf, basename); // name
7418 buffer_add_string (buf, image->module_name); // scopename
7419 buffer_add_string (buf, image->name); // fqname
7420 buffer_add_string (buf, mono_image_get_guid (image)); // guid
7421 buffer_add_assemblyid (buf, domain, image->assembly); // assembly
7422 if (CHECK_PROTOCOL_VERSION (2, 48))
7423 buffer_add_string (buf, sourcelink);
7424 g_free (basename);
7425 g_free (sourcelink);
7426 break;
7428 default:
7429 return ERR_NOT_IMPLEMENTED;
7432 return ERR_NONE;
7435 static ErrorCode
7436 field_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7438 ErrorCode err;
7439 MonoDomain *domain;
7441 switch (command) {
7442 case CMD_FIELD_GET_INFO: {
7443 MonoClassField *f = decode_fieldid (p, &p, end, &domain, &err);
7445 buffer_add_string (buf, f->name);
7446 buffer_add_typeid (buf, domain, f->parent);
7447 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (f->type));
7448 buffer_add_int (buf, f->type->attrs);
7449 break;
7451 default:
7452 return ERR_NOT_IMPLEMENTED;
7455 return ERR_NONE;
7458 static void
7459 buffer_add_cattr_arg (Buffer *buf, MonoType *t, MonoDomain *domain, MonoObject *val)
7461 if (val && val->vtable->klass == mono_defaults.runtimetype_class) {
7462 /* Special case these so the client doesn't have to handle Type objects */
7464 buffer_add_byte (buf, VALUE_TYPE_ID_TYPE);
7465 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (((MonoReflectionType*)val)->type));
7466 } else if (MONO_TYPE_IS_REFERENCE (t))
7467 buffer_add_value (buf, t, &val, domain);
7468 else
7469 buffer_add_value (buf, t, mono_object_unbox_internal (val), domain);
7472 static ErrorCode
7473 buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass *attr_klass, MonoCustomAttrInfo *cinfo)
7475 int i, j;
7476 int nattrs = 0;
7478 if (!cinfo) {
7479 buffer_add_int (buf, 0);
7480 return ERR_NONE;
7483 for (i = 0; i < cinfo->num_attrs; ++i) {
7484 if (!attr_klass || mono_class_has_parent (cinfo->attrs [i].ctor->klass, attr_klass))
7485 nattrs ++;
7487 buffer_add_int (buf, nattrs);
7489 for (i = 0; i < cinfo->num_attrs; ++i) {
7490 MonoCustomAttrEntry *attr = &cinfo->attrs [i];
7491 if (!attr_klass || mono_class_has_parent (attr->ctor->klass, attr_klass)) {
7492 MonoArray *typed_args, *named_args;
7493 MonoType *t;
7494 CattrNamedArg *arginfo = NULL;
7495 ERROR_DECL (error);
7497 mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, error);
7498 if (!mono_error_ok (error)) {
7499 DEBUG_PRINTF (2, "[dbg] mono_reflection_create_custom_attr_data_args () failed with: '%s'\n", mono_error_get_message (error));
7500 mono_error_cleanup (error);
7501 return ERR_LOADER_ERROR;
7504 buffer_add_methodid (buf, domain, attr->ctor);
7506 /* Ctor args */
7507 if (typed_args) {
7508 buffer_add_int (buf, mono_array_length_internal (typed_args));
7509 for (j = 0; j < mono_array_length_internal (typed_args); ++j) {
7510 MonoObject *val = mono_array_get_internal (typed_args, MonoObject*, j);
7512 t = mono_method_signature_internal (attr->ctor)->params [j];
7514 buffer_add_cattr_arg (buf, t, domain, val);
7516 } else {
7517 buffer_add_int (buf, 0);
7520 /* Named args */
7521 if (named_args) {
7522 buffer_add_int (buf, mono_array_length_internal (named_args));
7524 for (j = 0; j < mono_array_length_internal (named_args); ++j) {
7525 MonoObject *val = mono_array_get_internal (named_args, MonoObject*, j);
7527 if (arginfo [j].prop) {
7528 buffer_add_byte (buf, 0x54);
7529 buffer_add_propertyid (buf, domain, arginfo [j].prop);
7530 } else if (arginfo [j].field) {
7531 buffer_add_byte (buf, 0x53);
7532 buffer_add_fieldid (buf, domain, arginfo [j].field);
7533 } else {
7534 g_assert_not_reached ();
7537 buffer_add_cattr_arg (buf, arginfo [j].type, domain, val);
7539 } else {
7540 buffer_add_int (buf, 0);
7542 g_free (arginfo);
7546 return ERR_NONE;
7549 /* FIXME: Code duplication with icall.c */
7550 static void
7551 collect_interfaces (MonoClass *klass, GHashTable *ifaces, MonoError *error)
7553 int i;
7554 MonoClass *ic;
7556 mono_class_setup_interfaces (klass, error);
7557 if (!mono_error_ok (error))
7558 return;
7560 int klass_interface_count = m_class_get_interface_count (klass);
7561 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
7562 for (i = 0; i < klass_interface_count; i++) {
7563 ic = klass_interfaces [i];
7564 g_hash_table_insert (ifaces, ic, ic);
7566 collect_interfaces (ic, ifaces, error);
7567 if (!mono_error_ok (error))
7568 return;
7572 static ErrorCode
7573 type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf)
7575 ERROR_DECL (error);
7576 MonoClass *nested;
7577 MonoType *type;
7578 gpointer iter;
7579 guint8 b;
7580 int nnested;
7581 ErrorCode err;
7582 char *name;
7584 switch (command) {
7585 case CMD_TYPE_GET_INFO: {
7586 buffer_add_string (buf, m_class_get_name_space (klass));
7587 buffer_add_string (buf, m_class_get_name (klass));
7588 // FIXME: byref
7589 name = mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
7590 buffer_add_string (buf, name);
7591 g_free (name);
7592 buffer_add_assemblyid (buf, domain, m_class_get_image (klass)->assembly);
7593 buffer_add_moduleid (buf, domain, m_class_get_image (klass));
7594 buffer_add_typeid (buf, domain, m_class_get_parent (klass));
7595 if (m_class_get_rank (klass) || m_class_get_byval_arg (klass)->type == MONO_TYPE_PTR)
7596 buffer_add_typeid (buf, domain, m_class_get_element_class (klass));
7597 else
7598 buffer_add_id (buf, 0);
7599 buffer_add_int (buf, m_class_get_type_token (klass));
7600 buffer_add_byte (buf, m_class_get_rank (klass));
7601 buffer_add_int (buf, mono_class_get_flags (klass));
7602 b = 0;
7603 type = m_class_get_byval_arg (klass);
7604 // FIXME: Can't decide whenever a class represents a byref type
7605 if (FALSE)
7606 b |= (1 << 0);
7607 if (type->type == MONO_TYPE_PTR)
7608 b |= (1 << 1);
7609 if (!type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
7610 b |= (1 << 2);
7611 if (type->type == MONO_TYPE_VALUETYPE)
7612 b |= (1 << 3);
7613 if (m_class_is_enumtype (klass))
7614 b |= (1 << 4);
7615 if (mono_class_is_gtd (klass))
7616 b |= (1 << 5);
7617 if (mono_class_is_gtd (klass) || mono_class_is_ginst (klass))
7618 b |= (1 << 6);
7619 buffer_add_byte (buf, b);
7620 nnested = 0;
7621 iter = NULL;
7622 while ((nested = mono_class_get_nested_types (klass, &iter)))
7623 nnested ++;
7624 buffer_add_int (buf, nnested);
7625 iter = NULL;
7626 while ((nested = mono_class_get_nested_types (klass, &iter)))
7627 buffer_add_typeid (buf, domain, nested);
7628 if (CHECK_PROTOCOL_VERSION (2, 12)) {
7629 if (mono_class_is_gtd (klass))
7630 buffer_add_typeid (buf, domain, klass);
7631 else if (mono_class_is_ginst (klass))
7632 buffer_add_typeid (buf, domain, mono_class_get_generic_class (klass)->container_class);
7633 else
7634 buffer_add_id (buf, 0);
7636 if (CHECK_PROTOCOL_VERSION (2, 15)) {
7637 int count, i;
7639 if (mono_class_is_ginst (klass)) {
7640 MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
7642 count = inst->type_argc;
7643 buffer_add_int (buf, count);
7644 for (i = 0; i < count; i++)
7645 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (inst->type_argv [i]));
7646 } else if (mono_class_is_gtd (klass)) {
7647 MonoGenericContainer *container = mono_class_get_generic_container (klass);
7648 MonoClass *pklass;
7650 count = container->type_argc;
7651 buffer_add_int (buf, count);
7652 for (i = 0; i < count; i++) {
7653 pklass = mono_class_create_generic_parameter (mono_generic_container_get_param (container, i));
7654 buffer_add_typeid (buf, domain, pklass);
7656 } else {
7657 buffer_add_int (buf, 0);
7660 break;
7662 case CMD_TYPE_GET_METHODS: {
7663 int nmethods;
7664 int i = 0;
7665 gpointer iter = NULL;
7666 MonoMethod *m;
7668 mono_class_setup_methods (klass);
7670 nmethods = mono_class_num_methods (klass);
7672 buffer_add_int (buf, nmethods);
7674 while ((m = mono_class_get_methods (klass, &iter))) {
7675 buffer_add_methodid (buf, domain, m);
7676 i ++;
7678 g_assert (i == nmethods);
7679 break;
7681 case CMD_TYPE_GET_FIELDS: {
7682 int nfields;
7683 int i = 0;
7684 gpointer iter = NULL;
7685 MonoClassField *f;
7687 nfields = mono_class_num_fields (klass);
7689 buffer_add_int (buf, nfields);
7691 while ((f = mono_class_get_fields_internal (klass, &iter))) {
7692 buffer_add_fieldid (buf, domain, f);
7693 buffer_add_string (buf, f->name);
7694 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (f->type));
7695 buffer_add_int (buf, f->type->attrs);
7696 i ++;
7698 g_assert (i == nfields);
7699 break;
7701 case CMD_TYPE_GET_PROPERTIES: {
7702 int nprops;
7703 int i = 0;
7704 gpointer iter = NULL;
7705 MonoProperty *p;
7707 nprops = mono_class_num_properties (klass);
7709 buffer_add_int (buf, nprops);
7711 while ((p = mono_class_get_properties (klass, &iter))) {
7712 buffer_add_propertyid (buf, domain, p);
7713 buffer_add_string (buf, p->name);
7714 buffer_add_methodid (buf, domain, p->get);
7715 buffer_add_methodid (buf, domain, p->set);
7716 buffer_add_int (buf, p->attrs);
7717 i ++;
7719 g_assert (i == nprops);
7720 break;
7722 case CMD_TYPE_GET_CATTRS: {
7723 MonoClass *attr_klass;
7724 MonoCustomAttrInfo *cinfo;
7726 attr_klass = decode_typeid (p, &p, end, NULL, &err);
7727 /* attr_klass can be NULL */
7728 if (err != ERR_NONE)
7729 return err;
7731 cinfo = mono_custom_attrs_from_class_checked (klass, error);
7732 if (!is_ok (error)) {
7733 mono_error_cleanup (error); /* FIXME don't swallow the error message */
7734 return ERR_LOADER_ERROR;
7737 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
7738 if (err != ERR_NONE)
7739 return err;
7740 break;
7742 case CMD_TYPE_GET_FIELD_CATTRS: {
7743 MonoClass *attr_klass;
7744 MonoCustomAttrInfo *cinfo;
7745 MonoClassField *field;
7747 field = decode_fieldid (p, &p, end, NULL, &err);
7748 if (err != ERR_NONE)
7749 return err;
7750 attr_klass = decode_typeid (p, &p, end, NULL, &err);
7751 if (err != ERR_NONE)
7752 return err;
7754 cinfo = mono_custom_attrs_from_field_checked (klass, field, error);
7755 if (!is_ok (error)) {
7756 mono_error_cleanup (error); /* FIXME don't swallow the error message */
7757 return ERR_LOADER_ERROR;
7760 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
7761 if (err != ERR_NONE)
7762 return err;
7763 break;
7765 case CMD_TYPE_GET_PROPERTY_CATTRS: {
7766 MonoClass *attr_klass;
7767 MonoCustomAttrInfo *cinfo;
7768 MonoProperty *prop;
7770 prop = decode_propertyid (p, &p, end, NULL, &err);
7771 if (err != ERR_NONE)
7772 return err;
7773 attr_klass = decode_typeid (p, &p, end, NULL, &err);
7774 if (err != ERR_NONE)
7775 return err;
7777 cinfo = mono_custom_attrs_from_property_checked (klass, prop, error);
7778 if (!is_ok (error)) {
7779 mono_error_cleanup (error); /* FIXME don't swallow the error message */
7780 return ERR_LOADER_ERROR;
7783 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
7784 if (err != ERR_NONE)
7785 return err;
7786 break;
7788 case CMD_TYPE_GET_VALUES:
7789 case CMD_TYPE_GET_VALUES_2: {
7790 guint8 *val;
7791 MonoClassField *f;
7792 MonoVTable *vtable;
7793 MonoClass *k;
7794 int len, i;
7795 gboolean found;
7796 MonoThread *thread_obj;
7797 MonoInternalThread *thread = NULL;
7798 guint32 special_static_type;
7800 if (command == CMD_TYPE_GET_VALUES_2) {
7801 int objid = decode_objid (p, &p, end);
7802 ErrorCode err;
7804 err = get_object (objid, (MonoObject**)&thread_obj);
7805 if (err != ERR_NONE)
7806 return err;
7808 thread = THREAD_TO_INTERNAL (thread_obj);
7811 len = decode_int (p, &p, end);
7812 for (i = 0; i < len; ++i) {
7813 f = decode_fieldid (p, &p, end, NULL, &err);
7814 if (err != ERR_NONE)
7815 return err;
7817 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
7818 return ERR_INVALID_FIELDID;
7819 special_static_type = mono_class_field_get_special_static_type (f);
7820 if (special_static_type != SPECIAL_STATIC_NONE) {
7821 if (!(thread && special_static_type == SPECIAL_STATIC_THREAD))
7822 return ERR_INVALID_FIELDID;
7825 /* Check that the field belongs to the object */
7826 found = FALSE;
7827 for (k = klass; k; k = m_class_get_parent (k)) {
7828 if (k == f->parent) {
7829 found = TRUE;
7830 break;
7833 if (!found)
7834 return ERR_INVALID_FIELDID;
7836 vtable = mono_class_vtable_checked (domain, f->parent, error);
7837 if (!is_ok (error))
7838 return ERR_INVALID_FIELDID;
7839 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
7840 mono_field_static_get_value_for_thread (thread ? thread : mono_thread_internal_current (), vtable, f, val, error);
7841 if (!is_ok (error))
7842 return ERR_INVALID_FIELDID;
7843 buffer_add_value (buf, f->type, val, domain);
7844 g_free (val);
7846 break;
7848 case CMD_TYPE_SET_VALUES: {
7849 guint8 *val;
7850 MonoClassField *f;
7851 MonoVTable *vtable;
7852 MonoClass *k;
7853 int len, i;
7854 gboolean found;
7856 len = decode_int (p, &p, end);
7857 for (i = 0; i < len; ++i) {
7858 f = decode_fieldid (p, &p, end, NULL, &err);
7859 if (err != ERR_NONE)
7860 return err;
7862 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
7863 return ERR_INVALID_FIELDID;
7864 if (mono_class_field_is_special_static (f))
7865 return ERR_INVALID_FIELDID;
7867 /* Check that the field belongs to the object */
7868 found = FALSE;
7869 for (k = klass; k; k = m_class_get_parent (k)) {
7870 if (k == f->parent) {
7871 found = TRUE;
7872 break;
7875 if (!found)
7876 return ERR_INVALID_FIELDID;
7878 // FIXME: Check for literal/const
7880 vtable = mono_class_vtable_checked (domain, f->parent, error);
7881 if (!is_ok (error))
7882 return ERR_INVALID_FIELDID;
7883 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
7884 err = decode_value (f->type, domain, val, p, &p, end);
7885 if (err != ERR_NONE) {
7886 g_free (val);
7887 return err;
7889 if (MONO_TYPE_IS_REFERENCE (f->type))
7890 mono_field_static_set_value_internal (vtable, f, *(gpointer*)val);
7891 else
7892 mono_field_static_set_value_internal (vtable, f, val);
7893 g_free (val);
7895 break;
7897 case CMD_TYPE_GET_OBJECT: {
7898 MonoObject *o = (MonoObject*)mono_type_get_object_checked (domain, m_class_get_byval_arg (klass), error);
7899 if (!mono_error_ok (error)) {
7900 mono_error_cleanup (error);
7901 return ERR_INVALID_OBJECT;
7903 buffer_add_objid (buf, o);
7904 break;
7906 case CMD_TYPE_GET_SOURCE_FILES:
7907 case CMD_TYPE_GET_SOURCE_FILES_2: {
7908 char *source_file, *base;
7909 GPtrArray *files;
7910 int i;
7912 files = get_source_files_for_type (klass);
7914 buffer_add_int (buf, files->len);
7915 for (i = 0; i < files->len; ++i) {
7916 source_file = (char *)g_ptr_array_index (files, i);
7917 if (command == CMD_TYPE_GET_SOURCE_FILES_2) {
7918 buffer_add_string (buf, source_file);
7919 } else {
7920 base = dbg_path_get_basename (source_file);
7921 buffer_add_string (buf, base);
7922 g_free (base);
7924 g_free (source_file);
7926 g_ptr_array_free (files, TRUE);
7927 break;
7929 case CMD_TYPE_IS_ASSIGNABLE_FROM: {
7930 MonoClass *oklass = decode_typeid (p, &p, end, NULL, &err);
7932 if (err != ERR_NONE)
7933 return err;
7934 if (mono_class_is_assignable_from_internal (klass, oklass))
7935 buffer_add_byte (buf, 1);
7936 else
7937 buffer_add_byte (buf, 0);
7938 break;
7940 case CMD_TYPE_GET_METHODS_BY_NAME_FLAGS: {
7941 char *name = decode_string (p, &p, end);
7942 int i, flags = decode_int (p, &p, end);
7943 int mlisttype;
7944 if (CHECK_PROTOCOL_VERSION (2, 48))
7945 mlisttype = decode_int (p, &p, end);
7946 else
7947 mlisttype = 0; // MLISTTYPE_All
7948 ERROR_DECL (error);
7949 GPtrArray *array;
7951 error_init (error);
7952 array = mono_class_get_methods_by_name (klass, name, flags & ~BINDING_FLAGS_IGNORE_CASE, mlisttype, TRUE, error);
7953 if (!is_ok (error)) {
7954 mono_error_cleanup (error);
7955 return ERR_LOADER_ERROR;
7957 buffer_add_int (buf, array->len);
7958 for (i = 0; i < array->len; ++i) {
7959 MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, i);
7960 buffer_add_methodid (buf, domain, method);
7963 g_ptr_array_free (array, TRUE);
7964 g_free (name);
7965 break;
7967 case CMD_TYPE_GET_INTERFACES: {
7968 MonoClass *parent;
7969 GHashTable *iface_hash = g_hash_table_new (NULL, NULL);
7970 MonoClass *tclass, *iface;
7971 GHashTableIter iter;
7973 tclass = klass;
7975 for (parent = tclass; parent; parent = m_class_get_parent (parent)) {
7976 mono_class_setup_interfaces (parent, error);
7977 if (!mono_error_ok (error))
7978 return ERR_LOADER_ERROR;
7979 collect_interfaces (parent, iface_hash, error);
7980 if (!mono_error_ok (error))
7981 return ERR_LOADER_ERROR;
7984 buffer_add_int (buf, g_hash_table_size (iface_hash));
7986 g_hash_table_iter_init (&iter, iface_hash);
7987 while (g_hash_table_iter_next (&iter, NULL, (void**)&iface))
7988 buffer_add_typeid (buf, domain, iface);
7989 g_hash_table_destroy (iface_hash);
7990 break;
7992 case CMD_TYPE_GET_INTERFACE_MAP: {
7993 int tindex, ioffset;
7994 gboolean variance_used;
7995 MonoClass *iclass;
7996 int len, nmethods, i;
7997 gpointer iter;
7998 MonoMethod *method;
8000 len = decode_int (p, &p, end);
8001 mono_class_setup_vtable (klass);
8003 for (tindex = 0; tindex < len; ++tindex) {
8004 iclass = decode_typeid (p, &p, end, NULL, &err);
8005 if (err != ERR_NONE)
8006 return err;
8008 ioffset = mono_class_interface_offset_with_variance (klass, iclass, &variance_used);
8009 if (ioffset == -1)
8010 return ERR_INVALID_ARGUMENT;
8012 nmethods = mono_class_num_methods (iclass);
8013 buffer_add_int (buf, nmethods);
8015 iter = NULL;
8016 while ((method = mono_class_get_methods (iclass, &iter))) {
8017 buffer_add_methodid (buf, domain, method);
8019 MonoMethod **klass_vtable = m_class_get_vtable (klass);
8020 for (i = 0; i < nmethods; ++i)
8021 buffer_add_methodid (buf, domain, klass_vtable [i + ioffset]);
8023 break;
8025 case CMD_TYPE_IS_INITIALIZED: {
8026 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
8027 if (!is_ok (error))
8028 return ERR_LOADER_ERROR;
8030 if (vtable)
8031 buffer_add_int (buf, (vtable->initialized || vtable->init_failed) ? 1 : 0);
8032 else
8033 buffer_add_int (buf, 0);
8034 break;
8036 case CMD_TYPE_CREATE_INSTANCE: {
8037 ERROR_DECL (error);
8038 MonoObject *obj;
8040 obj = mono_object_new_checked (domain, klass, error);
8041 mono_error_assert_ok (error);
8042 buffer_add_objid (buf, obj);
8043 break;
8045 case CMD_TYPE_GET_VALUE_SIZE: {
8046 int32_t value_size;
8048 value_size = mono_class_value_size (klass, NULL);
8049 buffer_add_int (buf, value_size);
8050 break;
8052 default:
8053 return ERR_NOT_IMPLEMENTED;
8056 return ERR_NONE;
8059 static ErrorCode
8060 type_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8062 MonoClass *klass;
8063 MonoDomain *old_domain;
8064 MonoDomain *domain;
8065 ErrorCode err;
8067 klass = decode_typeid (p, &p, end, &domain, &err);
8068 if (err != ERR_NONE)
8069 return err;
8071 old_domain = mono_domain_get ();
8073 mono_domain_set (domain, TRUE);
8075 err = type_commands_internal (command, klass, domain, p, end, buf);
8077 mono_domain_set (old_domain, TRUE);
8079 return err;
8082 static ErrorCode
8083 method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf)
8085 MonoMethodHeader *header;
8086 ErrorCode err;
8088 switch (command) {
8089 case CMD_METHOD_GET_NAME: {
8090 buffer_add_string (buf, method->name);
8091 break;
8093 case CMD_METHOD_GET_DECLARING_TYPE: {
8094 buffer_add_typeid (buf, domain, method->klass);
8095 break;
8097 case CMD_METHOD_GET_DEBUG_INFO: {
8098 ERROR_DECL (error);
8099 MonoDebugMethodInfo *minfo;
8100 char *source_file;
8101 int i, j, n_il_offsets;
8102 int *source_files;
8103 GPtrArray *source_file_list;
8104 MonoSymSeqPoint *sym_seq_points;
8106 header = mono_method_get_header_checked (method, error);
8107 if (!header) {
8108 mono_error_cleanup (error); /* FIXME don't swallow the error */
8109 buffer_add_int (buf, 0);
8110 buffer_add_string (buf, "");
8111 buffer_add_int (buf, 0);
8112 break;
8115 minfo = mono_debug_lookup_method (method);
8116 if (!minfo) {
8117 buffer_add_int (buf, header->code_size);
8118 buffer_add_string (buf, "");
8119 buffer_add_int (buf, 0);
8120 mono_metadata_free_mh (header);
8121 break;
8124 mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
8125 buffer_add_int (buf, header->code_size);
8126 if (CHECK_PROTOCOL_VERSION (2, 13)) {
8127 buffer_add_int (buf, source_file_list->len);
8128 for (i = 0; i < source_file_list->len; ++i) {
8129 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
8130 buffer_add_string (buf, sinfo->source_file);
8131 if (CHECK_PROTOCOL_VERSION (2, 14)) {
8132 for (j = 0; j < 16; ++j)
8133 buffer_add_byte (buf, sinfo->hash [j]);
8136 } else {
8137 buffer_add_string (buf, source_file);
8139 buffer_add_int (buf, n_il_offsets);
8140 DEBUG_PRINTF (10, "Line number table for method %s:\n", mono_method_full_name (method, TRUE));
8141 for (i = 0; i < n_il_offsets; ++i) {
8142 MonoSymSeqPoint *sp = &sym_seq_points [i];
8143 const char *srcfile = "";
8145 if (source_files [i] != -1) {
8146 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
8147 srcfile = sinfo->source_file;
8149 DEBUG_PRINTF (10, "IL%x -> %s:%d %d %d %d\n", sp->il_offset, srcfile, sp->line, sp->column, sp->end_line, sp->end_column);
8150 buffer_add_int (buf, sp->il_offset);
8151 buffer_add_int (buf, sp->line);
8152 if (CHECK_PROTOCOL_VERSION (2, 13))
8153 buffer_add_int (buf, source_files [i]);
8154 if (CHECK_PROTOCOL_VERSION (2, 19))
8155 buffer_add_int (buf, sp->column);
8156 if (CHECK_PROTOCOL_VERSION (2, 32)) {
8157 buffer_add_int (buf, sp->end_line);
8158 buffer_add_int (buf, sp->end_column);
8161 g_free (source_file);
8162 g_free (source_files);
8163 g_free (sym_seq_points);
8164 g_ptr_array_free (source_file_list, TRUE);
8165 mono_metadata_free_mh (header);
8166 break;
8168 case CMD_METHOD_GET_PARAM_INFO: {
8169 MonoMethodSignature *sig = mono_method_signature_internal (method);
8170 guint32 i;
8171 char **names;
8173 /* FIXME: mono_class_from_mono_type_internal () and byrefs */
8175 /* FIXME: Use a smaller encoding */
8176 buffer_add_int (buf, sig->call_convention);
8177 buffer_add_int (buf, sig->param_count);
8178 buffer_add_int (buf, sig->generic_param_count);
8179 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (sig->ret));
8180 for (i = 0; i < sig->param_count; ++i) {
8181 /* FIXME: vararg */
8182 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (sig->params [i]));
8185 /* Emit parameter names */
8186 names = g_new (char *, sig->param_count);
8187 mono_method_get_param_names (method, (const char **) names);
8188 for (i = 0; i < sig->param_count; ++i)
8189 buffer_add_string (buf, names [i]);
8190 g_free (names);
8192 break;
8194 case CMD_METHOD_GET_LOCALS_INFO: {
8195 ERROR_DECL (error);
8196 int i, num_locals;
8197 MonoDebugLocalsInfo *locals;
8198 int *locals_map = NULL;
8200 header = mono_method_get_header_checked (method, error);
8201 if (!header) {
8202 mono_error_cleanup (error); /* FIXME don't swallow the error */
8203 return ERR_INVALID_ARGUMENT;
8206 locals = mono_debug_lookup_locals (method);
8207 if (!locals) {
8208 if (CHECK_PROTOCOL_VERSION (2, 43)) {
8209 /* Scopes */
8210 buffer_add_int (buf, 1);
8211 buffer_add_int (buf, 0);
8212 buffer_add_int (buf, header->code_size);
8214 buffer_add_int (buf, header->num_locals);
8215 /* Types */
8216 for (i = 0; i < header->num_locals; ++i) {
8217 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (header->locals [i]));
8219 /* Names */
8220 for (i = 0; i < header->num_locals; ++i) {
8221 char lname [128];
8222 sprintf (lname, "V_%d", i);
8223 buffer_add_string (buf, lname);
8225 /* Scopes */
8226 for (i = 0; i < header->num_locals; ++i) {
8227 buffer_add_int (buf, 0);
8228 buffer_add_int (buf, header->code_size);
8230 } else {
8231 if (CHECK_PROTOCOL_VERSION (2, 43)) {
8232 /* Scopes */
8233 buffer_add_int (buf, locals->num_blocks);
8234 int last_start = 0;
8235 for (i = 0; i < locals->num_blocks; ++i) {
8236 buffer_add_int (buf, locals->code_blocks [i].start_offset - last_start);
8237 buffer_add_int (buf, locals->code_blocks [i].end_offset - locals->code_blocks [i].start_offset);
8238 last_start = locals->code_blocks [i].start_offset;
8242 num_locals = locals->num_locals;
8243 buffer_add_int (buf, num_locals);
8245 /* Types */
8246 for (i = 0; i < num_locals; ++i) {
8247 g_assert (locals->locals [i].index < header->num_locals);
8248 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (header->locals [locals->locals [i].index]));
8250 /* Names */
8251 for (i = 0; i < num_locals; ++i)
8252 buffer_add_string (buf, locals->locals [i].name);
8253 /* Scopes */
8254 for (i = 0; i < num_locals; ++i) {
8255 if (locals->locals [i].block) {
8256 buffer_add_int (buf, locals->locals [i].block->start_offset);
8257 buffer_add_int (buf, locals->locals [i].block->end_offset);
8258 } else {
8259 buffer_add_int (buf, 0);
8260 buffer_add_int (buf, header->code_size);
8264 mono_metadata_free_mh (header);
8266 if (locals)
8267 mono_debug_free_locals (locals);
8268 g_free (locals_map);
8270 break;
8272 case CMD_METHOD_GET_INFO:
8273 buffer_add_int (buf, method->flags);
8274 buffer_add_int (buf, method->iflags);
8275 buffer_add_int (buf, method->token);
8276 if (CHECK_PROTOCOL_VERSION (2, 12)) {
8277 guint8 attrs = 0;
8278 if (method->is_generic)
8279 attrs |= (1 << 0);
8280 if (mono_method_signature_internal (method)->generic_param_count)
8281 attrs |= (1 << 1);
8282 buffer_add_byte (buf, attrs);
8283 if (method->is_generic || method->is_inflated) {
8284 MonoMethod *result;
8286 if (method->is_generic) {
8287 result = method;
8288 } else {
8289 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
8291 result = imethod->declaring;
8292 if (imethod->context.class_inst) {
8293 MonoClass *klass = ((MonoMethod *) imethod)->klass;
8294 /*Generic methods gets the context of the GTD.*/
8295 if (mono_class_get_context (klass)) {
8296 ERROR_DECL (error);
8297 result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error);
8298 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
8303 buffer_add_methodid (buf, domain, result);
8304 } else {
8305 buffer_add_id (buf, 0);
8307 if (CHECK_PROTOCOL_VERSION (2, 15)) {
8308 if (mono_method_signature_internal (method)->generic_param_count) {
8309 int count, i;
8311 if (method->is_inflated) {
8312 MonoGenericInst *inst = mono_method_get_context (method)->method_inst;
8313 if (inst) {
8314 count = inst->type_argc;
8315 buffer_add_int (buf, count);
8317 for (i = 0; i < count; i++)
8318 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (inst->type_argv [i]));
8319 } else {
8320 buffer_add_int (buf, 0);
8322 } else if (method->is_generic) {
8323 MonoGenericContainer *container = mono_method_get_generic_container (method);
8325 count = mono_method_signature_internal (method)->generic_param_count;
8326 buffer_add_int (buf, count);
8327 for (i = 0; i < count; i++) {
8328 MonoGenericParam *param = mono_generic_container_get_param (container, i);
8329 MonoClass *pklass = mono_class_create_generic_parameter (param);
8330 buffer_add_typeid (buf, domain, pklass);
8332 } else {
8333 buffer_add_int (buf, 0);
8335 } else {
8336 buffer_add_int (buf, 0);
8340 break;
8341 case CMD_METHOD_GET_BODY: {
8342 ERROR_DECL (error);
8343 int i;
8345 header = mono_method_get_header_checked (method, error);
8346 if (!header) {
8347 mono_error_cleanup (error); /* FIXME don't swallow the error */
8348 buffer_add_int (buf, 0);
8350 if (CHECK_PROTOCOL_VERSION (2, 18))
8351 buffer_add_int (buf, 0);
8352 } else {
8353 buffer_add_int (buf, header->code_size);
8354 for (i = 0; i < header->code_size; ++i)
8355 buffer_add_byte (buf, header->code [i]);
8357 if (CHECK_PROTOCOL_VERSION (2, 18)) {
8358 buffer_add_int (buf, header->num_clauses);
8359 for (i = 0; i < header->num_clauses; ++i) {
8360 MonoExceptionClause *clause = &header->clauses [i];
8362 buffer_add_int (buf, clause->flags);
8363 buffer_add_int (buf, clause->try_offset);
8364 buffer_add_int (buf, clause->try_len);
8365 buffer_add_int (buf, clause->handler_offset);
8366 buffer_add_int (buf, clause->handler_len);
8367 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
8368 buffer_add_typeid (buf, domain, clause->data.catch_class);
8369 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
8370 buffer_add_int (buf, clause->data.filter_offset);
8374 mono_metadata_free_mh (header);
8377 break;
8379 case CMD_METHOD_RESOLVE_TOKEN: {
8380 guint32 token = decode_int (p, &p, end);
8382 // FIXME: Generics
8383 switch (mono_metadata_token_code (token)) {
8384 case MONO_TOKEN_STRING: {
8385 ERROR_DECL (error);
8386 MonoString *s;
8387 char *s2;
8389 s = mono_ldstr_checked (domain, m_class_get_image (method->klass), mono_metadata_token_index (token), error);
8390 mono_error_assert_ok (error); /* FIXME don't swallow the error */
8392 s2 = mono_string_to_utf8_checked_internal (s, error);
8393 mono_error_assert_ok (error);
8395 buffer_add_byte (buf, TOKEN_TYPE_STRING);
8396 buffer_add_string (buf, s2);
8397 g_free (s2);
8398 break;
8400 default: {
8401 ERROR_DECL (error);
8402 gpointer val;
8403 MonoClass *handle_class;
8405 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8406 val = mono_method_get_wrapper_data (method, token);
8407 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, token + 1);
8409 if (handle_class == NULL) {
8410 // Can't figure out the token type
8411 buffer_add_byte (buf, TOKEN_TYPE_UNKNOWN);
8412 break;
8414 } else {
8415 val = mono_ldtoken_checked (m_class_get_image (method->klass), token, &handle_class, NULL, error);
8416 if (!val)
8417 g_error ("Could not load token due to %s", mono_error_get_message (error));
8420 if (handle_class == mono_defaults.typehandle_class) {
8421 buffer_add_byte (buf, TOKEN_TYPE_TYPE);
8422 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
8423 buffer_add_typeid (buf, domain, (MonoClass *) val);
8424 else
8425 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal ((MonoType*)val));
8426 } else if (handle_class == mono_defaults.fieldhandle_class) {
8427 buffer_add_byte (buf, TOKEN_TYPE_FIELD);
8428 buffer_add_fieldid (buf, domain, (MonoClassField *)val);
8429 } else if (handle_class == mono_defaults.methodhandle_class) {
8430 buffer_add_byte (buf, TOKEN_TYPE_METHOD);
8431 buffer_add_methodid (buf, domain, (MonoMethod *)val);
8432 } else if (handle_class == mono_defaults.string_class) {
8433 char *s;
8435 s = mono_string_to_utf8_checked_internal ((MonoString *)val, error);
8436 mono_error_assert_ok (error);
8437 buffer_add_byte (buf, TOKEN_TYPE_STRING);
8438 buffer_add_string (buf, s);
8439 g_free (s);
8440 } else {
8441 g_assert_not_reached ();
8443 break;
8446 break;
8448 case CMD_METHOD_GET_CATTRS: {
8449 ERROR_DECL (error);
8450 MonoClass *attr_klass;
8451 MonoCustomAttrInfo *cinfo;
8453 attr_klass = decode_typeid (p, &p, end, NULL, &err);
8454 /* attr_klass can be NULL */
8455 if (err != ERR_NONE)
8456 return err;
8458 cinfo = mono_custom_attrs_from_method_checked (method, error);
8459 if (!is_ok (error)) {
8460 mono_error_cleanup (error); /* FIXME don't swallow the error message */
8461 return ERR_LOADER_ERROR;
8464 err = buffer_add_cattrs (buf, domain, m_class_get_image (method->klass), attr_klass, cinfo);
8465 if (err != ERR_NONE)
8466 return err;
8467 break;
8469 case CMD_METHOD_MAKE_GENERIC_METHOD: {
8470 ERROR_DECL (error);
8471 MonoType **type_argv;
8472 int i, type_argc;
8473 MonoDomain *d;
8474 MonoClass *klass;
8475 MonoGenericInst *ginst;
8476 MonoGenericContext tmp_context;
8477 MonoMethod *inflated;
8479 type_argc = decode_int (p, &p, end);
8480 type_argv = g_new0 (MonoType*, type_argc);
8481 for (i = 0; i < type_argc; ++i) {
8482 klass = decode_typeid (p, &p, end, &d, &err);
8483 if (err != ERR_NONE) {
8484 g_free (type_argv);
8485 return err;
8487 if (domain != d) {
8488 g_free (type_argv);
8489 return ERR_INVALID_ARGUMENT;
8491 type_argv [i] = m_class_get_byval_arg (klass);
8493 ginst = mono_metadata_get_generic_inst (type_argc, type_argv);
8494 g_free (type_argv);
8495 tmp_context.class_inst = mono_class_is_ginst (method->klass) ? mono_class_get_generic_class (method->klass)->context.class_inst : NULL;
8496 tmp_context.method_inst = ginst;
8498 inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error);
8499 g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
8500 if (!mono_verifier_is_method_valid_generic_instantiation (inflated))
8501 return ERR_INVALID_ARGUMENT;
8502 buffer_add_methodid (buf, domain, inflated);
8503 break;
8505 default:
8506 return ERR_NOT_IMPLEMENTED;
8509 return ERR_NONE;
8512 static ErrorCode
8513 method_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8515 ErrorCode err;
8516 MonoDomain *old_domain;
8517 MonoDomain *domain;
8518 MonoMethod *method;
8520 method = decode_methodid (p, &p, end, &domain, &err);
8521 if (err != ERR_NONE)
8522 return err;
8524 old_domain = mono_domain_get ();
8526 mono_domain_set (domain, TRUE);
8528 err = method_commands_internal (command, method, domain, p, end, buf);
8530 mono_domain_set (old_domain, TRUE);
8532 return err;
8535 static ErrorCode
8536 thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8538 int objid = decode_objid (p, &p, end);
8539 ErrorCode err;
8540 MonoThread *thread_obj;
8541 MonoInternalThread *thread;
8543 err = get_object (objid, (MonoObject**)&thread_obj);
8544 if (err != ERR_NONE)
8545 return err;
8547 thread = THREAD_TO_INTERNAL (thread_obj);
8549 switch (command) {
8550 case CMD_THREAD_GET_NAME: {
8551 guint32 name_len;
8552 gunichar2 *s = mono_thread_get_name (thread, &name_len);
8554 if (!s) {
8555 buffer_add_int (buf, 0);
8556 } else {
8557 char *name;
8558 glong len;
8560 name = g_utf16_to_utf8 (s, name_len, NULL, &len, NULL);
8561 g_assert (name);
8562 buffer_add_int (buf, len);
8563 buffer_add_data (buf, (guint8*)name, len);
8564 g_free (s);
8566 break;
8568 case CMD_THREAD_GET_FRAME_INFO: {
8569 DebuggerTlsData *tls;
8570 int i, start_frame, length;
8572 // Wait for suspending if it already started
8573 // FIXME: Races with suspend_count
8574 while (!is_suspended ()) {
8575 if (suspend_count)
8576 wait_for_suspend ();
8579 if (suspend_count)
8580 wait_for_suspend ();
8581 if (!is_suspended ())
8582 return ERR_NOT_SUSPENDED;
8585 start_frame = decode_int (p, &p, end);
8586 length = decode_int (p, &p, end);
8588 if (start_frame != 0 || length != -1)
8589 return ERR_NOT_IMPLEMENTED;
8591 mono_loader_lock ();
8592 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
8593 mono_loader_unlock ();
8594 g_assert (tls);
8596 compute_frame_info (thread, tls);
8598 buffer_add_int (buf, tls->frame_count);
8599 for (i = 0; i < tls->frame_count; ++i) {
8600 buffer_add_int (buf, tls->frames [i]->id);
8601 buffer_add_methodid (buf, tls->frames [i]->de.domain, tls->frames [i]->actual_method);
8602 buffer_add_int (buf, tls->frames [i]->il_offset);
8604 * Instead of passing the frame type directly to the client, we associate
8605 * it with the previous frame using a set of flags. This avoids lots of
8606 * conditional code in the client, since a frame whose type isn't
8607 * FRAME_TYPE_MANAGED has no method, location, etc.
8609 buffer_add_byte (buf, tls->frames [i]->flags);
8612 break;
8614 case CMD_THREAD_GET_STATE:
8615 buffer_add_int (buf, thread->state);
8616 break;
8617 case CMD_THREAD_GET_INFO:
8618 buffer_add_byte (buf, thread->threadpool_thread);
8619 break;
8620 case CMD_THREAD_GET_ID:
8621 buffer_add_long (buf, (guint64)(gsize)thread);
8622 break;
8623 case CMD_THREAD_GET_TID:
8624 buffer_add_long (buf, (guint64)thread->tid);
8625 break;
8626 case CMD_THREAD_SET_IP: {
8627 DebuggerTlsData *tls;
8628 MonoMethod *method;
8629 MonoDomain *domain;
8630 MonoSeqPointInfo *seq_points;
8631 SeqPoint sp;
8632 gboolean found_sp;
8633 gint64 il_offset;
8635 method = decode_methodid (p, &p, end, &domain, &err);
8636 if (err != ERR_NONE)
8637 return err;
8638 il_offset = decode_long (p, &p, end);
8640 while (!is_suspended ()) {
8641 if (suspend_count)
8642 wait_for_suspend ();
8645 mono_loader_lock ();
8646 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
8647 mono_loader_unlock ();
8648 g_assert (tls);
8650 compute_frame_info (thread, tls);
8651 if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
8652 return ERR_INVALID_ARGUMENT;
8654 found_sp = mono_find_seq_point (domain, method, il_offset, &seq_points, &sp);
8656 g_assert (seq_points);
8658 if (!found_sp)
8659 return ERR_INVALID_ARGUMENT;
8661 // FIXME: Check that the ip change is safe
8663 DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset);
8665 if (tls->frames [0]->de.ji->is_interp) {
8666 MonoJitTlsData *jit_data = thread->thread_info->jit_data;
8667 mini_get_interp_callbacks ()->set_resume_state (jit_data, NULL, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->de.ji->code_start + sp.native_offset);
8668 } else {
8669 MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->de.ji->code_start + sp.native_offset);
8671 break;
8673 default:
8674 return ERR_NOT_IMPLEMENTED;
8677 return ERR_NONE;
8680 static ErrorCode
8681 frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8683 int objid;
8684 ErrorCode err;
8685 MonoThread *thread_obj;
8686 MonoInternalThread *thread;
8687 int pos, i, len, frame_idx;
8688 DebuggerTlsData *tls;
8689 StackFrame *frame;
8690 MonoDebugMethodJitInfo *jit;
8691 MonoMethodSignature *sig;
8692 gssize id;
8693 MonoMethodHeader *header;
8695 objid = decode_objid (p, &p, end);
8696 err = get_object (objid, (MonoObject**)&thread_obj);
8697 if (err != ERR_NONE)
8698 return err;
8700 thread = THREAD_TO_INTERNAL (thread_obj);
8702 id = decode_id (p, &p, end);
8704 mono_loader_lock ();
8705 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
8706 mono_loader_unlock ();
8707 g_assert (tls);
8709 for (i = 0; i < tls->frame_count; ++i) {
8710 if (tls->frames [i]->id == id)
8711 break;
8713 if (i == tls->frame_count)
8714 return ERR_INVALID_FRAMEID;
8716 frame_idx = i;
8717 frame = tls->frames [frame_idx];
8719 /* This is supported for frames without has_ctx etc. set */
8720 if (command == CMD_STACK_FRAME_GET_DOMAIN) {
8721 if (CHECK_PROTOCOL_VERSION (2, 38))
8722 buffer_add_domainid (buf, frame->de.domain);
8723 return ERR_NONE;
8726 if (!frame->has_ctx)
8727 return ERR_ABSENT_INFORMATION;
8729 if (!ensure_jit ((DbgEngineStackFrame*)frame))
8730 return ERR_ABSENT_INFORMATION;
8732 jit = frame->jit;
8734 sig = mono_method_signature_internal (frame->actual_method);
8736 if (!(jit->has_var_info || frame->de.ji->is_interp) || !mono_get_seq_points (frame->de.domain, frame->actual_method))
8738 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
8740 return ERR_ABSENT_INFORMATION;
8742 switch (command) {
8743 case CMD_STACK_FRAME_GET_VALUES: {
8744 ERROR_DECL (error);
8745 len = decode_int (p, &p, end);
8746 header = mono_method_get_header_checked (frame->actual_method, error);
8747 mono_error_assert_ok (error); /* FIXME report error */
8749 for (i = 0; i < len; ++i) {
8750 pos = decode_int (p, &p, end);
8752 if (pos < 0) {
8753 pos = - pos - 1;
8755 DEBUG_PRINTF (4, "[dbg] send arg %d.\n", pos);
8757 if (frame->de.ji->is_interp) {
8758 guint8 *addr;
8760 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos);
8762 buffer_add_value_full (buf, sig->params [pos], addr, frame->de.domain, FALSE, NULL);
8763 } else {
8764 g_assert (pos >= 0 && pos < jit->num_params);
8766 add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->de.domain, FALSE);
8768 } else {
8769 MonoDebugLocalsInfo *locals;
8771 locals = mono_debug_lookup_locals (frame->de.method);
8772 if (locals) {
8773 g_assert (pos < locals->num_locals);
8774 pos = locals->locals [pos].index;
8775 mono_debug_free_locals (locals);
8778 DEBUG_PRINTF (4, "[dbg] send local %d.\n", pos);
8780 if (frame->de.ji->is_interp) {
8781 guint8 *addr;
8783 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos);
8785 buffer_add_value_full (buf, header->locals [pos], addr, frame->de.domain, FALSE, NULL);
8786 } else {
8787 g_assert (pos >= 0 && pos < jit->num_locals);
8789 add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->de.domain, FALSE);
8793 mono_metadata_free_mh (header);
8794 break;
8796 case CMD_STACK_FRAME_GET_THIS: {
8797 if (frame->de.method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
8798 return ERR_ABSENT_INFORMATION;
8799 if (m_class_is_valuetype (frame->api_method->klass)) {
8800 if (!sig->hasthis) {
8801 MonoObject *p = NULL;
8802 buffer_add_value (buf, mono_get_object_type (), &p, frame->de.domain);
8803 } else {
8804 if (frame->de.ji->is_interp) {
8805 guint8 *addr;
8807 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
8809 buffer_add_value_full (buf, m_class_get_this_arg (frame->actual_method->klass), addr, frame->de.domain, FALSE, NULL);
8810 } else {
8811 add_var (buf, jit, m_class_get_this_arg (frame->actual_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
8814 } else {
8815 if (!sig->hasthis) {
8816 MonoObject *p = NULL;
8817 buffer_add_value (buf, m_class_get_byval_arg (frame->actual_method->klass), &p, frame->de.domain);
8818 } else {
8819 if (frame->de.ji->is_interp) {
8820 guint8 *addr;
8822 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
8824 buffer_add_value_full (buf, m_class_get_byval_arg (frame->api_method->klass), addr, frame->de.domain, FALSE, NULL);
8825 } else {
8826 add_var (buf, jit, m_class_get_byval_arg (frame->api_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
8830 break;
8832 case CMD_STACK_FRAME_SET_VALUES: {
8833 ERROR_DECL (error);
8834 guint8 *val_buf;
8835 MonoType *t;
8836 MonoDebugVarInfo *var = NULL;
8837 gboolean is_arg = FALSE;
8839 len = decode_int (p, &p, end);
8840 header = mono_method_get_header_checked (frame->actual_method, error);
8841 mono_error_assert_ok (error); /* FIXME report error */
8843 for (i = 0; i < len; ++i) {
8844 pos = decode_int (p, &p, end);
8846 if (pos < 0) {
8847 pos = - pos - 1;
8849 g_assert (pos >= 0 && pos < jit->num_params);
8851 t = sig->params [pos];
8852 var = &jit->params [pos];
8853 is_arg = TRUE;
8854 } else {
8855 MonoDebugLocalsInfo *locals;
8857 locals = mono_debug_lookup_locals (frame->de.method);
8858 if (locals) {
8859 g_assert (pos < locals->num_locals);
8860 pos = locals->locals [pos].index;
8861 mono_debug_free_locals (locals);
8863 g_assert (pos >= 0 && pos < jit->num_locals);
8865 t = header->locals [pos];
8866 var = &jit->locals [pos];
8869 if (MONO_TYPE_IS_REFERENCE (t))
8870 val_buf = (guint8 *)g_alloca (sizeof (MonoObject*));
8871 else
8872 val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (t)));
8873 err = decode_value (t, frame->de.domain, val_buf, p, &p, end);
8874 if (err != ERR_NONE)
8875 return err;
8877 if (frame->de.ji->is_interp) {
8878 guint8 *addr;
8880 if (is_arg)
8881 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos);
8882 else
8883 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos);
8884 set_interp_var (t, addr, val_buf);
8885 } else {
8886 set_var (t, var, &frame->ctx, frame->de.domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
8889 mono_metadata_free_mh (header);
8890 break;
8892 case CMD_STACK_FRAME_GET_DOMAIN: {
8893 if (CHECK_PROTOCOL_VERSION (2, 38))
8894 buffer_add_domainid (buf, frame->de.domain);
8895 break;
8897 case CMD_STACK_FRAME_SET_THIS: {
8898 guint8 *val_buf;
8899 MonoType *t;
8900 MonoDebugVarInfo *var;
8902 t = m_class_get_byval_arg (frame->actual_method->klass);
8903 /* Checked by the sender */
8904 g_assert (MONO_TYPE_ISSTRUCT (t));
8906 val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (t)));
8907 err = decode_value (t, frame->de.domain, val_buf, p, &p, end);
8908 if (err != ERR_NONE)
8909 return err;
8911 if (frame->de.ji->is_interp) {
8912 guint8 *addr;
8914 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
8915 set_interp_var (m_class_get_this_arg (frame->actual_method->klass), addr, val_buf);
8916 } else {
8917 var = jit->this_var;
8918 g_assert (var);
8920 set_var (m_class_get_this_arg (frame->actual_method->klass), var, &frame->ctx, frame->de.domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
8922 break;
8924 default:
8925 return ERR_NOT_IMPLEMENTED;
8928 return ERR_NONE;
8931 static ErrorCode
8932 array_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8934 MonoArray *arr;
8935 int objid, index, len, i, esize;
8936 ErrorCode err;
8937 gpointer elem;
8939 objid = decode_objid (p, &p, end);
8940 err = get_object (objid, (MonoObject**)&arr);
8941 if (err != ERR_NONE)
8942 return err;
8944 switch (command) {
8945 case CMD_ARRAY_REF_GET_LENGTH:
8946 buffer_add_int (buf, m_class_get_rank (arr->obj.vtable->klass));
8947 if (!arr->bounds) {
8948 buffer_add_int (buf, arr->max_length);
8949 buffer_add_int (buf, 0);
8950 } else {
8951 for (i = 0; i < m_class_get_rank (arr->obj.vtable->klass); ++i) {
8952 buffer_add_int (buf, arr->bounds [i].length);
8953 buffer_add_int (buf, arr->bounds [i].lower_bound);
8956 break;
8957 case CMD_ARRAY_REF_GET_VALUES:
8958 index = decode_int (p, &p, end);
8959 len = decode_int (p, &p, end);
8961 g_assert (index >= 0 && len >= 0);
8962 // Reordered to avoid integer overflow
8963 g_assert (!(index > arr->max_length - len));
8965 esize = mono_array_element_size (arr->obj.vtable->klass);
8966 for (i = index; i < index + len; ++i) {
8967 elem = (gpointer*)((char*)arr->vector + (i * esize));
8968 buffer_add_value (buf, m_class_get_byval_arg (m_class_get_element_class (arr->obj.vtable->klass)), elem, arr->obj.vtable->domain);
8970 break;
8971 case CMD_ARRAY_REF_SET_VALUES:
8972 index = decode_int (p, &p, end);
8973 len = decode_int (p, &p, end);
8975 g_assert (index >= 0 && len >= 0);
8976 // Reordered to avoid integer overflow
8977 g_assert (!(index > arr->max_length - len));
8979 esize = mono_array_element_size (arr->obj.vtable->klass);
8980 for (i = index; i < index + len; ++i) {
8981 elem = (gpointer*)((char*)arr->vector + (i * esize));
8983 decode_value (m_class_get_byval_arg (m_class_get_element_class (arr->obj.vtable->klass)), arr->obj.vtable->domain, (guint8 *)elem, p, &p, end);
8985 break;
8986 default:
8987 return ERR_NOT_IMPLEMENTED;
8990 return ERR_NONE;
8993 static ErrorCode
8994 string_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8996 int objid;
8997 ErrorCode err;
8998 MonoString *str;
8999 char *s;
9000 int i, index, length;
9001 gunichar2 *c;
9002 gboolean use_utf16 = FALSE;
9004 objid = decode_objid (p, &p, end);
9005 err = get_object (objid, (MonoObject**)&str);
9006 if (err != ERR_NONE)
9007 return err;
9009 switch (command) {
9010 case CMD_STRING_REF_GET_VALUE:
9011 if (CHECK_PROTOCOL_VERSION (2, 41)) {
9012 for (i = 0; i < mono_string_length_internal (str); ++i)
9013 if (mono_string_chars_internal (str)[i] == 0)
9014 use_utf16 = TRUE;
9015 buffer_add_byte (buf, use_utf16 ? 1 : 0);
9017 if (use_utf16) {
9018 buffer_add_int (buf, mono_string_length_internal (str) * 2);
9019 buffer_add_data (buf, (guint8*)mono_string_chars_internal (str), mono_string_length_internal (str) * 2);
9020 } else {
9021 ERROR_DECL (error);
9022 s = mono_string_to_utf8_checked_internal (str, error);
9023 if (!mono_error_ok (error)) {
9024 if (s)
9025 g_free (s);
9027 return ERR_INVALID_ARGUMENT;
9029 buffer_add_string (buf, s);
9030 g_free (s);
9032 break;
9033 case CMD_STRING_REF_GET_LENGTH:
9034 buffer_add_long (buf, mono_string_length_internal (str));
9035 break;
9036 case CMD_STRING_REF_GET_CHARS:
9037 index = decode_long (p, &p, end);
9038 length = decode_long (p, &p, end);
9039 if (index > mono_string_length_internal (str) - length)
9040 return ERR_INVALID_ARGUMENT;
9041 c = mono_string_chars_internal (str) + index;
9042 for (i = 0; i < length; ++i)
9043 buffer_add_short (buf, c [i]);
9044 break;
9045 default:
9046 return ERR_NOT_IMPLEMENTED;
9049 return ERR_NONE;
9052 static ErrorCode
9053 pointer_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9055 ErrorCode err;
9056 gint64 addr;
9057 MonoClass* klass;
9058 MonoDomain* domain = NULL;
9060 switch (command) {
9061 case CMD_POINTER_GET_VALUE:
9062 addr = decode_long (p, &p, end);
9063 klass = decode_typeid (p, &p, end, &domain, &err);
9064 if (err != ERR_NONE)
9065 return err;
9067 if (m_class_get_byval_arg (klass)->type != MONO_TYPE_PTR)
9068 return ERR_INVALID_ARGUMENT;
9070 buffer_add_value (buf, m_class_get_byval_arg (m_class_get_element_class (klass)), (gpointer)addr, domain);
9072 break;
9073 default:
9074 return ERR_NOT_IMPLEMENTED;
9077 return ERR_NONE;
9080 static ErrorCode
9081 object_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9083 ERROR_DECL (error);
9084 int objid;
9085 ErrorCode err;
9086 MonoObject *obj;
9087 int len, i;
9088 MonoClassField *f;
9089 MonoClass *k;
9090 gboolean found;
9092 if (command == CMD_OBJECT_REF_IS_COLLECTED) {
9093 objid = decode_objid (p, &p, end);
9094 err = get_object (objid, &obj);
9095 if (err != ERR_NONE)
9096 buffer_add_int (buf, 1);
9097 else
9098 buffer_add_int (buf, 0);
9099 return ERR_NONE;
9102 objid = decode_objid (p, &p, end);
9103 err = get_object (objid, &obj);
9104 if (err != ERR_NONE)
9105 return err;
9107 MonoClass *obj_type;
9108 gboolean remote_obj = FALSE;
9110 obj_type = obj->vtable->klass;
9111 if (mono_class_is_transparent_proxy (obj_type)) {
9112 obj_type = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
9113 remote_obj = TRUE;
9116 g_assert (obj_type);
9118 switch (command) {
9119 case CMD_OBJECT_REF_GET_TYPE:
9120 /* This handles transparent proxies too */
9121 buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type_internal (((MonoReflectionType*)obj->vtable->type)->type));
9122 break;
9123 case CMD_OBJECT_REF_GET_VALUES:
9124 len = decode_int (p, &p, end);
9126 for (i = 0; i < len; ++i) {
9127 MonoClassField *f = decode_fieldid (p, &p, end, NULL, &err);
9128 if (err != ERR_NONE)
9129 return err;
9131 /* Check that the field belongs to the object */
9132 found = FALSE;
9133 for (k = obj_type; k; k = m_class_get_parent (k)) {
9134 if (k == f->parent) {
9135 found = TRUE;
9136 break;
9139 if (!found)
9140 return ERR_INVALID_FIELDID;
9142 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9143 guint8 *val;
9144 MonoVTable *vtable;
9146 if (mono_class_field_is_special_static (f))
9147 return ERR_INVALID_FIELDID;
9149 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
9150 vtable = mono_class_vtable_checked (obj->vtable->domain, f->parent, error);
9151 if (!is_ok (error)) {
9152 mono_error_cleanup (error);
9153 return ERR_INVALID_OBJECT;
9155 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
9156 mono_field_static_get_value_checked (vtable, f, val, error);
9157 if (!is_ok (error)) {
9158 mono_error_cleanup (error); /* FIXME report the error */
9159 return ERR_INVALID_OBJECT;
9161 buffer_add_value (buf, f->type, val, obj->vtable->domain);
9162 g_free (val);
9163 } else {
9164 void *field_value = NULL;
9166 if (remote_obj) {
9167 #ifndef DISABLE_REMOTING
9168 void *field_storage = NULL;
9169 field_value = mono_load_remote_field_checked(obj, obj_type, f, &field_storage, error);
9170 if (!is_ok (error)) {
9171 mono_error_cleanup (error); /* FIXME report the error */
9172 return ERR_INVALID_OBJECT;
9174 #else
9175 g_assert_not_reached ();
9176 #endif
9177 } else
9178 field_value = (guint8*)obj + f->offset;
9180 buffer_add_value (buf, f->type, field_value, obj->vtable->domain);
9183 break;
9184 case CMD_OBJECT_REF_SET_VALUES:
9185 len = decode_int (p, &p, end);
9187 for (i = 0; i < len; ++i) {
9188 f = decode_fieldid (p, &p, end, NULL, &err);
9189 if (err != ERR_NONE)
9190 return err;
9192 /* Check that the field belongs to the object */
9193 found = FALSE;
9194 for (k = obj_type; k; k = m_class_get_parent (k)) {
9195 if (k == f->parent) {
9196 found = TRUE;
9197 break;
9200 if (!found)
9201 return ERR_INVALID_FIELDID;
9203 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9204 guint8 *val;
9205 MonoVTable *vtable;
9207 if (mono_class_field_is_special_static (f))
9208 return ERR_INVALID_FIELDID;
9210 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
9211 vtable = mono_class_vtable_checked (obj->vtable->domain, f->parent, error);
9212 if (!is_ok (error)) {
9213 mono_error_cleanup (error);
9214 return ERR_INVALID_FIELDID;
9217 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
9218 err = decode_value (f->type, obj->vtable->domain, val, p, &p, end);
9219 if (err != ERR_NONE) {
9220 g_free (val);
9221 return err;
9223 mono_field_static_set_value_internal (vtable, f, val);
9224 g_free (val);
9225 } else {
9226 err = decode_value (f->type, obj->vtable->domain, (guint8*)obj + f->offset, p, &p, end);
9227 if (err != ERR_NONE)
9228 return err;
9231 break;
9232 case CMD_OBJECT_REF_GET_ADDRESS:
9233 buffer_add_long (buf, (gssize)obj);
9234 break;
9235 case CMD_OBJECT_REF_GET_DOMAIN:
9236 buffer_add_domainid (buf, obj->vtable->domain);
9237 break;
9238 case CMD_OBJECT_REF_GET_INFO:
9239 buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type_internal (((MonoReflectionType*)obj->vtable->type)->type));
9240 buffer_add_domainid (buf, obj->vtable->domain);
9241 break;
9242 default:
9243 return ERR_NOT_IMPLEMENTED;
9246 return ERR_NONE;
9249 static const char*
9250 command_set_to_string (CommandSet command_set)
9252 switch (command_set) {
9253 case CMD_SET_VM:
9254 return "VM";
9255 case CMD_SET_OBJECT_REF:
9256 return "OBJECT_REF";
9257 case CMD_SET_STRING_REF:
9258 return "STRING_REF";
9259 case CMD_SET_THREAD:
9260 return "THREAD";
9261 case CMD_SET_ARRAY_REF:
9262 return "ARRAY_REF";
9263 case CMD_SET_EVENT_REQUEST:
9264 return "EVENT_REQUEST";
9265 case CMD_SET_STACK_FRAME:
9266 return "STACK_FRAME";
9267 case CMD_SET_APPDOMAIN:
9268 return "APPDOMAIN";
9269 case CMD_SET_ASSEMBLY:
9270 return "ASSEMBLY";
9271 case CMD_SET_METHOD:
9272 return "METHOD";
9273 case CMD_SET_TYPE:
9274 return "TYPE";
9275 case CMD_SET_MODULE:
9276 return "MODULE";
9277 case CMD_SET_FIELD:
9278 return "FIELD";
9279 case CMD_SET_EVENT:
9280 return "EVENT";
9281 case CMD_SET_POINTER:
9282 return "POINTER";
9283 default:
9284 return "";
9288 static const char* vm_cmds_str [] = {
9289 "VERSION",
9290 "ALL_THREADS",
9291 "SUSPEND",
9292 "RESUME",
9293 "EXIT",
9294 "DISPOSE",
9295 "INVOKE_METHOD",
9296 "SET_PROTOCOL_VERSION",
9297 "ABORT_INVOKE",
9298 "SET_KEEPALIVE"
9299 "GET_TYPES_FOR_SOURCE_FILE",
9300 "GET_TYPES",
9301 "INVOKE_METHODS"
9304 static const char* thread_cmds_str[] = {
9305 "GET_FRAME_INFO",
9306 "GET_NAME",
9307 "GET_STATE",
9308 "GET_INFO",
9309 "GET_ID",
9310 "GET_TID",
9311 "SET_IP"
9314 static const char* event_cmds_str[] = {
9315 "REQUEST_SET",
9316 "REQUEST_CLEAR",
9317 "REQUEST_CLEAR_ALL_BREAKPOINTS"
9320 static const char* appdomain_cmds_str[] = {
9321 "GET_ROOT_DOMAIN",
9322 "GET_FRIENDLY_NAME",
9323 "GET_ASSEMBLIES",
9324 "GET_ENTRY_ASSEMBLY",
9325 "CREATE_STRING",
9326 "GET_CORLIB",
9327 "CREATE_BOXED_VALUE"
9330 static const char* assembly_cmds_str[] = {
9331 "GET_LOCATION",
9332 "GET_ENTRY_POINT",
9333 "GET_MANIFEST_MODULE",
9334 "GET_OBJECT",
9335 "GET_TYPE",
9336 "GET_NAME",
9337 "GET_DOMAIN"
9340 static const char* module_cmds_str[] = {
9341 "GET_INFO",
9344 static const char* field_cmds_str[] = {
9345 "GET_INFO",
9348 static const char* method_cmds_str[] = {
9349 "GET_NAME",
9350 "GET_DECLARING_TYPE",
9351 "GET_DEBUG_INFO",
9352 "GET_PARAM_INFO",
9353 "GET_LOCALS_INFO",
9354 "GET_INFO",
9355 "GET_BODY",
9356 "RESOLVE_TOKEN",
9357 "GET_CATTRS ",
9358 "MAKE_GENERIC_METHOD"
9361 static const char* type_cmds_str[] = {
9362 "GET_INFO",
9363 "GET_METHODS",
9364 "GET_FIELDS",
9365 "GET_VALUES",
9366 "GET_OBJECT",
9367 "GET_SOURCE_FILES",
9368 "SET_VALUES",
9369 "IS_ASSIGNABLE_FROM",
9370 "GET_PROPERTIES ",
9371 "GET_CATTRS",
9372 "GET_FIELD_CATTRS",
9373 "GET_PROPERTY_CATTRS",
9374 "GET_SOURCE_FILES_2",
9375 "GET_VALUES_2",
9376 "GET_METHODS_BY_NAME_FLAGS",
9377 "GET_INTERFACES",
9378 "GET_INTERFACE_MAP",
9379 "IS_INITIALIZED",
9380 "CREATE_INSTANCE",
9381 "GET_VALUE_SIZE"
9384 static const char* stack_frame_cmds_str[] = {
9385 "GET_VALUES",
9386 "GET_THIS",
9387 "SET_VALUES",
9388 "GET_DOMAIN",
9389 "SET_THIS"
9392 static const char* array_cmds_str[] = {
9393 "GET_LENGTH",
9394 "GET_VALUES",
9395 "SET_VALUES",
9398 static const char* string_cmds_str[] = {
9399 "GET_VALUE",
9400 "GET_LENGTH",
9401 "GET_CHARS"
9404 static const char* pointer_cmds_str[] = {
9405 "GET_VALUE"
9408 static const char* object_cmds_str[] = {
9409 "GET_TYPE",
9410 "GET_VALUES",
9411 "IS_COLLECTED",
9412 "GET_ADDRESS",
9413 "GET_DOMAIN",
9414 "SET_VALUES",
9415 "GET_INFO",
9418 static const char*
9419 cmd_to_string (CommandSet set, int command)
9421 const char **cmds;
9422 int cmds_len = 0;
9424 switch (set) {
9425 case CMD_SET_VM:
9426 cmds = vm_cmds_str;
9427 cmds_len = G_N_ELEMENTS (vm_cmds_str);
9428 break;
9429 case CMD_SET_OBJECT_REF:
9430 cmds = object_cmds_str;
9431 cmds_len = G_N_ELEMENTS (object_cmds_str);
9432 break;
9433 case CMD_SET_STRING_REF:
9434 cmds = string_cmds_str;
9435 cmds_len = G_N_ELEMENTS (string_cmds_str);
9436 break;
9437 case CMD_SET_THREAD:
9438 cmds = thread_cmds_str;
9439 cmds_len = G_N_ELEMENTS (thread_cmds_str);
9440 break;
9441 case CMD_SET_ARRAY_REF:
9442 cmds = array_cmds_str;
9443 cmds_len = G_N_ELEMENTS (array_cmds_str);
9444 break;
9445 case CMD_SET_EVENT_REQUEST:
9446 cmds = event_cmds_str;
9447 cmds_len = G_N_ELEMENTS (event_cmds_str);
9448 break;
9449 case CMD_SET_STACK_FRAME:
9450 cmds = stack_frame_cmds_str;
9451 cmds_len = G_N_ELEMENTS (stack_frame_cmds_str);
9452 break;
9453 case CMD_SET_APPDOMAIN:
9454 cmds = appdomain_cmds_str;
9455 cmds_len = G_N_ELEMENTS (appdomain_cmds_str);
9456 break;
9457 case CMD_SET_ASSEMBLY:
9458 cmds = assembly_cmds_str;
9459 cmds_len = G_N_ELEMENTS (assembly_cmds_str);
9460 break;
9461 case CMD_SET_METHOD:
9462 cmds = method_cmds_str;
9463 cmds_len = G_N_ELEMENTS (method_cmds_str);
9464 break;
9465 case CMD_SET_TYPE:
9466 cmds = type_cmds_str;
9467 cmds_len = G_N_ELEMENTS (type_cmds_str);
9468 break;
9469 case CMD_SET_MODULE:
9470 cmds = module_cmds_str;
9471 cmds_len = G_N_ELEMENTS (module_cmds_str);
9472 break;
9473 case CMD_SET_FIELD:
9474 cmds = field_cmds_str;
9475 cmds_len = G_N_ELEMENTS (field_cmds_str);
9476 break;
9477 case CMD_SET_EVENT:
9478 cmds = event_cmds_str;
9479 cmds_len = G_N_ELEMENTS (event_cmds_str);
9480 break;
9481 case CMD_SET_POINTER:
9482 cmds = pointer_cmds_str;
9483 cmds_len = G_N_ELEMENTS (pointer_cmds_str);
9484 break;
9485 default:
9486 return NULL;
9488 if (command > 0 && command <= cmds_len)
9489 return cmds [command - 1];
9490 else
9491 return NULL;
9494 static gboolean
9495 wait_for_attach (void)
9497 #ifndef DISABLE_SOCKET_TRANSPORT
9498 if (listen_fd == -1) {
9499 DEBUG_PRINTF (1, "[dbg] Invalid listening socket\n");
9500 return FALSE;
9503 /* Block and wait for client connection */
9504 conn_fd = socket_transport_accept (listen_fd);
9506 DEBUG_PRINTF (1, "Accepted connection on %d\n", conn_fd);
9507 if (conn_fd == -1) {
9508 DEBUG_PRINTF (1, "[dbg] Bad client connection\n");
9509 return FALSE;
9511 #else
9512 g_assert_not_reached ();
9513 #endif
9515 /* Handshake */
9516 disconnected = !transport_handshake ();
9517 if (disconnected) {
9518 DEBUG_PRINTF (1, "Transport handshake failed!\n");
9519 return FALSE;
9522 return TRUE;
9526 * debugger_thread:
9528 * This thread handles communication with the debugger client using a JDWP
9529 * like protocol.
9531 static gsize WINAPI
9532 debugger_thread (void *arg)
9534 ERROR_DECL (error);
9535 int res, len, id, flags, command = 0;
9536 CommandSet command_set = (CommandSet)0;
9537 guint8 header [HEADER_LENGTH];
9538 guint8 *data, *p, *end;
9539 Buffer buf;
9540 ErrorCode err;
9541 gboolean no_reply;
9542 gboolean attach_failed = FALSE;
9544 DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer) (gsize) mono_native_thread_id_get ());
9546 gboolean log_each_step = g_hasenv ("MONO_DEBUGGER_LOG_AFTER_COMMAND");
9548 debugger_thread_id = mono_native_thread_id_get ();
9550 MonoInternalThread *internal = mono_thread_internal_current ();
9551 MonoString *str = mono_string_new_checked (mono_domain_get (), "Debugger agent", error);
9552 mono_error_assert_ok (error);
9553 mono_thread_set_name_internal (internal, str, TRUE, FALSE, error);
9554 mono_error_assert_ok (error);
9556 internal->state |= ThreadState_Background;
9557 internal->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
9559 if (agent_config.defer) {
9560 if (!wait_for_attach ()) {
9561 DEBUG_PRINTF (1, "[dbg] Can't attach, aborting debugger thread.\n");
9562 attach_failed = TRUE; // Don't abort process when we can't listen
9563 } else {
9564 mono_set_is_debugger_attached (TRUE);
9565 /* Send start event to client */
9566 process_profiler_event (EVENT_KIND_VM_START, mono_thread_get_main ());
9568 } else {
9569 mono_set_is_debugger_attached (TRUE);
9572 while (!attach_failed) {
9573 res = transport_recv (header, HEADER_LENGTH);
9575 /* This will break if the socket is closed during shutdown too */
9576 if (res != HEADER_LENGTH) {
9577 DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, HEADER_LENGTH);
9578 len = HEADER_LENGTH;
9579 id = 0;
9580 flags = 0;
9581 command_set = CMD_SET_VM;
9582 command = CMD_VM_DISPOSE;
9583 } else {
9584 p = header;
9585 end = header + HEADER_LENGTH;
9587 len = decode_int (p, &p, end);
9588 id = decode_int (p, &p, end);
9589 flags = decode_byte (p, &p, end);
9590 command_set = (CommandSet)decode_byte (p, &p, end);
9591 command = decode_byte (p, &p, end);
9594 g_assert (flags == 0);
9595 const char *cmd_str;
9596 char cmd_num [256];
9598 cmd_str = cmd_to_string (command_set, command);
9599 if (!cmd_str) {
9600 sprintf (cmd_num, "%d", command);
9601 cmd_str = cmd_num;
9604 if (log_level) {
9605 DEBUG_PRINTF (1, "[dbg] Command %s(%s) [%d][at=%lx].\n", command_set_to_string (command_set), cmd_str, id, (long)mono_100ns_ticks () / 10000);
9608 data = (guint8 *)g_malloc (len - HEADER_LENGTH);
9609 if (len - HEADER_LENGTH > 0)
9611 res = transport_recv (data, len - HEADER_LENGTH);
9612 if (res != len - HEADER_LENGTH) {
9613 DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH);
9614 break;
9618 p = data;
9619 end = data + (len - HEADER_LENGTH);
9621 buffer_init (&buf, 128);
9623 err = ERR_NONE;
9624 no_reply = FALSE;
9626 /* Process the request */
9627 switch (command_set) {
9628 case CMD_SET_VM:
9629 err = vm_commands (command, id, p, end, &buf);
9630 if (err == ERR_NONE && command == CMD_VM_INVOKE_METHOD)
9631 /* Sent after the invoke is complete */
9632 no_reply = TRUE;
9633 break;
9634 case CMD_SET_EVENT_REQUEST:
9635 err = event_commands (command, p, end, &buf);
9636 break;
9637 case CMD_SET_APPDOMAIN:
9638 err = domain_commands (command, p, end, &buf);
9639 break;
9640 case CMD_SET_ASSEMBLY:
9641 err = assembly_commands (command, p, end, &buf);
9642 break;
9643 case CMD_SET_MODULE:
9644 err = module_commands (command, p, end, &buf);
9645 break;
9646 case CMD_SET_FIELD:
9647 err = field_commands (command, p, end, &buf);
9648 break;
9649 case CMD_SET_TYPE:
9650 err = type_commands (command, p, end, &buf);
9651 break;
9652 case CMD_SET_METHOD:
9653 err = method_commands (command, p, end, &buf);
9654 break;
9655 case CMD_SET_THREAD:
9656 err = thread_commands (command, p, end, &buf);
9657 break;
9658 case CMD_SET_STACK_FRAME:
9659 err = frame_commands (command, p, end, &buf);
9660 break;
9661 case CMD_SET_ARRAY_REF:
9662 err = array_commands (command, p, end, &buf);
9663 break;
9664 case CMD_SET_STRING_REF:
9665 err = string_commands (command, p, end, &buf);
9666 break;
9667 case CMD_SET_POINTER:
9668 err = pointer_commands (command, p, end, &buf);
9669 break;
9670 case CMD_SET_OBJECT_REF:
9671 err = object_commands (command, p, end, &buf);
9672 break;
9673 default:
9674 err = ERR_NOT_IMPLEMENTED;
9677 if (command_set == CMD_SET_VM && command == CMD_VM_START_BUFFERING) {
9678 buffer_replies = TRUE;
9681 if (!no_reply) {
9682 if (buffer_replies) {
9683 buffer_reply_packet (id, err, &buf);
9684 } else {
9685 send_reply_packet (id, err, &buf);
9686 //DEBUG_PRINTF (1, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000);
9690 mono_debugger_log_command (command_set_to_string (command_set), cmd_str, buf.buf, buffer_len (&buf));
9692 if (err == ERR_NONE && command_set == CMD_SET_VM && command == CMD_VM_STOP_BUFFERING) {
9693 send_buffered_reply_packets ();
9694 buffer_replies = FALSE;
9697 g_free (data);
9698 buffer_free (&buf);
9700 if (log_each_step) {
9701 char *debugger_log = mono_debugger_state_str ();
9702 if (debugger_log) {
9703 fprintf (stderr, "Debugger state: %s\n", debugger_log);
9704 g_free (debugger_log);
9708 if (command_set == CMD_SET_VM && (command == CMD_VM_DISPOSE || command == CMD_VM_EXIT))
9709 break;
9712 mono_set_is_debugger_attached (FALSE);
9714 mono_coop_mutex_lock (&debugger_thread_exited_mutex);
9715 debugger_thread_exited = TRUE;
9716 mono_coop_cond_signal (&debugger_thread_exited_cond);
9717 mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
9719 DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");
9721 if (!attach_failed && command_set == CMD_SET_VM && command == CMD_VM_DISPOSE && !(vm_death_event_sent || mono_runtime_is_shutting_down ())) {
9722 DEBUG_PRINTF (2, "[dbg] Detached - restarting clean debugger thread.\n");
9723 start_debugger_thread ();
9726 return 0;
9729 void
9730 mono_debugger_agent_init (void)
9732 MonoDebuggerCallbacks cbs;
9734 memset (&cbs, 0, sizeof (MonoDebuggerCallbacks));
9735 cbs.version = MONO_DBG_CALLBACKS_VERSION;
9736 cbs.parse_options = debugger_agent_parse_options;
9737 cbs.init = debugger_agent_init;
9738 cbs.breakpoint_hit = debugger_agent_breakpoint_hit;
9739 cbs.single_step_event = debugger_agent_single_step_event;
9740 cbs.single_step_from_context = debugger_agent_single_step_from_context;
9741 cbs.breakpoint_from_context = debugger_agent_breakpoint_from_context;
9742 cbs.free_domain_info = debugger_agent_free_domain_info;
9743 cbs.unhandled_exception = debugger_agent_unhandled_exception;
9744 cbs.handle_exception = debugger_agent_handle_exception;
9745 cbs.begin_exception_filter = debugger_agent_begin_exception_filter;
9746 cbs.end_exception_filter = debugger_agent_end_exception_filter;
9747 cbs.user_break = debugger_agent_user_break;
9748 cbs.debug_log = debugger_agent_debug_log;
9749 cbs.debug_log_is_enabled = debugger_agent_debug_log_is_enabled;
9750 cbs.send_crash = mono_debugger_agent_send_crash;
9752 mini_install_dbg_callbacks (&cbs);
9755 void
9756 mono_debugger_agent_parse_options (char *options)
9758 sdb_options = options;
9761 #endif /* DISABLE_SDB */