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,
346 CMD_THREAD_GET_ID
= 5
350 CMD_EVENT_REQUEST_SET
= 1,
351 CMD_EVENT_REQUEST_CLEAR
= 2,
352 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
360 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
361 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
362 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
363 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
364 CMD_APPDOMAIN_CREATE_STRING
= 5,
365 CMD_APPDOMAIN_GET_CORLIB
= 6,
366 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7,
370 CMD_ASSEMBLY_GET_LOCATION
= 1,
371 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
372 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
373 CMD_ASSEMBLY_GET_OBJECT
= 4,
374 CMD_ASSEMBLY_GET_TYPE
= 5,
375 CMD_ASSEMBLY_GET_NAME
= 6
379 CMD_MODULE_GET_INFO
= 1,
383 CMD_METHOD_GET_NAME
= 1,
384 CMD_METHOD_GET_DECLARING_TYPE
= 2,
385 CMD_METHOD_GET_DEBUG_INFO
= 3,
386 CMD_METHOD_GET_PARAM_INFO
= 4,
387 CMD_METHOD_GET_LOCALS_INFO
= 5,
388 CMD_METHOD_GET_INFO
= 6,
389 CMD_METHOD_GET_BODY
= 7,
390 CMD_METHOD_RESOLVE_TOKEN
= 8,
394 CMD_TYPE_GET_INFO
= 1,
395 CMD_TYPE_GET_METHODS
= 2,
396 CMD_TYPE_GET_FIELDS
= 3,
397 CMD_TYPE_GET_VALUES
= 4,
398 CMD_TYPE_GET_OBJECT
= 5,
399 CMD_TYPE_GET_SOURCE_FILES
= 6,
400 CMD_TYPE_SET_VALUES
= 7,
401 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
402 CMD_TYPE_GET_PROPERTIES
= 9,
403 CMD_TYPE_GET_CATTRS
= 10,
404 CMD_TYPE_GET_FIELD_CATTRS
= 11,
405 CMD_TYPE_GET_PROPERTY_CATTRS
= 12
409 CMD_STACK_FRAME_GET_VALUES
= 1,
410 CMD_STACK_FRAME_GET_THIS
= 2,
411 CMD_STACK_FRAME_SET_VALUES
= 3
415 CMD_ARRAY_REF_GET_LENGTH
= 1,
416 CMD_ARRAY_REF_GET_VALUES
= 2,
417 CMD_ARRAY_REF_SET_VALUES
= 3,
421 CMD_STRING_REF_GET_VALUE
= 1,
425 CMD_OBJECT_REF_GET_TYPE
= 1,
426 CMD_OBJECT_REF_GET_VALUES
= 2,
427 CMD_OBJECT_REF_IS_COLLECTED
= 3,
428 CMD_OBJECT_REF_GET_ADDRESS
= 4,
429 CMD_OBJECT_REF_GET_DOMAIN
= 5,
430 CMD_OBJECT_REF_SET_VALUES
= 6
436 int count
; /* For kind == MOD_KIND_COUNT */
437 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
438 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
439 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
441 gboolean caught
, uncaught
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
450 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
454 * Describes a single step request.
458 MonoInternalThread
*thread
;
463 MonoMethod
*last_method
;
465 /* Whenever single stepping is performed using start/stop_single_stepping () */
467 /* The list of breakpoints used to implement step-over */
472 * Contains additional information for an event
475 /* For EVENT_KIND_EXCEPTION */
477 MonoContext catch_ctx
;
481 /* Dummy structure used for the profiler callbacks */
486 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
492 static AgentConfig agent_config
;
495 * Whenever the agent is fully initialized.
496 * When using the onuncaught or onthrow options, only some parts of the agent are
497 * initialized on startup, and the full initialization which includes connection
498 * establishment and the startup of the agent thread is only done in response to
501 static gint32 inited
;
505 static int packet_id
= 0;
507 static int objref_id
= 0;
509 static int event_request_id
= 0;
511 static int frame_id
= 0;
513 static GPtrArray
*event_requests
;
515 static guint32 debugger_tls_id
;
517 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
519 /* Maps MonoInternalThread -> DebuggerTlsData */
520 static MonoGHashTable
*thread_to_tls
;
522 /* Maps tid -> MonoInternalThread */
523 static MonoGHashTable
*tid_to_thread
;
525 /* Maps tid -> MonoThread (not MonoInternalThread) */
526 static MonoGHashTable
*tid_to_thread_obj
;
528 static gsize debugger_thread_id
;
530 static HANDLE debugger_thread_handle
;
532 static int log_level
;
534 static FILE *log_file
;
536 /* Classes whose class load event has been sent */
537 static GHashTable
*loaded_classes
;
539 /* Assemblies whose assembly load event has no been sent yet */
540 static GPtrArray
*pending_assembly_loads
;
542 /* Types whose type load event has no been sent yet */
543 static GPtrArray
*pending_type_loads
;
545 /* Whenever the debugger thread has exited */
546 static gboolean debugger_thread_exited
;
548 /* Cond variable used to wait for debugger_thread_exited becoming true */
549 static mono_cond_t debugger_thread_exited_cond
;
551 /* Mutex for the cond var above */
552 static mono_mutex_t debugger_thread_exited_mutex
;
554 static DebuggerProfiler debugger_profiler
;
556 /* The single step request instance */
557 static SingleStepReq
*ss_req
= NULL
;
558 static gpointer ss_invoke_addr
= NULL
;
560 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
561 /* Number of single stepping operations in progress */
565 /* The protocol version of the client */
566 static int major_version
, minor_version
;
568 /* Whenever the variables above are set by the client */
569 static gboolean protocol_version_set
;
571 static void transport_connect (const char *host
, int port
);
573 static guint32 WINAPI
debugger_thread (void *arg
);
575 static void runtime_initialized (MonoProfiler
*prof
);
577 static void runtime_shutdown (MonoProfiler
*prof
);
579 static void thread_startup (MonoProfiler
*prof
, intptr_t tid
);
581 static void thread_end (MonoProfiler
*prof
, intptr_t tid
);
583 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
585 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
587 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
589 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
591 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
593 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
595 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
597 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
599 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
601 static void start_single_stepping (void);
603 static void stop_single_stepping (void);
605 static void suspend_current (void);
607 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
609 /* Submodule init/cleanup */
610 static void breakpoints_init (void);
611 static void breakpoints_cleanup (void);
613 static void objrefs_init (void);
614 static void objrefs_cleanup (void);
616 static void ids_init (void);
617 static void ids_cleanup (void);
619 static void suspend_init (void);
621 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
);
622 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
623 static void ss_destroy (SingleStepReq
*req
);
625 static void start_debugger_thread (void);
627 static void finish_agent_init (gboolean on_startup
);
630 parse_address (char *address
, char **host
, int *port
)
632 char *pos
= strchr (address
, ':');
634 if (pos
== NULL
|| pos
== address
)
637 *host
= g_malloc (pos
- address
+ 1);
638 strncpy (*host
, address
, pos
- address
);
639 (*host
) [pos
- address
] = '\0';
641 *port
= atoi (pos
+ 1);
649 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
650 fprintf (stderr
, "Available options:\n");
651 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
652 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
653 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
654 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
655 fprintf (stderr
, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
656 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
657 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
661 parse_flag (const char *option
, char *flag
)
663 if (!strcmp (flag
, "y"))
665 else if (!strcmp (flag
, "n"))
668 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
675 mono_debugger_agent_parse_options (char *options
)
681 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
682 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
686 agent_config
.enabled
= TRUE
;
687 agent_config
.suspend
= TRUE
;
688 agent_config
.server
= FALSE
;
690 args
= g_strsplit (options
, ",", -1);
691 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
694 if (strncmp (arg
, "transport=", 10) == 0) {
695 agent_config
.transport
= g_strdup (arg
+ 10);
696 } else if (strncmp (arg
, "address=", 8) == 0) {
697 agent_config
.address
= g_strdup (arg
+ 8);
698 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
699 agent_config
.log_level
= atoi (arg
+ 9);
700 } else if (strncmp (arg
, "logfile=", 8) == 0) {
701 agent_config
.log_file
= g_strdup (arg
+ 8);
702 } else if (strncmp (arg
, "suspend=", 8) == 0) {
703 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
704 } else if (strncmp (arg
, "server=", 7) == 0) {
705 agent_config
.server
= parse_flag ("server", arg
+ 7);
706 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
707 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
708 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
709 /* We support multiple onthrow= options */
710 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
711 } else if (strncmp (arg
, "onthrow", 7) == 0) {
712 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
713 } else if (strncmp (arg
, "help", 4) == 0) {
716 } else if (strncmp (arg
, "timeout=", 8) == 0) {
717 agent_config
.timeout
= atoi (arg
+ 8);
718 } else if (strncmp (arg
, "launch=", 7) == 0) {
719 agent_config
.launch
= g_strdup (arg
+ 7);
726 if (agent_config
.transport
== NULL
) {
727 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
730 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
731 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
735 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
736 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
740 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
741 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
747 mono_debugger_agent_init (void)
749 if (!agent_config
.enabled
)
752 /* Need to know whenever a thread has acquired the loader mutex */
753 mono_loader_lock_track_ownership (TRUE
);
755 event_requests
= g_ptr_array_new ();
757 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
758 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
760 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
761 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
762 mono_profiler_install_runtime_initialized (runtime_initialized
);
763 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
764 mono_profiler_install_thread (thread_startup
, thread_end
);
765 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
766 mono_profiler_install_jit_end (jit_end
);
767 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
769 debugger_tls_id
= TlsAlloc ();
771 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
772 MONO_GC_REGISTER_ROOT (thread_to_tls
);
774 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
775 MONO_GC_REGISTER_ROOT (tid_to_thread
);
777 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
778 MONO_GC_REGISTER_ROOT (tid_to_thread_obj
);
780 loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
781 pending_assembly_loads
= g_ptr_array_new ();
782 pending_type_loads
= g_ptr_array_new ();
784 log_level
= agent_config
.log_level
;
786 if (agent_config
.log_file
) {
787 log_file
= fopen (agent_config
.log_file
, "w+");
789 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
801 mini_get_debug_options ()->gen_seq_points
= TRUE
;
803 * This is needed because currently we don't handle liveness info.
805 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
807 /* This is needed because we can't set local variables in registers yet */
808 mono_disable_optimizations (MONO_OPT_LINEARS
);
810 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
811 finish_agent_init (TRUE
);
817 * Finish the initialization of the agent. This involves connecting the transport
818 * and starting the agent thread. This is either done at startup, or
819 * in response to some event like an unhandled exception.
822 finish_agent_init (gboolean on_startup
)
828 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
831 if (agent_config
.launch
) {
834 // FIXME: Generated address
835 // FIXME: Races with transport_connect ()
837 argv
[0] = agent_config
.launch
;
838 argv
[1] = agent_config
.transport
;
839 argv
[2] = agent_config
.address
;
842 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
844 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
849 if (agent_config
.address
) {
850 res
= parse_address (agent_config
.address
, &host
, &port
);
857 transport_connect (host
, port
);
860 /* Do some which is usually done after sending the VMStart () event */
861 vm_start_event_sent
= TRUE
;
862 start_debugger_thread ();
867 mono_debugger_agent_cleanup (void)
872 /* This will interrupt the agent thread */
873 /* Close the read part only so it can still send back replies */
875 shutdown (conn_fd
, SD_RECEIVE
);
877 shutdown (conn_fd
, SHUT_RD
);
881 * Wait for the thread to exit.
883 * If we continue with the shutdown without waiting for it, then the client might
884 * not receive an answer to its last command like a resume.
885 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
888 //WaitForSingleObject (debugger_thread_handle, INFINITE);
889 if (GetCurrentThreadId () != debugger_thread_id
) {
890 mono_mutex_lock (&debugger_thread_exited_mutex
);
891 if (!debugger_thread_exited
) {
893 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
894 mono_mutex_unlock (&debugger_thread_exited_mutex
);
896 mono_mutex_lock (&debugger_thread_exited_mutex
);
899 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
902 mono_mutex_unlock (&debugger_thread_exited_mutex
);
905 breakpoints_cleanup ();
910 shutdown (conn_fd
, SD_BOTH
);
912 shutdown (conn_fd
, SHUT_RDWR
);
915 mono_mutex_destroy (&debugger_thread_exited_mutex
);
916 mono_cond_destroy (&debugger_thread_exited_cond
);
922 * recv() + handle incomplete reads and EINTR
925 recv_length (int fd
, void *buf
, int len
, int flags
)
931 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
934 } while ((res
> 0 && total
< len
) || (res
== -1 && errno
== EINTR
));
940 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
943 transport_connect (const char *host
, int port
)
945 struct addrinfo hints
;
946 struct addrinfo
*result
, *rp
;
948 char port_string
[128];
949 char handshake_msg
[128];
955 sprintf (port_string
, "%d", port
);
957 mono_network_init ();
959 /* Obtain address(es) matching host/port */
961 memset (&hints
, 0, sizeof (struct addrinfo
));
962 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
963 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
965 hints
.ai_protocol
= 0; /* Any protocol */
967 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
969 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d: %s\n", host
, port
, gai_strerror (s
));
974 if (agent_config
.server
) {
975 /* Wait for a connection */
977 struct sockaddr_in addr
;
980 /* No address, generate one */
981 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
984 /* This will bind the socket to a random port */
985 res
= listen (sfd
, 16);
987 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno
));
991 addrlen
= sizeof (addr
);
992 memset (&addr
, 0, sizeof (addr
));
993 res
= getsockname (sfd
, &addr
, &addrlen
);
997 port
= ntohs (addr
.sin_port
);
999 /* Emit the address to stdout */
1000 /* FIXME: Should print another interface, not localhost */
1001 printf ("%s:%d\n", host
, port
);
1003 /* Listen on the provided address */
1004 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1005 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1010 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1014 res
= listen (sfd
, 16);
1022 * this function is not present on win2000 which we still support, and the
1023 * workaround described here:
1024 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1025 * only works with MSVC.
1027 freeaddrinfo (result
);
1031 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1033 if (agent_config
.timeout
) {
1038 tv
.tv_usec
= agent_config
.timeout
* 1000;
1040 FD_SET (sfd
, &readfds
);
1041 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1043 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1048 conn_fd
= accept (sfd
, NULL
, NULL
);
1049 if (conn_fd
== -1) {
1050 fprintf (stderr
, "debugger-agent: Unable to listen on %s:%d\n", host
, port
);
1054 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1056 /* Connect to the specified address */
1057 /* FIXME: Respect the timeout */
1058 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1059 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1064 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1065 break; /* Success */
1073 /* See the comment above */
1074 freeaddrinfo (result
);
1078 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1083 /* Write handshake message */
1084 sprintf (handshake_msg
, "DWP-Handshake");
1086 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1087 } while (res
== -1 && errno
== EINTR
);
1088 g_assert (res
!= -1);
1091 res
= recv_length (conn_fd
, buf
, strlen (handshake_msg
), 0);
1092 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1093 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1098 * To support older clients, the client sends its protocol version after connecting
1099 * using a command. Until that is received, default to our protocol version.
1101 major_version
= MAJOR_VERSION
;
1102 minor_version
= MINOR_VERSION
;
1103 protocol_version_set
= FALSE
;
1106 * Set TCP_NODELAY on the socket so the client receives events/command
1107 * results immediately.
1111 int result
= setsockopt(conn_fd
,
1116 g_assert (result
>= 0);
1121 transport_send (guint8
*data
, int len
)
1126 res
= send (conn_fd
, data
, len
, 0);
1127 } while (res
== -1 && errno
== EINTR
);
1135 start_debugger_thread (void)
1139 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1140 g_assert (debugger_thread_handle
);
1144 * Functions to decode protocol data
1148 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1151 g_assert (*endbuf
<= limit
);
1156 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1159 g_assert (*endbuf
<= limit
);
1161 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1164 static inline gint64
1165 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1167 guint32 high
= decode_int (buf
, &buf
, limit
);
1168 guint32 low
= decode_int (buf
, &buf
, limit
);
1172 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1176 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1178 return decode_int (buf
, endbuf
, limit
);
1182 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1184 int len
= decode_int (buf
, &buf
, limit
);
1187 s
= g_malloc (len
+ 1);
1190 memcpy (s
, buf
, len
);
1199 * Functions to encode protocol data
1203 guint8
*buf
, *p
, *end
;
1207 buffer_init (Buffer
*buf
, int size
)
1209 buf
->buf
= g_malloc (size
);
1211 buf
->end
= buf
->buf
+ size
;
1215 buffer_make_room (Buffer
*buf
, int size
)
1217 if (buf
->end
- buf
->p
< size
) {
1218 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1219 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1220 size
= buf
->p
- buf
->buf
;
1223 buf
->end
= buf
->buf
+ new_size
;
1228 buffer_add_byte (Buffer
*buf
, guint8 val
)
1230 buffer_make_room (buf
, 1);
1236 buffer_add_int (Buffer
*buf
, guint32 val
)
1238 buffer_make_room (buf
, 4);
1239 buf
->p
[0] = (val
>> 24) & 0xff;
1240 buf
->p
[1] = (val
>> 16) & 0xff;
1241 buf
->p
[2] = (val
>> 8) & 0xff;
1242 buf
->p
[3] = (val
>> 0) & 0xff;
1247 buffer_add_long (Buffer
*buf
, guint64 l
)
1249 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1250 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1254 buffer_add_id (Buffer
*buf
, int id
)
1256 buffer_add_int (buf
, (guint64
)id
);
1260 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1262 buffer_make_room (buf
, len
);
1263 memcpy (buf
->p
, data
, len
);
1268 buffer_add_string (Buffer
*buf
, const char *str
)
1273 buffer_add_int (buf
, 0);
1276 buffer_add_int (buf
, len
);
1277 buffer_add_data (buf
, (guint8
*)str
, len
);
1282 buffer_free (Buffer
*buf
)
1288 send_packet (int command_set
, int command
, Buffer
*data
)
1294 id
= InterlockedIncrement (&packet_id
);
1296 len
= data
->p
- data
->buf
+ 11;
1297 buffer_init (&buf
, len
);
1298 buffer_add_int (&buf
, len
);
1299 buffer_add_int (&buf
, id
);
1300 buffer_add_byte (&buf
, 0); /* flags */
1301 buffer_add_byte (&buf
, command_set
);
1302 buffer_add_byte (&buf
, command
);
1303 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1305 res
= transport_send (buf
.buf
, len
);
1313 send_reply_packet (int id
, int error
, Buffer
*data
)
1319 len
= data
->p
- data
->buf
+ 11;
1320 buffer_init (&buf
, len
);
1321 buffer_add_int (&buf
, len
);
1322 buffer_add_int (&buf
, id
);
1323 buffer_add_byte (&buf
, 0x80); /* flags */
1324 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1325 buffer_add_byte (&buf
, error
);
1326 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1328 res
= transport_send (buf
.buf
, len
);
1340 * Represents an object accessible by the debugger client.
1343 /* Unique id used in the wire protocol to refer to objects */
1346 * A weakref gc handle pointing to the object. The gc handle is used to
1347 * detect if the object was garbage collected.
1352 /* Maps objid -> ObjRef */
1353 static GHashTable
*objrefs
;
1356 free_objref (gpointer value
)
1360 mono_gchandle_free (o
->handle
);
1368 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1372 objrefs_cleanup (void)
1374 g_hash_table_destroy (objrefs
);
1378 static GHashTable
*obj_to_objref
;
1381 * Return an ObjRef for OBJ.
1384 get_objref (MonoObject
*obj
)
1395 /* Use a hash table with masked pointers to internalize object references */
1396 /* FIXME: This can grow indefinitely */
1397 mono_loader_lock ();
1400 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1402 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1403 /* ref might refer to a different object with the same addr which was GCd */
1404 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1405 mono_loader_unlock ();
1409 ref
= g_new0 (ObjRef
, 1);
1410 ref
->id
= InterlockedIncrement (&objref_id
);
1411 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1413 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1414 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1416 mono_loader_unlock ();
1422 get_objid (MonoObject
*obj
)
1424 return get_objref (obj
)->id
;
1428 * Set OBJ to the object identified by OBJID.
1429 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1433 get_object_allow_null (int objid
, MonoObject
**obj
)
1443 return ERR_INVALID_OBJECT
;
1445 mono_loader_lock ();
1447 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1450 *obj
= mono_gchandle_get_target (ref
->handle
);
1451 mono_loader_unlock ();
1453 return ERR_INVALID_OBJECT
;
1456 mono_loader_unlock ();
1457 return ERR_INVALID_OBJECT
;
1462 get_object (int objid
, MonoObject
**obj
)
1464 int err
= get_object_allow_null (objid
, obj
);
1469 return ERR_INVALID_OBJECT
;
1474 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1476 return decode_id (buf
, endbuf
, limit
);
1480 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1482 buffer_add_id (buf
, get_objid (o
));
1501 * Represents a runtime structure accessible to the debugger client
1504 /* Unique id used in the wire protocol */
1506 /* Domain of the runtime structure, NULL if the domain was unloaded */
1513 MonoAssembly
*assembly
;
1514 MonoClassField
*field
;
1516 MonoProperty
*property
;
1521 /* Maps runtime structure -> Id */
1522 GHashTable
*val_to_id
[ID_NUM
];
1526 static GPtrArray
*ids
[ID_NUM
];
1533 for (i
= 0; i
< ID_NUM
; ++i
)
1534 ids
[i
] = g_ptr_array_new ();
1542 for (i
= 0; i
< ID_NUM
; ++i
) {
1544 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1545 g_free (g_ptr_array_index (ids
[i
], j
));
1546 g_ptr_array_free (ids
[i
], TRUE
);
1553 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1555 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1559 for (i
= 0; i
< ID_NUM
; ++i
)
1560 if (info
->val_to_id
[i
])
1561 g_hash_table_destroy (info
->val_to_id
[i
]);
1565 domain_jit_info (domain
)->agent_info
= NULL
;
1567 /* Clear ids referencing structures in the domain */
1568 for (i
= 0; i
< ID_NUM
; ++i
) {
1570 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1571 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1572 if (id
->domain
== domain
)
1580 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1583 AgentDomainInfo
*info
;
1588 mono_loader_lock ();
1590 mono_domain_lock (domain
);
1592 if (!domain_jit_info (domain
)->agent_info
)
1593 domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1594 info
= domain_jit_info (domain
)->agent_info
;
1595 if (info
->val_to_id
[type
] == NULL
)
1596 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1598 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1600 mono_domain_unlock (domain
);
1601 mono_loader_unlock ();
1605 id
= g_new0 (Id
, 1);
1607 id
->id
= ids
[type
]->len
+ 1;
1608 id
->domain
= domain
;
1611 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1613 mono_domain_unlock (domain
);
1615 g_ptr_array_add (ids
[type
], id
);
1617 mono_loader_unlock ();
1622 static inline gpointer
1623 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1627 int id
= decode_id (buf
, endbuf
, limit
);
1636 // FIXME: error handling
1637 mono_loader_lock ();
1638 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1640 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1641 mono_loader_unlock ();
1643 if (res
->domain
== NULL
) {
1644 *err
= ERR_UNLOADED
;
1649 *domain
= res
->domain
;
1651 return res
->data
.val
;
1655 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1657 buffer_add_id (buf
, get_id (domain
, type
, val
));
1660 static inline MonoClass
*
1661 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1663 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1666 static inline MonoAssembly
*
1667 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1669 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1672 static inline MonoImage
*
1673 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1675 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1678 static inline MonoMethod
*
1679 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1681 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1684 static inline MonoClassField
*
1685 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1687 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1690 static inline MonoDomain
*
1691 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1693 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1696 static inline MonoProperty
*
1697 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1699 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1703 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1705 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1709 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1711 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1715 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1717 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1721 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1723 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1727 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1729 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1733 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1735 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1739 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1741 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1744 static void invoke_method (void);
1751 * save_thread_context:
1753 * Set CTX as the current threads context which is used for computing stack traces.
1754 * This function is signal-safe.
1757 save_thread_context (MonoContext
*ctx
)
1759 DebuggerTlsData
*tls
;
1761 tls
= TlsGetValue (debugger_tls_id
);
1765 memcpy (&tls
->ctx
, ctx
, sizeof (MonoContext
));
1767 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1768 MONO_INIT_CONTEXT_FROM_CURRENT (&tls
->ctx
);
1770 MONO_INIT_CONTEXT_FROM_FUNC (&tls
->ctx
, save_thread_context
);
1774 tls
->lmf
= mono_get_lmf ();
1775 tls
->domain
= mono_domain_get ();
1776 tls
->has_context
= TRUE
;
1779 /* The number of times the runtime is suspended */
1780 static gint32 suspend_count
;
1782 /* Number of threads suspended */
1784 * If this is equal to the size of thread_to_tls, the runtime is considered
1787 static gint32 threads_suspend_count
;
1789 static mono_mutex_t suspend_mutex
;
1791 /* Cond variable used to wait for suspend_count becoming 0 */
1792 static mono_cond_t suspend_cond
;
1794 /* Semaphore used to wait for a thread becoming suspended */
1795 static MonoSemType suspend_sem
;
1800 mono_mutex_init (&suspend_mutex
, NULL
);
1801 mono_cond_init (&suspend_cond
, NULL
);
1802 MONO_SEM_INIT (&suspend_sem
, 0);
1807 StackFrameInfo last_frame
;
1808 gboolean last_frame_set
;
1811 } GetLastFrameUserData
;
1814 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
1816 GetLastFrameUserData
*data
= user_data
;
1818 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
1821 if (!data
->last_frame_set
) {
1822 /* Store the last frame */
1823 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
1824 data
->last_frame_set
= TRUE
;
1827 /* Store the context/lmf for the frame above the last frame */
1828 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
1829 data
->lmf
= info
->lmf
;
1836 * mono_debugger_agent_thread_interrupt:
1838 * Called by the abort signal handler.
1839 * Should be signal safe.
1842 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
1844 DebuggerTlsData
*tls
;
1849 tls
= TlsGetValue (debugger_tls_id
);
1854 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1855 * guarantee the signal handler will be called that many times. Instead of tracking
1856 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1857 * has been requested that hasn't been handled yet, otherwise we can have threads
1858 * refuse to die when VM_EXIT is called
1860 #if defined(__APPLE__)
1861 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
1865 * We use interrupt_count to determine whenever this interrupt should be processed
1866 * by us or the normal interrupt processing code in the signal handler.
1867 * There is no race here with notify_thread (), since the signal is sent after
1868 * incrementing interrupt_count.
1870 if (tls
->interrupt_count
== 0)
1873 InterlockedDecrement (&tls
->interrupt_count
);
1876 // FIXME: Races when the thread leaves managed code before hitting a single step
1880 /* Running managed code, will be suspended by the single step code */
1881 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
1885 * Running native code, will be suspended when it returns to/enters
1886 * managed code. Treat it as already suspended.
1887 * This might interrupt the code in process_single_step_inner (), we use the
1888 * tls->suspending flag to avoid races when that happens.
1890 if (!tls
->suspended
&& !tls
->suspending
) {
1892 GetLastFrameUserData data
;
1894 // FIXME: printf is not signal safe, but this is only used during
1895 // debugger debugging
1896 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
1897 //save_thread_context (&ctx);
1900 /* Already terminated */
1904 * We are in a difficult position: we want to be able to provide stack
1905 * traces for this thread, but we can't use the current ctx+lmf, since
1906 * the thread is still running, so it might return to managed code,
1907 * making these invalid.
1908 * So we start a stack walk and save the first frame, along with the
1909 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1910 * suspended when it returns to managed code, so the parent's ctx should
1913 data
.last_frame_set
= FALSE
;
1915 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1916 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame
, mono_domain_get (), &ctx
, FALSE
, tls
->thread
, mono_get_lmf (), &data
);
1918 if (data
.last_frame_set
) {
1919 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
1920 memcpy (&tls
->async_ctx
, &data
.ctx
, sizeof (MonoContext
));
1921 tls
->async_lmf
= data
.lmf
;
1922 tls
->has_async_ctx
= TRUE
;
1923 tls
->domain
= mono_domain_get ();
1924 memcpy (&tls
->ctx
, &ctx
, sizeof (MonoContext
));
1926 tls
->has_async_ctx
= FALSE
;
1929 mono_memory_barrier ();
1931 tls
->suspended
= TRUE
;
1932 MONO_SEM_POST (&suspend_sem
);
1939 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
1942 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
1944 #endif /* HOST_WIN32 */
1947 * reset_native_thread_suspend_state:
1949 * Reset the suspended flag on native threads
1952 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
1954 DebuggerTlsData
*tls
= value
;
1956 if (!tls
->really_suspended
&& tls
->suspended
)
1957 tls
->suspended
= FALSE
;
1963 * Notify a thread that it needs to suspend.
1966 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
1968 MonoInternalThread
*thread
= key
;
1969 DebuggerTlsData
*tls
= value
;
1970 gsize tid
= thread
->tid
;
1972 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
1975 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
1978 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1979 * guarantee the signal handler will be called that many times. Instead of tracking
1980 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1981 * has been requested that hasn't been handled yet, otherwise we can have threads
1982 * refuse to die when VM_EXIT is called
1984 #if defined(__APPLE__)
1985 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
1989 * Maybe we could use the normal interrupt infrastructure, but that does a lot
1990 * of things like breaking waits etc. which we don't want.
1992 InterlockedIncrement (&tls
->interrupt_count
);
1995 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
1997 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
1999 pthread_kill ((pthread_t
) tid
, mono_thread_get_abort_signal ());
2004 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2006 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2009 if (debugger_thread_id
== GetCurrentThreadId ())
2012 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2013 if (suspend_count
- tls
->resume_count
> 0)
2014 tls
->suspending
= TRUE
;
2016 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2018 if (suspend_count
- tls
->resume_count
== 0) {
2020 * We are executing a single threaded invoke but the single step for
2021 * suspending is still active.
2022 * FIXME: This slows down single threaded invokes.
2024 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2028 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2030 /* Can't suspend in these methods */
2031 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
2034 save_thread_context (ctx
);
2042 * Increase the suspend count of the VM. While the suspend count is greater
2043 * than 0, runtime threads are suspended at certain points during execution.
2048 mono_loader_lock ();
2050 mono_mutex_lock (&suspend_mutex
);
2054 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2056 if (suspend_count
== 1) {
2057 // FIXME: Is it safe to call this inside the lock ?
2058 start_single_stepping ();
2059 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2062 mono_mutex_unlock (&suspend_mutex
);
2064 mono_loader_unlock ();
2070 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2078 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2080 mono_loader_lock ();
2082 mono_mutex_lock (&suspend_mutex
);
2084 g_assert (suspend_count
> 0);
2087 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2089 if (suspend_count
== 0) {
2090 // FIXME: Is it safe to call this inside the lock ?
2091 stop_single_stepping ();
2092 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2095 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2096 err
= mono_cond_broadcast (&suspend_cond
);
2097 g_assert (err
== 0);
2099 mono_mutex_unlock (&suspend_mutex
);
2100 //g_assert (err == 0);
2102 mono_loader_unlock ();
2108 * Resume just one thread.
2111 resume_thread (MonoInternalThread
*thread
)
2114 DebuggerTlsData
*tls
;
2116 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2118 mono_loader_lock ();
2120 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2123 mono_mutex_lock (&suspend_mutex
);
2125 g_assert (suspend_count
> 0);
2127 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2129 tls
->resume_count
+= suspend_count
;
2132 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2133 * but only the one whose resume_count field is > 0 will be resumed.
2135 err
= mono_cond_broadcast (&suspend_cond
);
2136 g_assert (err
== 0);
2138 mono_mutex_unlock (&suspend_mutex
);
2139 //g_assert (err == 0);
2141 mono_loader_unlock ();
2145 invalidate_frames (DebuggerTlsData
*tls
)
2150 tls
= TlsGetValue (debugger_tls_id
);
2153 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2154 if (tls
->frames
[i
]->jit
)
2155 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2156 g_free (tls
->frames
[i
]);
2158 g_free (tls
->frames
);
2159 tls
->frame_count
= 0;
2166 * Suspend the current thread until the runtime is resumed. If the thread has a
2167 * pending invoke, then the invoke is executed before this function returns.
2170 suspend_current (void)
2173 DebuggerTlsData
*tls
;
2175 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2177 if (mono_loader_lock_is_owned_by_self ()) {
2179 * If we own the loader mutex, can't suspend until we release it, since the
2180 * whole runtime can deadlock otherwise.
2185 tls
= TlsGetValue (debugger_tls_id
);
2188 mono_mutex_lock (&suspend_mutex
);
2190 tls
->suspending
= FALSE
;
2191 tls
->really_suspended
= TRUE
;
2193 if (!tls
->suspended
) {
2194 tls
->suspended
= TRUE
;
2195 MONO_SEM_POST (&suspend_sem
);
2198 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2200 while (suspend_count
- tls
->resume_count
> 0) {
2202 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2204 mono_mutex_unlock (&suspend_mutex
);
2206 mono_mutex_lock (&suspend_mutex
);
2212 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2213 g_assert (err
== 0);
2217 tls
->suspended
= FALSE
;
2218 tls
->really_suspended
= FALSE
;
2220 threads_suspend_count
--;
2222 mono_mutex_unlock (&suspend_mutex
);
2224 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2226 if (tls
->pending_invoke
) {
2227 /* Save the original context */
2228 tls
->pending_invoke
->has_ctx
= TRUE
;
2229 memcpy (&tls
->pending_invoke
->ctx
, &tls
->ctx
, sizeof (MonoContext
));
2234 /* The frame info becomes invalid after a resume */
2235 tls
->has_context
= FALSE
;
2236 tls
->has_async_ctx
= FALSE
;
2237 invalidate_frames (NULL
);
2241 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2243 DebuggerTlsData
*tls
= value
;
2245 if (!tls
->suspended
&& !tls
->terminated
)
2246 *(int*)user_data
= *(int*)user_data
+ 1;
2250 count_threads_to_wait_for (void)
2254 mono_loader_lock ();
2255 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2256 mono_loader_unlock ();
2264 * Wait until the runtime is completely suspended.
2267 wait_for_suspend (void)
2269 int nthreads
, nwait
, err
;
2270 gboolean waited
= FALSE
;
2272 // FIXME: Threads starting/stopping ?
2273 mono_loader_lock ();
2274 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2275 mono_loader_unlock ();
2278 nwait
= count_threads_to_wait_for ();
2280 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2281 err
= MONO_SEM_WAIT (&suspend_sem
);
2282 g_assert (err
== 0);
2290 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2296 * Return whenever the runtime is suspended.
2301 return count_threads_to_wait_for () == 0;
2305 * find_seq_point_for_native_offset:
2307 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2308 * should be the location of a sequence point.
2311 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2313 MonoSeqPointInfo
*seq_points
;
2316 mono_domain_lock (domain
);
2317 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2318 mono_domain_unlock (domain
);
2319 g_assert (seq_points
);
2323 for (i
= 0; i
< seq_points
->len
; ++i
) {
2324 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2325 return &seq_points
->seq_points
[i
];
2334 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2335 * should be the location of a sequence point.
2338 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2340 MonoSeqPointInfo
*seq_points
;
2343 mono_domain_lock (domain
);
2344 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2345 mono_domain_unlock (domain
);
2346 g_assert (seq_points
);
2350 for (i
= 0; i
< seq_points
->len
; ++i
) {
2351 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2352 return &seq_points
->seq_points
[i
];
2359 * compute_il_offset:
2361 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2362 * a location of a sequence point.
2363 * We use this function instead of mono_debug_il_offset_from_address () etc,
2364 * which doesn't seem to work in a lot of cases.
2367 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2369 MonoSeqPointInfo
*seq_points
;
2370 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2372 mono_domain_lock (domain
);
2373 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2374 mono_domain_unlock (domain
);
2375 g_assert (seq_points
);
2377 last_il_offset
= -1;
2379 /* Find the sequence point */
2380 for (i
= 0; i
< seq_points
->len
; ++i
) {
2381 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2382 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2384 if (seq_native_offset
> native_offset
)
2386 last_il_offset
= seq_il_offset
;
2389 return last_il_offset
;
2393 DebuggerTlsData
*tls
;
2395 } ComputeFramesUserData
;
2398 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2400 ComputeFramesUserData
*ud
= user_data
;
2404 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2405 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2406 /* Mark the last frame as an invoke frame */
2408 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2414 method
= info
->ji
->method
;
2416 method
= info
->method
;
2418 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2421 if (info
->il_offset
== -1) {
2422 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2423 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2426 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
));
2428 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2430 * mono_arch_find_jit_info () returns the context stored in the LMF for
2431 * native frames, but it should unwind once. This is why we have duplicate
2432 * frames on the stack sometimes.
2433 * !managed also seems to be set for dynamic methods.
2438 frame
= g_new0 (StackFrame
, 1);
2439 frame
->method
= method
;
2440 frame
->il_offset
= info
->il_offset
;
2443 frame
->has_ctx
= TRUE
;
2445 frame
->domain
= info
->domain
;
2447 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2453 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2455 ComputeFramesUserData user_data
;
2457 int i
, findex
, new_frame_count
;
2458 StackFrame
**new_frames
, *f
;
2460 // FIXME: Locking on tls
2461 if (tls
->frames
&& tls
->frames_up_to_date
)
2464 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2466 user_data
.tls
= tls
;
2467 user_data
.frames
= NULL
;
2468 if (tls
->terminated
) {
2469 tls
->frame_count
= 0;
2471 } if (!tls
->really_suspended
&& tls
->has_async_ctx
) {
2472 /* Have to use the state saved by the signal handler */
2473 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2474 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->async_ctx
, FALSE
, thread
, tls
->async_lmf
, &user_data
);
2475 } else if (tls
->has_context
) {
2476 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->ctx
, FALSE
, thread
, tls
->lmf
, &user_data
);
2479 tls
->frame_count
= 0;
2483 new_frame_count
= g_slist_length (user_data
.frames
);
2484 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2486 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2490 * Reuse the id for already existing stack frames, so invokes don't invalidate
2491 * the still valid stack frames.
2493 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2494 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2495 f
->id
= tls
->frames
[i
]->id
;
2500 if (i
>= tls
->frame_count
)
2501 f
->id
= InterlockedIncrement (&frame_id
);
2503 new_frames
[findex
++] = f
;
2506 g_slist_free (user_data
.frames
);
2508 invalidate_frames (tls
);
2510 tls
->frames
= new_frames
;
2511 tls
->frame_count
= new_frame_count
;
2512 tls
->frames_up_to_date
= TRUE
;
2520 * create_event_list:
2522 * Return a list of event request ids matching EVENT, starting from REQS, which
2523 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2525 * We return request ids, instead of requests, to simplify threading, since
2526 * requests could be deleted anytime when the loader lock is not held.
2527 * LOCKING: Assumes the loader lock is held.
2530 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
2533 GSList
*events
= NULL
;
2535 *suspend_policy
= SUSPEND_POLICY_NONE
;
2538 reqs
= event_requests
;
2543 for (i
= 0; i
< reqs
->len
; ++i
) {
2544 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2545 if (req
->event_kind
== event
) {
2546 gboolean filtered
= FALSE
;
2549 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2550 Modifier
*mod
= &req
->modifiers
[j
];
2552 if (mod
->kind
== MOD_KIND_COUNT
) {
2554 if (mod
->data
.count
> 0) {
2555 if (mod
->data
.count
> 0) {
2557 if (mod
->data
.count
== 0)
2561 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2562 if (mod
->data
.thread
!= mono_thread_internal_current ())
2564 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
2565 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
2567 if (ei
->caught
&& !mod
->caught
)
2569 if (!ei
->caught
&& !mod
->uncaught
)
2571 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2573 gboolean found
= FALSE
;
2574 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2577 for (k
= 0; assemblies
[k
]; ++k
)
2578 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2587 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2588 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2593 /* Send a VM START/DEATH event by default */
2594 if (event
== EVENT_KIND_VM_START
)
2595 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2596 if (event
== EVENT_KIND_VM_DEATH
)
2597 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2602 static G_GNUC_UNUSED
const char*
2603 event_to_string (EventKind event
)
2606 case EVENT_KIND_VM_START
: return "VM_START";
2607 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2608 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2609 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2610 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2611 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2612 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2613 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2614 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2615 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2616 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2617 case EVENT_KIND_STEP
: return "STEP";
2618 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
2619 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
2621 g_assert_not_reached ();
2628 * Send an event to the client, suspending the vm if needed.
2629 * LOCKING: Since this can suspend the calling thread, no locks should be held
2631 * The EVENTS list is freed by this function.
2634 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
2638 MonoDomain
*domain
= mono_domain_get ();
2644 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
)
2645 // FIXME: We miss those events
2648 if (vm_death_event_sent
)
2651 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
)
2660 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
2661 // FIXME: Send these with a NULL thread, don't suspend the current thread
2664 buffer_init (&buf
, 128);
2665 buffer_add_byte (&buf
, suspend_policy
);
2666 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
2668 for (l
= events
; l
; l
= l
->next
) {
2669 buffer_add_byte (&buf
, event
); // event kind
2670 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
2672 thread
= mono_thread_current ();
2674 if (event
== EVENT_KIND_VM_START
)
2676 else if (event
== EVENT_KIND_THREAD_START
)
2677 g_assert (mono_thread_internal_current () == arg
);
2679 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
2682 case EVENT_KIND_THREAD_START
:
2683 case EVENT_KIND_THREAD_DEATH
:
2685 case EVENT_KIND_APPDOMAIN_CREATE
:
2686 case EVENT_KIND_APPDOMAIN_UNLOAD
:
2687 buffer_add_domainid (&buf
, arg
);
2689 case EVENT_KIND_METHOD_ENTRY
:
2690 case EVENT_KIND_METHOD_EXIT
:
2691 buffer_add_methodid (&buf
, domain
, arg
);
2693 case EVENT_KIND_ASSEMBLY_LOAD
:
2694 case EVENT_KIND_ASSEMBLY_UNLOAD
:
2695 buffer_add_assemblyid (&buf
, domain
, arg
);
2697 case EVENT_KIND_TYPE_LOAD
:
2698 buffer_add_typeid (&buf
, domain
, arg
);
2700 case EVENT_KIND_BREAKPOINT
:
2701 case EVENT_KIND_STEP
:
2702 buffer_add_methodid (&buf
, domain
, arg
);
2703 buffer_add_long (&buf
, il_offset
);
2705 case EVENT_KIND_VM_START
:
2706 buffer_add_domainid (&buf
, mono_get_root_domain ());
2708 case EVENT_KIND_VM_DEATH
:
2710 case EVENT_KIND_EXCEPTION
: {
2711 EventInfo
*ei
= arg
;
2712 buffer_add_objid (&buf
, ei
->exc
);
2716 g_assert_not_reached ();
2720 if (event
== EVENT_KIND_VM_START
) {
2721 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
2722 start_debugger_thread ();
2725 if (event
== EVENT_KIND_VM_DEATH
) {
2726 vm_death_event_sent
= TRUE
;
2728 suspend_policy
= SUSPEND_POLICY_NONE
;
2731 if (mono_runtime_is_shutting_down ())
2732 suspend_policy
= SUSPEND_POLICY_NONE
;
2734 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
2736 * Save the thread context and start suspending before sending the packet,
2737 * since we could be receiving the resume request before send_packet ()
2740 save_thread_context (ctx
);
2744 send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
2746 g_slist_free (events
);
2749 if (event
== EVENT_KIND_VM_START
)
2750 vm_start_event_sent
= TRUE
;
2752 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
2756 switch (suspend_policy
) {
2757 case SUSPEND_POLICY_NONE
:
2759 case SUSPEND_POLICY_ALL
:
2762 case SUSPEND_POLICY_EVENT_THREAD
:
2766 g_assert_not_reached ();
2771 process_profiler_event (EventKind event
, gpointer arg
)
2776 mono_loader_lock ();
2777 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
2778 mono_loader_unlock ();
2780 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
2784 runtime_initialized (MonoProfiler
*prof
)
2786 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
2790 runtime_shutdown (MonoProfiler
*prof
)
2792 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
2794 mono_debugger_agent_cleanup ();
2798 thread_startup (MonoProfiler
*prof
, intptr_t tid
)
2800 MonoInternalThread
*thread
= mono_thread_internal_current ();
2801 MonoInternalThread
*old_thread
;
2802 DebuggerTlsData
*tls
;
2804 if (tid
== debugger_thread_id
)
2807 g_assert (thread
->tid
== tid
);
2809 mono_loader_lock ();
2810 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2811 mono_loader_unlock ();
2813 if (thread
== old_thread
) {
2815 * For some reason, thread_startup () might be called for the same thread
2816 * multiple times (attach ?).
2818 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
2822 * thread_end () might not be called for some threads, and the tid could
2825 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
2826 mono_loader_lock ();
2827 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
2828 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
2829 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2830 mono_loader_unlock ();
2834 tls
= TlsGetValue (debugger_tls_id
);
2836 // FIXME: Free this somewhere
2837 tls
= g_new0 (DebuggerTlsData
, 1);
2838 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2839 MONO_GC_REGISTER_ROOT (tls
->thread
);
2840 tls
->thread
= thread
;
2841 TlsSetValue (debugger_tls_id
, tls
);
2843 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2845 mono_loader_lock ();
2846 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
2847 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
2848 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
2849 mono_loader_unlock ();
2851 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
2854 * suspend_vm () could have missed this thread, so wait for a resume.
2860 thread_end (MonoProfiler
*prof
, intptr_t tid
)
2862 MonoInternalThread
*thread
;
2863 DebuggerTlsData
*tls
= NULL
;
2865 mono_loader_lock ();
2866 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2868 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2869 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2870 tls
->terminated
= TRUE
;
2871 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2872 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2873 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
2876 mono_loader_unlock ();
2878 /* We might be called for threads started before we registered the start callback */
2880 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2881 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
2886 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
2888 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
2892 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
2894 /* Invalidate each thread's frame stack */
2895 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
2896 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
2900 * invalidate_each_thread:
2902 * A GHFunc to invalidate frames.
2903 * value must be a DebuggerTlsData*
2906 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
2908 invalidate_frames (value
);
2912 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
2914 /* Sent later in jit_end () */
2915 mono_loader_lock ();
2916 g_ptr_array_add (pending_assembly_loads
, assembly
);
2917 mono_loader_unlock ();
2921 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
2923 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
2925 clear_event_requests_for_assembly (assembly
);
2929 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2931 #if defined(HOST_WIN32) && !defined(__GNUC__)
2932 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2934 gpointer stackptr
= __builtin_frame_address (1);
2936 MonoInternalThread
*thread
= mono_thread_internal_current ();
2937 DebuggerTlsData
*tls
;
2939 mono_loader_lock ();
2941 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2942 /* Could be the debugger thread with assembly/type load hooks */
2944 tls
->invoke_addr
= stackptr
;
2946 mono_loader_unlock ();
2950 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2953 #if defined(HOST_WIN32) && !defined(__GNUC__)
2954 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2956 gpointer stackptr
= __builtin_frame_address (1);
2959 if (ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
2963 * We need to stop single stepping when exiting a runtime invoke, since if it is
2964 * a step out, it may return to native code, and thus never end.
2966 mono_loader_lock ();
2967 ss_invoke_addr
= NULL
;
2969 for (i
= 0; i
< event_requests
->len
; ++i
) {
2970 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
2972 if (req
->event_kind
== EVENT_KIND_STEP
) {
2973 ss_destroy (req
->info
);
2974 g_ptr_array_remove_index_fast (event_requests
, i
);
2979 mono_loader_unlock ();
2983 send_type_load (MonoClass
*klass
)
2985 gboolean type_load
= FALSE
;
2987 mono_loader_lock ();
2988 if (!g_hash_table_lookup (loaded_classes
, klass
)) {
2990 g_hash_table_insert (loaded_classes
, klass
, klass
);
2992 mono_loader_unlock ();
2994 process_profiler_event (EVENT_KIND_TYPE_LOAD
, klass
);
2998 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
3001 * We emit type load events when the first method of the type is JITted,
3002 * since the class load profiler callbacks might be called with the
3003 * loader lock held. They could also occur in the debugger thread.
3004 * Same for assembly load events.
3007 MonoAssembly
*assembly
= NULL
;
3009 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
3010 mono_loader_lock ();
3011 if (pending_assembly_loads
->len
> 0) {
3012 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
3013 g_ptr_array_remove_index (pending_assembly_loads
, 0);
3015 mono_loader_unlock ();
3018 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
3023 if (!vm_start_event_sent
) {
3024 /* Save these so they can be sent after the vm start event */
3025 mono_loader_lock ();
3026 g_ptr_array_add (pending_type_loads
, method
->klass
);
3027 mono_loader_unlock ();
3029 /* Send all pending type load events */
3033 mono_loader_lock ();
3034 if (pending_type_loads
->len
> 0) {
3035 klass
= g_ptr_array_index (pending_type_loads
, 0);
3036 g_ptr_array_remove_index (pending_type_loads
, 0);
3038 mono_loader_unlock ();
3040 send_type_load (klass
);
3045 send_type_load (method
->klass
);
3049 add_pending_breakpoints (method
, jinfo
);
3053 * BREAKPOINTS/SINGLE STEPPING
3057 * Contains information about an inserted breakpoint.
3060 long il_offset
, native_offset
;
3063 } BreakpointInstance
;
3066 * Contains generic information about a breakpoint.
3070 * The method where the breakpoint is placed. Can be NULL in which case it
3071 * is inserted into every method. This is used to implement method entry/
3072 * exit events. Can be a generic method definition, in which case the
3073 * breakpoint is inserted into every instance.
3079 * A list of BreakpointInstance structures describing where the breakpoint
3080 * was inserted. There could be more than one because of
3081 * generics/appdomains/method entry/exit.
3083 GPtrArray
*children
;
3086 /* List of breakpoints */
3087 static GPtrArray
*breakpoints
;
3088 /* Maps breakpoint locations to the number of breakpoints at that location */
3089 static GHashTable
*bp_locs
;
3092 breakpoints_init (void)
3094 breakpoints
= g_ptr_array_new ();
3095 bp_locs
= g_hash_table_new (NULL
, NULL
);
3099 breakpoints_cleanup (void)
3103 mono_loader_lock ();
3105 for (i
= 0; i
< breakpoints
->len
; ++i
)
3106 g_free (g_ptr_array_index (breakpoints
, i
));
3108 g_ptr_array_free (breakpoints
, TRUE
);
3109 g_hash_table_destroy (bp_locs
);
3111 mono_loader_unlock ();
3115 * insert_breakpoint:
3117 * Insert the breakpoint described by BP into the method described by
3121 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
)
3124 gint32 il_offset
= -1, native_offset
;
3125 BreakpointInstance
*inst
;
3128 for (i
= 0; i
< seq_points
->len
; ++i
) {
3129 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3130 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3132 if (il_offset
== bp
->il_offset
)
3136 if (i
== seq_points
->len
)
3137 /* Have to handle this somehow */
3140 inst
= g_new0 (BreakpointInstance
, 1);
3141 inst
->native_offset
= native_offset
;
3142 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3145 mono_loader_lock ();
3147 g_ptr_array_add (bp
->children
, inst
);
3149 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3150 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3151 mono_loader_unlock ();
3154 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3155 mono_arch_set_breakpoint (ji
, inst
->ip
);
3161 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji
->method
, TRUE
), (int)il_offset
));
3165 remove_breakpoint (BreakpointInstance
*inst
)
3167 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3169 MonoJitInfo
*ji
= inst
->ji
;
3170 guint8
*ip
= inst
->ip
;
3172 mono_loader_lock ();
3173 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3174 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3175 mono_loader_unlock ();
3177 g_assert (count
> 0);
3180 mono_arch_clear_breakpoint (ji
, ip
);
3187 static inline gboolean
3188 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
3190 return (!bp
->method
|| method
== bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
));
3194 * add_pending_breakpoints:
3196 * Insert pending breakpoints into the newly JITted method METHOD.
3199 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3202 MonoSeqPointInfo
*seq_points
;
3208 domain
= mono_domain_get ();
3210 mono_loader_lock ();
3212 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3213 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3214 gboolean found
= FALSE
;
3216 if (!bp_matches_method (bp
, method
))
3219 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3220 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3227 mono_domain_lock (domain
);
3228 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3229 mono_domain_unlock (domain
);
3231 /* Could be AOT code */
3233 g_assert (seq_points
);
3235 insert_breakpoint (seq_points
, ji
, bp
);
3239 mono_loader_unlock ();
3243 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
)
3248 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3250 /* Might be AOTed code */
3251 code
= mono_aot_get_method (domain
, method
);
3253 ji
= mono_jit_info_table_find (domain
, code
);
3258 insert_breakpoint (seq_points
, ji
, bp
);
3262 set_bp_in_method_cb (gpointer key
, gpointer value
, gpointer user_data
)
3264 MonoMethod
*method
= key
;
3265 MonoSeqPointInfo
*seq_points
= value
;
3266 MonoBreakpoint
*bp
= user_data
;
3267 MonoDomain
*domain
= mono_domain_get ();
3269 if (bp_matches_method (bp
, method
))
3270 set_bp_in_method (domain
, method
, seq_points
, bp
);
3276 * Set a breakpoint at IL_OFFSET in METHOD.
3277 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3278 * METHOD can also be a generic method definition, in which case a breakpoint
3279 * is placed in all instances of the method.
3281 static MonoBreakpoint
*
3282 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
)
3288 // - suspend/resume the vm to prevent code patching problems
3289 // - multiple breakpoints on the same location
3290 // - dynamic methods
3293 bp
= g_new0 (MonoBreakpoint
, 1);
3294 bp
->method
= method
;
3295 bp
->il_offset
= il_offset
;
3297 bp
->children
= g_ptr_array_new ();
3299 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
));
3301 domain
= mono_domain_get ();
3302 mono_domain_lock (domain
);
3303 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, bp
);
3304 mono_domain_unlock (domain
);
3306 mono_loader_lock ();
3307 g_ptr_array_add (breakpoints
, bp
);
3308 mono_loader_unlock ();
3314 clear_breakpoint (MonoBreakpoint
*bp
)
3318 // FIXME: locking, races
3319 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3320 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3322 remove_breakpoint (inst
);
3327 mono_loader_lock ();
3328 g_ptr_array_remove (breakpoints
, bp
);
3329 mono_loader_unlock ();
3331 g_ptr_array_free (bp
->children
, TRUE
);
3336 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
3338 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
3342 process_breakpoint_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3345 guint8
*orig_ip
, *ip
;
3346 int i
, j
, suspend_policy
;
3347 guint32 native_offset
;
3349 BreakpointInstance
*inst
;
3350 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3351 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3352 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3354 // FIXME: Speed this up
3356 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3357 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3359 g_assert (ji
->method
);
3361 /* Compute the native offset of the breakpoint from the ip */
3362 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3363 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3364 native_offset
= ip
- (guint8
*)ji
->code_start
;
3370 * Skip the instruction causing the breakpoint signal.
3372 mono_arch_skip_breakpoint (ctx
);
3374 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3377 bp_reqs
= g_ptr_array_new ();
3378 ss_reqs
= g_ptr_array_new ();
3379 ss_reqs_orig
= g_ptr_array_new ();
3381 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3383 mono_loader_lock ();
3386 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3387 bp
= g_ptr_array_index (breakpoints
, i
);
3392 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3393 inst
= g_ptr_array_index (bp
->children
, j
);
3394 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3395 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3396 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3398 g_ptr_array_add (bp_reqs
, bp
->req
);
3403 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3404 MonoSeqPointInfo
*seq_points
;
3405 int seq_il_offset
, seq_native_offset
;
3406 MonoDomain
*domain
= mono_domain_get ();
3408 /* Maybe a method entry/exit event */
3409 mono_domain_lock (domain
);
3410 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3411 mono_domain_unlock (domain
);
3413 // FIXME: Generic sharing */
3414 mono_loader_unlock ();
3417 g_assert (seq_points
);
3419 for (i
= 0; i
< seq_points
->len
; ++i
) {
3420 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3421 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3423 if (native_offset
== seq_native_offset
) {
3424 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3425 kind
= EVENT_KIND_METHOD_ENTRY
;
3426 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3427 kind
= EVENT_KIND_METHOD_EXIT
;
3433 /* Process single step requests */
3434 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3435 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3436 SingleStepReq
*ss_req
= bp
->req
->info
;
3437 gboolean hit
= TRUE
;
3438 MonoSeqPointInfo
*info
;
3441 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3444 if (ss_req
->size
== STEP_SIZE_LINE
) {
3445 /* Have to check whenever a different source line was reached */
3446 MonoDebugMethodInfo
*minfo
;
3447 MonoDebugSourceLocation
*loc
= NULL
;
3449 minfo
= mono_debug_lookup_method (ji
->method
);
3452 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3454 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3455 /* Have to continue single stepping */
3459 ss_req
->last_method
= ji
->method
;
3460 ss_req
->last_line
= loc
->row
;
3461 mono_debug_free_source_location (loc
);
3466 g_ptr_array_add (ss_reqs
, req
);
3468 /* Start single stepping again from the current sequence point */
3469 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
);
3472 if (ss_reqs
->len
> 0)
3473 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
3474 if (bp_reqs
->len
> 0)
3475 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
3476 if (kind
!= EVENT_KIND_BREAKPOINT
)
3477 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
3479 mono_loader_unlock ();
3481 g_ptr_array_free (bp_reqs
, TRUE
);
3482 g_ptr_array_free (ss_reqs
, TRUE
);
3485 * FIXME: The first event will suspend, so the second will only be sent after the
3489 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
3491 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
3492 if (enter_leave_events
)
3493 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
3497 process_breakpoint (void)
3499 DebuggerTlsData
*tls
;
3501 static void (*restore_context
) (void *);
3503 if (!restore_context
)
3504 restore_context
= mono_get_restore_context ();
3506 tls
= TlsGetValue (debugger_tls_id
);
3507 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3509 process_breakpoint_inner (tls
, &ctx
);
3511 /* This is called when resuming from a signal handler, so it shouldn't return */
3512 restore_context (&ctx
);
3513 g_assert_not_reached ();
3517 resume_from_signal_handler (void *sigctx
, void *func
)
3519 DebuggerTlsData
*tls
;
3522 /* Save the original context in TLS */
3523 // FIXME: This might not work on an altstack ?
3524 tls
= TlsGetValue (debugger_tls_id
);
3527 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3528 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3529 // clob:c could be added to op_seq_point.
3531 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3532 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
3533 MONO_CONTEXT_SET_IP (&ctx
, func
);
3534 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3536 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3537 mono_ppc_set_func_into_sigctx (sigctx
, func
);
3542 mono_debugger_agent_breakpoint_hit (void *sigctx
)
3545 * We are called from a signal handler, and running code there causes all kinds of
3546 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3547 * So set up the signal context to return to the real breakpoint handler function.
3550 resume_from_signal_handler (sigctx
, process_breakpoint
);
3554 process_single_step_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3559 int il_offset
, suspend_policy
;
3563 // FIXME: Speed this up
3565 ip
= MONO_CONTEXT_GET_IP (ctx
);
3567 /* Skip the instruction causing the single step */
3568 mono_arch_skip_single_step (ctx
);
3570 if (suspend_count
> 0) {
3571 process_suspend (tls
, ctx
);
3576 // FIXME: A suspend race
3579 if (mono_thread_internal_current () != ss_req
->thread
)
3582 if (log_level
> 0) {
3583 const char *depth
= NULL
;
3585 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3587 switch (ss_req
->depth
) {
3588 case STEP_DEPTH_OVER
:
3591 case STEP_DEPTH_OUT
:
3594 case STEP_DEPTH_INTO
:
3598 g_assert_not_reached ();
3601 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
));
3605 * We implement step over/out by single stepping until we reach the same
3606 * frame/parent frame.
3609 * - stack growing upward
3613 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
3614 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
3616 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
3619 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
3622 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3624 g_assert (ji
->method
);
3626 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
3631 * Stopping in memset makes half-initialized vtypes visible.
3632 * Stopping in memcpy makes half-copied vtypes visible.
3634 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
3638 * The ip points to the instruction causing the single step event, convert it
3639 * to the offset stored in seq_points.
3641 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3642 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
3644 g_assert_not_reached ();
3648 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3649 * example, so do things by hand.
3651 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
3653 if (il_offset
== -1)
3656 if (ss_req
->size
== STEP_SIZE_LINE
) {
3657 /* Step until a different source line is reached */
3658 MonoDebugMethodInfo
*minfo
;
3660 minfo
= mono_debug_lookup_method (ji
->method
);
3663 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
3665 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
3666 mono_debug_free_source_location (loc
);
3671 * Step until we reach a location with line number info,
3672 * otherwise the client can't show a location.
3673 * This can happen for example with statics initialized inline
3674 * outside of a cctor.
3679 ss_req
->last_method
= ji
->method
;
3680 ss_req
->last_line
= loc
->row
;
3681 mono_debug_free_source_location (loc
);
3686 // FIXME: Has to lock earlier
3688 reqs
= g_ptr_array_new ();
3690 mono_loader_lock ();
3692 g_ptr_array_add (reqs
, ss_req
->req
);
3694 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
3696 g_ptr_array_free (reqs
, TRUE
);
3698 mono_loader_unlock ();
3700 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
3704 process_single_step (void)
3706 DebuggerTlsData
*tls
;
3708 static void (*restore_context
) (void *);
3710 if (!restore_context
)
3711 restore_context
= mono_get_restore_context ();
3713 tls
= TlsGetValue (debugger_tls_id
);
3714 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3716 process_single_step_inner (tls
, &ctx
);
3718 /* This is called when resuming from a signal handler, so it shouldn't return */
3719 restore_context (&ctx
);
3720 g_assert_not_reached ();
3724 * mono_debugger_agent_single_step_event:
3726 * Called from a signal handler to handle a single step event.
3729 mono_debugger_agent_single_step_event (void *sigctx
)
3731 /* Resume to process_single_step through the signal context */
3733 // FIXME: Since step out/over is implemented using step in, the step in case should
3734 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3737 if (GetCurrentThreadId () == debugger_thread_id
) {
3739 * This could happen despite our best effors when the runtime calls
3740 * assembly/type resolve hooks.
3741 * FIXME: Breakpoints too.
3745 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3746 mono_arch_skip_single_step (&ctx
);
3747 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3751 resume_from_signal_handler (sigctx
, process_single_step
);
3755 * start_single_stepping:
3757 * Turn on single stepping. Can be called multiple times, for example,
3758 * by a single step event request + a suspend.
3761 start_single_stepping (void)
3763 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3764 int val
= InterlockedIncrement (&ss_count
);
3767 mono_arch_start_single_stepping ();
3769 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
3770 DebuggerTlsData
*tls
;
3772 mono_loader_lock ();
3774 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
3775 ss_invoke_addr
= tls
->invoke_addr
;
3777 mono_loader_unlock ();
3780 g_assert_not_reached ();
3785 stop_single_stepping (void)
3787 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3788 int val
= InterlockedDecrement (&ss_count
);
3791 mono_arch_stop_single_stepping ();
3793 g_assert_not_reached ();
3800 * Stop the single stepping operation given by SS_REQ.
3803 ss_stop (SingleStepReq
*ss_req
)
3805 gboolean use_bps
= FALSE
;
3812 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
3813 clear_breakpoint (l
->data
);
3815 g_slist_free (ss_req
->bps
);
3819 if (ss_req
->global
) {
3820 stop_single_stepping ();
3821 ss_req
->global
= FALSE
;
3828 * Start the single stepping operation given by SS_REQ from the sequence point SP.
3831 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
)
3833 gboolean use_bp
= FALSE
;
3838 /* Stop the previous operation */
3842 * Implement single stepping using breakpoints if possible.
3844 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3847 * Find the first sequence point in the current or in a previous frame which
3848 * is not the last in its method.
3850 while (sp
&& sp
->next_len
== 0) {
3852 if (tls
&& frame_index
< tls
->frame_count
) {
3853 StackFrame
*frame
= tls
->frames
[frame_index
];
3855 method
= frame
->method
;
3856 if (frame
->il_offset
!= -1) {
3857 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3863 if (sp
&& sp
->next_len
> 0) {
3865 for (i
= 0; i
< sp
->next_len
; ++i
) {
3866 next_sp
= &info
->seq_points
[sp
->next
[i
]];
3868 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
);
3869 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
3875 ss_req
->global
= TRUE
;
3876 start_single_stepping ();
3878 ss_req
->global
= FALSE
;
3883 * Start single stepping of thread THREAD
3886 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
3888 DebuggerTlsData
*tls
;
3889 MonoSeqPointInfo
*info
;
3890 SeqPoint
*sp
= NULL
;
3891 MonoMethod
*method
= NULL
;
3893 if (suspend_count
== 0)
3894 return ERR_NOT_SUSPENDED
;
3896 wait_for_suspend ();
3898 // FIXME: Multiple requests
3900 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
3901 return ERR_NOT_IMPLEMENTED
;
3904 ss_req
= g_new0 (SingleStepReq
, 1);
3906 ss_req
->thread
= thread
;
3907 ss_req
->size
= size
;
3908 ss_req
->depth
= depth
;
3911 mono_loader_lock ();
3912 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3913 mono_loader_unlock ();
3915 g_assert (tls
->has_context
);
3916 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->ctx
);
3918 if (ss_req
->size
== STEP_SIZE_LINE
) {
3920 MonoDebugMethodInfo
*minfo
;
3922 /* Compute the initial line info */
3923 compute_frame_info (thread
, tls
);
3925 g_assert (tls
->frame_count
);
3926 frame
= tls
->frames
[0];
3928 ss_req
->last_method
= frame
->method
;
3929 ss_req
->last_line
= -1;
3931 minfo
= mono_debug_lookup_method (frame
->method
);
3932 if (minfo
&& frame
->il_offset
!= -1) {
3933 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
3936 ss_req
->last_line
= loc
->row
;
3942 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3945 compute_frame_info (thread
, tls
);
3947 g_assert (tls
->frame_count
);
3948 frame
= tls
->frames
[0];
3950 if (frame
->il_offset
!= -1) {
3951 /* FIXME: Sort the table and use a binary search */
3952 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3954 method
= frame
->method
;
3958 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
);
3964 ss_destroy (SingleStepReq
*req
)
3967 g_assert (ss_req
== req
);
3976 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
3977 MonoContext
*catch_ctx
)
3984 if (thread_to_tls
!= NULL
) {
3985 MonoInternalThread
*thread
= mono_thread_internal_current ();
3986 DebuggerTlsData
*tls
;
3988 mono_loader_lock ();
3989 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3990 mono_loader_unlock ();
3992 if (tls
&& tls
->abort_requested
)
3996 memset (&ei
, 0, sizeof (EventInfo
));
3998 /* Just-In-Time debugging */
4000 if (agent_config
.onuncaught
&& !inited
) {
4001 finish_agent_init (FALSE
);
4004 * Send an unsolicited EXCEPTION event with a dummy request id.
4006 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4007 ei
.exc
= (MonoObject
*)exc
;
4008 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4011 } else if (agent_config
.onthrow
&& !inited
) {
4013 gboolean found
= FALSE
;
4015 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
4016 char *ex_type
= l
->data
;
4017 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
4019 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
4026 finish_agent_init (FALSE
);
4029 * Send an unsolicited EXCEPTION event with a dummy request id.
4031 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4032 ei
.exc
= (MonoObject
*)exc
;
4033 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4041 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
4043 ei
.exc
= (MonoObject
*)exc
;
4044 ei
.caught
= catch_ctx
!= NULL
;
4046 mono_loader_lock ();
4047 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
4048 mono_loader_unlock ();
4050 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
4054 * buffer_add_value_full:
4056 * Add the encoding of the value at ADDR described by T to the buffer.
4057 * AS_VTYPE determines whenever to treat primitive types as primitive types or
4061 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
4067 g_assert (*(void**)addr
);
4068 addr
= *(void**)addr
;
4073 case MONO_TYPE_BOOLEAN
:
4076 case MONO_TYPE_CHAR
:
4096 case MONO_TYPE_VOID
:
4097 buffer_add_byte (buf
, t
->type
);
4099 case MONO_TYPE_BOOLEAN
:
4102 buffer_add_byte (buf
, t
->type
);
4103 buffer_add_int (buf
, *(gint8
*)addr
);
4105 case MONO_TYPE_CHAR
:
4108 buffer_add_byte (buf
, t
->type
);
4109 buffer_add_int (buf
, *(gint16
*)addr
);
4114 buffer_add_byte (buf
, t
->type
);
4115 buffer_add_int (buf
, *(gint32
*)addr
);
4120 buffer_add_byte (buf
, t
->type
);
4121 buffer_add_long (buf
, *(gint64
*)addr
);
4125 /* Treat it as a vtype */
4127 case MONO_TYPE_PTR
: {
4128 gssize val
= *(gssize
*)addr
;
4130 buffer_add_byte (buf
, t
->type
);
4131 buffer_add_long (buf
, val
);
4135 case MONO_TYPE_STRING
:
4136 case MONO_TYPE_SZARRAY
:
4137 case MONO_TYPE_OBJECT
:
4138 case MONO_TYPE_CLASS
:
4139 case MONO_TYPE_ARRAY
:
4140 obj
= *(MonoObject
**)addr
;
4143 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4145 if (obj
->vtable
->klass
->valuetype
) {
4146 t
= &obj
->vtable
->klass
->byval_arg
;
4147 addr
= mono_object_unbox (obj
);
4149 } else if (obj
->vtable
->klass
->rank
) {
4150 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4151 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4152 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4154 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4156 buffer_add_objid (buf
, obj
);
4160 case MONO_TYPE_VALUETYPE
: {
4164 MonoClass
*klass
= mono_class_from_mono_type (t
);
4166 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4167 buffer_add_byte (buf
, klass
->enumtype
);
4168 buffer_add_typeid (buf
, domain
, klass
);
4172 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4173 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4175 if (mono_field_is_deleted (f
))
4179 buffer_add_int (buf
, nfields
);
4182 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4183 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4185 if (mono_field_is_deleted (f
))
4187 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4191 case MONO_TYPE_GENERICINST
:
4192 if (mono_type_generic_inst_is_valuetype (t
)) {
4204 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4206 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4210 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4213 int type
= decode_byte (buf
, &buf
, limit
);
4215 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4216 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4217 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4218 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4219 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4220 char *name
= mono_type_full_name (t
);
4221 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
4223 return ERR_INVALID_ARGUMENT
;
4227 case MONO_TYPE_BOOLEAN
:
4228 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4230 case MONO_TYPE_CHAR
:
4231 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4234 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4237 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4240 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4243 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4246 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4249 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4252 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4255 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4258 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4261 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4264 /* We send these as I8, so we get them back as such */
4265 g_assert (type
== MONO_TYPE_I8
);
4266 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4268 case MONO_TYPE_GENERICINST
:
4269 if (MONO_TYPE_ISSTRUCT (t
)) {
4270 /* The client sends these as a valuetype */
4278 /* We send these as vtypes, so we get them back as such */
4279 g_assert (type
== MONO_TYPE_VALUETYPE
);
4282 case MONO_TYPE_VALUETYPE
: {
4283 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
4287 gpointer iter
= NULL
;
4290 /* Enums are sent as a normal vtype */
4292 return ERR_NOT_IMPLEMENTED
;
4293 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
4297 if (klass
!= mono_class_from_mono_type (t
))
4298 return ERR_INVALID_ARGUMENT
;
4300 nfields
= decode_int (buf
, &buf
, limit
);
4301 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4302 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4304 if (mono_field_is_deleted (f
))
4306 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
4311 g_assert (nfields
== 0);
4316 if (MONO_TYPE_IS_REFERENCE (t
)) {
4317 if (type
== MONO_TYPE_OBJECT
) {
4318 int objid
= decode_objid (buf
, &buf
, limit
);
4322 err
= get_object (objid
, (MonoObject
**)&obj
);
4326 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
4327 return ERR_INVALID_ARGUMENT
;
4328 if (obj
&& obj
->vtable
->domain
!= domain
)
4329 return ERR_INVALID_ARGUMENT
;
4331 mono_gc_wbarrier_generic_store (addr
, obj
);
4332 } else if (type
== VALUE_TYPE_ID_NULL
) {
4333 *(MonoObject
**)addr
= NULL
;
4335 return ERR_INVALID_ARGUMENT
;
4349 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
4356 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4357 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4360 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4361 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
4363 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
4365 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4366 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4367 addr
+= (gint32
)var
->offset
;
4369 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4371 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
4373 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4377 g_assert_not_reached ();
4382 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
)
4388 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4389 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4391 if (MONO_TYPE_IS_REFERENCE (t
))
4392 size
= sizeof (gpointer
);
4394 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
4397 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4398 // FIXME: Can't set registers, so we disable linears
4401 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4402 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4403 addr
+= (gint32
)var
->offset
;
4405 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4407 // FIXME: Write barriers
4408 memcpy (addr
, val
, size
);
4410 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4414 g_assert_not_reached ();
4419 clear_event_request (int req_id
, int etype
)
4423 mono_loader_lock ();
4424 for (i
= 0; i
< event_requests
->len
; ++i
) {
4425 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4427 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
4428 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4429 clear_breakpoint (req
->info
);
4430 if (req
->event_kind
== EVENT_KIND_STEP
)
4431 ss_destroy (req
->info
);
4432 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
4433 clear_breakpoint (req
->info
);
4434 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
4435 clear_breakpoint (req
->info
);
4436 g_ptr_array_remove_index_fast (event_requests
, i
);
4441 mono_loader_unlock ();
4445 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
4447 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4448 return breakpoint_matches_assembly (req
->info
, assembly
);
4452 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
4453 Modifier
*m
= &req
->modifiers
[i
];
4455 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
4457 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
4458 for (j
= 0; m
->data
.assemblies
[j
]; ++j
)
4459 if (m
->data
.assemblies
[j
] == assembly
)
4469 * clear_event_requests_for_assembly:
4471 * Clear all events requests which reference ASSEMBLY.
4474 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
4479 mono_loader_lock ();
4483 for (i
= 0; i
< event_requests
->len
; ++i
) {
4484 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4486 if (event_req_matches_assembly (req
, assembly
)) {
4487 clear_event_request (req
->id
, req
->event_kind
);
4493 mono_loader_unlock ();
4497 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
4499 MonoInternalThread
*thread
= value
;
4500 Buffer
*buf
= user_data
;
4502 buffer_add_objid (buf
, (MonoObject
*)thread
);
4506 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
4508 guint8
*p
= invoke
->p
;
4509 guint8
*end
= invoke
->endp
;
4512 MonoMethodSignature
*sig
;
4515 MonoObject
*this, *res
, *exc
;
4518 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4522 if (invoke
->method
) {
4524 * Invoke this method directly, currently only Environment.Exit () is supported.
4527 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>"));
4528 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
4529 g_assert_not_reached ();
4532 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4535 sig
= mono_method_signature (m
);
4537 if (m
->klass
->valuetype
)
4538 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
4540 this_buf
= g_alloca (sizeof (MonoObject
*));
4541 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
4542 /* Should be null */
4543 int type
= decode_byte (p
, &p
, end
);
4544 if (type
!= VALUE_TYPE_ID_NULL
)
4545 return ERR_INVALID_ARGUMENT
;
4546 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
4548 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
4553 if (!m
->klass
->valuetype
)
4554 this = *(MonoObject
**)this_buf
;
4558 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>"));
4560 if (this && this->vtable
->domain
!= domain
)
4563 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
4564 if (!strcmp (m
->name
, ".ctor")) {
4565 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
4566 return ERR_INVALID_ARGUMENT
;
4568 this = mono_object_new (domain
, m
->klass
);
4570 return ERR_INVALID_ARGUMENT
;
4574 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
4575 return ERR_INVALID_ARGUMENT
;
4577 nargs
= decode_int (p
, &p
, end
);
4578 if (nargs
!= sig
->param_count
)
4579 return ERR_INVALID_ARGUMENT
;
4580 /* Use alloca to get gc tracking */
4581 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
4582 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
4583 args
= g_alloca (nargs
* sizeof (gpointer
));
4584 for (i
= 0; i
< nargs
; ++i
) {
4585 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
4586 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
4590 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
4593 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
4594 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
4597 args
[i
] = arg_buf
[i
];
4604 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
4605 tls
->disable_breakpoints
= TRUE
;
4607 tls
->disable_breakpoints
= FALSE
;
4610 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4612 /* FIXME: Move this to arch specific code */
4613 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4614 if (invoke
->has_ctx
) {
4617 lmf_addr
= mono_get_lmf_addr ();
4620 memset (&ext
, 0, sizeof (ext
));
4622 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4623 /* Mark that this is a MonoLMFExt */
4624 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4625 ext
.lmf
.rsp
= (gssize
)&ext
;
4626 #elif defined(TARGET_X86)
4627 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
4628 /* Mark that this is a MonoLMFExt */
4629 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4630 ext
.lmf
.ebp
= (gssize
)&ext
;
4631 #elif defined(TARGET_ARM)
4632 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4633 /* Mark that this is a MonoLMFExt */
4634 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4635 ext
.lmf
.ebp
= (gssize
)&ext
;
4636 #elif defined(TARGET_POWERPC)
4637 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4638 /* Mark that this is a MonoLMFExt */
4639 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4640 ext
.lmf
.ebp
= (gssize
)&ext
;
4642 g_assert_not_reached ();
4645 ext
.debugger_invoke
= TRUE
;
4646 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4648 mono_set_lmf ((MonoLMF
*)&ext
);
4652 if (m
->klass
->valuetype
)
4653 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
4655 res
= mono_runtime_invoke (m
, this, args
, &exc
);
4657 buffer_add_byte (buf
, 0);
4658 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
4660 buffer_add_byte (buf
, 1);
4661 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4662 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
4663 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
4666 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
4667 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
4668 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
4669 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
4671 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
4677 tls
->disable_breakpoints
= FALSE
;
4679 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4680 if (invoke
->has_ctx
)
4681 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
4684 // FIXME: byref arguments
4692 * Invoke the method given by tls->pending_invoke in the current thread.
4695 invoke_method (void)
4697 DebuggerTlsData
*tls
;
4702 static void (*restore_context
) (void *);
4703 MonoContext restore_ctx
;
4705 if (!restore_context
)
4706 restore_context
= mono_get_restore_context ();
4708 tls
= TlsGetValue (debugger_tls_id
);
4712 * Store the `InvokeData *' in `tls->invoke' until we're done with
4713 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
4716 mono_loader_lock ();
4718 invoke
= tls
->pending_invoke
;
4720 tls
->pending_invoke
= NULL
;
4722 invoke
->last_invoke
= tls
->invoke
;
4723 tls
->invoke
= invoke
;
4725 mono_loader_unlock ();
4727 tls
->frames_up_to_date
= FALSE
;
4731 buffer_init (&buf
, 128);
4733 err
= do_invoke_method (tls
, &buf
, invoke
);
4735 /* Start suspending before sending the reply */
4736 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
4739 send_reply_packet (id
, err
, &buf
);
4743 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4745 if (invoke
->has_ctx
)
4746 save_thread_context (&restore_ctx
);
4748 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
4749 g_assert (tls
->resume_count
);
4750 tls
->resume_count
-= invoke
->suspend_count
;
4753 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
4756 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
4758 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
4759 * after the mono_runtime_invoke() already returned, but it doesn't matter
4760 * because we reset the abort here.
4763 mono_loader_lock ();
4765 if (tls
->abort_requested
)
4766 mono_thread_internal_reset_abort (tls
->thread
);
4768 tls
->invoke
= tls
->invoke
->last_invoke
;
4769 tls
->abort_requested
= FALSE
;
4771 mono_loader_unlock ();
4780 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
4782 MonoThread
*thread
= value
;
4783 DebuggerTlsData
*tls
;
4786 mono_loader_lock ();
4787 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4789 res
= tls
->really_suspended
;
4790 mono_loader_unlock ();
4796 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4799 case CMD_VM_VERSION
: {
4800 char *build_info
, *version
;
4802 build_info
= mono_get_runtime_build_info ();
4803 version
= g_strdup_printf ("mono %s", build_info
);
4805 buffer_add_string (buf
, version
); /* vm version */
4806 buffer_add_int (buf
, MAJOR_VERSION
);
4807 buffer_add_int (buf
, MINOR_VERSION
);
4808 g_free (build_info
);
4812 case CMD_VM_SET_PROTOCOL_VERSION
: {
4813 major_version
= decode_int (p
, &p
, end
);
4814 minor_version
= decode_int (p
, &p
, end
);
4815 protocol_version_set
= TRUE
;
4816 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
4819 case CMD_VM_ALL_THREADS
: {
4821 mono_loader_lock ();
4822 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
4823 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
4824 mono_loader_unlock ();
4827 case CMD_VM_SUSPEND
:
4829 wait_for_suspend ();
4832 if (suspend_count
== 0)
4833 return ERR_NOT_SUSPENDED
;
4836 case CMD_VM_DISPOSE
:
4837 /* Clear all event requests */
4838 mono_loader_lock ();
4839 while (event_requests
->len
> 0) {
4840 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4842 clear_event_request (req
->id
, req
->event_kind
);
4844 mono_loader_unlock ();
4846 // FIXME: Count resumes
4848 disconnected
= TRUE
;
4851 MonoInternalThread
*thread
;
4852 DebuggerTlsData
*tls
;
4853 MonoClass
*env_class
;
4854 MonoMethod
*exit_method
;
4858 exit_code
= decode_int (p
, &p
, end
);
4860 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
4862 /* Have to send a reply before exiting */
4863 send_reply_packet (id
, 0, buf
);
4865 /* Clear all event requests */
4866 mono_loader_lock ();
4867 while (event_requests
->len
> 0) {
4868 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4870 clear_event_request (req
->id
, req
->event_kind
);
4872 mono_loader_unlock ();
4875 * The JDWP documentation says that the shutdown is not orderly. It doesn't
4876 * specify whenever a VM_DEATH event is sent. We currently do an orderly
4877 * shutdown by hijacking a thread to execute Environment.Exit (). This is
4878 * better than doing the shutdown ourselves, since it avoids various races.
4882 wait_for_suspend ();
4884 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
4885 g_assert (env_class
);
4886 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
4887 g_assert (exit_method
);
4889 mono_loader_lock ();
4890 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
4891 mono_loader_unlock ();
4894 mono_loader_lock ();
4895 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4896 mono_loader_unlock ();
4898 args
= g_new0 (gpointer
, 1);
4899 args
[0] = g_malloc (sizeof (int));
4900 *(int*)(args
[0]) = exit_code
;
4902 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4903 tls
->pending_invoke
->method
= exit_method
;
4904 tls
->pending_invoke
->args
= args
;
4906 while (suspend_count
> 0)
4910 * No thread found, do it ourselves.
4911 * FIXME: This can race with normal shutdown etc.
4913 while (suspend_count
> 0)
4916 mono_runtime_set_shutting_down ();
4918 mono_threads_set_shutting_down ();
4920 /* Suspend all managed threads since the runtime is going away */
4921 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
4922 mono_thread_suspend_all_other_threads ();
4923 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
4924 mono_runtime_quit ();
4926 shutdown (conn_fd
, SD_BOTH
);
4928 shutdown (conn_fd
, SHUT_RDWR
);
4930 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
4936 case CMD_VM_INVOKE_METHOD
: {
4937 int objid
= decode_objid (p
, &p
, end
);
4939 DebuggerTlsData
*tls
;
4942 err
= get_object (objid
, (MonoObject
**)&thread
);
4946 flags
= decode_int (p
, &p
, end
);
4948 // Wait for suspending if it already started
4950 wait_for_suspend ();
4951 if (!is_suspended ())
4952 return ERR_NOT_SUSPENDED
;
4954 mono_loader_lock ();
4955 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4956 mono_loader_unlock ();
4959 if (!tls
->really_suspended
)
4960 /* The thread is still running native code, can't do invokes */
4961 return ERR_NOT_SUSPENDED
;
4964 * Store the invoke data into tls, the thread will execute it after it is
4967 if (tls
->pending_invoke
)
4969 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
4970 tls
->pending_invoke
->id
= id
;
4971 tls
->pending_invoke
->flags
= flags
;
4972 tls
->pending_invoke
->p
= g_malloc (end
- p
);
4973 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
4974 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
4975 tls
->pending_invoke
->suspend_count
= suspend_count
;
4977 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
4978 resume_thread (THREAD_TO_INTERNAL (thread
));
4983 case CMD_VM_ABORT_INVOKE
: {
4984 int objid
= decode_objid (p
, &p
, end
);
4986 DebuggerTlsData
*tls
;
4989 err
= get_object (objid
, (MonoObject
**)&thread
);
4993 invoke_id
= decode_int (p
, &p
, end
);
4995 mono_loader_lock ();
4996 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4999 if (tls
->abort_requested
) {
5000 mono_loader_unlock ();
5005 * Check whether we're still inside the mono_runtime_invoke() and that it's
5006 * actually the correct invocation.
5008 * Careful, we do not stop the thread that's doing the invocation, so we can't
5009 * inspect its stack. However, invoke_method() also acquires the loader lock
5010 * when it's done, so we're safe here.
5014 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
5015 mono_loader_unlock ();
5016 return ERR_NO_INVOCATION
;
5019 tls
->abort_requested
= TRUE
;
5021 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
5022 mono_loader_unlock ();
5027 return ERR_NOT_IMPLEMENTED
;
5034 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5039 case CMD_EVENT_REQUEST_SET
: {
5041 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
5044 MonoThread
*step_thread
;
5045 int size
= 0, depth
= 0, step_thread_id
= 0;
5048 event_kind
= decode_byte (p
, &p
, end
);
5049 suspend_policy
= decode_byte (p
, &p
, end
);
5050 nmodifiers
= decode_byte (p
, &p
, end
);
5052 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
5053 req
->id
= InterlockedIncrement (&event_request_id
);
5054 req
->event_kind
= event_kind
;
5055 req
->suspend_policy
= suspend_policy
;
5056 req
->nmodifiers
= nmodifiers
;
5059 for (i
= 0; i
< nmodifiers
; ++i
) {
5060 mod
= decode_byte (p
, &p
, end
);
5062 req
->modifiers
[i
].kind
= mod
;
5063 if (mod
== MOD_KIND_COUNT
) {
5064 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
5065 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
5066 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5069 location
= decode_long (p
, &p
, end
);
5070 } else if (mod
== MOD_KIND_STEP
) {
5071 step_thread_id
= decode_id (p
, &p
, end
);
5072 size
= decode_int (p
, &p
, end
);
5073 depth
= decode_int (p
, &p
, end
);
5074 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
5075 int id
= decode_id (p
, &p
, end
);
5077 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
5082 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
5083 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5087 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
5088 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
5089 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" : ""));
5091 req
->modifiers
[i
].data
.exc_class
= exc_class
;
5093 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
5095 return ERR_INVALID_ARGUMENT
;
5098 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
5099 int n
= decode_int (p
, &p
, end
);
5102 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
5103 for (j
= 0; j
< n
; ++j
) {
5104 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5106 g_free (req
->modifiers
[i
].data
.assemblies
);
5112 return ERR_NOT_IMPLEMENTED
;
5116 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5119 req
->info
= set_breakpoint (method
, location
, req
);
5120 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
5121 g_assert (step_thread_id
);
5123 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
5129 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
5134 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
5135 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
);
5136 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
5137 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
);
5138 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
5140 if (req
->nmodifiers
) {
5142 return ERR_NOT_IMPLEMENTED
;
5146 mono_loader_lock ();
5147 g_ptr_array_add (event_requests
, req
);
5148 mono_loader_unlock ();
5150 buffer_add_int (buf
, req
->id
);
5153 case CMD_EVENT_REQUEST_CLEAR
: {
5154 int etype
= decode_byte (p
, &p
, end
);
5155 int req_id
= decode_int (p
, &p
, end
);
5157 // FIXME: Make a faster mapping from req_id to request
5158 mono_loader_lock ();
5159 clear_event_request (req_id
, etype
);
5160 mono_loader_unlock ();
5163 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
5166 mono_loader_lock ();
5168 while (i
< event_requests
->len
) {
5169 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5171 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5172 clear_breakpoint (req
->info
);
5174 g_ptr_array_remove_index_fast (event_requests
, i
);
5180 mono_loader_unlock ();
5184 return ERR_NOT_IMPLEMENTED
;
5191 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5197 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
5198 buffer_add_domainid (buf
, mono_get_root_domain ());
5201 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
5202 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5205 buffer_add_string (buf
, domain
->friendly_name
);
5208 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
5213 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5216 mono_loader_lock ();
5218 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5221 buffer_add_int (buf
, count
);
5222 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5224 buffer_add_assemblyid (buf
, domain
, ass
);
5226 mono_loader_unlock ();
5229 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
5230 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5234 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
5237 case CMD_APPDOMAIN_GET_CORLIB
: {
5238 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5242 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
5245 case CMD_APPDOMAIN_CREATE_STRING
: {
5249 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5252 s
= decode_string (p
, &p
, end
);
5254 o
= mono_string_new (domain
, s
);
5255 buffer_add_objid (buf
, (MonoObject
*)o
);
5258 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
5260 MonoDomain
*domain2
;
5263 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5266 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
5271 g_assert (domain
== domain2
);
5273 o
= mono_object_new (domain
, klass
);
5275 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
5279 buffer_add_objid (buf
, o
);
5283 return ERR_NOT_IMPLEMENTED
;
5290 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5296 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5301 case CMD_ASSEMBLY_GET_LOCATION
: {
5302 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
5305 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
5309 if (ass
->image
->dynamic
) {
5310 buffer_add_id (buf
, 0);
5312 token
= mono_image_get_entry_point (ass
->image
);
5314 buffer_add_id (buf
, 0);
5316 m
= mono_get_method (ass
->image
, token
, NULL
);
5317 buffer_add_methodid (buf
, domain
, m
);
5322 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
5323 buffer_add_moduleid (buf
, domain
, ass
->image
);
5326 case CMD_ASSEMBLY_GET_OBJECT
: {
5327 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
5328 buffer_add_objid (buf
, o
);
5331 case CMD_ASSEMBLY_GET_TYPE
: {
5332 char *s
= decode_string (p
, &p
, end
);
5333 gboolean ignorecase
= decode_byte (p
, &p
, end
);
5334 MonoTypeNameParse info
;
5336 gboolean type_resolve
;
5338 if (!mono_reflection_parse_type (s
, &info
)) {
5341 if (info
.assembly
.name
)
5343 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
5345 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
5346 mono_reflection_free_type_info (&info
);
5351 case CMD_ASSEMBLY_GET_NAME
: {
5353 MonoAssembly
*mass
= ass
;
5355 name
= g_strdup_printf (
5356 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
5358 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
5359 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
5360 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
5361 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
5363 buffer_add_string (buf
, name
);
5368 return ERR_NOT_IMPLEMENTED
;
5375 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5381 case CMD_MODULE_GET_INFO
: {
5382 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
5385 basename
= g_path_get_basename (image
->name
);
5386 buffer_add_string (buf
, basename
); // name
5387 buffer_add_string (buf
, image
->module_name
); // scopename
5388 buffer_add_string (buf
, image
->name
); // fqname
5389 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
5390 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
5395 return ERR_NOT_IMPLEMENTED
;
5402 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
5404 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
5405 /* Special case these so the client doesn't have to handle Type objects */
5407 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
5408 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
5409 } else if (MONO_TYPE_IS_REFERENCE (t
))
5410 buffer_add_value (buf
, t
, &val
, domain
);
5412 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
5416 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
5422 buffer_add_int (buf
, 0);
5426 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5427 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
5430 buffer_add_int (buf
, nattrs
);
5432 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5433 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
5434 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
5435 MonoArray
*typed_args
, *named_args
;
5437 CattrNamedArg
*arginfo
;
5439 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
5441 buffer_add_methodid (buf
, domain
, attr
->ctor
);
5445 buffer_add_int (buf
, mono_array_length (typed_args
));
5446 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
5447 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
5449 t
= mono_method_signature (attr
->ctor
)->params
[j
];
5451 buffer_add_cattr_arg (buf
, t
, domain
, val
);
5454 buffer_add_int (buf
, 0);
5459 buffer_add_int (buf
, mono_array_length (named_args
));
5461 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
5462 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
5464 if (arginfo
[j
].prop
) {
5465 buffer_add_byte (buf
, 0x54);
5466 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
5467 } else if (arginfo
[j
].field
) {
5468 buffer_add_byte (buf
, 0x53);
5470 g_assert_not_reached ();
5473 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
5476 buffer_add_int (buf
, 0);
5483 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5494 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5499 case CMD_TYPE_GET_INFO
: {
5500 buffer_add_string (buf
, klass
->name_space
);
5501 buffer_add_string (buf
, klass
->name
);
5503 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
5504 buffer_add_string (buf
, name
);
5506 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
5507 buffer_add_moduleid (buf
, domain
, klass
->image
);
5508 buffer_add_typeid (buf
, domain
, klass
->parent
);
5509 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
5510 buffer_add_typeid (buf
, domain
, klass
->element_class
);
5512 buffer_add_id (buf
, 0);
5513 buffer_add_int (buf
, klass
->type_token
);
5514 buffer_add_byte (buf
, klass
->rank
);
5515 buffer_add_int (buf
, klass
->flags
);
5517 type
= &klass
->byval_arg
;
5518 // FIXME: Can't decide whenever a class represents a byref type
5521 if (type
->type
== MONO_TYPE_PTR
)
5523 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
5525 if (type
->type
== MONO_TYPE_VALUETYPE
)
5527 if (klass
->enumtype
)
5529 buffer_add_byte (buf
, b
);
5532 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5534 buffer_add_int (buf
, nnested
);
5536 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5537 buffer_add_typeid (buf
, domain
, nested
);
5540 case CMD_TYPE_GET_METHODS
: {
5543 gpointer iter
= NULL
;
5546 mono_class_setup_methods (klass
);
5548 nmethods
= mono_class_num_methods (klass
);
5550 buffer_add_int (buf
, nmethods
);
5552 while ((m
= mono_class_get_methods (klass
, &iter
))) {
5553 buffer_add_methodid (buf
, domain
, m
);
5556 g_assert (i
== nmethods
);
5559 case CMD_TYPE_GET_FIELDS
: {
5562 gpointer iter
= NULL
;
5565 nfields
= mono_class_num_fields (klass
);
5567 buffer_add_int (buf
, nfields
);
5569 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5570 buffer_add_fieldid (buf
, domain
, f
);
5571 buffer_add_string (buf
, f
->name
);
5572 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
5573 buffer_add_int (buf
, f
->type
->attrs
);
5576 g_assert (i
== nfields
);
5579 case CMD_TYPE_GET_PROPERTIES
: {
5582 gpointer iter
= NULL
;
5585 nprops
= mono_class_num_properties (klass
);
5587 buffer_add_int (buf
, nprops
);
5589 while ((p
= mono_class_get_properties (klass
, &iter
))) {
5590 buffer_add_propertyid (buf
, domain
, p
);
5591 buffer_add_string (buf
, p
->name
);
5592 buffer_add_methodid (buf
, domain
, p
->get
);
5593 buffer_add_methodid (buf
, domain
, p
->set
);
5594 buffer_add_int (buf
, p
->attrs
);
5597 g_assert (i
== nprops
);
5600 case CMD_TYPE_GET_CATTRS
: {
5601 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5602 MonoCustomAttrInfo
*cinfo
;
5604 cinfo
= mono_custom_attrs_from_class (klass
);
5606 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5609 case CMD_TYPE_GET_FIELD_CATTRS
: {
5610 MonoClass
*attr_klass
;
5611 MonoCustomAttrInfo
*cinfo
;
5612 MonoClassField
*field
;
5614 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5617 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5621 cinfo
= mono_custom_attrs_from_field (klass
, field
);
5623 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5626 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
5627 MonoClass
*attr_klass
;
5628 MonoCustomAttrInfo
*cinfo
;
5631 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
5634 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5638 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
5640 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5643 case CMD_TYPE_GET_VALUES
: {
5651 len
= decode_int (p
, &p
, end
);
5652 for (i
= 0; i
< len
; ++i
) {
5653 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5657 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5658 return ERR_INVALID_FIELDID
;
5659 if (mono_class_field_is_special_static (f
))
5660 return ERR_INVALID_FIELDID
;
5662 /* Check that the field belongs to the object */
5664 for (k
= klass
; k
; k
= k
->parent
) {
5665 if (k
== f
->parent
) {
5671 return ERR_INVALID_FIELDID
;
5673 vtable
= mono_class_vtable (domain
, f
->parent
);
5674 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5675 mono_field_static_get_value (vtable
, f
, val
);
5676 buffer_add_value (buf
, f
->type
, val
, domain
);
5681 case CMD_TYPE_SET_VALUES
: {
5689 len
= decode_int (p
, &p
, end
);
5690 for (i
= 0; i
< len
; ++i
) {
5691 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5695 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5696 return ERR_INVALID_FIELDID
;
5697 if (mono_class_field_is_special_static (f
))
5698 return ERR_INVALID_FIELDID
;
5700 /* Check that the field belongs to the object */
5702 for (k
= klass
; k
; k
= k
->parent
) {
5703 if (k
== f
->parent
) {
5709 return ERR_INVALID_FIELDID
;
5711 // FIXME: Check for literal/const
5713 vtable
= mono_class_vtable (domain
, f
->parent
);
5714 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5715 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
5720 if (MONO_TYPE_IS_REFERENCE (f
->type
))
5721 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
5723 mono_field_static_set_value (vtable
, f
, val
);
5728 case CMD_TYPE_GET_OBJECT
: {
5729 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
5730 buffer_add_objid (buf
, o
);
5733 case CMD_TYPE_GET_SOURCE_FILES
: {
5734 gpointer iter
= NULL
;
5736 char *source_file
, *base
;
5740 files
= g_ptr_array_new ();
5742 while ((method
= mono_class_get_methods (klass
, &iter
))) {
5743 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
5746 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
5750 for (i
= 0; i
< files
->len
; ++i
)
5751 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
5753 if (i
== files
->len
)
5754 g_ptr_array_add (files
, g_strdup (source_file
));
5755 g_free (source_file
);
5759 buffer_add_int (buf
, files
->len
);
5760 for (i
= 0; i
< files
->len
; ++i
) {
5761 source_file
= g_ptr_array_index (files
, i
);
5762 base
= g_path_get_basename (source_file
);
5763 buffer_add_string (buf
, base
);
5765 g_free (source_file
);
5767 g_ptr_array_free (files
, TRUE
);
5770 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
5771 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5775 if (mono_class_is_assignable_from (klass
, oklass
))
5776 buffer_add_byte (buf
, 1);
5778 buffer_add_byte (buf
, 0);
5782 return ERR_NOT_IMPLEMENTED
;
5789 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5794 MonoMethodHeader
*header
;
5796 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5801 case CMD_METHOD_GET_NAME
: {
5802 buffer_add_string (buf
, method
->name
);
5805 case CMD_METHOD_GET_DECLARING_TYPE
: {
5806 buffer_add_typeid (buf
, domain
, method
->klass
);
5809 case CMD_METHOD_GET_DEBUG_INFO
: {
5810 MonoDebugMethodInfo
*minfo
;
5812 int i
, n_il_offsets
;
5816 header
= mono_method_get_header (method
);
5818 buffer_add_int (buf
, 0);
5819 buffer_add_string (buf
, "");
5820 buffer_add_int (buf
, 0);
5824 minfo
= mono_debug_lookup_method (method
);
5826 buffer_add_int (buf
, header
->code_size
);
5827 buffer_add_string (buf
, "");
5828 buffer_add_int (buf
, 0);
5829 mono_metadata_free_mh (header
);
5833 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
5834 buffer_add_int (buf
, header
->code_size
);
5835 buffer_add_string (buf
, source_file
);
5836 buffer_add_int (buf
, n_il_offsets
);
5837 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5838 for (i
= 0; i
< n_il_offsets
; ++i
) {
5839 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5840 buffer_add_int (buf
, il_offsets
[i
]);
5841 buffer_add_int (buf
, line_numbers
[i
]);
5843 g_free (source_file
);
5844 g_free (il_offsets
);
5845 g_free (line_numbers
);
5846 mono_metadata_free_mh (header
);
5849 case CMD_METHOD_GET_PARAM_INFO
: {
5850 MonoMethodSignature
*sig
= mono_method_signature (method
);
5854 /* FIXME: mono_class_from_mono_type () and byrefs */
5856 /* FIXME: Use a smaller encoding */
5857 buffer_add_int (buf
, sig
->call_convention
);
5858 buffer_add_int (buf
, sig
->param_count
);
5859 buffer_add_int (buf
, sig
->generic_param_count
);
5860 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
5861 for (i
= 0; i
< sig
->param_count
; ++i
) {
5863 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
5866 /* Emit parameter names */
5867 names
= g_new (char *, sig
->param_count
);
5868 mono_method_get_param_names (method
, (const char **) names
);
5869 for (i
= 0; i
< sig
->param_count
; ++i
)
5870 buffer_add_string (buf
, names
[i
]);
5875 case CMD_METHOD_GET_LOCALS_INFO
: {
5876 int i
, j
, num_locals
;
5880 header
= mono_method_get_header (method
);
5883 buffer_add_int (buf
, header
->num_locals
);
5886 for (i
= 0; i
< header
->num_locals
; ++i
)
5887 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
5890 num_locals
= mono_debug_lookup_locals (method
, &local_names
, &local_indexes
);
5891 for (i
= 0; i
< header
->num_locals
; ++i
) {
5892 for (j
= 0; j
< num_locals
; ++j
)
5893 if (local_indexes
[j
] == i
)
5896 buffer_add_string (buf
, local_names
[j
]);
5898 buffer_add_string (buf
, "");
5900 g_free (local_names
);
5901 g_free (local_indexes
);
5904 /* FIXME: This works because we set debug_options.mdb_optimizations */
5905 for (i
= 0; i
< header
->num_locals
; ++i
) {
5906 buffer_add_int (buf
, 0);
5907 buffer_add_int (buf
, header
->code_size
);
5909 mono_metadata_free_mh (header
);
5913 case CMD_METHOD_GET_INFO
:
5914 buffer_add_int (buf
, method
->flags
);
5915 buffer_add_int (buf
, method
->iflags
);
5916 buffer_add_int (buf
, method
->token
);
5918 case CMD_METHOD_GET_BODY
: {
5921 header
= mono_method_get_header (method
);
5923 buffer_add_int (buf
, 0);
5925 buffer_add_int (buf
, header
->code_size
);
5926 for (i
= 0; i
< header
->code_size
; ++i
)
5927 buffer_add_byte (buf
, header
->code
[i
]);
5929 mono_metadata_free_mh (header
);
5932 case CMD_METHOD_RESOLVE_TOKEN
: {
5933 guint32 token
= decode_int (p
, &p
, end
);
5936 switch (mono_metadata_token_code (token
)) {
5937 case MONO_TOKEN_STRING
: {
5941 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
5944 s2
= mono_string_to_utf8 (s
);
5946 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5947 buffer_add_string (buf
, s2
);
5953 MonoClass
*handle_class
;
5955 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5956 val
= mono_method_get_wrapper_data (method
, token
);
5957 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
5959 if (handle_class
== NULL
) {
5960 // Can't figure out the token type
5961 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
5965 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
5969 if (handle_class
== mono_defaults
.typehandle_class
) {
5970 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
5971 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
5972 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
5973 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
5974 buffer_add_fieldid (buf
, domain
, val
);
5975 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
5976 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
5977 buffer_add_methodid (buf
, domain
, val
);
5978 } else if (handle_class
== mono_defaults
.string_class
) {
5981 s
= mono_string_to_utf8 (val
);
5982 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5983 buffer_add_string (buf
, s
);
5986 g_assert_not_reached ();
5994 return ERR_NOT_IMPLEMENTED
;
6001 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6003 int objid
= decode_objid (p
, &p
, end
);
6005 MonoThread
*thread_obj
;
6006 MonoInternalThread
*thread
;
6008 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6012 thread
= THREAD_TO_INTERNAL (thread_obj
);
6015 case CMD_THREAD_GET_NAME
: {
6017 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
6020 buffer_add_int (buf
, 0);
6025 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
6027 buffer_add_int (buf
, len
);
6028 buffer_add_data (buf
, (guint8
*)name
, len
);
6033 case CMD_THREAD_GET_FRAME_INFO
: {
6034 DebuggerTlsData
*tls
;
6035 int i
, start_frame
, length
;
6037 // Wait for suspending if it already started
6039 wait_for_suspend ();
6040 if (!is_suspended ())
6041 return ERR_NOT_SUSPENDED
;
6043 start_frame
= decode_int (p
, &p
, end
);
6044 length
= decode_int (p
, &p
, end
);
6046 if (start_frame
!= 0 || length
!= -1)
6047 return ERR_NOT_IMPLEMENTED
;
6049 mono_loader_lock ();
6050 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6051 mono_loader_unlock ();
6054 compute_frame_info (thread
, tls
);
6056 buffer_add_int (buf
, tls
->frame_count
);
6057 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6058 buffer_add_int (buf
, tls
->frames
[i
]->id
);
6059 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->method
);
6060 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
6062 * Instead of passing the frame type directly to the client, we associate
6063 * it with the previous frame using a set of flags. This avoids lots of
6064 * conditional code in the client, since a frame whose type isn't
6065 * FRAME_TYPE_MANAGED has no method, location, etc.
6067 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
6072 case CMD_THREAD_GET_STATE
:
6073 buffer_add_int (buf
, thread
->state
);
6075 case CMD_THREAD_GET_INFO
:
6076 buffer_add_byte (buf
, thread
->threadpool_thread
);
6078 case CMD_THREAD_GET_ID
:
6079 buffer_add_long (buf
, (guint64
)thread
);
6082 return ERR_NOT_IMPLEMENTED
;
6089 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6093 MonoThread
*thread_obj
;
6094 MonoInternalThread
*thread
;
6096 DebuggerTlsData
*tls
;
6098 MonoDebugMethodJitInfo
*jit
;
6099 MonoDebugVarInfo
*var
;
6100 MonoMethodSignature
*sig
;
6102 MonoMethodHeader
*header
;
6104 objid
= decode_objid (p
, &p
, end
);
6105 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6109 thread
= THREAD_TO_INTERNAL (thread_obj
);
6111 id
= decode_id (p
, &p
, end
);
6113 mono_loader_lock ();
6114 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6115 mono_loader_unlock ();
6118 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6119 if (tls
->frames
[i
]->id
== id
)
6122 if (i
== tls
->frame_count
)
6123 return ERR_INVALID_FRAMEID
;
6125 frame
= tls
->frames
[i
];
6127 if (!frame
->has_ctx
)
6129 return ERR_INVALID_FRAMEID
;
6132 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
6133 g_assert (frame
->jit
);
6137 sig
= mono_method_signature (frame
->method
);
6140 case CMD_STACK_FRAME_GET_VALUES
: {
6141 len
= decode_int (p
, &p
, end
);
6142 header
= mono_method_get_header (frame
->method
);
6144 for (i
= 0; i
< len
; ++i
) {
6145 pos
= decode_int (p
, &p
, end
);
6150 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6152 var
= &jit
->params
[pos
];
6154 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6156 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6158 var
= &jit
->locals
[pos
];
6160 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6163 mono_metadata_free_mh (header
);
6166 case CMD_STACK_FRAME_GET_THIS
: {
6167 if (frame
->method
->klass
->valuetype
) {
6168 if (!sig
->hasthis
) {
6169 MonoObject
*p
= NULL
;
6170 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
6172 add_var (buf
, &frame
->method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6175 if (!sig
->hasthis
) {
6176 MonoObject
*p
= NULL
;
6177 buffer_add_value (buf
, &frame
->method
->klass
->byval_arg
, &p
, frame
->domain
);
6179 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6184 case CMD_STACK_FRAME_SET_VALUES
: {
6187 MonoDebugVarInfo
*var
;
6189 len
= decode_int (p
, &p
, end
);
6190 header
= mono_method_get_header (frame
->method
);
6192 for (i
= 0; i
< len
; ++i
) {
6193 pos
= decode_int (p
, &p
, end
);
6198 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6200 t
= sig
->params
[pos
];
6201 var
= &jit
->params
[pos
];
6203 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6205 t
= header
->locals
[pos
];
6206 var
= &jit
->locals
[pos
];
6209 if (MONO_TYPE_IS_REFERENCE (t
))
6210 val_buf
= g_alloca (sizeof (MonoObject
*));
6212 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
6213 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
6217 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
);
6219 mono_metadata_free_mh (header
);
6223 return ERR_NOT_IMPLEMENTED
;
6230 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6233 int objid
, err
, index
, len
, i
, esize
;
6236 objid
= decode_objid (p
, &p
, end
);
6237 err
= get_object (objid
, (MonoObject
**)&arr
);
6242 case CMD_ARRAY_REF_GET_LENGTH
:
6243 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
6245 buffer_add_int (buf
, arr
->max_length
);
6246 buffer_add_int (buf
, 0);
6248 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
6249 buffer_add_int (buf
, arr
->bounds
[i
].length
);
6250 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
6254 case CMD_ARRAY_REF_GET_VALUES
:
6255 index
= decode_int (p
, &p
, end
);
6256 len
= decode_int (p
, &p
, end
);
6258 g_assert (index
>= 0 && len
>= 0);
6259 // Reordered to avoid integer overflow
6260 g_assert (!(index
> arr
->max_length
- len
));
6262 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6263 for (i
= index
; i
< index
+ len
; ++i
) {
6264 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6265 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
6268 case CMD_ARRAY_REF_SET_VALUES
:
6269 index
= decode_int (p
, &p
, end
);
6270 len
= decode_int (p
, &p
, end
);
6272 g_assert (index
>= 0 && len
>= 0);
6273 // Reordered to avoid integer overflow
6274 g_assert (!(index
> arr
->max_length
- len
));
6276 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6277 for (i
= index
; i
< index
+ len
; ++i
) {
6278 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6280 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
6284 return ERR_NOT_IMPLEMENTED
;
6291 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6297 objid
= decode_objid (p
, &p
, end
);
6298 err
= get_object (objid
, (MonoObject
**)&str
);
6303 case CMD_STRING_REF_GET_VALUE
:
6304 s
= mono_string_to_utf8 (str
);
6305 buffer_add_string (buf
, s
);
6309 return ERR_NOT_IMPLEMENTED
;
6316 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6325 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
6326 objid
= decode_objid (p
, &p
, end
);
6327 err
= get_object (objid
, &obj
);
6329 buffer_add_int (buf
, 1);
6331 buffer_add_int (buf
, 0);
6335 objid
= decode_objid (p
, &p
, end
);
6336 err
= get_object (objid
, &obj
);
6341 case CMD_OBJECT_REF_GET_TYPE
:
6342 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
6344 case CMD_OBJECT_REF_GET_VALUES
:
6345 len
= decode_int (p
, &p
, end
);
6347 for (i
= 0; i
< len
; ++i
) {
6348 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6352 /* Check that the field belongs to the object */
6354 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6355 if (k
== f
->parent
) {
6361 return ERR_INVALID_FIELDID
;
6363 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6367 if (mono_class_field_is_special_static (f
))
6368 return ERR_INVALID_FIELDID
;
6370 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6371 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6372 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6373 mono_field_static_get_value (vtable
, f
, val
);
6374 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
6377 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
6381 case CMD_OBJECT_REF_SET_VALUES
:
6382 len
= decode_int (p
, &p
, end
);
6384 for (i
= 0; i
< len
; ++i
) {
6385 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6389 /* Check that the field belongs to the object */
6391 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6392 if (k
== f
->parent
) {
6398 return ERR_INVALID_FIELDID
;
6400 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6404 if (mono_class_field_is_special_static (f
))
6405 return ERR_INVALID_FIELDID
;
6407 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6408 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6410 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6411 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
6416 mono_field_static_set_value (vtable
, f
, val
);
6419 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
6425 case CMD_OBJECT_REF_GET_ADDRESS
:
6426 buffer_add_long (buf
, (gssize
)obj
);
6428 case CMD_OBJECT_REF_GET_DOMAIN
:
6429 buffer_add_domainid (buf
, obj
->vtable
->domain
);
6432 return ERR_NOT_IMPLEMENTED
;
6439 command_set_to_string (CommandSet command_set
)
6441 switch (command_set
) {
6444 case CMD_SET_OBJECT_REF
:
6445 return "OBJECT_REF";
6446 case CMD_SET_STRING_REF
:
6447 return "STRING_REF";
6448 case CMD_SET_THREAD
:
6450 case CMD_SET_ARRAY_REF
:
6452 case CMD_SET_EVENT_REQUEST
:
6453 return "EVENT_REQUEST";
6454 case CMD_SET_STACK_FRAME
:
6455 return "STACK_FRAME";
6456 case CMD_SET_APPDOMAIN
:
6458 case CMD_SET_ASSEMBLY
:
6460 case CMD_SET_METHOD
:
6464 case CMD_SET_MODULE
:
6476 * This thread handles communication with the debugger client using a JDWP
6479 static guint32 WINAPI
6480 debugger_thread (void *arg
)
6482 int res
, len
, id
, flags
, command_set
, command
;
6483 guint8 header
[HEADER_LENGTH
];
6484 guint8
*data
, *p
, *end
;
6489 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
6491 debugger_thread_id
= GetCurrentThreadId ();
6493 mono_jit_thread_attach (mono_get_root_domain ());
6495 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
6497 mono_set_is_debugger_attached (TRUE
);
6500 res
= recv_length (conn_fd
, header
, HEADER_LENGTH
, 0);
6502 /* This will break if the socket is closed during shutdown too */
6503 if (res
!= HEADER_LENGTH
)
6507 end
= header
+ HEADER_LENGTH
;
6509 len
= decode_int (p
, &p
, end
);
6510 id
= decode_int (p
, &p
, end
);
6511 flags
= decode_byte (p
, &p
, end
);
6512 command_set
= decode_byte (p
, &p
, end
);
6513 command
= decode_byte (p
, &p
, end
);
6515 g_assert (flags
== 0);
6517 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set
), command
, id
));
6519 data
= g_malloc (len
- HEADER_LENGTH
);
6520 if (len
- HEADER_LENGTH
> 0)
6522 res
= recv_length (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
6523 if (res
!= len
- HEADER_LENGTH
)
6528 end
= data
+ (len
- HEADER_LENGTH
);
6530 buffer_init (&buf
, 128);
6535 /* Process the request */
6536 switch (command_set
) {
6538 err
= vm_commands (command
, id
, p
, end
, &buf
);
6539 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
6540 /* Sent after the invoke is complete */
6543 case CMD_SET_EVENT_REQUEST
:
6544 err
= event_commands (command
, p
, end
, &buf
);
6546 case CMD_SET_APPDOMAIN
:
6547 err
= domain_commands (command
, p
, end
, &buf
);
6549 case CMD_SET_ASSEMBLY
:
6550 err
= assembly_commands (command
, p
, end
, &buf
);
6552 case CMD_SET_MODULE
:
6553 err
= module_commands (command
, p
, end
, &buf
);
6556 err
= type_commands (command
, p
, end
, &buf
);
6558 case CMD_SET_METHOD
:
6559 err
= method_commands (command
, p
, end
, &buf
);
6561 case CMD_SET_THREAD
:
6562 err
= thread_commands (command
, p
, end
, &buf
);
6564 case CMD_SET_STACK_FRAME
:
6565 err
= frame_commands (command
, p
, end
, &buf
);
6567 case CMD_SET_ARRAY_REF
:
6568 err
= array_commands (command
, p
, end
, &buf
);
6570 case CMD_SET_STRING_REF
:
6571 err
= string_commands (command
, p
, end
, &buf
);
6573 case CMD_SET_OBJECT_REF
:
6574 err
= object_commands (command
, p
, end
, &buf
);
6577 err
= ERR_NOT_IMPLEMENTED
;
6581 send_reply_packet (id
, err
, &buf
);
6586 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
6590 mono_set_is_debugger_attached (FALSE
);
6592 mono_mutex_lock (&debugger_thread_exited_mutex
);
6593 debugger_thread_exited
= TRUE
;
6594 mono_cond_signal (&debugger_thread_exited_cond
);
6595 mono_mutex_unlock (&debugger_thread_exited_mutex
);
6597 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6602 #else /* DISABLE_DEBUGGER_AGENT */
6605 mono_debugger_agent_parse_options (char *options
)
6607 g_error ("This runtime is configure with the debugger agent disabled.");
6611 mono_debugger_agent_init (void)
6616 mono_debugger_agent_breakpoint_hit (void *sigctx
)
6621 mono_debugger_agent_single_step_event (void *sigctx
)
6626 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
6631 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
6637 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
6638 MonoContext
*catch_ctx
)