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 /* Types whose type load event has no been sent yet */
542 static GPtrArray
*pending_type_loads
;
544 /* Whenever the debugger thread has exited */
545 static gboolean debugger_thread_exited
;
547 /* Cond variable used to wait for debugger_thread_exited becoming true */
548 static mono_cond_t debugger_thread_exited_cond
;
550 /* Mutex for the cond var above */
551 static mono_mutex_t debugger_thread_exited_mutex
;
553 static DebuggerProfiler debugger_profiler
;
555 /* The single step request instance */
556 static SingleStepReq
*ss_req
= NULL
;
557 static gpointer ss_invoke_addr
= NULL
;
559 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
560 /* Number of single stepping operations in progress */
564 /* The protocol version of the client */
565 static int major_version
, minor_version
;
567 /* Whenever the variables above are set by the client */
568 static gboolean protocol_version_set
;
570 static void transport_connect (const char *host
, int port
);
572 static guint32 WINAPI
debugger_thread (void *arg
);
574 static void runtime_initialized (MonoProfiler
*prof
);
576 static void runtime_shutdown (MonoProfiler
*prof
);
578 static void thread_startup (MonoProfiler
*prof
, intptr_t tid
);
580 static void thread_end (MonoProfiler
*prof
, intptr_t tid
);
582 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
584 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
586 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
588 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
590 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
592 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
594 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
596 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
598 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
600 static void start_single_stepping (void);
602 static void stop_single_stepping (void);
604 static void suspend_current (void);
606 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
608 /* Submodule init/cleanup */
609 static void breakpoints_init (void);
610 static void breakpoints_cleanup (void);
612 static void objrefs_init (void);
613 static void objrefs_cleanup (void);
615 static void ids_init (void);
616 static void ids_cleanup (void);
618 static void suspend_init (void);
620 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
);
621 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
622 static void ss_destroy (SingleStepReq
*req
);
624 static void start_debugger_thread (void);
626 static void finish_agent_init (gboolean on_startup
);
629 parse_address (char *address
, char **host
, int *port
)
631 char *pos
= strchr (address
, ':');
633 if (pos
== NULL
|| pos
== address
)
636 *host
= g_malloc (pos
- address
+ 1);
637 strncpy (*host
, address
, pos
- address
);
638 (*host
) [pos
- address
] = '\0';
640 *port
= atoi (pos
+ 1);
648 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
649 fprintf (stderr
, "Available options:\n");
650 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
651 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
652 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
653 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
654 fprintf (stderr
, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
655 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
656 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
660 parse_flag (const char *option
, char *flag
)
662 if (!strcmp (flag
, "y"))
664 else if (!strcmp (flag
, "n"))
667 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
674 mono_debugger_agent_parse_options (char *options
)
680 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
681 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
685 agent_config
.enabled
= TRUE
;
686 agent_config
.suspend
= TRUE
;
687 agent_config
.server
= FALSE
;
689 args
= g_strsplit (options
, ",", -1);
690 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
693 if (strncmp (arg
, "transport=", 10) == 0) {
694 agent_config
.transport
= g_strdup (arg
+ 10);
695 } else if (strncmp (arg
, "address=", 8) == 0) {
696 agent_config
.address
= g_strdup (arg
+ 8);
697 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
698 agent_config
.log_level
= atoi (arg
+ 9);
699 } else if (strncmp (arg
, "logfile=", 8) == 0) {
700 agent_config
.log_file
= g_strdup (arg
+ 8);
701 } else if (strncmp (arg
, "suspend=", 8) == 0) {
702 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
703 } else if (strncmp (arg
, "server=", 7) == 0) {
704 agent_config
.server
= parse_flag ("server", arg
+ 7);
705 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
706 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
707 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
708 /* We support multiple onthrow= options */
709 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
710 } else if (strncmp (arg
, "onthrow", 7) == 0) {
711 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
712 } else if (strncmp (arg
, "help", 4) == 0) {
715 } else if (strncmp (arg
, "timeout=", 8) == 0) {
716 agent_config
.timeout
= atoi (arg
+ 8);
717 } else if (strncmp (arg
, "launch=", 7) == 0) {
718 agent_config
.launch
= g_strdup (arg
+ 7);
725 if (agent_config
.transport
== NULL
) {
726 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
729 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
730 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
734 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
735 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
739 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
740 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
746 mono_debugger_agent_init (void)
748 if (!agent_config
.enabled
)
751 /* Need to know whenever a thread has acquired the loader mutex */
752 mono_loader_lock_track_ownership (TRUE
);
754 event_requests
= g_ptr_array_new ();
756 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
757 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
759 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
760 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
761 mono_profiler_install_runtime_initialized (runtime_initialized
);
762 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
763 mono_profiler_install_thread (thread_startup
, thread_end
);
764 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
765 mono_profiler_install_jit_end (jit_end
);
766 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
768 debugger_tls_id
= TlsAlloc ();
770 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
771 MONO_GC_REGISTER_ROOT (thread_to_tls
);
773 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
774 MONO_GC_REGISTER_ROOT (tid_to_thread
);
776 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
777 MONO_GC_REGISTER_ROOT (tid_to_thread_obj
);
779 loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
780 pending_assembly_loads
= g_ptr_array_new ();
781 pending_type_loads
= g_ptr_array_new ();
783 log_level
= agent_config
.log_level
;
785 if (agent_config
.log_file
) {
786 log_file
= fopen (agent_config
.log_file
, "w+");
788 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
800 mini_get_debug_options ()->gen_seq_points
= TRUE
;
802 * This is needed because currently we don't handle liveness info.
804 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
806 /* This is needed because we can't set local variables in registers yet */
807 mono_disable_optimizations (MONO_OPT_LINEARS
);
809 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
810 finish_agent_init (TRUE
);
816 * Finish the initialization of the agent. This involves connecting the transport
817 * and starting the agent thread. This is either done at startup, or
818 * in response to some event like an unhandled exception.
821 finish_agent_init (gboolean on_startup
)
827 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
830 if (agent_config
.launch
) {
833 // FIXME: Generated address
834 // FIXME: Races with transport_connect ()
836 argv
[0] = agent_config
.launch
;
837 argv
[1] = agent_config
.transport
;
838 argv
[2] = agent_config
.address
;
841 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
843 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
848 if (agent_config
.address
) {
849 res
= parse_address (agent_config
.address
, &host
, &port
);
856 transport_connect (host
, port
);
859 /* Do some which is usually done after sending the VMStart () event */
860 vm_start_event_sent
= TRUE
;
861 start_debugger_thread ();
866 mono_debugger_agent_cleanup (void)
871 /* This will interrupt the agent thread */
872 /* Close the read part only so it can still send back replies */
874 shutdown (conn_fd
, SD_RECEIVE
);
876 shutdown (conn_fd
, SHUT_RD
);
880 * Wait for the thread to exit.
882 * If we continue with the shutdown without waiting for it, then the client might
883 * not receive an answer to its last command like a resume.
884 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
887 //WaitForSingleObject (debugger_thread_handle, INFINITE);
888 if (GetCurrentThreadId () != debugger_thread_id
) {
889 mono_mutex_lock (&debugger_thread_exited_mutex
);
890 if (!debugger_thread_exited
) {
892 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
893 mono_mutex_unlock (&debugger_thread_exited_mutex
);
895 mono_mutex_lock (&debugger_thread_exited_mutex
);
898 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
901 mono_mutex_unlock (&debugger_thread_exited_mutex
);
904 breakpoints_cleanup ();
909 shutdown (conn_fd
, SD_BOTH
);
911 shutdown (conn_fd
, SHUT_RDWR
);
914 mono_mutex_destroy (&debugger_thread_exited_mutex
);
915 mono_cond_destroy (&debugger_thread_exited_cond
);
921 * recv() + handle incomplete reads and EINTR
924 recv_length (int fd
, void *buf
, int len
, int flags
)
930 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
933 } while ((res
> 0 && total
< len
) || (res
== -1 && errno
== EINTR
));
939 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
942 transport_connect (const char *host
, int port
)
944 struct addrinfo hints
;
945 struct addrinfo
*result
, *rp
;
947 char port_string
[128];
948 char handshake_msg
[128];
954 sprintf (port_string
, "%d", port
);
956 mono_network_init ();
958 /* Obtain address(es) matching host/port */
960 memset (&hints
, 0, sizeof (struct addrinfo
));
961 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
962 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
964 hints
.ai_protocol
= 0; /* Any protocol */
966 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
968 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d: %s\n", host
, port
, gai_strerror (s
));
973 if (agent_config
.server
) {
974 /* Wait for a connection */
976 struct sockaddr_in addr
;
979 /* No address, generate one */
980 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
983 /* This will bind the socket to a random port */
984 res
= listen (sfd
, 16);
986 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno
));
990 addrlen
= sizeof (addr
);
991 memset (&addr
, 0, sizeof (addr
));
992 res
= getsockname (sfd
, &addr
, &addrlen
);
996 port
= ntohs (addr
.sin_port
);
998 /* Emit the address to stdout */
999 /* FIXME: Should print another interface, not localhost */
1000 printf ("%s:%d\n", host
, port
);
1002 /* Listen on the provided address */
1003 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1004 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1009 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1013 res
= listen (sfd
, 16);
1021 * this function is not present on win2000 which we still support, and the
1022 * workaround described here:
1023 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1024 * only works with MSVC.
1026 freeaddrinfo (result
);
1030 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1032 if (agent_config
.timeout
) {
1037 tv
.tv_usec
= agent_config
.timeout
* 1000;
1039 FD_SET (sfd
, &readfds
);
1040 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1042 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1047 conn_fd
= accept (sfd
, NULL
, NULL
);
1048 if (conn_fd
== -1) {
1049 fprintf (stderr
, "debugger-agent: Unable to listen on %s:%d\n", host
, port
);
1053 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1055 /* Connect to the specified address */
1056 /* FIXME: Respect the timeout */
1057 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1058 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1063 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1064 break; /* Success */
1072 /* See the comment above */
1073 freeaddrinfo (result
);
1077 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1082 /* Write handshake message */
1083 sprintf (handshake_msg
, "DWP-Handshake");
1085 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1086 } while (res
== -1 && errno
== EINTR
);
1087 g_assert (res
!= -1);
1090 res
= recv_length (conn_fd
, buf
, strlen (handshake_msg
), 0);
1091 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1092 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1097 * To support older clients, the client sends its protocol version after connecting
1098 * using a command. Until that is received, default to our protocol version.
1100 major_version
= MAJOR_VERSION
;
1101 minor_version
= MINOR_VERSION
;
1102 protocol_version_set
= FALSE
;
1105 * Set TCP_NODELAY on the socket so the client receives events/command
1106 * results immediately.
1110 int result
= setsockopt(conn_fd
,
1115 g_assert (result
>= 0);
1120 transport_send (guint8
*data
, int len
)
1125 res
= send (conn_fd
, data
, len
, 0);
1126 } while (res
== -1 && errno
== EINTR
);
1134 start_debugger_thread (void)
1138 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1139 g_assert (debugger_thread_handle
);
1143 * Functions to decode protocol data
1147 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1150 g_assert (*endbuf
<= limit
);
1155 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1158 g_assert (*endbuf
<= limit
);
1160 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1163 static inline gint64
1164 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1166 guint32 high
= decode_int (buf
, &buf
, limit
);
1167 guint32 low
= decode_int (buf
, &buf
, limit
);
1171 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1175 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1177 return decode_int (buf
, endbuf
, limit
);
1181 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1183 int len
= decode_int (buf
, &buf
, limit
);
1186 s
= g_malloc (len
+ 1);
1189 memcpy (s
, buf
, len
);
1198 * Functions to encode protocol data
1202 guint8
*buf
, *p
, *end
;
1206 buffer_init (Buffer
*buf
, int size
)
1208 buf
->buf
= g_malloc (size
);
1210 buf
->end
= buf
->buf
+ size
;
1214 buffer_make_room (Buffer
*buf
, int size
)
1216 if (buf
->end
- buf
->p
< size
) {
1217 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1218 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1219 size
= buf
->p
- buf
->buf
;
1222 buf
->end
= buf
->buf
+ new_size
;
1227 buffer_add_byte (Buffer
*buf
, guint8 val
)
1229 buffer_make_room (buf
, 1);
1235 buffer_add_int (Buffer
*buf
, guint32 val
)
1237 buffer_make_room (buf
, 4);
1238 buf
->p
[0] = (val
>> 24) & 0xff;
1239 buf
->p
[1] = (val
>> 16) & 0xff;
1240 buf
->p
[2] = (val
>> 8) & 0xff;
1241 buf
->p
[3] = (val
>> 0) & 0xff;
1246 buffer_add_long (Buffer
*buf
, guint64 l
)
1248 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1249 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1253 buffer_add_id (Buffer
*buf
, int id
)
1255 buffer_add_int (buf
, (guint64
)id
);
1259 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1261 buffer_make_room (buf
, len
);
1262 memcpy (buf
->p
, data
, len
);
1267 buffer_add_string (Buffer
*buf
, const char *str
)
1272 buffer_add_int (buf
, 0);
1275 buffer_add_int (buf
, len
);
1276 buffer_add_data (buf
, (guint8
*)str
, len
);
1281 buffer_free (Buffer
*buf
)
1287 send_packet (int command_set
, int command
, Buffer
*data
)
1293 id
= InterlockedIncrement (&packet_id
);
1295 len
= data
->p
- data
->buf
+ 11;
1296 buffer_init (&buf
, len
);
1297 buffer_add_int (&buf
, len
);
1298 buffer_add_int (&buf
, id
);
1299 buffer_add_byte (&buf
, 0); /* flags */
1300 buffer_add_byte (&buf
, command_set
);
1301 buffer_add_byte (&buf
, command
);
1302 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1304 res
= transport_send (buf
.buf
, len
);
1312 send_reply_packet (int id
, int error
, Buffer
*data
)
1318 len
= data
->p
- data
->buf
+ 11;
1319 buffer_init (&buf
, len
);
1320 buffer_add_int (&buf
, len
);
1321 buffer_add_int (&buf
, id
);
1322 buffer_add_byte (&buf
, 0x80); /* flags */
1323 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1324 buffer_add_byte (&buf
, error
);
1325 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1327 res
= transport_send (buf
.buf
, len
);
1339 * Represents an object accessible by the debugger client.
1342 /* Unique id used in the wire protocol to refer to objects */
1345 * A weakref gc handle pointing to the object. The gc handle is used to
1346 * detect if the object was garbage collected.
1351 /* Maps objid -> ObjRef */
1352 static GHashTable
*objrefs
;
1355 free_objref (gpointer value
)
1359 mono_gchandle_free (o
->handle
);
1367 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1371 objrefs_cleanup (void)
1373 g_hash_table_destroy (objrefs
);
1377 static GHashTable
*obj_to_objref
;
1380 * Return an ObjRef for OBJ.
1383 get_objref (MonoObject
*obj
)
1394 /* Use a hash table with masked pointers to internalize object references */
1395 /* FIXME: This can grow indefinitely */
1396 mono_loader_lock ();
1399 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1401 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1402 /* ref might refer to a different object with the same addr which was GCd */
1403 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1404 mono_loader_unlock ();
1408 ref
= g_new0 (ObjRef
, 1);
1409 ref
->id
= InterlockedIncrement (&objref_id
);
1410 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1412 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1413 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1415 mono_loader_unlock ();
1421 get_objid (MonoObject
*obj
)
1423 return get_objref (obj
)->id
;
1427 * Set OBJ to the object identified by OBJID.
1428 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1432 get_object_allow_null (int objid
, MonoObject
**obj
)
1442 return ERR_INVALID_OBJECT
;
1444 mono_loader_lock ();
1446 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1449 *obj
= mono_gchandle_get_target (ref
->handle
);
1450 mono_loader_unlock ();
1452 return ERR_INVALID_OBJECT
;
1455 mono_loader_unlock ();
1456 return ERR_INVALID_OBJECT
;
1461 get_object (int objid
, MonoObject
**obj
)
1463 int err
= get_object_allow_null (objid
, obj
);
1468 return ERR_INVALID_OBJECT
;
1473 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1475 return decode_id (buf
, endbuf
, limit
);
1479 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1481 buffer_add_id (buf
, get_objid (o
));
1500 * Represents a runtime structure accessible to the debugger client
1503 /* Unique id used in the wire protocol */
1505 /* Domain of the runtime structure, NULL if the domain was unloaded */
1512 MonoAssembly
*assembly
;
1513 MonoClassField
*field
;
1515 MonoProperty
*property
;
1520 /* Maps runtime structure -> Id */
1521 GHashTable
*val_to_id
[ID_NUM
];
1525 static GPtrArray
*ids
[ID_NUM
];
1532 for (i
= 0; i
< ID_NUM
; ++i
)
1533 ids
[i
] = g_ptr_array_new ();
1541 for (i
= 0; i
< ID_NUM
; ++i
) {
1543 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1544 g_free (g_ptr_array_index (ids
[i
], j
));
1545 g_ptr_array_free (ids
[i
], TRUE
);
1552 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1554 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1558 for (i
= 0; i
< ID_NUM
; ++i
)
1559 if (info
->val_to_id
[i
])
1560 g_hash_table_destroy (info
->val_to_id
[i
]);
1564 domain_jit_info (domain
)->agent_info
= NULL
;
1566 /* Clear ids referencing structures in the domain */
1567 for (i
= 0; i
< ID_NUM
; ++i
) {
1569 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1570 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1571 if (id
->domain
== domain
)
1579 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1582 AgentDomainInfo
*info
;
1587 mono_loader_lock ();
1589 mono_domain_lock (domain
);
1591 if (!domain_jit_info (domain
)->agent_info
)
1592 domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1593 info
= domain_jit_info (domain
)->agent_info
;
1594 if (info
->val_to_id
[type
] == NULL
)
1595 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1597 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1599 mono_domain_unlock (domain
);
1600 mono_loader_unlock ();
1604 id
= g_new0 (Id
, 1);
1606 id
->id
= ids
[type
]->len
+ 1;
1607 id
->domain
= domain
;
1610 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1612 mono_domain_unlock (domain
);
1614 g_ptr_array_add (ids
[type
], id
);
1616 mono_loader_unlock ();
1621 static inline gpointer
1622 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1626 int id
= decode_id (buf
, endbuf
, limit
);
1635 // FIXME: error handling
1636 mono_loader_lock ();
1637 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1639 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1640 mono_loader_unlock ();
1642 if (res
->domain
== NULL
) {
1643 *err
= ERR_UNLOADED
;
1648 *domain
= res
->domain
;
1650 return res
->data
.val
;
1654 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1656 buffer_add_id (buf
, get_id (domain
, type
, val
));
1659 static inline MonoClass
*
1660 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1662 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1665 static inline MonoAssembly
*
1666 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1668 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1671 static inline MonoImage
*
1672 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1674 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1677 static inline MonoMethod
*
1678 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1680 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1683 static inline MonoClassField
*
1684 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1686 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1689 static inline MonoDomain
*
1690 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1692 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1695 static inline MonoProperty
*
1696 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1698 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1702 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1704 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1708 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1710 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1714 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1716 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1720 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1722 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1726 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1728 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1732 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1734 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1738 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1740 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1743 static void invoke_method (void);
1750 * save_thread_context:
1752 * Set CTX as the current threads context which is used for computing stack traces.
1753 * This function is signal-safe.
1756 save_thread_context (MonoContext
*ctx
)
1758 DebuggerTlsData
*tls
;
1760 tls
= TlsGetValue (debugger_tls_id
);
1764 memcpy (&tls
->ctx
, ctx
, sizeof (MonoContext
));
1766 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1767 MONO_INIT_CONTEXT_FROM_CURRENT (&tls
->ctx
);
1769 MONO_INIT_CONTEXT_FROM_FUNC (&tls
->ctx
, save_thread_context
);
1773 tls
->lmf
= mono_get_lmf ();
1774 tls
->domain
= mono_domain_get ();
1775 tls
->has_context
= TRUE
;
1778 /* The number of times the runtime is suspended */
1779 static gint32 suspend_count
;
1781 /* Number of threads suspended */
1783 * If this is equal to the size of thread_to_tls, the runtime is considered
1786 static gint32 threads_suspend_count
;
1788 static mono_mutex_t suspend_mutex
;
1790 /* Cond variable used to wait for suspend_count becoming 0 */
1791 static mono_cond_t suspend_cond
;
1793 /* Semaphore used to wait for a thread becoming suspended */
1794 static MonoSemType suspend_sem
;
1799 mono_mutex_init (&suspend_mutex
, NULL
);
1800 mono_cond_init (&suspend_cond
, NULL
);
1801 MONO_SEM_INIT (&suspend_sem
, 0);
1806 StackFrameInfo last_frame
;
1807 gboolean last_frame_set
;
1810 } GetLastFrameUserData
;
1813 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
1815 GetLastFrameUserData
*data
= user_data
;
1817 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
1820 if (!data
->last_frame_set
) {
1821 /* Store the last frame */
1822 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
1823 data
->last_frame_set
= TRUE
;
1826 /* Store the context/lmf for the frame above the last frame */
1827 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
1828 data
->lmf
= info
->lmf
;
1835 * mono_debugger_agent_thread_interrupt:
1837 * Called by the abort signal handler.
1838 * Should be signal safe.
1841 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
1843 DebuggerTlsData
*tls
;
1848 tls
= TlsGetValue (debugger_tls_id
);
1853 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1854 * guarantee the signal handler will be called that many times. Instead of tracking
1855 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1856 * has been requested that hasn't been handled yet, otherwise we can have threads
1857 * refuse to die when VM_EXIT is called
1859 #if defined(__APPLE__)
1860 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
1864 * We use interrupt_count to determine whenever this interrupt should be processed
1865 * by us or the normal interrupt processing code in the signal handler.
1866 * There is no race here with notify_thread (), since the signal is sent after
1867 * incrementing interrupt_count.
1869 if (tls
->interrupt_count
== 0)
1872 InterlockedDecrement (&tls
->interrupt_count
);
1875 // FIXME: Races when the thread leaves managed code before hitting a single step
1879 /* Running managed code, will be suspended by the single step code */
1880 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
1884 * Running native code, will be suspended when it returns to/enters
1885 * managed code. Treat it as already suspended.
1886 * This might interrupt the code in process_single_step_inner (), we use the
1887 * tls->suspending flag to avoid races when that happens.
1889 if (!tls
->suspended
&& !tls
->suspending
) {
1891 GetLastFrameUserData data
;
1893 // FIXME: printf is not signal safe, but this is only used during
1894 // debugger debugging
1895 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
1896 //save_thread_context (&ctx);
1899 /* Already terminated */
1903 * We are in a difficult position: we want to be able to provide stack
1904 * traces for this thread, but we can't use the current ctx+lmf, since
1905 * the thread is still running, so it might return to managed code,
1906 * making these invalid.
1907 * So we start a stack walk and save the first frame, along with the
1908 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1909 * suspended when it returns to managed code, so the parent's ctx should
1912 data
.last_frame_set
= FALSE
;
1914 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1915 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame
, mono_domain_get (), &ctx
, FALSE
, tls
->thread
, mono_get_lmf (), &data
);
1917 if (data
.last_frame_set
) {
1918 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
1919 memcpy (&tls
->async_ctx
, &data
.ctx
, sizeof (MonoContext
));
1920 tls
->async_lmf
= data
.lmf
;
1921 tls
->has_async_ctx
= TRUE
;
1922 tls
->domain
= mono_domain_get ();
1923 memcpy (&tls
->ctx
, &ctx
, sizeof (MonoContext
));
1925 tls
->has_async_ctx
= FALSE
;
1928 mono_memory_barrier ();
1930 tls
->suspended
= TRUE
;
1931 MONO_SEM_POST (&suspend_sem
);
1938 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
1941 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
1943 #endif /* HOST_WIN32 */
1946 * reset_native_thread_suspend_state:
1948 * Reset the suspended flag on native threads
1951 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
1953 DebuggerTlsData
*tls
= value
;
1955 if (!tls
->really_suspended
&& tls
->suspended
)
1956 tls
->suspended
= FALSE
;
1962 * Notify a thread that it needs to suspend.
1965 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
1967 MonoInternalThread
*thread
= key
;
1968 DebuggerTlsData
*tls
= value
;
1969 gsize tid
= thread
->tid
;
1971 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
1974 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
1977 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1978 * guarantee the signal handler will be called that many times. Instead of tracking
1979 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1980 * has been requested that hasn't been handled yet, otherwise we can have threads
1981 * refuse to die when VM_EXIT is called
1983 #if defined(__APPLE__)
1984 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
1988 * Maybe we could use the normal interrupt infrastructure, but that does a lot
1989 * of things like breaking waits etc. which we don't want.
1991 InterlockedIncrement (&tls
->interrupt_count
);
1994 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
1996 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
1998 pthread_kill ((pthread_t
) tid
, mono_thread_get_abort_signal ());
2003 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2005 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2008 if (debugger_thread_id
== GetCurrentThreadId ())
2011 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2012 if (suspend_count
- tls
->resume_count
> 0)
2013 tls
->suspending
= TRUE
;
2015 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2017 if (suspend_count
- tls
->resume_count
== 0) {
2019 * We are executing a single threaded invoke but the single step for
2020 * suspending is still active.
2021 * FIXME: This slows down single threaded invokes.
2023 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2027 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2029 /* Can't suspend in these methods */
2030 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
2033 save_thread_context (ctx
);
2041 * Increase the suspend count of the VM. While the suspend count is greater
2042 * than 0, runtime threads are suspended at certain points during execution.
2047 mono_loader_lock ();
2049 mono_mutex_lock (&suspend_mutex
);
2053 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2055 if (suspend_count
== 1) {
2056 // FIXME: Is it safe to call this inside the lock ?
2057 start_single_stepping ();
2058 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2061 mono_mutex_unlock (&suspend_mutex
);
2063 mono_loader_unlock ();
2069 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2077 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2079 mono_loader_lock ();
2081 mono_mutex_lock (&suspend_mutex
);
2083 g_assert (suspend_count
> 0);
2086 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2088 if (suspend_count
== 0) {
2089 // FIXME: Is it safe to call this inside the lock ?
2090 stop_single_stepping ();
2091 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2094 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2095 err
= mono_cond_broadcast (&suspend_cond
);
2096 g_assert (err
== 0);
2098 mono_mutex_unlock (&suspend_mutex
);
2099 //g_assert (err == 0);
2101 mono_loader_unlock ();
2107 * Resume just one thread.
2110 resume_thread (MonoInternalThread
*thread
)
2113 DebuggerTlsData
*tls
;
2115 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2117 mono_loader_lock ();
2119 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2122 mono_mutex_lock (&suspend_mutex
);
2124 g_assert (suspend_count
> 0);
2126 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2128 tls
->resume_count
+= suspend_count
;
2131 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2132 * but only the one whose resume_count field is > 0 will be resumed.
2134 err
= mono_cond_broadcast (&suspend_cond
);
2135 g_assert (err
== 0);
2137 mono_mutex_unlock (&suspend_mutex
);
2138 //g_assert (err == 0);
2140 mono_loader_unlock ();
2144 invalidate_frames (DebuggerTlsData
*tls
)
2149 tls
= TlsGetValue (debugger_tls_id
);
2152 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2153 if (tls
->frames
[i
]->jit
)
2154 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2155 g_free (tls
->frames
[i
]);
2157 g_free (tls
->frames
);
2158 tls
->frame_count
= 0;
2165 * Suspend the current thread until the runtime is resumed. If the thread has a
2166 * pending invoke, then the invoke is executed before this function returns.
2169 suspend_current (void)
2172 DebuggerTlsData
*tls
;
2174 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2176 if (mono_loader_lock_is_owned_by_self ()) {
2178 * If we own the loader mutex, can't suspend until we release it, since the
2179 * whole runtime can deadlock otherwise.
2184 tls
= TlsGetValue (debugger_tls_id
);
2187 mono_mutex_lock (&suspend_mutex
);
2189 tls
->suspending
= FALSE
;
2190 tls
->really_suspended
= TRUE
;
2192 if (!tls
->suspended
) {
2193 tls
->suspended
= TRUE
;
2194 MONO_SEM_POST (&suspend_sem
);
2197 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2199 while (suspend_count
- tls
->resume_count
> 0) {
2201 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2203 mono_mutex_unlock (&suspend_mutex
);
2205 mono_mutex_lock (&suspend_mutex
);
2211 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2212 g_assert (err
== 0);
2216 tls
->suspended
= FALSE
;
2217 tls
->really_suspended
= FALSE
;
2219 threads_suspend_count
--;
2221 mono_mutex_unlock (&suspend_mutex
);
2223 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2225 if (tls
->pending_invoke
) {
2226 /* Save the original context */
2227 tls
->pending_invoke
->has_ctx
= TRUE
;
2228 memcpy (&tls
->pending_invoke
->ctx
, &tls
->ctx
, sizeof (MonoContext
));
2233 /* The frame info becomes invalid after a resume */
2234 tls
->has_context
= FALSE
;
2235 tls
->has_async_ctx
= FALSE
;
2236 invalidate_frames (NULL
);
2240 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2242 DebuggerTlsData
*tls
= value
;
2244 if (!tls
->suspended
&& !tls
->terminated
)
2245 *(int*)user_data
= *(int*)user_data
+ 1;
2249 count_threads_to_wait_for (void)
2253 mono_loader_lock ();
2254 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2255 mono_loader_unlock ();
2263 * Wait until the runtime is completely suspended.
2266 wait_for_suspend (void)
2268 int nthreads
, nwait
, err
;
2269 gboolean waited
= FALSE
;
2271 // FIXME: Threads starting/stopping ?
2272 mono_loader_lock ();
2273 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2274 mono_loader_unlock ();
2277 nwait
= count_threads_to_wait_for ();
2279 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2280 err
= MONO_SEM_WAIT (&suspend_sem
);
2281 g_assert (err
== 0);
2289 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2295 * Return whenever the runtime is suspended.
2300 return count_threads_to_wait_for () == 0;
2304 * find_seq_point_for_native_offset:
2306 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2307 * should be the location of a sequence point.
2310 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2312 MonoSeqPointInfo
*seq_points
;
2315 mono_domain_lock (domain
);
2316 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2317 mono_domain_unlock (domain
);
2318 g_assert (seq_points
);
2322 for (i
= 0; i
< seq_points
->len
; ++i
) {
2323 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2324 return &seq_points
->seq_points
[i
];
2333 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2334 * should be the location of a sequence point.
2337 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2339 MonoSeqPointInfo
*seq_points
;
2342 mono_domain_lock (domain
);
2343 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2344 mono_domain_unlock (domain
);
2345 g_assert (seq_points
);
2349 for (i
= 0; i
< seq_points
->len
; ++i
) {
2350 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2351 return &seq_points
->seq_points
[i
];
2358 * compute_il_offset:
2360 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2361 * a location of a sequence point.
2362 * We use this function instead of mono_debug_il_offset_from_address () etc,
2363 * which doesn't seem to work in a lot of cases.
2366 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2368 MonoSeqPointInfo
*seq_points
;
2369 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2371 mono_domain_lock (domain
);
2372 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2373 mono_domain_unlock (domain
);
2374 g_assert (seq_points
);
2376 last_il_offset
= -1;
2378 /* Find the sequence point */
2379 for (i
= 0; i
< seq_points
->len
; ++i
) {
2380 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2381 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2383 if (seq_native_offset
> native_offset
)
2385 last_il_offset
= seq_il_offset
;
2388 return last_il_offset
;
2392 DebuggerTlsData
*tls
;
2394 } ComputeFramesUserData
;
2397 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2399 ComputeFramesUserData
*ud
= user_data
;
2403 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2404 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2405 /* Mark the last frame as an invoke frame */
2407 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2413 method
= info
->ji
->method
;
2415 method
= info
->method
;
2417 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2420 if (info
->il_offset
== -1) {
2421 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2422 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2425 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
));
2427 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2429 * mono_arch_find_jit_info () returns the context stored in the LMF for
2430 * native frames, but it should unwind once. This is why we have duplicate
2431 * frames on the stack sometimes.
2432 * !managed also seems to be set for dynamic methods.
2437 frame
= g_new0 (StackFrame
, 1);
2438 frame
->method
= method
;
2439 frame
->il_offset
= info
->il_offset
;
2442 frame
->has_ctx
= TRUE
;
2444 frame
->domain
= info
->domain
;
2446 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2452 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2454 ComputeFramesUserData user_data
;
2456 int i
, findex
, new_frame_count
;
2457 StackFrame
**new_frames
, *f
;
2459 // FIXME: Locking on tls
2460 if (tls
->frames
&& tls
->frames_up_to_date
)
2463 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2465 user_data
.tls
= tls
;
2466 user_data
.frames
= NULL
;
2467 if (tls
->terminated
) {
2468 tls
->frame_count
= 0;
2470 } if (!tls
->really_suspended
&& tls
->has_async_ctx
) {
2471 /* Have to use the state saved by the signal handler */
2472 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2473 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->async_ctx
, FALSE
, thread
, tls
->async_lmf
, &user_data
);
2474 } else if (tls
->has_context
) {
2475 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->ctx
, FALSE
, thread
, tls
->lmf
, &user_data
);
2478 tls
->frame_count
= 0;
2482 new_frame_count
= g_slist_length (user_data
.frames
);
2483 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2485 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2489 * Reuse the id for already existing stack frames, so invokes don't invalidate
2490 * the still valid stack frames.
2492 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2493 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2494 f
->id
= tls
->frames
[i
]->id
;
2499 if (i
>= tls
->frame_count
)
2500 f
->id
= InterlockedIncrement (&frame_id
);
2502 new_frames
[findex
++] = f
;
2505 g_slist_free (user_data
.frames
);
2507 invalidate_frames (tls
);
2509 tls
->frames
= new_frames
;
2510 tls
->frame_count
= new_frame_count
;
2511 tls
->frames_up_to_date
= TRUE
;
2519 * create_event_list:
2521 * Return a list of event request ids matching EVENT, starting from REQS, which
2522 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2524 * We return request ids, instead of requests, to simplify threading, since
2525 * requests could be deleted anytime when the loader lock is not held.
2526 * LOCKING: Assumes the loader lock is held.
2529 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
2532 GSList
*events
= NULL
;
2534 *suspend_policy
= SUSPEND_POLICY_NONE
;
2537 reqs
= event_requests
;
2542 for (i
= 0; i
< reqs
->len
; ++i
) {
2543 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2544 if (req
->event_kind
== event
) {
2545 gboolean filtered
= FALSE
;
2548 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2549 Modifier
*mod
= &req
->modifiers
[j
];
2551 if (mod
->kind
== MOD_KIND_COUNT
) {
2553 if (mod
->data
.count
> 0) {
2554 if (mod
->data
.count
> 0) {
2556 if (mod
->data
.count
== 0)
2560 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2561 if (mod
->data
.thread
!= mono_thread_internal_current ())
2563 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
2564 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
2566 if (ei
->caught
&& !mod
->caught
)
2568 if (!ei
->caught
&& !mod
->uncaught
)
2570 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2572 gboolean found
= FALSE
;
2573 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2576 for (k
= 0; assemblies
[k
]; ++k
)
2577 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2586 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2587 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2592 /* Send a VM START/DEATH event by default */
2593 if (event
== EVENT_KIND_VM_START
)
2594 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2595 if (event
== EVENT_KIND_VM_DEATH
)
2596 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2601 static G_GNUC_UNUSED
const char*
2602 event_to_string (EventKind event
)
2605 case EVENT_KIND_VM_START
: return "VM_START";
2606 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2607 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2608 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2609 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2610 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2611 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2612 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2613 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2614 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2615 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2616 case EVENT_KIND_STEP
: return "STEP";
2617 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
2618 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
2620 g_assert_not_reached ();
2627 * Send an event to the client, suspending the vm if needed.
2628 * LOCKING: Since this can suspend the calling thread, no locks should be held
2630 * The EVENTS list is freed by this function.
2633 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
2637 MonoDomain
*domain
= mono_domain_get ();
2643 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
)
2644 // FIXME: We miss those events
2647 if (vm_death_event_sent
)
2650 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
)
2659 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
2660 // FIXME: Send these with a NULL thread, don't suspend the current thread
2663 buffer_init (&buf
, 128);
2664 buffer_add_byte (&buf
, suspend_policy
);
2665 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
2667 for (l
= events
; l
; l
= l
->next
) {
2668 buffer_add_byte (&buf
, event
); // event kind
2669 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
2671 thread
= mono_thread_current ();
2673 if (event
== EVENT_KIND_VM_START
)
2675 else if (event
== EVENT_KIND_THREAD_START
)
2676 g_assert (mono_thread_internal_current () == arg
);
2678 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
2681 case EVENT_KIND_THREAD_START
:
2682 case EVENT_KIND_THREAD_DEATH
:
2684 case EVENT_KIND_APPDOMAIN_CREATE
:
2685 case EVENT_KIND_APPDOMAIN_UNLOAD
:
2686 buffer_add_domainid (&buf
, arg
);
2688 case EVENT_KIND_METHOD_ENTRY
:
2689 case EVENT_KIND_METHOD_EXIT
:
2690 buffer_add_methodid (&buf
, domain
, arg
);
2692 case EVENT_KIND_ASSEMBLY_LOAD
:
2693 case EVENT_KIND_ASSEMBLY_UNLOAD
:
2694 buffer_add_assemblyid (&buf
, domain
, arg
);
2696 case EVENT_KIND_TYPE_LOAD
:
2697 buffer_add_typeid (&buf
, domain
, arg
);
2699 case EVENT_KIND_BREAKPOINT
:
2700 case EVENT_KIND_STEP
:
2701 buffer_add_methodid (&buf
, domain
, arg
);
2702 buffer_add_long (&buf
, il_offset
);
2704 case EVENT_KIND_VM_START
:
2705 buffer_add_domainid (&buf
, mono_get_root_domain ());
2707 case EVENT_KIND_VM_DEATH
:
2709 case EVENT_KIND_EXCEPTION
: {
2710 EventInfo
*ei
= arg
;
2711 buffer_add_objid (&buf
, ei
->exc
);
2715 g_assert_not_reached ();
2719 if (event
== EVENT_KIND_VM_START
) {
2720 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
2721 start_debugger_thread ();
2724 if (event
== EVENT_KIND_VM_DEATH
) {
2725 vm_death_event_sent
= TRUE
;
2727 suspend_policy
= SUSPEND_POLICY_NONE
;
2730 if (mono_runtime_is_shutting_down ())
2731 suspend_policy
= SUSPEND_POLICY_NONE
;
2733 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
2735 * Save the thread context and start suspending before sending the packet,
2736 * since we could be receiving the resume request before send_packet ()
2739 save_thread_context (ctx
);
2743 send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
2745 g_slist_free (events
);
2748 if (event
== EVENT_KIND_VM_START
)
2749 vm_start_event_sent
= TRUE
;
2751 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
2755 switch (suspend_policy
) {
2756 case SUSPEND_POLICY_NONE
:
2758 case SUSPEND_POLICY_ALL
:
2761 case SUSPEND_POLICY_EVENT_THREAD
:
2765 g_assert_not_reached ();
2770 process_profiler_event (EventKind event
, gpointer arg
)
2775 mono_loader_lock ();
2776 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
2777 mono_loader_unlock ();
2779 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
2783 runtime_initialized (MonoProfiler
*prof
)
2785 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
2789 runtime_shutdown (MonoProfiler
*prof
)
2791 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
2793 mono_debugger_agent_cleanup ();
2797 thread_startup (MonoProfiler
*prof
, intptr_t tid
)
2799 MonoInternalThread
*thread
= mono_thread_internal_current ();
2800 MonoInternalThread
*old_thread
;
2801 DebuggerTlsData
*tls
;
2803 if (tid
== debugger_thread_id
)
2806 g_assert (thread
->tid
== tid
);
2808 mono_loader_lock ();
2809 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2810 mono_loader_unlock ();
2812 if (thread
== old_thread
) {
2814 * For some reason, thread_startup () might be called for the same thread
2815 * multiple times (attach ?).
2817 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
2821 * thread_end () might not be called for some threads, and the tid could
2824 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
2825 mono_loader_lock ();
2826 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
2827 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
2828 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2829 mono_loader_unlock ();
2833 tls
= TlsGetValue (debugger_tls_id
);
2835 // FIXME: Free this somewhere
2836 tls
= g_new0 (DebuggerTlsData
, 1);
2837 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2838 MONO_GC_REGISTER_ROOT (tls
->thread
);
2839 tls
->thread
= thread
;
2840 TlsSetValue (debugger_tls_id
, tls
);
2842 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2844 mono_loader_lock ();
2845 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
2846 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
2847 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
2848 mono_loader_unlock ();
2850 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
2853 * suspend_vm () could have missed this thread, so wait for a resume.
2859 thread_end (MonoProfiler
*prof
, intptr_t tid
)
2861 MonoInternalThread
*thread
;
2862 DebuggerTlsData
*tls
= NULL
;
2864 mono_loader_lock ();
2865 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2867 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2868 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2869 tls
->terminated
= TRUE
;
2870 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2871 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2872 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
2875 mono_loader_unlock ();
2877 /* We might be called for threads started before we registered the start callback */
2879 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2880 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
2885 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
2887 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
2891 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
2893 /* Invalidate each thread's frame stack */
2894 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
2895 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
2899 * invalidate_each_thread:
2901 * A GHFunc to invalidate frames.
2902 * value must be a DebuggerTlsData*
2905 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
2907 invalidate_frames (value
);
2911 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
2913 /* Sent later in jit_end () */
2914 mono_loader_lock ();
2915 g_ptr_array_add (pending_assembly_loads
, assembly
);
2916 mono_loader_unlock ();
2920 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
2922 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
2924 clear_event_requests_for_assembly (assembly
);
2928 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2930 #if defined(HOST_WIN32) && !defined(__GNUC__)
2931 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2933 gpointer stackptr
= __builtin_frame_address (1);
2935 MonoInternalThread
*thread
= mono_thread_internal_current ();
2936 DebuggerTlsData
*tls
;
2938 mono_loader_lock ();
2940 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2941 /* Could be the debugger thread with assembly/type load hooks */
2943 tls
->invoke_addr
= stackptr
;
2945 mono_loader_unlock ();
2949 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2952 #if defined(HOST_WIN32) && !defined(__GNUC__)
2953 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2955 gpointer stackptr
= __builtin_frame_address (1);
2958 if (ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
2962 * We need to stop single stepping when exiting a runtime invoke, since if it is
2963 * a step out, it may return to native code, and thus never end.
2965 mono_loader_lock ();
2966 ss_invoke_addr
= NULL
;
2968 for (i
= 0; i
< event_requests
->len
; ++i
) {
2969 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
2971 if (req
->event_kind
== EVENT_KIND_STEP
) {
2972 ss_destroy (req
->info
);
2973 g_ptr_array_remove_index_fast (event_requests
, i
);
2978 mono_loader_unlock ();
2982 send_type_load (MonoClass
*klass
)
2984 gboolean type_load
= FALSE
;
2986 mono_loader_lock ();
2987 if (!g_hash_table_lookup (loaded_classes
, klass
)) {
2989 g_hash_table_insert (loaded_classes
, klass
, klass
);
2991 mono_loader_unlock ();
2993 process_profiler_event (EVENT_KIND_TYPE_LOAD
, klass
);
2997 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
3000 * We emit type load events when the first method of the type is JITted,
3001 * since the class load profiler callbacks might be called with the
3002 * loader lock held. They could also occur in the debugger thread.
3003 * Same for assembly load events.
3006 MonoAssembly
*assembly
= NULL
;
3008 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
3009 mono_loader_lock ();
3010 if (pending_assembly_loads
->len
> 0) {
3011 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
3012 g_ptr_array_remove_index (pending_assembly_loads
, 0);
3014 mono_loader_unlock ();
3017 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
3022 if (!vm_start_event_sent
) {
3023 /* Save these so they can be sent after the vm start event */
3024 mono_loader_lock ();
3025 g_ptr_array_add (pending_type_loads
, method
->klass
);
3026 mono_loader_unlock ();
3028 /* Send all pending type load events */
3032 mono_loader_lock ();
3033 if (pending_type_loads
->len
> 0) {
3034 klass
= g_ptr_array_index (pending_type_loads
, 0);
3035 g_ptr_array_remove_index (pending_type_loads
, 0);
3037 mono_loader_unlock ();
3039 send_type_load (klass
);
3044 send_type_load (method
->klass
);
3048 add_pending_breakpoints (method
, jinfo
);
3052 * BREAKPOINTS/SINGLE STEPPING
3056 * Contains information about an inserted breakpoint.
3059 long il_offset
, native_offset
;
3062 } BreakpointInstance
;
3065 * Contains generic information about a breakpoint.
3069 * The method where the breakpoint is placed. Can be NULL in which case it
3070 * is inserted into every method. This is used to implement method entry/
3071 * exit events. Can be a generic method definition, in which case the
3072 * breakpoint is inserted into every instance.
3078 * A list of BreakpointInstance structures describing where the breakpoint
3079 * was inserted. There could be more than one because of
3080 * generics/appdomains/method entry/exit.
3082 GPtrArray
*children
;
3085 /* List of breakpoints */
3086 static GPtrArray
*breakpoints
;
3087 /* Maps breakpoint locations to the number of breakpoints at that location */
3088 static GHashTable
*bp_locs
;
3091 breakpoints_init (void)
3093 breakpoints
= g_ptr_array_new ();
3094 bp_locs
= g_hash_table_new (NULL
, NULL
);
3098 breakpoints_cleanup (void)
3102 mono_loader_lock ();
3104 for (i
= 0; i
< breakpoints
->len
; ++i
)
3105 g_free (g_ptr_array_index (breakpoints
, i
));
3107 g_ptr_array_free (breakpoints
, TRUE
);
3108 g_hash_table_destroy (bp_locs
);
3110 mono_loader_unlock ();
3114 * insert_breakpoint:
3116 * Insert the breakpoint described by BP into the method described by
3120 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
)
3123 gint32 il_offset
= -1, native_offset
;
3124 BreakpointInstance
*inst
;
3127 for (i
= 0; i
< seq_points
->len
; ++i
) {
3128 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3129 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3131 if (il_offset
== bp
->il_offset
)
3135 if (i
== seq_points
->len
)
3136 /* Have to handle this somehow */
3139 inst
= g_new0 (BreakpointInstance
, 1);
3140 inst
->native_offset
= native_offset
;
3141 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3144 mono_loader_lock ();
3146 g_ptr_array_add (bp
->children
, inst
);
3148 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3149 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3150 mono_loader_unlock ();
3153 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3154 mono_arch_set_breakpoint (ji
, inst
->ip
);
3160 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji
->method
, TRUE
), (int)il_offset
));
3164 remove_breakpoint (BreakpointInstance
*inst
)
3166 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3168 MonoJitInfo
*ji
= inst
->ji
;
3169 guint8
*ip
= inst
->ip
;
3171 mono_loader_lock ();
3172 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3173 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3174 mono_loader_unlock ();
3176 g_assert (count
> 0);
3179 mono_arch_clear_breakpoint (ji
, ip
);
3186 static inline gboolean
3187 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
3189 return (!bp
->method
|| method
== bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
));
3193 * add_pending_breakpoints:
3195 * Insert pending breakpoints into the newly JITted method METHOD.
3198 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3201 MonoSeqPointInfo
*seq_points
;
3207 domain
= mono_domain_get ();
3209 mono_loader_lock ();
3211 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3212 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3213 gboolean found
= FALSE
;
3215 if (!bp_matches_method (bp
, method
))
3218 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3219 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3226 mono_domain_lock (domain
);
3227 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3228 mono_domain_unlock (domain
);
3230 /* Could be AOT code */
3232 g_assert (seq_points
);
3234 insert_breakpoint (seq_points
, ji
, bp
);
3238 mono_loader_unlock ();
3242 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
)
3247 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3249 /* Might be AOTed code */
3250 code
= mono_aot_get_method (domain
, method
);
3252 ji
= mono_jit_info_table_find (domain
, code
);
3257 insert_breakpoint (seq_points
, ji
, bp
);
3261 set_bp_in_method_cb (gpointer key
, gpointer value
, gpointer user_data
)
3263 MonoMethod
*method
= key
;
3264 MonoSeqPointInfo
*seq_points
= value
;
3265 MonoBreakpoint
*bp
= user_data
;
3266 MonoDomain
*domain
= mono_domain_get ();
3268 if (bp_matches_method (bp
, method
))
3269 set_bp_in_method (domain
, method
, seq_points
, bp
);
3275 * Set a breakpoint at IL_OFFSET in METHOD.
3276 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3277 * METHOD can also be a generic method definition, in which case a breakpoint
3278 * is placed in all instances of the method.
3280 static MonoBreakpoint
*
3281 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
)
3287 // - suspend/resume the vm to prevent code patching problems
3288 // - multiple breakpoints on the same location
3289 // - dynamic methods
3292 bp
= g_new0 (MonoBreakpoint
, 1);
3293 bp
->method
= method
;
3294 bp
->il_offset
= il_offset
;
3296 bp
->children
= g_ptr_array_new ();
3298 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
));
3300 domain
= mono_domain_get ();
3301 mono_domain_lock (domain
);
3302 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, bp
);
3303 mono_domain_unlock (domain
);
3305 mono_loader_lock ();
3306 g_ptr_array_add (breakpoints
, bp
);
3307 mono_loader_unlock ();
3313 clear_breakpoint (MonoBreakpoint
*bp
)
3317 // FIXME: locking, races
3318 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3319 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3321 remove_breakpoint (inst
);
3326 mono_loader_lock ();
3327 g_ptr_array_remove (breakpoints
, bp
);
3328 mono_loader_unlock ();
3330 g_ptr_array_free (bp
->children
, TRUE
);
3335 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
3337 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
3341 process_breakpoint_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3344 guint8
*orig_ip
, *ip
;
3345 int i
, j
, suspend_policy
;
3346 guint32 native_offset
;
3348 BreakpointInstance
*inst
;
3349 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3350 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3351 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3353 // FIXME: Speed this up
3355 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3356 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3358 g_assert (ji
->method
);
3360 /* Compute the native offset of the breakpoint from the ip */
3361 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3362 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3363 native_offset
= ip
- (guint8
*)ji
->code_start
;
3369 * Skip the instruction causing the breakpoint signal.
3371 mono_arch_skip_breakpoint (ctx
);
3373 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3376 bp_reqs
= g_ptr_array_new ();
3377 ss_reqs
= g_ptr_array_new ();
3378 ss_reqs_orig
= g_ptr_array_new ();
3380 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3382 mono_loader_lock ();
3385 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3386 bp
= g_ptr_array_index (breakpoints
, i
);
3391 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3392 inst
= g_ptr_array_index (bp
->children
, j
);
3393 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3394 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3395 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3397 g_ptr_array_add (bp_reqs
, bp
->req
);
3402 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3403 MonoSeqPointInfo
*seq_points
;
3404 int seq_il_offset
, seq_native_offset
;
3405 MonoDomain
*domain
= mono_domain_get ();
3407 /* Maybe a method entry/exit event */
3408 mono_domain_lock (domain
);
3409 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3410 mono_domain_unlock (domain
);
3412 // FIXME: Generic sharing */
3413 mono_loader_unlock ();
3416 g_assert (seq_points
);
3418 for (i
= 0; i
< seq_points
->len
; ++i
) {
3419 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3420 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3422 if (native_offset
== seq_native_offset
) {
3423 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3424 kind
= EVENT_KIND_METHOD_ENTRY
;
3425 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3426 kind
= EVENT_KIND_METHOD_EXIT
;
3432 /* Process single step requests */
3433 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3434 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3435 SingleStepReq
*ss_req
= bp
->req
->info
;
3436 gboolean hit
= TRUE
;
3437 MonoSeqPointInfo
*info
;
3440 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3443 if (ss_req
->size
== STEP_SIZE_LINE
) {
3444 /* Have to check whenever a different source line was reached */
3445 MonoDebugMethodInfo
*minfo
;
3446 MonoDebugSourceLocation
*loc
= NULL
;
3448 minfo
= mono_debug_lookup_method (ji
->method
);
3451 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3453 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3454 /* Have to continue single stepping */
3458 ss_req
->last_method
= ji
->method
;
3459 ss_req
->last_line
= loc
->row
;
3460 mono_debug_free_source_location (loc
);
3465 g_ptr_array_add (ss_reqs
, req
);
3467 /* Start single stepping again from the current sequence point */
3468 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
);
3471 if (ss_reqs
->len
> 0)
3472 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
3473 if (bp_reqs
->len
> 0)
3474 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
3475 if (kind
!= EVENT_KIND_BREAKPOINT
)
3476 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
3478 mono_loader_unlock ();
3480 g_ptr_array_free (bp_reqs
, TRUE
);
3481 g_ptr_array_free (ss_reqs
, TRUE
);
3484 * FIXME: The first event will suspend, so the second will only be sent after the
3488 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
3490 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
3491 if (enter_leave_events
)
3492 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
3496 process_breakpoint (void)
3498 DebuggerTlsData
*tls
;
3500 static void (*restore_context
) (void *);
3502 if (!restore_context
)
3503 restore_context
= mono_get_restore_context ();
3505 tls
= TlsGetValue (debugger_tls_id
);
3506 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3508 process_breakpoint_inner (tls
, &ctx
);
3510 /* This is called when resuming from a signal handler, so it shouldn't return */
3511 restore_context (&ctx
);
3512 g_assert_not_reached ();
3516 resume_from_signal_handler (void *sigctx
, void *func
)
3518 DebuggerTlsData
*tls
;
3521 /* Save the original context in TLS */
3522 // FIXME: This might not work on an altstack ?
3523 tls
= TlsGetValue (debugger_tls_id
);
3526 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3527 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3528 // clob:c could be added to op_seq_point.
3530 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3531 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
3532 MONO_CONTEXT_SET_IP (&ctx
, func
);
3533 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3535 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3536 mono_ppc_set_func_into_sigctx (sigctx
, func
);
3541 mono_debugger_agent_breakpoint_hit (void *sigctx
)
3544 * We are called from a signal handler, and running code there causes all kinds of
3545 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3546 * So set up the signal context to return to the real breakpoint handler function.
3549 resume_from_signal_handler (sigctx
, process_breakpoint
);
3553 process_single_step_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3558 int il_offset
, suspend_policy
;
3562 // FIXME: Speed this up
3564 ip
= MONO_CONTEXT_GET_IP (ctx
);
3566 /* Skip the instruction causing the single step */
3567 mono_arch_skip_single_step (ctx
);
3569 if (suspend_count
> 0) {
3570 process_suspend (tls
, ctx
);
3575 // FIXME: A suspend race
3578 if (mono_thread_internal_current () != ss_req
->thread
)
3581 if (log_level
> 0) {
3582 const char *depth
= NULL
;
3584 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3586 switch (ss_req
->depth
) {
3587 case STEP_DEPTH_OVER
:
3590 case STEP_DEPTH_OUT
:
3593 case STEP_DEPTH_INTO
:
3597 g_assert_not_reached ();
3600 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
));
3604 * We implement step over/out by single stepping until we reach the same
3605 * frame/parent frame.
3608 * - stack growing upward
3612 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
3613 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
3615 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
3618 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
3621 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3623 g_assert (ji
->method
);
3625 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
3630 * Stopping in memset makes half-initialized vtypes visible.
3631 * Stopping in memcpy makes half-copied vtypes visible.
3633 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
3637 * The ip points to the instruction causing the single step event, convert it
3638 * to the offset stored in seq_points.
3640 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3641 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
3643 g_assert_not_reached ();
3647 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3648 * example, so do things by hand.
3650 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
3652 if (il_offset
== -1)
3655 if (ss_req
->size
== STEP_SIZE_LINE
) {
3656 /* Step until a different source line is reached */
3657 MonoDebugMethodInfo
*minfo
;
3659 minfo
= mono_debug_lookup_method (ji
->method
);
3662 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
3664 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
3665 mono_debug_free_source_location (loc
);
3670 * Step until we reach a location with line number info,
3671 * otherwise the client can't show a location.
3672 * This can happen for example with statics initialized inline
3673 * outside of a cctor.
3678 ss_req
->last_method
= ji
->method
;
3679 ss_req
->last_line
= loc
->row
;
3680 mono_debug_free_source_location (loc
);
3685 // FIXME: Has to lock earlier
3687 reqs
= g_ptr_array_new ();
3689 mono_loader_lock ();
3691 g_ptr_array_add (reqs
, ss_req
->req
);
3693 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
3695 g_ptr_array_free (reqs
, TRUE
);
3697 mono_loader_unlock ();
3699 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
3703 process_single_step (void)
3705 DebuggerTlsData
*tls
;
3707 static void (*restore_context
) (void *);
3709 if (!restore_context
)
3710 restore_context
= mono_get_restore_context ();
3712 tls
= TlsGetValue (debugger_tls_id
);
3713 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3715 process_single_step_inner (tls
, &ctx
);
3717 /* This is called when resuming from a signal handler, so it shouldn't return */
3718 restore_context (&ctx
);
3719 g_assert_not_reached ();
3723 * mono_debugger_agent_single_step_event:
3725 * Called from a signal handler to handle a single step event.
3728 mono_debugger_agent_single_step_event (void *sigctx
)
3730 /* Resume to process_single_step through the signal context */
3732 // FIXME: Since step out/over is implemented using step in, the step in case should
3733 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3736 if (GetCurrentThreadId () == debugger_thread_id
) {
3738 * This could happen despite our best effors when the runtime calls
3739 * assembly/type resolve hooks.
3740 * FIXME: Breakpoints too.
3744 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3745 mono_arch_skip_single_step (&ctx
);
3746 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3750 resume_from_signal_handler (sigctx
, process_single_step
);
3754 * start_single_stepping:
3756 * Turn on single stepping. Can be called multiple times, for example,
3757 * by a single step event request + a suspend.
3760 start_single_stepping (void)
3762 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3763 int val
= InterlockedIncrement (&ss_count
);
3766 mono_arch_start_single_stepping ();
3768 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
3769 DebuggerTlsData
*tls
;
3771 mono_loader_lock ();
3773 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
3774 ss_invoke_addr
= tls
->invoke_addr
;
3776 mono_loader_unlock ();
3779 g_assert_not_reached ();
3784 stop_single_stepping (void)
3786 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3787 int val
= InterlockedDecrement (&ss_count
);
3790 mono_arch_stop_single_stepping ();
3792 g_assert_not_reached ();
3799 * Stop the single stepping operation given by SS_REQ.
3802 ss_stop (SingleStepReq
*ss_req
)
3804 gboolean use_bps
= FALSE
;
3811 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
3812 clear_breakpoint (l
->data
);
3814 g_slist_free (ss_req
->bps
);
3818 if (ss_req
->global
) {
3819 stop_single_stepping ();
3820 ss_req
->global
= FALSE
;
3827 * Start the single stepping operation given by SS_REQ from the sequence point SP.
3830 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
)
3832 gboolean use_bp
= FALSE
;
3837 /* Stop the previous operation */
3841 * Implement single stepping using breakpoints if possible.
3843 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3846 * Find the first sequence point in the current or in a previous frame which
3847 * is not the last in its method.
3849 while (sp
&& sp
->next_len
== 0) {
3851 if (tls
&& frame_index
< tls
->frame_count
) {
3852 StackFrame
*frame
= tls
->frames
[frame_index
];
3854 method
= frame
->method
;
3855 if (frame
->il_offset
!= -1) {
3856 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3862 if (sp
&& sp
->next_len
> 0) {
3864 for (i
= 0; i
< sp
->next_len
; ++i
) {
3865 next_sp
= &info
->seq_points
[sp
->next
[i
]];
3867 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
);
3868 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
3874 ss_req
->global
= TRUE
;
3875 start_single_stepping ();
3877 ss_req
->global
= FALSE
;
3882 * Start single stepping of thread THREAD
3885 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
3887 DebuggerTlsData
*tls
;
3888 MonoSeqPointInfo
*info
;
3889 SeqPoint
*sp
= NULL
;
3890 MonoMethod
*method
= NULL
;
3892 if (suspend_count
== 0)
3893 return ERR_NOT_SUSPENDED
;
3895 wait_for_suspend ();
3897 // FIXME: Multiple requests
3899 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
3900 return ERR_NOT_IMPLEMENTED
;
3903 ss_req
= g_new0 (SingleStepReq
, 1);
3905 ss_req
->thread
= thread
;
3906 ss_req
->size
= size
;
3907 ss_req
->depth
= depth
;
3910 mono_loader_lock ();
3911 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3912 mono_loader_unlock ();
3914 g_assert (tls
->has_context
);
3915 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->ctx
);
3917 if (ss_req
->size
== STEP_SIZE_LINE
) {
3919 MonoDebugMethodInfo
*minfo
;
3921 /* Compute the initial line info */
3922 compute_frame_info (thread
, tls
);
3924 g_assert (tls
->frame_count
);
3925 frame
= tls
->frames
[0];
3927 ss_req
->last_method
= frame
->method
;
3928 ss_req
->last_line
= -1;
3930 minfo
= mono_debug_lookup_method (frame
->method
);
3931 if (minfo
&& frame
->il_offset
!= -1) {
3932 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
3935 ss_req
->last_line
= loc
->row
;
3941 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3944 compute_frame_info (thread
, tls
);
3946 g_assert (tls
->frame_count
);
3947 frame
= tls
->frames
[0];
3949 if (frame
->il_offset
!= -1) {
3950 /* FIXME: Sort the table and use a binary search */
3951 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3953 method
= frame
->method
;
3957 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
);
3963 ss_destroy (SingleStepReq
*req
)
3966 g_assert (ss_req
== req
);
3975 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
3976 MonoContext
*catch_ctx
)
3983 if (thread_to_tls
!= NULL
) {
3984 MonoInternalThread
*thread
= mono_thread_internal_current ();
3985 DebuggerTlsData
*tls
;
3987 mono_loader_lock ();
3988 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3989 mono_loader_unlock ();
3991 if (tls
&& tls
->abort_requested
)
3995 memset (&ei
, 0, sizeof (EventInfo
));
3997 /* Just-In-Time debugging */
3999 if (agent_config
.onuncaught
&& !inited
) {
4000 finish_agent_init (FALSE
);
4003 * Send an unsolicited EXCEPTION event with a dummy request id.
4005 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4006 ei
.exc
= (MonoObject
*)exc
;
4007 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4010 } else if (agent_config
.onthrow
&& !inited
) {
4012 gboolean found
= FALSE
;
4014 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
4015 char *ex_type
= l
->data
;
4016 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
4018 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
4025 finish_agent_init (FALSE
);
4028 * Send an unsolicited EXCEPTION event with a dummy request id.
4030 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4031 ei
.exc
= (MonoObject
*)exc
;
4032 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4040 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
4042 ei
.exc
= (MonoObject
*)exc
;
4043 ei
.caught
= catch_ctx
!= NULL
;
4045 mono_loader_lock ();
4046 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
4047 mono_loader_unlock ();
4049 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
4053 * buffer_add_value_full:
4055 * Add the encoding of the value at ADDR described by T to the buffer.
4056 * AS_VTYPE determines whenever to treat primitive types as primitive types or
4060 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
4066 g_assert (*(void**)addr
);
4067 addr
= *(void**)addr
;
4072 case MONO_TYPE_BOOLEAN
:
4075 case MONO_TYPE_CHAR
:
4095 case MONO_TYPE_VOID
:
4096 buffer_add_byte (buf
, t
->type
);
4098 case MONO_TYPE_BOOLEAN
:
4101 buffer_add_byte (buf
, t
->type
);
4102 buffer_add_int (buf
, *(gint8
*)addr
);
4104 case MONO_TYPE_CHAR
:
4107 buffer_add_byte (buf
, t
->type
);
4108 buffer_add_int (buf
, *(gint16
*)addr
);
4113 buffer_add_byte (buf
, t
->type
);
4114 buffer_add_int (buf
, *(gint32
*)addr
);
4119 buffer_add_byte (buf
, t
->type
);
4120 buffer_add_long (buf
, *(gint64
*)addr
);
4124 /* Treat it as a vtype */
4126 case MONO_TYPE_PTR
: {
4127 gssize val
= *(gssize
*)addr
;
4129 buffer_add_byte (buf
, t
->type
);
4130 buffer_add_long (buf
, val
);
4134 case MONO_TYPE_STRING
:
4135 case MONO_TYPE_SZARRAY
:
4136 case MONO_TYPE_OBJECT
:
4137 case MONO_TYPE_CLASS
:
4138 case MONO_TYPE_ARRAY
:
4139 obj
= *(MonoObject
**)addr
;
4142 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4144 if (obj
->vtable
->klass
->valuetype
) {
4145 t
= &obj
->vtable
->klass
->byval_arg
;
4146 addr
= mono_object_unbox (obj
);
4148 } else if (obj
->vtable
->klass
->rank
) {
4149 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4150 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4151 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4153 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4155 buffer_add_objid (buf
, obj
);
4159 case MONO_TYPE_VALUETYPE
: {
4163 MonoClass
*klass
= mono_class_from_mono_type (t
);
4165 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4166 buffer_add_byte (buf
, klass
->enumtype
);
4167 buffer_add_typeid (buf
, domain
, klass
);
4171 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4172 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4174 if (mono_field_is_deleted (f
))
4178 buffer_add_int (buf
, nfields
);
4181 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4182 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4184 if (mono_field_is_deleted (f
))
4186 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4190 case MONO_TYPE_GENERICINST
:
4191 if (mono_type_generic_inst_is_valuetype (t
)) {
4203 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4205 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4209 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4212 int type
= decode_byte (buf
, &buf
, limit
);
4214 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4215 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4216 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4217 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4218 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4219 char *name
= mono_type_full_name (t
);
4220 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
4222 return ERR_INVALID_ARGUMENT
;
4226 case MONO_TYPE_BOOLEAN
:
4227 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4229 case MONO_TYPE_CHAR
:
4230 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4233 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4236 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4239 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4242 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4245 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4248 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4251 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4254 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4257 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4260 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4263 /* We send these as I8, so we get them back as such */
4264 g_assert (type
== MONO_TYPE_I8
);
4265 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4267 case MONO_TYPE_GENERICINST
:
4268 if (MONO_TYPE_ISSTRUCT (t
)) {
4269 /* The client sends these as a valuetype */
4277 /* We send these as vtypes, so we get them back as such */
4278 g_assert (type
== MONO_TYPE_VALUETYPE
);
4281 case MONO_TYPE_VALUETYPE
: {
4282 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
4286 gpointer iter
= NULL
;
4289 /* Enums are sent as a normal vtype */
4291 return ERR_NOT_IMPLEMENTED
;
4292 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
4296 if (klass
!= mono_class_from_mono_type (t
))
4297 return ERR_INVALID_ARGUMENT
;
4299 nfields
= decode_int (buf
, &buf
, limit
);
4300 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4301 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4303 if (mono_field_is_deleted (f
))
4305 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
4310 g_assert (nfields
== 0);
4315 if (MONO_TYPE_IS_REFERENCE (t
)) {
4316 if (type
== MONO_TYPE_OBJECT
) {
4317 int objid
= decode_objid (buf
, &buf
, limit
);
4321 err
= get_object (objid
, (MonoObject
**)&obj
);
4325 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
4326 return ERR_INVALID_ARGUMENT
;
4327 if (obj
&& obj
->vtable
->domain
!= domain
)
4328 return ERR_INVALID_ARGUMENT
;
4330 mono_gc_wbarrier_generic_store (addr
, obj
);
4331 } else if (type
== VALUE_TYPE_ID_NULL
) {
4332 *(MonoObject
**)addr
= NULL
;
4334 return ERR_INVALID_ARGUMENT
;
4348 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
4355 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4356 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4359 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4360 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
4362 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
4364 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4365 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4366 addr
+= (gint32
)var
->offset
;
4368 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4370 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
4372 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4376 g_assert_not_reached ();
4381 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
)
4387 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4388 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4390 if (MONO_TYPE_IS_REFERENCE (t
))
4391 size
= sizeof (gpointer
);
4393 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
4396 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4397 // FIXME: Can't set registers, so we disable linears
4400 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4401 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4402 addr
+= (gint32
)var
->offset
;
4404 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4406 // FIXME: Write barriers
4407 memcpy (addr
, val
, size
);
4409 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4413 g_assert_not_reached ();
4418 clear_event_request (int req_id
, int etype
)
4422 mono_loader_lock ();
4423 for (i
= 0; i
< event_requests
->len
; ++i
) {
4424 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4426 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
4427 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4428 clear_breakpoint (req
->info
);
4429 if (req
->event_kind
== EVENT_KIND_STEP
)
4430 ss_destroy (req
->info
);
4431 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
4432 clear_breakpoint (req
->info
);
4433 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
4434 clear_breakpoint (req
->info
);
4435 g_ptr_array_remove_index_fast (event_requests
, i
);
4440 mono_loader_unlock ();
4444 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
4446 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4447 return breakpoint_matches_assembly (req
->info
, assembly
);
4451 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
4452 Modifier
*m
= &req
->modifiers
[i
];
4454 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
4456 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
4457 for (j
= 0; m
->data
.assemblies
[j
]; ++j
)
4458 if (m
->data
.assemblies
[j
] == assembly
)
4468 * clear_event_requests_for_assembly:
4470 * Clear all events requests which reference ASSEMBLY.
4473 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
4478 mono_loader_lock ();
4482 for (i
= 0; i
< event_requests
->len
; ++i
) {
4483 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4485 if (event_req_matches_assembly (req
, assembly
)) {
4486 clear_event_request (req
->id
, req
->event_kind
);
4492 mono_loader_unlock ();
4496 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
4498 MonoInternalThread
*thread
= value
;
4499 Buffer
*buf
= user_data
;
4501 buffer_add_objid (buf
, (MonoObject
*)thread
);
4505 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
4507 guint8
*p
= invoke
->p
;
4508 guint8
*end
= invoke
->endp
;
4511 MonoMethodSignature
*sig
;
4514 MonoObject
*this, *res
, *exc
;
4517 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4521 if (invoke
->method
) {
4523 * Invoke this method directly, currently only Environment.Exit () is supported.
4526 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>"));
4527 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
4528 g_assert_not_reached ();
4531 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4534 sig
= mono_method_signature (m
);
4536 if (m
->klass
->valuetype
)
4537 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
4539 this_buf
= g_alloca (sizeof (MonoObject
*));
4540 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
4541 /* Should be null */
4542 int type
= decode_byte (p
, &p
, end
);
4543 if (type
!= VALUE_TYPE_ID_NULL
)
4544 return ERR_INVALID_ARGUMENT
;
4545 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
4547 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
4552 if (!m
->klass
->valuetype
)
4553 this = *(MonoObject
**)this_buf
;
4557 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>"));
4559 if (this && this->vtable
->domain
!= domain
)
4562 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
4563 if (!strcmp (m
->name
, ".ctor")) {
4564 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
4565 return ERR_INVALID_ARGUMENT
;
4567 this = mono_object_new (domain
, m
->klass
);
4569 return ERR_INVALID_ARGUMENT
;
4573 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
4574 return ERR_INVALID_ARGUMENT
;
4576 nargs
= decode_int (p
, &p
, end
);
4577 if (nargs
!= sig
->param_count
)
4578 return ERR_INVALID_ARGUMENT
;
4579 /* Use alloca to get gc tracking */
4580 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
4581 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
4582 args
= g_alloca (nargs
* sizeof (gpointer
));
4583 for (i
= 0; i
< nargs
; ++i
) {
4584 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
4585 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
4589 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
4592 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
4593 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
4596 args
[i
] = arg_buf
[i
];
4603 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
4604 tls
->disable_breakpoints
= TRUE
;
4606 tls
->disable_breakpoints
= FALSE
;
4609 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4611 /* FIXME: Move this to arch specific code */
4612 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4613 if (invoke
->has_ctx
) {
4616 lmf_addr
= mono_get_lmf_addr ();
4619 memset (&ext
, 0, sizeof (ext
));
4621 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4622 /* Mark that this is a MonoLMFExt */
4623 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4624 ext
.lmf
.rsp
= (gssize
)&ext
;
4625 #elif defined(TARGET_X86)
4626 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
4627 /* Mark that this is a MonoLMFExt */
4628 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4629 ext
.lmf
.ebp
= (gssize
)&ext
;
4630 #elif defined(TARGET_ARM)
4631 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4632 /* Mark that this is a MonoLMFExt */
4633 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4634 ext
.lmf
.ebp
= (gssize
)&ext
;
4635 #elif defined(TARGET_POWERPC)
4636 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4637 /* Mark that this is a MonoLMFExt */
4638 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4639 ext
.lmf
.ebp
= (gssize
)&ext
;
4641 g_assert_not_reached ();
4644 ext
.debugger_invoke
= TRUE
;
4645 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4647 mono_set_lmf ((MonoLMF
*)&ext
);
4651 if (m
->klass
->valuetype
)
4652 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
4654 res
= mono_runtime_invoke (m
, this, args
, &exc
);
4656 buffer_add_byte (buf
, 0);
4657 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
4659 buffer_add_byte (buf
, 1);
4660 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4661 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
4662 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
4665 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
4666 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
4667 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
4668 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
4670 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
4676 tls
->disable_breakpoints
= FALSE
;
4678 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4679 if (invoke
->has_ctx
)
4680 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
4683 // FIXME: byref arguments
4691 * Invoke the method given by tls->pending_invoke in the current thread.
4694 invoke_method (void)
4696 DebuggerTlsData
*tls
;
4701 static void (*restore_context
) (void *);
4702 MonoContext restore_ctx
;
4704 if (!restore_context
)
4705 restore_context
= mono_get_restore_context ();
4707 tls
= TlsGetValue (debugger_tls_id
);
4711 * Store the `InvokeData *' in `tls->invoke' until we're done with
4712 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
4715 mono_loader_lock ();
4717 invoke
= tls
->pending_invoke
;
4719 tls
->pending_invoke
= NULL
;
4721 invoke
->last_invoke
= tls
->invoke
;
4722 tls
->invoke
= invoke
;
4724 mono_loader_unlock ();
4726 tls
->frames_up_to_date
= FALSE
;
4730 buffer_init (&buf
, 128);
4732 err
= do_invoke_method (tls
, &buf
, invoke
);
4734 /* Start suspending before sending the reply */
4735 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
4738 send_reply_packet (id
, err
, &buf
);
4742 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4744 if (invoke
->has_ctx
)
4745 save_thread_context (&restore_ctx
);
4747 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
4748 g_assert (tls
->resume_count
);
4749 tls
->resume_count
-= invoke
->suspend_count
;
4752 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
4755 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
4757 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
4758 * after the mono_runtime_invoke() already returned, but it doesn't matter
4759 * because we reset the abort here.
4762 mono_loader_lock ();
4764 if (tls
->abort_requested
)
4765 mono_thread_internal_reset_abort (tls
->thread
);
4767 tls
->invoke
= tls
->invoke
->last_invoke
;
4768 tls
->abort_requested
= FALSE
;
4770 mono_loader_unlock ();
4779 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
4781 MonoThread
*thread
= value
;
4782 DebuggerTlsData
*tls
;
4785 mono_loader_lock ();
4786 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4788 res
= tls
->really_suspended
;
4789 mono_loader_unlock ();
4795 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4798 case CMD_VM_VERSION
: {
4799 char *build_info
, *version
;
4801 build_info
= mono_get_runtime_build_info ();
4802 version
= g_strdup_printf ("mono %s", build_info
);
4804 buffer_add_string (buf
, version
); /* vm version */
4805 buffer_add_int (buf
, MAJOR_VERSION
);
4806 buffer_add_int (buf
, MINOR_VERSION
);
4807 g_free (build_info
);
4811 case CMD_VM_SET_PROTOCOL_VERSION
: {
4812 major_version
= decode_int (p
, &p
, end
);
4813 minor_version
= decode_int (p
, &p
, end
);
4814 protocol_version_set
= TRUE
;
4815 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
4818 case CMD_VM_ALL_THREADS
: {
4820 mono_loader_lock ();
4821 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
4822 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
4823 mono_loader_unlock ();
4826 case CMD_VM_SUSPEND
:
4828 wait_for_suspend ();
4831 if (suspend_count
== 0)
4832 return ERR_NOT_SUSPENDED
;
4835 case CMD_VM_DISPOSE
:
4836 /* Clear all event requests */
4837 mono_loader_lock ();
4838 while (event_requests
->len
> 0) {
4839 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4841 clear_event_request (req
->id
, req
->event_kind
);
4843 mono_loader_unlock ();
4845 // FIXME: Count resumes
4847 disconnected
= TRUE
;
4850 MonoInternalThread
*thread
;
4851 DebuggerTlsData
*tls
;
4852 MonoClass
*env_class
;
4853 MonoMethod
*exit_method
;
4857 exit_code
= decode_int (p
, &p
, end
);
4859 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
4861 /* Have to send a reply before exiting */
4862 send_reply_packet (id
, 0, buf
);
4864 /* Clear all event requests */
4865 mono_loader_lock ();
4866 while (event_requests
->len
> 0) {
4867 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4869 clear_event_request (req
->id
, req
->event_kind
);
4871 mono_loader_unlock ();
4874 * The JDWP documentation says that the shutdown is not orderly. It doesn't
4875 * specify whenever a VM_DEATH event is sent. We currently do an orderly
4876 * shutdown by hijacking a thread to execute Environment.Exit (). This is
4877 * better than doing the shutdown ourselves, since it avoids various races.
4881 wait_for_suspend ();
4883 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
4884 g_assert (env_class
);
4885 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
4886 g_assert (exit_method
);
4888 mono_loader_lock ();
4889 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
4890 mono_loader_unlock ();
4893 mono_loader_lock ();
4894 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4895 mono_loader_unlock ();
4897 args
= g_new0 (gpointer
, 1);
4898 args
[0] = g_malloc (sizeof (int));
4899 *(int*)(args
[0]) = exit_code
;
4901 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4902 tls
->pending_invoke
->method
= exit_method
;
4903 tls
->pending_invoke
->args
= args
;
4905 while (suspend_count
> 0)
4909 * No thread found, do it ourselves.
4910 * FIXME: This can race with normal shutdown etc.
4912 while (suspend_count
> 0)
4915 mono_runtime_set_shutting_down ();
4917 mono_threads_set_shutting_down ();
4919 /* Suspend all managed threads since the runtime is going away */
4920 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
4921 mono_thread_suspend_all_other_threads ();
4922 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
4923 mono_runtime_quit ();
4925 shutdown (conn_fd
, SD_BOTH
);
4927 shutdown (conn_fd
, SHUT_RDWR
);
4929 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
4935 case CMD_VM_INVOKE_METHOD
: {
4936 int objid
= decode_objid (p
, &p
, end
);
4938 DebuggerTlsData
*tls
;
4941 err
= get_object (objid
, (MonoObject
**)&thread
);
4945 flags
= decode_int (p
, &p
, end
);
4947 // Wait for suspending if it already started
4949 wait_for_suspend ();
4950 if (!is_suspended ())
4951 return ERR_NOT_SUSPENDED
;
4953 mono_loader_lock ();
4954 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4955 mono_loader_unlock ();
4958 if (!tls
->really_suspended
)
4959 /* The thread is still running native code, can't do invokes */
4960 return ERR_NOT_SUSPENDED
;
4963 * Store the invoke data into tls, the thread will execute it after it is
4966 if (tls
->pending_invoke
)
4968 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4969 tls
->pending_invoke
->id
= id
;
4970 tls
->pending_invoke
->flags
= flags
;
4971 tls
->pending_invoke
->p
= g_malloc (end
- p
);
4972 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
4973 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
4974 tls
->pending_invoke
->suspend_count
= suspend_count
;
4976 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
4977 resume_thread (THREAD_TO_INTERNAL (thread
));
4982 case CMD_VM_ABORT_INVOKE
: {
4983 int objid
= decode_objid (p
, &p
, end
);
4985 DebuggerTlsData
*tls
;
4988 err
= get_object (objid
, (MonoObject
**)&thread
);
4992 invoke_id
= decode_int (p
, &p
, end
);
4994 mono_loader_lock ();
4995 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4998 if (tls
->abort_requested
) {
4999 mono_loader_unlock ();
5004 * Check whether we're still inside the mono_runtime_invoke() and that it's
5005 * actually the correct invocation.
5007 * Careful, we do not stop the thread that's doing the invocation, so we can't
5008 * inspect its stack. However, invoke_method() also acquires the loader lock
5009 * when it's done, so we're safe here.
5013 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
5014 mono_loader_unlock ();
5015 return ERR_NO_INVOCATION
;
5018 tls
->abort_requested
= TRUE
;
5020 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
5021 mono_loader_unlock ();
5026 return ERR_NOT_IMPLEMENTED
;
5033 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5038 case CMD_EVENT_REQUEST_SET
: {
5040 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
5043 MonoThread
*step_thread
;
5044 int size
= 0, depth
= 0, step_thread_id
= 0;
5047 event_kind
= decode_byte (p
, &p
, end
);
5048 suspend_policy
= decode_byte (p
, &p
, end
);
5049 nmodifiers
= decode_byte (p
, &p
, end
);
5051 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
5052 req
->id
= InterlockedIncrement (&event_request_id
);
5053 req
->event_kind
= event_kind
;
5054 req
->suspend_policy
= suspend_policy
;
5055 req
->nmodifiers
= nmodifiers
;
5058 for (i
= 0; i
< nmodifiers
; ++i
) {
5059 mod
= decode_byte (p
, &p
, end
);
5061 req
->modifiers
[i
].kind
= mod
;
5062 if (mod
== MOD_KIND_COUNT
) {
5063 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
5064 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
5065 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5068 location
= decode_long (p
, &p
, end
);
5069 } else if (mod
== MOD_KIND_STEP
) {
5070 step_thread_id
= decode_id (p
, &p
, end
);
5071 size
= decode_int (p
, &p
, end
);
5072 depth
= decode_int (p
, &p
, end
);
5073 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
5074 int id
= decode_id (p
, &p
, end
);
5076 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
5081 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
5082 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5086 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
5087 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
5088 DEBUG(1, fprintf (log_file
, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s).\n", exc_class
? exc_class
->name
: "all", req
->modifiers
[i
].caught
? ", caught" : "", req
->modifiers
[i
].uncaught
? ", uncaught" : ""));
5090 req
->modifiers
[i
].data
.exc_class
= exc_class
;
5092 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
5094 return ERR_INVALID_ARGUMENT
;
5097 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
5098 int n
= decode_int (p
, &p
, end
);
5101 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
5102 for (j
= 0; j
< n
; ++j
) {
5103 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5105 g_free (req
->modifiers
[i
].data
.assemblies
);
5111 return ERR_NOT_IMPLEMENTED
;
5115 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5118 req
->info
= set_breakpoint (method
, location
, req
);
5119 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
5120 g_assert (step_thread_id
);
5122 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
5128 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
5133 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
5134 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
);
5135 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
5136 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
);
5137 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
5139 if (req
->nmodifiers
) {
5141 return ERR_NOT_IMPLEMENTED
;
5145 mono_loader_lock ();
5146 g_ptr_array_add (event_requests
, req
);
5147 mono_loader_unlock ();
5149 buffer_add_int (buf
, req
->id
);
5152 case CMD_EVENT_REQUEST_CLEAR
: {
5153 int etype
= decode_byte (p
, &p
, end
);
5154 int req_id
= decode_int (p
, &p
, end
);
5156 // FIXME: Make a faster mapping from req_id to request
5157 mono_loader_lock ();
5158 clear_event_request (req_id
, etype
);
5159 mono_loader_unlock ();
5162 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
5165 mono_loader_lock ();
5167 while (i
< event_requests
->len
) {
5168 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5170 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5171 clear_breakpoint (req
->info
);
5173 g_ptr_array_remove_index_fast (event_requests
, i
);
5179 mono_loader_unlock ();
5183 return ERR_NOT_IMPLEMENTED
;
5190 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5196 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
5197 buffer_add_domainid (buf
, mono_get_root_domain ());
5200 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
5201 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5204 buffer_add_string (buf
, domain
->friendly_name
);
5207 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
5212 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5215 mono_loader_lock ();
5217 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5220 buffer_add_int (buf
, count
);
5221 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5223 buffer_add_assemblyid (buf
, domain
, ass
);
5225 mono_loader_unlock ();
5228 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
5229 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5233 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
5236 case CMD_APPDOMAIN_GET_CORLIB
: {
5237 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5241 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
5244 case CMD_APPDOMAIN_CREATE_STRING
: {
5248 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5251 s
= decode_string (p
, &p
, end
);
5253 o
= mono_string_new (domain
, s
);
5254 buffer_add_objid (buf
, (MonoObject
*)o
);
5257 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
5259 MonoDomain
*domain2
;
5262 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5265 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
5270 g_assert (domain
== domain2
);
5272 o
= mono_object_new (domain
, klass
);
5274 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
5278 buffer_add_objid (buf
, o
);
5282 return ERR_NOT_IMPLEMENTED
;
5289 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5295 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5300 case CMD_ASSEMBLY_GET_LOCATION
: {
5301 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
5304 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
5308 if (ass
->image
->dynamic
) {
5309 buffer_add_id (buf
, 0);
5311 token
= mono_image_get_entry_point (ass
->image
);
5313 buffer_add_id (buf
, 0);
5315 m
= mono_get_method (ass
->image
, token
, NULL
);
5316 buffer_add_methodid (buf
, domain
, m
);
5321 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
5322 buffer_add_moduleid (buf
, domain
, ass
->image
);
5325 case CMD_ASSEMBLY_GET_OBJECT
: {
5326 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
5327 buffer_add_objid (buf
, o
);
5330 case CMD_ASSEMBLY_GET_TYPE
: {
5331 char *s
= decode_string (p
, &p
, end
);
5332 gboolean ignorecase
= decode_byte (p
, &p
, end
);
5333 MonoTypeNameParse info
;
5335 gboolean type_resolve
;
5337 if (!mono_reflection_parse_type (s
, &info
)) {
5340 if (info
.assembly
.name
)
5342 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
5344 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
5345 mono_reflection_free_type_info (&info
);
5350 case CMD_ASSEMBLY_GET_NAME
: {
5352 MonoAssembly
*mass
= ass
;
5354 name
= g_strdup_printf (
5355 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
5357 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
5358 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
5359 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
5360 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
5362 buffer_add_string (buf
, name
);
5367 return ERR_NOT_IMPLEMENTED
;
5374 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5380 case CMD_MODULE_GET_INFO
: {
5381 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
5384 basename
= g_path_get_basename (image
->name
);
5385 buffer_add_string (buf
, basename
); // name
5386 buffer_add_string (buf
, image
->module_name
); // scopename
5387 buffer_add_string (buf
, image
->name
); // fqname
5388 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
5389 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
5394 return ERR_NOT_IMPLEMENTED
;
5401 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
5403 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
5404 /* Special case these so the client doesn't have to handle Type objects */
5406 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
5407 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
5408 } else if (MONO_TYPE_IS_REFERENCE (t
))
5409 buffer_add_value (buf
, t
, &val
, domain
);
5411 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
5415 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
5421 buffer_add_int (buf
, 0);
5425 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5426 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
5429 buffer_add_int (buf
, nattrs
);
5431 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5432 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
5433 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
5434 MonoArray
*typed_args
, *named_args
;
5436 CattrNamedArg
*arginfo
;
5438 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
5440 buffer_add_methodid (buf
, domain
, attr
->ctor
);
5444 buffer_add_int (buf
, mono_array_length (typed_args
));
5445 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
5446 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
5448 t
= mono_method_signature (attr
->ctor
)->params
[j
];
5450 buffer_add_cattr_arg (buf
, t
, domain
, val
);
5453 buffer_add_int (buf
, 0);
5458 buffer_add_int (buf
, mono_array_length (named_args
));
5460 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
5461 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
5463 if (arginfo
[j
].prop
) {
5464 buffer_add_byte (buf
, 0x54);
5465 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
5466 } else if (arginfo
[j
].field
) {
5467 buffer_add_byte (buf
, 0x53);
5469 g_assert_not_reached ();
5472 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
5475 buffer_add_int (buf
, 0);
5482 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5493 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5498 case CMD_TYPE_GET_INFO
: {
5499 buffer_add_string (buf
, klass
->name_space
);
5500 buffer_add_string (buf
, klass
->name
);
5502 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
5503 buffer_add_string (buf
, name
);
5505 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
5506 buffer_add_moduleid (buf
, domain
, klass
->image
);
5507 buffer_add_typeid (buf
, domain
, klass
->parent
);
5508 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
5509 buffer_add_typeid (buf
, domain
, klass
->element_class
);
5511 buffer_add_id (buf
, 0);
5512 buffer_add_int (buf
, klass
->type_token
);
5513 buffer_add_byte (buf
, klass
->rank
);
5514 buffer_add_int (buf
, klass
->flags
);
5516 type
= &klass
->byval_arg
;
5517 // FIXME: Can't decide whenever a class represents a byref type
5520 if (type
->type
== MONO_TYPE_PTR
)
5522 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
5524 if (type
->type
== MONO_TYPE_VALUETYPE
)
5526 if (klass
->enumtype
)
5528 buffer_add_byte (buf
, b
);
5531 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5533 buffer_add_int (buf
, nnested
);
5535 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5536 buffer_add_typeid (buf
, domain
, nested
);
5539 case CMD_TYPE_GET_METHODS
: {
5542 gpointer iter
= NULL
;
5545 nmethods
= mono_class_num_methods (klass
);
5547 buffer_add_int (buf
, nmethods
);
5549 while ((m
= mono_class_get_methods (klass
, &iter
))) {
5550 buffer_add_methodid (buf
, domain
, m
);
5553 g_assert (i
== nmethods
);
5556 case CMD_TYPE_GET_FIELDS
: {
5559 gpointer iter
= NULL
;
5562 nfields
= mono_class_num_fields (klass
);
5564 buffer_add_int (buf
, nfields
);
5566 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5567 buffer_add_fieldid (buf
, domain
, f
);
5568 buffer_add_string (buf
, f
->name
);
5569 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
5570 buffer_add_int (buf
, f
->type
->attrs
);
5573 g_assert (i
== nfields
);
5576 case CMD_TYPE_GET_PROPERTIES
: {
5579 gpointer iter
= NULL
;
5582 nprops
= mono_class_num_properties (klass
);
5584 buffer_add_int (buf
, nprops
);
5586 while ((p
= mono_class_get_properties (klass
, &iter
))) {
5587 buffer_add_propertyid (buf
, domain
, p
);
5588 buffer_add_string (buf
, p
->name
);
5589 buffer_add_methodid (buf
, domain
, p
->get
);
5590 buffer_add_methodid (buf
, domain
, p
->set
);
5591 buffer_add_int (buf
, p
->attrs
);
5594 g_assert (i
== nprops
);
5597 case CMD_TYPE_GET_CATTRS
: {
5598 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5599 MonoCustomAttrInfo
*cinfo
;
5601 cinfo
= mono_custom_attrs_from_class (klass
);
5603 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5606 case CMD_TYPE_GET_FIELD_CATTRS
: {
5607 MonoClass
*attr_klass
;
5608 MonoCustomAttrInfo
*cinfo
;
5609 MonoClassField
*field
;
5611 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5614 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5618 cinfo
= mono_custom_attrs_from_field (klass
, field
);
5620 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5623 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
5624 MonoClass
*attr_klass
;
5625 MonoCustomAttrInfo
*cinfo
;
5628 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
5631 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5635 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
5637 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5640 case CMD_TYPE_GET_VALUES
: {
5648 len
= decode_int (p
, &p
, end
);
5649 for (i
= 0; i
< len
; ++i
) {
5650 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5654 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5655 return ERR_INVALID_FIELDID
;
5656 if (mono_class_field_is_special_static (f
))
5657 return ERR_INVALID_FIELDID
;
5659 /* Check that the field belongs to the object */
5661 for (k
= klass
; k
; k
= k
->parent
) {
5662 if (k
== f
->parent
) {
5668 return ERR_INVALID_FIELDID
;
5670 vtable
= mono_class_vtable (domain
, f
->parent
);
5671 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5672 mono_field_static_get_value (vtable
, f
, val
);
5673 buffer_add_value (buf
, f
->type
, val
, domain
);
5678 case CMD_TYPE_SET_VALUES
: {
5686 len
= decode_int (p
, &p
, end
);
5687 for (i
= 0; i
< len
; ++i
) {
5688 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5692 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5693 return ERR_INVALID_FIELDID
;
5694 if (mono_class_field_is_special_static (f
))
5695 return ERR_INVALID_FIELDID
;
5697 /* Check that the field belongs to the object */
5699 for (k
= klass
; k
; k
= k
->parent
) {
5700 if (k
== f
->parent
) {
5706 return ERR_INVALID_FIELDID
;
5708 // FIXME: Check for literal/const
5710 vtable
= mono_class_vtable (domain
, f
->parent
);
5711 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5712 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
5717 if (MONO_TYPE_IS_REFERENCE (f
->type
))
5718 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
5720 mono_field_static_set_value (vtable
, f
, val
);
5725 case CMD_TYPE_GET_OBJECT
: {
5726 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
5727 buffer_add_objid (buf
, o
);
5730 case CMD_TYPE_GET_SOURCE_FILES
: {
5731 gpointer iter
= NULL
;
5733 char *source_file
, *base
;
5737 files
= g_ptr_array_new ();
5739 while ((method
= mono_class_get_methods (klass
, &iter
))) {
5740 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
5743 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
5747 for (i
= 0; i
< files
->len
; ++i
)
5748 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
5750 if (i
== files
->len
)
5751 g_ptr_array_add (files
, g_strdup (source_file
));
5752 g_free (source_file
);
5756 buffer_add_int (buf
, files
->len
);
5757 for (i
= 0; i
< files
->len
; ++i
) {
5758 source_file
= g_ptr_array_index (files
, i
);
5759 base
= g_path_get_basename (source_file
);
5760 buffer_add_string (buf
, base
);
5762 g_free (source_file
);
5764 g_ptr_array_free (files
, TRUE
);
5767 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
5768 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5772 if (mono_class_is_assignable_from (klass
, oklass
))
5773 buffer_add_byte (buf
, 1);
5775 buffer_add_byte (buf
, 0);
5779 return ERR_NOT_IMPLEMENTED
;
5786 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5791 MonoMethodHeader
*header
;
5793 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5798 case CMD_METHOD_GET_NAME
: {
5799 buffer_add_string (buf
, method
->name
);
5802 case CMD_METHOD_GET_DECLARING_TYPE
: {
5803 buffer_add_typeid (buf
, domain
, method
->klass
);
5806 case CMD_METHOD_GET_DEBUG_INFO
: {
5807 MonoDebugMethodInfo
*minfo
;
5809 int i
, n_il_offsets
;
5813 header
= mono_method_get_header (method
);
5815 buffer_add_int (buf
, 0);
5816 buffer_add_string (buf
, "");
5817 buffer_add_int (buf
, 0);
5821 minfo
= mono_debug_lookup_method (method
);
5823 buffer_add_int (buf
, header
->code_size
);
5824 buffer_add_string (buf
, "");
5825 buffer_add_int (buf
, 0);
5826 mono_metadata_free_mh (header
);
5830 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
5831 buffer_add_int (buf
, header
->code_size
);
5832 buffer_add_string (buf
, source_file
);
5833 buffer_add_int (buf
, n_il_offsets
);
5834 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5835 for (i
= 0; i
< n_il_offsets
; ++i
) {
5836 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5837 buffer_add_int (buf
, il_offsets
[i
]);
5838 buffer_add_int (buf
, line_numbers
[i
]);
5840 g_free (source_file
);
5841 g_free (il_offsets
);
5842 g_free (line_numbers
);
5843 mono_metadata_free_mh (header
);
5846 case CMD_METHOD_GET_PARAM_INFO
: {
5847 MonoMethodSignature
*sig
= mono_method_signature (method
);
5851 /* FIXME: mono_class_from_mono_type () and byrefs */
5853 /* FIXME: Use a smaller encoding */
5854 buffer_add_int (buf
, sig
->call_convention
);
5855 buffer_add_int (buf
, sig
->param_count
);
5856 buffer_add_int (buf
, sig
->generic_param_count
);
5857 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
5858 for (i
= 0; i
< sig
->param_count
; ++i
) {
5860 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
5863 /* Emit parameter names */
5864 names
= g_new (char *, sig
->param_count
);
5865 mono_method_get_param_names (method
, (const char **) names
);
5866 for (i
= 0; i
< sig
->param_count
; ++i
)
5867 buffer_add_string (buf
, names
[i
]);
5872 case CMD_METHOD_GET_LOCALS_INFO
: {
5873 int i
, j
, num_locals
;
5877 header
= mono_method_get_header (method
);
5880 buffer_add_int (buf
, header
->num_locals
);
5883 for (i
= 0; i
< header
->num_locals
; ++i
)
5884 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
5887 num_locals
= mono_debug_lookup_locals (method
, &local_names
, &local_indexes
);
5888 for (i
= 0; i
< header
->num_locals
; ++i
) {
5889 for (j
= 0; j
< num_locals
; ++j
)
5890 if (local_indexes
[j
] == i
)
5893 buffer_add_string (buf
, local_names
[j
]);
5895 buffer_add_string (buf
, "");
5897 g_free (local_names
);
5898 g_free (local_indexes
);
5901 /* FIXME: This works because we set debug_options.mdb_optimizations */
5902 for (i
= 0; i
< header
->num_locals
; ++i
) {
5903 buffer_add_int (buf
, 0);
5904 buffer_add_int (buf
, header
->code_size
);
5906 mono_metadata_free_mh (header
);
5910 case CMD_METHOD_GET_INFO
:
5911 buffer_add_int (buf
, method
->flags
);
5912 buffer_add_int (buf
, method
->iflags
);
5913 buffer_add_int (buf
, method
->token
);
5915 case CMD_METHOD_GET_BODY
: {
5918 header
= mono_method_get_header (method
);
5920 buffer_add_int (buf
, 0);
5922 buffer_add_int (buf
, header
->code_size
);
5923 for (i
= 0; i
< header
->code_size
; ++i
)
5924 buffer_add_byte (buf
, header
->code
[i
]);
5926 mono_metadata_free_mh (header
);
5929 case CMD_METHOD_RESOLVE_TOKEN
: {
5930 guint32 token
= decode_int (p
, &p
, end
);
5933 switch (mono_metadata_token_code (token
)) {
5934 case MONO_TOKEN_STRING
: {
5938 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
5941 s2
= mono_string_to_utf8 (s
);
5943 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5944 buffer_add_string (buf
, s2
);
5950 MonoClass
*handle_class
;
5952 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5953 val
= mono_method_get_wrapper_data (method
, token
);
5954 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
5956 if (handle_class
== NULL
) {
5957 // Can't figure out the token type
5958 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
5962 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
5966 if (handle_class
== mono_defaults
.typehandle_class
) {
5967 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
5968 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
5969 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
5970 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
5971 buffer_add_fieldid (buf
, domain
, val
);
5972 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
5973 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
5974 buffer_add_methodid (buf
, domain
, val
);
5975 } else if (handle_class
== mono_defaults
.string_class
) {
5978 s
= mono_string_to_utf8 (val
);
5979 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5980 buffer_add_string (buf
, s
);
5983 g_assert_not_reached ();
5991 return ERR_NOT_IMPLEMENTED
;
5998 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6000 int objid
= decode_objid (p
, &p
, end
);
6002 MonoThread
*thread_obj
;
6003 MonoInternalThread
*thread
;
6005 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6009 thread
= THREAD_TO_INTERNAL (thread_obj
);
6012 case CMD_THREAD_GET_NAME
: {
6014 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
6017 buffer_add_int (buf
, 0);
6022 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
6024 buffer_add_int (buf
, len
);
6025 buffer_add_data (buf
, (guint8
*)name
, len
);
6030 case CMD_THREAD_GET_FRAME_INFO
: {
6031 DebuggerTlsData
*tls
;
6032 int i
, start_frame
, length
;
6034 // Wait for suspending if it already started
6036 wait_for_suspend ();
6037 if (!is_suspended ())
6038 return ERR_NOT_SUSPENDED
;
6040 start_frame
= decode_int (p
, &p
, end
);
6041 length
= decode_int (p
, &p
, end
);
6043 if (start_frame
!= 0 || length
!= -1)
6044 return ERR_NOT_IMPLEMENTED
;
6046 mono_loader_lock ();
6047 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6048 mono_loader_unlock ();
6051 compute_frame_info (thread
, tls
);
6053 buffer_add_int (buf
, tls
->frame_count
);
6054 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6055 buffer_add_int (buf
, tls
->frames
[i
]->id
);
6056 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->method
);
6057 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
6059 * Instead of passing the frame type directly to the client, we associate
6060 * it with the previous frame using a set of flags. This avoids lots of
6061 * conditional code in the client, since a frame whose type isn't
6062 * FRAME_TYPE_MANAGED has no method, location, etc.
6064 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
6069 case CMD_THREAD_GET_STATE
:
6070 buffer_add_int (buf
, thread
->state
);
6072 case CMD_THREAD_GET_INFO
:
6073 buffer_add_byte (buf
, thread
->threadpool_thread
);
6076 return ERR_NOT_IMPLEMENTED
;
6083 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6087 MonoThread
*thread_obj
;
6088 MonoInternalThread
*thread
;
6090 DebuggerTlsData
*tls
;
6092 MonoDebugMethodJitInfo
*jit
;
6093 MonoDebugVarInfo
*var
;
6094 MonoMethodSignature
*sig
;
6096 MonoMethodHeader
*header
;
6098 objid
= decode_objid (p
, &p
, end
);
6099 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6103 thread
= THREAD_TO_INTERNAL (thread_obj
);
6105 id
= decode_id (p
, &p
, end
);
6107 mono_loader_lock ();
6108 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6109 mono_loader_unlock ();
6112 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6113 if (tls
->frames
[i
]->id
== id
)
6116 if (i
== tls
->frame_count
)
6117 return ERR_INVALID_FRAMEID
;
6119 frame
= tls
->frames
[i
];
6121 if (!frame
->has_ctx
)
6123 return ERR_INVALID_FRAMEID
;
6126 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
6127 g_assert (frame
->jit
);
6131 sig
= mono_method_signature (frame
->method
);
6134 case CMD_STACK_FRAME_GET_VALUES
: {
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 var
= &jit
->params
[pos
];
6148 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6150 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6152 var
= &jit
->locals
[pos
];
6154 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6157 mono_metadata_free_mh (header
);
6160 case CMD_STACK_FRAME_GET_THIS
: {
6161 if (frame
->method
->klass
->valuetype
) {
6162 if (!sig
->hasthis
) {
6163 MonoObject
*p
= NULL
;
6164 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
6166 add_var (buf
, &frame
->method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6169 if (!sig
->hasthis
) {
6170 MonoObject
*p
= NULL
;
6171 buffer_add_value (buf
, &frame
->method
->klass
->byval_arg
, &p
, frame
->domain
);
6173 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6178 case CMD_STACK_FRAME_SET_VALUES
: {
6181 MonoDebugVarInfo
*var
;
6183 len
= decode_int (p
, &p
, end
);
6184 header
= mono_method_get_header (frame
->method
);
6186 for (i
= 0; i
< len
; ++i
) {
6187 pos
= decode_int (p
, &p
, end
);
6192 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6194 t
= sig
->params
[pos
];
6195 var
= &jit
->params
[pos
];
6197 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6199 t
= header
->locals
[pos
];
6200 var
= &jit
->locals
[pos
];
6203 if (MONO_TYPE_IS_REFERENCE (t
))
6204 val_buf
= g_alloca (sizeof (MonoObject
*));
6206 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
6207 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
6211 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
);
6213 mono_metadata_free_mh (header
);
6217 return ERR_NOT_IMPLEMENTED
;
6224 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6227 int objid
, err
, index
, len
, i
, esize
;
6230 objid
= decode_objid (p
, &p
, end
);
6231 err
= get_object (objid
, (MonoObject
**)&arr
);
6236 case CMD_ARRAY_REF_GET_LENGTH
:
6237 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
6239 buffer_add_int (buf
, arr
->max_length
);
6240 buffer_add_int (buf
, 0);
6242 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
6243 buffer_add_int (buf
, arr
->bounds
[i
].length
);
6244 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
6248 case CMD_ARRAY_REF_GET_VALUES
:
6249 index
= decode_int (p
, &p
, end
);
6250 len
= decode_int (p
, &p
, end
);
6252 g_assert (index
>= 0 && len
>= 0);
6253 // Reordered to avoid integer overflow
6254 g_assert (!(index
> arr
->max_length
- len
));
6256 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6257 for (i
= index
; i
< index
+ len
; ++i
) {
6258 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6259 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
6262 case CMD_ARRAY_REF_SET_VALUES
:
6263 index
= decode_int (p
, &p
, end
);
6264 len
= decode_int (p
, &p
, end
);
6266 g_assert (index
>= 0 && len
>= 0);
6267 // Reordered to avoid integer overflow
6268 g_assert (!(index
> arr
->max_length
- len
));
6270 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6271 for (i
= index
; i
< index
+ len
; ++i
) {
6272 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6274 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
6278 return ERR_NOT_IMPLEMENTED
;
6285 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6291 objid
= decode_objid (p
, &p
, end
);
6292 err
= get_object (objid
, (MonoObject
**)&str
);
6297 case CMD_STRING_REF_GET_VALUE
:
6298 s
= mono_string_to_utf8 (str
);
6299 buffer_add_string (buf
, s
);
6303 return ERR_NOT_IMPLEMENTED
;
6310 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6319 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
6320 objid
= decode_objid (p
, &p
, end
);
6321 err
= get_object (objid
, &obj
);
6323 buffer_add_int (buf
, 1);
6325 buffer_add_int (buf
, 0);
6329 objid
= decode_objid (p
, &p
, end
);
6330 err
= get_object (objid
, &obj
);
6335 case CMD_OBJECT_REF_GET_TYPE
:
6336 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
6338 case CMD_OBJECT_REF_GET_VALUES
:
6339 len
= decode_int (p
, &p
, end
);
6341 for (i
= 0; i
< len
; ++i
) {
6342 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6346 /* Check that the field belongs to the object */
6348 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6349 if (k
== f
->parent
) {
6355 return ERR_INVALID_FIELDID
;
6357 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6361 if (mono_class_field_is_special_static (f
))
6362 return ERR_INVALID_FIELDID
;
6364 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6365 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6366 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6367 mono_field_static_get_value (vtable
, f
, val
);
6368 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
6371 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
6375 case CMD_OBJECT_REF_SET_VALUES
:
6376 len
= decode_int (p
, &p
, end
);
6378 for (i
= 0; i
< len
; ++i
) {
6379 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6383 /* Check that the field belongs to the object */
6385 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6386 if (k
== f
->parent
) {
6392 return ERR_INVALID_FIELDID
;
6394 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6398 if (mono_class_field_is_special_static (f
))
6399 return ERR_INVALID_FIELDID
;
6401 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6402 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6404 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6405 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
6410 mono_field_static_set_value (vtable
, f
, val
);
6413 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
6419 case CMD_OBJECT_REF_GET_ADDRESS
:
6420 buffer_add_long (buf
, (gssize
)obj
);
6422 case CMD_OBJECT_REF_GET_DOMAIN
:
6423 buffer_add_domainid (buf
, obj
->vtable
->domain
);
6426 return ERR_NOT_IMPLEMENTED
;
6433 command_set_to_string (CommandSet command_set
)
6435 switch (command_set
) {
6438 case CMD_SET_OBJECT_REF
:
6439 return "OBJECT_REF";
6440 case CMD_SET_STRING_REF
:
6441 return "STRING_REF";
6442 case CMD_SET_THREAD
:
6444 case CMD_SET_ARRAY_REF
:
6446 case CMD_SET_EVENT_REQUEST
:
6447 return "EVENT_REQUEST";
6448 case CMD_SET_STACK_FRAME
:
6449 return "STACK_FRAME";
6450 case CMD_SET_APPDOMAIN
:
6452 case CMD_SET_ASSEMBLY
:
6454 case CMD_SET_METHOD
:
6458 case CMD_SET_MODULE
:
6470 * This thread handles communication with the debugger client using a JDWP
6473 static guint32 WINAPI
6474 debugger_thread (void *arg
)
6476 int res
, len
, id
, flags
, command_set
, command
;
6477 guint8 header
[HEADER_LENGTH
];
6478 guint8
*data
, *p
, *end
;
6483 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
6485 debugger_thread_id
= GetCurrentThreadId ();
6487 mono_jit_thread_attach (mono_get_root_domain ());
6489 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
6491 mono_set_is_debugger_attached (TRUE
);
6494 res
= recv_length (conn_fd
, header
, HEADER_LENGTH
, 0);
6496 /* This will break if the socket is closed during shutdown too */
6497 if (res
!= HEADER_LENGTH
)
6501 end
= header
+ HEADER_LENGTH
;
6503 len
= decode_int (p
, &p
, end
);
6504 id
= decode_int (p
, &p
, end
);
6505 flags
= decode_byte (p
, &p
, end
);
6506 command_set
= decode_byte (p
, &p
, end
);
6507 command
= decode_byte (p
, &p
, end
);
6509 g_assert (flags
== 0);
6511 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set
), command
, id
));
6513 data
= g_malloc (len
- HEADER_LENGTH
);
6514 if (len
- HEADER_LENGTH
> 0)
6516 res
= recv_length (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
6517 if (res
!= len
- HEADER_LENGTH
)
6522 end
= data
+ (len
- HEADER_LENGTH
);
6524 buffer_init (&buf
, 128);
6529 /* Process the request */
6530 switch (command_set
) {
6532 err
= vm_commands (command
, id
, p
, end
, &buf
);
6533 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
6534 /* Sent after the invoke is complete */
6537 case CMD_SET_EVENT_REQUEST
:
6538 err
= event_commands (command
, p
, end
, &buf
);
6540 case CMD_SET_APPDOMAIN
:
6541 err
= domain_commands (command
, p
, end
, &buf
);
6543 case CMD_SET_ASSEMBLY
:
6544 err
= assembly_commands (command
, p
, end
, &buf
);
6546 case CMD_SET_MODULE
:
6547 err
= module_commands (command
, p
, end
, &buf
);
6550 err
= type_commands (command
, p
, end
, &buf
);
6552 case CMD_SET_METHOD
:
6553 err
= method_commands (command
, p
, end
, &buf
);
6555 case CMD_SET_THREAD
:
6556 err
= thread_commands (command
, p
, end
, &buf
);
6558 case CMD_SET_STACK_FRAME
:
6559 err
= frame_commands (command
, p
, end
, &buf
);
6561 case CMD_SET_ARRAY_REF
:
6562 err
= array_commands (command
, p
, end
, &buf
);
6564 case CMD_SET_STRING_REF
:
6565 err
= string_commands (command
, p
, end
, &buf
);
6567 case CMD_SET_OBJECT_REF
:
6568 err
= object_commands (command
, p
, end
, &buf
);
6571 err
= ERR_NOT_IMPLEMENTED
;
6575 send_reply_packet (id
, err
, &buf
);
6580 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
6584 mono_set_is_debugger_attached (FALSE
);
6586 mono_mutex_lock (&debugger_thread_exited_mutex
);
6587 debugger_thread_exited
= TRUE
;
6588 mono_cond_signal (&debugger_thread_exited_cond
);
6589 mono_mutex_unlock (&debugger_thread_exited_mutex
);
6591 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6596 #else /* DISABLE_DEBUGGER_AGENT */
6599 mono_debugger_agent_parse_options (char *options
)
6601 g_error ("This runtime is configure with the debugger agent disabled.");
6605 mono_debugger_agent_init (void)
6610 mono_debugger_agent_breakpoint_hit (void *sigctx
)
6615 mono_debugger_agent_single_step_event (void *sigctx
)
6620 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
6625 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
6631 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
6632 MonoContext
*catch_ctx
)