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_SELECT_H
18 #include <sys/select.h>
20 #ifdef HAVE_SYS_SOCKET_H
21 #include <sys/socket.h>
23 #ifdef HAVE_NETINET_TCP_H
24 #include <netinet/tcp.h>
26 #ifdef HAVE_NETINET_IN_H
27 #include <netinet/in.h>
42 #ifdef HAVE_UCONTEXT_H
52 /* cygwin's headers do not seem to define these */
53 void WSAAPI
freeaddrinfo (struct addrinfo
*);
54 int WSAAPI
getaddrinfo (const char*,const char*,const struct addrinfo
*,
56 int WSAAPI
getnameinfo(const struct sockaddr
*,socklen_t
,char*,DWORD
,
61 #ifdef PLATFORM_ANDROID
63 #include <linux/tcp.h>
64 #include <sys/endian.h>
67 #include <mono/metadata/mono-debug.h>
68 #include <mono/metadata/mono-debug-debugger.h>
69 #include <mono/metadata/debug-mono-symfile.h>
70 #include <mono/metadata/gc-internal.h>
71 #include <mono/metadata/threads-types.h>
72 #include <mono/metadata/socket-io.h>
73 #include <mono/utils/mono-semaphore.h>
74 #include "debugger-agent.h"
77 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
78 #define DISABLE_DEBUGGER_AGENT 1
81 #ifdef DISABLE_SOFT_DEBUG
82 #define DISABLE_DEBUGGER_AGENT 1
85 #ifndef DISABLE_DEBUGGER_AGENT
86 #include <mono/io-layer/mono-mutex.h>
88 /* Definitions to make backporting to 2.6 easier */
89 //#define MonoInternalThread MonoThread
90 //#define mono_thread_internal_current mono_thread_current
91 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
114 MonoDebugMethodJitInfo
*jit
;
117 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
118 * the frame can become invalid.
123 typedef struct _InvokeData InvokeData
;
131 /* This is the context which needs to be restored after the invoke */
135 * If this is set, invoke this method with the arguments given by ARGS.
139 guint32 suspend_count
;
141 InvokeData
*last_invoke
;
148 gboolean has_context
;
149 gpointer resume_event
;
150 /* This is computed on demand when it is requested using the wire protocol */
151 /* It is freed up when the thread is resumed */
155 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
158 gboolean frames_up_to_date
;
160 * Points to data about a pending invoke which needs to be executed after the thread
163 InvokeData
*pending_invoke
;
165 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
170 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
171 * within a finite amount of time.
175 * Set to TRUE if this thread is suspended in suspend_current ().
177 gboolean really_suspended
;
178 /* Used to pass the context to the breakpoint/single step handler */
179 MonoContext handler_ctx
;
180 /* Whenever thread_stop () was called for this thread */
183 /* Number of thread interruptions not yet processed */
184 gint32 interrupt_count
;
186 /* Whenever to disable breakpoints (used during invokes) */
187 gboolean disable_breakpoints
;
190 * Number of times this thread has been resumed using resume_thread ().
192 guint32 resume_count
;
194 MonoInternalThread
*thread
;
197 * Information about the frame which transitioned to native code for running
200 StackFrameInfo async_last_frame
;
203 * The context where the stack walk can be started for running threads.
205 MonoContext async_ctx
;
207 gboolean has_async_ctx
;
210 * The lmf where the stack walk can be started for running threads.
215 * The callee address of the last mono_runtime_invoke call
217 gpointer invoke_addr
;
219 gboolean abort_requested
;
222 * The current mono_runtime_invoke invocation.
228 * Wire Protocol definitions
231 #define HEADER_LENGTH 11
233 #define MAJOR_VERSION 2
234 #define MINOR_VERSION 1
238 CMD_SET_OBJECT_REF
= 9,
239 CMD_SET_STRING_REF
= 10,
241 CMD_SET_ARRAY_REF
= 13,
242 CMD_SET_EVENT_REQUEST
= 15,
243 CMD_SET_STACK_FRAME
= 16,
244 CMD_SET_APPDOMAIN
= 20,
245 CMD_SET_ASSEMBLY
= 21,
253 EVENT_KIND_VM_START
= 0,
254 EVENT_KIND_VM_DEATH
= 1,
255 EVENT_KIND_THREAD_START
= 2,
256 EVENT_KIND_THREAD_DEATH
= 3,
257 EVENT_KIND_APPDOMAIN_CREATE
= 4,
258 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
259 EVENT_KIND_METHOD_ENTRY
= 6,
260 EVENT_KIND_METHOD_EXIT
= 7,
261 EVENT_KIND_ASSEMBLY_LOAD
= 8,
262 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
263 EVENT_KIND_BREAKPOINT
= 10,
264 EVENT_KIND_STEP
= 11,
265 EVENT_KIND_TYPE_LOAD
= 12,
266 EVENT_KIND_EXCEPTION
= 13
270 SUSPEND_POLICY_NONE
= 0,
271 SUSPEND_POLICY_EVENT_THREAD
= 1,
272 SUSPEND_POLICY_ALL
= 2
277 ERR_INVALID_OBJECT
= 20,
278 ERR_INVALID_FIELDID
= 25,
279 ERR_INVALID_FRAMEID
= 30,
280 ERR_NOT_IMPLEMENTED
= 100,
281 ERR_NOT_SUSPENDED
= 101,
282 ERR_INVALID_ARGUMENT
= 102,
284 ERR_NO_INVOCATION
= 104
289 MOD_KIND_THREAD_ONLY
= 3,
290 MOD_KIND_LOCATION_ONLY
= 7,
291 MOD_KIND_EXCEPTION_ONLY
= 8,
293 MOD_KIND_ASSEMBLY_ONLY
= 11
308 TOKEN_TYPE_STRING
= 0,
310 TOKEN_TYPE_FIELD
= 2,
311 TOKEN_TYPE_METHOD
= 3,
312 TOKEN_TYPE_UNKNOWN
= 4
316 VALUE_TYPE_ID_NULL
= 0xf0,
317 VALUE_TYPE_ID_TYPE
= 0xf1
321 FRAME_FLAG_DEBUGGER_INVOKE
= 1
325 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
326 INVOKE_FLAG_SINGLE_THREADED
= 2
331 CMD_VM_ALL_THREADS
= 2,
336 CMD_VM_INVOKE_METHOD
= 7,
337 CMD_VM_SET_PROTOCOL_VERSION
= 8,
338 CMD_VM_ABORT_INVOKE
= 9
342 CMD_THREAD_GET_FRAME_INFO
= 1,
343 CMD_THREAD_GET_NAME
= 2,
344 CMD_THREAD_GET_STATE
= 3,
345 CMD_THREAD_GET_INFO
= 4
349 CMD_EVENT_REQUEST_SET
= 1,
350 CMD_EVENT_REQUEST_CLEAR
= 2,
351 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
359 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
360 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
361 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
362 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
363 CMD_APPDOMAIN_CREATE_STRING
= 5,
364 CMD_APPDOMAIN_GET_CORLIB
= 6,
365 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7,
369 CMD_ASSEMBLY_GET_LOCATION
= 1,
370 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
371 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
372 CMD_ASSEMBLY_GET_OBJECT
= 4,
373 CMD_ASSEMBLY_GET_TYPE
= 5,
374 CMD_ASSEMBLY_GET_NAME
= 6
378 CMD_MODULE_GET_INFO
= 1,
382 CMD_METHOD_GET_NAME
= 1,
383 CMD_METHOD_GET_DECLARING_TYPE
= 2,
384 CMD_METHOD_GET_DEBUG_INFO
= 3,
385 CMD_METHOD_GET_PARAM_INFO
= 4,
386 CMD_METHOD_GET_LOCALS_INFO
= 5,
387 CMD_METHOD_GET_INFO
= 6,
388 CMD_METHOD_GET_BODY
= 7,
389 CMD_METHOD_RESOLVE_TOKEN
= 8,
393 CMD_TYPE_GET_INFO
= 1,
394 CMD_TYPE_GET_METHODS
= 2,
395 CMD_TYPE_GET_FIELDS
= 3,
396 CMD_TYPE_GET_VALUES
= 4,
397 CMD_TYPE_GET_OBJECT
= 5,
398 CMD_TYPE_GET_SOURCE_FILES
= 6,
399 CMD_TYPE_SET_VALUES
= 7,
400 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
401 CMD_TYPE_GET_PROPERTIES
= 9,
402 CMD_TYPE_GET_CATTRS
= 10,
403 CMD_TYPE_GET_FIELD_CATTRS
= 11,
404 CMD_TYPE_GET_PROPERTY_CATTRS
= 12
408 CMD_STACK_FRAME_GET_VALUES
= 1,
409 CMD_STACK_FRAME_GET_THIS
= 2,
410 CMD_STACK_FRAME_SET_VALUES
= 3
414 CMD_ARRAY_REF_GET_LENGTH
= 1,
415 CMD_ARRAY_REF_GET_VALUES
= 2,
416 CMD_ARRAY_REF_SET_VALUES
= 3,
420 CMD_STRING_REF_GET_VALUE
= 1,
424 CMD_OBJECT_REF_GET_TYPE
= 1,
425 CMD_OBJECT_REF_GET_VALUES
= 2,
426 CMD_OBJECT_REF_IS_COLLECTED
= 3,
427 CMD_OBJECT_REF_GET_ADDRESS
= 4,
428 CMD_OBJECT_REF_GET_DOMAIN
= 5,
429 CMD_OBJECT_REF_SET_VALUES
= 6
435 int count
; /* For kind == MOD_KIND_COUNT */
436 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
437 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
438 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
440 gboolean caught
, uncaught
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
449 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
453 * Describes a single step request.
457 MonoInternalThread
*thread
;
462 MonoMethod
*last_method
;
464 /* Whenever single stepping is performed using start/stop_single_stepping () */
466 /* The list of breakpoints used to implement step-over */
471 * Contains additional information for an event
474 /* For EVENT_KIND_EXCEPTION */
476 MonoContext catch_ctx
;
480 /* Dummy structure used for the profiler callbacks */
485 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
491 static AgentConfig agent_config
;
494 * Whenever the agent is fully initialized.
495 * When using the onuncaught or onthrow options, only some parts of the agent are
496 * initialized on startup, and the full initialization which includes connection
497 * establishment and the startup of the agent thread is only done in response to
500 static gint32 inited
;
504 static int packet_id
= 0;
506 static int objref_id
= 0;
508 static int event_request_id
= 0;
510 static int frame_id
= 0;
512 static GPtrArray
*event_requests
;
514 static guint32 debugger_tls_id
;
516 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
518 /* Maps MonoInternalThread -> DebuggerTlsData */
519 static MonoGHashTable
*thread_to_tls
;
521 /* Maps tid -> MonoInternalThread */
522 static MonoGHashTable
*tid_to_thread
;
524 /* Maps tid -> MonoThread (not MonoInternalThread) */
525 static MonoGHashTable
*tid_to_thread_obj
;
527 static gsize debugger_thread_id
;
529 static HANDLE debugger_thread_handle
;
531 static int log_level
;
533 static FILE *log_file
;
535 /* Classes whose class load event has been sent */
536 static GHashTable
*loaded_classes
;
538 /* Assemblies whose assembly load event has no been sent yet */
539 static GPtrArray
*pending_assembly_loads
;
541 /* Whenever the debugger thread has exited */
542 static gboolean debugger_thread_exited
;
544 /* Cond variable used to wait for debugger_thread_exited becoming true */
545 static mono_cond_t debugger_thread_exited_cond
;
547 /* Mutex for the cond var above */
548 static mono_mutex_t debugger_thread_exited_mutex
;
550 static DebuggerProfiler debugger_profiler
;
552 /* The single step request instance */
553 static SingleStepReq
*ss_req
= NULL
;
554 static gpointer ss_invoke_addr
= NULL
;
556 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
557 /* Number of single stepping operations in progress */
561 /* The protocol version of the client */
562 static int major_version
, minor_version
;
564 /* Whenever the variables above are set by the client */
565 static gboolean protocol_version_set
;
567 static void transport_connect (const char *host
, int port
);
569 static guint32 WINAPI
debugger_thread (void *arg
);
571 static void runtime_initialized (MonoProfiler
*prof
);
573 static void runtime_shutdown (MonoProfiler
*prof
);
575 static void thread_startup (MonoProfiler
*prof
, intptr_t tid
);
577 static void thread_end (MonoProfiler
*prof
, intptr_t tid
);
579 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
581 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
583 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
585 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
587 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
589 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
591 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
593 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
595 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
597 static void start_single_stepping (void);
599 static void stop_single_stepping (void);
601 static void suspend_current (void);
603 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
605 /* Submodule init/cleanup */
606 static void breakpoints_init (void);
607 static void breakpoints_cleanup (void);
609 static void objrefs_init (void);
610 static void objrefs_cleanup (void);
612 static void ids_init (void);
613 static void ids_cleanup (void);
615 static void suspend_init (void);
617 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
);
618 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
619 static void ss_destroy (SingleStepReq
*req
);
621 static void start_debugger_thread (void);
623 static void finish_agent_init (gboolean on_startup
);
626 parse_address (char *address
, char **host
, int *port
)
628 char *pos
= strchr (address
, ':');
630 if (pos
== NULL
|| pos
== address
)
633 *host
= g_malloc (pos
- address
+ 1);
634 strncpy (*host
, address
, pos
- address
);
635 (*host
) [pos
- address
] = '\0';
637 *port
= atoi (pos
+ 1);
645 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
646 fprintf (stderr
, "Available options:\n");
647 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
648 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
649 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
650 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
651 fprintf (stderr
, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
652 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
653 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
657 parse_flag (const char *option
, char *flag
)
659 if (!strcmp (flag
, "y"))
661 else if (!strcmp (flag
, "n"))
664 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
671 mono_debugger_agent_parse_options (char *options
)
677 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
678 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
682 agent_config
.enabled
= TRUE
;
683 agent_config
.suspend
= TRUE
;
684 agent_config
.server
= FALSE
;
686 args
= g_strsplit (options
, ",", -1);
687 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
690 if (strncmp (arg
, "transport=", 10) == 0) {
691 agent_config
.transport
= g_strdup (arg
+ 10);
692 } else if (strncmp (arg
, "address=", 8) == 0) {
693 agent_config
.address
= g_strdup (arg
+ 8);
694 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
695 agent_config
.log_level
= atoi (arg
+ 9);
696 } else if (strncmp (arg
, "logfile=", 8) == 0) {
697 agent_config
.log_file
= g_strdup (arg
+ 8);
698 } else if (strncmp (arg
, "suspend=", 8) == 0) {
699 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
700 } else if (strncmp (arg
, "server=", 7) == 0) {
701 agent_config
.server
= parse_flag ("server", arg
+ 7);
702 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
703 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
704 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
705 /* We support multiple onthrow= options */
706 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
707 } else if (strncmp (arg
, "onthrow", 7) == 0) {
708 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
709 } else if (strncmp (arg
, "help", 4) == 0) {
712 } else if (strncmp (arg
, "timeout=", 8) == 0) {
713 agent_config
.timeout
= atoi (arg
+ 8);
714 } else if (strncmp (arg
, "launch=", 7) == 0) {
715 agent_config
.launch
= g_strdup (arg
+ 7);
722 if (agent_config
.transport
== NULL
) {
723 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
726 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
727 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
731 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
732 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
736 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
737 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
743 mono_debugger_agent_init (void)
745 if (!agent_config
.enabled
)
748 /* Need to know whenever a thread has acquired the loader mutex */
749 mono_loader_lock_track_ownership (TRUE
);
751 event_requests
= g_ptr_array_new ();
753 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
754 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
756 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
757 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
758 mono_profiler_install_runtime_initialized (runtime_initialized
);
759 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
760 mono_profiler_install_thread (thread_startup
, thread_end
);
761 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
762 mono_profiler_install_jit_end (jit_end
);
763 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
765 debugger_tls_id
= TlsAlloc ();
767 thread_to_tls
= mono_g_hash_table_new (NULL
, NULL
);
768 MONO_GC_REGISTER_ROOT (thread_to_tls
);
770 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
771 MONO_GC_REGISTER_ROOT (tid_to_thread
);
773 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
774 MONO_GC_REGISTER_ROOT (tid_to_thread_obj
);
776 loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
777 pending_assembly_loads
= g_ptr_array_new ();
779 log_level
= agent_config
.log_level
;
781 if (agent_config
.log_file
) {
782 log_file
= fopen (agent_config
.log_file
, "w+");
784 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
796 mini_get_debug_options ()->gen_seq_points
= TRUE
;
798 * This is needed because currently we don't handle liveness info.
800 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
802 /* This is needed because we can't set local variables in registers yet */
803 mono_disable_optimizations (MONO_OPT_LINEARS
);
805 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
806 finish_agent_init (TRUE
);
812 * Finish the initialization of the agent. This involves connecting the transport
813 * and starting the agent thread. This is either done at startup, or
814 * in response to some event like an unhandled exception.
817 finish_agent_init (gboolean on_startup
)
823 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
826 if (agent_config
.launch
) {
829 // FIXME: Generated address
830 // FIXME: Races with transport_connect ()
832 argv
[0] = agent_config
.launch
;
833 argv
[1] = agent_config
.transport
;
834 argv
[2] = agent_config
.address
;
837 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
839 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
844 if (agent_config
.address
) {
845 res
= parse_address (agent_config
.address
, &host
, &port
);
852 transport_connect (host
, port
);
855 /* Do some which is usually done after sending the VMStart () event */
856 vm_start_event_sent
= TRUE
;
857 start_debugger_thread ();
862 mono_debugger_agent_cleanup (void)
867 /* This will interrupt the agent thread */
868 /* Close the read part only so it can still send back replies */
870 shutdown (conn_fd
, SD_RECEIVE
);
872 shutdown (conn_fd
, SHUT_RD
);
876 * Wait for the thread to exit.
878 * If we continue with the shutdown without waiting for it, then the client might
879 * not receive an answer to its last command like a resume.
880 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
883 //WaitForSingleObject (debugger_thread_handle, INFINITE);
884 if (GetCurrentThreadId () != debugger_thread_id
) {
885 mono_mutex_lock (&debugger_thread_exited_mutex
);
886 if (!debugger_thread_exited
) {
888 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
889 mono_mutex_unlock (&debugger_thread_exited_mutex
);
891 mono_mutex_lock (&debugger_thread_exited_mutex
);
894 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
897 mono_mutex_unlock (&debugger_thread_exited_mutex
);
900 breakpoints_cleanup ();
905 shutdown (conn_fd
, SD_BOTH
);
907 shutdown (conn_fd
, SHUT_RDWR
);
910 mono_mutex_destroy (&debugger_thread_exited_mutex
);
911 mono_cond_destroy (&debugger_thread_exited_cond
);
917 * recv() + handle incomplete reads and EINTR
920 recv_length (int fd
, void *buf
, int len
, int flags
)
926 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
929 } while ((res
> 0 && total
< len
) || (res
== -1 && errno
== EINTR
));
935 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
938 transport_connect (const char *host
, int port
)
940 struct addrinfo hints
;
941 struct addrinfo
*result
, *rp
;
943 char port_string
[128];
944 char handshake_msg
[128];
950 sprintf (port_string
, "%d", port
);
952 mono_network_init ();
954 /* Obtain address(es) matching host/port */
956 memset (&hints
, 0, sizeof (struct addrinfo
));
957 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
958 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
960 hints
.ai_protocol
= 0; /* Any protocol */
962 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
964 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d: %s\n", host
, port
, gai_strerror (s
));
969 if (agent_config
.server
) {
970 /* Wait for a connection */
972 struct sockaddr_in addr
;
975 /* No address, generate one */
976 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
979 /* This will bind the socket to a random port */
980 res
= listen (sfd
, 16);
982 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno
));
986 addrlen
= sizeof (addr
);
987 memset (&addr
, 0, sizeof (addr
));
988 res
= getsockname (sfd
, &addr
, &addrlen
);
992 port
= ntohs (addr
.sin_port
);
994 /* Emit the address to stdout */
995 /* FIXME: Should print another interface, not localhost */
996 printf ("%s:%d\n", host
, port
);
998 /* Listen on the provided address */
999 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1000 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1005 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1009 res
= listen (sfd
, 16);
1017 * this function is not present on win2000 which we still support, and the
1018 * workaround described here:
1019 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1020 * only works with MSVC.
1022 freeaddrinfo (result
);
1026 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1028 if (agent_config
.timeout
) {
1033 tv
.tv_usec
= agent_config
.timeout
* 1000;
1035 FD_SET (sfd
, &readfds
);
1036 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1038 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1043 conn_fd
= accept (sfd
, NULL
, NULL
);
1044 if (conn_fd
== -1) {
1045 fprintf (stderr
, "debugger-agent: Unable to listen on %s:%d\n", host
, port
);
1049 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1051 /* Connect to the specified address */
1052 /* FIXME: Respect the timeout */
1053 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1054 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1059 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1060 break; /* Success */
1068 /* See the comment above */
1069 freeaddrinfo (result
);
1073 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1078 /* Write handshake message */
1079 sprintf (handshake_msg
, "DWP-Handshake");
1081 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1082 } while (res
== -1 && errno
== EINTR
);
1083 g_assert (res
!= -1);
1086 res
= recv_length (conn_fd
, buf
, strlen (handshake_msg
), 0);
1087 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1088 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1093 * To support older clients, the client sends its protocol version after connecting
1094 * using a command. Until that is received, default to our protocol version.
1096 major_version
= MAJOR_VERSION
;
1097 minor_version
= MINOR_VERSION
;
1098 protocol_version_set
= FALSE
;
1101 * Set TCP_NODELAY on the socket so the client receives events/command
1102 * results immediately.
1106 int result
= setsockopt(conn_fd
,
1111 g_assert (result
>= 0);
1116 transport_send (guint8
*data
, int len
)
1121 res
= send (conn_fd
, data
, len
, 0);
1122 } while (res
== -1 && errno
== EINTR
);
1130 start_debugger_thread (void)
1134 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1135 g_assert (debugger_thread_handle
);
1139 * Functions to decode protocol data
1143 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1146 g_assert (*endbuf
<= limit
);
1151 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1154 g_assert (*endbuf
<= limit
);
1156 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1159 static inline gint64
1160 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1162 guint32 high
= decode_int (buf
, &buf
, limit
);
1163 guint32 low
= decode_int (buf
, &buf
, limit
);
1167 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1171 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1173 return decode_int (buf
, endbuf
, limit
);
1177 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1179 int len
= decode_int (buf
, &buf
, limit
);
1182 s
= g_malloc (len
+ 1);
1185 memcpy (s
, buf
, len
);
1194 * Functions to encode protocol data
1198 guint8
*buf
, *p
, *end
;
1202 buffer_init (Buffer
*buf
, int size
)
1204 buf
->buf
= g_malloc (size
);
1206 buf
->end
= buf
->buf
+ size
;
1210 buffer_make_room (Buffer
*buf
, int size
)
1212 if (buf
->end
- buf
->p
< size
) {
1213 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1214 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1215 size
= buf
->p
- buf
->buf
;
1218 buf
->end
= buf
->buf
+ new_size
;
1223 buffer_add_byte (Buffer
*buf
, guint8 val
)
1225 buffer_make_room (buf
, 1);
1231 buffer_add_int (Buffer
*buf
, guint32 val
)
1233 buffer_make_room (buf
, 4);
1234 buf
->p
[0] = (val
>> 24) & 0xff;
1235 buf
->p
[1] = (val
>> 16) & 0xff;
1236 buf
->p
[2] = (val
>> 8) & 0xff;
1237 buf
->p
[3] = (val
>> 0) & 0xff;
1242 buffer_add_long (Buffer
*buf
, guint64 l
)
1244 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1245 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1249 buffer_add_id (Buffer
*buf
, int id
)
1251 buffer_add_int (buf
, (guint64
)id
);
1255 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1257 buffer_make_room (buf
, len
);
1258 memcpy (buf
->p
, data
, len
);
1263 buffer_add_string (Buffer
*buf
, const char *str
)
1268 buffer_add_int (buf
, 0);
1271 buffer_add_int (buf
, len
);
1272 buffer_add_data (buf
, (guint8
*)str
, len
);
1277 buffer_free (Buffer
*buf
)
1283 send_packet (int command_set
, int command
, Buffer
*data
)
1289 id
= InterlockedIncrement (&packet_id
);
1291 len
= data
->p
- data
->buf
+ 11;
1292 buffer_init (&buf
, len
);
1293 buffer_add_int (&buf
, len
);
1294 buffer_add_int (&buf
, id
);
1295 buffer_add_byte (&buf
, 0); /* flags */
1296 buffer_add_byte (&buf
, command_set
);
1297 buffer_add_byte (&buf
, command
);
1298 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1300 res
= transport_send (buf
.buf
, len
);
1308 send_reply_packet (int id
, int error
, Buffer
*data
)
1314 len
= data
->p
- data
->buf
+ 11;
1315 buffer_init (&buf
, len
);
1316 buffer_add_int (&buf
, len
);
1317 buffer_add_int (&buf
, id
);
1318 buffer_add_byte (&buf
, 0x80); /* flags */
1319 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1320 buffer_add_byte (&buf
, error
);
1321 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1323 res
= transport_send (buf
.buf
, len
);
1335 * Represents an object accessible by the debugger client.
1338 /* Unique id used in the wire protocol to refer to objects */
1341 * A weakref gc handle pointing to the object. The gc handle is used to
1342 * detect if the object was garbage collected.
1347 /* Maps objid -> ObjRef */
1348 static GHashTable
*objrefs
;
1351 free_objref (gpointer value
)
1355 mono_gchandle_free (o
->handle
);
1363 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1367 objrefs_cleanup (void)
1369 g_hash_table_destroy (objrefs
);
1373 static GHashTable
*obj_to_objref
;
1376 * Return an ObjRef for OBJ.
1379 get_objref (MonoObject
*obj
)
1390 /* Use a hash table with masked pointers to internalize object references */
1391 /* FIXME: This can grow indefinitely */
1392 mono_loader_lock ();
1395 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1397 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1398 /* ref might refer to a different object with the same addr which was GCd */
1399 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1400 mono_loader_unlock ();
1404 ref
= g_new0 (ObjRef
, 1);
1405 ref
->id
= InterlockedIncrement (&objref_id
);
1406 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1408 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1409 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1411 mono_loader_unlock ();
1417 get_objid (MonoObject
*obj
)
1419 return get_objref (obj
)->id
;
1423 * Set OBJ to the object identified by OBJID.
1424 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1428 get_object_allow_null (int objid
, MonoObject
**obj
)
1438 return ERR_INVALID_OBJECT
;
1440 mono_loader_lock ();
1442 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1445 *obj
= mono_gchandle_get_target (ref
->handle
);
1446 mono_loader_unlock ();
1448 return ERR_INVALID_OBJECT
;
1451 mono_loader_unlock ();
1452 return ERR_INVALID_OBJECT
;
1457 get_object (int objid
, MonoObject
**obj
)
1459 int err
= get_object_allow_null (objid
, obj
);
1464 return ERR_INVALID_OBJECT
;
1469 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1471 return decode_id (buf
, endbuf
, limit
);
1475 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1477 buffer_add_id (buf
, get_objid (o
));
1496 * Represents a runtime structure accessible to the debugger client
1499 /* Unique id used in the wire protocol */
1501 /* Domain of the runtime structure, NULL if the domain was unloaded */
1508 MonoAssembly
*assembly
;
1509 MonoClassField
*field
;
1511 MonoProperty
*property
;
1516 /* Maps runtime structure -> Id */
1517 GHashTable
*val_to_id
[ID_NUM
];
1521 static GPtrArray
*ids
[ID_NUM
];
1528 for (i
= 0; i
< ID_NUM
; ++i
)
1529 ids
[i
] = g_ptr_array_new ();
1537 for (i
= 0; i
< ID_NUM
; ++i
) {
1539 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1540 g_free (g_ptr_array_index (ids
[i
], j
));
1541 g_ptr_array_free (ids
[i
], TRUE
);
1548 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1550 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1554 for (i
= 0; i
< ID_NUM
; ++i
)
1555 if (info
->val_to_id
[i
])
1556 g_hash_table_destroy (info
->val_to_id
[i
]);
1560 domain_jit_info (domain
)->agent_info
= NULL
;
1562 /* Clear ids referencing structures in the domain */
1563 for (i
= 0; i
< ID_NUM
; ++i
) {
1565 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1566 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1567 if (id
->domain
== domain
)
1575 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1578 AgentDomainInfo
*info
;
1583 mono_loader_lock ();
1585 mono_domain_lock (domain
);
1587 if (!domain_jit_info (domain
)->agent_info
)
1588 domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1589 info
= domain_jit_info (domain
)->agent_info
;
1590 if (info
->val_to_id
[type
] == NULL
)
1591 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1593 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1595 mono_domain_unlock (domain
);
1596 mono_loader_unlock ();
1600 id
= g_new0 (Id
, 1);
1602 id
->id
= ids
[type
]->len
+ 1;
1603 id
->domain
= domain
;
1606 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1608 mono_domain_unlock (domain
);
1610 g_ptr_array_add (ids
[type
], id
);
1612 mono_loader_unlock ();
1617 static inline gpointer
1618 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1622 int id
= decode_id (buf
, endbuf
, limit
);
1631 // FIXME: error handling
1632 mono_loader_lock ();
1633 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1635 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1636 mono_loader_unlock ();
1638 if (res
->domain
== NULL
) {
1639 *err
= ERR_UNLOADED
;
1644 *domain
= res
->domain
;
1646 return res
->data
.val
;
1650 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1652 buffer_add_id (buf
, get_id (domain
, type
, val
));
1655 static inline MonoClass
*
1656 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1658 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1661 static inline MonoAssembly
*
1662 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1664 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1667 static inline MonoImage
*
1668 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1670 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1673 static inline MonoMethod
*
1674 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1676 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1679 static inline MonoClassField
*
1680 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1682 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1685 static inline MonoDomain
*
1686 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1688 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1691 static inline MonoProperty
*
1692 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1694 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1698 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1700 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1704 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1706 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1710 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1712 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1716 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1718 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1722 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1724 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1728 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1730 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1734 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1736 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1739 static void invoke_method (void);
1746 * save_thread_context:
1748 * Set CTX as the current threads context which is used for computing stack traces.
1749 * This function is signal-safe.
1752 save_thread_context (MonoContext
*ctx
)
1754 DebuggerTlsData
*tls
;
1756 tls
= TlsGetValue (debugger_tls_id
);
1760 memcpy (&tls
->ctx
, ctx
, sizeof (MonoContext
));
1762 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1763 MONO_INIT_CONTEXT_FROM_CURRENT (&tls
->ctx
);
1765 MONO_INIT_CONTEXT_FROM_FUNC (&tls
->ctx
, save_thread_context
);
1769 tls
->lmf
= mono_get_lmf ();
1770 tls
->domain
= mono_domain_get ();
1771 tls
->has_context
= TRUE
;
1774 /* The number of times the runtime is suspended */
1775 static gint32 suspend_count
;
1777 /* Number of threads suspended */
1779 * If this is equal to the size of thread_to_tls, the runtime is considered
1782 static gint32 threads_suspend_count
;
1784 static mono_mutex_t suspend_mutex
;
1786 /* Cond variable used to wait for suspend_count becoming 0 */
1787 static mono_cond_t suspend_cond
;
1789 /* Semaphore used to wait for a thread becoming suspended */
1790 static MonoSemType suspend_sem
;
1795 mono_mutex_init (&suspend_mutex
, NULL
);
1796 mono_cond_init (&suspend_cond
, NULL
);
1797 MONO_SEM_INIT (&suspend_sem
, 0);
1802 StackFrameInfo last_frame
;
1803 gboolean last_frame_set
;
1806 } GetLastFrameUserData
;
1809 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
1811 GetLastFrameUserData
*data
= user_data
;
1813 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
1816 if (!data
->last_frame_set
) {
1817 /* Store the last frame */
1818 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
1819 data
->last_frame_set
= TRUE
;
1822 /* Store the context/lmf for the frame above the last frame */
1823 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
1824 data
->lmf
= info
->lmf
;
1831 * mono_debugger_agent_thread_interrupt:
1833 * Called by the abort signal handler.
1834 * Should be signal safe.
1837 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
1839 DebuggerTlsData
*tls
;
1844 tls
= TlsGetValue (debugger_tls_id
);
1849 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1850 * guarantee the signal handler will be called that many times. Instead of tracking
1851 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1852 * has been requested that hasn't been handled yet, otherwise we can have threads
1853 * refuse to die when VM_EXIT is called
1855 #if defined(__APPLE__)
1856 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
1860 * We use interrupt_count to determine whenever this interrupt should be processed
1861 * by us or the normal interrupt processing code in the signal handler.
1862 * There is no race here with notify_thread (), since the signal is sent after
1863 * incrementing interrupt_count.
1865 if (tls
->interrupt_count
== 0)
1868 InterlockedDecrement (&tls
->interrupt_count
);
1871 // FIXME: Races when the thread leaves managed code before hitting a single step
1875 /* Running managed code, will be suspended by the single step code */
1876 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
1880 * Running native code, will be suspended when it returns to/enters
1881 * managed code. Treat it as already suspended.
1882 * This might interrupt the code in process_single_step_inner (), we use the
1883 * tls->suspending flag to avoid races when that happens.
1885 if (!tls
->suspended
&& !tls
->suspending
) {
1887 GetLastFrameUserData data
;
1889 // FIXME: printf is not signal safe, but this is only used during
1890 // debugger debugging
1891 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
1892 //save_thread_context (&ctx);
1895 /* Already terminated */
1899 * We are in a difficult position: we want to be able to provide stack
1900 * traces for this thread, but we can't use the current ctx+lmf, since
1901 * the thread is still running, so it might return to managed code,
1902 * making these invalid.
1903 * So we start a stack walk and save the first frame, along with the
1904 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1905 * suspended when it returns to managed code, so the parent's ctx should
1908 data
.last_frame_set
= FALSE
;
1910 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1911 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame
, mono_domain_get (), &ctx
, FALSE
, tls
->thread
, mono_get_lmf (), &data
);
1913 if (data
.last_frame_set
) {
1914 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
1915 memcpy (&tls
->async_ctx
, &data
.ctx
, sizeof (MonoContext
));
1916 tls
->async_lmf
= data
.lmf
;
1917 tls
->has_async_ctx
= TRUE
;
1918 tls
->domain
= mono_domain_get ();
1919 memcpy (&tls
->ctx
, &ctx
, sizeof (MonoContext
));
1921 tls
->has_async_ctx
= FALSE
;
1924 mono_memory_barrier ();
1926 tls
->suspended
= TRUE
;
1927 MONO_SEM_POST (&suspend_sem
);
1934 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
1937 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
1939 #endif /* HOST_WIN32 */
1942 * reset_native_thread_suspend_state:
1944 * Reset the suspended flag on native threads
1947 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
1949 DebuggerTlsData
*tls
= value
;
1951 if (!tls
->really_suspended
&& tls
->suspended
)
1952 tls
->suspended
= FALSE
;
1958 * Notify a thread that it needs to suspend.
1961 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
1963 MonoInternalThread
*thread
= key
;
1964 DebuggerTlsData
*tls
= value
;
1965 gsize tid
= thread
->tid
;
1967 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
1970 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
1973 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1974 * guarantee the signal handler will be called that many times. Instead of tracking
1975 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1976 * has been requested that hasn't been handled yet, otherwise we can have threads
1977 * refuse to die when VM_EXIT is called
1979 #if defined(__APPLE__)
1980 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
1984 * Maybe we could use the normal interrupt infrastructure, but that does a lot
1985 * of things like breaking waits etc. which we don't want.
1987 InterlockedIncrement (&tls
->interrupt_count
);
1990 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
1992 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
1994 pthread_kill ((pthread_t
) tid
, mono_thread_get_abort_signal ());
1999 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2001 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2004 if (debugger_thread_id
== GetCurrentThreadId ())
2007 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2008 if (suspend_count
- tls
->resume_count
> 0)
2009 tls
->suspending
= TRUE
;
2011 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2013 if (suspend_count
- tls
->resume_count
== 0) {
2015 * We are executing a single threaded invoke but the single step for
2016 * suspending is still active.
2017 * FIXME: This slows down single threaded invokes.
2019 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2023 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2025 /* Can't suspend in these methods */
2026 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
2029 save_thread_context (ctx
);
2037 * Increase the suspend count of the VM. While the suspend count is greater
2038 * than 0, runtime threads are suspended at certain points during execution.
2043 mono_loader_lock ();
2045 mono_mutex_lock (&suspend_mutex
);
2049 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2051 if (suspend_count
== 1) {
2052 // FIXME: Is it safe to call this inside the lock ?
2053 start_single_stepping ();
2054 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2057 mono_mutex_unlock (&suspend_mutex
);
2059 mono_loader_unlock ();
2065 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2073 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2075 mono_loader_lock ();
2077 mono_mutex_lock (&suspend_mutex
);
2079 g_assert (suspend_count
> 0);
2082 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2084 if (suspend_count
== 0) {
2085 // FIXME: Is it safe to call this inside the lock ?
2086 stop_single_stepping ();
2087 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2090 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2091 err
= mono_cond_broadcast (&suspend_cond
);
2092 g_assert (err
== 0);
2094 mono_mutex_unlock (&suspend_mutex
);
2095 //g_assert (err == 0);
2097 mono_loader_unlock ();
2103 * Resume just one thread.
2106 resume_thread (MonoInternalThread
*thread
)
2109 DebuggerTlsData
*tls
;
2111 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2113 mono_loader_lock ();
2115 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2118 mono_mutex_lock (&suspend_mutex
);
2120 g_assert (suspend_count
> 0);
2122 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2124 tls
->resume_count
+= suspend_count
;
2127 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2128 * but only the one whose resume_count field is > 0 will be resumed.
2130 err
= mono_cond_broadcast (&suspend_cond
);
2131 g_assert (err
== 0);
2133 mono_mutex_unlock (&suspend_mutex
);
2134 //g_assert (err == 0);
2136 mono_loader_unlock ();
2140 invalidate_frames (DebuggerTlsData
*tls
)
2145 tls
= TlsGetValue (debugger_tls_id
);
2148 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2149 if (tls
->frames
[i
]->jit
)
2150 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2151 g_free (tls
->frames
[i
]);
2153 g_free (tls
->frames
);
2154 tls
->frame_count
= 0;
2161 * Suspend the current thread until the runtime is resumed. If the thread has a
2162 * pending invoke, then the invoke is executed before this function returns.
2165 suspend_current (void)
2168 DebuggerTlsData
*tls
;
2170 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2172 if (mono_loader_lock_is_owned_by_self ()) {
2174 * If we own the loader mutex, can't suspend until we release it, since the
2175 * whole runtime can deadlock otherwise.
2180 tls
= TlsGetValue (debugger_tls_id
);
2183 mono_mutex_lock (&suspend_mutex
);
2185 tls
->suspending
= FALSE
;
2186 tls
->really_suspended
= TRUE
;
2188 if (!tls
->suspended
) {
2189 tls
->suspended
= TRUE
;
2190 MONO_SEM_POST (&suspend_sem
);
2193 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2195 while (suspend_count
- tls
->resume_count
> 0) {
2197 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2199 mono_mutex_unlock (&suspend_mutex
);
2201 mono_mutex_lock (&suspend_mutex
);
2207 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2208 g_assert (err
== 0);
2212 tls
->suspended
= FALSE
;
2213 tls
->really_suspended
= FALSE
;
2215 threads_suspend_count
--;
2217 mono_mutex_unlock (&suspend_mutex
);
2219 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2221 if (tls
->pending_invoke
) {
2222 /* Save the original context */
2223 tls
->pending_invoke
->has_ctx
= TRUE
;
2224 memcpy (&tls
->pending_invoke
->ctx
, &tls
->ctx
, sizeof (MonoContext
));
2229 /* The frame info becomes invalid after a resume */
2230 tls
->has_context
= FALSE
;
2231 tls
->has_async_ctx
= FALSE
;
2232 invalidate_frames (NULL
);
2236 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2238 DebuggerTlsData
*tls
= value
;
2240 if (!tls
->suspended
&& !tls
->terminated
)
2241 *(int*)user_data
= *(int*)user_data
+ 1;
2245 count_threads_to_wait_for (void)
2249 mono_loader_lock ();
2250 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2251 mono_loader_unlock ();
2259 * Wait until the runtime is completely suspended.
2262 wait_for_suspend (void)
2264 int nthreads
, nwait
, err
;
2265 gboolean waited
= FALSE
;
2267 // FIXME: Threads starting/stopping ?
2268 mono_loader_lock ();
2269 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2270 mono_loader_unlock ();
2273 nwait
= count_threads_to_wait_for ();
2275 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2276 err
= MONO_SEM_WAIT (&suspend_sem
);
2277 g_assert (err
== 0);
2285 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2291 * Return whenever the runtime is suspended.
2296 return count_threads_to_wait_for () == 0;
2300 * find_seq_point_for_native_offset:
2302 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2303 * should be the location of a sequence point.
2306 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2308 MonoSeqPointInfo
*seq_points
;
2311 mono_domain_lock (domain
);
2312 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2313 mono_domain_unlock (domain
);
2314 g_assert (seq_points
);
2318 for (i
= 0; i
< seq_points
->len
; ++i
) {
2319 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2320 return &seq_points
->seq_points
[i
];
2329 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2330 * should be the location of a sequence point.
2333 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2335 MonoSeqPointInfo
*seq_points
;
2338 mono_domain_lock (domain
);
2339 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2340 mono_domain_unlock (domain
);
2341 g_assert (seq_points
);
2345 for (i
= 0; i
< seq_points
->len
; ++i
) {
2346 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2347 return &seq_points
->seq_points
[i
];
2354 * compute_il_offset:
2356 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2357 * a location of a sequence point.
2358 * We use this function instead of mono_debug_il_offset_from_address () etc,
2359 * which doesn't seem to work in a lot of cases.
2362 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2364 MonoSeqPointInfo
*seq_points
;
2365 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2367 mono_domain_lock (domain
);
2368 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2369 mono_domain_unlock (domain
);
2370 g_assert (seq_points
);
2372 last_il_offset
= -1;
2374 /* Find the sequence point */
2375 for (i
= 0; i
< seq_points
->len
; ++i
) {
2376 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2377 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2379 if (seq_native_offset
> native_offset
)
2381 last_il_offset
= seq_il_offset
;
2384 return last_il_offset
;
2388 DebuggerTlsData
*tls
;
2390 } ComputeFramesUserData
;
2393 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2395 ComputeFramesUserData
*ud
= user_data
;
2399 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2400 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2401 /* Mark the last frame as an invoke frame */
2403 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2409 method
= info
->ji
->method
;
2411 method
= info
->method
;
2413 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2416 if (info
->il_offset
== -1) {
2417 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2418 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2421 DEBUG (1, fprintf (log_file
, "\tFrame: %s %d %d %d\n", mono_method_full_name (method
, TRUE
), info
->native_offset
, info
->il_offset
, info
->managed
));
2423 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2425 * mono_arch_find_jit_info () returns the context stored in the LMF for
2426 * native frames, but it should unwind once. This is why we have duplicate
2427 * frames on the stack sometimes.
2428 * !managed also seems to be set for dynamic methods.
2433 frame
= g_new0 (StackFrame
, 1);
2434 frame
->method
= method
;
2435 frame
->il_offset
= info
->il_offset
;
2438 frame
->has_ctx
= TRUE
;
2440 frame
->domain
= info
->domain
;
2442 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2448 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2450 ComputeFramesUserData user_data
;
2452 int i
, findex
, new_frame_count
;
2453 StackFrame
**new_frames
, *f
;
2455 // FIXME: Locking on tls
2456 if (tls
->frames
&& tls
->frames_up_to_date
)
2459 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2461 user_data
.tls
= tls
;
2462 user_data
.frames
= NULL
;
2463 if (tls
->terminated
) {
2464 tls
->frame_count
= 0;
2466 } if (!tls
->really_suspended
&& tls
->has_async_ctx
) {
2467 /* Have to use the state saved by the signal handler */
2468 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2469 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->async_ctx
, FALSE
, thread
, tls
->async_lmf
, &user_data
);
2470 } else if (tls
->has_context
) {
2471 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->ctx
, FALSE
, thread
, tls
->lmf
, &user_data
);
2474 tls
->frame_count
= 0;
2478 new_frame_count
= g_slist_length (user_data
.frames
);
2479 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2481 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2485 * Reuse the id for already existing stack frames, so invokes don't invalidate
2486 * the still valid stack frames.
2488 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2489 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2490 f
->id
= tls
->frames
[i
]->id
;
2495 if (i
>= tls
->frame_count
)
2496 f
->id
= InterlockedIncrement (&frame_id
);
2498 new_frames
[findex
++] = f
;
2501 g_slist_free (user_data
.frames
);
2503 invalidate_frames (tls
);
2505 tls
->frames
= new_frames
;
2506 tls
->frame_count
= new_frame_count
;
2507 tls
->frames_up_to_date
= TRUE
;
2515 * create_event_list:
2517 * Return a list of event request ids matching EVENT, starting from REQS, which
2518 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2520 * We return request ids, instead of requests, to simplify threading, since
2521 * requests could be deleted anytime when the loader lock is not held.
2522 * LOCKING: Assumes the loader lock is held.
2525 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
2528 GSList
*events
= NULL
;
2530 *suspend_policy
= SUSPEND_POLICY_NONE
;
2533 reqs
= event_requests
;
2538 for (i
= 0; i
< reqs
->len
; ++i
) {
2539 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2540 if (req
->event_kind
== event
) {
2541 gboolean filtered
= FALSE
;
2544 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2545 Modifier
*mod
= &req
->modifiers
[j
];
2547 if (mod
->kind
== MOD_KIND_COUNT
) {
2549 if (mod
->data
.count
> 0) {
2550 if (mod
->data
.count
> 0) {
2552 if (mod
->data
.count
== 0)
2556 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2557 if (mod
->data
.thread
!= mono_thread_internal_current ())
2559 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
2560 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
2562 if (ei
->caught
&& !mod
->caught
)
2564 if (!ei
->caught
&& !mod
->uncaught
)
2566 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2568 gboolean found
= FALSE
;
2569 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2572 for (k
= 0; assemblies
[k
]; ++k
)
2573 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2582 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2583 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2588 /* Send a VM START/DEATH event by default */
2589 if (event
== EVENT_KIND_VM_START
)
2590 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2591 if (event
== EVENT_KIND_VM_DEATH
)
2592 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2597 static G_GNUC_UNUSED
const char*
2598 event_to_string (EventKind event
)
2601 case EVENT_KIND_VM_START
: return "VM_START";
2602 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2603 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2604 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2605 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2606 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2607 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2608 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2609 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2610 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2611 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2612 case EVENT_KIND_STEP
: return "STEP";
2613 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
2614 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
2616 g_assert_not_reached ();
2623 * Send an event to the client, suspending the vm if needed.
2624 * LOCKING: Since this can suspend the calling thread, no locks should be held
2626 * The EVENTS list is freed by this function.
2629 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
2633 MonoDomain
*domain
= mono_domain_get ();
2639 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
)
2640 // FIXME: We miss those events
2643 if (vm_death_event_sent
)
2646 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
)
2655 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
2656 // FIXME: Send these with a NULL thread, don't suspend the current thread
2659 buffer_init (&buf
, 128);
2660 buffer_add_byte (&buf
, suspend_policy
);
2661 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
2663 for (l
= events
; l
; l
= l
->next
) {
2664 buffer_add_byte (&buf
, event
); // event kind
2665 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
2667 thread
= mono_thread_current ();
2669 if (event
== EVENT_KIND_VM_START
)
2671 else if (event
== EVENT_KIND_THREAD_START
)
2672 g_assert (mono_thread_internal_current () == arg
);
2674 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
2677 case EVENT_KIND_THREAD_START
:
2678 case EVENT_KIND_THREAD_DEATH
:
2680 case EVENT_KIND_APPDOMAIN_CREATE
:
2681 case EVENT_KIND_APPDOMAIN_UNLOAD
:
2682 buffer_add_domainid (&buf
, arg
);
2684 case EVENT_KIND_METHOD_ENTRY
:
2685 case EVENT_KIND_METHOD_EXIT
:
2686 buffer_add_methodid (&buf
, domain
, arg
);
2688 case EVENT_KIND_ASSEMBLY_LOAD
:
2689 case EVENT_KIND_ASSEMBLY_UNLOAD
:
2690 buffer_add_assemblyid (&buf
, domain
, arg
);
2692 case EVENT_KIND_TYPE_LOAD
:
2693 buffer_add_typeid (&buf
, domain
, arg
);
2695 case EVENT_KIND_BREAKPOINT
:
2696 case EVENT_KIND_STEP
:
2697 buffer_add_methodid (&buf
, domain
, arg
);
2698 buffer_add_long (&buf
, il_offset
);
2700 case EVENT_KIND_VM_START
:
2701 buffer_add_domainid (&buf
, mono_get_root_domain ());
2703 case EVENT_KIND_VM_DEATH
:
2705 case EVENT_KIND_EXCEPTION
: {
2706 EventInfo
*ei
= arg
;
2707 buffer_add_objid (&buf
, ei
->exc
);
2711 g_assert_not_reached ();
2715 if (event
== EVENT_KIND_VM_START
) {
2716 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
2717 start_debugger_thread ();
2720 if (event
== EVENT_KIND_VM_DEATH
) {
2721 vm_death_event_sent
= TRUE
;
2723 suspend_policy
= SUSPEND_POLICY_NONE
;
2726 if (mono_runtime_is_shutting_down ())
2727 suspend_policy
= SUSPEND_POLICY_NONE
;
2729 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
2731 * Save the thread context and start suspending before sending the packet,
2732 * since we could be receiving the resume request before send_packet ()
2735 save_thread_context (ctx
);
2739 send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
2741 g_slist_free (events
);
2744 if (event
== EVENT_KIND_VM_START
)
2745 vm_start_event_sent
= TRUE
;
2747 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
2751 switch (suspend_policy
) {
2752 case SUSPEND_POLICY_NONE
:
2754 case SUSPEND_POLICY_ALL
:
2757 case SUSPEND_POLICY_EVENT_THREAD
:
2761 g_assert_not_reached ();
2766 process_profiler_event (EventKind event
, gpointer arg
)
2771 mono_loader_lock ();
2772 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
2773 mono_loader_unlock ();
2775 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
2779 runtime_initialized (MonoProfiler
*prof
)
2781 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
2785 runtime_shutdown (MonoProfiler
*prof
)
2787 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
2789 mono_debugger_agent_cleanup ();
2793 thread_startup (MonoProfiler
*prof
, intptr_t tid
)
2795 MonoInternalThread
*thread
= mono_thread_internal_current ();
2796 MonoInternalThread
*old_thread
;
2797 DebuggerTlsData
*tls
;
2799 if (tid
== debugger_thread_id
)
2802 g_assert (thread
->tid
== tid
);
2804 mono_loader_lock ();
2805 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2806 mono_loader_unlock ();
2808 if (thread
== old_thread
) {
2810 * For some reason, thread_startup () might be called for the same thread
2811 * multiple times (attach ?).
2813 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
2817 * thread_end () might not be called for some threads, and the tid could
2820 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
2821 mono_loader_lock ();
2822 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
2823 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
2824 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2825 mono_loader_unlock ();
2829 tls
= TlsGetValue (debugger_tls_id
);
2831 // FIXME: Free this somewhere
2832 tls
= g_new0 (DebuggerTlsData
, 1);
2833 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2834 MONO_GC_REGISTER_ROOT (tls
->thread
);
2835 tls
->thread
= thread
;
2836 TlsSetValue (debugger_tls_id
, tls
);
2838 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2840 mono_loader_lock ();
2841 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
2842 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
2843 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
2844 mono_loader_unlock ();
2846 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
2849 * suspend_vm () could have missed this thread, so wait for a resume.
2855 thread_end (MonoProfiler
*prof
, intptr_t tid
)
2857 MonoInternalThread
*thread
;
2858 DebuggerTlsData
*tls
= NULL
;
2860 mono_loader_lock ();
2861 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2863 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2864 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2865 tls
->terminated
= TRUE
;
2866 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2867 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2868 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
2871 mono_loader_unlock ();
2873 /* We might be called for threads started before we registered the start callback */
2875 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2876 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
2881 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
2883 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
2887 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
2889 /* Invalidate each thread's frame stack */
2890 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
2891 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
2895 * invalidate_each_thread:
2897 * A GHFunc to invalidate frames.
2898 * value must be a DebuggerTlsData*
2901 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
2903 invalidate_frames (value
);
2907 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
2909 /* Sent later in jit_end () */
2910 mono_loader_lock ();
2911 g_ptr_array_add (pending_assembly_loads
, assembly
);
2912 mono_loader_unlock ();
2916 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
2918 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
2920 clear_event_requests_for_assembly (assembly
);
2924 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2926 #if defined(HOST_WIN32) && !defined(__GNUC__)
2927 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2929 gpointer stackptr
= __builtin_frame_address (1);
2931 MonoInternalThread
*thread
= mono_thread_internal_current ();
2932 DebuggerTlsData
*tls
;
2934 mono_loader_lock ();
2936 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2937 /* Could be the debugger thread with assembly/type load hooks */
2939 tls
->invoke_addr
= stackptr
;
2941 mono_loader_unlock ();
2945 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2948 #if defined(HOST_WIN32) && !defined(__GNUC__)
2949 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2951 gpointer stackptr
= __builtin_frame_address (1);
2954 if (ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
2958 * We need to stop single stepping when exiting a runtime invoke, since if it is
2959 * a step out, it may return to native code, and thus never end.
2961 mono_loader_lock ();
2962 ss_invoke_addr
= NULL
;
2964 for (i
= 0; i
< event_requests
->len
; ++i
) {
2965 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
2967 if (req
->event_kind
== EVENT_KIND_STEP
) {
2968 ss_destroy (req
->info
);
2969 g_ptr_array_remove_index_fast (event_requests
, i
);
2974 mono_loader_unlock ();
2978 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
2981 * We emit type load events when the first method of the type is JITted,
2982 * since the class load profiler callbacks might be called with the
2983 * loader lock held. They could also occur in the debugger thread.
2984 * Same for assembly load events.
2986 gboolean type_load
= FALSE
;
2989 MonoAssembly
*assembly
= NULL
;
2991 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
2992 mono_loader_lock ();
2993 if (pending_assembly_loads
->len
> 0) {
2994 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
2995 g_ptr_array_remove_index (pending_assembly_loads
, 0);
2997 mono_loader_unlock ();
3000 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
3005 mono_loader_lock ();
3006 if (!g_hash_table_lookup (loaded_classes
, method
->klass
)) {
3008 g_hash_table_insert (loaded_classes
, method
->klass
, method
->klass
);
3010 mono_loader_unlock ();
3012 process_profiler_event (EVENT_KIND_TYPE_LOAD
, method
->klass
);
3015 add_pending_breakpoints (method
, jinfo
);
3019 * BREAKPOINTS/SINGLE STEPPING
3023 * Contains information about an inserted breakpoint.
3026 long il_offset
, native_offset
;
3029 } BreakpointInstance
;
3032 * Contains generic information about a breakpoint.
3036 * The method where the breakpoint is placed. Can be NULL in which case it
3037 * is inserted into every method. This is used to implement method entry/
3038 * exit events. Can be a generic method definition, in which case the
3039 * breakpoint is inserted into every instance.
3045 * A list of BreakpointInstance structures describing where the breakpoint
3046 * was inserted. There could be more than one because of
3047 * generics/appdomains/method entry/exit.
3049 GPtrArray
*children
;
3052 /* List of breakpoints */
3053 static GPtrArray
*breakpoints
;
3054 /* Maps breakpoint locations to the number of breakpoints at that location */
3055 static GHashTable
*bp_locs
;
3058 breakpoints_init (void)
3060 breakpoints
= g_ptr_array_new ();
3061 bp_locs
= g_hash_table_new (NULL
, NULL
);
3065 breakpoints_cleanup (void)
3069 mono_loader_lock ();
3071 for (i
= 0; i
< breakpoints
->len
; ++i
)
3072 g_free (g_ptr_array_index (breakpoints
, i
));
3074 g_ptr_array_free (breakpoints
, TRUE
);
3075 g_hash_table_destroy (bp_locs
);
3077 mono_loader_unlock ();
3081 * insert_breakpoint:
3083 * Insert the breakpoint described by BP into the method described by
3087 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
)
3090 gint32 il_offset
, native_offset
;
3091 BreakpointInstance
*inst
;
3094 for (i
= 0; i
< seq_points
->len
; ++i
) {
3095 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3096 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3098 if (il_offset
== bp
->il_offset
)
3102 if (i
== seq_points
->len
)
3103 /* Have to handle this somehow */
3106 inst
= g_new0 (BreakpointInstance
, 1);
3107 inst
->native_offset
= native_offset
;
3108 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3111 mono_loader_lock ();
3113 g_ptr_array_add (bp
->children
, inst
);
3115 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3116 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3117 mono_loader_unlock ();
3120 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3121 mono_arch_set_breakpoint (ji
, inst
->ip
);
3127 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji
->method
, TRUE
), (int)il_offset
));
3131 remove_breakpoint (BreakpointInstance
*inst
)
3133 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3135 MonoJitInfo
*ji
= inst
->ji
;
3136 guint8
*ip
= inst
->ip
;
3138 mono_loader_lock ();
3139 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3140 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3141 mono_loader_unlock ();
3143 g_assert (count
> 0);
3146 mono_arch_clear_breakpoint (ji
, ip
);
3153 static inline gboolean
3154 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
3156 return (!bp
->method
|| method
== bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
));
3160 * add_pending_breakpoints:
3162 * Insert pending breakpoints into the newly JITted method METHOD.
3165 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3168 MonoSeqPointInfo
*seq_points
;
3174 domain
= mono_domain_get ();
3176 mono_loader_lock ();
3178 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3179 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3180 gboolean found
= FALSE
;
3182 if (!bp_matches_method (bp
, method
))
3185 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3186 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3193 mono_domain_lock (domain
);
3194 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3195 mono_domain_unlock (domain
);
3197 /* Could be AOT code */
3199 g_assert (seq_points
);
3201 insert_breakpoint (seq_points
, ji
, bp
);
3205 mono_loader_unlock ();
3209 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
)
3214 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3216 /* Might be AOTed code */
3217 code
= mono_aot_get_method (domain
, method
);
3219 ji
= mono_jit_info_table_find (domain
, code
);
3224 insert_breakpoint (seq_points
, ji
, bp
);
3228 set_bp_in_method_cb (gpointer key
, gpointer value
, gpointer user_data
)
3230 MonoMethod
*method
= key
;
3231 MonoSeqPointInfo
*seq_points
= value
;
3232 MonoBreakpoint
*bp
= user_data
;
3233 MonoDomain
*domain
= mono_domain_get ();
3235 if (bp_matches_method (bp
, method
))
3236 set_bp_in_method (domain
, method
, seq_points
, bp
);
3242 * Set a breakpoint at IL_OFFSET in METHOD.
3243 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3244 * METHOD can also be a generic method definition, in which case a breakpoint
3245 * is placed in all instances of the method.
3247 static MonoBreakpoint
*
3248 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
)
3254 // - suspend/resume the vm to prevent code patching problems
3255 // - multiple breakpoints on the same location
3256 // - dynamic methods
3259 bp
= g_new0 (MonoBreakpoint
, 1);
3260 bp
->method
= method
;
3261 bp
->il_offset
= il_offset
;
3263 bp
->children
= g_ptr_array_new ();
3265 DEBUG(1, fprintf (log_file
, "[dbg] Setting %sbreakpoint at %s:0x%x.\n", (req
->event_kind
== EVENT_KIND_STEP
) ? "single step " : "", method
? mono_method_full_name (method
, TRUE
) : "<all>", (int)il_offset
));
3267 domain
= mono_domain_get ();
3268 mono_domain_lock (domain
);
3269 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, bp
);
3270 mono_domain_unlock (domain
);
3272 mono_loader_lock ();
3273 g_ptr_array_add (breakpoints
, bp
);
3274 mono_loader_unlock ();
3280 clear_breakpoint (MonoBreakpoint
*bp
)
3284 // FIXME: locking, races
3285 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3286 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3288 remove_breakpoint (inst
);
3293 mono_loader_lock ();
3294 g_ptr_array_remove (breakpoints
, bp
);
3295 mono_loader_unlock ();
3297 g_ptr_array_free (bp
->children
, TRUE
);
3302 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
3304 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
3308 process_breakpoint_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3311 guint8
*orig_ip
, *ip
;
3312 int i
, j
, suspend_policy
;
3313 guint32 native_offset
;
3315 BreakpointInstance
*inst
;
3316 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3317 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3318 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3320 // FIXME: Speed this up
3322 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3323 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3325 g_assert (ji
->method
);
3327 /* Compute the native offset of the breakpoint from the ip */
3328 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3329 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3330 native_offset
= ip
- (guint8
*)ji
->code_start
;
3336 * Skip the instruction causing the breakpoint signal.
3338 mono_arch_skip_breakpoint (ctx
);
3340 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3343 bp_reqs
= g_ptr_array_new ();
3344 ss_reqs
= g_ptr_array_new ();
3345 ss_reqs_orig
= g_ptr_array_new ();
3347 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3349 mono_loader_lock ();
3352 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3353 bp
= g_ptr_array_index (breakpoints
, i
);
3358 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3359 inst
= g_ptr_array_index (bp
->children
, j
);
3360 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3361 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3362 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3364 g_ptr_array_add (bp_reqs
, bp
->req
);
3369 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3370 MonoSeqPointInfo
*seq_points
;
3371 int seq_il_offset
, seq_native_offset
;
3372 MonoDomain
*domain
= mono_domain_get ();
3374 /* Maybe a method entry/exit event */
3375 mono_domain_lock (domain
);
3376 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3377 mono_domain_unlock (domain
);
3379 // FIXME: Generic sharing */
3380 mono_loader_unlock ();
3383 g_assert (seq_points
);
3385 for (i
= 0; i
< seq_points
->len
; ++i
) {
3386 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3387 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3389 if (native_offset
== seq_native_offset
) {
3390 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3391 kind
= EVENT_KIND_METHOD_ENTRY
;
3392 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3393 kind
= EVENT_KIND_METHOD_EXIT
;
3399 /* Process single step requests */
3400 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3401 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3402 SingleStepReq
*ss_req
= bp
->req
->info
;
3403 gboolean hit
= TRUE
;
3404 MonoSeqPointInfo
*info
;
3407 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3410 if (ss_req
->size
== STEP_SIZE_LINE
) {
3411 /* Have to check whenever a different source line was reached */
3412 MonoDebugMethodInfo
*minfo
;
3413 MonoDebugSourceLocation
*loc
= NULL
;
3415 minfo
= mono_debug_lookup_method (ji
->method
);
3418 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3420 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3421 /* Have to continue single stepping */
3425 ss_req
->last_method
= ji
->method
;
3426 ss_req
->last_line
= loc
->row
;
3427 mono_debug_free_source_location (loc
);
3432 g_ptr_array_add (ss_reqs
, req
);
3434 /* Start single stepping again from the current sequence point */
3435 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
);
3438 if (ss_reqs
->len
> 0)
3439 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
3440 if (bp_reqs
->len
> 0)
3441 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
3442 if (kind
!= EVENT_KIND_BREAKPOINT
)
3443 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
3445 mono_loader_unlock ();
3447 g_ptr_array_free (bp_reqs
, TRUE
);
3448 g_ptr_array_free (ss_reqs
, TRUE
);
3451 * FIXME: The first event will suspend, so the second will only be sent after the
3455 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
3457 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
3458 if (enter_leave_events
)
3459 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
3463 process_breakpoint (void)
3465 DebuggerTlsData
*tls
;
3467 static void (*restore_context
) (void *);
3469 if (!restore_context
)
3470 restore_context
= mono_get_restore_context ();
3472 tls
= TlsGetValue (debugger_tls_id
);
3473 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3475 process_breakpoint_inner (tls
, &ctx
);
3477 /* This is called when resuming from a signal handler, so it shouldn't return */
3478 restore_context (&ctx
);
3479 g_assert_not_reached ();
3483 resume_from_signal_handler (void *sigctx
, void *func
)
3485 DebuggerTlsData
*tls
;
3488 /* Save the original context in TLS */
3489 // FIXME: This might not work on an altstack ?
3490 tls
= TlsGetValue (debugger_tls_id
);
3493 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3494 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3495 // clob:c could be added to op_seq_point.
3497 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3498 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
3499 MONO_CONTEXT_SET_IP (&ctx
, func
);
3500 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3502 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3503 mono_ppc_set_func_into_sigctx (sigctx
, func
);
3508 mono_debugger_agent_breakpoint_hit (void *sigctx
)
3511 * We are called from a signal handler, and running code there causes all kinds of
3512 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3513 * So set up the signal context to return to the real breakpoint handler function.
3516 resume_from_signal_handler (sigctx
, process_breakpoint
);
3520 process_single_step_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3525 int il_offset
, suspend_policy
;
3529 // FIXME: Speed this up
3531 ip
= MONO_CONTEXT_GET_IP (ctx
);
3533 /* Skip the instruction causing the single step */
3534 mono_arch_skip_single_step (ctx
);
3536 if (suspend_count
> 0) {
3537 process_suspend (tls
, ctx
);
3542 // FIXME: A suspend race
3545 if (mono_thread_internal_current () != ss_req
->thread
)
3548 if (log_level
> 0) {
3549 const char *depth
= NULL
;
3551 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3553 switch (ss_req
->depth
) {
3554 case STEP_DEPTH_OVER
:
3557 case STEP_DEPTH_OUT
:
3560 case STEP_DEPTH_INTO
:
3564 g_assert_not_reached ();
3567 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
));
3571 * We implement step over/out by single stepping until we reach the same
3572 * frame/parent frame.
3575 * - stack growing upward
3579 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
3580 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
3582 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
3585 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
3588 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3590 g_assert (ji
->method
);
3592 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
3597 * Stopping in memset makes half-initialized vtypes visible.
3598 * Stopping in memcpy makes half-copied vtypes visible.
3600 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
3604 * The ip points to the instruction causing the single step event, convert it
3605 * to the offset stored in seq_points.
3607 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3608 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
3610 g_assert_not_reached ();
3614 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3615 * example, so do things by hand.
3617 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
3619 if (il_offset
== -1)
3622 if (ss_req
->size
== STEP_SIZE_LINE
) {
3623 /* Step until a different source line is reached */
3624 MonoDebugMethodInfo
*minfo
;
3626 minfo
= mono_debug_lookup_method (ji
->method
);
3629 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
3631 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
3632 mono_debug_free_source_location (loc
);
3637 * Step until we reach a location with line number info,
3638 * otherwise the client can't show a location.
3639 * This can happen for example with statics initialized inline
3640 * outside of a cctor.
3645 ss_req
->last_method
= ji
->method
;
3646 ss_req
->last_line
= loc
->row
;
3647 mono_debug_free_source_location (loc
);
3652 // FIXME: Has to lock earlier
3654 reqs
= g_ptr_array_new ();
3656 mono_loader_lock ();
3658 g_ptr_array_add (reqs
, ss_req
->req
);
3660 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
3662 g_ptr_array_free (reqs
, TRUE
);
3664 mono_loader_unlock ();
3666 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
3670 process_single_step (void)
3672 DebuggerTlsData
*tls
;
3674 static void (*restore_context
) (void *);
3676 if (!restore_context
)
3677 restore_context
= mono_get_restore_context ();
3679 tls
= TlsGetValue (debugger_tls_id
);
3680 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3682 process_single_step_inner (tls
, &ctx
);
3684 /* This is called when resuming from a signal handler, so it shouldn't return */
3685 restore_context (&ctx
);
3686 g_assert_not_reached ();
3690 * mono_debugger_agent_single_step_event:
3692 * Called from a signal handler to handle a single step event.
3695 mono_debugger_agent_single_step_event (void *sigctx
)
3697 /* Resume to process_single_step through the signal context */
3699 // FIXME: Since step out/over is implemented using step in, the step in case should
3700 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3703 if (GetCurrentThreadId () == debugger_thread_id
) {
3705 * This could happen despite our best effors when the runtime calls
3706 * assembly/type resolve hooks.
3707 * FIXME: Breakpoints too.
3711 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3712 mono_arch_skip_single_step (&ctx
);
3713 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3717 resume_from_signal_handler (sigctx
, process_single_step
);
3721 * start_single_stepping:
3723 * Turn on single stepping. Can be called multiple times, for example,
3724 * by a single step event request + a suspend.
3727 start_single_stepping (void)
3729 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3730 int val
= InterlockedIncrement (&ss_count
);
3733 mono_arch_start_single_stepping ();
3735 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
3736 DebuggerTlsData
*tls
;
3738 mono_loader_lock ();
3740 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
3741 ss_invoke_addr
= tls
->invoke_addr
;
3743 mono_loader_unlock ();
3746 g_assert_not_reached ();
3751 stop_single_stepping (void)
3753 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3754 int val
= InterlockedDecrement (&ss_count
);
3757 mono_arch_stop_single_stepping ();
3759 g_assert_not_reached ();
3766 * Stop the single stepping operation given by SS_REQ.
3769 ss_stop (SingleStepReq
*ss_req
)
3771 gboolean use_bps
= FALSE
;
3778 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
3779 clear_breakpoint (l
->data
);
3781 g_slist_free (ss_req
->bps
);
3785 if (ss_req
->global
) {
3786 stop_single_stepping ();
3787 ss_req
->global
= FALSE
;
3794 * Start the single stepping operation given by SS_REQ from the sequence point SP.
3797 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
)
3799 gboolean use_bp
= FALSE
;
3804 /* Stop the previous operation */
3808 * Implement single stepping using breakpoints if possible.
3810 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3813 * Find the first sequence point in the current or in a previous frame which
3814 * is not the last in its method.
3816 while (sp
&& sp
->next_len
== 0) {
3818 if (tls
&& frame_index
< tls
->frame_count
) {
3819 StackFrame
*frame
= tls
->frames
[frame_index
];
3821 method
= frame
->method
;
3822 if (frame
->il_offset
!= -1) {
3823 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3829 if (sp
&& sp
->next_len
> 0) {
3831 for (i
= 0; i
< sp
->next_len
; ++i
) {
3832 next_sp
= &info
->seq_points
[sp
->next
[i
]];
3834 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
);
3835 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
3841 ss_req
->global
= TRUE
;
3842 start_single_stepping ();
3844 ss_req
->global
= FALSE
;
3849 * Start single stepping of thread THREAD
3852 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
3854 DebuggerTlsData
*tls
;
3855 MonoSeqPointInfo
*info
;
3856 SeqPoint
*sp
= NULL
;
3857 MonoMethod
*method
= NULL
;
3859 if (suspend_count
== 0)
3860 return ERR_NOT_SUSPENDED
;
3862 wait_for_suspend ();
3864 // FIXME: Multiple requests
3866 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
3867 return ERR_NOT_IMPLEMENTED
;
3870 ss_req
= g_new0 (SingleStepReq
, 1);
3872 ss_req
->thread
= thread
;
3873 ss_req
->size
= size
;
3874 ss_req
->depth
= depth
;
3877 mono_loader_lock ();
3878 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3879 mono_loader_unlock ();
3881 g_assert (tls
->has_context
);
3882 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->ctx
);
3884 if (ss_req
->size
== STEP_SIZE_LINE
) {
3886 MonoDebugMethodInfo
*minfo
;
3888 /* Compute the initial line info */
3889 compute_frame_info (thread
, tls
);
3891 g_assert (tls
->frame_count
);
3892 frame
= tls
->frames
[0];
3894 ss_req
->last_method
= frame
->method
;
3895 ss_req
->last_line
= -1;
3897 minfo
= mono_debug_lookup_method (frame
->method
);
3898 if (minfo
&& frame
->il_offset
!= -1) {
3899 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
3902 ss_req
->last_line
= loc
->row
;
3908 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3911 compute_frame_info (thread
, tls
);
3913 g_assert (tls
->frame_count
);
3914 frame
= tls
->frames
[0];
3916 if (frame
->il_offset
!= -1) {
3917 /* FIXME: Sort the table and use a binary search */
3918 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3920 method
= frame
->method
;
3924 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
);
3930 ss_destroy (SingleStepReq
*req
)
3933 g_assert (ss_req
== req
);
3942 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
3943 MonoContext
*catch_ctx
)
3950 if (thread_to_tls
!= NULL
) {
3951 MonoInternalThread
*thread
= mono_thread_internal_current ();
3952 DebuggerTlsData
*tls
;
3954 mono_loader_lock ();
3955 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3956 mono_loader_unlock ();
3958 if (tls
&& tls
->abort_requested
)
3962 memset (&ei
, 0, sizeof (EventInfo
));
3964 /* Just-In-Time debugging */
3966 if (agent_config
.onuncaught
&& !inited
) {
3967 finish_agent_init (FALSE
);
3970 * Send an unsolicited EXCEPTION event with a dummy request id.
3972 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
3973 ei
.exc
= (MonoObject
*)exc
;
3974 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
3977 } else if (agent_config
.onthrow
&& !inited
) {
3979 gboolean found
= FALSE
;
3981 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
3982 char *ex_type
= l
->data
;
3983 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
3985 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
3992 finish_agent_init (FALSE
);
3995 * Send an unsolicited EXCEPTION event with a dummy request id.
3997 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
3998 ei
.exc
= (MonoObject
*)exc
;
3999 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4007 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
4009 ei
.exc
= (MonoObject
*)exc
;
4010 ei
.caught
= catch_ctx
!= NULL
;
4012 mono_loader_lock ();
4013 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
4014 mono_loader_unlock ();
4016 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
4020 * buffer_add_value_full:
4022 * Add the encoding of the value at ADDR described by T to the buffer.
4023 * AS_VTYPE determines whenever to treat primitive types as primitive types or
4027 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
4033 g_assert (*(void**)addr
);
4034 addr
= *(void**)addr
;
4039 case MONO_TYPE_BOOLEAN
:
4042 case MONO_TYPE_CHAR
:
4062 case MONO_TYPE_VOID
:
4063 buffer_add_byte (buf
, t
->type
);
4065 case MONO_TYPE_BOOLEAN
:
4068 buffer_add_byte (buf
, t
->type
);
4069 buffer_add_int (buf
, *(gint8
*)addr
);
4071 case MONO_TYPE_CHAR
:
4074 buffer_add_byte (buf
, t
->type
);
4075 buffer_add_int (buf
, *(gint16
*)addr
);
4080 buffer_add_byte (buf
, t
->type
);
4081 buffer_add_int (buf
, *(gint32
*)addr
);
4086 buffer_add_byte (buf
, t
->type
);
4087 buffer_add_long (buf
, *(gint64
*)addr
);
4091 /* Treat it as a vtype */
4093 case MONO_TYPE_PTR
: {
4094 gssize val
= *(gssize
*)addr
;
4096 buffer_add_byte (buf
, t
->type
);
4097 buffer_add_long (buf
, val
);
4101 case MONO_TYPE_STRING
:
4102 case MONO_TYPE_SZARRAY
:
4103 case MONO_TYPE_OBJECT
:
4104 case MONO_TYPE_CLASS
:
4105 case MONO_TYPE_ARRAY
:
4106 obj
= *(MonoObject
**)addr
;
4109 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4111 if (obj
->vtable
->klass
->valuetype
) {
4112 t
= &obj
->vtable
->klass
->byval_arg
;
4113 addr
= mono_object_unbox (obj
);
4115 } else if (obj
->vtable
->klass
->rank
) {
4116 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4117 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4118 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4120 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4122 buffer_add_objid (buf
, obj
);
4126 case MONO_TYPE_VALUETYPE
: {
4130 MonoClass
*klass
= mono_class_from_mono_type (t
);
4132 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4133 buffer_add_byte (buf
, klass
->enumtype
);
4134 buffer_add_typeid (buf
, domain
, klass
);
4138 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4139 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4141 if (mono_field_is_deleted (f
))
4145 buffer_add_int (buf
, nfields
);
4148 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4149 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4151 if (mono_field_is_deleted (f
))
4153 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4157 case MONO_TYPE_GENERICINST
:
4158 if (mono_type_generic_inst_is_valuetype (t
)) {
4170 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4172 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4176 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4179 int type
= decode_byte (buf
, &buf
, limit
);
4181 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4182 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4183 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4184 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4185 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4186 char *name
= mono_type_full_name (t
);
4187 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
4189 return ERR_INVALID_ARGUMENT
;
4193 case MONO_TYPE_BOOLEAN
:
4194 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4196 case MONO_TYPE_CHAR
:
4197 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4200 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4203 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4206 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4209 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4212 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4215 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4218 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4221 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4224 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4227 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4230 /* We send these as I8, so we get them back as such */
4231 g_assert (type
== MONO_TYPE_I8
);
4232 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4234 case MONO_TYPE_GENERICINST
:
4235 if (MONO_TYPE_ISSTRUCT (t
)) {
4236 /* The client sends these as a valuetype */
4244 /* We send these as vtypes, so we get them back as such */
4245 g_assert (type
== MONO_TYPE_VALUETYPE
);
4248 case MONO_TYPE_VALUETYPE
: {
4249 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
4253 gpointer iter
= NULL
;
4256 /* Enums are sent as a normal vtype */
4258 return ERR_NOT_IMPLEMENTED
;
4259 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
4263 if (klass
!= mono_class_from_mono_type (t
))
4264 return ERR_INVALID_ARGUMENT
;
4266 nfields
= decode_int (buf
, &buf
, limit
);
4267 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4268 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4270 if (mono_field_is_deleted (f
))
4272 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
4277 g_assert (nfields
== 0);
4282 if (MONO_TYPE_IS_REFERENCE (t
)) {
4283 if (type
== MONO_TYPE_OBJECT
) {
4284 int objid
= decode_objid (buf
, &buf
, limit
);
4288 err
= get_object (objid
, (MonoObject
**)&obj
);
4292 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
4293 return ERR_INVALID_ARGUMENT
;
4294 if (obj
&& obj
->vtable
->domain
!= domain
)
4295 return ERR_INVALID_ARGUMENT
;
4297 mono_gc_wbarrier_generic_store (addr
, obj
);
4298 } else if (type
== VALUE_TYPE_ID_NULL
) {
4299 *(MonoObject
**)addr
= NULL
;
4301 return ERR_INVALID_ARGUMENT
;
4315 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
4322 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4323 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4326 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4327 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
4329 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
4331 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4332 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4333 addr
+= (gint32
)var
->offset
;
4335 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4337 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
4339 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4343 g_assert_not_reached ();
4348 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
)
4354 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4355 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4357 if (MONO_TYPE_IS_REFERENCE (t
))
4358 size
= sizeof (gpointer
);
4360 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
4363 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4364 // FIXME: Can't set registers, so we disable linears
4367 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4368 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4369 addr
+= (gint32
)var
->offset
;
4371 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4373 // FIXME: Write barriers
4374 memcpy (addr
, val
, size
);
4376 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4380 g_assert_not_reached ();
4385 clear_event_request (int req_id
, int etype
)
4389 mono_loader_lock ();
4390 for (i
= 0; i
< event_requests
->len
; ++i
) {
4391 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4393 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
4394 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4395 clear_breakpoint (req
->info
);
4396 if (req
->event_kind
== EVENT_KIND_STEP
)
4397 ss_destroy (req
->info
);
4398 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
4399 clear_breakpoint (req
->info
);
4400 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
4401 clear_breakpoint (req
->info
);
4402 g_ptr_array_remove_index_fast (event_requests
, i
);
4407 mono_loader_unlock ();
4411 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
4413 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4414 return breakpoint_matches_assembly (req
->info
, assembly
);
4421 * clear_event_requests_for_assembly:
4423 * Clear all events requests which reference ASSEMBLY.
4426 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
4431 mono_loader_lock ();
4435 for (i
= 0; i
< event_requests
->len
; ++i
) {
4436 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4438 if (event_req_matches_assembly (req
, assembly
)) {
4439 clear_event_request (req
->id
, req
->event_kind
);
4445 mono_loader_unlock ();
4449 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
4451 MonoInternalThread
*thread
= value
;
4452 Buffer
*buf
= user_data
;
4454 buffer_add_objid (buf
, (MonoObject
*)thread
);
4458 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
4460 guint8
*p
= invoke
->p
;
4461 guint8
*end
= invoke
->endp
;
4464 MonoMethodSignature
*sig
;
4467 MonoObject
*this, *res
, *exc
;
4470 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4474 if (invoke
->method
) {
4476 * Invoke this method directly, currently only Environment.Exit () is supported.
4479 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>"));
4480 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
4481 g_assert_not_reached ();
4484 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4487 sig
= mono_method_signature (m
);
4489 if (m
->klass
->valuetype
)
4490 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
4492 this_buf
= g_alloca (sizeof (MonoObject
*));
4493 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
4494 /* Should be null */
4495 int type
= decode_byte (p
, &p
, end
);
4496 if (type
!= VALUE_TYPE_ID_NULL
)
4497 return ERR_INVALID_ARGUMENT
;
4498 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
4500 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
4505 if (!m
->klass
->valuetype
)
4506 this = *(MonoObject
**)this_buf
;
4510 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>"));
4512 if (this && this->vtable
->domain
!= domain
)
4515 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
4516 if (!strcmp (m
->name
, ".ctor")) {
4517 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
4518 return ERR_INVALID_ARGUMENT
;
4520 this = mono_object_new (domain
, m
->klass
);
4522 return ERR_INVALID_ARGUMENT
;
4526 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
4527 return ERR_INVALID_ARGUMENT
;
4529 nargs
= decode_int (p
, &p
, end
);
4530 if (nargs
!= sig
->param_count
)
4531 return ERR_INVALID_ARGUMENT
;
4532 /* Use alloca to get gc tracking */
4533 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
4534 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
4535 args
= g_alloca (nargs
* sizeof (gpointer
));
4536 for (i
= 0; i
< nargs
; ++i
) {
4537 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
4538 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
4542 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
4545 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
4546 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
4549 args
[i
] = arg_buf
[i
];
4556 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
4557 tls
->disable_breakpoints
= TRUE
;
4559 tls
->disable_breakpoints
= FALSE
;
4562 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4564 /* FIXME: Move this to arch specific code */
4565 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4566 if (invoke
->has_ctx
) {
4569 lmf_addr
= mono_get_lmf_addr ();
4572 memset (&ext
, 0, sizeof (ext
));
4574 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4575 /* Mark that this is a MonoLMFExt */
4576 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4577 ext
.lmf
.rsp
= (gssize
)&ext
;
4578 #elif defined(TARGET_X86)
4579 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
4580 /* Mark that this is a MonoLMFExt */
4581 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4582 ext
.lmf
.ebp
= (gssize
)&ext
;
4583 #elif defined(TARGET_ARM)
4584 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4585 /* Mark that this is a MonoLMFExt */
4586 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4587 ext
.lmf
.ebp
= (gssize
)&ext
;
4588 #elif defined(TARGET_POWERPC)
4589 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4590 /* Mark that this is a MonoLMFExt */
4591 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4592 ext
.lmf
.ebp
= (gssize
)&ext
;
4594 g_assert_not_reached ();
4597 ext
.debugger_invoke
= TRUE
;
4598 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4600 mono_set_lmf ((MonoLMF
*)&ext
);
4604 if (m
->klass
->valuetype
)
4605 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
4607 res
= mono_runtime_invoke (m
, this, args
, &exc
);
4609 buffer_add_byte (buf
, 0);
4610 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
4612 buffer_add_byte (buf
, 1);
4613 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4614 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
4615 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
4618 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
4619 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
4620 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
4621 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
4623 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
4629 tls
->disable_breakpoints
= FALSE
;
4631 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4632 if (invoke
->has_ctx
)
4633 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
4636 // FIXME: byref arguments
4644 * Invoke the method given by tls->pending_invoke in the current thread.
4647 invoke_method (void)
4649 DebuggerTlsData
*tls
;
4654 static void (*restore_context
) (void *);
4655 MonoContext restore_ctx
;
4657 if (!restore_context
)
4658 restore_context
= mono_get_restore_context ();
4660 tls
= TlsGetValue (debugger_tls_id
);
4664 * Store the `InvokeData *' in `tls->invoke' until we're done with
4665 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
4668 mono_loader_lock ();
4670 invoke
= tls
->pending_invoke
;
4672 tls
->pending_invoke
= NULL
;
4674 invoke
->last_invoke
= tls
->invoke
;
4675 tls
->invoke
= invoke
;
4677 mono_loader_unlock ();
4679 tls
->frames_up_to_date
= FALSE
;
4683 buffer_init (&buf
, 128);
4685 err
= do_invoke_method (tls
, &buf
, invoke
);
4687 /* Start suspending before sending the reply */
4688 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
4691 send_reply_packet (id
, err
, &buf
);
4695 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4697 if (invoke
->has_ctx
)
4698 save_thread_context (&restore_ctx
);
4700 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
4701 g_assert (tls
->resume_count
);
4702 tls
->resume_count
-= invoke
->suspend_count
;
4705 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
4708 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
4710 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
4711 * after the mono_runtime_invoke() already returned, but it doesn't matter
4712 * because we reset the abort here.
4715 mono_loader_lock ();
4717 if (tls
->abort_requested
)
4718 mono_thread_internal_reset_abort (tls
->thread
);
4720 tls
->invoke
= tls
->invoke
->last_invoke
;
4721 tls
->abort_requested
= FALSE
;
4723 mono_loader_unlock ();
4732 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
4734 MonoThread
*thread
= value
;
4735 DebuggerTlsData
*tls
;
4738 mono_loader_lock ();
4739 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4741 res
= tls
->really_suspended
;
4742 mono_loader_unlock ();
4748 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4751 case CMD_VM_VERSION
: {
4752 char *build_info
, *version
;
4754 build_info
= mono_get_runtime_build_info ();
4755 version
= g_strdup_printf ("mono %s", build_info
);
4757 buffer_add_string (buf
, version
); /* vm version */
4758 buffer_add_int (buf
, MAJOR_VERSION
);
4759 buffer_add_int (buf
, MINOR_VERSION
);
4760 g_free (build_info
);
4764 case CMD_VM_SET_PROTOCOL_VERSION
: {
4765 major_version
= decode_int (p
, &p
, end
);
4766 minor_version
= decode_int (p
, &p
, end
);
4767 protocol_version_set
= TRUE
;
4768 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
4771 case CMD_VM_ALL_THREADS
: {
4773 mono_loader_lock ();
4774 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
4775 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
4776 mono_loader_unlock ();
4779 case CMD_VM_SUSPEND
:
4781 wait_for_suspend ();
4784 if (suspend_count
== 0)
4785 return ERR_NOT_SUSPENDED
;
4788 case CMD_VM_DISPOSE
:
4789 /* Clear all event requests */
4790 mono_loader_lock ();
4791 while (event_requests
->len
> 0) {
4792 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4794 clear_event_request (req
->id
, req
->event_kind
);
4796 mono_loader_unlock ();
4798 // FIXME: Count resumes
4800 disconnected
= TRUE
;
4803 MonoInternalThread
*thread
;
4804 DebuggerTlsData
*tls
;
4805 MonoClass
*env_class
;
4806 MonoMethod
*exit_method
;
4810 exit_code
= decode_int (p
, &p
, end
);
4812 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
4814 /* Have to send a reply before exiting */
4815 send_reply_packet (id
, 0, buf
);
4817 /* Clear all event requests */
4818 mono_loader_lock ();
4819 while (event_requests
->len
> 0) {
4820 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4822 clear_event_request (req
->id
, req
->event_kind
);
4824 mono_loader_unlock ();
4827 * The JDWP documentation says that the shutdown is not orderly. It doesn't
4828 * specify whenever a VM_DEATH event is sent. We currently do an orderly
4829 * shutdown by hijacking a thread to execute Environment.Exit (). This is
4830 * better than doing the shutdown ourselves, since it avoids various races.
4834 wait_for_suspend ();
4836 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
4837 g_assert (env_class
);
4838 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
4839 g_assert (exit_method
);
4841 mono_loader_lock ();
4842 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
4843 mono_loader_unlock ();
4846 mono_loader_lock ();
4847 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4848 mono_loader_unlock ();
4850 args
= g_new0 (gpointer
, 1);
4851 args
[0] = g_malloc (sizeof (int));
4852 *(int*)(args
[0]) = exit_code
;
4854 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4855 tls
->pending_invoke
->method
= exit_method
;
4856 tls
->pending_invoke
->args
= args
;
4858 while (suspend_count
> 0)
4862 * No thread found, do it ourselves.
4863 * FIXME: This can race with normal shutdown etc.
4865 while (suspend_count
> 0)
4868 mono_runtime_set_shutting_down ();
4870 mono_threads_set_shutting_down ();
4872 /* Suspend all managed threads since the runtime is going away */
4873 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
4874 mono_thread_suspend_all_other_threads ();
4875 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
4876 mono_runtime_quit ();
4878 shutdown (conn_fd
, SD_BOTH
);
4880 shutdown (conn_fd
, SHUT_RDWR
);
4882 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
4888 case CMD_VM_INVOKE_METHOD
: {
4889 int objid
= decode_objid (p
, &p
, end
);
4891 DebuggerTlsData
*tls
;
4894 err
= get_object (objid
, (MonoObject
**)&thread
);
4898 flags
= decode_int (p
, &p
, end
);
4900 // Wait for suspending if it already started
4902 wait_for_suspend ();
4903 if (!is_suspended ())
4904 return ERR_NOT_SUSPENDED
;
4906 mono_loader_lock ();
4907 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4908 mono_loader_unlock ();
4911 if (!tls
->really_suspended
)
4912 /* The thread is still running native code, can't do invokes */
4913 return ERR_NOT_SUSPENDED
;
4916 * Store the invoke data into tls, the thread will execute it after it is
4919 if (tls
->pending_invoke
)
4921 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4922 tls
->pending_invoke
->id
= id
;
4923 tls
->pending_invoke
->flags
= flags
;
4924 tls
->pending_invoke
->p
= g_malloc (end
- p
);
4925 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
4926 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
4927 tls
->pending_invoke
->suspend_count
= suspend_count
;
4929 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
4930 resume_thread (THREAD_TO_INTERNAL (thread
));
4935 case CMD_VM_ABORT_INVOKE
: {
4936 int objid
= decode_objid (p
, &p
, end
);
4938 DebuggerTlsData
*tls
;
4941 err
= get_object (objid
, (MonoObject
**)&thread
);
4945 invoke_id
= decode_int (p
, &p
, end
);
4947 mono_loader_lock ();
4948 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4951 if (tls
->abort_requested
) {
4952 mono_loader_unlock ();
4957 * Check whether we're still inside the mono_runtime_invoke() and that it's
4958 * actually the correct invocation.
4960 * Careful, we do not stop the thread that's doing the invocation, so we can't
4961 * inspect its stack. However, invoke_method() also acquires the loader lock
4962 * when it's done, so we're safe here.
4966 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
4967 mono_loader_unlock ();
4968 return ERR_NO_INVOCATION
;
4971 tls
->abort_requested
= TRUE
;
4973 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
4974 mono_loader_unlock ();
4979 return ERR_NOT_IMPLEMENTED
;
4986 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4991 case CMD_EVENT_REQUEST_SET
: {
4993 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
4996 MonoThread
*step_thread
;
4997 int size
= 0, depth
= 0, step_thread_id
= 0;
5000 event_kind
= decode_byte (p
, &p
, end
);
5001 suspend_policy
= decode_byte (p
, &p
, end
);
5002 nmodifiers
= decode_byte (p
, &p
, end
);
5004 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
5005 req
->id
= InterlockedIncrement (&event_request_id
);
5006 req
->event_kind
= event_kind
;
5007 req
->suspend_policy
= suspend_policy
;
5008 req
->nmodifiers
= nmodifiers
;
5011 for (i
= 0; i
< nmodifiers
; ++i
) {
5012 mod
= decode_byte (p
, &p
, end
);
5014 req
->modifiers
[i
].kind
= mod
;
5015 if (mod
== MOD_KIND_COUNT
) {
5016 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
5017 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
5018 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5021 location
= decode_long (p
, &p
, end
);
5022 } else if (mod
== MOD_KIND_STEP
) {
5023 step_thread_id
= decode_id (p
, &p
, end
);
5024 size
= decode_int (p
, &p
, end
);
5025 depth
= decode_int (p
, &p
, end
);
5026 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
5027 int id
= decode_id (p
, &p
, end
);
5029 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
5034 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
5035 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5039 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
5040 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
5042 req
->modifiers
[i
].data
.exc_class
= exc_class
;
5044 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
5046 return ERR_INVALID_ARGUMENT
;
5049 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
5050 int n
= decode_int (p
, &p
, end
);
5053 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
5054 for (j
= 0; j
< n
; ++j
) {
5055 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5057 g_free (req
->modifiers
[i
].data
.assemblies
);
5063 return ERR_NOT_IMPLEMENTED
;
5067 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5070 req
->info
= set_breakpoint (method
, location
, req
);
5071 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
5072 g_assert (step_thread_id
);
5074 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
5080 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
5085 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
5086 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
);
5087 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
5088 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
);
5089 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
5091 if (req
->nmodifiers
) {
5093 return ERR_NOT_IMPLEMENTED
;
5097 mono_loader_lock ();
5098 g_ptr_array_add (event_requests
, req
);
5099 mono_loader_unlock ();
5101 buffer_add_int (buf
, req
->id
);
5104 case CMD_EVENT_REQUEST_CLEAR
: {
5105 int etype
= decode_byte (p
, &p
, end
);
5106 int req_id
= decode_int (p
, &p
, end
);
5108 // FIXME: Make a faster mapping from req_id to request
5109 mono_loader_lock ();
5110 clear_event_request (req_id
, etype
);
5111 mono_loader_unlock ();
5114 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
5117 mono_loader_lock ();
5119 while (i
< event_requests
->len
) {
5120 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5122 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5123 clear_breakpoint (req
->info
);
5125 g_ptr_array_remove_index_fast (event_requests
, i
);
5131 mono_loader_unlock ();
5135 return ERR_NOT_IMPLEMENTED
;
5142 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5148 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
5149 buffer_add_domainid (buf
, mono_get_root_domain ());
5152 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
5153 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5156 buffer_add_string (buf
, domain
->friendly_name
);
5159 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
5164 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5167 mono_loader_lock ();
5169 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5172 buffer_add_int (buf
, count
);
5173 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5175 buffer_add_assemblyid (buf
, domain
, ass
);
5177 mono_loader_unlock ();
5180 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
5181 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5185 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
5188 case CMD_APPDOMAIN_GET_CORLIB
: {
5189 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5193 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
5196 case CMD_APPDOMAIN_CREATE_STRING
: {
5200 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5203 s
= decode_string (p
, &p
, end
);
5205 o
= mono_string_new (domain
, s
);
5206 buffer_add_objid (buf
, (MonoObject
*)o
);
5209 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
5211 MonoDomain
*domain2
;
5214 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5217 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
5222 g_assert (domain
== domain2
);
5224 o
= mono_object_new (domain
, klass
);
5226 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
5230 buffer_add_objid (buf
, o
);
5234 return ERR_NOT_IMPLEMENTED
;
5241 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5247 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5252 case CMD_ASSEMBLY_GET_LOCATION
: {
5253 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
5256 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
5260 if (ass
->image
->dynamic
) {
5261 buffer_add_id (buf
, 0);
5263 token
= mono_image_get_entry_point (ass
->image
);
5265 buffer_add_id (buf
, 0);
5267 m
= mono_get_method (ass
->image
, token
, NULL
);
5268 buffer_add_methodid (buf
, domain
, m
);
5273 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
5274 buffer_add_moduleid (buf
, domain
, ass
->image
);
5277 case CMD_ASSEMBLY_GET_OBJECT
: {
5278 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
5279 buffer_add_objid (buf
, o
);
5282 case CMD_ASSEMBLY_GET_TYPE
: {
5283 char *s
= decode_string (p
, &p
, end
);
5284 gboolean ignorecase
= decode_byte (p
, &p
, end
);
5285 MonoTypeNameParse info
;
5287 gboolean type_resolve
;
5289 if (!mono_reflection_parse_type (s
, &info
)) {
5292 if (info
.assembly
.name
)
5294 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
5296 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
5297 mono_reflection_free_type_info (&info
);
5302 case CMD_ASSEMBLY_GET_NAME
: {
5304 MonoAssembly
*mass
= ass
;
5306 name
= g_strdup_printf (
5307 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
5309 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
5310 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
5311 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
5312 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
5314 buffer_add_string (buf
, name
);
5319 return ERR_NOT_IMPLEMENTED
;
5326 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5332 case CMD_MODULE_GET_INFO
: {
5333 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
5336 basename
= g_path_get_basename (image
->name
);
5337 buffer_add_string (buf
, basename
); // name
5338 buffer_add_string (buf
, image
->module_name
); // scopename
5339 buffer_add_string (buf
, image
->name
); // fqname
5340 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
5341 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
5346 return ERR_NOT_IMPLEMENTED
;
5353 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
5355 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
5356 /* Special case these so the client doesn't have to handle Type objects */
5358 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
5359 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
5360 } else if (MONO_TYPE_IS_REFERENCE (t
))
5361 buffer_add_value (buf
, t
, &val
, domain
);
5363 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
5367 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
5373 buffer_add_int (buf
, 0);
5377 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5378 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
5381 buffer_add_int (buf
, nattrs
);
5383 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5384 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
5385 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
5386 MonoArray
*typed_args
, *named_args
;
5388 CattrNamedArg
*arginfo
;
5390 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
5392 buffer_add_methodid (buf
, domain
, attr
->ctor
);
5396 buffer_add_int (buf
, mono_array_length (typed_args
));
5397 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
5398 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
5400 t
= mono_method_signature (attr
->ctor
)->params
[j
];
5402 buffer_add_cattr_arg (buf
, t
, domain
, val
);
5405 buffer_add_int (buf
, 0);
5410 buffer_add_int (buf
, mono_array_length (named_args
));
5412 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
5413 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
5415 if (arginfo
[j
].prop
) {
5416 buffer_add_byte (buf
, 0x54);
5417 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
5418 } else if (arginfo
[j
].field
) {
5419 buffer_add_byte (buf
, 0x53);
5421 g_assert_not_reached ();
5424 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
5427 buffer_add_int (buf
, 0);
5434 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5445 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5450 case CMD_TYPE_GET_INFO
: {
5451 buffer_add_string (buf
, klass
->name_space
);
5452 buffer_add_string (buf
, klass
->name
);
5454 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
5455 buffer_add_string (buf
, name
);
5457 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
5458 buffer_add_moduleid (buf
, domain
, klass
->image
);
5459 buffer_add_typeid (buf
, domain
, klass
->parent
);
5460 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
5461 buffer_add_typeid (buf
, domain
, klass
->element_class
);
5463 buffer_add_id (buf
, 0);
5464 buffer_add_int (buf
, klass
->type_token
);
5465 buffer_add_byte (buf
, klass
->rank
);
5466 buffer_add_int (buf
, klass
->flags
);
5468 type
= &klass
->byval_arg
;
5469 // FIXME: Can't decide whenever a class represents a byref type
5472 if (type
->type
== MONO_TYPE_PTR
)
5474 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
5476 if (type
->type
== MONO_TYPE_VALUETYPE
)
5478 if (klass
->enumtype
)
5480 buffer_add_byte (buf
, b
);
5483 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5485 buffer_add_int (buf
, nnested
);
5487 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5488 buffer_add_typeid (buf
, domain
, nested
);
5491 case CMD_TYPE_GET_METHODS
: {
5494 gpointer iter
= NULL
;
5497 nmethods
= mono_class_num_methods (klass
);
5499 buffer_add_int (buf
, nmethods
);
5501 while ((m
= mono_class_get_methods (klass
, &iter
))) {
5502 buffer_add_methodid (buf
, domain
, m
);
5505 g_assert (i
== nmethods
);
5508 case CMD_TYPE_GET_FIELDS
: {
5511 gpointer iter
= NULL
;
5514 nfields
= mono_class_num_fields (klass
);
5516 buffer_add_int (buf
, nfields
);
5518 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5519 buffer_add_fieldid (buf
, domain
, f
);
5520 buffer_add_string (buf
, f
->name
);
5521 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
5522 buffer_add_int (buf
, f
->type
->attrs
);
5525 g_assert (i
== nfields
);
5528 case CMD_TYPE_GET_PROPERTIES
: {
5531 gpointer iter
= NULL
;
5534 nprops
= mono_class_num_properties (klass
);
5536 buffer_add_int (buf
, nprops
);
5538 while ((p
= mono_class_get_properties (klass
, &iter
))) {
5539 buffer_add_propertyid (buf
, domain
, p
);
5540 buffer_add_string (buf
, p
->name
);
5541 buffer_add_methodid (buf
, domain
, p
->get
);
5542 buffer_add_methodid (buf
, domain
, p
->set
);
5543 buffer_add_int (buf
, p
->attrs
);
5546 g_assert (i
== nprops
);
5549 case CMD_TYPE_GET_CATTRS
: {
5550 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5551 MonoCustomAttrInfo
*cinfo
;
5553 cinfo
= mono_custom_attrs_from_class (klass
);
5555 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5558 case CMD_TYPE_GET_FIELD_CATTRS
: {
5559 MonoClass
*attr_klass
;
5560 MonoCustomAttrInfo
*cinfo
;
5561 MonoClassField
*field
;
5563 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5566 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5570 cinfo
= mono_custom_attrs_from_field (klass
, field
);
5572 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5575 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
5576 MonoClass
*attr_klass
;
5577 MonoCustomAttrInfo
*cinfo
;
5580 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
5583 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5587 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
5589 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5592 case CMD_TYPE_GET_VALUES
: {
5600 len
= decode_int (p
, &p
, end
);
5601 for (i
= 0; i
< len
; ++i
) {
5602 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5606 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5607 return ERR_INVALID_FIELDID
;
5608 if (mono_class_field_is_special_static (f
))
5609 return ERR_INVALID_FIELDID
;
5611 /* Check that the field belongs to the object */
5613 for (k
= klass
; k
; k
= k
->parent
) {
5614 if (k
== f
->parent
) {
5620 return ERR_INVALID_FIELDID
;
5622 vtable
= mono_class_vtable (domain
, f
->parent
);
5623 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5624 mono_field_static_get_value (vtable
, f
, val
);
5625 buffer_add_value (buf
, f
->type
, val
, domain
);
5630 case CMD_TYPE_SET_VALUES
: {
5638 len
= decode_int (p
, &p
, end
);
5639 for (i
= 0; i
< len
; ++i
) {
5640 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5644 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5645 return ERR_INVALID_FIELDID
;
5646 if (mono_class_field_is_special_static (f
))
5647 return ERR_INVALID_FIELDID
;
5649 /* Check that the field belongs to the object */
5651 for (k
= klass
; k
; k
= k
->parent
) {
5652 if (k
== f
->parent
) {
5658 return ERR_INVALID_FIELDID
;
5660 // FIXME: Check for literal/const
5662 vtable
= mono_class_vtable (domain
, f
->parent
);
5663 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5664 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
5669 if (MONO_TYPE_IS_REFERENCE (f
->type
))
5670 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
5672 mono_field_static_set_value (vtable
, f
, val
);
5677 case CMD_TYPE_GET_OBJECT
: {
5678 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
5679 buffer_add_objid (buf
, o
);
5682 case CMD_TYPE_GET_SOURCE_FILES
: {
5683 gpointer iter
= NULL
;
5685 char *source_file
, *base
;
5689 files
= g_ptr_array_new ();
5691 while ((method
= mono_class_get_methods (klass
, &iter
))) {
5692 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
5695 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
5699 for (i
= 0; i
< files
->len
; ++i
)
5700 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
5702 if (i
== files
->len
)
5703 g_ptr_array_add (files
, g_strdup (source_file
));
5704 g_free (source_file
);
5708 buffer_add_int (buf
, files
->len
);
5709 for (i
= 0; i
< files
->len
; ++i
) {
5710 source_file
= g_ptr_array_index (files
, i
);
5711 base
= g_path_get_basename (source_file
);
5712 buffer_add_string (buf
, base
);
5714 g_free (source_file
);
5716 g_ptr_array_free (files
, TRUE
);
5719 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
5720 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5724 if (mono_class_is_assignable_from (klass
, oklass
))
5725 buffer_add_byte (buf
, 1);
5727 buffer_add_byte (buf
, 0);
5731 return ERR_NOT_IMPLEMENTED
;
5738 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5743 MonoMethodHeader
*header
;
5745 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5750 case CMD_METHOD_GET_NAME
: {
5751 buffer_add_string (buf
, method
->name
);
5754 case CMD_METHOD_GET_DECLARING_TYPE
: {
5755 buffer_add_typeid (buf
, domain
, method
->klass
);
5758 case CMD_METHOD_GET_DEBUG_INFO
: {
5759 MonoDebugMethodInfo
*minfo
;
5761 int i
, n_il_offsets
;
5765 header
= mono_method_get_header (method
);
5767 buffer_add_int (buf
, 0);
5768 buffer_add_string (buf
, "");
5769 buffer_add_int (buf
, 0);
5773 minfo
= mono_debug_lookup_method (method
);
5775 buffer_add_int (buf
, header
->code_size
);
5776 buffer_add_string (buf
, "");
5777 buffer_add_int (buf
, 0);
5778 mono_metadata_free_mh (header
);
5782 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
5783 buffer_add_int (buf
, header
->code_size
);
5784 buffer_add_string (buf
, source_file
);
5785 buffer_add_int (buf
, n_il_offsets
);
5786 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5787 for (i
= 0; i
< n_il_offsets
; ++i
) {
5788 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5789 buffer_add_int (buf
, il_offsets
[i
]);
5790 buffer_add_int (buf
, line_numbers
[i
]);
5792 g_free (source_file
);
5793 g_free (il_offsets
);
5794 g_free (line_numbers
);
5795 mono_metadata_free_mh (header
);
5798 case CMD_METHOD_GET_PARAM_INFO
: {
5799 MonoMethodSignature
*sig
= mono_method_signature (method
);
5803 /* FIXME: mono_class_from_mono_type () and byrefs */
5805 /* FIXME: Use a smaller encoding */
5806 buffer_add_int (buf
, sig
->call_convention
);
5807 buffer_add_int (buf
, sig
->param_count
);
5808 buffer_add_int (buf
, sig
->generic_param_count
);
5809 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
5810 for (i
= 0; i
< sig
->param_count
; ++i
) {
5812 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
5815 /* Emit parameter names */
5816 names
= g_new (char *, sig
->param_count
);
5817 mono_method_get_param_names (method
, (const char **) names
);
5818 for (i
= 0; i
< sig
->param_count
; ++i
)
5819 buffer_add_string (buf
, names
[i
]);
5824 case CMD_METHOD_GET_LOCALS_INFO
: {
5825 int i
, j
, num_locals
;
5829 header
= mono_method_get_header (method
);
5832 buffer_add_int (buf
, header
->num_locals
);
5835 for (i
= 0; i
< header
->num_locals
; ++i
)
5836 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
5839 num_locals
= mono_debug_lookup_locals (method
, &local_names
, &local_indexes
);
5840 for (i
= 0; i
< header
->num_locals
; ++i
) {
5841 for (j
= 0; j
< num_locals
; ++j
)
5842 if (local_indexes
[j
] == i
)
5845 buffer_add_string (buf
, local_names
[j
]);
5847 buffer_add_string (buf
, "");
5849 g_free (local_names
);
5850 g_free (local_indexes
);
5853 /* FIXME: This works because we set debug_options.mdb_optimizations */
5854 for (i
= 0; i
< header
->num_locals
; ++i
) {
5855 buffer_add_int (buf
, 0);
5856 buffer_add_int (buf
, header
->code_size
);
5858 mono_metadata_free_mh (header
);
5862 case CMD_METHOD_GET_INFO
:
5863 buffer_add_int (buf
, method
->flags
);
5864 buffer_add_int (buf
, method
->iflags
);
5865 buffer_add_int (buf
, method
->token
);
5867 case CMD_METHOD_GET_BODY
: {
5870 header
= mono_method_get_header (method
);
5872 buffer_add_int (buf
, 0);
5874 buffer_add_int (buf
, header
->code_size
);
5875 for (i
= 0; i
< header
->code_size
; ++i
)
5876 buffer_add_byte (buf
, header
->code
[i
]);
5878 mono_metadata_free_mh (header
);
5881 case CMD_METHOD_RESOLVE_TOKEN
: {
5882 guint32 token
= decode_int (p
, &p
, end
);
5885 switch (mono_metadata_token_code (token
)) {
5886 case MONO_TOKEN_STRING
: {
5890 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
5893 s2
= mono_string_to_utf8 (s
);
5895 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5896 buffer_add_string (buf
, s2
);
5902 MonoClass
*handle_class
;
5904 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5905 val
= mono_method_get_wrapper_data (method
, token
);
5906 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
5908 if (handle_class
== NULL
) {
5909 // Can't figure out the token type
5910 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
5914 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
5918 if (handle_class
== mono_defaults
.typehandle_class
) {
5919 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
5920 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
5921 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
5922 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
5923 buffer_add_fieldid (buf
, domain
, val
);
5924 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
5925 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
5926 buffer_add_methodid (buf
, domain
, val
);
5927 } else if (handle_class
== mono_defaults
.string_class
) {
5930 s
= mono_string_to_utf8 (val
);
5931 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5932 buffer_add_string (buf
, s
);
5935 g_assert_not_reached ();
5943 return ERR_NOT_IMPLEMENTED
;
5950 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5952 int objid
= decode_objid (p
, &p
, end
);
5954 MonoThread
*thread_obj
;
5955 MonoInternalThread
*thread
;
5957 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
5961 thread
= THREAD_TO_INTERNAL (thread_obj
);
5964 case CMD_THREAD_GET_NAME
: {
5966 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
5969 buffer_add_int (buf
, 0);
5974 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
5976 buffer_add_int (buf
, len
);
5977 buffer_add_data (buf
, (guint8
*)name
, len
);
5982 case CMD_THREAD_GET_FRAME_INFO
: {
5983 DebuggerTlsData
*tls
;
5984 int i
, start_frame
, length
;
5986 // Wait for suspending if it already started
5988 wait_for_suspend ();
5989 if (!is_suspended ())
5990 return ERR_NOT_SUSPENDED
;
5992 start_frame
= decode_int (p
, &p
, end
);
5993 length
= decode_int (p
, &p
, end
);
5995 if (start_frame
!= 0 || length
!= -1)
5996 return ERR_NOT_IMPLEMENTED
;
5998 mono_loader_lock ();
5999 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6000 mono_loader_unlock ();
6003 compute_frame_info (thread
, tls
);
6005 buffer_add_int (buf
, tls
->frame_count
);
6006 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6007 buffer_add_int (buf
, tls
->frames
[i
]->id
);
6008 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->method
);
6009 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
6011 * Instead of passing the frame type directly to the client, we associate
6012 * it with the previous frame using a set of flags. This avoids lots of
6013 * conditional code in the client, since a frame whose type isn't
6014 * FRAME_TYPE_MANAGED has no method, location, etc.
6016 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
6021 case CMD_THREAD_GET_STATE
:
6022 buffer_add_int (buf
, thread
->state
);
6024 case CMD_THREAD_GET_INFO
:
6025 buffer_add_byte (buf
, thread
->threadpool_thread
);
6028 return ERR_NOT_IMPLEMENTED
;
6035 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6039 MonoThread
*thread_obj
;
6040 MonoInternalThread
*thread
;
6042 DebuggerTlsData
*tls
;
6044 MonoDebugMethodJitInfo
*jit
;
6045 MonoDebugVarInfo
*var
;
6046 MonoMethodSignature
*sig
;
6048 MonoMethodHeader
*header
;
6050 objid
= decode_objid (p
, &p
, end
);
6051 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6055 thread
= THREAD_TO_INTERNAL (thread_obj
);
6057 id
= decode_id (p
, &p
, end
);
6059 mono_loader_lock ();
6060 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6061 mono_loader_unlock ();
6064 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6065 if (tls
->frames
[i
]->id
== id
)
6068 if (i
== tls
->frame_count
)
6069 return ERR_INVALID_FRAMEID
;
6071 frame
= tls
->frames
[i
];
6073 if (!frame
->has_ctx
)
6075 return ERR_INVALID_FRAMEID
;
6078 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
6079 g_assert (frame
->jit
);
6083 sig
= mono_method_signature (frame
->method
);
6086 case CMD_STACK_FRAME_GET_VALUES
: {
6087 len
= decode_int (p
, &p
, end
);
6088 header
= mono_method_get_header (frame
->method
);
6090 for (i
= 0; i
< len
; ++i
) {
6091 pos
= decode_int (p
, &p
, end
);
6096 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6098 var
= &jit
->params
[pos
];
6100 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6102 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6104 var
= &jit
->locals
[pos
];
6106 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6109 mono_metadata_free_mh (header
);
6112 case CMD_STACK_FRAME_GET_THIS
: {
6113 if (frame
->method
->klass
->valuetype
) {
6114 if (!sig
->hasthis
) {
6115 MonoObject
*p
= NULL
;
6116 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
6118 add_var (buf
, &frame
->method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6121 if (!sig
->hasthis
) {
6122 MonoObject
*p
= NULL
;
6123 buffer_add_value (buf
, &frame
->method
->klass
->byval_arg
, &p
, frame
->domain
);
6125 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6130 case CMD_STACK_FRAME_SET_VALUES
: {
6133 MonoDebugVarInfo
*var
;
6135 len
= decode_int (p
, &p
, end
);
6136 header
= mono_method_get_header (frame
->method
);
6138 for (i
= 0; i
< len
; ++i
) {
6139 pos
= decode_int (p
, &p
, end
);
6144 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6146 t
= sig
->params
[pos
];
6147 var
= &jit
->params
[pos
];
6149 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6151 t
= header
->locals
[pos
];
6152 var
= &jit
->locals
[pos
];
6155 if (MONO_TYPE_IS_REFERENCE (t
))
6156 val_buf
= g_alloca (sizeof (MonoObject
*));
6158 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
6159 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
6163 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
);
6165 mono_metadata_free_mh (header
);
6169 return ERR_NOT_IMPLEMENTED
;
6176 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6179 int objid
, err
, index
, len
, i
, esize
;
6182 objid
= decode_objid (p
, &p
, end
);
6183 err
= get_object (objid
, (MonoObject
**)&arr
);
6188 case CMD_ARRAY_REF_GET_LENGTH
:
6189 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
6191 buffer_add_int (buf
, arr
->max_length
);
6192 buffer_add_int (buf
, 0);
6194 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
6195 buffer_add_int (buf
, arr
->bounds
[i
].length
);
6196 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
6200 case CMD_ARRAY_REF_GET_VALUES
:
6201 index
= decode_int (p
, &p
, end
);
6202 len
= decode_int (p
, &p
, end
);
6204 g_assert (index
>= 0 && len
>= 0);
6205 // Reordered to avoid integer overflow
6206 g_assert (!(index
> arr
->max_length
- len
));
6208 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6209 for (i
= index
; i
< index
+ len
; ++i
) {
6210 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6211 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
6214 case CMD_ARRAY_REF_SET_VALUES
:
6215 index
= decode_int (p
, &p
, end
);
6216 len
= decode_int (p
, &p
, end
);
6218 g_assert (index
>= 0 && len
>= 0);
6219 // Reordered to avoid integer overflow
6220 g_assert (!(index
> arr
->max_length
- len
));
6222 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6223 for (i
= index
; i
< index
+ len
; ++i
) {
6224 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6226 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
6230 return ERR_NOT_IMPLEMENTED
;
6237 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6243 objid
= decode_objid (p
, &p
, end
);
6244 err
= get_object (objid
, (MonoObject
**)&str
);
6249 case CMD_STRING_REF_GET_VALUE
:
6250 s
= mono_string_to_utf8 (str
);
6251 buffer_add_string (buf
, s
);
6255 return ERR_NOT_IMPLEMENTED
;
6262 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6271 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
6272 objid
= decode_objid (p
, &p
, end
);
6273 err
= get_object (objid
, &obj
);
6275 buffer_add_int (buf
, 1);
6277 buffer_add_int (buf
, 0);
6281 objid
= decode_objid (p
, &p
, end
);
6282 err
= get_object (objid
, &obj
);
6287 case CMD_OBJECT_REF_GET_TYPE
:
6288 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
6290 case CMD_OBJECT_REF_GET_VALUES
:
6291 len
= decode_int (p
, &p
, end
);
6293 for (i
= 0; i
< len
; ++i
) {
6294 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6298 /* Check that the field belongs to the object */
6300 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6301 if (k
== f
->parent
) {
6307 return ERR_INVALID_FIELDID
;
6309 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6313 if (mono_class_field_is_special_static (f
))
6314 return ERR_INVALID_FIELDID
;
6316 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6317 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6318 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6319 mono_field_static_get_value (vtable
, f
, val
);
6320 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
6323 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
6327 case CMD_OBJECT_REF_SET_VALUES
:
6328 len
= decode_int (p
, &p
, end
);
6330 for (i
= 0; i
< len
; ++i
) {
6331 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6335 /* Check that the field belongs to the object */
6337 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6338 if (k
== f
->parent
) {
6344 return ERR_INVALID_FIELDID
;
6346 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6350 if (mono_class_field_is_special_static (f
))
6351 return ERR_INVALID_FIELDID
;
6353 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6354 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6356 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6357 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
6362 mono_field_static_set_value (vtable
, f
, val
);
6365 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
6371 case CMD_OBJECT_REF_GET_ADDRESS
:
6372 buffer_add_long (buf
, (gssize
)obj
);
6374 case CMD_OBJECT_REF_GET_DOMAIN
:
6375 buffer_add_domainid (buf
, obj
->vtable
->domain
);
6378 return ERR_NOT_IMPLEMENTED
;
6385 command_set_to_string (CommandSet command_set
)
6387 switch (command_set
) {
6390 case CMD_SET_OBJECT_REF
:
6391 return "OBJECT_REF";
6392 case CMD_SET_STRING_REF
:
6393 return "STRING_REF";
6394 case CMD_SET_THREAD
:
6396 case CMD_SET_ARRAY_REF
:
6398 case CMD_SET_EVENT_REQUEST
:
6399 return "EVENT_REQUEST";
6400 case CMD_SET_STACK_FRAME
:
6401 return "STACK_FRAME";
6402 case CMD_SET_APPDOMAIN
:
6404 case CMD_SET_ASSEMBLY
:
6406 case CMD_SET_METHOD
:
6410 case CMD_SET_MODULE
:
6422 * This thread handles communication with the debugger client using a JDWP
6425 static guint32 WINAPI
6426 debugger_thread (void *arg
)
6428 int res
, len
, id
, flags
, command_set
, command
;
6429 guint8 header
[HEADER_LENGTH
];
6430 guint8
*data
, *p
, *end
;
6435 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
6437 debugger_thread_id
= GetCurrentThreadId ();
6439 mono_jit_thread_attach (mono_get_root_domain ());
6441 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
6443 mono_set_is_debugger_attached (TRUE
);
6446 res
= recv_length (conn_fd
, header
, HEADER_LENGTH
, 0);
6448 /* This will break if the socket is closed during shutdown too */
6449 if (res
!= HEADER_LENGTH
)
6453 end
= header
+ HEADER_LENGTH
;
6455 len
= decode_int (p
, &p
, end
);
6456 id
= decode_int (p
, &p
, end
);
6457 flags
= decode_byte (p
, &p
, end
);
6458 command_set
= decode_byte (p
, &p
, end
);
6459 command
= decode_byte (p
, &p
, end
);
6461 g_assert (flags
== 0);
6463 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set
), command
, id
));
6465 data
= g_malloc (len
- HEADER_LENGTH
);
6466 if (len
- HEADER_LENGTH
> 0)
6468 res
= recv_length (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
6469 if (res
!= len
- HEADER_LENGTH
)
6474 end
= data
+ (len
- HEADER_LENGTH
);
6476 buffer_init (&buf
, 128);
6481 /* Process the request */
6482 switch (command_set
) {
6484 err
= vm_commands (command
, id
, p
, end
, &buf
);
6485 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
6486 /* Sent after the invoke is complete */
6489 case CMD_SET_EVENT_REQUEST
:
6490 err
= event_commands (command
, p
, end
, &buf
);
6492 case CMD_SET_APPDOMAIN
:
6493 err
= domain_commands (command
, p
, end
, &buf
);
6495 case CMD_SET_ASSEMBLY
:
6496 err
= assembly_commands (command
, p
, end
, &buf
);
6498 case CMD_SET_MODULE
:
6499 err
= module_commands (command
, p
, end
, &buf
);
6502 err
= type_commands (command
, p
, end
, &buf
);
6504 case CMD_SET_METHOD
:
6505 err
= method_commands (command
, p
, end
, &buf
);
6507 case CMD_SET_THREAD
:
6508 err
= thread_commands (command
, p
, end
, &buf
);
6510 case CMD_SET_STACK_FRAME
:
6511 err
= frame_commands (command
, p
, end
, &buf
);
6513 case CMD_SET_ARRAY_REF
:
6514 err
= array_commands (command
, p
, end
, &buf
);
6516 case CMD_SET_STRING_REF
:
6517 err
= string_commands (command
, p
, end
, &buf
);
6519 case CMD_SET_OBJECT_REF
:
6520 err
= object_commands (command
, p
, end
, &buf
);
6523 err
= ERR_NOT_IMPLEMENTED
;
6527 send_reply_packet (id
, err
, &buf
);
6532 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
6536 mono_set_is_debugger_attached (FALSE
);
6538 mono_mutex_lock (&debugger_thread_exited_mutex
);
6539 debugger_thread_exited
= TRUE
;
6540 mono_cond_signal (&debugger_thread_exited_cond
);
6541 mono_mutex_unlock (&debugger_thread_exited_mutex
);
6543 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6548 #else /* DISABLE_DEBUGGER_AGENT */
6551 mono_debugger_agent_parse_options (char *options
)
6553 g_error ("This runtime is configure with the debugger agent disabled.");
6557 mono_debugger_agent_init (void)
6562 mono_debugger_agent_breakpoint_hit (void *sigctx
)
6567 mono_debugger_agent_single_step_event (void *sigctx
)
6572 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
6577 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
6583 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
6584 MonoContext
*catch_ctx
)