2 * debugger-agent.c: Debugger back-end module
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2009 Novell, Inc.
14 #ifdef HAVE_SYS_TYPES_H
15 #include <sys/types.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 #include <sys/socket.h>
20 #ifdef HAVE_NETINET_TCP_H
21 #include <netinet/tcp.h>
23 #ifdef HAVE_NETINET_IN_H
24 #include <netinet/in.h>
39 #ifdef HAVE_UCONTEXT_H
46 /* cygwin's headers do not seem to define these */
47 void WSAAPI freeaddrinfo (struct addrinfo*);
48 int WSAAPI getaddrinfo (const char*,const char*,const struct addrinfo*,
50 int WSAAPI getnameinfo(const struct sockaddr*,socklen_t,char*,DWORD,
55 #ifdef PLATFORM_ANDROID
57 #include <linux/tcp.h>
58 #include <sys/endian.h>
61 #include <mono/metadata/mono-debug.h>
62 #include <mono/metadata/mono-debug-debugger.h>
63 #include <mono/metadata/debug-mono-symfile.h>
64 #include <mono/metadata/gc-internal.h>
65 #include <mono/metadata/threads-types.h>
66 #include <mono/metadata/socket-io.h>
67 #include <mono/utils/mono-semaphore.h>
68 #include "debugger-agent.h"
71 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
72 #define DISABLE_DEBUGGER_AGENT 1
75 #ifdef DISABLE_SOFT_DEBUG
76 #define DISABLE_DEBUGGER_AGENT 1
79 #ifndef DISABLE_DEBUGGER_AGENT
80 #include <mono/io-layer/mono-mutex.h>
82 /* Definitions to make backporting to 2.6 easier */
83 //#define MonoInternalThread MonoThread
84 //#define mono_thread_internal_current mono_thread_current
85 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
108 MonoDebugMethodJitInfo *jit;
111 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
112 * the frame can become invalid.
123 /* This is the context which needs to be restored after the invoke */
127 * If this is set, invoke this method with the arguments given by ARGS.
131 guint32 suspend_count;
138 gboolean has_context;
139 gpointer resume_event;
140 /* This is computed on demand when it is requested using the wire protocol */
141 /* It is freed up when the thread is resumed */
145 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
148 gboolean frames_up_to_date;
150 * Points to data about a pending invoke which needs to be executed after the thread
155 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
160 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
161 * within a finite amount of time.
165 * Set to TRUE if this thread is suspended in suspend_current ().
167 gboolean really_suspended;
168 /* Used to pass the context to the breakpoint/single step handler */
169 MonoContext handler_ctx;
170 /* Whenever thread_stop () was called for this thread */
173 /* Number of thread interruptions not yet processed */
174 gint32 interrupt_count;
176 /* Whenever to disable breakpoints (used during invokes) */
177 gboolean disable_breakpoints;
180 * Number of times this thread has been resumed using resume_thread ().
182 guint32 resume_count;
184 MonoInternalThread *thread;
187 * Information about the frame which transitioned to native code for running
190 StackFrameInfo async_last_frame;
193 * The context where the stack walk can be started for running threads.
195 MonoContext async_ctx;
197 gboolean has_async_ctx;
200 * The lmf where the stack walk can be started for running threads.
205 * The callee address of the last mono_runtime_invoke call
207 gpointer invoke_addr;
211 * Wire Protocol definitions
214 #define HEADER_LENGTH 11
216 #define MAJOR_VERSION 2
217 #define MINOR_VERSION 0
221 CMD_SET_OBJECT_REF = 9,
222 CMD_SET_STRING_REF = 10,
224 CMD_SET_ARRAY_REF = 13,
225 CMD_SET_EVENT_REQUEST = 15,
226 CMD_SET_STACK_FRAME = 16,
227 CMD_SET_APPDOMAIN = 20,
228 CMD_SET_ASSEMBLY = 21,
236 EVENT_KIND_VM_START = 0,
237 EVENT_KIND_VM_DEATH = 1,
238 EVENT_KIND_THREAD_START = 2,
239 EVENT_KIND_THREAD_DEATH = 3,
240 EVENT_KIND_APPDOMAIN_CREATE = 4,
241 EVENT_KIND_APPDOMAIN_UNLOAD = 5,
242 EVENT_KIND_METHOD_ENTRY = 6,
243 EVENT_KIND_METHOD_EXIT = 7,
244 EVENT_KIND_ASSEMBLY_LOAD = 8,
245 EVENT_KIND_ASSEMBLY_UNLOAD = 9,
246 EVENT_KIND_BREAKPOINT = 10,
247 EVENT_KIND_STEP = 11,
248 EVENT_KIND_TYPE_LOAD = 12,
249 EVENT_KIND_EXCEPTION = 13
253 SUSPEND_POLICY_NONE = 0,
254 SUSPEND_POLICY_EVENT_THREAD = 1,
255 SUSPEND_POLICY_ALL = 2
260 ERR_INVALID_OBJECT = 20,
261 ERR_INVALID_FIELDID = 25,
262 ERR_INVALID_FRAMEID = 30,
263 ERR_NOT_IMPLEMENTED = 100,
264 ERR_NOT_SUSPENDED = 101,
265 ERR_INVALID_ARGUMENT = 102,
271 MOD_KIND_THREAD_ONLY = 3,
272 MOD_KIND_LOCATION_ONLY = 7,
273 MOD_KIND_EXCEPTION_ONLY = 8,
275 MOD_KIND_ASSEMBLY_ONLY = 11
290 TOKEN_TYPE_STRING = 0,
292 TOKEN_TYPE_FIELD = 2,
293 TOKEN_TYPE_METHOD = 3,
294 TOKEN_TYPE_UNKNOWN = 4
298 VALUE_TYPE_ID_NULL = 0xf0,
299 VALUE_TYPE_ID_TYPE = 0xf1
303 FRAME_FLAG_DEBUGGER_INVOKE = 1
307 INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
308 INVOKE_FLAG_SINGLE_THREADED = 2
313 CMD_VM_ALL_THREADS = 2,
318 CMD_VM_INVOKE_METHOD = 7
322 CMD_THREAD_GET_FRAME_INFO = 1,
323 CMD_THREAD_GET_NAME = 2,
324 CMD_THREAD_GET_STATE = 3,
325 CMD_THREAD_GET_INFO = 4
329 CMD_EVENT_REQUEST_SET = 1,
330 CMD_EVENT_REQUEST_CLEAR = 2,
331 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS = 3
339 CMD_APPDOMAIN_GET_ROOT_DOMAIN = 1,
340 CMD_APPDOMAIN_GET_FRIENDLY_NAME = 2,
341 CMD_APPDOMAIN_GET_ASSEMBLIES = 3,
342 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY = 4,
343 CMD_APPDOMAIN_CREATE_STRING = 5,
344 CMD_APPDOMAIN_GET_CORLIB = 6
348 CMD_ASSEMBLY_GET_LOCATION = 1,
349 CMD_ASSEMBLY_GET_ENTRY_POINT = 2,
350 CMD_ASSEMBLY_GET_MANIFEST_MODULE = 3,
351 CMD_ASSEMBLY_GET_OBJECT = 4,
352 CMD_ASSEMBLY_GET_TYPE = 5,
353 CMD_ASSEMBLY_GET_NAME = 6
357 CMD_MODULE_GET_INFO = 1,
361 CMD_METHOD_GET_NAME = 1,
362 CMD_METHOD_GET_DECLARING_TYPE = 2,
363 CMD_METHOD_GET_DEBUG_INFO = 3,
364 CMD_METHOD_GET_PARAM_INFO = 4,
365 CMD_METHOD_GET_LOCALS_INFO = 5,
366 CMD_METHOD_GET_INFO = 6,
367 CMD_METHOD_GET_BODY = 7,
368 CMD_METHOD_RESOLVE_TOKEN = 8,
372 CMD_TYPE_GET_INFO = 1,
373 CMD_TYPE_GET_METHODS = 2,
374 CMD_TYPE_GET_FIELDS = 3,
375 CMD_TYPE_GET_VALUES = 4,
376 CMD_TYPE_GET_OBJECT = 5,
377 CMD_TYPE_GET_SOURCE_FILES = 6,
378 CMD_TYPE_SET_VALUES = 7,
379 CMD_TYPE_IS_ASSIGNABLE_FROM = 8,
380 CMD_TYPE_GET_PROPERTIES = 9,
381 CMD_TYPE_GET_CATTRS = 10,
382 CMD_TYPE_GET_FIELD_CATTRS = 11,
383 CMD_TYPE_GET_PROPERTY_CATTRS = 12
387 CMD_STACK_FRAME_GET_VALUES = 1,
388 CMD_STACK_FRAME_GET_THIS = 2,
389 CMD_STACK_FRAME_SET_VALUES = 3
393 CMD_ARRAY_REF_GET_LENGTH = 1,
394 CMD_ARRAY_REF_GET_VALUES = 2,
395 CMD_ARRAY_REF_SET_VALUES = 3,
399 CMD_STRING_REF_GET_VALUE = 1,
403 CMD_OBJECT_REF_GET_TYPE = 1,
404 CMD_OBJECT_REF_GET_VALUES = 2,
405 CMD_OBJECT_REF_IS_COLLECTED = 3,
406 CMD_OBJECT_REF_GET_ADDRESS = 4,
407 CMD_OBJECT_REF_GET_DOMAIN = 5,
408 CMD_OBJECT_REF_SET_VALUES = 6
414 int count; /* For kind == MOD_KIND_COUNT */
415 MonoInternalThread *thread; /* For kind == MOD_KIND_THREAD_ONLY */
416 MonoClass *exc_class; /* For kind == MONO_KIND_EXCEPTION_ONLY */
417 MonoAssembly **assemblies; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
427 Modifier modifiers [MONO_ZERO_LEN_ARRAY];
431 * Describes a single step request.
435 MonoInternalThread *thread;
440 MonoMethod *last_method;
444 /* Dummy structure used for the profiler callbacks */
449 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
455 static AgentConfig agent_config;
458 * Whenever the agent is fully initialized.
459 * When using the onuncaught or onthrow options, only some parts of the agent are
460 * initialized on startup, and the full initialization which includes connection
461 * establishment and the startup of the agent thread is only done in response to
464 static gint32 inited;
468 static int packet_id = 0;
470 static int objref_id = 0;
472 static int event_request_id = 0;
474 static int frame_id = 0;
476 static GPtrArray *event_requests;
478 static guint32 debugger_tls_id;
480 static gboolean vm_start_event_sent, vm_death_event_sent, disconnected;
482 /* Maps MonoInternalThread -> DebuggerTlsData */
483 static MonoGHashTable *thread_to_tls;
485 /* Maps tid -> MonoInternalThread */
486 static MonoGHashTable *tid_to_thread;
488 /* Maps tid -> MonoThread (not MonoInternalThread) */
489 static MonoGHashTable *tid_to_thread_obj;
491 static gsize debugger_thread_id;
493 static HANDLE debugger_thread_handle;
495 static int log_level;
497 static FILE *log_file;
499 /* Classes whose class load event has been sent */
500 static GHashTable *loaded_classes;
502 /* Assemblies whose assembly load event has no been sent yet */
503 static GPtrArray *pending_assembly_loads;
505 /* Whenever the debugger thread has exited */
506 static gboolean debugger_thread_exited;
508 /* Cond variable used to wait for debugger_thread_exited becoming true */
509 static mono_cond_t debugger_thread_exited_cond;
511 /* Mutex for the cond var above */
512 static mono_mutex_t debugger_thread_exited_mutex;
514 static DebuggerProfiler debugger_profiler;
516 /* The single step request instance */
517 static MonoSingleStepReq *ss_req = NULL;
518 static gpointer ss_invoke_addr = NULL;
520 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
521 /* Number of single stepping operations in progress */
525 static void transport_connect (const char *host, int port);
527 static guint32 WINAPI debugger_thread (void *arg);
529 static void runtime_initialized (MonoProfiler *prof);
531 static void runtime_shutdown (MonoProfiler *prof);
533 static void thread_startup (MonoProfiler *prof, gsize tid);
535 static void thread_end (MonoProfiler *prof, gsize tid);
537 static void appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result);
539 static void appdomain_unload (MonoProfiler *prof, MonoDomain *domain);
541 static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result);
543 static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly);
545 static void start_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
547 static void end_runtime_invoke (MonoProfiler *prof, MonoMethod *method);
549 static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
551 static void add_pending_breakpoints (MonoMethod *method, MonoJitInfo *jinfo);
553 static void start_single_stepping (void);
555 static void stop_single_stepping (void);
557 static void suspend_current (void);
559 /* Submodule init/cleanup */
560 static void breakpoints_init (void);
561 static void breakpoints_cleanup (void);
563 static void objrefs_init (void);
564 static void objrefs_cleanup (void);
566 static void ids_init (void);
567 static void ids_cleanup (void);
569 static void suspend_init (void);
571 static ErrorCode ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
572 static void ss_stop (EventRequest *req);
574 static void start_debugger_thread (void);
576 static void finish_agent_init (gboolean on_startup);
579 parse_address (char *address, char **host, int *port)
581 char *pos = strchr (address, ':');
583 if (pos == NULL || pos == address)
586 *host = g_malloc (pos - address + 1);
587 strncpy (*host, address, pos - address);
588 (*host) [pos - address] = '\0';
590 *port = atoi (pos + 1);
598 fprintf (stderr, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
599 fprintf (stderr, "Available options:\n");
600 fprintf (stderr, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
601 fprintf (stderr, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
602 fprintf (stderr, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
603 fprintf (stderr, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
604 fprintf (stderr, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
605 fprintf (stderr, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
606 fprintf (stderr, " help\t\t\t\tPrint this help.\n");
610 parse_flag (const char *option, char *flag)
612 if (!strcmp (flag, "y"))
614 else if (!strcmp (flag, "n"))
617 fprintf (stderr, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option);
624 mono_debugger_agent_parse_options (char *options)
630 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
631 fprintf (stderr, "--debugger-agent is not supported on this platform.\n");
635 agent_config.enabled = TRUE;
636 agent_config.suspend = TRUE;
637 agent_config.server = FALSE;
639 args = g_strsplit (options, ",", -1);
640 for (ptr = args; ptr && *ptr; ptr ++) {
643 if (strncmp (arg, "transport=", 10) == 0) {
644 agent_config.transport = g_strdup (arg + 10);
645 } else if (strncmp (arg, "address=", 8) == 0) {
646 agent_config.address = g_strdup (arg + 8);
647 } else if (strncmp (arg, "loglevel=", 9) == 0) {
648 agent_config.log_level = atoi (arg + 9);
649 } else if (strncmp (arg, "logfile=", 8) == 0) {
650 agent_config.log_file = g_strdup (arg + 8);
651 } else if (strncmp (arg, "suspend=", 8) == 0) {
652 agent_config.suspend = parse_flag ("suspend", arg + 8);
653 } else if (strncmp (arg, "server=", 7) == 0) {
654 agent_config.server = parse_flag ("server", arg + 7);
655 } else if (strncmp (arg, "onuncaught=", 11) == 0) {
656 agent_config.onuncaught = parse_flag ("onuncaught", arg + 11);
657 } else if (strncmp (arg, "onthrow=", 8) == 0) {
658 /* We support multiple onthrow= options */
659 agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (arg + 8));
660 } else if (strncmp (arg, "help", 4) == 0) {
663 } else if (strncmp (arg, "timeout=", 8) == 0) {
664 agent_config.timeout = atoi (arg + 8);
665 } else if (strncmp (arg, "launch=", 7) == 0) {
666 agent_config.launch = g_strdup (arg + 7);
673 if (agent_config.transport == NULL) {
674 fprintf (stderr, "debugger-agent: The 'transport' option is mandatory.\n");
677 if (strcmp (agent_config.transport, "dt_socket") != 0) {
678 fprintf (stderr, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
682 if (agent_config.address == NULL && !agent_config.server) {
683 fprintf (stderr, "debugger-agent: The 'address' option is mandatory.\n");
687 if (agent_config.address && parse_address (agent_config.address, &host, &port)) {
688 fprintf (stderr, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
694 mono_debugger_agent_init (void)
696 if (!agent_config.enabled)
699 /* Need to know whenever a thread has acquired the loader mutex */
700 mono_loader_lock_track_ownership (TRUE);
702 event_requests = g_ptr_array_new ();
704 mono_mutex_init (&debugger_thread_exited_mutex, NULL);
705 mono_cond_init (&debugger_thread_exited_cond, NULL);
707 mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown);
708 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS);
709 mono_profiler_install_runtime_initialized (runtime_initialized);
710 mono_profiler_install_appdomain (NULL, appdomain_load, appdomain_unload, NULL);
711 mono_profiler_install_thread (thread_startup, thread_end);
712 mono_profiler_install_assembly (NULL, assembly_load, assembly_unload, NULL);
713 mono_profiler_install_jit_end (jit_end);
714 mono_profiler_install_method_invoke (start_runtime_invoke, end_runtime_invoke);
716 debugger_tls_id = TlsAlloc ();
718 thread_to_tls = mono_g_hash_table_new (NULL, NULL);
719 MONO_GC_REGISTER_ROOT (thread_to_tls);
721 tid_to_thread = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
722 MONO_GC_REGISTER_ROOT (tid_to_thread);
724 tid_to_thread_obj = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
725 MONO_GC_REGISTER_ROOT (tid_to_thread_obj);
727 loaded_classes = g_hash_table_new (mono_aligned_addr_hash, NULL);
728 pending_assembly_loads = g_ptr_array_new ();
730 log_level = agent_config.log_level;
732 if (agent_config.log_file) {
733 log_file = fopen (agent_config.log_file, "w+");
735 fprintf (stderr, "Unable to create log file '%s': %s.\n", agent_config.log_file, strerror (errno));
747 mini_get_debug_options ()->gen_seq_points = TRUE;
749 * This is needed because currently we don't handle liveness info.
751 mini_get_debug_options ()->mdb_optimizations = TRUE;
753 /* This is needed because we can't set local variables in registers yet */
754 mono_disable_optimizations (MONO_OPT_LINEARS);
756 if (!agent_config.onuncaught && !agent_config.onthrow)
757 finish_agent_init (TRUE);
763 * Finish the initialization of the agent. This involves connecting the transport
764 * and starting the agent thread. This is either done at startup, or
765 * in response to some event like an unhandled exception.
768 finish_agent_init (gboolean on_startup)
774 if (InterlockedCompareExchange (&inited, 1, 0) == 1)
777 if (agent_config.launch) {
780 // FIXME: Generated address
781 // FIXME: Races with transport_connect ()
783 argv [0] = agent_config.launch;
784 argv [1] = agent_config.transport;
785 argv [2] = agent_config.address;
788 res = g_spawn_async_with_pipes (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
790 fprintf (stderr, "Failed to execute '%s'.\n", agent_config.launch);
795 if (agent_config.address) {
796 res = parse_address (agent_config.address, &host, &port);
803 transport_connect (host, port);
806 /* Do some which is usually done after sending the VMStart () event */
807 vm_start_event_sent = TRUE;
808 start_debugger_thread ();
813 mono_debugger_agent_cleanup (void)
818 /* This will interrupt the agent thread */
819 /* Close the read part only so it can still send back replies */
821 shutdown (conn_fd, SD_RECEIVE);
823 shutdown (conn_fd, SHUT_RD);
827 * Wait for the thread to exit.
829 * If we continue with the shutdown without waiting for it, then the client might
830 * not receive an answer to its last command like a resume.
831 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
834 //WaitForSingleObject (debugger_thread_handle, INFINITE);
835 if (GetCurrentThreadId () != debugger_thread_id) {
836 mono_mutex_lock (&debugger_thread_exited_mutex);
837 if (!debugger_thread_exited) {
839 if (WAIT_TIMEOUT == WaitForSingleObject(debugger_thread_exited_cond, 0)) {
840 mono_mutex_unlock (&debugger_thread_exited_mutex);
842 mono_mutex_lock (&debugger_thread_exited_mutex);
845 mono_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
848 mono_mutex_unlock (&debugger_thread_exited_mutex);
851 breakpoints_cleanup ();
856 shutdown (conn_fd, SD_BOTH);
858 shutdown (conn_fd, SHUT_RDWR);
861 mono_mutex_destroy (&debugger_thread_exited_mutex);
862 mono_cond_destroy (&debugger_thread_exited_cond);
868 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
871 transport_connect (const char *host, int port)
873 struct addrinfo hints;
874 struct addrinfo *result, *rp;
876 char port_string [128];
877 char handshake_msg [128];
883 sprintf (port_string, "%d", port);
885 mono_network_init ();
887 /* Obtain address(es) matching host/port */
889 memset (&hints, 0, sizeof (struct addrinfo));
890 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
891 hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
893 hints.ai_protocol = 0; /* Any protocol */
895 s = getaddrinfo (host, port_string, &hints, &result);
897 fprintf (stderr, "debugger-agent: Unable to connect to %s:%d: %s\n", host, port, gai_strerror (s));
902 if (agent_config.server) {
903 /* Wait for a connection */
905 struct sockaddr_in addr;
908 /* No address, generate one */
909 sfd = socket (AF_INET, SOCK_STREAM, 0);
912 /* This will bind the socket to a random port */
913 res = listen (sfd, 16);
915 fprintf (stderr, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno));
919 addrlen = sizeof (addr);
920 memset (&addr, 0, sizeof (addr));
921 res = getsockname (sfd, &addr, &addrlen);
925 port = ntohs (addr.sin_port);
927 /* Emit the address to stdout */
928 /* FIXME: Should print another interface, not localhost */
929 printf ("%s:%d\n", host, port);
931 /* Listen on the provided address */
932 for (rp = result; rp != NULL; rp = rp->ai_next) {
933 sfd = socket (rp->ai_family, rp->ai_socktype,
938 res = bind (sfd, rp->ai_addr, rp->ai_addrlen);
942 res = listen (sfd, 16);
948 freeaddrinfo (result);
951 DEBUG (1, fprintf (log_file, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout));
953 if (agent_config.timeout) {
958 tv.tv_usec = agent_config.timeout * 1000;
960 FD_SET (sfd, &readfds);
961 res = select (sfd + 1, &readfds, NULL, NULL, &tv);
963 fprintf (stderr, "debugger-agent: Timed out waiting to connect.\n");
968 conn_fd = accept (sfd, NULL, NULL);
970 fprintf (stderr, "debugger-agent: Unable to listen on %s:%d\n", host, port);
974 DEBUG (1, fprintf (log_file, "Accepted connection from client, socket fd=%d.\n", conn_fd));
976 /* Connect to the specified address */
977 /* FIXME: Respect the timeout */
978 for (rp = result; rp != NULL; rp = rp->ai_next) {
979 sfd = socket (rp->ai_family, rp->ai_socktype,
984 if (connect (sfd, rp->ai_addr, rp->ai_addrlen) != -1)
992 freeaddrinfo (result);
995 fprintf (stderr, "debugger-agent: Unable to connect to %s:%d\n", host, port);
1000 /* Write handshake message */
1001 sprintf (handshake_msg, "DWP-Handshake");
1002 res = send (conn_fd, handshake_msg, strlen (handshake_msg), 0);
1003 g_assert (res != -1);
1006 res = recv (conn_fd, buf, strlen (handshake_msg), 0);
1007 if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg) != 0))) {
1008 fprintf (stderr, "debugger-agent: DWP handshake failed.\n");
1013 * Set TCP_NODELAY on the socket so the client receives events/command
1014 * results immediately.
1018 int result = setsockopt(conn_fd,
1023 g_assert (result >= 0);
1028 transport_send (guint8 *data, int len)
1032 res = send (conn_fd, data, len, 0);
1040 start_debugger_thread (void)
1044 debugger_thread_handle = mono_create_thread (NULL, 0, debugger_thread, NULL, 0, &tid);
1045 g_assert (debugger_thread_handle);
1049 * Functions to decode protocol data
1053 decode_byte (guint8 *buf, guint8 **endbuf, guint8 *limit)
1056 g_assert (*endbuf <= limit);
1061 decode_int (guint8 *buf, guint8 **endbuf, guint8 *limit)
1064 g_assert (*endbuf <= limit);
1066 return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0);
1069 static inline gint64
1070 decode_long (guint8 *buf, guint8 **endbuf, guint8 *limit)
1072 guint32 high = decode_int (buf, &buf, limit);
1073 guint32 low = decode_int (buf, &buf, limit);
1077 return ((((guint64)high) << 32) | ((guint64)low));
1081 decode_id (guint8 *buf, guint8 **endbuf, guint8 *limit)
1083 return decode_int (buf, endbuf, limit);
1087 decode_string (guint8 *buf, guint8 **endbuf, guint8 *limit)
1089 int len = decode_int (buf, &buf, limit);
1092 s = g_malloc (len + 1);
1095 memcpy (s, buf, len);
1104 * Functions to encode protocol data
1108 guint8 *buf, *p, *end;
1112 buffer_init (Buffer *buf, int size)
1114 buf->buf = g_malloc (size);
1116 buf->end = buf->buf + size;
1120 buffer_make_room (Buffer *buf, int size)
1122 if (buf->end - buf->p < size) {
1123 int new_size = buf->end - buf->buf + size + 32;
1124 guint8 *p = g_realloc (buf->buf, new_size);
1125 size = buf->p - buf->buf;
1128 buf->end = buf->buf + new_size;
1133 buffer_add_byte (Buffer *buf, guint8 val)
1135 buffer_make_room (buf, 1);
1141 buffer_add_int (Buffer *buf, guint32 val)
1143 buffer_make_room (buf, 4);
1144 buf->p [0] = (val >> 24) & 0xff;
1145 buf->p [1] = (val >> 16) & 0xff;
1146 buf->p [2] = (val >> 8) & 0xff;
1147 buf->p [3] = (val >> 0) & 0xff;
1152 buffer_add_long (Buffer *buf, guint64 l)
1154 buffer_add_int (buf, (l >> 32) & 0xffffffff);
1155 buffer_add_int (buf, (l >> 0) & 0xffffffff);
1159 buffer_add_id (Buffer *buf, int id)
1161 buffer_add_int (buf, (guint64)id);
1165 buffer_add_data (Buffer *buf, guint8 *data, int len)
1167 buffer_make_room (buf, len);
1168 memcpy (buf->p, data, len);
1173 buffer_add_string (Buffer *buf, const char *str)
1178 buffer_add_int (buf, 0);
1181 buffer_add_int (buf, len);
1182 buffer_add_data (buf, (guint8*)str, len);
1187 buffer_free (Buffer *buf)
1193 send_packet (int command_set, int command, Buffer *data)
1199 id = InterlockedIncrement (&packet_id);
1201 len = data->p - data->buf + 11;
1202 buffer_init (&buf, len);
1203 buffer_add_int (&buf, len);
1204 buffer_add_int (&buf, id);
1205 buffer_add_byte (&buf, 0); /* flags */
1206 buffer_add_byte (&buf, command_set);
1207 buffer_add_byte (&buf, command);
1208 memcpy (buf.buf + 11, data->buf, data->p - data->buf);
1210 res = transport_send (buf.buf, len);
1218 send_reply_packet (int id, int error, Buffer *data)
1224 len = data->p - data->buf + 11;
1225 buffer_init (&buf, len);
1226 buffer_add_int (&buf, len);
1227 buffer_add_int (&buf, id);
1228 buffer_add_byte (&buf, 0x80); /* flags */
1229 buffer_add_byte (&buf, (error >> 8) & 0xff);
1230 buffer_add_byte (&buf, error);
1231 memcpy (buf.buf + 11, data->buf, data->p - data->buf);
1233 res = transport_send (buf.buf, len);
1245 * Represents an object accessible by the debugger client.
1248 /* Unique id used in the wire protocol to refer to objects */
1251 * A weakref gc handle pointing to the object. The gc handle is used to
1252 * detect if the object was garbage collected.
1257 /* Maps objid -> ObjRef */
1258 static GHashTable *objrefs;
1261 free_objref (gpointer value)
1265 mono_gchandle_free (o->handle);
1273 objrefs = g_hash_table_new_full (NULL, NULL, NULL, free_objref);
1277 objrefs_cleanup (void)
1279 g_hash_table_destroy (objrefs);
1283 static GHashTable *obj_to_objref;
1286 * Return an ObjRef for OBJ.
1289 get_objref (MonoObject *obj)
1300 /* Use a hash table with masked pointers to internalize object references */
1301 /* FIXME: This can grow indefinitely */
1302 mono_loader_lock ();
1305 obj_to_objref = g_hash_table_new (NULL, NULL);
1307 ref = g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
1308 /* ref might refer to a different object with the same addr which was GCd */
1309 if (ref && mono_gchandle_get_target (ref->handle) == obj) {
1310 mono_loader_unlock ();
1314 ref = g_new0 (ObjRef, 1);
1315 ref->id = InterlockedIncrement (&objref_id);
1316 ref->handle = mono_gchandle_new_weakref (obj, FALSE);
1318 g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
1319 g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
1321 mono_loader_unlock ();
1327 get_objid (MonoObject *obj)
1329 return get_objref (obj)->id;
1333 * Set OBJ to the object identified by OBJID.
1334 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1338 get_object_allow_null (int objid, MonoObject **obj)
1348 return ERR_INVALID_OBJECT;
1350 mono_loader_lock ();
1352 ref = g_hash_table_lookup (objrefs, GINT_TO_POINTER (objid));
1355 *obj = mono_gchandle_get_target (ref->handle);
1356 mono_loader_unlock ();
1358 return ERR_INVALID_OBJECT;
1361 mono_loader_unlock ();
1362 return ERR_INVALID_OBJECT;
1367 get_object (int objid, MonoObject **obj)
1369 int err = get_object_allow_null (objid, obj);
1374 return ERR_INVALID_OBJECT;
1379 decode_objid (guint8 *buf, guint8 **endbuf, guint8 *limit)
1381 return decode_id (buf, endbuf, limit);
1385 buffer_add_objid (Buffer *buf, MonoObject *o)
1387 buffer_add_id (buf, get_objid (o));
1406 * Represents a runtime structure accessible to the debugger client
1409 /* Unique id used in the wire protocol */
1411 /* Domain of the runtime structure, NULL if the domain was unloaded */
1418 MonoAssembly *assembly;
1419 MonoClassField *field;
1421 MonoProperty *property;
1426 /* Maps runtime structure -> Id */
1427 GHashTable *val_to_id [ID_NUM];
1431 static GPtrArray *ids [ID_NUM];
1438 for (i = 0; i < ID_NUM; ++i)
1439 ids [i] = g_ptr_array_new ();
1447 for (i = 0; i < ID_NUM; ++i) {
1449 for (j = 0; j < ids [i]->len; ++j)
1450 g_free (g_ptr_array_index (ids [i], j));
1451 g_ptr_array_free (ids [i], TRUE);
1458 mono_debugger_agent_free_domain_info (MonoDomain *domain)
1460 AgentDomainInfo *info = domain_jit_info (domain)->agent_info;
1464 for (i = 0; i < ID_NUM; ++i)
1465 if (info->val_to_id [i])
1466 g_hash_table_destroy (info->val_to_id [i]);
1470 domain_jit_info (domain)->agent_info = NULL;
1472 /* Clear ids referencing structures in the domain */
1473 for (i = 0; i < ID_NUM; ++i) {
1475 for (j = 0; j < ids [i]->len; ++j) {
1476 Id *id = g_ptr_array_index (ids [i], j);
1477 if (id->domain == domain)
1485 get_id (MonoDomain *domain, IdType type, gpointer val)
1488 AgentDomainInfo *info;
1493 mono_loader_lock ();
1495 mono_domain_lock (domain);
1497 if (!domain_jit_info (domain)->agent_info)
1498 domain_jit_info (domain)->agent_info = g_new0 (AgentDomainInfo, 1);
1499 info = domain_jit_info (domain)->agent_info;
1500 if (info->val_to_id [type] == NULL)
1501 info->val_to_id [type] = g_hash_table_new (mono_aligned_addr_hash, NULL);
1503 id = g_hash_table_lookup (info->val_to_id [type], val);
1505 mono_domain_unlock (domain);
1506 mono_loader_unlock ();
1510 id = g_new0 (Id, 1);
1512 id->id = ids [type]->len + 1;
1513 id->domain = domain;
1516 g_hash_table_insert (info->val_to_id [type], val, id);
1518 mono_domain_unlock (domain);
1520 g_ptr_array_add (ids [type], id);
1522 mono_loader_unlock ();
1527 static inline gpointer
1528 decode_ptr_id (guint8 *buf, guint8 **endbuf, guint8 *limit, IdType type, MonoDomain **domain, int *err)
1532 int id = decode_id (buf, endbuf, limit);
1541 // FIXME: error handling
1542 mono_loader_lock ();
1543 g_assert (id > 0 && id <= ids [type]->len);
1545 res = g_ptr_array_index (ids [type], GPOINTER_TO_INT (id - 1));
1546 mono_loader_unlock ();
1548 if (res->domain == NULL) {
1549 *err = ERR_UNLOADED;
1554 *domain = res->domain;
1556 return res->data.val;
1560 buffer_add_ptr_id (Buffer *buf, MonoDomain *domain, IdType type, gpointer val)
1562 buffer_add_id (buf, get_id (domain, type, val));
1565 static inline MonoClass*
1566 decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1568 return decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err);
1571 static inline MonoAssembly*
1572 decode_assemblyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1574 return decode_ptr_id (buf, endbuf, limit, ID_ASSEMBLY, domain, err);
1577 static inline MonoImage*
1578 decode_moduleid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1580 return decode_ptr_id (buf, endbuf, limit, ID_MODULE, domain, err);
1583 static inline MonoMethod*
1584 decode_methodid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1586 return decode_ptr_id (buf, endbuf, limit, ID_METHOD, domain, err);
1589 static inline MonoClassField*
1590 decode_fieldid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1592 return decode_ptr_id (buf, endbuf, limit, ID_FIELD, domain, err);
1595 static inline MonoDomain*
1596 decode_domainid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1598 return decode_ptr_id (buf, endbuf, limit, ID_DOMAIN, domain, err);
1601 static inline MonoProperty*
1602 decode_propertyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, int *err)
1604 return decode_ptr_id (buf, endbuf, limit, ID_PROPERTY, domain, err);
1608 buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
1610 buffer_add_ptr_id (buf, domain, ID_TYPE, klass);
1614 buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method)
1616 buffer_add_ptr_id (buf, domain, ID_METHOD, method);
1620 buffer_add_assemblyid (Buffer *buf, MonoDomain *domain, MonoAssembly *assembly)
1622 buffer_add_ptr_id (buf, domain, ID_ASSEMBLY, assembly);
1626 buffer_add_moduleid (Buffer *buf, MonoDomain *domain, MonoImage *image)
1628 buffer_add_ptr_id (buf, domain, ID_MODULE, image);
1632 buffer_add_fieldid (Buffer *buf, MonoDomain *domain, MonoClassField *field)
1634 buffer_add_ptr_id (buf, domain, ID_FIELD, field);
1638 buffer_add_propertyid (Buffer *buf, MonoDomain *domain, MonoProperty *property)
1640 buffer_add_ptr_id (buf, domain, ID_PROPERTY, property);
1644 buffer_add_domainid (Buffer *buf, MonoDomain *domain)
1646 buffer_add_ptr_id (buf, domain, ID_DOMAIN, domain);
1649 static void invoke_method (void);
1656 * save_thread_context:
1658 * Set CTX as the current threads context which is used for computing stack traces.
1659 * This function is signal-safe.
1662 save_thread_context (MonoContext *ctx)
1664 DebuggerTlsData *tls;
1666 tls = TlsGetValue (debugger_tls_id);
1670 memcpy (&tls->ctx, ctx, sizeof (MonoContext));
1672 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1673 MONO_INIT_CONTEXT_FROM_CURRENT (&tls->ctx);
1675 MONO_INIT_CONTEXT_FROM_FUNC (&tls->ctx, save_thread_context);
1679 tls->lmf = mono_get_lmf ();
1680 tls->domain = mono_domain_get ();
1681 tls->has_context = TRUE;
1684 /* The number of times the runtime is suspended */
1685 static gint32 suspend_count;
1687 /* Number of threads suspended */
1689 * If this is equal to the size of thread_to_tls, the runtime is considered
1692 static gint32 threads_suspend_count;
1694 static mono_mutex_t suspend_mutex;
1696 /* Cond variable used to wait for suspend_count becoming 0 */
1697 static mono_cond_t suspend_cond;
1699 /* Semaphore used to wait for a thread becoming suspended */
1700 static MonoSemType suspend_sem;
1705 mono_mutex_init (&suspend_mutex, NULL);
1706 mono_cond_init (&suspend_cond, NULL);
1707 MONO_SEM_INIT (&suspend_sem, 0);
1712 StackFrameInfo last_frame;
1713 gboolean last_frame_set;
1716 } GetLastFrameUserData;
1719 get_last_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
1721 GetLastFrameUserData *data = user_data;
1723 if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE)
1726 if (!data->last_frame_set) {
1727 /* Store the last frame */
1728 memcpy (&data->last_frame, info, sizeof (StackFrameInfo));
1729 data->last_frame_set = TRUE;
1732 /* Store the context/lmf for the frame above the last frame */
1733 memcpy (&data->ctx, ctx, sizeof (MonoContext));
1734 data->lmf = info->lmf;
1741 * mono_debugger_agent_thread_interrupt:
1743 * Called by the abort signal handler.
1744 * Should be signal safe.
1747 mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
1749 DebuggerTlsData *tls;
1754 tls = TlsGetValue (debugger_tls_id);
1759 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1760 * guarantee the signal handler will be called that many times. Instead of tracking
1761 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1762 * has been requested that hasn't been handled yet, otherwise we can have threads
1763 * refuse to die when VM_EXIT is called
1765 #if defined(__APPLE__)
1766 if (InterlockedCompareExchange (&tls->interrupt_count, 0, 1) == 0)
1770 * We use interrupt_count to determine whenever this interrupt should be processed
1771 * by us or the normal interrupt processing code in the signal handler.
1772 * There is no race here with notify_thread (), since the signal is sent after
1773 * incrementing interrupt_count.
1775 if (tls->interrupt_count == 0)
1778 InterlockedDecrement (&tls->interrupt_count);
1781 // FIXME: Races when the thread leaves managed code before hitting a single step
1785 /* Running managed code, will be suspended by the single step code */
1786 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)GetCurrentThreadId (), ji->method->name, mono_arch_ip_from_context (sigctx)));
1790 * Running native code, will be suspended when it returns to/enters
1791 * managed code. Treat it as already suspended.
1792 * This might interrupt the code in process_single_step_inner (), we use the
1793 * tls->suspending flag to avoid races when that happens.
1795 if (!tls->suspended && !tls->suspending) {
1797 GetLastFrameUserData data;
1799 // FIXME: printf is not signal safe, but this is only used during
1800 // debugger debugging
1801 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx)));
1802 //save_thread_context (&ctx);
1805 /* Already terminated */
1809 * We are in a difficult position: we want to be able to provide stack
1810 * traces for this thread, but we can't use the current ctx+lmf, since
1811 * the thread is still running, so it might return to managed code,
1812 * making these invalid.
1813 * So we start a stack walk and save the first frame, along with the
1814 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1815 * suspended when it returns to managed code, so the parent's ctx should
1818 data.last_frame_set = FALSE;
1820 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
1821 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame, mono_domain_get (), &ctx, FALSE, tls->thread, mono_get_lmf (), &data);
1823 if (data.last_frame_set) {
1824 memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
1825 memcpy (&tls->async_ctx, &data.ctx, sizeof (MonoContext));
1826 tls->async_lmf = data.lmf;
1827 tls->has_async_ctx = TRUE;
1828 tls->domain = mono_domain_get ();
1829 memcpy (&tls->ctx, &ctx, sizeof (MonoContext));
1831 tls->has_async_ctx = FALSE;
1834 tls->suspended = TRUE;
1835 MONO_SEM_POST (&suspend_sem);
1842 static void CALLBACK notify_thread_apc (ULONG_PTR param)
1845 mono_debugger_agent_thread_interrupt (NULL, NULL);
1847 #endif /* HOST_WIN32 */
1850 * reset_native_thread_suspend_state:
1852 * Reset the suspended flag on native threads
1855 reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_data)
1857 DebuggerTlsData *tls = value;
1859 if (!tls->really_suspended && tls->suspended)
1860 tls->suspended = FALSE;
1866 * Notify a thread that it needs to suspend.
1869 notify_thread (gpointer key, gpointer value, gpointer user_data)
1871 MonoInternalThread *thread = key;
1872 DebuggerTlsData *tls = value;
1873 gsize tid = thread->tid;
1875 if (GetCurrentThreadId () != tid) {
1876 DEBUG(1, fprintf (log_file, "[%p] Interrupting %p...\n", (gpointer)GetCurrentThreadId (), (gpointer)tid));
1879 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1880 * guarantee the signal handler will be called that many times. Instead of tracking
1881 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1882 * has been requested that hasn't been handled yet, otherwise we can have threads
1883 * refuse to die when VM_EXIT is called
1885 #if defined(__APPLE__)
1886 if (InterlockedCompareExchange (&tls->interrupt_count, 1, 0) == 1)
1890 * Maybe we could use the normal interrupt infrastructure, but that does a lot
1891 * of things like breaking waits etc. which we don't want.
1893 InterlockedIncrement (&tls->interrupt_count);
1896 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
1898 QueueUserAPC (notify_thread_apc, thread->handle, NULL);
1900 pthread_kill ((pthread_t) tid, mono_thread_get_abort_signal ());
1906 process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
1908 guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
1911 if (debugger_thread_id == GetCurrentThreadId ())
1914 /* Prevent races with mono_debugger_agent_thread_interrupt () */
1915 if (suspend_count - tls->resume_count > 0)
1916 tls->suspending = TRUE;
1918 DEBUG(1, fprintf (log_file, "[%p] Received single step event for suspending.\n", (gpointer)GetCurrentThreadId ()));
1920 if (suspend_count - tls->resume_count == 0) {
1922 * We are executing a single threaded invoke but the single step for
1923 * suspending is still active.
1924 * FIXME: This slows down single threaded invokes.
1926 DEBUG(1, fprintf (log_file, "[%p] Ignored during single threaded invoke.\n", (gpointer)GetCurrentThreadId ()));
1930 ji = mono_jit_info_table_find (mono_domain_get (), (char*)ip);
1932 /* Can't suspend in these methods */
1933 if (ji->method->klass == mono_defaults.string_class && (!strcmp (ji->method->name, "memset") || strstr (ji->method->name, "memcpy")))
1936 save_thread_context (ctx);
1944 * Increase the suspend count of the VM. While the suspend count is greater
1945 * than 0, runtime threads are suspended at certain points during execution.
1950 mono_loader_lock ();
1952 mono_mutex_lock (&suspend_mutex);
1956 DEBUG(1, fprintf (log_file, "[%p] Suspending vm...\n", (gpointer)GetCurrentThreadId ()));
1958 if (suspend_count == 1) {
1959 // FIXME: Is it safe to call this inside the lock ?
1960 start_single_stepping ();
1961 mono_g_hash_table_foreach (thread_to_tls, notify_thread, NULL);
1964 mono_mutex_unlock (&suspend_mutex);
1966 mono_loader_unlock ();
1972 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
1980 g_assert (debugger_thread_id == GetCurrentThreadId ());
1982 mono_loader_lock ();
1984 mono_mutex_lock (&suspend_mutex);
1986 g_assert (suspend_count > 0);
1989 DEBUG(1, fprintf (log_file, "[%p] Resuming vm...\n", (gpointer)GetCurrentThreadId ()));
1991 if (suspend_count == 0) {
1992 // FIXME: Is it safe to call this inside the lock ?
1993 stop_single_stepping ();
1994 mono_g_hash_table_foreach (thread_to_tls, reset_native_thread_suspend_state, NULL);
1997 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
1998 err = mono_cond_broadcast (&suspend_cond);
1999 g_assert (err == 0);
2001 mono_mutex_unlock (&suspend_mutex);
2002 //g_assert (err == 0);
2004 mono_loader_unlock ();
2010 * Resume just one thread.
2013 resume_thread (MonoInternalThread *thread)
2016 DebuggerTlsData *tls;
2018 g_assert (debugger_thread_id == GetCurrentThreadId ());
2020 mono_loader_lock ();
2022 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
2025 mono_mutex_lock (&suspend_mutex);
2027 g_assert (suspend_count > 0);
2029 DEBUG(1, fprintf (log_file, "[%p] Resuming thread...\n", (gpointer)(gssize)thread->tid));
2031 tls->resume_count += suspend_count;
2034 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2035 * but only the one whose resume_count field is > 0 will be resumed.
2037 err = mono_cond_broadcast (&suspend_cond);
2038 g_assert (err == 0);
2040 mono_mutex_unlock (&suspend_mutex);
2041 //g_assert (err == 0);
2043 mono_loader_unlock ();
2047 invalidate_frames (DebuggerTlsData *tls)
2052 tls = TlsGetValue (debugger_tls_id);
2055 for (i = 0; i < tls->frame_count; ++i) {
2056 if (tls->frames [i]->jit)
2057 mono_debug_free_method_jit_info (tls->frames [i]->jit);
2058 g_free (tls->frames [i]);
2060 g_free (tls->frames);
2061 tls->frame_count = 0;
2068 * Suspend the current thread until the runtime is resumed. If the thread has a
2069 * pending invoke, then the invoke is executed before this function returns.
2072 suspend_current (void)
2075 DebuggerTlsData *tls;
2077 g_assert (debugger_thread_id != GetCurrentThreadId ());
2079 if (mono_loader_lock_is_owned_by_self ()) {
2081 * If we own the loader mutex, can't suspend until we release it, since the
2082 * whole runtime can deadlock otherwise.
2087 tls = TlsGetValue (debugger_tls_id);
2090 mono_mutex_lock (&suspend_mutex);
2092 tls->suspending = FALSE;
2093 tls->really_suspended = TRUE;
2095 if (!tls->suspended) {
2096 tls->suspended = TRUE;
2097 MONO_SEM_POST (&suspend_sem);
2100 DEBUG(1, fprintf (log_file, "[%p] Suspended.\n", (gpointer)GetCurrentThreadId ()));
2102 while (suspend_count - tls->resume_count > 0) {
2104 if (WAIT_TIMEOUT == WaitForSingleObject(suspend_cond, 0))
2106 mono_mutex_unlock (&suspend_mutex);
2108 mono_mutex_lock (&suspend_mutex);
2114 err = mono_cond_wait (&suspend_cond, &suspend_mutex);
2115 g_assert (err == 0);
2119 tls->suspended = FALSE;
2120 tls->really_suspended = FALSE;
2122 threads_suspend_count --;
2124 mono_mutex_unlock (&suspend_mutex);
2126 DEBUG(1, fprintf (log_file, "[%p] Resumed.\n", (gpointer)GetCurrentThreadId ()));
2129 /* Save the original context */
2130 tls->invoke->has_ctx = TRUE;
2131 memcpy (&tls->invoke->ctx, &tls->ctx, sizeof (MonoContext));
2136 /* The frame info becomes invalid after a resume */
2137 tls->has_context = FALSE;
2138 tls->has_async_ctx = FALSE;
2139 invalidate_frames (NULL);
2143 count_thread (gpointer key, gpointer value, gpointer user_data)
2145 DebuggerTlsData *tls = value;
2147 if (!tls->suspended && !tls->terminated)
2148 *(int*)user_data = *(int*)user_data + 1;
2152 count_threads_to_wait_for (void)
2156 mono_loader_lock ();
2157 mono_g_hash_table_foreach (thread_to_tls, count_thread, &count);
2158 mono_loader_unlock ();
2166 * Wait until the runtime is completely suspended.
2169 wait_for_suspend (void)
2171 int nthreads, nwait, err;
2172 gboolean waited = FALSE;
2174 // FIXME: Threads starting/stopping ?
2175 mono_loader_lock ();
2176 nthreads = mono_g_hash_table_size (thread_to_tls);
2177 mono_loader_unlock ();
2180 nwait = count_threads_to_wait_for ();
2182 DEBUG(1, fprintf (log_file, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads));
2183 err = MONO_SEM_WAIT (&suspend_sem);
2184 g_assert (err == 0);
2192 DEBUG(1, fprintf (log_file, "%d threads suspended.\n", nthreads));
2198 * Return whenever the runtime is suspended.
2203 return count_threads_to_wait_for () == 0;
2207 * compute_il_offset:
2209 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2210 * a location of a sequence point.
2211 * We use this function instead of mono_debug_il_offset_from_address () etc,
2212 * which doesn't seem to work in a lot of cases.
2215 compute_il_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
2217 GPtrArray *seq_points;
2218 int i, last_il_offset, seq_il_offset, seq_native_offset;
2220 mono_domain_lock (domain);
2221 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
2222 mono_domain_unlock (domain);
2223 g_assert (seq_points);
2225 last_il_offset = -1;
2227 /* Find the sequence point */
2228 for (i = 0; i < seq_points->len; i += 2) {
2229 seq_il_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i));
2230 seq_native_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i + 1));
2232 if (seq_native_offset > native_offset)
2234 last_il_offset = seq_il_offset;
2237 return last_il_offset;
2241 DebuggerTlsData *tls;
2243 } ComputeFramesUserData;
2246 process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
2248 ComputeFramesUserData *ud = user_data;
2252 if (info->type != FRAME_TYPE_MANAGED) {
2253 if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
2254 /* Mark the last frame as an invoke frame */
2256 ((StackFrame*)ud->frames->data)->flags |= FRAME_FLAG_DEBUGGER_INVOKE;
2262 method = info->ji->method;
2264 method = info->method;
2266 if (!method || (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD))
2269 if (info->il_offset == -1) {
2270 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2271 info->il_offset = mono_debug_il_offset_from_address (method, info->domain, info->native_offset);
2274 DEBUG (1, fprintf (stderr, "\tFrame: %s %d %d %d\n", mono_method_full_name (method, TRUE), info->native_offset, info->il_offset, info->managed));
2276 if (!info->managed && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD) {
2278 * mono_arch_find_jit_info () returns the context stored in the LMF for
2279 * native frames, but it should unwind once. This is why we have duplicate
2280 * frames on the stack sometimes.
2281 * !managed also seems to be set for dynamic methods.
2286 frame = g_new0 (StackFrame, 1);
2287 frame->method = method;
2288 frame->il_offset = info->il_offset;
2291 frame->has_ctx = TRUE;
2293 frame->domain = info->domain;
2295 ud->frames = g_slist_append (ud->frames, frame);
2301 compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls)
2303 ComputeFramesUserData user_data;
2305 int i, findex, new_frame_count;
2306 StackFrame **new_frames, *f;
2308 // FIXME: Locking on tls
2309 if (tls->frames && tls->frames_up_to_date)
2312 DEBUG(1, fprintf (log_file, "Frames for %p(tid=%lx):\n", thread, (glong)thread->tid));
2314 user_data.tls = tls;
2315 user_data.frames = NULL;
2316 if (tls->terminated) {
2317 tls->frame_count = 0;
2319 } if (!tls->really_suspended && tls->has_async_ctx) {
2320 /* Have to use the state saved by the signal handler */
2321 process_frame (&tls->async_last_frame, NULL, &user_data);
2322 mono_jit_walk_stack_from_ctx_in_thread (process_frame, tls->domain, &tls->async_ctx, FALSE, thread, tls->async_lmf, &user_data);
2323 } else if (tls->has_context) {
2324 mono_jit_walk_stack_from_ctx_in_thread (process_frame, tls->domain, &tls->ctx, FALSE, thread, tls->lmf, &user_data);
2327 tls->frame_count = 0;
2331 new_frame_count = g_slist_length (user_data.frames);
2332 new_frames = g_new0 (StackFrame*, new_frame_count);
2334 for (tmp = user_data.frames; tmp; tmp = tmp->next) {
2338 * Reuse the id for already existing stack frames, so invokes don't invalidate
2339 * the still valid stack frames.
2341 for (i = 0; i < tls->frame_count; ++i) {
2342 if (MONO_CONTEXT_GET_SP (&tls->frames [i]->ctx) == MONO_CONTEXT_GET_SP (&f->ctx)) {
2343 f->id = tls->frames [i]->id;
2348 if (i >= tls->frame_count)
2349 f->id = InterlockedIncrement (&frame_id);
2351 new_frames [findex ++] = f;
2354 g_slist_free (user_data.frames);
2356 invalidate_frames (tls);
2358 tls->frames = new_frames;
2359 tls->frame_count = new_frame_count;
2360 tls->frames_up_to_date = TRUE;
2368 * create_event_list:
2370 * Return a list of event request ids matching EVENT, starting from REQS, which
2371 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2373 * We return request ids, instead of requests, to simplify threading, since
2374 * requests could be deleted anytime when the loader lock is not held.
2375 * LOCKING: Assumes the loader lock is held.
2378 create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, MonoException *exc, int *suspend_policy)
2381 GSList *events = NULL;
2383 *suspend_policy = SUSPEND_POLICY_NONE;
2386 reqs = event_requests;
2391 for (i = 0; i < reqs->len; ++i) {
2392 EventRequest *req = g_ptr_array_index (reqs, i);
2393 if (req->event_kind == event) {
2394 gboolean filtered = FALSE;
2397 for (j = 0; j < req->nmodifiers; ++j) {
2398 Modifier *mod = &req->modifiers [j];
2400 if (mod->kind == MOD_KIND_COUNT) {
2402 if (mod->data.count > 0) {
2403 if (mod->data.count > 0) {
2405 if (mod->data.count == 0)
2409 } else if (mod->kind == MOD_KIND_THREAD_ONLY) {
2410 if (mod->data.thread != mono_thread_internal_current ())
2412 } else if (mod->kind == MOD_KIND_EXCEPTION_ONLY && exc) {
2413 if (mod->data.exc_class && !mono_class_is_assignable_from (mod->data.exc_class, exc->object.vtable->klass))
2415 } else if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && ji) {
2417 gboolean found = FALSE;
2418 MonoAssembly **assemblies = mod->data.assemblies;
2421 for (k = 0; assemblies [k]; ++k)
2422 if (assemblies [k] == ji->method->klass->image->assembly)
2431 *suspend_policy = MAX (*suspend_policy, req->suspend_policy);
2432 events = g_slist_append (events, GINT_TO_POINTER (req->id));
2437 /* Send a VM START/DEATH event by default */
2438 if (event == EVENT_KIND_VM_START)
2439 events = g_slist_append (events, GINT_TO_POINTER (0));
2440 if (event == EVENT_KIND_VM_DEATH)
2441 events = g_slist_append (events, GINT_TO_POINTER (0));
2446 static G_GNUC_UNUSED const char*
2447 event_to_string (EventKind event)
2450 case EVENT_KIND_VM_START: return "VM_START";
2451 case EVENT_KIND_VM_DEATH: return "VM_DEATH";
2452 case EVENT_KIND_THREAD_START: return "THREAD_START";
2453 case EVENT_KIND_THREAD_DEATH: return "THREAD_DEATH";
2454 case EVENT_KIND_APPDOMAIN_CREATE: return "APPDOMAIN_CREATE";
2455 case EVENT_KIND_APPDOMAIN_UNLOAD: return "APPDOMAIN_UNLOAD";
2456 case EVENT_KIND_METHOD_ENTRY: return "METHOD_ENTRY";
2457 case EVENT_KIND_METHOD_EXIT: return "METHOD_EXIT";
2458 case EVENT_KIND_ASSEMBLY_LOAD: return "ASSEMBLY_LOAD";
2459 case EVENT_KIND_ASSEMBLY_UNLOAD: return "ASSEMBLY_UNLOAD";
2460 case EVENT_KIND_BREAKPOINT: return "BREAKPOINT";
2461 case EVENT_KIND_STEP: return "STEP";
2462 case EVENT_KIND_TYPE_LOAD: return "TYPE_LOAD";
2463 case EVENT_KIND_EXCEPTION: return "EXCEPTION";
2465 g_assert_not_reached ();
2472 * Send an event to the client, suspending the vm if needed.
2473 * LOCKING: Since this can suspend the calling thread, no locks should be held
2475 * The EVENTS list is freed by this function.
2478 process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx, GSList *events, int suspend_policy)
2482 MonoDomain *domain = mono_domain_get ();
2488 if (!vm_start_event_sent && event != EVENT_KIND_VM_START)
2489 // FIXME: We miss those events
2492 if (vm_death_event_sent)
2495 if (mono_runtime_is_shutting_down () && event != EVENT_KIND_VM_DEATH)
2504 if (debugger_thread_id == GetCurrentThreadId () && event != EVENT_KIND_VM_DEATH)
2505 // FIXME: Send these with a NULL thread, don't suspend the current thread
2508 buffer_init (&buf, 128);
2509 buffer_add_byte (&buf, suspend_policy);
2510 buffer_add_int (&buf, g_slist_length (events)); // n of events
2512 for (l = events; l; l = l->next) {
2513 buffer_add_byte (&buf, event); // event kind
2514 buffer_add_int (&buf, GPOINTER_TO_INT (l->data)); // request id
2516 thread = mono_thread_current ();
2518 if (event == EVENT_KIND_VM_START)
2520 else if (event == EVENT_KIND_THREAD_START)
2521 g_assert (mono_thread_internal_current () == arg);
2523 buffer_add_objid (&buf, (MonoObject*)thread); // thread
2526 case EVENT_KIND_THREAD_START:
2527 case EVENT_KIND_THREAD_DEATH:
2529 case EVENT_KIND_APPDOMAIN_CREATE:
2530 case EVENT_KIND_APPDOMAIN_UNLOAD:
2531 buffer_add_domainid (&buf, arg);
2533 case EVENT_KIND_METHOD_ENTRY:
2534 case EVENT_KIND_METHOD_EXIT:
2535 buffer_add_methodid (&buf, domain, arg);
2537 case EVENT_KIND_ASSEMBLY_LOAD:
2538 case EVENT_KIND_ASSEMBLY_UNLOAD:
2539 buffer_add_assemblyid (&buf, domain, arg);
2541 case EVENT_KIND_TYPE_LOAD:
2542 buffer_add_typeid (&buf, domain, arg);
2544 case EVENT_KIND_BREAKPOINT:
2545 case EVENT_KIND_STEP:
2546 buffer_add_methodid (&buf, domain, arg);
2547 buffer_add_long (&buf, il_offset);
2549 case EVENT_KIND_VM_START:
2550 buffer_add_domainid (&buf, mono_get_root_domain ());
2552 case EVENT_KIND_VM_DEATH:
2554 case EVENT_KIND_EXCEPTION:
2555 buffer_add_objid (&buf, (MonoObject*)arg);
2558 g_assert_not_reached ();
2562 if (event == EVENT_KIND_VM_START) {
2563 suspend_policy = agent_config.suspend ? SUSPEND_POLICY_ALL : SUSPEND_POLICY_NONE;
2564 start_debugger_thread ();
2567 if (event == EVENT_KIND_VM_DEATH) {
2568 vm_death_event_sent = TRUE;
2570 suspend_policy = SUSPEND_POLICY_NONE;
2573 if (mono_runtime_is_shutting_down ())
2574 suspend_policy = SUSPEND_POLICY_NONE;
2576 if (suspend_policy != SUSPEND_POLICY_NONE) {
2578 * Save the thread context and start suspending before sending the packet,
2579 * since we could be receiving the resume request before send_packet ()
2582 save_thread_context (ctx);
2586 send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf);
2588 g_slist_free (events);
2591 if (event == EVENT_KIND_VM_START)
2592 vm_start_event_sent = TRUE;
2594 DEBUG (1, fprintf (log_file, "[%p] Sent event %s, suspend=%d.\n", (gpointer)GetCurrentThreadId (), event_to_string (event), suspend_policy));
2598 switch (suspend_policy) {
2599 case SUSPEND_POLICY_NONE:
2601 case SUSPEND_POLICY_ALL:
2604 case SUSPEND_POLICY_EVENT_THREAD:
2608 g_assert_not_reached ();
2613 process_profiler_event (EventKind event, gpointer arg)
2618 mono_loader_lock ();
2619 events = create_event_list (event, NULL, NULL, NULL, &suspend_policy);
2620 mono_loader_unlock ();
2622 process_event (event, arg, 0, NULL, events, suspend_policy);
2626 runtime_initialized (MonoProfiler *prof)
2628 process_profiler_event (EVENT_KIND_VM_START, mono_thread_current ());
2632 runtime_shutdown (MonoProfiler *prof)
2634 process_profiler_event (EVENT_KIND_VM_DEATH, mono_thread_current ());
2636 mono_debugger_agent_cleanup ();
2640 thread_startup (MonoProfiler *prof, gsize tid)
2642 MonoInternalThread *thread = mono_thread_internal_current ();
2643 MonoInternalThread *old_thread;
2644 DebuggerTlsData *tls;
2646 if (tid == debugger_thread_id)
2649 g_assert (thread->tid == tid);
2651 mono_loader_lock ();
2652 old_thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid);
2653 mono_loader_unlock ();
2655 if (thread == old_thread) {
2657 * For some reason, thread_startup () might be called for the same thread
2658 * multiple times (attach ?).
2660 DEBUG (1, fprintf (log_file, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer)tid, (gpointer)tid));
2664 * thread_end () might not be called for some threads, and the tid could
2667 DEBUG (1, fprintf (log_file, "[%p] Removing stale data for tid %p.\n", (gpointer)tid, (gpointer)tid));
2668 mono_loader_lock ();
2669 mono_g_hash_table_remove (thread_to_tls, old_thread);
2670 mono_g_hash_table_remove (tid_to_thread, (gpointer)tid);
2671 mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid);
2672 mono_loader_unlock ();
2676 tls = TlsGetValue (debugger_tls_id);
2678 // FIXME: Free this somewhere
2679 tls = g_new0 (DebuggerTlsData, 1);
2680 tls->resume_event = CreateEvent (NULL, FALSE, FALSE, NULL);
2681 MONO_GC_REGISTER_ROOT (tls->thread);
2682 tls->thread = thread;
2683 TlsSetValue (debugger_tls_id, tls);
2685 DEBUG (1, fprintf (log_file, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls));
2687 mono_loader_lock ();
2688 mono_g_hash_table_insert (thread_to_tls, thread, tls);
2689 mono_g_hash_table_insert (tid_to_thread, (gpointer)tid, thread);
2690 mono_g_hash_table_insert (tid_to_thread_obj, (gpointer)tid, mono_thread_current ());
2691 mono_loader_unlock ();
2693 process_profiler_event (EVENT_KIND_THREAD_START, thread);
2696 * suspend_vm () could have missed this thread, so wait for a resume.
2702 thread_end (MonoProfiler *prof, gsize tid)
2704 MonoInternalThread *thread;
2705 DebuggerTlsData *tls = NULL;
2707 mono_loader_lock ();
2708 thread = mono_g_hash_table_lookup (tid_to_thread, (gpointer)tid);
2710 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
2711 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2712 tls->terminated = TRUE;
2713 mono_g_hash_table_remove (tid_to_thread_obj, (gpointer)tid);
2714 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2715 MONO_GC_UNREGISTER_ROOT (tls->thread);
2718 mono_loader_unlock ();
2720 /* We might be called for threads started before we registered the start callback */
2722 DEBUG (1, fprintf (log_file, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls));
2723 process_profiler_event (EVENT_KIND_THREAD_DEATH, thread);
2728 appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result)
2730 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE, domain);
2734 appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
2736 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD, domain);
2740 assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result)
2742 /* Sent later in jit_end () */
2743 mono_loader_lock ();
2744 g_ptr_array_add (pending_assembly_loads, assembly);
2745 mono_loader_unlock ();
2749 assembly_unload (MonoProfiler *prof, MonoAssembly *assembly)
2751 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
2755 start_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
2757 #if defined(HOST_WIN32) && !defined(__GNUC__)
2758 gpointer stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));
2760 gpointer stackptr = __builtin_frame_address (1);
2762 MonoInternalThread *thread = mono_thread_internal_current ();
2763 DebuggerTlsData *tls;
2765 mono_loader_lock ();
2767 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
2768 /* Could be the debugger thread with assembly/type load hooks */
2770 tls->invoke_addr = stackptr;
2772 mono_loader_unlock ();
2776 end_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
2779 #if defined(HOST_WIN32) && !defined(__GNUC__)
2780 gpointer stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));
2782 gpointer stackptr = __builtin_frame_address (1);
2785 if (ss_req == NULL || stackptr != ss_invoke_addr || ss_req->thread != mono_thread_internal_current ())
2789 * We need to stop single stepping when exiting a runtime invoke, since if it is
2790 * a step out, it may return to native code, and thus never end.
2792 mono_loader_lock ();
2793 ss_invoke_addr = NULL;
2795 for (i = 0; i < event_requests->len; ++i) {
2796 EventRequest *req = g_ptr_array_index (event_requests, i);
2798 if (req->event_kind == EVENT_KIND_STEP) {
2800 g_ptr_array_remove_index_fast (event_requests, i);
2805 mono_loader_unlock ();
2809 jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result)
2812 * We emit type load events when the first method of the type is JITted,
2813 * since the class load profiler callbacks might be called with the
2814 * loader lock held. They could also occur in the debugger thread.
2815 * Same for assembly load events.
2817 gboolean type_load = FALSE;
2820 MonoAssembly *assembly = NULL;
2822 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
2823 mono_loader_lock ();
2824 if (pending_assembly_loads->len > 0) {
2825 assembly = g_ptr_array_index (pending_assembly_loads, 0);
2826 g_ptr_array_remove_index (pending_assembly_loads, 0);
2828 mono_loader_unlock ();
2831 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly);
2836 mono_loader_lock ();
2837 if (!g_hash_table_lookup (loaded_classes, method->klass)) {
2839 g_hash_table_insert (loaded_classes, method->klass, method->klass);
2841 mono_loader_unlock ();
2843 process_profiler_event (EVENT_KIND_TYPE_LOAD, method->klass);
2846 add_pending_breakpoints (method, jinfo);
2850 * BREAKPOINTS/SINGLE STEPPING
2854 * Contains information about an inserted breakpoint.
2857 long il_offset, native_offset;
2859 gboolean pending, entry;
2861 } BreakpointInstance;
2864 * Contains generic information about a breakpoint.
2868 * The method where the breakpoint is placed. Can be NULL in which case it
2869 * is inserted into every method. This is used to implement method entry/
2870 * exit events. Can be a generic method definition, in which case the
2871 * breakpoint is inserted into every instance.
2875 gboolean pending, entry;
2878 * A list of BreakpointInstance structures describing where the breakpoint
2879 * was inserted. There could be more than one because of
2880 * generics/appdomains/method entry/exit.
2882 GPtrArray *children;
2885 /* List of breakpoints */
2886 static GPtrArray *breakpoints;
2887 /* Maps breakpoint locations to the number of breakpoints at that location */
2888 static GHashTable *bp_locs;
2891 breakpoints_init (void)
2893 breakpoints = g_ptr_array_new ();
2894 bp_locs = g_hash_table_new (NULL, NULL);
2898 breakpoints_cleanup (void)
2902 mono_loader_lock ();
2904 for (i = 0; i < breakpoints->len; ++i)
2905 g_free (g_ptr_array_index (breakpoints, i));
2907 g_ptr_array_free (breakpoints, TRUE);
2908 g_hash_table_destroy (bp_locs);
2910 mono_loader_unlock ();
2914 * insert_breakpoint:
2916 * Insert the breakpoint described by BP into the method described by
2920 insert_breakpoint (GPtrArray *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
2923 gint32 il_offset, native_offset;
2924 BreakpointInstance *inst;
2927 for (i = 0; i < seq_points->len; i += 2) {
2928 il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
2929 native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
2931 if (il_offset == bp->il_offset)
2935 if (i == seq_points->len)
2936 /* Have to handle this somehow */
2939 inst = g_new0 (BreakpointInstance, 1);
2940 inst->native_offset = native_offset;
2941 inst->ip = (guint8*)ji->code_start + native_offset;
2944 mono_loader_lock ();
2946 g_ptr_array_add (bp->children, inst);
2948 count = GPOINTER_TO_INT (g_hash_table_lookup (bp_locs, inst->ip));
2949 g_hash_table_insert (bp_locs, inst->ip, GINT_TO_POINTER (count + 1));
2950 mono_loader_unlock ();
2953 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
2954 mono_arch_set_breakpoint (ji, inst->ip);
2962 remove_breakpoint (BreakpointInstance *inst)
2964 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
2966 MonoJitInfo *ji = inst->ji;
2967 guint8 *ip = inst->ip;
2969 mono_loader_lock ();
2970 count = GPOINTER_TO_INT (g_hash_table_lookup (bp_locs, ip));
2971 g_hash_table_insert (bp_locs, ip, GINT_TO_POINTER (count - 1));
2972 mono_loader_unlock ();
2974 g_assert (count > 0);
2977 mono_arch_clear_breakpoint (ji, ip);
2985 * add_pending_breakpoints:
2987 * Insert pending breakpoints into the newly JITted method METHOD.
2990 add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
2993 GPtrArray *seq_points;
2999 domain = mono_domain_get ();
3001 mono_loader_lock ();
3003 for (i = 0; i < breakpoints->len; ++i) {
3004 MonoBreakpoint *bp = g_ptr_array_index (breakpoints, i);
3006 if (bp->pending && (bp->method == method || !bp->method || (method->is_inflated && ((MonoMethodInflated*)method)->declaring == bp->method))) {
3007 mono_domain_lock (domain);
3008 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, ji->method);
3009 mono_domain_unlock (domain);
3011 /* Could be AOT code */
3013 g_assert (seq_points);
3015 insert_breakpoint (seq_points, ji, bp);
3019 mono_loader_unlock ();
3023 set_bp_in_method (MonoDomain *domain, MonoMethod *method, GPtrArray *seq_points, MonoBreakpoint *bp)
3028 code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
3030 /* Might be AOTed code */
3031 code = mono_aot_get_method (domain, method);
3033 ji = mono_jit_info_table_find (domain, code);
3038 insert_breakpoint (seq_points, ji, bp);
3042 set_bp_in_method_cb (gpointer key, gpointer value, gpointer user_data)
3044 MonoMethod *method = key;
3045 GPtrArray *seq_points = value;
3046 MonoBreakpoint *bp = user_data;
3047 MonoDomain *domain = mono_domain_get ();
3050 if (method->is_inflated && ((MonoMethodInflated*)method)->declaring == bp->method) {
3051 /* Generic instance */
3052 set_bp_in_method (domain, method, seq_points, bp);
3055 /* Method entry/exit */
3056 set_bp_in_method (domain, method, seq_points, bp);
3063 * Set a breakpoint at IL_OFFSET in METHOD.
3064 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3065 * METHOD can also be a generic method definition, in which case a breakpoint
3066 * is placed in all instances of the method.
3068 static MonoBreakpoint*
3069 set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req)
3071 GPtrArray *seq_points;
3076 // - suspend/resume the vm to prevent code patching problems
3078 // - multiple breakpoints on the same location
3079 // - dynamic methods
3082 bp = g_new0 (MonoBreakpoint, 1);
3083 bp->method = method;
3084 bp->il_offset = il_offset;
3086 bp->children = g_ptr_array_new ();
3088 DEBUG(1, fprintf (log_file, "[dbg] Setting breakpoint at %s:0x%x.\n", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
3090 domain = mono_domain_get ();
3091 mono_domain_lock (domain);
3093 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
3095 set_bp_in_method (domain, method, seq_points, bp);
3097 if (method->is_generic)
3098 /* There might be already JITted instances */
3099 g_hash_table_foreach (domain_jit_info (domain)->seq_points, set_bp_in_method_cb, bp);
3101 /* Not yet JITted */
3105 g_hash_table_foreach (domain_jit_info (domain)->seq_points, set_bp_in_method_cb, bp);
3108 mono_domain_unlock (domain);
3110 mono_loader_lock ();
3111 g_ptr_array_add (breakpoints, bp);
3112 mono_loader_unlock ();
3118 clear_breakpoint (MonoBreakpoint *bp)
3122 // FIXME: locking, races
3123 for (i = 0; i < bp->children->len; ++i) {
3124 BreakpointInstance *inst = g_ptr_array_index (bp->children, i);
3126 remove_breakpoint (inst);
3131 mono_loader_lock ();
3132 g_ptr_array_remove (breakpoints, bp);
3133 mono_loader_unlock ();
3135 g_ptr_array_free (bp->children, TRUE);
3140 process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
3143 guint8 *orig_ip, *ip;
3144 int i, j, suspend_policy;
3145 guint32 native_offset;
3147 BreakpointInstance *inst;
3149 GSList *events = NULL;
3150 EventKind kind = EVENT_KIND_BREAKPOINT;
3152 // FIXME: Speed this up
3154 orig_ip = ip = MONO_CONTEXT_GET_IP (ctx);
3155 ji = mono_jit_info_table_find (mono_domain_get (), (char*)ip);
3157 g_assert (ji->method);
3159 /* Compute the native offset of the breakpoint from the ip */
3160 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3161 ip = mono_arch_get_ip_for_breakpoint (ji, ctx);
3162 native_offset = ip - (guint8*)ji->code_start;
3168 * Skip the instruction causing the breakpoint signal.
3170 mono_arch_skip_breakpoint (ctx);
3172 if (ji->method->wrapper_type || tls->disable_breakpoints)
3175 reqs = g_ptr_array_new ();
3177 DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, native_offset));
3179 mono_loader_lock ();
3182 for (i = 0; i < breakpoints->len; ++i) {
3183 bp = g_ptr_array_index (breakpoints, i);
3188 for (j = 0; j < bp->children->len; ++j) {
3189 inst = g_ptr_array_index (bp->children, j);
3190 if (inst->ji == ji && inst->native_offset == native_offset)
3191 g_ptr_array_add (reqs, bp->req);
3194 if (reqs->len == 0) {
3195 GPtrArray *seq_points;
3196 int seq_il_offset, seq_native_offset;
3197 MonoDomain *domain = mono_domain_get ();
3199 /* Maybe a method entry/exit event */
3200 mono_domain_lock (domain);
3201 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, ji->method);
3202 mono_domain_unlock (domain);
3204 // FIXME: Generic sharing */
3205 mono_loader_unlock ();
3208 g_assert (seq_points);
3210 for (i = 0; i < seq_points->len; i += 2) {
3211 seq_il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
3212 seq_native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
3214 if (native_offset == seq_native_offset) {
3215 if (seq_il_offset == METHOD_ENTRY_IL_OFFSET)
3216 kind = EVENT_KIND_METHOD_ENTRY;
3217 else if (seq_il_offset == METHOD_EXIT_IL_OFFSET)
3218 kind = EVENT_KIND_METHOD_EXIT;
3225 events = create_event_list (EVENT_KIND_BREAKPOINT, reqs, ji, NULL, &suspend_policy);
3226 else if (kind != EVENT_KIND_BREAKPOINT)
3227 events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
3229 g_ptr_array_free (reqs, TRUE);
3231 mono_loader_unlock ();
3234 process_event (kind, ji->method, 0, ctx, events, suspend_policy);
3238 process_breakpoint (void)
3240 DebuggerTlsData *tls;
3242 static void (*restore_context) (void *);
3244 if (!restore_context)
3245 restore_context = mono_get_restore_context ();
3247 tls = TlsGetValue (debugger_tls_id);
3248 memcpy (&ctx, &tls->handler_ctx, sizeof (MonoContext));
3250 process_breakpoint_inner (tls, &ctx);
3252 /* This is called when resuming from a signal handler, so it shouldn't return */
3253 restore_context (&ctx);
3254 g_assert_not_reached ();
3258 resume_from_signal_handler (void *sigctx, void *func)
3260 DebuggerTlsData *tls;
3263 /* Save the original context in TLS */
3264 // FIXME: This might not work on an altstack ?
3265 tls = TlsGetValue (debugger_tls_id);
3268 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3269 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3270 // clob:c could be added to op_seq_point.
3272 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
3273 memcpy (&tls->handler_ctx, &ctx, sizeof (MonoContext));
3274 MONO_CONTEXT_SET_IP (&ctx, func);
3276 mono_arch_monoctx_to_sigctx (&ctx, sigctx);
3280 mono_debugger_agent_breakpoint_hit (void *sigctx)
3283 * We are called from a signal handler, and running code there causes all kinds of
3284 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3285 * So set up the signal context to return to the real breakpoint handler function.
3288 resume_from_signal_handler (sigctx, process_breakpoint);
3292 process_single_step_inner (DebuggerTlsData *tls, MonoContext *ctx)
3297 int il_offset, suspend_policy;
3298 MonoDomain *domain = mono_domain_get ();
3301 // FIXME: Speed this up
3303 ip = MONO_CONTEXT_GET_IP (ctx);
3305 /* Skip the instruction causing the single step */
3306 mono_arch_skip_single_step (ctx);
3308 if (suspend_count > 0) {
3309 process_suspend (tls, ctx);
3314 // FIXME: A suspend race
3317 if (mono_thread_internal_current () != ss_req->thread)
3320 if (log_level > 0) {
3321 const char *depth = NULL;
3323 ji = mono_jit_info_table_find (mono_domain_get (), (char*)ip);
3325 switch (ss_req->depth) {
3326 case STEP_DEPTH_OVER:
3329 case STEP_DEPTH_OUT:
3332 case STEP_DEPTH_INTO:
3336 g_assert_not_reached ();
3339 DEBUG (1, fprintf (log_file, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer)GetCurrentThreadId (), ss_req->depth == STEP_DEPTH_OVER ? "over" : "out", mono_method_full_name (ji->method, TRUE), MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp));
3343 * We implement step over/out by single stepping until we reach the same
3344 * frame/parent frame.
3347 * - stack growing upward
3351 if (ss_req->depth != STEP_DEPTH_INTO) {
3352 if (ss_req->depth == STEP_DEPTH_OVER && MONO_CONTEXT_GET_SP (ctx) < ss_req->last_sp)
3354 if (ss_req->depth == STEP_DEPTH_OUT && MONO_CONTEXT_GET_SP (ctx) <= ss_req->last_sp)
3357 ss_req->last_sp = MONO_CONTEXT_GET_SP (ctx);
3360 ji = mono_jit_info_table_find (mono_domain_get (), (char*)ip);
3362 g_assert (ji->method);
3364 if (ji->method->wrapper_type && ji->method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
3369 * Stopping in memset makes half-initialized vtypes visible.
3370 * Stopping in memcpy makes half-copied vtypes visible.
3372 if (ji->method->klass == mono_defaults.string_class && (!strcmp (ji->method->name, "memset") || strstr (ji->method->name, "memcpy")))
3376 * The ip points to the instruction causing the single step event, convert it
3377 * to the offset stored in seq_points.
3379 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3380 ip = mono_arch_get_ip_for_single_step (ji, ctx);
3382 g_assert_not_reached ();
3386 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3387 * example, so do things by hand.
3389 il_offset = compute_il_offset (domain, ji->method, (guint8*)ip - (guint8*)ji->code_start);
3391 if (il_offset == -1)
3394 if (ss_req->size == STEP_SIZE_LINE) {
3395 /* Step until a different source line is reached */
3396 MonoDebugMethodInfo *minfo;
3398 minfo = mono_debug_lookup_method (ji->method);
3401 MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, il_offset);
3403 if (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line) {
3404 mono_debug_free_source_location (loc);
3409 * Step until we reach a location with line number info,
3410 * otherwise the client can't show a location.
3411 * This can happen for example with statics initialized inline
3412 * outside of a cctor.
3417 ss_req->last_method = ji->method;
3418 ss_req->last_line = loc->row;
3419 mono_debug_free_source_location (loc);
3424 // FIXME: Has to lock earlier
3426 reqs = g_ptr_array_new ();
3428 mono_loader_lock ();
3430 g_ptr_array_add (reqs, ss_req->req);
3432 events = create_event_list (EVENT_KIND_STEP, reqs, ji, NULL, &suspend_policy);
3434 g_ptr_array_free (reqs, TRUE);
3436 mono_loader_unlock ();
3438 process_event (EVENT_KIND_STEP, ji->method, il_offset, ctx, events, suspend_policy);
3442 process_single_step (void)
3444 DebuggerTlsData *tls;
3446 static void (*restore_context) (void *);
3448 if (!restore_context)
3449 restore_context = mono_get_restore_context ();
3451 tls = TlsGetValue (debugger_tls_id);
3452 memcpy (&ctx, &tls->handler_ctx, sizeof (MonoContext));
3454 process_single_step_inner (tls, &ctx);
3456 /* This is called when resuming from a signal handler, so it shouldn't return */
3457 restore_context (&ctx);
3458 g_assert_not_reached ();
3462 * mono_debugger_agent_single_step_event:
3464 * Called from a signal handler to handle a single step event.
3467 mono_debugger_agent_single_step_event (void *sigctx)
3469 /* Resume to process_single_step through the signal context */
3471 // FIXME: Since step out/over is implemented using step in, the step in case should
3472 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3475 if (GetCurrentThreadId () == debugger_thread_id) {
3477 * This could happen despite our best effors when the runtime calls
3478 * assembly/type resolve hooks.
3479 * FIXME: Breakpoints too.
3483 mono_arch_sigctx_to_monoctx (sigctx, &ctx);
3484 mono_arch_skip_single_step (&ctx);
3485 mono_arch_monoctx_to_sigctx (&ctx, sigctx);
3489 resume_from_signal_handler (sigctx, process_single_step);
3493 * start_single_stepping:
3495 * Turn on single stepping. Can be called multiple times, for example,
3496 * by a single step event request + a suspend.
3499 start_single_stepping (void)
3501 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3502 int val = InterlockedIncrement (&ss_count);
3505 mono_arch_start_single_stepping ();
3507 if (ss_req != NULL && ss_invoke_addr == NULL) {
3508 DebuggerTlsData *tls;
3510 mono_loader_lock ();
3512 tls = mono_g_hash_table_lookup (thread_to_tls, ss_req->thread);
3513 ss_invoke_addr = tls->invoke_addr;
3515 mono_loader_unlock ();
3518 g_assert_not_reached ();
3523 stop_single_stepping (void)
3525 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3526 int val = InterlockedDecrement (&ss_count);
3529 mono_arch_stop_single_stepping ();
3531 g_assert_not_reached ();
3536 * Start single stepping of thread THREAD
3539 ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
3541 DebuggerTlsData *tls;
3543 if (suspend_count == 0)
3544 return ERR_NOT_SUSPENDED;
3546 wait_for_suspend ();
3548 // FIXME: Multiple requests
3550 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
3551 return ERR_NOT_IMPLEMENTED;
3554 ss_req = g_new0 (MonoSingleStepReq, 1);
3556 ss_req->thread = thread;
3557 ss_req->size = size;
3558 ss_req->depth = depth;
3561 mono_loader_lock ();
3562 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
3563 mono_loader_unlock ();
3565 g_assert (tls->has_context);
3566 ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->ctx);
3568 if (ss_req->size == STEP_SIZE_LINE) {
3570 MonoDebugMethodInfo *minfo;
3572 /* Compute the initial line info */
3573 compute_frame_info (thread, tls);
3575 g_assert (tls->frame_count);
3576 frame = tls->frames [0];
3578 ss_req->last_method = frame->method;
3579 ss_req->last_line = -1;
3581 minfo = mono_debug_lookup_method (frame->method);
3582 if (minfo && frame->il_offset != -1) {
3583 MonoDebugSourceLocation *loc = mono_debug_symfile_lookup_location (minfo, frame->il_offset);
3586 ss_req->last_line = loc->row;
3592 start_single_stepping ();
3598 ss_stop (EventRequest *req)
3602 g_assert (ss_req->req == req);
3607 stop_single_stepping ();
3611 mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *ctx)
3617 /* Just-In-Time debugging */
3618 if (agent_config.onthrow && !inited) {
3620 gboolean found = FALSE;
3622 for (l = agent_config.onthrow; l; l = l->next) {
3623 char *ex_type = l->data;
3624 char *f = mono_type_full_name (&exc->object.vtable->klass->byval_arg);
3626 if (!strcmp (ex_type, f))
3633 finish_agent_init (FALSE);
3636 * Send an unsolicited EXCEPTION event with a dummy request id.
3638 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
3639 process_event (EVENT_KIND_EXCEPTION, exc, 0, ctx, events, SUSPEND_POLICY_ALL);
3647 ji = mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (ctx), NULL);
3649 mono_loader_lock ();
3650 events = create_event_list (EVENT_KIND_EXCEPTION, NULL, ji, exc, &suspend_policy);
3651 mono_loader_unlock ();
3653 process_event (EVENT_KIND_EXCEPTION, exc, 0, ctx, events, suspend_policy);
3657 mono_debugger_agent_handle_unhandled_exception (MonoException *exc, MonoContext *ctx)
3661 if (!agent_config.onuncaught)
3664 finish_agent_init (FALSE);
3667 * Send an unsolicited EXCEPTION event with a dummy request id.
3669 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
3670 process_event (EVENT_KIND_EXCEPTION, exc, 0, ctx, events, SUSPEND_POLICY_ALL);
3674 * buffer_add_value_full:
3676 * Add the encoding of the value at ADDR described by T to the buffer.
3677 * AS_VTYPE determines whenever to treat primitive types as primitive types or
3681 buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
3687 g_assert (*(void**)addr);
3688 addr = *(void**)addr;
3693 case MONO_TYPE_BOOLEAN:
3696 case MONO_TYPE_CHAR:
3716 case MONO_TYPE_VOID:
3717 buffer_add_byte (buf, t->type);
3719 case MONO_TYPE_BOOLEAN:
3722 buffer_add_byte (buf, t->type);
3723 buffer_add_int (buf, *(gint8*)addr);
3725 case MONO_TYPE_CHAR:
3728 buffer_add_byte (buf, t->type);
3729 buffer_add_int (buf, *(gint16*)addr);
3734 buffer_add_byte (buf, t->type);
3735 buffer_add_int (buf, *(gint32*)addr);
3740 buffer_add_byte (buf, t->type);
3741 buffer_add_long (buf, *(gint64*)addr);
3745 /* Treat it as a vtype */
3747 case MONO_TYPE_PTR: {
3748 gssize val = *(gssize*)addr;
3750 buffer_add_byte (buf, t->type);
3751 buffer_add_long (buf, val);
3755 case MONO_TYPE_STRING:
3756 case MONO_TYPE_SZARRAY:
3757 case MONO_TYPE_OBJECT:
3758 case MONO_TYPE_CLASS:
3759 case MONO_TYPE_ARRAY:
3760 obj = *(MonoObject**)addr;
3763 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
3765 if (obj->vtable->klass->valuetype) {
3766 t = &obj->vtable->klass->byval_arg;
3767 addr = mono_object_unbox (obj);
3769 } else if (obj->vtable->klass->rank) {
3770 buffer_add_byte (buf, obj->vtable->klass->byval_arg.type);
3771 } else if (obj->vtable->klass->byval_arg.type == MONO_TYPE_GENERICINST) {
3772 buffer_add_byte (buf, MONO_TYPE_CLASS);
3774 buffer_add_byte (buf, obj->vtable->klass->byval_arg.type);
3776 buffer_add_objid (buf, obj);
3780 case MONO_TYPE_VALUETYPE: {
3784 MonoClass *klass = mono_class_from_mono_type (t);
3786 buffer_add_byte (buf, MONO_TYPE_VALUETYPE);
3787 buffer_add_byte (buf, klass->enumtype);
3788 buffer_add_typeid (buf, domain, klass);
3792 while ((f = mono_class_get_fields (klass, &iter))) {
3793 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
3795 if (mono_field_is_deleted (f))
3799 buffer_add_int (buf, nfields);
3802 while ((f = mono_class_get_fields (klass, &iter))) {
3803 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
3805 if (mono_field_is_deleted (f))
3807 buffer_add_value_full (buf, f->type, (guint8*)addr + f->offset - sizeof (MonoObject), domain, FALSE);
3811 case MONO_TYPE_GENERICINST:
3812 if (mono_type_generic_inst_is_valuetype (t)) {
3824 buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
3826 buffer_add_value_full (buf, t, addr, domain, FALSE);
3830 decode_value (MonoType *t, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit)
3833 int type = decode_byte (buf, &buf, limit);
3835 if (type != t->type && !MONO_TYPE_IS_REFERENCE (t)) {
3836 DEBUG(1, fprintf (log_file, "Expected value of type %d, got %d.\n", t->type, type));
3837 return ERR_INVALID_ARGUMENT;
3841 case MONO_TYPE_BOOLEAN:
3842 *(guint8*)addr = decode_int (buf, &buf, limit);
3844 case MONO_TYPE_CHAR:
3845 *(gunichar2*)addr = decode_int (buf, &buf, limit);
3848 *(gint8*)addr = decode_int (buf, &buf, limit);
3851 *(guint8*)addr = decode_int (buf, &buf, limit);
3854 *(gint16*)addr = decode_int (buf, &buf, limit);
3857 *(guint16*)addr = decode_int (buf, &buf, limit);
3860 *(gint32*)addr = decode_int (buf, &buf, limit);
3863 *(guint32*)addr = decode_int (buf, &buf, limit);
3866 *(gint64*)addr = decode_long (buf, &buf, limit);
3869 *(guint64*)addr = decode_long (buf, &buf, limit);
3872 *(guint32*)addr = decode_int (buf, &buf, limit);
3875 *(guint64*)addr = decode_long (buf, &buf, limit);
3877 case MONO_TYPE_VALUETYPE: {
3878 gboolean is_enum = decode_byte (buf, &buf, limit);
3882 gpointer iter = NULL;
3885 /* Enums are sent as a normal vtype */
3887 return ERR_NOT_IMPLEMENTED;
3888 klass = decode_typeid (buf, &buf, limit, &d, &err);
3892 if (klass != mono_class_from_mono_type (t))
3893 return ERR_INVALID_ARGUMENT;
3895 nfields = decode_int (buf, &buf, limit);
3896 while ((f = mono_class_get_fields (klass, &iter))) {
3897 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
3899 if (mono_field_is_deleted (f))
3901 err = decode_value (f->type, domain, (guint8*)addr + f->offset - sizeof (MonoObject), buf, &buf, limit);
3906 g_assert (nfields == 0);
3910 if (MONO_TYPE_IS_REFERENCE (t)) {
3911 if (type == MONO_TYPE_OBJECT) {
3912 int objid = decode_objid (buf, &buf, limit);
3916 err = get_object (objid, (MonoObject**)&obj);
3920 if (obj && !mono_class_is_assignable_from (mono_class_from_mono_type (t), obj->vtable->klass))
3921 return ERR_INVALID_ARGUMENT;
3922 if (obj && obj->vtable->domain != domain)
3923 return ERR_INVALID_ARGUMENT;
3925 mono_gc_wbarrier_generic_store (addr, obj);
3926 } else if (type == VALUE_TYPE_ID_NULL) {
3927 *(MonoObject**)addr = NULL;
3929 return ERR_INVALID_ARGUMENT;
3943 add_var (Buffer *buf, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
3950 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
3951 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
3954 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
3955 reg_val = mono_arch_context_get_int_reg (ctx, reg);
3957 buffer_add_value_full (buf, t, ®_val, domain, as_vtype);
3959 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
3960 addr = mono_arch_context_get_int_reg (ctx, reg);
3961 addr += (gint32)var->offset;
3963 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
3965 buffer_add_value_full (buf, t, addr, domain, as_vtype);
3967 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
3971 g_assert_not_reached ();
3976 set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, guint8 *val)
3982 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
3983 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
3985 if (MONO_TYPE_IS_REFERENCE (t))
3986 size = sizeof (gpointer);
3988 size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
3991 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
3992 // FIXME: Can't set registers, so we disable linears
3995 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
3996 addr = mono_arch_context_get_int_reg (ctx, reg);
3997 addr += (gint32)var->offset;
3999 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4001 // FIXME: Write barriers
4002 memcpy (addr, val, size);
4004 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
4008 g_assert_not_reached ();
4013 clear_event_request (int req_id, int etype)
4017 mono_loader_lock ();
4018 for (i = 0; i < event_requests->len; ++i) {
4019 EventRequest *req = g_ptr_array_index (event_requests, i);
4021 if (req->id == req_id && req->event_kind == etype) {
4022 if (req->event_kind == EVENT_KIND_BREAKPOINT)
4023 clear_breakpoint (req->info);
4024 if (req->event_kind == EVENT_KIND_STEP)
4026 if (req->event_kind == EVENT_KIND_METHOD_ENTRY)
4027 clear_breakpoint (req->info);
4028 if (req->event_kind == EVENT_KIND_METHOD_EXIT)
4029 clear_breakpoint (req->info);
4030 g_ptr_array_remove_index_fast (event_requests, i);
4035 mono_loader_unlock ();
4039 add_thread (gpointer key, gpointer value, gpointer user_data)
4041 MonoInternalThread *thread = value;
4042 Buffer *buf = user_data;
4044 buffer_add_objid (buf, (MonoObject*)thread);
4048 do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke)
4050 guint8 *p = invoke->p;
4051 guint8 *end = invoke->endp;
4054 MonoMethodSignature *sig;
4057 MonoObject *this, *res, *exc;
4060 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4064 if (invoke->method) {
4066 * Invoke this method directly, currently only Environment.Exit () is supported.
4069 DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (invoke->method, TRUE), this ? this->vtable->klass->name : "<null>"));
4070 mono_runtime_invoke (invoke->method, NULL, invoke->args, &exc);
4071 g_assert_not_reached ();
4074 m = decode_methodid (p, &p, end, &domain, &err);
4077 sig = mono_method_signature (m);
4079 if (m->klass->valuetype)
4080 this_buf = g_alloca (mono_class_instance_size (m->klass));
4082 this_buf = g_alloca (sizeof (MonoObject*));
4083 err = decode_value (&m->klass->byval_arg, domain, this_buf, p, &p, end);
4087 if (!m->klass->valuetype)
4088 this = *(MonoObject**)this_buf;
4092 DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer)GetCurrentThreadId (), mono_method_full_name (m, TRUE), this ? this->vtable->klass->name : "<null>"));
4094 if (this && this->vtable->domain != domain)
4097 if (!m->klass->valuetype && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this) {
4098 if (!strcmp (m->name, ".ctor")) {
4099 if (m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT)
4100 return ERR_INVALID_ARGUMENT;
4102 this = mono_object_new (domain, m->klass);
4104 return ERR_INVALID_ARGUMENT;
4108 if (this && !mono_class_is_assignable_from (m->klass, this->vtable->klass))
4109 return ERR_INVALID_ARGUMENT;
4111 nargs = decode_int (p, &p, end);
4112 if (nargs != sig->param_count)
4113 return ERR_INVALID_ARGUMENT;
4114 /* Use alloca to get gc tracking */
4115 arg_buf = g_alloca (nargs * sizeof (gpointer));
4116 memset (arg_buf, 0, nargs * sizeof (gpointer));
4117 args = g_alloca (nargs * sizeof (gpointer));
4118 for (i = 0; i < nargs; ++i) {
4119 if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
4120 err = decode_value (sig->params [i], domain, (guint8*)&args [i], p, &p, end);
4124 if (args [i] && ((MonoObject*)args [i])->vtable->domain != domain)
4127 arg_buf [i] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig->params [i])));
4128 err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end);
4131 args [i] = arg_buf [i];
4138 if (invoke->flags & INVOKE_FLAG_DISABLE_BREAKPOINTS)
4139 tls->disable_breakpoints = TRUE;
4141 tls->disable_breakpoints = FALSE;
4144 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4146 /* FIXME: Move this to arch specific code */
4147 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4148 if (invoke->has_ctx) {
4151 lmf_addr = mono_get_lmf_addr ();
4154 memset (&ext, 0, sizeof (ext));
4156 ext.lmf.previous_lmf = *(lmf_addr);
4157 /* Mark that this is a MonoLMFExt */
4158 ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
4159 ext.lmf.rsp = (gssize)&ext;
4160 #elif defined(TARGET_X86)
4161 ext.lmf.previous_lmf = (gsize)*(lmf_addr);
4162 /* Mark that this is a MonoLMFExt */
4163 ext.lmf.previous_lmf = (gsize)(gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
4164 ext.lmf.ebp = (gssize)&ext;
4165 #elif defined(TARGET_ARM)
4166 ext.lmf.previous_lmf = *(lmf_addr);
4167 /* Mark that this is a MonoLMFExt */
4168 ext.lmf.previous_lmf = (gpointer)(((gssize)ext.lmf.previous_lmf) | 2);
4169 ext.lmf.ebp = (gssize)&ext;
4171 g_assert_not_reached ();
4174 ext.debugger_invoke = TRUE;
4175 memcpy (&ext.ctx, &invoke->ctx, sizeof (MonoContext));
4177 mono_set_lmf ((MonoLMF*)&ext);
4181 if (m->klass->valuetype)
4182 res = mono_runtime_invoke (m, this_buf, args, &exc);
4184 res = mono_runtime_invoke (m, this, args, &exc);
4186 buffer_add_byte (buf, 0);
4187 buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &exc, domain);
4189 buffer_add_byte (buf, 1);
4190 if (sig->ret->type == MONO_TYPE_VOID) {
4191 if (!strcmp (m->name, ".ctor") && !m->klass->valuetype) {
4192 buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &this, domain);
4195 buffer_add_value (buf, &mono_defaults.void_class->byval_arg, NULL, domain);
4196 } else if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
4197 buffer_add_value (buf, sig->ret, &res, domain);
4198 } else if (mono_class_from_mono_type (sig->ret)->valuetype) {
4200 buffer_add_value (buf, sig->ret, mono_object_unbox (res), domain);
4206 tls->disable_breakpoints = FALSE;
4208 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4209 if (invoke->has_ctx)
4210 mono_set_lmf ((gpointer)(((gssize)ext.lmf.previous_lmf) & ~3));
4213 // FIXME: byref arguments
4221 * Invoke the method given by tls->invoke in the current thread.
4224 invoke_method (void)
4226 DebuggerTlsData *tls;
4231 static void (*restore_context) (void *);
4232 MonoContext restore_ctx;
4234 if (!restore_context)
4235 restore_context = mono_get_restore_context ();
4237 tls = TlsGetValue (debugger_tls_id);
4240 invoke = tls->invoke;
4244 tls->frames_up_to_date = FALSE;
4248 buffer_init (&buf, 128);
4250 err = do_invoke_method (tls, &buf, invoke);
4252 /* Start suspending before sending the reply */
4253 if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED))
4256 send_reply_packet (id, err, &buf);
4260 memcpy (&restore_ctx, &invoke->ctx, sizeof (MonoContext));
4262 if (invoke->has_ctx)
4263 save_thread_context (&restore_ctx);
4265 if (invoke->flags & INVOKE_FLAG_SINGLE_THREADED) {
4266 g_assert (tls->resume_count);
4267 tls->resume_count -= invoke->suspend_count;
4270 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer)GetCurrentThreadId (), tls->resume_count));
4279 is_really_suspended (gpointer key, gpointer value, gpointer user_data)
4281 MonoThread *thread = value;
4282 DebuggerTlsData *tls;
4285 mono_loader_lock ();
4286 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
4288 res = tls->really_suspended;
4289 mono_loader_unlock ();
4295 vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
4298 case CMD_VM_VERSION: {
4299 char *build_info, *version;
4301 build_info = mono_get_runtime_build_info ();
4302 version = g_strdup_printf ("mono %s", build_info);
4304 buffer_add_string (buf, version); /* vm version */
4305 buffer_add_int (buf, MAJOR_VERSION);
4306 buffer_add_int (buf, MINOR_VERSION);
4307 g_free (build_info);
4311 case CMD_VM_ALL_THREADS: {
4313 mono_loader_lock ();
4314 buffer_add_int (buf, mono_g_hash_table_size (tid_to_thread_obj));
4315 mono_g_hash_table_foreach (tid_to_thread_obj, add_thread, buf);
4316 mono_loader_unlock ();
4319 case CMD_VM_SUSPEND:
4321 wait_for_suspend ();
4324 if (suspend_count == 0)
4325 return ERR_NOT_SUSPENDED;
4328 case CMD_VM_DISPOSE:
4329 /* Clear all event requests */
4330 mono_loader_lock ();
4331 while (event_requests->len > 0) {
4332 EventRequest *req = g_ptr_array_index (event_requests, 0);
4334 clear_event_request (req->id, req->event_kind);
4336 mono_loader_unlock ();
4338 // FIXME: Count resumes
4340 disconnected = TRUE;
4343 MonoInternalThread *thread;
4344 DebuggerTlsData *tls;
4345 MonoClass *env_class;
4346 MonoMethod *exit_method;
4350 exit_code = decode_int (p, &p, end);
4352 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
4354 /* Have to send a reply before exiting */
4355 send_reply_packet (id, 0, buf);
4357 /* Clear all event requests */
4358 mono_loader_lock ();
4359 while (event_requests->len > 0) {
4360 EventRequest *req = g_ptr_array_index (event_requests, 0);
4362 clear_event_request (req->id, req->event_kind);
4364 mono_loader_unlock ();
4367 * The JDWP documentation says that the shutdown is not orderly. It doesn't
4368 * specify whenever a VM_DEATH event is sent. We currently do an orderly
4369 * shutdown by hijacking a thread to execute Environment.Exit (). This is
4370 * better than doing the shutdown ourselves, since it avoids various races.
4374 wait_for_suspend ();
4376 env_class = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
4377 g_assert (env_class);
4378 exit_method = mono_class_get_method_from_name (env_class, "Exit", 1);
4379 g_assert (exit_method);
4381 mono_loader_lock ();
4382 thread = mono_g_hash_table_find (tid_to_thread, is_really_suspended, NULL);
4383 mono_loader_unlock ();
4386 mono_loader_lock ();
4387 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
4388 mono_loader_unlock ();
4390 args = g_new0 (gpointer, 1);
4391 args [0] = g_malloc (sizeof (int));
4392 *(int*)(args [0]) = exit_code;
4394 tls->invoke = g_new0 (InvokeData, 1);
4395 tls->invoke->method = exit_method;
4396 tls->invoke->args = args;
4398 while (suspend_count > 0)
4402 * No thread found, do it ourselves.
4403 * FIXME: This can race with normal shutdown etc.
4405 while (suspend_count > 0)
4408 mono_runtime_set_shutting_down ();
4410 mono_threads_set_shutting_down ();
4412 /* Suspend all managed threads since the runtime is going away */
4413 DEBUG(1, fprintf (log_file, "Suspending all threads...\n"));
4414 mono_thread_suspend_all_other_threads ();
4415 DEBUG(1, fprintf (log_file, "Shutting down the runtime...\n"));
4416 mono_runtime_quit ();
4418 shutdown (conn_fd, SD_BOTH);
4420 shutdown (conn_fd, SHUT_RDWR);
4422 DEBUG(1, fprintf (log_file, "Exiting...\n"));
4428 case CMD_VM_INVOKE_METHOD: {
4429 int objid = decode_objid (p, &p, end);
4431 DebuggerTlsData *tls;
4434 err = get_object (objid, (MonoObject**)&thread);
4438 flags = decode_int (p, &p, end);
4440 // Wait for suspending if it already started
4442 wait_for_suspend ();
4443 if (!is_suspended ())
4444 return ERR_NOT_SUSPENDED;
4446 mono_loader_lock ();
4447 tls = mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL (thread));
4448 mono_loader_unlock ();
4451 if (!tls->really_suspended)
4452 /* The thread is still running native code, can't do invokes */
4453 return ERR_NOT_SUSPENDED;
4456 * Store the invoke data into tls, the thread will execute it after it is
4461 tls->invoke = g_new0 (InvokeData, 1);
4462 tls->invoke->id = id;
4463 tls->invoke->flags = flags;
4464 tls->invoke->p = g_malloc (end - p);
4465 memcpy (tls->invoke->p, p, end - p);
4466 tls->invoke->endp = tls->invoke->p + (end - p);
4467 tls->invoke->suspend_count = suspend_count;
4469 if (flags & INVOKE_FLAG_SINGLE_THREADED)
4470 resume_thread (THREAD_TO_INTERNAL (thread));
4476 return ERR_NOT_IMPLEMENTED;
4483 event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
4488 case CMD_EVENT_REQUEST_SET: {
4490 int i, event_kind, suspend_policy, nmodifiers, mod;
4493 MonoThread *step_thread;
4494 int size = 0, depth = 0, step_thread_id = 0;
4497 event_kind = decode_byte (p, &p, end);
4498 suspend_policy = decode_byte (p, &p, end);
4499 nmodifiers = decode_byte (p, &p, end);
4501 req = g_malloc0 (sizeof (EventRequest) + (nmodifiers * sizeof (Modifier)));
4502 req->id = InterlockedIncrement (&event_request_id);
4503 req->event_kind = event_kind;
4504 req->suspend_policy = suspend_policy;
4505 req->nmodifiers = nmodifiers;
4508 for (i = 0; i < nmodifiers; ++i) {
4509 mod = decode_byte (p, &p, end);
4511 req->modifiers [i].kind = mod;
4512 if (mod == MOD_KIND_COUNT) {
4513 req->modifiers [i].data.count = decode_int (p, &p, end);
4514 } else if (mod == MOD_KIND_LOCATION_ONLY) {
4515 method = decode_methodid (p, &p, end, &domain, &err);
4518 location = decode_long (p, &p, end);
4519 } else if (mod == MOD_KIND_STEP) {
4520 step_thread_id = decode_id (p, &p, end);
4521 size = decode_int (p, &p, end);
4522 depth = decode_int (p, &p, end);
4523 } else if (mod == MOD_KIND_THREAD_ONLY) {
4524 int id = decode_id (p, &p, end);
4526 err = get_object (id, (MonoObject**)&req->modifiers [i].data.thread);
4531 } else if (mod == MOD_KIND_EXCEPTION_ONLY) {
4532 MonoClass *exc_class = decode_typeid (p, &p, end, &domain, &err);
4537 req->modifiers [i].data.exc_class = exc_class;
4539 if (!mono_class_is_assignable_from (mono_defaults.exception_class, exc_class)) {
4541 return ERR_INVALID_ARGUMENT;
4544 } else if (mod == MOD_KIND_ASSEMBLY_ONLY) {
4545 int n = decode_int (p, &p, end);
4548 req->modifiers [i].data.assemblies = g_new0 (MonoAssembly*, n);
4549 for (j = 0; j < n; ++j) {
4550 req->modifiers [i].data.assemblies [j] = decode_assemblyid (p, &p, end, &domain, &err);
4552 g_free (req->modifiers [i].data.assemblies);
4558 return ERR_NOT_IMPLEMENTED;
4562 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
4565 req->info = set_breakpoint (method, location, req);
4566 } else if (req->event_kind == EVENT_KIND_STEP) {
4567 g_assert (step_thread_id);
4569 err = get_object (step_thread_id, (MonoObject**)&step_thread);
4575 err = ss_start (THREAD_TO_INTERNAL (step_thread), size, depth, req);
4580 } else if (req->event_kind == EVENT_KIND_METHOD_ENTRY) {
4581 req->info = set_breakpoint (NULL, METHOD_ENTRY_IL_OFFSET, req);
4582 } else if (req->event_kind == EVENT_KIND_METHOD_EXIT) {
4583 req->info = set_breakpoint (NULL, METHOD_EXIT_IL_OFFSET, req);
4584 } else if (req->event_kind == EVENT_KIND_EXCEPTION) {
4586 if (req->nmodifiers) {
4588 return ERR_NOT_IMPLEMENTED;
4592 mono_loader_lock ();
4593 g_ptr_array_add (event_requests, req);
4594 mono_loader_unlock ();
4596 buffer_add_int (buf, req->id);
4599 case CMD_EVENT_REQUEST_CLEAR: {
4600 int etype = decode_byte (p, &p, end);
4601 int req_id = decode_int (p, &p, end);
4603 // FIXME: Make a faster mapping from req_id to request
4604 mono_loader_lock ();
4605 clear_event_request (req_id, etype);
4606 mono_loader_unlock ();
4609 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS: {
4612 mono_loader_lock ();
4614 while (i < event_requests->len) {
4615 EventRequest *req = g_ptr_array_index (event_requests, i);
4617 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
4618 clear_breakpoint (req->info);
4620 g_ptr_array_remove_index_fast (event_requests, i);
4626 mono_loader_unlock ();
4630 return ERR_NOT_IMPLEMENTED;
4637 domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
4643 case CMD_APPDOMAIN_GET_ROOT_DOMAIN: {
4644 buffer_add_domainid (buf, mono_get_root_domain ());
4647 case CMD_APPDOMAIN_GET_FRIENDLY_NAME: {
4648 domain = decode_domainid (p, &p, end, NULL, &err);
4651 buffer_add_string (buf, domain->friendly_name);
4654 case CMD_APPDOMAIN_GET_ASSEMBLIES: {
4659 domain = decode_domainid (p, &p, end, NULL, &err);
4662 mono_loader_lock ();
4664 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
4667 buffer_add_int (buf, count);
4668 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
4670 buffer_add_assemblyid (buf, domain, ass);
4672 mono_loader_unlock ();
4675 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY: {
4676 domain = decode_domainid (p, &p, end, NULL, &err);
4680 buffer_add_assemblyid (buf, domain, domain->entry_assembly);
4683 case CMD_APPDOMAIN_GET_CORLIB: {
4684 domain = decode_domainid (p, &p, end, NULL, &err);
4688 buffer_add_assemblyid (buf, domain, domain->domain->mbr.obj.vtable->klass->image->assembly);
4691 case CMD_APPDOMAIN_CREATE_STRING: {
4695 domain = decode_domainid (p, &p, end, NULL, &err);
4698 s = decode_string (p, &p, end);
4700 o = mono_string_new (domain, s);
4701 buffer_add_objid (buf, (MonoObject*)o);
4705 return ERR_NOT_IMPLEMENTED;
4712 assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
4718 ass = decode_assemblyid (p, &p, end, &domain, &err);
4723 case CMD_ASSEMBLY_GET_LOCATION: {
4724 buffer_add_string (buf, mono_image_get_filename (ass->image));
4727 case CMD_ASSEMBLY_GET_ENTRY_POINT: {
4731 if (ass->image->dynamic) {
4732 buffer_add_id (buf, 0);
4734 token = mono_image_get_entry_point (ass->image);
4736 buffer_add_id (buf, 0);
4738 m = mono_get_method (ass->image, token, NULL);
4739 buffer_add_methodid (buf, domain, m);
4744 case CMD_ASSEMBLY_GET_MANIFEST_MODULE: {
4745 buffer_add_moduleid (buf, domain, ass->image);
4748 case CMD_ASSEMBLY_GET_OBJECT: {
4749 MonoObject *o = (MonoObject*)mono_assembly_get_object (mono_domain_get (), ass);
4750 buffer_add_objid (buf, o);
4753 case CMD_ASSEMBLY_GET_TYPE: {
4754 char *s = decode_string (p, &p, end);
4755 gboolean ignorecase = decode_byte (p, &p, end);
4756 MonoTypeNameParse info;
4758 gboolean type_resolve;
4760 if (!mono_reflection_parse_type (s, &info)) {
4763 if (info.assembly.name)
4765 t = mono_reflection_get_type (ass->image, &info, ignorecase, &type_resolve);
4767 buffer_add_typeid (buf, domain, t ? mono_class_from_mono_type (t) : NULL);
4768 mono_reflection_free_type_info (&info);
4773 case CMD_ASSEMBLY_GET_NAME: {
4775 MonoAssembly *mass = ass;
4777 name = g_strdup_printf (
4778 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
4780 mass->aname.major, mass->aname.minor, mass->aname.build, mass->aname.revision,
4781 mass->aname.culture && *mass->aname.culture? mass->aname.culture: "neutral",
4782 mass->aname.public_key_token [0] ? (char *)mass->aname.public_key_token : "null",
4783 (mass->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
4785 buffer_add_string (buf, name);
4790 return ERR_NOT_IMPLEMENTED;
4797 module_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
4803 case CMD_MODULE_GET_INFO: {
4804 MonoImage *image = decode_moduleid (p, &p, end, &domain, &err);
4807 basename = g_path_get_basename (image->name);
4808 buffer_add_string (buf, basename); // name
4809 buffer_add_string (buf, image->module_name); // scopename
4810 buffer_add_string (buf, image->name); // fqname
4811 buffer_add_string (buf, mono_image_get_guid (image)); // guid
4812 buffer_add_assemblyid (buf, domain, image->assembly); // assembly
4817 return ERR_NOT_IMPLEMENTED;
4824 buffer_add_cattr_arg (Buffer *buf, MonoType *t, MonoDomain *domain, MonoObject *val)
4826 if (val && val->vtable->klass == mono_defaults.monotype_class) {
4827 /* Special case these so the client doesn't have to handle Type objects */
4829 buffer_add_byte (buf, VALUE_TYPE_ID_TYPE);
4830 buffer_add_typeid (buf, domain, mono_class_from_mono_type (((MonoReflectionType*)val)->type));
4831 } else if (MONO_TYPE_IS_REFERENCE (t))
4832 buffer_add_value (buf, t, &val, domain);
4834 buffer_add_value (buf, t, mono_object_unbox (val), domain);
4838 buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass *attr_klass, MonoCustomAttrInfo *cinfo)
4844 buffer_add_int (buf, 0);
4848 for (i = 0; i < cinfo->num_attrs; ++i) {
4849 if (!attr_klass || mono_class_has_parent (cinfo->attrs [i].ctor->klass, attr_klass))
4852 buffer_add_int (buf, nattrs);
4854 for (i = 0; i < cinfo->num_attrs; ++i) {
4855 MonoCustomAttrEntry *attr = &cinfo->attrs [i];
4856 if (!attr_klass || mono_class_has_parent (attr->ctor->klass, attr_klass)) {
4857 MonoArray *typed_args, *named_args;
4859 CattrNamedArg *arginfo;
4861 mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo);
4863 buffer_add_methodid (buf, domain, attr->ctor);
4867 buffer_add_int (buf, mono_array_length (typed_args));
4868 for (j = 0; j < mono_array_length (typed_args); ++j) {
4869 MonoObject *val = mono_array_get (typed_args, MonoObject*, j);
4871 t = mono_method_signature (attr->ctor)->params [j];
4873 buffer_add_cattr_arg (buf, t, domain, val);
4876 buffer_add_int (buf, 0);
4881 buffer_add_int (buf, mono_array_length (named_args));
4883 for (j = 0; j < mono_array_length (named_args); ++j) {
4884 MonoObject *val = mono_array_get (named_args, MonoObject*, j);
4886 if (arginfo [j].prop) {
4887 buffer_add_byte (buf, 0x54);
4888 buffer_add_propertyid (buf, domain, arginfo [j].prop);
4889 } else if (arginfo [j].field) {
4890 buffer_add_byte (buf, 0x53);
4892 g_assert_not_reached ();
4895 buffer_add_cattr_arg (buf, arginfo [j].type, domain, val);
4898 buffer_add_int (buf, 0);
4905 type_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
4916 klass = decode_typeid (p, &p, end, &domain, &err);
4921 case CMD_TYPE_GET_INFO: {
4922 buffer_add_string (buf, klass->name_space);
4923 buffer_add_string (buf, klass->name);
4925 name = mono_type_get_name_full (&klass->byval_arg, MONO_TYPE_NAME_FORMAT_FULL_NAME);
4926 buffer_add_string (buf, name);
4928 buffer_add_assemblyid (buf, domain, klass->image->assembly);
4929 buffer_add_moduleid (buf, domain, klass->image);
4930 buffer_add_typeid (buf, domain, klass->parent);
4931 if (klass->rank || klass->byval_arg.type == MONO_TYPE_PTR)
4932 buffer_add_typeid (buf, domain, klass->element_class);
4934 buffer_add_id (buf, 0);
4935 buffer_add_int (buf, klass->type_token);
4936 buffer_add_byte (buf, klass->rank);
4937 buffer_add_int (buf, klass->flags);
4939 type = &klass->byval_arg;
4940 // FIXME: Can't decide whenever a class represents a byref type
4943 if (type->type == MONO_TYPE_PTR)
4945 if (!type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
4947 if (type->type == MONO_TYPE_VALUETYPE)
4949 buffer_add_byte (buf, b);
4952 while ((nested = mono_class_get_nested_types (klass, &iter)))
4954 buffer_add_int (buf, nnested);
4956 while ((nested = mono_class_get_nested_types (klass, &iter)))
4957 buffer_add_typeid (buf, domain, nested);
4960 case CMD_TYPE_GET_METHODS: {
4963 gpointer iter = NULL;
4966 nmethods = mono_class_num_methods (klass);
4968 buffer_add_int (buf, nmethods);
4970 while ((m = mono_class_get_methods (klass, &iter))) {
4971 buffer_add_methodid (buf, domain, m);
4974 g_assert (i == nmethods);
4977 case CMD_TYPE_GET_FIELDS: {
4980 gpointer iter = NULL;
4983 nfields = mono_class_num_fields (klass);
4985 buffer_add_int (buf, nfields);
4987 while ((f = mono_class_get_fields (klass, &iter))) {
4988 buffer_add_fieldid (buf, domain, f);
4989 buffer_add_string (buf, f->name);
4990 buffer_add_typeid (buf, domain, mono_class_from_mono_type (f->type));
4991 buffer_add_int (buf, f->type->attrs);
4994 g_assert (i == nfields);
4997 case CMD_TYPE_GET_PROPERTIES: {
5000 gpointer iter = NULL;
5003 nprops = mono_class_num_properties (klass);
5005 buffer_add_int (buf, nprops);
5007 while ((p = mono_class_get_properties (klass, &iter))) {
5008 buffer_add_propertyid (buf, domain, p);
5009 buffer_add_string (buf, p->name);
5010 buffer_add_methodid (buf, domain, p->get);
5011 buffer_add_methodid (buf, domain, p->set);
5012 buffer_add_int (buf, p->attrs);
5015 g_assert (i == nprops);
5018 case CMD_TYPE_GET_CATTRS: {
5019 MonoClass *attr_klass = decode_typeid (p, &p, end, NULL, &err);
5020 MonoCustomAttrInfo *cinfo;
5022 cinfo = mono_custom_attrs_from_class (klass);
5024 buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
5027 case CMD_TYPE_GET_FIELD_CATTRS: {
5028 MonoClass *attr_klass;
5029 MonoCustomAttrInfo *cinfo;
5030 MonoClassField *field;
5032 field = decode_fieldid (p, &p, end, NULL, &err);
5035 attr_klass = decode_typeid (p, &p, end, NULL, &err);
5039 cinfo = mono_custom_attrs_from_field (klass, field);
5041 buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
5044 case CMD_TYPE_GET_PROPERTY_CATTRS: {
5045 MonoClass *attr_klass;
5046 MonoCustomAttrInfo *cinfo;
5049 prop = decode_propertyid (p, &p, end, NULL, &err);
5052 attr_klass = decode_typeid (p, &p, end, NULL, &err);
5056 cinfo = mono_custom_attrs_from_property (klass, prop);
5058 buffer_add_cattrs (buf, domain, klass->image, attr_klass, cinfo);
5061 case CMD_TYPE_GET_VALUES: {
5069 len = decode_int (p, &p, end);
5070 for (i = 0; i < len; ++i) {
5071 f = decode_fieldid (p, &p, end, NULL, &err);
5075 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
5076 return ERR_INVALID_FIELDID;
5077 if (mono_class_field_is_special_static (f))
5078 return ERR_INVALID_FIELDID;
5080 /* Check that the field belongs to the object */
5082 for (k = klass; k; k = k->parent) {
5083 if (k == f->parent) {
5089 return ERR_INVALID_FIELDID;
5091 vtable = mono_class_vtable (domain, f->parent);
5092 val = g_malloc (mono_class_instance_size (mono_class_from_mono_type (f->type)));
5093 mono_field_static_get_value (vtable, f, val);
5094 buffer_add_value (buf, f->type, val, domain);
5099 case CMD_TYPE_SET_VALUES: {
5107 len = decode_int (p, &p, end);
5108 for (i = 0; i < len; ++i) {
5109 f = decode_fieldid (p, &p, end, NULL, &err);
5113 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
5114 return ERR_INVALID_FIELDID;
5115 if (mono_class_field_is_special_static (f))
5116 return ERR_INVALID_FIELDID;
5118 /* Check that the field belongs to the object */
5120 for (k = klass; k; k = k->parent) {
5121 if (k == f->parent) {
5127 return ERR_INVALID_FIELDID;
5129 // FIXME: Check for literal/const
5131 vtable = mono_class_vtable (domain, f->parent);
5132 val = g_malloc (mono_class_instance_size (mono_class_from_mono_type (f->type)));
5133 err = decode_value (f->type, domain, val, p, &p, end);
5138 mono_field_static_set_value (vtable, f, val);
5143 case CMD_TYPE_GET_OBJECT: {
5144 MonoObject *o = (MonoObject*)mono_type_get_object (mono_domain_get (), &klass->byval_arg);
5145 buffer_add_objid (buf, o);
5148 case CMD_TYPE_GET_SOURCE_FILES: {
5149 gpointer iter = NULL;
5151 char *source_file, *base;
5155 files = g_ptr_array_new ();
5157 while ((method = mono_class_get_methods (klass, &iter))) {
5158 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
5161 mono_debug_symfile_get_line_numbers (minfo, &source_file, NULL, NULL, NULL);
5163 for (i = 0; i < files->len; ++i)
5164 if (!strcmp (g_ptr_array_index (files, i), source_file))
5166 if (i == files->len)
5167 g_ptr_array_add (files, g_strdup (source_file));
5168 g_free (source_file);
5172 buffer_add_int (buf, files->len);
5173 for (i = 0; i < files->len; ++i) {
5174 source_file = g_ptr_array_index (files, i);
5175 base = g_path_get_basename (source_file);
5176 buffer_add_string (buf, base);
5178 g_free (source_file);
5180 g_ptr_array_free (files, TRUE);
5183 case CMD_TYPE_IS_ASSIGNABLE_FROM: {
5184 MonoClass *oklass = decode_typeid (p, &p, end, NULL, &err);
5188 if (mono_class_is_assignable_from (klass, oklass))
5189 buffer_add_byte (buf, 1);
5191 buffer_add_byte (buf, 0);
5195 return ERR_NOT_IMPLEMENTED;
5202 method_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5207 MonoMethodHeader *header;
5209 method = decode_methodid (p, &p, end, &domain, &err);
5214 case CMD_METHOD_GET_NAME: {
5215 buffer_add_string (buf, method->name);
5218 case CMD_METHOD_GET_DECLARING_TYPE: {
5219 buffer_add_typeid (buf, domain, method->klass);
5222 case CMD_METHOD_GET_DEBUG_INFO: {
5223 MonoDebugMethodInfo *minfo;
5225 int i, n_il_offsets;
5229 header = mono_method_get_header (method);
5231 buffer_add_int (buf, 0);
5232 buffer_add_string (buf, "");
5233 buffer_add_int (buf, 0);
5237 minfo = mono_debug_lookup_method (method);
5239 buffer_add_int (buf, header->code_size);
5240 buffer_add_string (buf, "");
5241 buffer_add_int (buf, 0);
5245 mono_debug_symfile_get_line_numbers (minfo, &source_file, &n_il_offsets, &il_offsets, &line_numbers);
5246 buffer_add_int (buf, header->code_size);
5247 buffer_add_string (buf, source_file);
5248 buffer_add_int (buf, n_il_offsets);
5249 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5250 for (i = 0; i < n_il_offsets; ++i) {
5251 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5252 buffer_add_int (buf, il_offsets [i]);
5253 buffer_add_int (buf, line_numbers [i]);
5255 g_free (source_file);
5256 g_free (il_offsets);
5257 g_free (line_numbers);
5260 case CMD_METHOD_GET_PARAM_INFO: {
5261 MonoMethodSignature *sig = mono_method_signature (method);
5265 /* FIXME: mono_class_from_mono_type () and byrefs */
5267 /* FIXME: Use a smaller encoding */
5268 buffer_add_int (buf, sig->call_convention);
5269 buffer_add_int (buf, sig->param_count);
5270 buffer_add_int (buf, sig->generic_param_count);
5271 buffer_add_typeid (buf, domain, mono_class_from_mono_type (sig->ret));
5272 for (i = 0; i < sig->param_count; ++i) {
5274 buffer_add_typeid (buf, domain, mono_class_from_mono_type (sig->params [i]));
5277 /* Emit parameter names */
5278 names = g_new (char *, sig->param_count);
5279 mono_method_get_param_names (method, (const char **) names);
5280 for (i = 0; i < sig->param_count; ++i)
5281 buffer_add_string (buf, names [i]);
5286 case CMD_METHOD_GET_LOCALS_INFO: {
5287 int i, j, num_locals;
5291 header = mono_method_get_header (method);
5294 buffer_add_int (buf, header->num_locals);
5297 for (i = 0; i < header->num_locals; ++i)
5298 buffer_add_typeid (buf, domain, mono_class_from_mono_type (header->locals [i]));
5301 num_locals = mono_debug_lookup_locals (method, &local_names, &local_indexes);
5302 for (i = 0; i < header->num_locals; ++i) {
5303 for (j = 0; j < num_locals; ++j)
5304 if (local_indexes [j] == i)
5307 buffer_add_string (buf, local_names [j]);
5309 buffer_add_string (buf, "");
5311 g_free (local_names);
5312 g_free (local_indexes);
5315 /* FIXME: This works because we set debug_options.mdb_optimizations */
5316 for (i = 0; i < header->num_locals; ++i) {
5317 buffer_add_int (buf, 0);
5318 buffer_add_int (buf, header->code_size);
5323 case CMD_METHOD_GET_INFO:
5324 buffer_add_int (buf, method->flags);
5325 buffer_add_int (buf, method->iflags);
5326 buffer_add_int (buf, method->token);
5328 case CMD_METHOD_GET_BODY: {
5331 header = mono_method_get_header (method);
5333 buffer_add_int (buf, 0);
5335 buffer_add_int (buf, header->code_size);
5336 for (i = 0; i < header->code_size; ++i)
5337 buffer_add_byte (buf, header->code [i]);
5341 case CMD_METHOD_RESOLVE_TOKEN: {
5342 guint32 token = decode_int (p, &p, end);
5345 switch (mono_metadata_token_code (token)) {
5346 case MONO_TOKEN_STRING: {
5350 s = mono_ldstr (domain, method->klass->image, mono_metadata_token_index (token));
5353 s2 = mono_string_to_utf8 (s);
5355 buffer_add_byte (buf, TOKEN_TYPE_STRING);
5356 buffer_add_string (buf, s2);
5362 MonoClass *handle_class;
5364 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
5365 val = mono_method_get_wrapper_data (method, token);
5366 handle_class = mono_method_get_wrapper_data (method, token + 1);
5368 if (handle_class == NULL) {
5369 // Can't figure out the token type
5370 buffer_add_byte (buf, TOKEN_TYPE_UNKNOWN);
5374 val = mono_ldtoken (method->klass->image, token, &handle_class, NULL);
5378 if (handle_class == mono_defaults.typehandle_class) {
5379 buffer_add_byte (buf, TOKEN_TYPE_TYPE);
5380 buffer_add_typeid (buf, domain, mono_class_from_mono_type ((MonoType*)val));
5381 } else if (handle_class == mono_defaults.fieldhandle_class) {
5382 buffer_add_byte (buf, TOKEN_TYPE_FIELD);
5383 buffer_add_fieldid (buf, domain, val);
5384 } else if (handle_class == mono_defaults.methodhandle_class) {
5385 buffer_add_byte (buf, TOKEN_TYPE_METHOD);
5386 buffer_add_methodid (buf, domain, val);
5387 } else if (handle_class == mono_defaults.string_class) {
5390 s = mono_string_to_utf8 (val);
5391 buffer_add_byte (buf, TOKEN_TYPE_STRING);
5392 buffer_add_string (buf, s);
5395 g_assert_not_reached ();
5403 return ERR_NOT_IMPLEMENTED;
5410 thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5412 int objid = decode_objid (p, &p, end);
5414 MonoThread *thread_obj;
5415 MonoInternalThread *thread;
5417 err = get_object (objid, (MonoObject**)&thread_obj);
5421 thread = THREAD_TO_INTERNAL (thread_obj);
5424 case CMD_THREAD_GET_NAME: {
5426 gunichar2 *s = mono_thread_get_name (thread, &name_len);
5429 buffer_add_int (buf, 0);
5434 name = g_utf16_to_utf8 (s, name_len, NULL, &len, NULL);
5436 buffer_add_int (buf, len);
5437 buffer_add_data (buf, (guint8*)name, len);
5442 case CMD_THREAD_GET_FRAME_INFO: {
5443 DebuggerTlsData *tls;
5444 int i, start_frame, length;
5446 // Wait for suspending if it already started
5448 wait_for_suspend ();
5449 if (!is_suspended ())
5450 return ERR_NOT_SUSPENDED;
5452 start_frame = decode_int (p, &p, end);
5453 length = decode_int (p, &p, end);
5455 if (start_frame != 0 || length != -1)
5456 return ERR_NOT_IMPLEMENTED;
5458 mono_loader_lock ();
5459 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
5460 mono_loader_unlock ();
5463 compute_frame_info (thread, tls);
5465 buffer_add_int (buf, tls->frame_count);
5466 for (i = 0; i < tls->frame_count; ++i) {
5467 buffer_add_int (buf, tls->frames [i]->id);
5468 buffer_add_methodid (buf, tls->frames [i]->domain, tls->frames [i]->method);
5469 buffer_add_int (buf, tls->frames [i]->il_offset);
5471 * Instead of passing the frame type directly to the client, we associate
5472 * it with the previous frame using a set of flags. This avoids lots of
5473 * conditional code in the client, since a frame whose type isn't
5474 * FRAME_TYPE_MANAGED has no method, location, etc.
5476 buffer_add_byte (buf, tls->frames [i]->flags);
5481 case CMD_THREAD_GET_STATE:
5482 buffer_add_int (buf, thread->state);
5484 case CMD_THREAD_GET_INFO:
5485 buffer_add_byte (buf, thread->threadpool_thread);
5488 return ERR_NOT_IMPLEMENTED;
5495 frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5499 MonoThread *thread_obj;
5500 MonoInternalThread *thread;
5502 DebuggerTlsData *tls;
5504 MonoDebugMethodJitInfo *jit;
5505 MonoDebugVarInfo *var;
5506 MonoMethodSignature *sig;
5508 MonoMethodHeader *header;
5510 objid = decode_objid (p, &p, end);
5511 err = get_object (objid, (MonoObject**)&thread_obj);
5515 thread = THREAD_TO_INTERNAL (thread_obj);
5517 id = decode_id (p, &p, end);
5519 mono_loader_lock ();
5520 tls = mono_g_hash_table_lookup (thread_to_tls, thread);
5521 mono_loader_unlock ();
5524 for (i = 0; i < tls->frame_count; ++i) {
5525 if (tls->frames [i]->id == id)
5528 if (i == tls->frame_count)
5529 return ERR_INVALID_FRAMEID;
5531 frame = tls->frames [i];
5533 if (!frame->has_ctx)
5535 return ERR_INVALID_FRAMEID;
5538 frame->jit = mono_debug_find_method (frame->method, frame->domain);
5539 g_assert (frame->jit);
5543 sig = mono_method_signature (frame->method);
5546 case CMD_STACK_FRAME_GET_VALUES: {
5547 len = decode_int (p, &p, end);
5548 header = mono_method_get_header (frame->method);
5550 for (i = 0; i < len; ++i) {
5551 pos = decode_int (p, &p, end);
5556 g_assert (pos >= 0 && pos < jit->num_params);
5558 var = &jit->params [pos];
5560 add_var (buf, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
5562 g_assert (pos >= 0 && pos < jit->num_locals);
5564 var = &jit->locals [pos];
5566 add_var (buf, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
5571 case CMD_STACK_FRAME_GET_THIS: {
5572 if (frame->method->klass->valuetype) {
5573 if (!sig->hasthis) {
5574 MonoObject *p = NULL;
5575 buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
5577 add_var (buf, &frame->method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
5580 if (!sig->hasthis) {
5581 MonoObject *p = NULL;
5582 buffer_add_value (buf, &frame->method->klass->byval_arg, &p, frame->domain);
5584 add_var (buf, &frame->method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
5589 case CMD_STACK_FRAME_SET_VALUES: {
5592 MonoDebugVarInfo *var;
5594 len = decode_int (p, &p, end);
5595 header = mono_method_get_header (frame->method);
5597 for (i = 0; i < len; ++i) {
5598 pos = decode_int (p, &p, end);
5603 g_assert (pos >= 0 && pos < jit->num_params);
5605 t = sig->params [pos];
5606 var = &jit->params [pos];
5608 g_assert (pos >= 0 && pos < jit->num_locals);
5610 t = header->locals [pos];
5611 var = &jit->locals [pos];
5614 if (MONO_TYPE_IS_REFERENCE (t))
5615 val_buf = g_alloca (sizeof (MonoObject*));
5617 val_buf = g_alloca (mono_class_instance_size (mono_class_from_mono_type (t)));
5618 err = decode_value (t, frame->domain, val_buf, p, &p, end);
5622 set_var (t, var, &frame->ctx, frame->domain, val_buf);
5627 return ERR_NOT_IMPLEMENTED;
5634 array_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5637 int objid, err, index, len, i, esize;
5640 objid = decode_objid (p, &p, end);
5641 err = get_object (objid, (MonoObject**)&arr);
5646 case CMD_ARRAY_REF_GET_LENGTH:
5647 buffer_add_int (buf, arr->obj.vtable->klass->rank);
5649 buffer_add_int (buf, arr->max_length);
5650 buffer_add_int (buf, 0);
5652 for (i = 0; i < arr->obj.vtable->klass->rank; ++i) {
5653 buffer_add_int (buf, arr->bounds [i].length);
5654 buffer_add_int (buf, arr->bounds [i].lower_bound);
5658 case CMD_ARRAY_REF_GET_VALUES:
5659 index = decode_int (p, &p, end);
5660 len = decode_int (p, &p, end);
5662 g_assert (index >= 0 && len >= 0);
5663 // Reordered to avoid integer overflow
5664 g_assert (!(index > arr->max_length - len));
5666 esize = mono_array_element_size (arr->obj.vtable->klass);
5667 for (i = index; i < index + len; ++i) {
5668 elem = (gpointer*)((char*)arr->vector + (i * esize));
5669 buffer_add_value (buf, &arr->obj.vtable->klass->element_class->byval_arg, elem, arr->obj.vtable->domain);
5672 case CMD_ARRAY_REF_SET_VALUES:
5673 index = decode_int (p, &p, end);
5674 len = decode_int (p, &p, end);
5676 g_assert (index >= 0 && len >= 0);
5677 // Reordered to avoid integer overflow
5678 g_assert (!(index > arr->max_length - len));
5680 esize = mono_array_element_size (arr->obj.vtable->klass);
5681 for (i = index; i < index + len; ++i) {
5682 elem = (gpointer*)((char*)arr->vector + (i * esize));
5684 decode_value (&arr->obj.vtable->klass->element_class->byval_arg, arr->obj.vtable->domain, elem, p, &p, end);
5688 return ERR_NOT_IMPLEMENTED;
5695 string_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5701 objid = decode_objid (p, &p, end);
5702 err = get_object (objid, (MonoObject**)&str);
5707 case CMD_STRING_REF_GET_VALUE:
5708 s = mono_string_to_utf8 (str);
5709 buffer_add_string (buf, s);
5713 return ERR_NOT_IMPLEMENTED;
5720 object_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
5729 if (command == CMD_OBJECT_REF_IS_COLLECTED) {
5730 objid = decode_objid (p, &p, end);
5731 err = get_object (objid, &obj);
5733 buffer_add_int (buf, 1);
5735 buffer_add_int (buf, 0);
5739 objid = decode_objid (p, &p, end);
5740 err = get_object (objid, &obj);
5745 case CMD_OBJECT_REF_GET_TYPE:
5746 buffer_add_typeid (buf, obj->vtable->domain, obj->vtable->klass);
5748 case CMD_OBJECT_REF_GET_VALUES:
5749 len = decode_int (p, &p, end);
5751 for (i = 0; i < len; ++i) {
5752 MonoClassField *f = decode_fieldid (p, &p, end, NULL, &err);
5756 /* Check that the field belongs to the object */
5758 for (k = obj->vtable->klass; k; k = k->parent) {
5759 if (k == f->parent) {
5765 return ERR_INVALID_FIELDID;
5767 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
5771 if (mono_class_field_is_special_static (f))
5772 return ERR_INVALID_FIELDID;
5774 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
5775 vtable = mono_class_vtable (obj->vtable->domain, f->parent);
5776 val = g_malloc (mono_class_instance_size (mono_class_from_mono_type (f->type)));
5777 mono_field_static_get_value (vtable, f, val);
5778 buffer_add_value (buf, f->type, val, obj->vtable->domain);
5781 buffer_add_value (buf, f->type, (guint8*)obj + f->offset, obj->vtable->domain);
5785 case CMD_OBJECT_REF_SET_VALUES:
5786 len = decode_int (p, &p, end);
5788 for (i = 0; i < len; ++i) {
5789 f = decode_fieldid (p, &p, end, NULL, &err);
5793 /* Check that the field belongs to the object */
5795 for (k = obj->vtable->klass; k; k = k->parent) {
5796 if (k == f->parent) {
5802 return ERR_INVALID_FIELDID;
5804 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
5808 if (mono_class_field_is_special_static (f))
5809 return ERR_INVALID_FIELDID;
5811 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
5812 vtable = mono_class_vtable (obj->vtable->domain, f->parent);
5814 val = g_malloc (mono_class_instance_size (mono_class_from_mono_type (f->type)));
5815 err = decode_value (f->type, obj->vtable->domain, val, p, &p, end);
5820 mono_field_static_set_value (vtable, f, val);
5823 err = decode_value (f->type, obj->vtable->domain, (guint8*)obj + f->offset, p, &p, end);
5829 case CMD_OBJECT_REF_GET_ADDRESS:
5830 buffer_add_long (buf, (gssize)obj);
5832 case CMD_OBJECT_REF_GET_DOMAIN:
5833 buffer_add_domainid (buf, obj->vtable->domain);
5836 return ERR_NOT_IMPLEMENTED;
5843 command_set_to_string (CommandSet command_set)
5845 switch (command_set) {
5848 case CMD_SET_OBJECT_REF:
5849 return "OBJECT_REF";
5850 case CMD_SET_STRING_REF:
5851 return "STRING_REF";
5852 case CMD_SET_THREAD:
5854 case CMD_SET_ARRAY_REF:
5856 case CMD_SET_EVENT_REQUEST:
5857 return "EVENT_REQUEST";
5858 case CMD_SET_STACK_FRAME:
5859 return "STACK_FRAME";
5860 case CMD_SET_APPDOMAIN:
5862 case CMD_SET_ASSEMBLY:
5864 case CMD_SET_METHOD:
5868 case CMD_SET_MODULE:
5880 * This thread handles communication with the debugger client using a JDWP
5883 static guint32 WINAPI
5884 debugger_thread (void *arg)
5886 int res, len, id, flags, command_set, command;
5887 guint8 header [HEADER_LENGTH];
5888 guint8 *data, *p, *end;
5893 DEBUG (1, fprintf (log_file, "[dbg] Agent thread started, pid=%p\n", (gpointer)GetCurrentThreadId ()));
5895 debugger_thread_id = GetCurrentThreadId ();
5897 mono_jit_thread_attach (mono_get_root_domain ());
5899 mono_thread_internal_current ()->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
5901 mono_set_is_debugger_attached (TRUE);
5904 res = recv (conn_fd, header, HEADER_LENGTH, 0);
5906 /* This will break if the socket is closed during shutdown too */
5907 if (res != HEADER_LENGTH)
5911 end = header + HEADER_LENGTH;
5913 len = decode_int (p, &p, end);
5914 id = decode_int (p, &p, end);
5915 flags = decode_byte (p, &p, end);
5916 command_set = decode_byte (p, &p, end);
5917 command = decode_byte (p, &p, end);
5919 g_assert (flags == 0);
5921 DEBUG (1, fprintf (log_file, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set), command, id));
5923 data = g_malloc (len - HEADER_LENGTH);
5924 if (len - HEADER_LENGTH > 0)
5926 res = recv (conn_fd, data, len - HEADER_LENGTH, 0);
5927 if (res != len - HEADER_LENGTH)
5932 end = data + (len - HEADER_LENGTH);
5934 buffer_init (&buf, 128);
5939 /* Process the request */
5940 switch (command_set) {
5942 err = vm_commands (command, id, p, end, &buf);
5943 if (!err && command == CMD_VM_INVOKE_METHOD)
5944 /* Sent after the invoke is complete */
5947 case CMD_SET_EVENT_REQUEST:
5948 err = event_commands (command, p, end, &buf);
5950 case CMD_SET_APPDOMAIN:
5951 err = domain_commands (command, p, end, &buf);
5953 case CMD_SET_ASSEMBLY:
5954 err = assembly_commands (command, p, end, &buf);
5956 case CMD_SET_MODULE:
5957 err = module_commands (command, p, end, &buf);
5960 err = type_commands (command, p, end, &buf);
5962 case CMD_SET_METHOD:
5963 err = method_commands (command, p, end, &buf);
5965 case CMD_SET_THREAD:
5966 err = thread_commands (command, p, end, &buf);
5968 case CMD_SET_STACK_FRAME:
5969 err = frame_commands (command, p, end, &buf);
5971 case CMD_SET_ARRAY_REF:
5972 err = array_commands (command, p, end, &buf);
5974 case CMD_SET_STRING_REF:
5975 err = string_commands (command, p, end, &buf);
5977 case CMD_SET_OBJECT_REF:
5978 err = object_commands (command, p, end, &buf);
5981 err = ERR_NOT_IMPLEMENTED;
5985 send_reply_packet (id, err, &buf);
5990 if (command_set == CMD_SET_VM && command == CMD_VM_DISPOSE)
5994 mono_set_is_debugger_attached (FALSE);
5996 mono_mutex_lock (&debugger_thread_exited_mutex);
5997 debugger_thread_exited = TRUE;
5998 mono_cond_signal (&debugger_thread_exited_cond);
5999 mono_mutex_unlock (&debugger_thread_exited_mutex);
6001 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6006 #else /* DISABLE_DEBUGGER_AGENT */
6009 mono_debugger_agent_parse_options (char *options)
6011 g_error ("This runtime is configure with the debugger agent disabled.");
6015 mono_debugger_agent_init (void)
6020 mono_debugger_agent_breakpoint_hit (void *sigctx)
6025 mono_debugger_agent_single_step_event (void *sigctx)
6030 mono_debugger_agent_free_domain_info (MonoDomain *domain)
6035 mono_debugger_agent_thread_interrupt (void *sigctx, MonoJitInfo *ji)
6041 mono_debugger_agent_handle_exception (MonoException *ext, MonoContext *ctx)
6046 mono_debugger_agent_handle_unhandled_exception (MonoException *exc, MonoContext *ctx)