2 * debugger-agent.c: Soft Debugger back-end module
5 * Zoltan Varga (vargaz@gmail.com)
7 * Copyright 2009-2010 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/metadata/assembly.h>
74 #include <mono/utils/mono-semaphore.h>
75 #include <mono/utils/mono-error-internals.h>
76 #include <mono/utils/mono-stack-unwinding.h>
77 #include "debugger-agent.h"
80 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
81 #define DISABLE_DEBUGGER_AGENT 1
84 #ifdef DISABLE_SOFT_DEBUG
85 #define DISABLE_DEBUGGER_AGENT 1
89 #include <mono/utils/mono-threads.h>
93 #ifndef DISABLE_DEBUGGER_AGENT
95 #include <mono/io-layer/mono-mutex.h>
97 /* Definitions to make backporting to 2.6 easier */
98 //#define MonoInternalThread MonoThread
99 //#define mono_thread_internal_current mono_thread_current
100 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
122 guint32 il_offset
, native_offset
;
126 * If method is gshared, this is the actual instance, otherwise this is equal to
129 MonoMethod
*actual_method
;
131 MonoDebugMethodJitInfo
*jit
;
133 mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
135 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
136 * the frame can become invalid.
141 typedef struct _InvokeData InvokeData
;
149 /* This is the context which needs to be restored after the invoke */
153 * If this is set, invoke this method with the arguments given by ARGS.
157 guint32 suspend_count
;
159 InvokeData
*last_invoke
;
163 MonoThreadUnwindState context
;
165 gpointer resume_event
;
166 /* This is computed on demand when it is requested using the wire protocol */
167 /* It is freed up when the thread is resumed */
171 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
174 gboolean frames_up_to_date
;
176 * Points to data about a pending invoke which needs to be executed after the thread
179 InvokeData
*pending_invoke
;
181 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
186 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
187 * within a finite amount of time.
191 * Set to TRUE if this thread is suspended in suspend_current ().
193 gboolean really_suspended
;
194 /* Used to pass the context to the breakpoint/single step handler */
195 MonoContext handler_ctx
;
196 /* Whenever thread_stop () was called for this thread */
199 /* Number of thread interruptions not yet processed */
200 gint32 interrupt_count
;
202 /* Whenever to disable breakpoints (used during invokes) */
203 gboolean disable_breakpoints
;
206 * Number of times this thread has been resumed using resume_thread ().
208 guint32 resume_count
;
210 MonoInternalThread
*thread
;
213 * Information about the frame which transitioned to native code for running
216 StackFrameInfo async_last_frame
;
219 * The context where the stack walk can be started for running threads.
221 MonoThreadUnwindState async_state
;
224 * The context used for filter clauses
226 MonoThreadUnwindState filter_state
;
229 * The callee address of the last mono_runtime_invoke call
231 gpointer invoke_addr
;
233 gboolean abort_requested
;
236 * The current mono_runtime_invoke invocation.
241 * The context where single stepping should resume while the thread is suspended because
242 * of an EXCEPTION event.
244 MonoContext catch_ctx
;
246 gboolean has_catch_ctx
;
249 * The context which needs to be restored after handling a single step/breakpoint
250 * event. This is the same as the ctx at step/breakpoint site, but includes changes
251 * to caller saved registers done by set_var ().
253 MonoContext restore_ctx
;
257 * Wire Protocol definitions
260 #define HEADER_LENGTH 11
262 #define MAJOR_VERSION 2
263 #define MINOR_VERSION 4
267 CMD_SET_OBJECT_REF
= 9,
268 CMD_SET_STRING_REF
= 10,
270 CMD_SET_ARRAY_REF
= 13,
271 CMD_SET_EVENT_REQUEST
= 15,
272 CMD_SET_STACK_FRAME
= 16,
273 CMD_SET_APPDOMAIN
= 20,
274 CMD_SET_ASSEMBLY
= 21,
282 EVENT_KIND_VM_START
= 0,
283 EVENT_KIND_VM_DEATH
= 1,
284 EVENT_KIND_THREAD_START
= 2,
285 EVENT_KIND_THREAD_DEATH
= 3,
286 EVENT_KIND_APPDOMAIN_CREATE
= 4,
287 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
288 EVENT_KIND_METHOD_ENTRY
= 6,
289 EVENT_KIND_METHOD_EXIT
= 7,
290 EVENT_KIND_ASSEMBLY_LOAD
= 8,
291 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
292 EVENT_KIND_BREAKPOINT
= 10,
293 EVENT_KIND_STEP
= 11,
294 EVENT_KIND_TYPE_LOAD
= 12,
295 EVENT_KIND_EXCEPTION
= 13,
296 EVENT_KIND_KEEPALIVE
= 14,
297 EVENT_KIND_USER_BREAK
= 15,
298 EVENT_KIND_USER_LOG
= 16
302 SUSPEND_POLICY_NONE
= 0,
303 SUSPEND_POLICY_EVENT_THREAD
= 1,
304 SUSPEND_POLICY_ALL
= 2
309 ERR_INVALID_OBJECT
= 20,
310 ERR_INVALID_FIELDID
= 25,
311 ERR_INVALID_FRAMEID
= 30,
312 ERR_NOT_IMPLEMENTED
= 100,
313 ERR_NOT_SUSPENDED
= 101,
314 ERR_INVALID_ARGUMENT
= 102,
316 ERR_NO_INVOCATION
= 104,
317 ERR_ABSENT_INFORMATION
= 105,
318 ERR_NO_SEQ_POINT_AT_IL_OFFSET
= 106
323 MOD_KIND_THREAD_ONLY
= 3,
324 MOD_KIND_LOCATION_ONLY
= 7,
325 MOD_KIND_EXCEPTION_ONLY
= 8,
327 MOD_KIND_ASSEMBLY_ONLY
= 11
342 TOKEN_TYPE_STRING
= 0,
344 TOKEN_TYPE_FIELD
= 2,
345 TOKEN_TYPE_METHOD
= 3,
346 TOKEN_TYPE_UNKNOWN
= 4
350 VALUE_TYPE_ID_NULL
= 0xf0,
351 VALUE_TYPE_ID_TYPE
= 0xf1
355 FRAME_FLAG_DEBUGGER_INVOKE
= 1
359 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
360 INVOKE_FLAG_SINGLE_THREADED
= 2
365 CMD_VM_ALL_THREADS
= 2,
370 CMD_VM_INVOKE_METHOD
= 7,
371 CMD_VM_SET_PROTOCOL_VERSION
= 8,
372 CMD_VM_ABORT_INVOKE
= 9,
373 CMD_VM_SET_KEEPALIVE
= 10
377 CMD_THREAD_GET_FRAME_INFO
= 1,
378 CMD_THREAD_GET_NAME
= 2,
379 CMD_THREAD_GET_STATE
= 3,
380 CMD_THREAD_GET_INFO
= 4,
381 CMD_THREAD_GET_ID
= 5,
382 CMD_THREAD_GET_TID
= 6
386 CMD_EVENT_REQUEST_SET
= 1,
387 CMD_EVENT_REQUEST_CLEAR
= 2,
388 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
396 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
397 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
398 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
399 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
400 CMD_APPDOMAIN_CREATE_STRING
= 5,
401 CMD_APPDOMAIN_GET_CORLIB
= 6,
402 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7,
406 CMD_ASSEMBLY_GET_LOCATION
= 1,
407 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
408 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
409 CMD_ASSEMBLY_GET_OBJECT
= 4,
410 CMD_ASSEMBLY_GET_TYPE
= 5,
411 CMD_ASSEMBLY_GET_NAME
= 6
415 CMD_MODULE_GET_INFO
= 1,
419 CMD_METHOD_GET_NAME
= 1,
420 CMD_METHOD_GET_DECLARING_TYPE
= 2,
421 CMD_METHOD_GET_DEBUG_INFO
= 3,
422 CMD_METHOD_GET_PARAM_INFO
= 4,
423 CMD_METHOD_GET_LOCALS_INFO
= 5,
424 CMD_METHOD_GET_INFO
= 6,
425 CMD_METHOD_GET_BODY
= 7,
426 CMD_METHOD_RESOLVE_TOKEN
= 8,
430 CMD_TYPE_GET_INFO
= 1,
431 CMD_TYPE_GET_METHODS
= 2,
432 CMD_TYPE_GET_FIELDS
= 3,
433 CMD_TYPE_GET_VALUES
= 4,
434 CMD_TYPE_GET_OBJECT
= 5,
435 CMD_TYPE_GET_SOURCE_FILES
= 6,
436 CMD_TYPE_SET_VALUES
= 7,
437 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
438 CMD_TYPE_GET_PROPERTIES
= 9,
439 CMD_TYPE_GET_CATTRS
= 10,
440 CMD_TYPE_GET_FIELD_CATTRS
= 11,
441 CMD_TYPE_GET_PROPERTY_CATTRS
= 12,
442 CMD_TYPE_GET_SOURCE_FILES_2
= 13,
443 CMD_TYPE_GET_VALUES_2
= 14
447 CMD_STACK_FRAME_GET_VALUES
= 1,
448 CMD_STACK_FRAME_GET_THIS
= 2,
449 CMD_STACK_FRAME_SET_VALUES
= 3
453 CMD_ARRAY_REF_GET_LENGTH
= 1,
454 CMD_ARRAY_REF_GET_VALUES
= 2,
455 CMD_ARRAY_REF_SET_VALUES
= 3,
459 CMD_STRING_REF_GET_VALUE
= 1,
463 CMD_OBJECT_REF_GET_TYPE
= 1,
464 CMD_OBJECT_REF_GET_VALUES
= 2,
465 CMD_OBJECT_REF_IS_COLLECTED
= 3,
466 CMD_OBJECT_REF_GET_ADDRESS
= 4,
467 CMD_OBJECT_REF_GET_DOMAIN
= 5,
468 CMD_OBJECT_REF_SET_VALUES
= 6
474 int count
; /* For kind == MOD_KIND_COUNT */
475 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
476 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
477 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
479 gboolean caught
, uncaught
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
488 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
492 * Describes a single step request.
496 MonoInternalThread
*thread
;
501 MonoMethod
*last_method
;
503 /* Whenever single stepping is performed using start/stop_single_stepping () */
505 /* The list of breakpoints used to implement step-over */
510 * Contains additional information for an event
513 /* For EVENT_KIND_EXCEPTION */
515 MonoContext catch_ctx
;
517 /* For EVENT_KIND_USER_LOG */
519 char *category
, *message
;
522 /* Dummy structure used for the profiler callbacks */
527 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
530 #define get_last_sock_error() WSAGetLastError()
531 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
532 #define MONO_EINTR WSAEINTR
534 #define get_last_sock_error() errno
535 #define MONO_EWOULDBLOCK EWOULDBLOCK
536 #define MONO_EINTR EINTR
543 static AgentConfig agent_config
;
546 * Whenever the agent is fully initialized.
547 * When using the onuncaught or onthrow options, only some parts of the agent are
548 * initialized on startup, and the full initialization which includes connection
549 * establishment and the startup of the agent thread is only done in response to
552 static gint32 inited
;
555 static int listen_fd
;
557 static int packet_id
= 0;
559 static int objref_id
= 0;
561 static int event_request_id
= 0;
563 static int frame_id
= 0;
565 static GPtrArray
*event_requests
;
567 static MonoNativeTlsKey debugger_tls_id
;
569 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
571 /* Maps MonoInternalThread -> DebuggerTlsData */
572 static MonoGHashTable
*thread_to_tls
;
574 /* Maps tid -> MonoInternalThread */
575 static MonoGHashTable
*tid_to_thread
;
577 /* Maps tid -> MonoThread (not MonoInternalThread) */
578 static MonoGHashTable
*tid_to_thread_obj
;
580 static gsize debugger_thread_id
;
582 static HANDLE debugger_thread_handle
;
584 static int log_level
;
586 static gboolean embedding
;
588 static FILE *log_file
;
590 /* Assemblies whose assembly load event has no been sent yet */
591 static GPtrArray
*pending_assembly_loads
;
593 /* Whenever the debugger thread has exited */
594 static gboolean debugger_thread_exited
;
596 /* Cond variable used to wait for debugger_thread_exited becoming true */
597 static mono_cond_t debugger_thread_exited_cond
;
599 /* Mutex for the cond var above */
600 static mono_mutex_t debugger_thread_exited_mutex
;
602 static DebuggerProfiler debugger_profiler
;
604 /* The single step request instance */
605 static SingleStepReq
*ss_req
= NULL
;
606 static gpointer ss_invoke_addr
= NULL
;
608 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
609 /* Number of single stepping operations in progress */
613 /* The protocol version of the client */
614 static int major_version
, minor_version
;
616 /* Whenever the variables above are set by the client */
617 static gboolean protocol_version_set
;
619 /* A hash table containing all active domains */
620 static GHashTable
*domains
;
622 static void transport_connect (const char *host
, int port
);
624 static guint32 WINAPI
debugger_thread (void *arg
);
626 static void runtime_initialized (MonoProfiler
*prof
);
628 static void runtime_shutdown (MonoProfiler
*prof
);
630 static void thread_startup (MonoProfiler
*prof
, uintptr_t tid
);
632 static void thread_end (MonoProfiler
*prof
, uintptr_t tid
);
634 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
636 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
638 static void emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
);
640 static void emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
);
642 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
644 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
646 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
648 static void emit_assembly_load (gpointer assembly
, gpointer user_data
);
650 static void emit_type_load (gpointer key
, gpointer type
, gpointer user_data
);
652 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
654 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
656 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
658 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
660 static void start_single_stepping (void);
662 static void stop_single_stepping (void);
664 static void suspend_current (void);
666 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
668 static void clear_types_for_assembly (MonoAssembly
*assembly
);
670 static void clear_breakpoints_for_domain (MonoDomain
*domain
);
672 static void process_profiler_event (EventKind event
, gpointer arg
);
674 /* Submodule init/cleanup */
675 static void breakpoints_init (void);
676 static void breakpoints_cleanup (void);
678 static void objrefs_init (void);
679 static void objrefs_cleanup (void);
681 static void ids_init (void);
682 static void ids_cleanup (void);
684 static void suspend_init (void);
686 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
);
687 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
688 static void ss_destroy (SingleStepReq
*req
);
690 static void start_debugger_thread (void);
691 static void stop_debugger_thread (void);
693 static void finish_agent_init (gboolean on_startup
);
695 static void process_profiler_event (EventKind event
, gpointer arg
);
698 parse_address (char *address
, char **host
, int *port
)
700 char *pos
= strchr (address
, ':');
702 if (pos
== NULL
|| pos
== address
)
705 *host
= g_malloc (pos
- address
+ 1);
706 strncpy (*host
, address
, pos
- address
);
707 (*host
) [pos
- address
] = '\0';
709 *port
= atoi (pos
+ 1);
717 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
718 fprintf (stderr
, "Available options:\n");
719 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
720 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
721 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
722 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
723 fprintf (stderr
, " suspend=y/n\t\t\tWhether to suspend after startup.\n");
724 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
725 fprintf (stderr
, " server=y/n\t\t\tWhether to listen for a client connection.\n");
726 fprintf (stderr
, " keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
727 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
731 parse_flag (const char *option
, char *flag
)
733 if (!strcmp (flag
, "y"))
735 else if (!strcmp (flag
, "n"))
738 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
745 mono_debugger_agent_parse_options (char *options
)
751 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
752 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
756 agent_config
.enabled
= TRUE
;
757 agent_config
.suspend
= TRUE
;
758 agent_config
.server
= FALSE
;
759 agent_config
.defer
= FALSE
;
760 agent_config
.address
= NULL
;
762 args
= g_strsplit (options
, ",", -1);
763 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
766 if (strncmp (arg
, "transport=", 10) == 0) {
767 agent_config
.transport
= g_strdup (arg
+ 10);
768 } else if (strncmp (arg
, "address=", 8) == 0) {
769 agent_config
.address
= g_strdup (arg
+ 8);
770 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
771 agent_config
.log_level
= atoi (arg
+ 9);
772 } else if (strncmp (arg
, "logfile=", 8) == 0) {
773 agent_config
.log_file
= g_strdup (arg
+ 8);
774 } else if (strncmp (arg
, "suspend=", 8) == 0) {
775 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
776 } else if (strncmp (arg
, "server=", 7) == 0) {
777 agent_config
.server
= parse_flag ("server", arg
+ 7);
778 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
779 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
780 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
781 /* We support multiple onthrow= options */
782 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
783 } else if (strncmp (arg
, "onthrow", 7) == 0) {
784 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
785 } else if (strncmp (arg
, "help", 4) == 0) {
788 } else if (strncmp (arg
, "timeout=", 8) == 0) {
789 agent_config
.timeout
= atoi (arg
+ 8);
790 } else if (strncmp (arg
, "launch=", 7) == 0) {
791 agent_config
.launch
= g_strdup (arg
+ 7);
792 } else if (strncmp (arg
, "embedding=", 10) == 0) {
793 agent_config
.embedding
= atoi (arg
+ 10) == 1;
794 } else if (strncmp (arg
, "keepalive=", 10) == 0) {
795 agent_config
.keepalive
= atoi (arg
+ 10);
802 if (agent_config
.server
&& !agent_config
.suspend
) {
803 /* Waiting for deferred attachment */
804 agent_config
.defer
= TRUE
;
805 if (agent_config
.address
== NULL
) {
806 agent_config
.address
= g_strdup_printf ("0.0.0.0:%u", 56000 + (GetCurrentProcessId () % 1000));
810 if (agent_config
.transport
== NULL
) {
811 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
814 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
815 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
819 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
820 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
824 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
825 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
831 mono_debugger_agent_init (void)
833 if (!agent_config
.enabled
)
836 /* Need to know whenever a thread has acquired the loader mutex */
837 mono_loader_lock_track_ownership (TRUE
);
839 event_requests
= g_ptr_array_new ();
841 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
842 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
844 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
845 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
846 mono_profiler_install_runtime_initialized (runtime_initialized
);
847 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
848 mono_profiler_install_thread (thread_startup
, thread_end
);
849 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
850 mono_profiler_install_jit_end (jit_end
);
851 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
853 mono_native_tls_alloc (&debugger_tls_id
, NULL
);
855 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
856 MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls
);
858 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
859 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread
);
861 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
862 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj
);
864 pending_assembly_loads
= g_ptr_array_new ();
865 domains
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
867 log_level
= agent_config
.log_level
;
869 embedding
= agent_config
.embedding
;
872 if (agent_config
.log_file
) {
873 log_file
= fopen (agent_config
.log_file
, "w+");
875 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
887 mini_get_debug_options ()->gen_seq_points
= TRUE
;
889 * This is needed because currently we don't handle liveness info.
891 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
893 #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
894 /* This is needed because we can't set local variables in registers yet */
895 mono_disable_optimizations (MONO_OPT_LINEARS
);
898 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
899 finish_agent_init (TRUE
);
901 #if defined(__MACH__)
902 /*FIXME Under darwin, we need to disable the new interruption code since sdb needs to old signal based one.*/
903 mono_thread_info_disable_new_interrupt (TRUE
);
911 * Finish the initialization of the agent. This involves connecting the transport
912 * and starting the agent thread. This is either done at startup, or
913 * in response to some event like an unhandled exception.
916 finish_agent_init (gboolean on_startup
)
922 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
925 if (agent_config
.launch
) {
928 // FIXME: Generated address
929 // FIXME: Races with transport_connect ()
931 argv
[0] = agent_config
.launch
;
932 argv
[1] = agent_config
.transport
;
933 argv
[2] = agent_config
.address
;
936 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
938 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
943 if (agent_config
.address
) {
944 res
= parse_address (agent_config
.address
, &host
, &port
);
951 transport_connect (host
, port
);
954 /* Do some which is usually done after sending the VMStart () event */
955 vm_start_event_sent
= TRUE
;
956 start_debugger_thread ();
961 mono_debugger_agent_cleanup (void)
966 stop_debugger_thread ();
968 breakpoints_cleanup ();
972 mono_mutex_destroy (&debugger_thread_exited_mutex
);
973 mono_cond_destroy (&debugger_thread_exited_cond
);
979 * recv() + handle incomplete reads and EINTR
982 recv_length (int fd
, void *buf
, int len
, int flags
)
989 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
992 if (agent_config
.keepalive
&& res
== -1 && get_last_sock_error () == MONO_EWOULDBLOCK
) {
993 process_profiler_event (EVENT_KIND_KEEPALIVE
, NULL
);
996 } while ((res
> 0 && total
< len
) || (res
== -1 && get_last_sock_error () == MONO_EINTR
));
1001 #define HAVE_GETADDRINFO 1
1005 set_keepalive (void)
1010 if (!agent_config
.keepalive
)
1013 tv
.tv_sec
= agent_config
.keepalive
/ 1000;
1014 tv
.tv_usec
= (agent_config
.keepalive
% 1000) * 1000;
1016 result
= setsockopt (conn_fd
, SOL_SOCKET
, SO_RCVTIMEO
, (char *) &tv
, sizeof(struct timeval
));
1017 g_assert (result
>= 0);
1021 transport_accept (int socket_fd
)
1023 conn_fd
= accept (socket_fd
, NULL
, NULL
);
1024 if (conn_fd
== -1) {
1025 fprintf (stderr
, "debugger-agent: Unable to listen on %d\n", socket_fd
);
1027 DEBUG (1, fprintf (log_file
, "Accepted connection from client, connection fd=%d.\n", conn_fd
));
1034 transport_handshake (void)
1036 char handshake_msg
[128];
1040 /* Write handshake message */
1041 sprintf (handshake_msg
, "DWP-Handshake");
1043 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1044 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1045 g_assert (res
!= -1);
1048 res
= recv_length (conn_fd
, buf
, strlen (handshake_msg
), 0);
1049 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1050 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1055 * To support older clients, the client sends its protocol version after connecting
1056 * using a command. Until that is received, default to our protocol version.
1058 major_version
= MAJOR_VERSION
;
1059 minor_version
= MINOR_VERSION
;
1060 protocol_version_set
= FALSE
;
1063 * Set TCP_NODELAY on the socket so the client receives events/command
1064 * results immediately.
1068 int result
= setsockopt (conn_fd
,
1073 g_assert (result
>= 0);
1082 * transport_connect:
1084 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
1087 transport_connect (const char *host
, int port
)
1089 #ifdef HAVE_GETADDRINFO
1090 struct addrinfo hints
;
1091 struct addrinfo
*result
, *rp
;
1093 struct hostent
*result
;
1095 int sfd
= -1, s
, res
;
1096 char port_string
[128];
1102 sprintf (port_string
, "%d", port
);
1104 mono_network_init ();
1106 /* Obtain address(es) matching host/port */
1107 #ifdef HAVE_GETADDRINFO
1108 memset (&hints
, 0, sizeof (struct addrinfo
));
1109 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
1110 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
1112 hints
.ai_protocol
= 0; /* Any protocol */
1114 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
1116 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %s\n", host
, port
, gai_strerror (s
));
1120 /* The PS3 doesn't even have _r or hstrerror () */
1121 result
= gethostbyname (host
);
1123 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %d\n", host
, port
, h_errno
);
1128 if (agent_config
.server
) {
1129 #ifdef HAVE_GETADDRINFO
1130 /* Wait for a connection */
1132 struct sockaddr_in addr
;
1135 /* No address, generate one */
1136 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
1139 /* This will bind the socket to a random port */
1140 res
= listen (sfd
, 16);
1142 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
1147 addrlen
= sizeof (addr
);
1148 memset (&addr
, 0, sizeof (addr
));
1149 res
= getsockname (sfd
, &addr
, &addrlen
);
1150 g_assert (res
== 0);
1153 port
= ntohs (addr
.sin_port
);
1155 /* Emit the address to stdout */
1156 /* FIXME: Should print another interface, not localhost */
1157 printf ("%s:%d\n", host
, port
);
1159 /* Listen on the provided address */
1160 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1163 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1168 if (setsockopt (sfd
, SOL_SOCKET
, SO_REUSEADDR
, &n
, sizeof(n
)) == -1)
1171 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1175 res
= listen (sfd
, 16);
1184 * this function is not present on win2000 which we still support, and the
1185 * workaround described here:
1186 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1187 * only works with MSVC.
1189 #ifdef HAVE_GETADDRINFO
1190 freeaddrinfo (result
);
1195 if (agent_config
.defer
)
1198 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1200 if (agent_config
.timeout
) {
1205 tv
.tv_usec
= agent_config
.timeout
* 1000;
1207 FD_SET (sfd
, &readfds
);
1208 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1210 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1215 conn_fd
= transport_accept (sfd
);
1219 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1222 #endif /* HAVE_GETADDRINFO */
1224 /* Connect to the specified address */
1225 #ifdef HAVE_GETADDRINFO
1226 /* FIXME: Respect the timeout */
1227 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1228 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1233 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1234 break; /* Success */
1240 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1244 sfd
= socket (result
->h_addrtype
, SOCK_STREAM
, 0);
1246 g_assert_not_reached ();
1247 res
= connect (sfd
, (void*)result
->h_addr_list
[0], result
->h_length
);
1249 g_assert_not_reached ();
1255 /* See the comment above */
1256 #ifdef HAVE_GETADDRINFO
1257 freeaddrinfo (result
);
1262 disconnected
= !transport_handshake ();
1268 transport_send (guint8
*data
, int len
)
1273 res
= send (conn_fd
, data
, len
, 0);
1274 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1282 stop_debugger_thread (void)
1287 /* This will interrupt the agent thread */
1288 /* Close the read part only so it can still send back replies */
1289 /* Also shut down the connection listener so that we can exit normally */
1291 /* SD_RECEIVE doesn't break the recv in the debugger thread */
1292 shutdown (conn_fd
, SD_BOTH
);
1293 shutdown (listen_fd
, SD_BOTH
);
1294 closesocket (listen_fd
);
1296 shutdown (conn_fd
, SHUT_RD
);
1297 shutdown (listen_fd
, SHUT_RDWR
);
1302 * Wait for the thread to exit.
1304 * If we continue with the shutdown without waiting for it, then the client might
1305 * not receive an answer to its last command like a resume.
1306 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
1309 //WaitForSingleObject (debugger_thread_handle, INFINITE);
1310 if (GetCurrentThreadId () != debugger_thread_id
) {
1312 mono_mutex_lock (&debugger_thread_exited_mutex
);
1313 if (!debugger_thread_exited
) {
1315 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
1316 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1318 mono_mutex_lock (&debugger_thread_exited_mutex
);
1321 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
1324 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1325 } while (!debugger_thread_exited
);
1329 shutdown (conn_fd
, SD_BOTH
);
1331 shutdown (conn_fd
, SHUT_RDWR
);
1336 start_debugger_thread (void)
1340 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1341 g_assert (debugger_thread_handle
);
1345 * Functions to decode protocol data
1349 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1352 g_assert (*endbuf
<= limit
);
1357 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1360 g_assert (*endbuf
<= limit
);
1362 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1365 static inline gint64
1366 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1368 guint32 high
= decode_int (buf
, &buf
, limit
);
1369 guint32 low
= decode_int (buf
, &buf
, limit
);
1373 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1377 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1379 return decode_int (buf
, endbuf
, limit
);
1383 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1385 int len
= decode_int (buf
, &buf
, limit
);
1388 s
= g_malloc (len
+ 1);
1391 memcpy (s
, buf
, len
);
1400 * Functions to encode protocol data
1404 guint8
*buf
, *p
, *end
;
1408 buffer_init (Buffer
*buf
, int size
)
1410 buf
->buf
= g_malloc (size
);
1412 buf
->end
= buf
->buf
+ size
;
1416 buffer_make_room (Buffer
*buf
, int size
)
1418 if (buf
->end
- buf
->p
< size
) {
1419 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1420 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1421 size
= buf
->p
- buf
->buf
;
1424 buf
->end
= buf
->buf
+ new_size
;
1429 buffer_add_byte (Buffer
*buf
, guint8 val
)
1431 buffer_make_room (buf
, 1);
1437 buffer_add_int (Buffer
*buf
, guint32 val
)
1439 buffer_make_room (buf
, 4);
1440 buf
->p
[0] = (val
>> 24) & 0xff;
1441 buf
->p
[1] = (val
>> 16) & 0xff;
1442 buf
->p
[2] = (val
>> 8) & 0xff;
1443 buf
->p
[3] = (val
>> 0) & 0xff;
1448 buffer_add_long (Buffer
*buf
, guint64 l
)
1450 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1451 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1455 buffer_add_id (Buffer
*buf
, int id
)
1457 buffer_add_int (buf
, (guint64
)id
);
1461 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1463 buffer_make_room (buf
, len
);
1464 memcpy (buf
->p
, data
, len
);
1469 buffer_add_string (Buffer
*buf
, const char *str
)
1474 buffer_add_int (buf
, 0);
1477 buffer_add_int (buf
, len
);
1478 buffer_add_data (buf
, (guint8
*)str
, len
);
1483 buffer_free (Buffer
*buf
)
1489 send_packet (int command_set
, int command
, Buffer
*data
)
1495 id
= InterlockedIncrement (&packet_id
);
1497 len
= data
->p
- data
->buf
+ 11;
1498 buffer_init (&buf
, len
);
1499 buffer_add_int (&buf
, len
);
1500 buffer_add_int (&buf
, id
);
1501 buffer_add_byte (&buf
, 0); /* flags */
1502 buffer_add_byte (&buf
, command_set
);
1503 buffer_add_byte (&buf
, command
);
1504 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1506 res
= transport_send (buf
.buf
, len
);
1514 send_reply_packet (int id
, int error
, Buffer
*data
)
1520 len
= data
->p
- data
->buf
+ 11;
1521 buffer_init (&buf
, len
);
1522 buffer_add_int (&buf
, len
);
1523 buffer_add_int (&buf
, id
);
1524 buffer_add_byte (&buf
, 0x80); /* flags */
1525 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1526 buffer_add_byte (&buf
, error
);
1527 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1529 res
= transport_send (buf
.buf
, len
);
1541 * Represents an object accessible by the debugger client.
1544 /* Unique id used in the wire protocol to refer to objects */
1547 * A weakref gc handle pointing to the object. The gc handle is used to
1548 * detect if the object was garbage collected.
1553 /* Maps objid -> ObjRef */
1554 static GHashTable
*objrefs
;
1557 free_objref (gpointer value
)
1561 mono_gchandle_free (o
->handle
);
1569 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1573 objrefs_cleanup (void)
1575 g_hash_table_destroy (objrefs
);
1579 static GHashTable
*obj_to_objref
;
1582 * Return an ObjRef for OBJ.
1585 get_objref (MonoObject
*obj
)
1588 GSList
*reflist
= NULL
, *l
;
1594 mono_loader_lock ();
1597 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1599 /* FIXME: The tables can grow indefinitely */
1601 if (mono_gc_is_moving ()) {
1603 * Objects can move, so use a hash table mapping hash codes to lists of
1604 * ObjRef structures.
1606 hash
= mono_object_hash (obj
);
1608 reflist
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (hash
));
1609 for (l
= reflist
; l
; l
= l
->next
) {
1611 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1612 mono_loader_unlock ();
1617 /* Use a hash table with masked pointers to internalize object references */
1618 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1619 /* ref might refer to a different object with the same addr which was GCd */
1620 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1621 mono_loader_unlock ();
1626 ref
= g_new0 (ObjRef
, 1);
1627 ref
->id
= InterlockedIncrement (&objref_id
);
1628 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1630 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1632 if (mono_gc_is_moving ()) {
1633 reflist
= g_slist_append (reflist
, ref
);
1634 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (hash
), reflist
);
1636 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1639 mono_loader_unlock ();
1645 get_objid (MonoObject
*obj
)
1647 return get_objref (obj
)->id
;
1651 * Set OBJ to the object identified by OBJID.
1652 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1656 get_object_allow_null (int objid
, MonoObject
**obj
)
1666 return ERR_INVALID_OBJECT
;
1668 mono_loader_lock ();
1670 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1673 *obj
= mono_gchandle_get_target (ref
->handle
);
1674 mono_loader_unlock ();
1676 return ERR_INVALID_OBJECT
;
1679 mono_loader_unlock ();
1680 return ERR_INVALID_OBJECT
;
1685 get_object (int objid
, MonoObject
**obj
)
1687 int err
= get_object_allow_null (objid
, obj
);
1692 return ERR_INVALID_OBJECT
;
1697 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1699 return decode_id (buf
, endbuf
, limit
);
1703 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1705 buffer_add_id (buf
, get_objid (o
));
1724 * Represents a runtime structure accessible to the debugger client
1727 /* Unique id used in the wire protocol */
1729 /* Domain of the runtime structure, NULL if the domain was unloaded */
1736 MonoAssembly
*assembly
;
1737 MonoClassField
*field
;
1739 MonoProperty
*property
;
1744 /* Maps runtime structure -> Id */
1745 GHashTable
*val_to_id
[ID_NUM
];
1746 /* Classes whose class load event has been sent */
1747 GHashTable
*loaded_classes
;
1751 static GPtrArray
*ids
[ID_NUM
];
1758 for (i
= 0; i
< ID_NUM
; ++i
)
1759 ids
[i
] = g_ptr_array_new ();
1767 for (i
= 0; i
< ID_NUM
; ++i
) {
1769 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1770 g_free (g_ptr_array_index (ids
[i
], j
));
1771 g_ptr_array_free (ids
[i
], TRUE
);
1778 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1780 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1784 for (i
= 0; i
< ID_NUM
; ++i
)
1785 if (info
->val_to_id
[i
])
1786 g_hash_table_destroy (info
->val_to_id
[i
]);
1787 g_hash_table_destroy (info
->loaded_classes
);
1791 domain_jit_info (domain
)->agent_info
= NULL
;
1793 /* Clear ids referencing structures in the domain */
1794 for (i
= 0; i
< ID_NUM
; ++i
) {
1796 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1797 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1798 if (id
->domain
== domain
)
1804 mono_loader_lock ();
1805 g_hash_table_remove (domains
, domain
);
1806 mono_loader_unlock ();
1809 static AgentDomainInfo
*
1810 get_agent_domain_info (MonoDomain
*domain
)
1812 AgentDomainInfo
*info
= NULL
;
1814 mono_domain_lock (domain
);
1816 info
= domain_jit_info (domain
)->agent_info
;
1818 info
= domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1819 info
->loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1822 mono_domain_unlock (domain
);
1828 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1831 AgentDomainInfo
*info
;
1836 mono_loader_lock ();
1838 mono_domain_lock (domain
);
1840 info
= get_agent_domain_info (domain
);
1842 if (info
->val_to_id
[type
] == NULL
)
1843 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1845 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1847 mono_domain_unlock (domain
);
1848 mono_loader_unlock ();
1852 id
= g_new0 (Id
, 1);
1854 id
->id
= ids
[type
]->len
+ 1;
1855 id
->domain
= domain
;
1858 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1860 mono_domain_unlock (domain
);
1862 g_ptr_array_add (ids
[type
], id
);
1864 mono_loader_unlock ();
1869 static inline gpointer
1870 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1874 int id
= decode_id (buf
, endbuf
, limit
);
1883 // FIXME: error handling
1884 mono_loader_lock ();
1885 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1887 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1888 mono_loader_unlock ();
1890 if (res
->domain
== NULL
) {
1891 *err
= ERR_UNLOADED
;
1896 *domain
= res
->domain
;
1898 return res
->data
.val
;
1902 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1904 buffer_add_id (buf
, get_id (domain
, type
, val
));
1907 static inline MonoClass
*
1908 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1910 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1913 static inline MonoAssembly
*
1914 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1916 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1919 static inline MonoImage
*
1920 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1922 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1925 static inline MonoMethod
*
1926 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1928 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1931 static inline MonoClassField
*
1932 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1934 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1937 static inline MonoDomain
*
1938 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1940 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1943 static inline MonoProperty
*
1944 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1946 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1950 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1952 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1956 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1958 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1962 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1964 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1968 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1970 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1974 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1976 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1980 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1982 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1986 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1988 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1991 static void invoke_method (void);
1998 * save_thread_context:
2000 * Set CTX as the current threads context which is used for computing stack traces.
2001 * This function is signal-safe.
2004 save_thread_context (MonoContext
*ctx
)
2006 DebuggerTlsData
*tls
;
2008 tls
= mono_native_tls_get_value (debugger_tls_id
);
2012 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
2014 mono_thread_state_init_from_current (&tls
->context
);
2017 /* The number of times the runtime is suspended */
2018 static gint32 suspend_count
;
2020 /* Number of threads suspended */
2022 * If this is equal to the size of thread_to_tls, the runtime is considered
2025 static gint32 threads_suspend_count
;
2027 static mono_mutex_t suspend_mutex
;
2029 /* Cond variable used to wait for suspend_count becoming 0 */
2030 static mono_cond_t suspend_cond
;
2032 /* Semaphore used to wait for a thread becoming suspended */
2033 static MonoSemType suspend_sem
;
2038 mono_mutex_init (&suspend_mutex
, NULL
);
2039 mono_cond_init (&suspend_cond
, NULL
);
2040 MONO_SEM_INIT (&suspend_sem
, 0);
2045 StackFrameInfo last_frame
;
2046 gboolean last_frame_set
;
2049 } GetLastFrameUserData
;
2052 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2054 GetLastFrameUserData
*data
= user_data
;
2056 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
2059 if (!data
->last_frame_set
) {
2060 /* Store the last frame */
2061 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
2062 data
->last_frame_set
= TRUE
;
2065 /* Store the context/lmf for the frame above the last frame */
2066 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
2067 data
->lmf
= info
->lmf
;
2074 * mono_debugger_agent_thread_interrupt:
2076 * Called by the abort signal handler.
2077 * Should be signal safe.
2080 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
2082 DebuggerTlsData
*tls
;
2087 tls
= mono_native_tls_get_value (debugger_tls_id
);
2092 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2093 * guarantee the signal handler will be called that many times. Instead of tracking
2094 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2095 * has been requested that hasn't been handled yet, otherwise we can have threads
2096 * refuse to die when VM_EXIT is called
2098 #if defined(__APPLE__)
2099 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
2103 * We use interrupt_count to determine whenever this interrupt should be processed
2104 * by us or the normal interrupt processing code in the signal handler.
2105 * There is no race here with notify_thread (), since the signal is sent after
2106 * incrementing interrupt_count.
2108 if (tls
->interrupt_count
== 0)
2111 InterlockedDecrement (&tls
->interrupt_count
);
2114 // FIXME: Races when the thread leaves managed code before hitting a single step
2118 /* Running managed code, will be suspended by the single step code */
2119 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
2123 * Running native code, will be suspended when it returns to/enters
2124 * managed code. Treat it as already suspended.
2125 * This might interrupt the code in process_single_step_inner (), we use the
2126 * tls->suspending flag to avoid races when that happens.
2128 if (!tls
->suspended
&& !tls
->suspending
) {
2130 GetLastFrameUserData data
;
2132 // FIXME: printf is not signal safe, but this is only used during
2133 // debugger debugging
2135 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
2136 //save_thread_context (&ctx);
2139 /* Already terminated */
2143 * We are in a difficult position: we want to be able to provide stack
2144 * traces for this thread, but we can't use the current ctx+lmf, since
2145 * the thread is still running, so it might return to managed code,
2146 * making these invalid.
2147 * So we start a stack walk and save the first frame, along with the
2148 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
2149 * suspended when it returns to managed code, so the parent's ctx should
2152 data
.last_frame_set
= FALSE
;
2154 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
2155 mono_walk_stack_with_ctx (get_last_frame
, &ctx
, MONO_UNWIND_DEFAULT
, &data
);
2157 if (data
.last_frame_set
) {
2158 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
2159 g_assert (mono_thread_state_init_from_monoctx (&tls
->async_state
, sigctx
));
2160 g_assert (mono_thread_state_init_from_monoctx (&tls
->context
, sigctx
));
2162 tls
->async_state
.valid
= FALSE
;
2165 mono_memory_barrier ();
2167 tls
->suspended
= TRUE
;
2168 MONO_SEM_POST (&suspend_sem
);
2175 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
2178 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
2180 #endif /* HOST_WIN32 */
2183 * reset_native_thread_suspend_state:
2185 * Reset the suspended flag on native threads
2188 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
2190 DebuggerTlsData
*tls
= value
;
2192 if (!tls
->really_suspended
&& tls
->suspended
)
2193 tls
->suspended
= FALSE
;
2199 * Notify a thread that it needs to suspend.
2202 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
2204 MonoInternalThread
*thread
= key
;
2205 DebuggerTlsData
*tls
= value
;
2206 gsize tid
= thread
->tid
;
2208 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
2211 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2214 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2215 * guarantee the signal handler will be called that many times. Instead of tracking
2216 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2217 * has been requested that hasn't been handled yet, otherwise we can have threads
2218 * refuse to die when VM_EXIT is called
2220 #if defined(__APPLE__)
2221 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
2225 * Maybe we could use the normal interrupt infrastructure, but that does a lot
2226 * of things like breaking waits etc. which we don't want.
2228 InterlockedIncrement (&tls
->interrupt_count
);
2231 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
2233 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
2235 mono_thread_kill (thread
, mono_thread_get_abort_signal ());
2240 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2242 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2245 if (mono_loader_lock_is_owned_by_self ()) {
2247 * Shortcut for the check in suspend_current (). This speeds up processing
2248 * when executing long running code inside the loader lock, i.e. assembly load
2254 if (debugger_thread_id
== GetCurrentThreadId ())
2257 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2258 if (suspend_count
- tls
->resume_count
> 0)
2259 tls
->suspending
= TRUE
;
2261 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2263 if (suspend_count
- tls
->resume_count
== 0) {
2265 * We are executing a single threaded invoke but the single step for
2266 * suspending is still active.
2267 * FIXME: This slows down single threaded invokes.
2269 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2273 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2275 /* Can't suspend in these methods */
2276 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
2279 save_thread_context (ctx
);
2287 * Increase the suspend count of the VM. While the suspend count is greater
2288 * than 0, runtime threads are suspended at certain points during execution.
2293 mono_loader_lock ();
2295 mono_mutex_lock (&suspend_mutex
);
2299 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2301 if (suspend_count
== 1) {
2302 // FIXME: Is it safe to call this inside the lock ?
2303 start_single_stepping ();
2304 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2307 mono_mutex_unlock (&suspend_mutex
);
2309 mono_loader_unlock ();
2315 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2323 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2325 mono_loader_lock ();
2327 mono_mutex_lock (&suspend_mutex
);
2329 g_assert (suspend_count
> 0);
2332 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2334 if (suspend_count
== 0) {
2335 // FIXME: Is it safe to call this inside the lock ?
2336 stop_single_stepping ();
2337 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2340 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2341 err
= mono_cond_broadcast (&suspend_cond
);
2342 g_assert (err
== 0);
2344 mono_mutex_unlock (&suspend_mutex
);
2345 //g_assert (err == 0);
2347 mono_loader_unlock ();
2353 * Resume just one thread.
2356 resume_thread (MonoInternalThread
*thread
)
2359 DebuggerTlsData
*tls
;
2361 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2363 mono_loader_lock ();
2365 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2368 mono_mutex_lock (&suspend_mutex
);
2370 g_assert (suspend_count
> 0);
2372 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2374 tls
->resume_count
+= suspend_count
;
2377 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2378 * but only the one whose resume_count field is > 0 will be resumed.
2380 err
= mono_cond_broadcast (&suspend_cond
);
2381 g_assert (err
== 0);
2383 mono_mutex_unlock (&suspend_mutex
);
2384 //g_assert (err == 0);
2386 mono_loader_unlock ();
2390 invalidate_frames (DebuggerTlsData
*tls
)
2395 tls
= mono_native_tls_get_value (debugger_tls_id
);
2398 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2399 if (tls
->frames
[i
]->jit
)
2400 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2401 g_free (tls
->frames
[i
]);
2403 g_free (tls
->frames
);
2404 tls
->frame_count
= 0;
2411 * Suspend the current thread until the runtime is resumed. If the thread has a
2412 * pending invoke, then the invoke is executed before this function returns.
2415 suspend_current (void)
2418 DebuggerTlsData
*tls
;
2420 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2422 if (mono_loader_lock_is_owned_by_self ()) {
2424 * If we own the loader mutex, can't suspend until we release it, since the
2425 * whole runtime can deadlock otherwise.
2430 tls
= mono_native_tls_get_value (debugger_tls_id
);
2433 mono_mutex_lock (&suspend_mutex
);
2435 tls
->suspending
= FALSE
;
2436 tls
->really_suspended
= TRUE
;
2438 if (!tls
->suspended
) {
2439 tls
->suspended
= TRUE
;
2440 MONO_SEM_POST (&suspend_sem
);
2443 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2445 while (suspend_count
- tls
->resume_count
> 0) {
2447 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2449 mono_mutex_unlock (&suspend_mutex
);
2451 mono_mutex_lock (&suspend_mutex
);
2457 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2458 g_assert (err
== 0);
2462 tls
->suspended
= FALSE
;
2463 tls
->really_suspended
= FALSE
;
2465 threads_suspend_count
--;
2467 mono_mutex_unlock (&suspend_mutex
);
2469 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2471 if (tls
->pending_invoke
) {
2472 /* Save the original context */
2473 tls
->pending_invoke
->has_ctx
= TRUE
;
2474 tls
->pending_invoke
->ctx
= tls
->context
.ctx
;
2479 /* The frame info becomes invalid after a resume */
2480 tls
->context
.valid
= FALSE
;
2481 tls
->async_state
.valid
= FALSE
;
2482 invalidate_frames (NULL
);
2486 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2488 DebuggerTlsData
*tls
= value
;
2490 if (!tls
->suspended
&& !tls
->terminated
)
2491 *(int*)user_data
= *(int*)user_data
+ 1;
2495 count_threads_to_wait_for (void)
2499 mono_loader_lock ();
2500 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2501 mono_loader_unlock ();
2509 * Wait until the runtime is completely suspended.
2512 wait_for_suspend (void)
2514 int nthreads
, nwait
, err
;
2515 gboolean waited
= FALSE
;
2517 // FIXME: Threads starting/stopping ?
2518 mono_loader_lock ();
2519 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2520 mono_loader_unlock ();
2523 nwait
= count_threads_to_wait_for ();
2525 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2526 err
= MONO_SEM_WAIT (&suspend_sem
);
2527 g_assert (err
== 0);
2535 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2541 * Return whenever the runtime is suspended.
2546 return count_threads_to_wait_for () == 0;
2550 * find_seq_point_for_native_offset:
2552 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2553 * should be the location of a sequence point.
2556 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2558 MonoSeqPointInfo
*seq_points
;
2561 mono_domain_lock (domain
);
2562 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2563 mono_domain_unlock (domain
);
2564 g_assert (seq_points
);
2568 for (i
= 0; i
< seq_points
->len
; ++i
) {
2569 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2570 return &seq_points
->seq_points
[i
];
2577 * find_next_seq_point_for_native_offset:
2579 * Find the first sequence point after NATIVE_OFFSET.
2582 find_next_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2584 MonoSeqPointInfo
*seq_points
;
2587 mono_domain_lock (domain
);
2588 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2589 mono_domain_unlock (domain
);
2590 g_assert (seq_points
);
2594 for (i
= 0; i
< seq_points
->len
; ++i
) {
2595 if (seq_points
->seq_points
[i
].native_offset
>= native_offset
)
2596 return &seq_points
->seq_points
[i
];
2603 * find_prev_seq_point_for_native_offset:
2605 * Find the first sequence point before NATIVE_OFFSET.
2608 find_prev_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2610 MonoSeqPointInfo
*seq_points
;
2613 mono_domain_lock (domain
);
2614 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2615 mono_domain_unlock (domain
);
2616 g_assert (seq_points
);
2620 for (i
= seq_points
->len
- 1; i
>= 0; --i
) {
2621 if (seq_points
->seq_points
[i
].native_offset
<= native_offset
)
2622 return &seq_points
->seq_points
[i
];
2631 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2632 * should be the location of a sequence point.
2635 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2637 MonoSeqPointInfo
*seq_points
;
2640 mono_domain_lock (domain
);
2641 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2642 mono_domain_unlock (domain
);
2643 g_assert (seq_points
);
2647 for (i
= 0; i
< seq_points
->len
; ++i
) {
2648 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2649 return &seq_points
->seq_points
[i
];
2656 * compute_il_offset:
2658 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2659 * a location of a sequence point.
2660 * We use this function instead of mono_debug_il_offset_from_address () etc,
2661 * which doesn't seem to work in a lot of cases.
2664 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2666 MonoSeqPointInfo
*seq_points
;
2667 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2669 mono_domain_lock (domain
);
2670 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2671 mono_domain_unlock (domain
);
2672 g_assert (seq_points
);
2674 last_il_offset
= -1;
2676 /* Find the sequence point */
2677 for (i
= 0; i
< seq_points
->len
; ++i
) {
2678 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2679 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2681 if (seq_native_offset
> native_offset
)
2683 last_il_offset
= seq_il_offset
;
2686 return last_il_offset
;
2690 DebuggerTlsData
*tls
;
2692 } ComputeFramesUserData
;
2695 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2697 ComputeFramesUserData
*ud
= user_data
;
2699 MonoMethod
*method
, *actual_method
;
2701 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2702 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2703 /* Mark the last frame as an invoke frame */
2705 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2711 method
= info
->ji
->method
;
2713 method
= info
->method
;
2714 actual_method
= info
->actual_method
;
2716 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2719 if (info
->il_offset
== -1) {
2720 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2721 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2724 DEBUG (1, fprintf (log_file
, "\tFrame: %s:%x(%x) %d\n", mono_method_full_name (method
, TRUE
), info
->il_offset
, info
->native_offset
, info
->managed
));
2726 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2728 * mono_arch_find_jit_info () returns the context stored in the LMF for
2729 * native frames, but it should unwind once. This is why we have duplicate
2730 * frames on the stack sometimes.
2731 * !managed also seems to be set for dynamic methods.
2736 frame
= g_new0 (StackFrame
, 1);
2737 frame
->method
= method
;
2738 frame
->actual_method
= actual_method
;
2739 frame
->il_offset
= info
->il_offset
;
2740 frame
->native_offset
= info
->native_offset
;
2741 memcpy (frame
->reg_locations
, info
->reg_locations
, MONO_MAX_IREGS
* sizeof (mgreg_t
*));
2744 frame
->has_ctx
= TRUE
;
2746 frame
->domain
= info
->domain
;
2748 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2754 process_filter_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2756 ComputeFramesUserData
*ud
= user_data
;
2759 * 'tls->filter_ctx' is the location of the throw site.
2761 * mono_walk_stack() will never actually hit the throw site, but unwind
2762 * directly from the filter to the call site; we abort stack unwinding here
2763 * once this happens and resume from the throw site.
2766 if (MONO_CONTEXT_GET_SP (ctx
) >= MONO_CONTEXT_GET_SP (&ud
->tls
->filter_state
.ctx
))
2769 return process_frame (info
, ctx
, user_data
);
2773 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2775 ComputeFramesUserData user_data
;
2777 int i
, findex
, new_frame_count
;
2778 StackFrame
**new_frames
, *f
;
2779 MonoUnwindOptions opts
= MONO_UNWIND_DEFAULT
|MONO_UNWIND_REG_LOCATIONS
;
2781 // FIXME: Locking on tls
2782 if (tls
->frames
&& tls
->frames_up_to_date
)
2785 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2787 user_data
.tls
= tls
;
2788 user_data
.frames
= NULL
;
2789 if (tls
->terminated
) {
2790 tls
->frame_count
= 0;
2792 } if (!tls
->really_suspended
&& tls
->async_state
.valid
) {
2793 /* Have to use the state saved by the signal handler */
2794 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2795 mono_walk_stack_with_state (process_frame
, &tls
->async_state
, opts
, &user_data
);
2796 } else if (tls
->filter_state
.valid
) {
2798 * We are inside an exception filter.
2800 * First we add all the frames from inside the filter; 'tls->ctx' has the current context.
2802 if (tls
->context
.valid
)
2803 mono_walk_stack_with_state (process_filter_frame
, &tls
->context
, opts
, &user_data
);
2805 * After that, we resume unwinding from the location where the exception has been thrown.
2807 mono_walk_stack_with_state (process_frame
, &tls
->filter_state
, opts
, &user_data
);
2808 } else if (tls
->context
.valid
) {
2809 mono_walk_stack_with_state (process_frame
, &tls
->context
, opts
, &user_data
);
2812 tls
->frame_count
= 0;
2816 new_frame_count
= g_slist_length (user_data
.frames
);
2817 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2819 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2823 * Reuse the id for already existing stack frames, so invokes don't invalidate
2824 * the still valid stack frames.
2826 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2827 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2828 f
->id
= tls
->frames
[i
]->id
;
2833 if (i
>= tls
->frame_count
)
2834 f
->id
= InterlockedIncrement (&frame_id
);
2836 new_frames
[findex
++] = f
;
2839 g_slist_free (user_data
.frames
);
2841 invalidate_frames (tls
);
2843 tls
->frames
= new_frames
;
2844 tls
->frame_count
= new_frame_count
;
2845 tls
->frames_up_to_date
= TRUE
;
2849 * GHFunc to emit an appdomain creation event
2850 * @param key Don't care
2851 * @param value A loaded appdomain
2852 * @param user_data Don't care
2855 emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
)
2857 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, value
);
2858 g_hash_table_foreach (get_agent_domain_info (value
)->loaded_classes
, emit_type_load
, NULL
);
2862 * GHFunc to emit a thread start event
2863 * @param key A thread id
2864 * @param value A thread object
2865 * @param user_data Don't care
2868 emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
)
2870 if (GPOINTER_TO_INT (key
) != debugger_thread_id
)
2871 process_profiler_event (EVENT_KIND_THREAD_START
, value
);
2875 * GFunc to emit an assembly load event
2876 * @param value A loaded assembly
2877 * @param user_data Don't care
2880 emit_assembly_load (gpointer value
, gpointer user_data
)
2882 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, value
);
2886 * GFunc to emit a type load event
2887 * @param value A loaded type
2888 * @param user_data Don't care
2891 emit_type_load (gpointer key
, gpointer value
, gpointer user_data
)
2893 process_profiler_event (EVENT_KIND_TYPE_LOAD
, value
);
2902 * create_event_list:
2904 * Return a list of event request ids matching EVENT, starting from REQS, which
2905 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2907 * We return request ids, instead of requests, to simplify threading, since
2908 * requests could be deleted anytime when the loader lock is not held.
2909 * LOCKING: Assumes the loader lock is held.
2912 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
2915 GSList
*events
= NULL
;
2917 *suspend_policy
= SUSPEND_POLICY_NONE
;
2920 reqs
= event_requests
;
2925 for (i
= 0; i
< reqs
->len
; ++i
) {
2926 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2927 if (req
->event_kind
== event
) {
2928 gboolean filtered
= FALSE
;
2931 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2932 Modifier
*mod
= &req
->modifiers
[j
];
2934 if (mod
->kind
== MOD_KIND_COUNT
) {
2936 if (mod
->data
.count
> 0) {
2937 if (mod
->data
.count
> 0) {
2939 if (mod
->data
.count
== 0)
2943 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2944 if (mod
->data
.thread
!= mono_thread_internal_current ())
2946 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
2947 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
2949 if (ei
->caught
&& !mod
->caught
)
2951 if (!ei
->caught
&& !mod
->uncaught
)
2953 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2955 gboolean found
= FALSE
;
2956 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2959 for (k
= 0; assemblies
[k
]; ++k
)
2960 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2969 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2970 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2975 /* Send a VM START/DEATH event by default */
2976 if (event
== EVENT_KIND_VM_START
)
2977 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2978 if (event
== EVENT_KIND_VM_DEATH
)
2979 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2984 static G_GNUC_UNUSED
const char*
2985 event_to_string (EventKind event
)
2988 case EVENT_KIND_VM_START
: return "VM_START";
2989 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2990 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2991 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2992 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2993 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2994 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2995 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2996 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2997 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2998 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2999 case EVENT_KIND_STEP
: return "STEP";
3000 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
3001 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
3002 case EVENT_KIND_KEEPALIVE
: return "KEEPALIVE";
3004 g_assert_not_reached ();
3011 * Send an event to the client, suspending the vm if needed.
3012 * LOCKING: Since this can suspend the calling thread, no locks should be held
3014 * The EVENTS list is freed by this function.
3017 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
3021 MonoDomain
*domain
= mono_domain_get ();
3022 MonoThread
*thread
= NULL
;
3023 gboolean send_success
= FALSE
;
3026 DEBUG (2, fprintf (log_file
, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event
)));
3030 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
) {
3031 // FIXME: We miss those events
3032 DEBUG (2, fprintf (log_file
, "VM start event not sent yet: dropping %s\n", event_to_string (event
)));
3036 if (vm_death_event_sent
) {
3037 DEBUG (2, fprintf (log_file
, "VM death event has been sent: dropping %s\n", event_to_string (event
)));
3041 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
) {
3042 DEBUG (2, fprintf (log_file
, "Mono runtime is shutting down: dropping %s\n", event_to_string (event
)));
3047 DEBUG (2, fprintf (log_file
, "Debugger client is not connected: dropping %s\n", event_to_string (event
)));
3051 if (event
== EVENT_KIND_KEEPALIVE
)
3052 suspend_policy
= SUSPEND_POLICY_NONE
;
3057 if (agent_config
.defer
) {
3058 /* Make sure the thread id is always set when doing deferred debugging */
3059 if (debugger_thread_id
== GetCurrentThreadId ()) {
3060 /* Don't suspend on events from the debugger thread */
3061 suspend_policy
= SUSPEND_POLICY_NONE
;
3062 thread
= mono_thread_get_main ();
3064 else thread
= mono_thread_current ();
3066 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
3067 // FIXME: Send these with a NULL thread, don't suspend the current thread
3072 buffer_init (&buf
, 128);
3073 buffer_add_byte (&buf
, suspend_policy
);
3074 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
3076 for (l
= events
; l
; l
= l
->next
) {
3077 buffer_add_byte (&buf
, event
); // event kind
3078 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
3081 thread
= mono_thread_current ();
3083 if (event
== EVENT_KIND_VM_START
&& arg
!= NULL
)
3086 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
3089 case EVENT_KIND_THREAD_START
:
3090 case EVENT_KIND_THREAD_DEATH
:
3092 case EVENT_KIND_APPDOMAIN_CREATE
:
3093 case EVENT_KIND_APPDOMAIN_UNLOAD
:
3094 buffer_add_domainid (&buf
, arg
);
3096 case EVENT_KIND_METHOD_ENTRY
:
3097 case EVENT_KIND_METHOD_EXIT
:
3098 buffer_add_methodid (&buf
, domain
, arg
);
3100 case EVENT_KIND_ASSEMBLY_LOAD
:
3101 case EVENT_KIND_ASSEMBLY_UNLOAD
:
3102 buffer_add_assemblyid (&buf
, domain
, arg
);
3104 case EVENT_KIND_TYPE_LOAD
:
3105 buffer_add_typeid (&buf
, domain
, arg
);
3107 case EVENT_KIND_BREAKPOINT
:
3108 case EVENT_KIND_STEP
:
3109 buffer_add_methodid (&buf
, domain
, arg
);
3110 buffer_add_long (&buf
, il_offset
);
3112 case EVENT_KIND_VM_START
:
3113 buffer_add_domainid (&buf
, mono_get_root_domain ());
3115 case EVENT_KIND_VM_DEATH
:
3117 case EVENT_KIND_EXCEPTION
: {
3118 EventInfo
*ei
= arg
;
3119 buffer_add_objid (&buf
, ei
->exc
);
3122 case EVENT_KIND_USER_BREAK
:
3124 case EVENT_KIND_USER_LOG
: {
3125 EventInfo
*ei
= arg
;
3126 buffer_add_int (&buf
, ei
->level
);
3127 buffer_add_string (&buf
, ei
->category
? ei
->category
: "");
3128 buffer_add_string (&buf
, ei
->message
? ei
->message
: "");
3131 case EVENT_KIND_KEEPALIVE
:
3132 suspend_policy
= SUSPEND_POLICY_NONE
;
3135 g_assert_not_reached ();
3139 if (event
== EVENT_KIND_VM_START
) {
3140 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
3141 if (!agent_config
.defer
)
3142 start_debugger_thread ();
3145 if (event
== EVENT_KIND_VM_DEATH
) {
3146 vm_death_event_sent
= TRUE
;
3147 suspend_policy
= SUSPEND_POLICY_NONE
;
3150 if (mono_runtime_is_shutting_down ())
3151 suspend_policy
= SUSPEND_POLICY_NONE
;
3153 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
3155 * Save the thread context and start suspending before sending the packet,
3156 * since we could be receiving the resume request before send_packet ()
3159 save_thread_context (ctx
);
3163 send_success
= send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
3167 g_slist_free (events
);
3170 if (!send_success
) {
3171 DEBUG (2, fprintf (log_file
, "Sending command %s failed.\n", event_to_string (event
)));
3175 if (event
== EVENT_KIND_VM_START
) {
3176 vm_start_event_sent
= TRUE
;
3179 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
3182 switch (suspend_policy
) {
3183 case SUSPEND_POLICY_NONE
:
3185 case SUSPEND_POLICY_ALL
:
3188 case SUSPEND_POLICY_EVENT_THREAD
:
3192 g_assert_not_reached ();
3197 process_profiler_event (EventKind event
, gpointer arg
)
3202 mono_loader_lock ();
3203 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
3204 mono_loader_unlock ();
3206 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
3210 runtime_initialized (MonoProfiler
*prof
)
3212 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
3213 if (agent_config
.defer
)
3214 start_debugger_thread ();
3218 runtime_shutdown (MonoProfiler
*prof
)
3220 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
3222 mono_debugger_agent_cleanup ();
3226 thread_startup (MonoProfiler
*prof
, uintptr_t tid
)
3228 MonoInternalThread
*thread
= mono_thread_internal_current ();
3229 MonoInternalThread
*old_thread
;
3230 DebuggerTlsData
*tls
;
3232 if (tid
== debugger_thread_id
)
3235 g_assert (thread
->tid
== tid
);
3237 mono_loader_lock ();
3238 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3239 mono_loader_unlock ();
3241 if (thread
== old_thread
) {
3243 * For some reason, thread_startup () might be called for the same thread
3244 * multiple times (attach ?).
3246 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
3250 * thread_end () might not be called for some threads, and the tid could
3253 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
3254 mono_loader_lock ();
3255 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
3256 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
3257 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
3258 mono_loader_unlock ();
3262 tls
= mono_native_tls_get_value (debugger_tls_id
);
3264 // FIXME: Free this somewhere
3265 tls
= g_new0 (DebuggerTlsData
, 1);
3266 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
3267 MONO_GC_REGISTER_ROOT_SINGLE (tls
->thread
);
3268 tls
->thread
= thread
;
3269 mono_native_tls_set_value (debugger_tls_id
, tls
);
3271 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
3273 mono_loader_lock ();
3274 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
3275 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
3276 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
3277 mono_loader_unlock ();
3279 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
3282 * suspend_vm () could have missed this thread, so wait for a resume.
3288 thread_end (MonoProfiler
*prof
, uintptr_t tid
)
3290 MonoInternalThread
*thread
;
3291 DebuggerTlsData
*tls
= NULL
;
3293 mono_loader_lock ();
3294 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3296 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3297 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
3298 tls
->terminated
= TRUE
;
3299 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
3300 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
3301 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
3304 mono_loader_unlock ();
3306 /* We might be called for threads started before we registered the start callback */
3308 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
3309 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
3314 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
3316 mono_loader_lock ();
3317 g_hash_table_insert (domains
, domain
, domain
);
3318 mono_loader_unlock ();
3320 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
3324 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
3326 clear_breakpoints_for_domain (domain
);
3328 mono_loader_lock ();
3329 /* Invalidate each thread's frame stack */
3330 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
3331 mono_loader_unlock ();
3333 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
3337 * invalidate_each_thread:
3339 * A GHFunc to invalidate frames.
3340 * value must be a DebuggerTlsData*
3343 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
3345 invalidate_frames (value
);
3349 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
3351 /* Sent later in jit_end () */
3352 mono_loader_lock ();
3353 g_ptr_array_add (pending_assembly_loads
, assembly
);
3354 mono_loader_unlock ();
3358 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
3360 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
3362 clear_event_requests_for_assembly (assembly
);
3363 clear_types_for_assembly (assembly
);
3367 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
3369 #if defined(HOST_WIN32) && !defined(__GNUC__)
3370 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
3372 gpointer stackptr
= __builtin_frame_address (1);
3374 MonoInternalThread
*thread
= mono_thread_internal_current ();
3375 DebuggerTlsData
*tls
;
3377 mono_loader_lock ();
3379 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3380 /* Could be the debugger thread with assembly/type load hooks */
3382 tls
->invoke_addr
= stackptr
;
3384 mono_loader_unlock ();
3388 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
3391 #if defined(HOST_WIN32) && !defined(__GNUC__)
3392 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
3394 gpointer stackptr
= __builtin_frame_address (1);
3397 if (!embedding
|| ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
3401 * We need to stop single stepping when exiting a runtime invoke, since if it is
3402 * a step out, it may return to native code, and thus never end.
3404 mono_loader_lock ();
3405 ss_invoke_addr
= NULL
;
3407 for (i
= 0; i
< event_requests
->len
; ++i
) {
3408 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
3410 if (req
->event_kind
== EVENT_KIND_STEP
) {
3411 ss_destroy (req
->info
);
3412 g_ptr_array_remove_index_fast (event_requests
, i
);
3417 mono_loader_unlock ();
3421 send_type_load (MonoClass
*klass
)
3423 gboolean type_load
= FALSE
;
3424 MonoDomain
*domain
= mono_domain_get ();
3425 AgentDomainInfo
*info
= NULL
;
3427 mono_loader_lock ();
3428 mono_domain_lock (domain
);
3430 info
= get_agent_domain_info (domain
);
3432 if (!g_hash_table_lookup (info
->loaded_classes
, klass
)) {
3434 g_hash_table_insert (info
->loaded_classes
, klass
, klass
);
3437 mono_domain_unlock (domain
);
3438 mono_loader_unlock ();
3440 emit_type_load (klass
, klass
, NULL
);
3444 * Emit load events for all types currently loaded in the domain.
3445 * Takes the loader and domain locks.
3446 * user_data is unused.
3449 send_types_for_domain (MonoDomain
*domain
, void *user_data
)
3451 AgentDomainInfo
*info
= NULL
;
3453 mono_loader_lock ();
3454 mono_domain_lock (domain
);
3455 info
= get_agent_domain_info (domain
);
3457 g_hash_table_foreach (info
->loaded_classes
, emit_type_load
, NULL
);
3458 mono_domain_unlock (domain
);
3459 mono_loader_unlock ();
3463 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
3466 * We emit type load events when the first method of the type is JITted,
3467 * since the class load profiler callbacks might be called with the
3468 * loader lock held. They could also occur in the debugger thread.
3469 * Same for assembly load events.
3472 MonoAssembly
*assembly
= NULL
;
3474 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
3475 mono_loader_lock ();
3476 if (pending_assembly_loads
->len
> 0) {
3477 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
3478 g_ptr_array_remove_index (pending_assembly_loads
, 0);
3480 mono_loader_unlock ();
3483 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
3489 send_type_load (method
->klass
);
3492 add_pending_breakpoints (method
, jinfo
);
3496 * BREAKPOINTS/SINGLE STEPPING
3500 * Contains information about an inserted breakpoint.
3503 long il_offset
, native_offset
;
3507 } BreakpointInstance
;
3510 * Contains generic information about a breakpoint.
3514 * The method where the breakpoint is placed. Can be NULL in which case it
3515 * is inserted into every method. This is used to implement method entry/
3516 * exit events. Can be a generic method definition, in which case the
3517 * breakpoint is inserted into every instance.
3523 * A list of BreakpointInstance structures describing where the breakpoint
3524 * was inserted. There could be more than one because of
3525 * generics/appdomains/method entry/exit.
3527 GPtrArray
*children
;
3530 /* List of breakpoints */
3531 static GPtrArray
*breakpoints
;
3532 /* Maps breakpoint locations to the number of breakpoints at that location */
3533 static GHashTable
*bp_locs
;
3536 breakpoints_init (void)
3538 breakpoints
= g_ptr_array_new ();
3539 bp_locs
= g_hash_table_new (NULL
, NULL
);
3543 * insert_breakpoint:
3545 * Insert the breakpoint described by BP into the method described by
3549 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoDomain
*domain
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
, MonoError
*error
)
3552 gint32 il_offset
= -1, native_offset
;
3553 BreakpointInstance
*inst
;
3556 mono_error_init (error
);
3559 for (i
= 0; i
< seq_points
->len
; ++i
) {
3560 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3561 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3563 if (il_offset
== bp
->il_offset
)
3567 if (i
== seq_points
->len
) {
3568 char *s
= g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (ji
->method
, TRUE
), bp
->il_offset
, seq_points
->len
);
3570 mono_error_set_error (error
, MONO_ERROR_GENERIC
, "%s", s
);
3579 inst
= g_new0 (BreakpointInstance
, 1);
3580 inst
->native_offset
= native_offset
;
3581 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3583 inst
->domain
= domain
;
3585 mono_loader_lock ();
3587 g_ptr_array_add (bp
->children
, inst
);
3589 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3590 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3591 mono_loader_unlock ();
3594 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3595 mono_arch_set_breakpoint (ji
, inst
->ip
);
3601 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji
->method
, TRUE
), (int)il_offset
));
3605 remove_breakpoint (BreakpointInstance
*inst
)
3607 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3609 MonoJitInfo
*ji
= inst
->ji
;
3610 guint8
*ip
= inst
->ip
;
3612 mono_loader_lock ();
3613 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3614 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3615 mono_loader_unlock ();
3617 g_assert (count
> 0);
3620 mono_arch_clear_breakpoint (ji
, ip
);
3627 static inline gboolean
3628 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
3630 return (!bp
->method
|| method
== bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
));
3634 * add_pending_breakpoints:
3636 * Insert pending breakpoints into the newly JITted method METHOD.
3639 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3642 MonoSeqPointInfo
*seq_points
;
3648 domain
= mono_domain_get ();
3650 mono_loader_lock ();
3652 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3653 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3654 gboolean found
= FALSE
;
3656 if (!bp_matches_method (bp
, method
))
3659 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3660 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3667 mono_domain_lock (domain
);
3668 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3669 mono_domain_unlock (domain
);
3671 /* Could be AOT code */
3673 g_assert (seq_points
);
3675 insert_breakpoint (seq_points
, domain
, ji
, bp
, NULL
);
3679 mono_loader_unlock ();
3683 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
, MonoError
*error
)
3689 mono_error_init (error
);
3691 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3693 /* Might be AOTed code */
3694 code
= mono_aot_get_method (domain
, method
);
3696 ji
= mono_jit_info_table_find (domain
, code
);
3701 insert_breakpoint (seq_points
, domain
, ji
, bp
, error
);
3705 clear_breakpoint (MonoBreakpoint
*bp
);
3710 * Set a breakpoint at IL_OFFSET in METHOD.
3711 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3712 * METHOD can also be a generic method definition, in which case a breakpoint
3713 * is placed in all instances of the method.
3714 * If ERROR is non-NULL, then it is set and NULL is returnd if some breakpoints couldn't be
3717 static MonoBreakpoint
*
3718 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
, MonoError
*error
)
3721 GHashTableIter iter
, iter2
;
3724 MonoSeqPointInfo
*seq_points
;
3727 mono_error_init (error
);
3730 // - suspend/resume the vm to prevent code patching problems
3731 // - multiple breakpoints on the same location
3732 // - dynamic methods
3735 bp
= g_new0 (MonoBreakpoint
, 1);
3736 bp
->method
= method
;
3737 bp
->il_offset
= il_offset
;
3739 bp
->children
= g_ptr_array_new ();
3741 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
));
3743 mono_loader_lock ();
3745 g_hash_table_iter_init (&iter
, domains
);
3746 while (g_hash_table_iter_next (&iter
, (void**)&domain
, NULL
)) {
3747 mono_domain_lock (domain
);
3749 g_hash_table_iter_init (&iter2
, domain_jit_info (domain
)->seq_points
);
3750 while (g_hash_table_iter_next (&iter2
, (void**)&m
, (void**)&seq_points
)) {
3751 if (bp_matches_method (bp
, m
))
3752 set_bp_in_method (domain
, m
, seq_points
, bp
, error
);
3755 mono_domain_unlock (domain
);
3758 mono_loader_unlock ();
3760 mono_loader_lock ();
3761 g_ptr_array_add (breakpoints
, bp
);
3762 mono_loader_unlock ();
3764 if (error
&& !mono_error_ok (error
)) {
3765 clear_breakpoint (bp
);
3773 clear_breakpoint (MonoBreakpoint
*bp
)
3777 // FIXME: locking, races
3778 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3779 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3781 remove_breakpoint (inst
);
3786 mono_loader_lock ();
3787 g_ptr_array_remove (breakpoints
, bp
);
3788 mono_loader_unlock ();
3790 g_ptr_array_free (bp
->children
, TRUE
);
3795 breakpoints_cleanup (void)
3799 mono_loader_lock ();
3801 while (i
< event_requests
->len
) {
3802 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
3804 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
3805 clear_breakpoint (req
->info
);
3806 g_ptr_array_remove_index_fast (event_requests
, i
);
3813 for (i
= 0; i
< breakpoints
->len
; ++i
)
3814 g_free (g_ptr_array_index (breakpoints
, i
));
3816 g_ptr_array_free (breakpoints
, TRUE
);
3817 g_hash_table_destroy (bp_locs
);
3822 mono_loader_unlock ();
3826 * clear_breakpoints_for_domain:
3828 * Clear breakpoint instances which reference DOMAIN.
3831 clear_breakpoints_for_domain (MonoDomain
*domain
)
3835 /* This could be called after shutdown */
3839 mono_loader_lock ();
3840 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3841 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3844 while (j
< bp
->children
->len
) {
3845 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3847 if (inst
->domain
== domain
) {
3848 remove_breakpoint (inst
);
3852 g_ptr_array_remove_index_fast (bp
->children
, j
);
3858 mono_loader_unlock ();
3862 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
3864 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
3868 process_breakpoint_inner (DebuggerTlsData
*tls
)
3871 guint8
*orig_ip
, *ip
;
3872 int i
, j
, suspend_policy
;
3873 guint32 native_offset
;
3875 BreakpointInstance
*inst
;
3876 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3877 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3878 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3879 MonoContext
*ctx
= &tls
->restore_ctx
;
3881 // FIXME: Speed this up
3883 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3884 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3886 g_assert (ji
->method
);
3888 /* Compute the native offset of the breakpoint from the ip */
3889 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3890 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3891 native_offset
= ip
- (guint8
*)ji
->code_start
;
3897 * Skip the instruction causing the breakpoint signal.
3899 mono_arch_skip_breakpoint (ctx
);
3901 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3904 bp_reqs
= g_ptr_array_new ();
3905 ss_reqs
= g_ptr_array_new ();
3906 ss_reqs_orig
= g_ptr_array_new ();
3908 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3910 mono_loader_lock ();
3913 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3914 bp
= g_ptr_array_index (breakpoints
, i
);
3919 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3920 inst
= g_ptr_array_index (bp
->children
, j
);
3921 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3922 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3923 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3925 g_ptr_array_add (bp_reqs
, bp
->req
);
3930 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3931 MonoSeqPointInfo
*seq_points
;
3932 int seq_il_offset
, seq_native_offset
;
3933 MonoDomain
*domain
= mono_domain_get ();
3935 /* Maybe a method entry/exit event */
3936 mono_domain_lock (domain
);
3937 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3938 mono_domain_unlock (domain
);
3940 // FIXME: Generic sharing */
3941 mono_loader_unlock ();
3944 g_assert (seq_points
);
3946 for (i
= 0; i
< seq_points
->len
; ++i
) {
3947 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3948 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3950 if (native_offset
== seq_native_offset
) {
3951 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3952 kind
= EVENT_KIND_METHOD_ENTRY
;
3953 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3954 kind
= EVENT_KIND_METHOD_EXIT
;
3960 /* Process single step requests */
3961 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3962 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3963 SingleStepReq
*ss_req
= req
->info
;
3964 gboolean hit
= TRUE
;
3965 MonoSeqPointInfo
*info
;
3968 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3971 if (ss_req
->size
== STEP_SIZE_LINE
) {
3972 /* Have to check whenever a different source line was reached */
3973 MonoDebugMethodInfo
*minfo
;
3974 MonoDebugSourceLocation
*loc
= NULL
;
3976 minfo
= mono_debug_lookup_method (ji
->method
);
3979 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3981 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3982 /* Have to continue single stepping */
3986 ss_req
->last_method
= ji
->method
;
3987 ss_req
->last_line
= loc
->row
;
3988 mono_debug_free_source_location (loc
);
3993 g_ptr_array_add (ss_reqs
, req
);
3995 /* Start single stepping again from the current sequence point */
3996 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
, FALSE
);
3999 if (ss_reqs
->len
> 0)
4000 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
4001 if (bp_reqs
->len
> 0)
4002 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
4003 if (kind
!= EVENT_KIND_BREAKPOINT
)
4004 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
4006 mono_loader_unlock ();
4008 g_ptr_array_free (bp_reqs
, TRUE
);
4009 g_ptr_array_free (ss_reqs
, TRUE
);
4012 * FIXME: The first event will suspend, so the second will only be sent after the
4016 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
4018 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
4019 if (enter_leave_events
)
4020 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
4023 /* Process a breakpoint/single step event after resuming from a signal handler */
4025 process_signal_event (void (*func
) (DebuggerTlsData
*))
4027 DebuggerTlsData
*tls
;
4028 MonoContext orig_restore_ctx
, ctx
;
4029 static void (*restore_context
) (void *);
4031 if (!restore_context
)
4032 restore_context
= mono_get_restore_context ();
4034 tls
= mono_native_tls_get_value (debugger_tls_id
);
4035 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4036 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4037 memcpy (&tls
->restore_ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
4041 /* This is called when resuming from a signal handler, so it shouldn't return */
4042 memcpy (&ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4043 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
4044 restore_context (&ctx
);
4045 g_assert_not_reached ();
4049 process_breakpoint (void)
4051 process_signal_event (process_breakpoint_inner
);
4055 resume_from_signal_handler (void *sigctx
, void *func
)
4057 DebuggerTlsData
*tls
;
4060 /* Save the original context in TLS */
4061 // FIXME: This might not work on an altstack ?
4062 tls
= mono_native_tls_get_value (debugger_tls_id
);
4065 // FIXME: MonoContext usually doesn't include the fp registers, so these are
4066 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
4067 // clob:c could be added to op_seq_point.
4069 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
4070 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
4071 #ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
4072 mono_arch_setup_resume_sighandler_ctx (&ctx
, func
);
4074 MONO_CONTEXT_SET_IP (&ctx
, func
);
4076 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
4078 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4079 mono_ppc_set_func_into_sigctx (sigctx
, func
);
4084 mono_debugger_agent_breakpoint_hit (void *sigctx
)
4087 * We are called from a signal handler, and running code there causes all kinds of
4088 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
4089 * So set up the signal context to return to the real breakpoint handler function.
4092 resume_from_signal_handler (sigctx
, process_breakpoint
);
4096 user_break_cb (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4098 if (frame
->managed
) {
4099 *(MonoContext
*)data
= *ctx
;
4108 * Called by System.Diagnostics.Debugger:Break ().
4111 mono_debugger_agent_user_break (void)
4113 if (agent_config
.enabled
) {
4118 /* Obtain a context */
4119 MONO_CONTEXT_SET_IP (&ctx
, NULL
);
4120 mono_walk_stack_with_ctx (user_break_cb
, NULL
, 0, &ctx
);
4121 g_assert (MONO_CONTEXT_GET_IP (&ctx
) != NULL
);
4123 mono_loader_lock ();
4124 events
= create_event_list (EVENT_KIND_USER_BREAK
, NULL
, NULL
, NULL
, &suspend_policy
);
4125 mono_loader_unlock ();
4127 process_event (EVENT_KIND_USER_BREAK
, NULL
, 0, &ctx
, events
, suspend_policy
);
4134 ss_depth_to_string (StepDepth depth
)
4137 case STEP_DEPTH_OVER
:
4139 case STEP_DEPTH_OUT
:
4141 case STEP_DEPTH_INTO
:
4144 g_assert_not_reached ();
4150 process_single_step_inner (DebuggerTlsData
*tls
)
4155 int il_offset
, suspend_policy
;
4158 MonoContext
*ctx
= &tls
->restore_ctx
;
4160 // FIXME: Speed this up
4162 ip
= MONO_CONTEXT_GET_IP (ctx
);
4164 /* Skip the instruction causing the single step */
4165 mono_arch_skip_single_step (ctx
);
4167 if (suspend_count
> 0) {
4168 process_suspend (tls
, ctx
);
4173 // FIXME: A suspend race
4176 if (mono_thread_internal_current () != ss_req
->thread
)
4179 if (log_level
> 0) {
4180 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4182 DEBUG (1, fprintf (log_file
, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer
)GetCurrentThreadId (), ss_depth_to_string (ss_req
->depth
), mono_method_full_name (ji
->method
, TRUE
), MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), ss_req
->last_sp
));
4186 * We implement step over/out by single stepping until we reach the same
4187 * frame/parent frame.
4190 * - stack growing upward
4194 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
4195 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
4197 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
4200 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
4203 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4205 g_assert (ji
->method
);
4207 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
4212 * Stopping in memset makes half-initialized vtypes visible.
4213 * Stopping in memcpy makes half-copied vtypes visible.
4215 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
4219 * The ip points to the instruction causing the single step event, convert it
4220 * to the offset stored in seq_points.
4222 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4223 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
4225 g_assert_not_reached ();
4229 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
4230 * example, so do things by hand.
4232 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
4234 if (il_offset
== -1)
4237 if (ss_req
->size
== STEP_SIZE_LINE
) {
4238 /* Step until a different source line is reached */
4239 MonoDebugMethodInfo
*minfo
;
4241 minfo
= mono_debug_lookup_method (ji
->method
);
4244 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
4246 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
4247 mono_debug_free_source_location (loc
);
4252 * Step until we reach a location with line number info,
4253 * otherwise the client can't show a location.
4254 * This can happen for example with statics initialized inline
4255 * outside of a cctor.
4260 ss_req
->last_method
= ji
->method
;
4261 ss_req
->last_line
= loc
->row
;
4262 mono_debug_free_source_location (loc
);
4267 // FIXME: Has to lock earlier
4269 reqs
= g_ptr_array_new ();
4271 mono_loader_lock ();
4273 g_ptr_array_add (reqs
, ss_req
->req
);
4275 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
4277 g_ptr_array_free (reqs
, TRUE
);
4279 mono_loader_unlock ();
4281 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
4285 process_single_step (void)
4287 process_signal_event (process_single_step_inner
);
4291 * mono_debugger_agent_single_step_event:
4293 * Called from a signal handler to handle a single step event.
4296 mono_debugger_agent_single_step_event (void *sigctx
)
4298 /* Resume to process_single_step through the signal context */
4300 // FIXME: Since step out/over is implemented using step in, the step in case should
4301 // be as fast as possible. Move the relevant code from process_single_step_inner ()
4304 if (GetCurrentThreadId () == debugger_thread_id
) {
4306 * This could happen despite our best effors when the runtime calls
4307 * assembly/type resolve hooks.
4308 * FIXME: Breakpoints too.
4312 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
4313 mono_arch_skip_single_step (&ctx
);
4314 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
4318 resume_from_signal_handler (sigctx
, process_single_step
);
4322 debugger_agent_single_step_from_context (MonoContext
*ctx
)
4324 DebuggerTlsData
*tls
;
4326 tls
= mono_native_tls_get_value (debugger_tls_id
);
4328 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
4330 process_single_step_inner (tls
);
4334 debugger_agent_breakpoint_from_context (MonoContext
*ctx
)
4336 DebuggerTlsData
*tls
;
4338 tls
= mono_native_tls_get_value (debugger_tls_id
);
4340 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
4342 process_breakpoint_inner (tls
);
4346 * start_single_stepping:
4348 * Turn on single stepping. Can be called multiple times, for example,
4349 * by a single step event request + a suspend.
4352 start_single_stepping (void)
4354 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4355 int val
= InterlockedIncrement (&ss_count
);
4358 mono_arch_start_single_stepping ();
4360 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
4361 DebuggerTlsData
*tls
;
4363 mono_loader_lock ();
4365 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
4366 ss_invoke_addr
= tls
->invoke_addr
;
4368 mono_loader_unlock ();
4371 g_assert_not_reached ();
4376 stop_single_stepping (void)
4378 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4379 int val
= InterlockedDecrement (&ss_count
);
4382 mono_arch_stop_single_stepping ();
4384 g_assert_not_reached ();
4391 * Stop the single stepping operation given by SS_REQ.
4394 ss_stop (SingleStepReq
*ss_req
)
4399 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
4400 clear_breakpoint (l
->data
);
4402 g_slist_free (ss_req
->bps
);
4406 if (ss_req
->global
) {
4407 stop_single_stepping ();
4408 ss_req
->global
= FALSE
;
4415 * Start the single stepping operation given by SS_REQ from the sequence point SP.
4418 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
)
4424 /* Stop the previous operation */
4428 * Implement single stepping using breakpoints if possible.
4430 if (step_to_catch
) {
4431 bp
= set_breakpoint (method
, sp
->il_offset
, ss_req
->req
, NULL
);
4432 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
4433 } else if (ss_req
->depth
== STEP_DEPTH_OVER
) {
4436 * Find the first sequence point in the current or in a previous frame which
4437 * is not the last in its method.
4439 while (sp
&& sp
->next_len
== 0) {
4441 if (tls
&& frame_index
< tls
->frame_count
) {
4442 StackFrame
*frame
= tls
->frames
[frame_index
];
4444 method
= frame
->method
;
4445 if (frame
->il_offset
!= -1) {
4446 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
4452 if (sp
&& sp
->next_len
> 0) {
4453 for (i
= 0; i
< sp
->next_len
; ++i
) {
4454 next_sp
= &info
->seq_points
[sp
->next
[i
]];
4456 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
, NULL
);
4457 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
4463 DEBUG (1, fprintf (log_file
, "[dbg] Turning on global single stepping.\n"));
4464 ss_req
->global
= TRUE
;
4465 start_single_stepping ();
4467 ss_req
->global
= FALSE
;
4472 * Start single stepping of thread THREAD
4475 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
4477 DebuggerTlsData
*tls
;
4478 MonoSeqPointInfo
*info
= NULL
;
4479 SeqPoint
*sp
= NULL
;
4480 MonoMethod
*method
= NULL
;
4481 MonoDebugMethodInfo
*minfo
;
4482 gboolean step_to_catch
= FALSE
;
4484 if (suspend_count
== 0)
4485 return ERR_NOT_SUSPENDED
;
4487 wait_for_suspend ();
4489 // FIXME: Multiple requests
4491 DEBUG (0, fprintf (log_file
, "Received a single step request while the previous one was still active.\n"));
4492 return ERR_NOT_IMPLEMENTED
;
4495 DEBUG (1, fprintf (log_file
, "[dbg] Starting single step of thread %p (depth=%s).\n", thread
, ss_depth_to_string (depth
)));
4497 ss_req
= g_new0 (SingleStepReq
, 1);
4499 ss_req
->thread
= thread
;
4500 ss_req
->size
= size
;
4501 ss_req
->depth
= depth
;
4504 mono_loader_lock ();
4505 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4506 mono_loader_unlock ();
4508 g_assert (tls
->context
.valid
);
4509 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->context
.ctx
);
4511 if (tls
->has_catch_ctx
) {
4513 StackFrameInfo frame
;
4514 MonoContext new_ctx
;
4515 MonoLMF
*lmf
= NULL
;
4518 * We are stopped at a throw site. Stepping should go to the catch site.
4521 /* Find the the jit info for the catch context */
4522 res
= mono_find_jit_info_ext (mono_domain_get (), thread
->jit_data
, NULL
, &tls
->catch_ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
4524 g_assert (frame
.type
== FRAME_TYPE_MANAGED
);
4527 * Find the seq point corresponding to the landing site ip, which is the first seq
4530 sp
= find_next_seq_point_for_native_offset (frame
.domain
, frame
.method
, frame
.native_offset
, &info
);
4533 method
= frame
.method
;
4535 step_to_catch
= TRUE
;
4536 /* This make sure the seq point is not skipped by process_single_step () */
4537 ss_req
->last_sp
= NULL
;
4540 if (!step_to_catch
&& ss_req
->size
== STEP_SIZE_LINE
) {
4543 /* Compute the initial line info */
4544 compute_frame_info (thread
, tls
);
4546 g_assert (tls
->frame_count
);
4547 frame
= tls
->frames
[0];
4549 ss_req
->last_method
= frame
->method
;
4550 ss_req
->last_line
= -1;
4552 minfo
= mono_debug_lookup_method (frame
->method
);
4553 if (minfo
&& frame
->il_offset
!= -1) {
4554 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
4557 ss_req
->last_line
= loc
->row
;
4563 if (!step_to_catch
&& ss_req
->depth
== STEP_DEPTH_OVER
) {
4566 compute_frame_info (thread
, tls
);
4568 g_assert (tls
->frame_count
);
4569 frame
= tls
->frames
[0];
4571 if (!method
&& frame
->il_offset
!= -1) {
4572 /* FIXME: Sort the table and use a binary search */
4573 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
4575 method
= frame
->method
;
4579 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
, step_to_catch
);
4585 ss_destroy (SingleStepReq
*req
)
4588 g_assert (ss_req
== req
);
4597 * Called from metadata by the icall for System.Diagnostics.Debugger:Log ().
4600 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
4606 if (!agent_config
.enabled
)
4609 mono_loader_lock ();
4610 events
= create_event_list (EVENT_KIND_USER_LOG
, NULL
, NULL
, NULL
, &suspend_policy
);
4611 mono_loader_unlock ();
4614 ei
.category
= category
? mono_string_to_utf8 (category
) : NULL
;
4615 ei
.message
= message
? mono_string_to_utf8 (message
) : NULL
;
4617 process_event (EVENT_KIND_USER_LOG
, &ei
, 0, NULL
, events
, suspend_policy
);
4619 g_free (ei
.category
);
4620 g_free (ei
.message
);
4624 mono_debugger_agent_debug_log_is_enabled (void)
4626 /* Treat this as true even if there is no event request for EVENT_KIND_USER_LOG */
4627 return agent_config
.enabled
;
4631 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
4632 MonoContext
*catch_ctx
)
4638 DebuggerTlsData
*tls
= NULL
;
4640 if (thread_to_tls
!= NULL
) {
4641 MonoInternalThread
*thread
= mono_thread_internal_current ();
4643 mono_loader_lock ();
4644 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4645 mono_loader_unlock ();
4647 if (tls
&& tls
->abort_requested
)
4649 if (tls
&& tls
->disable_breakpoints
)
4653 memset (&ei
, 0, sizeof (EventInfo
));
4655 /* Just-In-Time debugging */
4657 if (agent_config
.onuncaught
&& !inited
) {
4658 finish_agent_init (FALSE
);
4661 * Send an unsolicited EXCEPTION event with a dummy request id.
4663 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4664 ei
.exc
= (MonoObject
*)exc
;
4665 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4668 } else if (agent_config
.onthrow
&& !inited
) {
4670 gboolean found
= FALSE
;
4672 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
4673 char *ex_type
= l
->data
;
4674 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
4676 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
4683 finish_agent_init (FALSE
);
4686 * Send an unsolicited EXCEPTION event with a dummy request id.
4688 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4689 ei
.exc
= (MonoObject
*)exc
;
4690 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4698 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
4700 ei
.exc
= (MonoObject
*)exc
;
4701 ei
.caught
= catch_ctx
!= NULL
;
4703 mono_loader_lock ();
4704 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
4705 mono_loader_unlock ();
4707 if (tls
&& catch_ctx
) {
4708 tls
->catch_ctx
= *catch_ctx
;
4709 tls
->has_catch_ctx
= TRUE
;
4712 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
4715 tls
->has_catch_ctx
= FALSE
;
4719 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
4721 DebuggerTlsData
*tls
;
4726 tls
= mono_native_tls_get_value (debugger_tls_id
);
4731 * We're about to invoke an exception filter during the first pass of exception handling.
4733 * 'ctx' is the context that'll get passed to the filter ('call_filter (ctx, ei->data.filter)'),
4734 * 'orig_ctx' is the context where the exception has been thrown.
4737 * See mcs/class/Mono.Debugger.Soft/Tests/dtest-excfilter.il for an example.
4739 * If we're stopped in Filter(), normal stack unwinding would first unwind to
4740 * the call site (line 37) and then continue to Main(), but it would never
4741 * include the throw site (line 32).
4743 * Since exception filters are invoked during the first pass of exception handling,
4744 * the stack frames of the throw site are still intact, so we should include them
4747 * We do this here by saving the context of the throw site in 'tls->filter_state'.
4749 * Exception filters are used by MonoDroid, where we want to stop inside a call filter,
4750 * but report the location of the 'throw' to the user.
4754 g_assert (mono_thread_state_init_from_monoctx (&tls
->filter_state
, orig_ctx
));
4758 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
4760 DebuggerTlsData
*tls
;
4765 tls
= mono_native_tls_get_value (debugger_tls_id
);
4769 tls
->filter_state
.valid
= FALSE
;
4773 * buffer_add_value_full:
4775 * Add the encoding of the value at ADDR described by T to the buffer.
4776 * AS_VTYPE determines whenever to treat primitive types as primitive types or
4780 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
4786 g_assert (*(void**)addr
);
4787 addr
= *(void**)addr
;
4792 case MONO_TYPE_BOOLEAN
:
4795 case MONO_TYPE_CHAR
:
4815 case MONO_TYPE_VOID
:
4816 buffer_add_byte (buf
, t
->type
);
4818 case MONO_TYPE_BOOLEAN
:
4821 buffer_add_byte (buf
, t
->type
);
4822 buffer_add_int (buf
, *(gint8
*)addr
);
4824 case MONO_TYPE_CHAR
:
4827 buffer_add_byte (buf
, t
->type
);
4828 buffer_add_int (buf
, *(gint16
*)addr
);
4833 buffer_add_byte (buf
, t
->type
);
4834 buffer_add_int (buf
, *(gint32
*)addr
);
4839 buffer_add_byte (buf
, t
->type
);
4840 buffer_add_long (buf
, *(gint64
*)addr
);
4844 /* Treat it as a vtype */
4846 case MONO_TYPE_PTR
: {
4847 gssize val
= *(gssize
*)addr
;
4849 buffer_add_byte (buf
, t
->type
);
4850 buffer_add_long (buf
, val
);
4854 case MONO_TYPE_STRING
:
4855 case MONO_TYPE_SZARRAY
:
4856 case MONO_TYPE_OBJECT
:
4857 case MONO_TYPE_CLASS
:
4858 case MONO_TYPE_ARRAY
:
4859 obj
= *(MonoObject
**)addr
;
4862 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4864 if (obj
->vtable
->klass
->valuetype
) {
4865 t
= &obj
->vtable
->klass
->byval_arg
;
4866 addr
= mono_object_unbox (obj
);
4868 } else if (obj
->vtable
->klass
->rank
) {
4869 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4870 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4871 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4873 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4875 buffer_add_objid (buf
, obj
);
4879 case MONO_TYPE_VALUETYPE
: {
4883 MonoClass
*klass
= mono_class_from_mono_type (t
);
4885 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4886 buffer_add_byte (buf
, klass
->enumtype
);
4887 buffer_add_typeid (buf
, domain
, klass
);
4891 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4892 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4894 if (mono_field_is_deleted (f
))
4898 buffer_add_int (buf
, nfields
);
4901 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4902 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4904 if (mono_field_is_deleted (f
))
4906 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4910 case MONO_TYPE_GENERICINST
:
4911 if (mono_type_generic_inst_is_valuetype (t
)) {
4923 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4925 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4929 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4932 int type
= decode_byte (buf
, &buf
, limit
);
4934 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4935 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4936 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4937 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4938 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4939 char *name
= mono_type_full_name (t
);
4940 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
4942 return ERR_INVALID_ARGUMENT
;
4946 case MONO_TYPE_BOOLEAN
:
4947 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4949 case MONO_TYPE_CHAR
:
4950 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4953 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4956 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4959 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4962 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4965 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4968 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4971 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4974 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4977 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4980 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4983 /* We send these as I8, so we get them back as such */
4984 g_assert (type
== MONO_TYPE_I8
);
4985 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4987 case MONO_TYPE_GENERICINST
:
4988 if (MONO_TYPE_ISSTRUCT (t
)) {
4989 /* The client sends these as a valuetype */
4997 /* We send these as vtypes, so we get them back as such */
4998 g_assert (type
== MONO_TYPE_VALUETYPE
);
5001 case MONO_TYPE_VALUETYPE
: {
5002 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
5006 gpointer iter
= NULL
;
5009 /* Enums are sent as a normal vtype */
5011 return ERR_NOT_IMPLEMENTED
;
5012 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
5016 if (klass
!= mono_class_from_mono_type (t
))
5017 return ERR_INVALID_ARGUMENT
;
5019 nfields
= decode_int (buf
, &buf
, limit
);
5020 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5021 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5023 if (mono_field_is_deleted (f
))
5025 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
5030 g_assert (nfields
== 0);
5035 if (MONO_TYPE_IS_REFERENCE (t
)) {
5036 if (type
== MONO_TYPE_OBJECT
) {
5037 int objid
= decode_objid (buf
, &buf
, limit
);
5041 err
= get_object (objid
, (MonoObject
**)&obj
);
5045 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
5046 return ERR_INVALID_ARGUMENT
;
5047 if (obj
&& obj
->vtable
->domain
!= domain
)
5048 return ERR_INVALID_ARGUMENT
;
5050 mono_gc_wbarrier_generic_store (addr
, obj
);
5051 } else if (type
== VALUE_TYPE_ID_NULL
) {
5052 *(MonoObject
**)addr
= NULL
;
5054 return ERR_INVALID_ARGUMENT
;
5068 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
5075 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
5076 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
5079 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
5080 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
5082 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
5084 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
5085 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
5086 addr
+= (gint32
)var
->offset
;
5088 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
5090 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
5092 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
5096 g_assert_not_reached ();
5101 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
, mgreg_t
**reg_locations
, MonoContext
*restore_ctx
)
5107 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
5108 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
5110 if (MONO_TYPE_IS_REFERENCE (t
))
5111 size
= sizeof (gpointer
);
5113 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
5116 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
: {
5117 #ifdef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
5119 gboolean is_signed
= FALSE
;
5121 if (!t
->byref
&& (t
->type
== MONO_TYPE_I1
|| t
->type
== MONO_TYPE_I2
|| t
->type
== MONO_TYPE_I4
|| t
->type
== MONO_TYPE_I8
))
5126 v
= is_signed
? *(gint8
*)val
: *(guint8
*)val
;
5129 v
= is_signed
? *(gint16
*)val
: *(guint16
*)val
;
5132 v
= is_signed
? *(gint32
*)val
: *(guint32
*)val
;
5135 v
= is_signed
? *(gint64
*)val
: *(guint64
*)val
;
5138 g_assert_not_reached ();
5141 /* Set value on the stack or in the return ctx */
5142 if (reg_locations
[reg
]) {
5143 /* Saved on the stack */
5144 DEBUG (1, fprintf (log_file
, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations
[reg
], reg
, (gpointer
)v
));
5145 *(reg_locations
[reg
]) = v
;
5148 DEBUG (1, fprintf (log_file
, "[dbg] Setting context location for reg %x to %p.\n", reg
, (gpointer
)v
));
5149 mono_arch_context_set_int_reg (restore_ctx
, reg
, v
);
5152 // FIXME: Move these to mono-context.h/c.
5153 mono_arch_context_set_int_reg (ctx
, reg
, v
);
5155 // FIXME: Can't set registers, so we disable linears
5160 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
5161 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
5162 addr
+= (gint32
)var
->offset
;
5164 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
5166 // FIXME: Write barriers
5167 memcpy (addr
, val
, size
);
5169 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
5173 g_assert_not_reached ();
5178 clear_event_request (int req_id
, int etype
)
5182 mono_loader_lock ();
5183 for (i
= 0; i
< event_requests
->len
; ++i
) {
5184 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5186 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
5187 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
5188 clear_breakpoint (req
->info
);
5189 if (req
->event_kind
== EVENT_KIND_STEP
)
5190 ss_destroy (req
->info
);
5191 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
5192 clear_breakpoint (req
->info
);
5193 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
5194 clear_breakpoint (req
->info
);
5195 g_ptr_array_remove_index_fast (event_requests
, i
);
5200 mono_loader_unlock ();
5204 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
5206 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
5207 return breakpoint_matches_assembly (req
->info
, assembly
);
5211 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
5212 Modifier
*m
= &req
->modifiers
[i
];
5214 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
5216 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
5217 for (j
= 0; m
->data
.assemblies
[j
]; ++j
)
5218 if (m
->data
.assemblies
[j
] == assembly
)
5228 * clear_event_requests_for_assembly:
5230 * Clear all events requests which reference ASSEMBLY.
5233 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
5238 mono_loader_lock ();
5242 for (i
= 0; i
< event_requests
->len
; ++i
) {
5243 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5245 if (event_req_matches_assembly (req
, assembly
)) {
5246 clear_event_request (req
->id
, req
->event_kind
);
5252 mono_loader_unlock ();
5256 * type_comes_from_assembly:
5258 * GHRFunc that returns TRUE if klass comes from assembly
5261 type_comes_from_assembly (gpointer klass
, gpointer also_klass
, gpointer assembly
)
5263 return (mono_class_get_image ((MonoClass
*)klass
) == mono_assembly_get_image ((MonoAssembly
*)assembly
));
5267 * clear_types_for_assembly:
5269 * Clears types from loaded_classes for a given assembly
5272 clear_types_for_assembly (MonoAssembly
*assembly
)
5274 MonoDomain
*domain
= mono_domain_get ();
5275 AgentDomainInfo
*info
= NULL
;
5277 mono_loader_lock ();
5278 info
= get_agent_domain_info (domain
);
5279 g_hash_table_foreach_remove (info
->loaded_classes
, type_comes_from_assembly
, assembly
);
5280 mono_loader_unlock ();
5284 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
5286 MonoInternalThread
*thread
= value
;
5287 Buffer
*buf
= user_data
;
5289 buffer_add_objid (buf
, (MonoObject
*)thread
);
5293 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
5295 guint8
*p
= invoke
->p
;
5296 guint8
*end
= invoke
->endp
;
5299 MonoMethodSignature
*sig
;
5302 MonoObject
*this, *res
, *exc
;
5305 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5309 if (invoke
->method
) {
5311 * Invoke this method directly, currently only Environment.Exit () is supported.
5314 DEBUG (1, fprintf (log_file
, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (invoke
->method
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
5315 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
5316 g_assert_not_reached ();
5319 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5322 sig
= mono_method_signature (m
);
5324 if (m
->klass
->valuetype
)
5325 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
5327 this_buf
= g_alloca (sizeof (MonoObject
*));
5328 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
5329 /* Should be null */
5330 int type
= decode_byte (p
, &p
, end
);
5331 if (type
!= VALUE_TYPE_ID_NULL
)
5332 return ERR_INVALID_ARGUMENT
;
5333 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
5335 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
5340 if (!m
->klass
->valuetype
)
5341 this = *(MonoObject
**)this_buf
;
5345 DEBUG (1, fprintf (log_file
, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (m
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
5347 if (this && this->vtable
->domain
!= domain
)
5350 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
5351 if (!strcmp (m
->name
, ".ctor")) {
5352 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
5353 return ERR_INVALID_ARGUMENT
;
5355 this = mono_object_new (domain
, m
->klass
);
5357 return ERR_INVALID_ARGUMENT
;
5361 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
5362 return ERR_INVALID_ARGUMENT
;
5364 nargs
= decode_int (p
, &p
, end
);
5365 if (nargs
!= sig
->param_count
)
5366 return ERR_INVALID_ARGUMENT
;
5367 /* Use alloca to get gc tracking */
5368 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
5369 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
5370 args
= g_alloca (nargs
* sizeof (gpointer
));
5371 for (i
= 0; i
< nargs
; ++i
) {
5372 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
5373 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
5377 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
5380 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
5381 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
5384 args
[i
] = arg_buf
[i
];
5391 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
5392 tls
->disable_breakpoints
= TRUE
;
5394 tls
->disable_breakpoints
= FALSE
;
5397 * Add an LMF frame to link the stack frames on the invoke method with our caller.
5399 /* FIXME: Move this to arch specific code */
5400 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5401 if (invoke
->has_ctx
) {
5404 lmf_addr
= mono_get_lmf_addr ();
5407 memset (&ext
, 0, sizeof (ext
));
5409 ext
.lmf
.previous_lmf
= *(lmf_addr
);
5410 /* Mark that this is a MonoLMFExt */
5411 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
5412 ext
.lmf
.rsp
= (gssize
)&ext
;
5413 #elif defined(TARGET_X86)
5414 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
5415 /* Mark that this is a MonoLMFExt */
5416 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
5417 ext
.lmf
.ebp
= (gssize
)&ext
;
5418 #elif defined(TARGET_ARM)
5419 ext
.lmf
.previous_lmf
= *(lmf_addr
);
5420 /* Mark that this is a MonoLMFExt */
5421 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
5422 #elif defined(TARGET_POWERPC)
5423 ext
.lmf
.previous_lmf
= *(lmf_addr
);
5424 /* Mark that this is a MonoLMFExt */
5425 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
5426 ext
.lmf
.ebp
= (gssize
)&ext
;
5427 #elif defined(TARGET_S390X)
5428 ext
.lmf
.previous_lmf
= *(lmf_addr
);
5429 /* Mark that this is a MonoLMFExt */
5430 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
5431 ext
.lmf
.ebp
= (gssize
)&ext
;
5433 g_assert_not_reached ();
5436 ext
.debugger_invoke
= TRUE
;
5437 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
5439 mono_set_lmf ((MonoLMF
*)&ext
);
5443 if (m
->klass
->valuetype
)
5444 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
5446 res
= mono_runtime_invoke (m
, this, args
, &exc
);
5448 buffer_add_byte (buf
, 0);
5449 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
5451 buffer_add_byte (buf
, 1);
5452 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
5453 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
5454 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
5457 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
5458 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
5459 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
5460 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
5461 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->ret
))) {
5463 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &res
, domain
);
5465 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
5468 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
5475 tls
->disable_breakpoints
= FALSE
;
5477 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5478 if (invoke
->has_ctx
)
5479 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
5482 // FIXME: byref arguments
5490 * Invoke the method given by tls->pending_invoke in the current thread.
5493 invoke_method (void)
5495 DebuggerTlsData
*tls
;
5500 static void (*restore_context
) (void *);
5501 MonoContext restore_ctx
;
5503 if (!restore_context
)
5504 restore_context
= mono_get_restore_context ();
5506 tls
= mono_native_tls_get_value (debugger_tls_id
);
5510 * Store the `InvokeData *' in `tls->invoke' until we're done with
5511 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
5514 mono_loader_lock ();
5516 invoke
= tls
->pending_invoke
;
5518 tls
->pending_invoke
= NULL
;
5520 invoke
->last_invoke
= tls
->invoke
;
5521 tls
->invoke
= invoke
;
5523 mono_loader_unlock ();
5525 tls
->frames_up_to_date
= FALSE
;
5529 buffer_init (&buf
, 128);
5531 err
= do_invoke_method (tls
, &buf
, invoke
);
5533 /* Start suspending before sending the reply */
5534 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
5537 send_reply_packet (id
, err
, &buf
);
5541 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
5543 if (invoke
->has_ctx
)
5544 save_thread_context (&restore_ctx
);
5546 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
5547 g_assert (tls
->resume_count
);
5548 tls
->resume_count
-= invoke
->suspend_count
;
5551 DEBUG (1, fprintf (log_file
, "[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
5554 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
5556 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
5557 * after the mono_runtime_invoke() already returned, but it doesn't matter
5558 * because we reset the abort here.
5561 mono_loader_lock ();
5563 if (tls
->abort_requested
)
5564 mono_thread_internal_reset_abort (tls
->thread
);
5566 tls
->invoke
= tls
->invoke
->last_invoke
;
5567 tls
->abort_requested
= FALSE
;
5569 mono_loader_unlock ();
5578 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
5580 MonoThread
*thread
= value
;
5581 DebuggerTlsData
*tls
;
5584 mono_loader_lock ();
5585 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5587 res
= tls
->really_suspended
;
5588 mono_loader_unlock ();
5594 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5597 case CMD_VM_VERSION
: {
5598 char *build_info
, *version
;
5600 build_info
= mono_get_runtime_build_info ();
5601 version
= g_strdup_printf ("mono %s", build_info
);
5603 buffer_add_string (buf
, version
); /* vm version */
5604 buffer_add_int (buf
, MAJOR_VERSION
);
5605 buffer_add_int (buf
, MINOR_VERSION
);
5606 g_free (build_info
);
5610 case CMD_VM_SET_PROTOCOL_VERSION
: {
5611 major_version
= decode_int (p
, &p
, end
);
5612 minor_version
= decode_int (p
, &p
, end
);
5613 protocol_version_set
= TRUE
;
5614 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
5617 case CMD_VM_ALL_THREADS
: {
5619 mono_loader_lock ();
5620 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
5621 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
5622 mono_loader_unlock ();
5625 case CMD_VM_SUSPEND
:
5627 wait_for_suspend ();
5630 if (suspend_count
== 0)
5631 return ERR_NOT_SUSPENDED
;
5634 case CMD_VM_DISPOSE
:
5635 /* Clear all event requests */
5636 mono_loader_lock ();
5637 while (event_requests
->len
> 0) {
5638 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
5640 clear_event_request (req
->id
, req
->event_kind
);
5642 mono_loader_unlock ();
5644 while (suspend_count
> 0)
5646 disconnected
= TRUE
;
5647 vm_start_event_sent
= FALSE
;
5650 MonoInternalThread
*thread
;
5651 DebuggerTlsData
*tls
;
5652 MonoClass
*env_class
;
5653 MonoMethod
*exit_method
= NULL
;
5657 exit_code
= decode_int (p
, &p
, end
);
5659 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
5661 /* Have to send a reply before exiting */
5662 send_reply_packet (id
, 0, buf
);
5664 /* Clear all event requests */
5665 mono_loader_lock ();
5666 while (event_requests
->len
> 0) {
5667 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
5669 clear_event_request (req
->id
, req
->event_kind
);
5671 mono_loader_unlock ();
5674 * The JDWP documentation says that the shutdown is not orderly. It doesn't
5675 * specify whenever a VM_DEATH event is sent. We currently do an orderly
5676 * shutdown by hijacking a thread to execute Environment.Exit (). This is
5677 * better than doing the shutdown ourselves, since it avoids various races.
5681 wait_for_suspend ();
5683 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
5685 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
5687 mono_loader_lock ();
5688 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
5689 mono_loader_unlock ();
5691 if (thread
&& exit_method
) {
5692 mono_loader_lock ();
5693 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5694 mono_loader_unlock ();
5696 args
= g_new0 (gpointer
, 1);
5697 args
[0] = g_malloc (sizeof (int));
5698 *(int*)(args
[0]) = exit_code
;
5700 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
5701 tls
->pending_invoke
->method
= exit_method
;
5702 tls
->pending_invoke
->args
= args
;
5704 while (suspend_count
> 0)
5708 * No thread found, do it ourselves.
5709 * FIXME: This can race with normal shutdown etc.
5711 while (suspend_count
> 0)
5714 mono_runtime_set_shutting_down ();
5716 mono_threads_set_shutting_down ();
5718 /* Suspend all managed threads since the runtime is going away */
5719 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
5720 mono_thread_suspend_all_other_threads ();
5721 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
5722 mono_runtime_quit ();
5724 shutdown (conn_fd
, SD_BOTH
);
5726 shutdown (conn_fd
, SHUT_RDWR
);
5728 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
5734 case CMD_VM_INVOKE_METHOD
: {
5735 int objid
= decode_objid (p
, &p
, end
);
5737 DebuggerTlsData
*tls
;
5740 err
= get_object (objid
, (MonoObject
**)&thread
);
5744 flags
= decode_int (p
, &p
, end
);
5746 // Wait for suspending if it already started
5748 wait_for_suspend ();
5749 if (!is_suspended ())
5750 return ERR_NOT_SUSPENDED
;
5752 mono_loader_lock ();
5753 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
5754 mono_loader_unlock ();
5757 if (!tls
->really_suspended
)
5758 /* The thread is still running native code, can't do invokes */
5759 return ERR_NOT_SUSPENDED
;
5762 * Store the invoke data into tls, the thread will execute it after it is
5765 if (tls
->pending_invoke
)
5767 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
5768 tls
->pending_invoke
->id
= id
;
5769 tls
->pending_invoke
->flags
= flags
;
5770 tls
->pending_invoke
->p
= g_malloc (end
- p
);
5771 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
5772 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
5773 tls
->pending_invoke
->suspend_count
= suspend_count
;
5775 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
5776 resume_thread (THREAD_TO_INTERNAL (thread
));
5781 case CMD_VM_ABORT_INVOKE
: {
5782 int objid
= decode_objid (p
, &p
, end
);
5784 DebuggerTlsData
*tls
;
5787 err
= get_object (objid
, (MonoObject
**)&thread
);
5791 invoke_id
= decode_int (p
, &p
, end
);
5793 mono_loader_lock ();
5794 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
5797 if (tls
->abort_requested
) {
5798 mono_loader_unlock ();
5803 * Check whether we're still inside the mono_runtime_invoke() and that it's
5804 * actually the correct invocation.
5806 * Careful, we do not stop the thread that's doing the invocation, so we can't
5807 * inspect its stack. However, invoke_method() also acquires the loader lock
5808 * when it's done, so we're safe here.
5812 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
5813 mono_loader_unlock ();
5814 return ERR_NO_INVOCATION
;
5817 tls
->abort_requested
= TRUE
;
5819 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
5820 mono_loader_unlock ();
5824 case CMD_VM_SET_KEEPALIVE
: {
5825 int timeout
= decode_int (p
, &p
, end
);
5826 agent_config
.keepalive
= timeout
;
5832 return ERR_NOT_IMPLEMENTED
;
5839 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5845 case CMD_EVENT_REQUEST_SET
: {
5847 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
5850 MonoThread
*step_thread
;
5851 int size
= 0, depth
= 0, step_thread_id
= 0;
5854 event_kind
= decode_byte (p
, &p
, end
);
5855 suspend_policy
= decode_byte (p
, &p
, end
);
5856 nmodifiers
= decode_byte (p
, &p
, end
);
5858 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
5859 req
->id
= InterlockedIncrement (&event_request_id
);
5860 req
->event_kind
= event_kind
;
5861 req
->suspend_policy
= suspend_policy
;
5862 req
->nmodifiers
= nmodifiers
;
5865 for (i
= 0; i
< nmodifiers
; ++i
) {
5866 mod
= decode_byte (p
, &p
, end
);
5868 req
->modifiers
[i
].kind
= mod
;
5869 if (mod
== MOD_KIND_COUNT
) {
5870 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
5871 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
5872 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5875 location
= decode_long (p
, &p
, end
);
5876 } else if (mod
== MOD_KIND_STEP
) {
5877 step_thread_id
= decode_id (p
, &p
, end
);
5878 size
= decode_int (p
, &p
, end
);
5879 depth
= decode_int (p
, &p
, end
);
5880 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
5881 int id
= decode_id (p
, &p
, end
);
5883 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
5888 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
5889 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5893 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
5894 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
5895 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" : ""));
5897 req
->modifiers
[i
].data
.exc_class
= exc_class
;
5899 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
5901 return ERR_INVALID_ARGUMENT
;
5904 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
5905 int n
= decode_int (p
, &p
, end
);
5908 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
5909 for (j
= 0; j
< n
; ++j
) {
5910 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5912 g_free (req
->modifiers
[i
].data
.assemblies
);
5918 return ERR_NOT_IMPLEMENTED
;
5922 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5925 req
->info
= set_breakpoint (method
, location
, req
, &error
);
5926 if (!mono_error_ok (&error
)) {
5928 DEBUG(1, fprintf (log_file
, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (&error
)));
5929 mono_error_cleanup (&error
);
5930 return ERR_NO_SEQ_POINT_AT_IL_OFFSET
;
5932 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
5933 g_assert (step_thread_id
);
5935 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
5941 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
5946 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
5947 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
, NULL
);
5948 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
5949 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
, NULL
);
5950 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
5952 if (req
->nmodifiers
) {
5954 return ERR_NOT_IMPLEMENTED
;
5958 mono_loader_lock ();
5959 g_ptr_array_add (event_requests
, req
);
5961 if (agent_config
.defer
) {
5962 /* Transmit cached data to the client on receipt of the event request */
5963 switch (req
->event_kind
) {
5964 case EVENT_KIND_APPDOMAIN_CREATE
:
5965 /* Emit load events for currently loaded domains */
5966 g_hash_table_foreach (domains
, emit_appdomain_load
, NULL
);
5968 case EVENT_KIND_ASSEMBLY_LOAD
:
5969 /* Emit load events for currently loaded assemblies */
5970 mono_assembly_foreach (emit_assembly_load
, NULL
);
5972 case EVENT_KIND_THREAD_START
:
5973 /* Emit start events for currently started threads */
5974 mono_g_hash_table_foreach (tid_to_thread
, emit_thread_start
, NULL
);
5976 case EVENT_KIND_TYPE_LOAD
:
5977 /* Emit type load events for currently loaded types */
5978 mono_domain_foreach (send_types_for_domain
, NULL
);
5984 mono_loader_unlock ();
5986 buffer_add_int (buf
, req
->id
);
5989 case CMD_EVENT_REQUEST_CLEAR
: {
5990 int etype
= decode_byte (p
, &p
, end
);
5991 int req_id
= decode_int (p
, &p
, end
);
5993 // FIXME: Make a faster mapping from req_id to request
5994 mono_loader_lock ();
5995 clear_event_request (req_id
, etype
);
5996 mono_loader_unlock ();
5999 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
6002 mono_loader_lock ();
6004 while (i
< event_requests
->len
) {
6005 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
6007 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
6008 clear_breakpoint (req
->info
);
6010 g_ptr_array_remove_index_fast (event_requests
, i
);
6016 mono_loader_unlock ();
6020 return ERR_NOT_IMPLEMENTED
;
6027 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6033 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
6034 buffer_add_domainid (buf
, mono_get_root_domain ());
6037 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
6038 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6041 buffer_add_string (buf
, domain
->friendly_name
);
6044 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
6049 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6052 mono_loader_lock ();
6054 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
6057 buffer_add_int (buf
, count
);
6058 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
6060 buffer_add_assemblyid (buf
, domain
, ass
);
6062 mono_loader_unlock ();
6065 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
6066 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6070 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
6073 case CMD_APPDOMAIN_GET_CORLIB
: {
6074 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6078 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
6081 case CMD_APPDOMAIN_CREATE_STRING
: {
6085 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6088 s
= decode_string (p
, &p
, end
);
6090 o
= mono_string_new (domain
, s
);
6091 buffer_add_objid (buf
, (MonoObject
*)o
);
6094 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
6096 MonoDomain
*domain2
;
6099 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
6102 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
6107 g_assert (domain
== domain2
);
6109 o
= mono_object_new (domain
, klass
);
6111 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
6115 buffer_add_objid (buf
, o
);
6119 return ERR_NOT_IMPLEMENTED
;
6126 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6132 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
6137 case CMD_ASSEMBLY_GET_LOCATION
: {
6138 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
6141 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
6145 if (ass
->image
->dynamic
) {
6146 buffer_add_id (buf
, 0);
6148 token
= mono_image_get_entry_point (ass
->image
);
6150 buffer_add_id (buf
, 0);
6152 m
= mono_get_method (ass
->image
, token
, NULL
);
6153 buffer_add_methodid (buf
, domain
, m
);
6158 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
6159 buffer_add_moduleid (buf
, domain
, ass
->image
);
6162 case CMD_ASSEMBLY_GET_OBJECT
: {
6163 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
6164 buffer_add_objid (buf
, o
);
6167 case CMD_ASSEMBLY_GET_TYPE
: {
6168 char *s
= decode_string (p
, &p
, end
);
6169 gboolean ignorecase
= decode_byte (p
, &p
, end
);
6170 MonoTypeNameParse info
;
6172 gboolean type_resolve
, res
;
6173 MonoDomain
*d
= mono_domain_get ();
6175 /* This is needed to be able to find referenced assemblies */
6176 res
= mono_domain_set (domain
, FALSE
);
6179 if (!mono_reflection_parse_type (s
, &info
)) {
6182 if (info
.assembly
.name
)
6184 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
6186 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
6187 mono_reflection_free_type_info (&info
);
6190 mono_domain_set (d
, TRUE
);
6194 case CMD_ASSEMBLY_GET_NAME
: {
6196 MonoAssembly
*mass
= ass
;
6198 name
= g_strdup_printf (
6199 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
6201 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
6202 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
6203 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
6204 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
6206 buffer_add_string (buf
, name
);
6211 return ERR_NOT_IMPLEMENTED
;
6218 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6224 case CMD_MODULE_GET_INFO
: {
6225 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
6228 basename
= g_path_get_basename (image
->name
);
6229 buffer_add_string (buf
, basename
); // name
6230 buffer_add_string (buf
, image
->module_name
); // scopename
6231 buffer_add_string (buf
, image
->name
); // fqname
6232 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
6233 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
6238 return ERR_NOT_IMPLEMENTED
;
6245 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
6247 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
6248 /* Special case these so the client doesn't have to handle Type objects */
6250 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
6251 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
6252 } else if (MONO_TYPE_IS_REFERENCE (t
))
6253 buffer_add_value (buf
, t
, &val
, domain
);
6255 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
6259 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
6265 buffer_add_int (buf
, 0);
6269 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
6270 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
6273 buffer_add_int (buf
, nattrs
);
6275 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
6276 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
6277 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
6278 MonoArray
*typed_args
, *named_args
;
6280 CattrNamedArg
*arginfo
;
6282 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
6284 buffer_add_methodid (buf
, domain
, attr
->ctor
);
6288 buffer_add_int (buf
, mono_array_length (typed_args
));
6289 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
6290 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
6292 t
= mono_method_signature (attr
->ctor
)->params
[j
];
6294 buffer_add_cattr_arg (buf
, t
, domain
, val
);
6297 buffer_add_int (buf
, 0);
6302 buffer_add_int (buf
, mono_array_length (named_args
));
6304 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
6305 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
6307 if (arginfo
[j
].prop
) {
6308 buffer_add_byte (buf
, 0x54);
6309 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
6310 } else if (arginfo
[j
].field
) {
6311 buffer_add_byte (buf
, 0x53);
6313 g_assert_not_reached ();
6316 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
6319 buffer_add_int (buf
, 0);
6326 type_commands_internal (int command
, MonoClass
*klass
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6336 case CMD_TYPE_GET_INFO
: {
6337 buffer_add_string (buf
, klass
->name_space
);
6338 buffer_add_string (buf
, klass
->name
);
6340 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
6341 buffer_add_string (buf
, name
);
6343 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
6344 buffer_add_moduleid (buf
, domain
, klass
->image
);
6345 buffer_add_typeid (buf
, domain
, klass
->parent
);
6346 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
6347 buffer_add_typeid (buf
, domain
, klass
->element_class
);
6349 buffer_add_id (buf
, 0);
6350 buffer_add_int (buf
, klass
->type_token
);
6351 buffer_add_byte (buf
, klass
->rank
);
6352 buffer_add_int (buf
, klass
->flags
);
6354 type
= &klass
->byval_arg
;
6355 // FIXME: Can't decide whenever a class represents a byref type
6358 if (type
->type
== MONO_TYPE_PTR
)
6360 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
6362 if (type
->type
== MONO_TYPE_VALUETYPE
)
6364 if (klass
->enumtype
)
6366 buffer_add_byte (buf
, b
);
6369 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
6371 buffer_add_int (buf
, nnested
);
6373 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
6374 buffer_add_typeid (buf
, domain
, nested
);
6377 case CMD_TYPE_GET_METHODS
: {
6380 gpointer iter
= NULL
;
6383 mono_class_setup_methods (klass
);
6385 nmethods
= mono_class_num_methods (klass
);
6387 buffer_add_int (buf
, nmethods
);
6389 while ((m
= mono_class_get_methods (klass
, &iter
))) {
6390 buffer_add_methodid (buf
, domain
, m
);
6393 g_assert (i
== nmethods
);
6396 case CMD_TYPE_GET_FIELDS
: {
6399 gpointer iter
= NULL
;
6402 nfields
= mono_class_num_fields (klass
);
6404 buffer_add_int (buf
, nfields
);
6406 while ((f
= mono_class_get_fields (klass
, &iter
))) {
6407 buffer_add_fieldid (buf
, domain
, f
);
6408 buffer_add_string (buf
, f
->name
);
6409 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
6410 buffer_add_int (buf
, f
->type
->attrs
);
6413 g_assert (i
== nfields
);
6416 case CMD_TYPE_GET_PROPERTIES
: {
6419 gpointer iter
= NULL
;
6422 nprops
= mono_class_num_properties (klass
);
6424 buffer_add_int (buf
, nprops
);
6426 while ((p
= mono_class_get_properties (klass
, &iter
))) {
6427 buffer_add_propertyid (buf
, domain
, p
);
6428 buffer_add_string (buf
, p
->name
);
6429 buffer_add_methodid (buf
, domain
, p
->get
);
6430 buffer_add_methodid (buf
, domain
, p
->set
);
6431 buffer_add_int (buf
, p
->attrs
);
6434 g_assert (i
== nprops
);
6437 case CMD_TYPE_GET_CATTRS
: {
6438 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
6439 MonoCustomAttrInfo
*cinfo
;
6441 cinfo
= mono_custom_attrs_from_class (klass
);
6443 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
6446 case CMD_TYPE_GET_FIELD_CATTRS
: {
6447 MonoClass
*attr_klass
;
6448 MonoCustomAttrInfo
*cinfo
;
6449 MonoClassField
*field
;
6451 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6454 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
6458 cinfo
= mono_custom_attrs_from_field (klass
, field
);
6460 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
6463 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
6464 MonoClass
*attr_klass
;
6465 MonoCustomAttrInfo
*cinfo
;
6468 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
6471 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
6475 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
6477 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
6480 case CMD_TYPE_GET_VALUES
:
6481 case CMD_TYPE_GET_VALUES_2
: {
6488 MonoThread
*thread_obj
;
6489 MonoInternalThread
*thread
= NULL
;
6490 guint32 special_static_type
;
6492 if (command
== CMD_TYPE_GET_VALUES_2
) {
6493 int objid
= decode_objid (p
, &p
, end
);
6496 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6500 thread
= THREAD_TO_INTERNAL (thread_obj
);
6503 len
= decode_int (p
, &p
, end
);
6504 for (i
= 0; i
< len
; ++i
) {
6505 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6509 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
6510 return ERR_INVALID_FIELDID
;
6511 special_static_type
= mono_class_field_get_special_static_type (f
);
6512 if (special_static_type
!= SPECIAL_STATIC_NONE
) {
6513 if (!(thread
&& special_static_type
== SPECIAL_STATIC_THREAD
))
6514 return ERR_INVALID_FIELDID
;
6517 /* Check that the field belongs to the object */
6519 for (k
= klass
; k
; k
= k
->parent
) {
6520 if (k
== f
->parent
) {
6526 return ERR_INVALID_FIELDID
;
6528 vtable
= mono_class_vtable (domain
, f
->parent
);
6529 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6530 mono_field_static_get_value_for_thread (thread
? thread
: mono_thread_internal_current (), vtable
, f
, val
);
6531 buffer_add_value (buf
, f
->type
, val
, domain
);
6536 case CMD_TYPE_SET_VALUES
: {
6544 len
= decode_int (p
, &p
, end
);
6545 for (i
= 0; i
< len
; ++i
) {
6546 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6550 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
6551 return ERR_INVALID_FIELDID
;
6552 if (mono_class_field_is_special_static (f
))
6553 return ERR_INVALID_FIELDID
;
6555 /* Check that the field belongs to the object */
6557 for (k
= klass
; k
; k
= k
->parent
) {
6558 if (k
== f
->parent
) {
6564 return ERR_INVALID_FIELDID
;
6566 // FIXME: Check for literal/const
6568 vtable
= mono_class_vtable (domain
, f
->parent
);
6569 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6570 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
6575 if (MONO_TYPE_IS_REFERENCE (f
->type
))
6576 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
6578 mono_field_static_set_value (vtable
, f
, val
);
6583 case CMD_TYPE_GET_OBJECT
: {
6584 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
6585 buffer_add_objid (buf
, o
);
6588 case CMD_TYPE_GET_SOURCE_FILES
:
6589 case CMD_TYPE_GET_SOURCE_FILES_2
: {
6590 gpointer iter
= NULL
;
6592 char *source_file
, *base
;
6596 files
= g_ptr_array_new ();
6598 while ((method
= mono_class_get_methods (klass
, &iter
))) {
6599 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
6602 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
6606 for (i
= 0; i
< files
->len
; ++i
)
6607 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
6609 if (i
== files
->len
)
6610 g_ptr_array_add (files
, g_strdup (source_file
));
6611 g_free (source_file
);
6615 buffer_add_int (buf
, files
->len
);
6616 for (i
= 0; i
< files
->len
; ++i
) {
6617 source_file
= g_ptr_array_index (files
, i
);
6618 if (command
== CMD_TYPE_GET_SOURCE_FILES_2
) {
6619 buffer_add_string (buf
, source_file
);
6621 base
= g_path_get_basename (source_file
);
6622 buffer_add_string (buf
, base
);
6625 g_free (source_file
);
6627 g_ptr_array_free (files
, TRUE
);
6630 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
6631 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
6635 if (mono_class_is_assignable_from (klass
, oklass
))
6636 buffer_add_byte (buf
, 1);
6638 buffer_add_byte (buf
, 0);
6642 return ERR_NOT_IMPLEMENTED
;
6649 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6652 MonoDomain
*old_domain
;
6656 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
6660 old_domain
= mono_domain_get ();
6662 mono_domain_set (domain
, TRUE
);
6664 err
= type_commands_internal (command
, klass
, domain
, p
, end
, buf
);
6666 mono_domain_set (old_domain
, TRUE
);
6672 method_commands_internal (int command
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6674 MonoMethodHeader
*header
;
6677 case CMD_METHOD_GET_NAME
: {
6678 buffer_add_string (buf
, method
->name
);
6681 case CMD_METHOD_GET_DECLARING_TYPE
: {
6682 buffer_add_typeid (buf
, domain
, method
->klass
);
6685 case CMD_METHOD_GET_DEBUG_INFO
: {
6686 MonoDebugMethodInfo
*minfo
;
6688 int i
, n_il_offsets
;
6692 header
= mono_method_get_header (method
);
6694 buffer_add_int (buf
, 0);
6695 buffer_add_string (buf
, "");
6696 buffer_add_int (buf
, 0);
6700 minfo
= mono_debug_lookup_method (method
);
6702 buffer_add_int (buf
, header
->code_size
);
6703 buffer_add_string (buf
, "");
6704 buffer_add_int (buf
, 0);
6705 mono_metadata_free_mh (header
);
6709 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
6710 buffer_add_int (buf
, header
->code_size
);
6711 buffer_add_string (buf
, source_file
);
6712 buffer_add_int (buf
, n_il_offsets
);
6713 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
6714 for (i
= 0; i
< n_il_offsets
; ++i
) {
6715 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
6716 buffer_add_int (buf
, il_offsets
[i
]);
6717 buffer_add_int (buf
, line_numbers
[i
]);
6719 g_free (source_file
);
6720 g_free (il_offsets
);
6721 g_free (line_numbers
);
6722 mono_metadata_free_mh (header
);
6725 case CMD_METHOD_GET_PARAM_INFO
: {
6726 MonoMethodSignature
*sig
= mono_method_signature (method
);
6730 /* FIXME: mono_class_from_mono_type () and byrefs */
6732 /* FIXME: Use a smaller encoding */
6733 buffer_add_int (buf
, sig
->call_convention
);
6734 buffer_add_int (buf
, sig
->param_count
);
6735 buffer_add_int (buf
, sig
->generic_param_count
);
6736 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
6737 for (i
= 0; i
< sig
->param_count
; ++i
) {
6739 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
6742 /* Emit parameter names */
6743 names
= g_new (char *, sig
->param_count
);
6744 mono_method_get_param_names (method
, (const char **) names
);
6745 for (i
= 0; i
< sig
->param_count
; ++i
)
6746 buffer_add_string (buf
, names
[i
]);
6751 case CMD_METHOD_GET_LOCALS_INFO
: {
6752 int i
, j
, num_locals
;
6753 MonoDebugLocalsInfo
*locals
;
6755 header
= mono_method_get_header (method
);
6758 buffer_add_int (buf
, header
->num_locals
);
6761 for (i
= 0; i
< header
->num_locals
; ++i
)
6762 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
6765 locals
= mono_debug_lookup_locals (method
);
6767 num_locals
= locals
->num_locals
;
6770 for (i
= 0; i
< header
->num_locals
; ++i
) {
6771 for (j
= 0; j
< num_locals
; ++j
)
6772 if (locals
->locals
[j
].index
== i
)
6775 buffer_add_string (buf
, locals
->locals
[j
].name
);
6777 buffer_add_string (buf
, "");
6781 for (i
= 0; i
< header
->num_locals
; ++i
) {
6782 for (j
= 0; j
< num_locals
; ++j
)
6783 if (locals
->locals
[j
].index
== i
)
6785 if (j
< num_locals
&& locals
->locals
[j
].block
) {
6786 buffer_add_int (buf
, locals
->locals
[j
].block
->start_offset
);
6787 buffer_add_int (buf
, locals
->locals
[j
].block
->end_offset
);
6789 buffer_add_int (buf
, 0);
6790 buffer_add_int (buf
, header
->code_size
);
6793 mono_metadata_free_mh (header
);
6796 mono_debug_symfile_free_locals (locals
);
6800 case CMD_METHOD_GET_INFO
:
6801 buffer_add_int (buf
, method
->flags
);
6802 buffer_add_int (buf
, method
->iflags
);
6803 buffer_add_int (buf
, method
->token
);
6805 case CMD_METHOD_GET_BODY
: {
6808 header
= mono_method_get_header (method
);
6810 buffer_add_int (buf
, 0);
6812 buffer_add_int (buf
, header
->code_size
);
6813 for (i
= 0; i
< header
->code_size
; ++i
)
6814 buffer_add_byte (buf
, header
->code
[i
]);
6816 mono_metadata_free_mh (header
);
6819 case CMD_METHOD_RESOLVE_TOKEN
: {
6820 guint32 token
= decode_int (p
, &p
, end
);
6823 switch (mono_metadata_token_code (token
)) {
6824 case MONO_TOKEN_STRING
: {
6828 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
6831 s2
= mono_string_to_utf8 (s
);
6833 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
6834 buffer_add_string (buf
, s2
);
6840 MonoClass
*handle_class
;
6842 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
6843 val
= mono_method_get_wrapper_data (method
, token
);
6844 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
6846 if (handle_class
== NULL
) {
6847 // Can't figure out the token type
6848 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
6852 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
6856 if (handle_class
== mono_defaults
.typehandle_class
) {
6857 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
6858 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
6859 buffer_add_typeid (buf
, domain
, (MonoClass
*) val
);
6861 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
6862 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
6863 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
6864 buffer_add_fieldid (buf
, domain
, val
);
6865 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
6866 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
6867 buffer_add_methodid (buf
, domain
, val
);
6868 } else if (handle_class
== mono_defaults
.string_class
) {
6871 s
= mono_string_to_utf8 (val
);
6872 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
6873 buffer_add_string (buf
, s
);
6876 g_assert_not_reached ();
6884 return ERR_NOT_IMPLEMENTED
;
6891 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6894 MonoDomain
*old_domain
;
6898 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
6902 old_domain
= mono_domain_get ();
6904 mono_domain_set (domain
, TRUE
);
6906 err
= method_commands_internal (command
, method
, domain
, p
, end
, buf
);
6908 mono_domain_set (old_domain
, TRUE
);
6914 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6916 int objid
= decode_objid (p
, &p
, end
);
6918 MonoThread
*thread_obj
;
6919 MonoInternalThread
*thread
;
6921 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6925 thread
= THREAD_TO_INTERNAL (thread_obj
);
6928 case CMD_THREAD_GET_NAME
: {
6930 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
6933 buffer_add_int (buf
, 0);
6938 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
6940 buffer_add_int (buf
, len
);
6941 buffer_add_data (buf
, (guint8
*)name
, len
);
6946 case CMD_THREAD_GET_FRAME_INFO
: {
6947 DebuggerTlsData
*tls
;
6948 int i
, start_frame
, length
;
6950 // Wait for suspending if it already started
6952 wait_for_suspend ();
6953 if (!is_suspended ())
6954 return ERR_NOT_SUSPENDED
;
6956 start_frame
= decode_int (p
, &p
, end
);
6957 length
= decode_int (p
, &p
, end
);
6959 if (start_frame
!= 0 || length
!= -1)
6960 return ERR_NOT_IMPLEMENTED
;
6962 mono_loader_lock ();
6963 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6964 mono_loader_unlock ();
6967 compute_frame_info (thread
, tls
);
6969 buffer_add_int (buf
, tls
->frame_count
);
6970 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6971 buffer_add_int (buf
, tls
->frames
[i
]->id
);
6972 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->actual_method
);
6973 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
6975 * Instead of passing the frame type directly to the client, we associate
6976 * it with the previous frame using a set of flags. This avoids lots of
6977 * conditional code in the client, since a frame whose type isn't
6978 * FRAME_TYPE_MANAGED has no method, location, etc.
6980 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
6985 case CMD_THREAD_GET_STATE
:
6986 buffer_add_int (buf
, thread
->state
);
6988 case CMD_THREAD_GET_INFO
:
6989 buffer_add_byte (buf
, thread
->threadpool_thread
);
6991 case CMD_THREAD_GET_ID
:
6992 buffer_add_long (buf
, (guint64
)(gsize
)thread
);
6994 case CMD_THREAD_GET_TID
:
6995 buffer_add_long (buf
, (guint64
)thread
->tid
);
6998 return ERR_NOT_IMPLEMENTED
;
7005 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7009 MonoThread
*thread_obj
;
7010 MonoInternalThread
*thread
;
7011 int pos
, i
, len
, frame_idx
;
7012 DebuggerTlsData
*tls
;
7014 MonoDebugMethodJitInfo
*jit
;
7015 MonoDebugVarInfo
*var
;
7016 MonoMethodSignature
*sig
;
7018 MonoMethodHeader
*header
;
7020 objid
= decode_objid (p
, &p
, end
);
7021 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
7025 thread
= THREAD_TO_INTERNAL (thread_obj
);
7027 id
= decode_id (p
, &p
, end
);
7029 mono_loader_lock ();
7030 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
7031 mono_loader_unlock ();
7034 for (i
= 0; i
< tls
->frame_count
; ++i
) {
7035 if (tls
->frames
[i
]->id
== id
)
7038 if (i
== tls
->frame_count
)
7039 return ERR_INVALID_FRAMEID
;
7042 frame
= tls
->frames
[frame_idx
];
7044 if (!frame
->has_ctx
)
7046 return ERR_INVALID_FRAMEID
;
7049 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
7051 /* This could happen for aot images with no jit debug info */
7052 return ERR_ABSENT_INFORMATION
;
7056 sig
= mono_method_signature (frame
->actual_method
);
7059 case CMD_STACK_FRAME_GET_VALUES
: {
7060 len
= decode_int (p
, &p
, end
);
7061 header
= mono_method_get_header (frame
->actual_method
);
7063 for (i
= 0; i
< len
; ++i
) {
7064 pos
= decode_int (p
, &p
, end
);
7069 g_assert (pos
>= 0 && pos
< jit
->num_params
);
7071 var
= &jit
->params
[pos
];
7073 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
7075 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
7077 var
= &jit
->locals
[pos
];
7079 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
7082 mono_metadata_free_mh (header
);
7085 case CMD_STACK_FRAME_GET_THIS
: {
7086 if (frame
->method
->klass
->valuetype
) {
7087 if (!sig
->hasthis
) {
7088 MonoObject
*p
= NULL
;
7089 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
7091 add_var (buf
, &frame
->actual_method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
7094 if (!sig
->hasthis
) {
7095 MonoObject
*p
= NULL
;
7096 buffer_add_value (buf
, &frame
->actual_method
->klass
->byval_arg
, &p
, frame
->domain
);
7098 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
7103 case CMD_STACK_FRAME_SET_VALUES
: {
7106 MonoDebugVarInfo
*var
;
7108 len
= decode_int (p
, &p
, end
);
7109 header
= mono_method_get_header (frame
->actual_method
);
7111 for (i
= 0; i
< len
; ++i
) {
7112 pos
= decode_int (p
, &p
, end
);
7117 g_assert (pos
>= 0 && pos
< jit
->num_params
);
7119 t
= sig
->params
[pos
];
7120 var
= &jit
->params
[pos
];
7122 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
7124 t
= header
->locals
[pos
];
7125 var
= &jit
->locals
[pos
];
7128 if (MONO_TYPE_IS_REFERENCE (t
))
7129 val_buf
= g_alloca (sizeof (MonoObject
*));
7131 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
7132 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
7136 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
, frame
->reg_locations
, &tls
->restore_ctx
);
7138 mono_metadata_free_mh (header
);
7142 return ERR_NOT_IMPLEMENTED
;
7149 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7152 int objid
, err
, index
, len
, i
, esize
;
7155 objid
= decode_objid (p
, &p
, end
);
7156 err
= get_object (objid
, (MonoObject
**)&arr
);
7161 case CMD_ARRAY_REF_GET_LENGTH
:
7162 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
7164 buffer_add_int (buf
, arr
->max_length
);
7165 buffer_add_int (buf
, 0);
7167 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
7168 buffer_add_int (buf
, arr
->bounds
[i
].length
);
7169 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
7173 case CMD_ARRAY_REF_GET_VALUES
:
7174 index
= decode_int (p
, &p
, end
);
7175 len
= decode_int (p
, &p
, end
);
7177 g_assert (index
>= 0 && len
>= 0);
7178 // Reordered to avoid integer overflow
7179 g_assert (!(index
> arr
->max_length
- len
));
7181 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
7182 for (i
= index
; i
< index
+ len
; ++i
) {
7183 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
7184 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
7187 case CMD_ARRAY_REF_SET_VALUES
:
7188 index
= decode_int (p
, &p
, end
);
7189 len
= decode_int (p
, &p
, end
);
7191 g_assert (index
>= 0 && len
>= 0);
7192 // Reordered to avoid integer overflow
7193 g_assert (!(index
> arr
->max_length
- len
));
7195 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
7196 for (i
= index
; i
< index
+ len
; ++i
) {
7197 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
7199 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
7203 return ERR_NOT_IMPLEMENTED
;
7210 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7216 objid
= decode_objid (p
, &p
, end
);
7217 err
= get_object (objid
, (MonoObject
**)&str
);
7222 case CMD_STRING_REF_GET_VALUE
:
7223 s
= mono_string_to_utf8 (str
);
7224 buffer_add_string (buf
, s
);
7228 return ERR_NOT_IMPLEMENTED
;
7235 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7244 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
7245 objid
= decode_objid (p
, &p
, end
);
7246 err
= get_object (objid
, &obj
);
7248 buffer_add_int (buf
, 1);
7250 buffer_add_int (buf
, 0);
7254 objid
= decode_objid (p
, &p
, end
);
7255 err
= get_object (objid
, &obj
);
7260 case CMD_OBJECT_REF_GET_TYPE
:
7261 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
7263 case CMD_OBJECT_REF_GET_VALUES
:
7264 len
= decode_int (p
, &p
, end
);
7266 for (i
= 0; i
< len
; ++i
) {
7267 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7271 /* Check that the field belongs to the object */
7273 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
7274 if (k
== f
->parent
) {
7280 return ERR_INVALID_FIELDID
;
7282 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
7286 if (mono_class_field_is_special_static (f
))
7287 return ERR_INVALID_FIELDID
;
7289 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
7290 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
7291 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
7292 mono_field_static_get_value (vtable
, f
, val
);
7293 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
7296 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
7300 case CMD_OBJECT_REF_SET_VALUES
:
7301 len
= decode_int (p
, &p
, end
);
7303 for (i
= 0; i
< len
; ++i
) {
7304 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7308 /* Check that the field belongs to the object */
7310 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
7311 if (k
== f
->parent
) {
7317 return ERR_INVALID_FIELDID
;
7319 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
7323 if (mono_class_field_is_special_static (f
))
7324 return ERR_INVALID_FIELDID
;
7326 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
7327 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
7329 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
7330 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
7335 mono_field_static_set_value (vtable
, f
, val
);
7338 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
7344 case CMD_OBJECT_REF_GET_ADDRESS
:
7345 buffer_add_long (buf
, (gssize
)obj
);
7347 case CMD_OBJECT_REF_GET_DOMAIN
:
7348 buffer_add_domainid (buf
, obj
->vtable
->domain
);
7351 return ERR_NOT_IMPLEMENTED
;
7358 command_set_to_string (CommandSet command_set
)
7360 switch (command_set
) {
7363 case CMD_SET_OBJECT_REF
:
7364 return "OBJECT_REF";
7365 case CMD_SET_STRING_REF
:
7366 return "STRING_REF";
7367 case CMD_SET_THREAD
:
7369 case CMD_SET_ARRAY_REF
:
7371 case CMD_SET_EVENT_REQUEST
:
7372 return "EVENT_REQUEST";
7373 case CMD_SET_STACK_FRAME
:
7374 return "STACK_FRAME";
7375 case CMD_SET_APPDOMAIN
:
7377 case CMD_SET_ASSEMBLY
:
7379 case CMD_SET_METHOD
:
7383 case CMD_SET_MODULE
:
7393 cmd_to_string (CommandSet set
, int command
)
7398 case CMD_VM_VERSION
:
7400 case CMD_VM_ALL_THREADS
:
7401 return "ALL_THREADS";
7402 case CMD_VM_SUSPEND
:
7408 case CMD_VM_DISPOSE
:
7410 case CMD_VM_INVOKE_METHOD
:
7411 return "INVOKE_METHOD";
7412 case CMD_VM_SET_PROTOCOL_VERSION
:
7413 return "SET_PROTOCOL_VERSION";
7414 case CMD_VM_ABORT_INVOKE
:
7415 return "ABORT_INVOKE";
7428 wait_for_attach (void)
7430 if (listen_fd
== -1) {
7431 DEBUG (1, fprintf (log_file
, "[dbg] Invalid listening socket\n"));
7435 /* Block and wait for client connection */
7436 conn_fd
= transport_accept (listen_fd
);
7437 DEBUG (1, fprintf (log_file
, "Accepted connection on %d\n", conn_fd
));
7438 if (conn_fd
== -1) {
7439 DEBUG (1, fprintf (log_file
, "[dbg] Bad client connection\n"));
7444 disconnected
= !transport_handshake ();
7446 DEBUG (1, fprintf (log_file
, "Transport handshake failed!\n"));
7456 * This thread handles communication with the debugger client using a JDWP
7459 static guint32 WINAPI
7460 debugger_thread (void *arg
)
7462 int res
, len
, id
, flags
, command_set
= 0, command
= 0;
7463 guint8 header
[HEADER_LENGTH
];
7464 guint8
*data
, *p
, *end
;
7468 gboolean attach_failed
= FALSE
;
7470 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
7472 debugger_thread_id
= GetCurrentThreadId ();
7474 mono_jit_thread_attach (mono_get_root_domain ());
7476 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
7478 mono_set_is_debugger_attached (TRUE
);
7480 if (agent_config
.defer
) {
7481 if (!wait_for_attach ()) {
7482 DEBUG (1, fprintf (log_file
, "[dbg] Can't attach, aborting debugger thread.\n"));
7483 attach_failed
= TRUE
; // Don't abort process when we can't listen
7485 /* Send start event to client */
7486 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_get_main ());
7490 while (!attach_failed
) {
7491 res
= recv_length (conn_fd
, header
, HEADER_LENGTH
, 0);
7493 /* This will break if the socket is closed during shutdown too */
7494 if (res
!= HEADER_LENGTH
)
7498 end
= header
+ HEADER_LENGTH
;
7500 len
= decode_int (p
, &p
, end
);
7501 id
= decode_int (p
, &p
, end
);
7502 flags
= decode_byte (p
, &p
, end
);
7503 command_set
= decode_byte (p
, &p
, end
);
7504 command
= decode_byte (p
, &p
, end
);
7506 g_assert (flags
== 0);
7509 const char *cmd_str
;
7512 cmd_str
= cmd_to_string (command_set
, command
);
7514 sprintf (cmd_num
, "%d", command
);
7518 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%s), id=%d.\n", command_set_to_string (command_set
), cmd_str
, id
));
7521 data
= g_malloc (len
- HEADER_LENGTH
);
7522 if (len
- HEADER_LENGTH
> 0)
7524 res
= recv_length (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
7525 if (res
!= len
- HEADER_LENGTH
)
7530 end
= data
+ (len
- HEADER_LENGTH
);
7532 buffer_init (&buf
, 128);
7537 /* Process the request */
7538 switch (command_set
) {
7540 err
= vm_commands (command
, id
, p
, end
, &buf
);
7541 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
7542 /* Sent after the invoke is complete */
7545 case CMD_SET_EVENT_REQUEST
:
7546 err
= event_commands (command
, p
, end
, &buf
);
7548 case CMD_SET_APPDOMAIN
:
7549 err
= domain_commands (command
, p
, end
, &buf
);
7551 case CMD_SET_ASSEMBLY
:
7552 err
= assembly_commands (command
, p
, end
, &buf
);
7554 case CMD_SET_MODULE
:
7555 err
= module_commands (command
, p
, end
, &buf
);
7558 err
= type_commands (command
, p
, end
, &buf
);
7560 case CMD_SET_METHOD
:
7561 err
= method_commands (command
, p
, end
, &buf
);
7563 case CMD_SET_THREAD
:
7564 err
= thread_commands (command
, p
, end
, &buf
);
7566 case CMD_SET_STACK_FRAME
:
7567 err
= frame_commands (command
, p
, end
, &buf
);
7569 case CMD_SET_ARRAY_REF
:
7570 err
= array_commands (command
, p
, end
, &buf
);
7572 case CMD_SET_STRING_REF
:
7573 err
= string_commands (command
, p
, end
, &buf
);
7575 case CMD_SET_OBJECT_REF
:
7576 err
= object_commands (command
, p
, end
, &buf
);
7579 err
= ERR_NOT_IMPLEMENTED
;
7583 send_reply_packet (id
, err
, &buf
);
7588 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
7592 mono_set_is_debugger_attached (FALSE
);
7594 mono_mutex_lock (&debugger_thread_exited_mutex
);
7595 debugger_thread_exited
= TRUE
;
7596 mono_cond_signal (&debugger_thread_exited_cond
);
7597 mono_mutex_unlock (&debugger_thread_exited_mutex
);
7599 DEBUG (1, fprintf (log_file
, "[dbg] Debugger thread exited.\n"));
7601 if (!attach_failed
&& command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
&& !(vm_death_event_sent
|| mono_runtime_is_shutting_down ())) {
7602 DEBUG (2, fprintf (log_file
, "[dbg] Detached - restarting clean debugger thread.\n"));
7603 start_debugger_thread ();
7609 #else /* DISABLE_DEBUGGER_AGENT */
7612 mono_debugger_agent_parse_options (char *options
)
7614 g_error ("This runtime is configured with the debugger agent disabled.");
7618 mono_debugger_agent_init (void)
7623 mono_debugger_agent_breakpoint_hit (void *sigctx
)
7628 mono_debugger_agent_single_step_event (void *sigctx
)
7633 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
7638 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
7644 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
7645 MonoContext
*catch_ctx
)
7650 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
7655 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
7660 mono_debugger_agent_user_break (void)
7666 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
7671 mono_debugger_agent_debug_log_is_enabled (void)