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 "debugger-agent.h"
78 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
79 #define DISABLE_DEBUGGER_AGENT 1
82 #ifdef DISABLE_SOFT_DEBUG
83 #define DISABLE_DEBUGGER_AGENT 1
86 #ifndef DISABLE_DEBUGGER_AGENT
87 #include <mono/io-layer/mono-mutex.h>
89 /* Definitions to make backporting to 2.6 easier */
90 //#define MonoInternalThread MonoThread
91 //#define mono_thread_internal_current mono_thread_current
92 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
115 MonoDebugMethodJitInfo
*jit
;
118 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
119 * the frame can become invalid.
124 typedef struct _InvokeData InvokeData
;
132 /* This is the context which needs to be restored after the invoke */
136 * If this is set, invoke this method with the arguments given by ARGS.
140 guint32 suspend_count
;
142 InvokeData
*last_invoke
;
149 gboolean has_context
;
150 gpointer resume_event
;
151 /* This is computed on demand when it is requested using the wire protocol */
152 /* It is freed up when the thread is resumed */
156 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
159 gboolean frames_up_to_date
;
161 * Points to data about a pending invoke which needs to be executed after the thread
164 InvokeData
*pending_invoke
;
166 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
171 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
172 * within a finite amount of time.
176 * Set to TRUE if this thread is suspended in suspend_current ().
178 gboolean really_suspended
;
179 /* Used to pass the context to the breakpoint/single step handler */
180 MonoContext handler_ctx
;
181 /* Whenever thread_stop () was called for this thread */
184 /* Number of thread interruptions not yet processed */
185 gint32 interrupt_count
;
187 /* Whenever to disable breakpoints (used during invokes) */
188 gboolean disable_breakpoints
;
191 * Number of times this thread has been resumed using resume_thread ().
193 guint32 resume_count
;
195 MonoInternalThread
*thread
;
198 * Information about the frame which transitioned to native code for running
201 StackFrameInfo async_last_frame
;
204 * The context where the stack walk can be started for running threads.
206 MonoContext async_ctx
;
208 gboolean has_async_ctx
;
211 * The lmf where the stack walk can be started for running threads.
216 * The callee address of the last mono_runtime_invoke call
218 gpointer invoke_addr
;
220 gboolean abort_requested
;
223 * The current mono_runtime_invoke invocation.
229 * Wire Protocol definitions
232 #define HEADER_LENGTH 11
234 #define MAJOR_VERSION 2
235 #define MINOR_VERSION 1
239 CMD_SET_OBJECT_REF
= 9,
240 CMD_SET_STRING_REF
= 10,
242 CMD_SET_ARRAY_REF
= 13,
243 CMD_SET_EVENT_REQUEST
= 15,
244 CMD_SET_STACK_FRAME
= 16,
245 CMD_SET_APPDOMAIN
= 20,
246 CMD_SET_ASSEMBLY
= 21,
254 EVENT_KIND_VM_START
= 0,
255 EVENT_KIND_VM_DEATH
= 1,
256 EVENT_KIND_THREAD_START
= 2,
257 EVENT_KIND_THREAD_DEATH
= 3,
258 EVENT_KIND_APPDOMAIN_CREATE
= 4,
259 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
260 EVENT_KIND_METHOD_ENTRY
= 6,
261 EVENT_KIND_METHOD_EXIT
= 7,
262 EVENT_KIND_ASSEMBLY_LOAD
= 8,
263 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
264 EVENT_KIND_BREAKPOINT
= 10,
265 EVENT_KIND_STEP
= 11,
266 EVENT_KIND_TYPE_LOAD
= 12,
267 EVENT_KIND_EXCEPTION
= 13
271 SUSPEND_POLICY_NONE
= 0,
272 SUSPEND_POLICY_EVENT_THREAD
= 1,
273 SUSPEND_POLICY_ALL
= 2
278 ERR_INVALID_OBJECT
= 20,
279 ERR_INVALID_FIELDID
= 25,
280 ERR_INVALID_FRAMEID
= 30,
281 ERR_NOT_IMPLEMENTED
= 100,
282 ERR_NOT_SUSPENDED
= 101,
283 ERR_INVALID_ARGUMENT
= 102,
285 ERR_NO_INVOCATION
= 104,
286 ERR_ABSENT_INFORMATION
= 105
291 MOD_KIND_THREAD_ONLY
= 3,
292 MOD_KIND_LOCATION_ONLY
= 7,
293 MOD_KIND_EXCEPTION_ONLY
= 8,
295 MOD_KIND_ASSEMBLY_ONLY
= 11
310 TOKEN_TYPE_STRING
= 0,
312 TOKEN_TYPE_FIELD
= 2,
313 TOKEN_TYPE_METHOD
= 3,
314 TOKEN_TYPE_UNKNOWN
= 4
318 VALUE_TYPE_ID_NULL
= 0xf0,
319 VALUE_TYPE_ID_TYPE
= 0xf1
323 FRAME_FLAG_DEBUGGER_INVOKE
= 1
327 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
328 INVOKE_FLAG_SINGLE_THREADED
= 2
333 CMD_VM_ALL_THREADS
= 2,
338 CMD_VM_INVOKE_METHOD
= 7,
339 CMD_VM_SET_PROTOCOL_VERSION
= 8,
340 CMD_VM_ABORT_INVOKE
= 9
344 CMD_THREAD_GET_FRAME_INFO
= 1,
345 CMD_THREAD_GET_NAME
= 2,
346 CMD_THREAD_GET_STATE
= 3,
347 CMD_THREAD_GET_INFO
= 4,
348 CMD_THREAD_GET_ID
= 5
352 CMD_EVENT_REQUEST_SET
= 1,
353 CMD_EVENT_REQUEST_CLEAR
= 2,
354 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
362 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
363 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
364 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
365 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
366 CMD_APPDOMAIN_CREATE_STRING
= 5,
367 CMD_APPDOMAIN_GET_CORLIB
= 6,
368 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7,
372 CMD_ASSEMBLY_GET_LOCATION
= 1,
373 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
374 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
375 CMD_ASSEMBLY_GET_OBJECT
= 4,
376 CMD_ASSEMBLY_GET_TYPE
= 5,
377 CMD_ASSEMBLY_GET_NAME
= 6
381 CMD_MODULE_GET_INFO
= 1,
385 CMD_METHOD_GET_NAME
= 1,
386 CMD_METHOD_GET_DECLARING_TYPE
= 2,
387 CMD_METHOD_GET_DEBUG_INFO
= 3,
388 CMD_METHOD_GET_PARAM_INFO
= 4,
389 CMD_METHOD_GET_LOCALS_INFO
= 5,
390 CMD_METHOD_GET_INFO
= 6,
391 CMD_METHOD_GET_BODY
= 7,
392 CMD_METHOD_RESOLVE_TOKEN
= 8,
396 CMD_TYPE_GET_INFO
= 1,
397 CMD_TYPE_GET_METHODS
= 2,
398 CMD_TYPE_GET_FIELDS
= 3,
399 CMD_TYPE_GET_VALUES
= 4,
400 CMD_TYPE_GET_OBJECT
= 5,
401 CMD_TYPE_GET_SOURCE_FILES
= 6,
402 CMD_TYPE_SET_VALUES
= 7,
403 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
404 CMD_TYPE_GET_PROPERTIES
= 9,
405 CMD_TYPE_GET_CATTRS
= 10,
406 CMD_TYPE_GET_FIELD_CATTRS
= 11,
407 CMD_TYPE_GET_PROPERTY_CATTRS
= 12,
408 CMD_TYPE_GET_SOURCE_FILES_2
= 13,
412 CMD_STACK_FRAME_GET_VALUES
= 1,
413 CMD_STACK_FRAME_GET_THIS
= 2,
414 CMD_STACK_FRAME_SET_VALUES
= 3
418 CMD_ARRAY_REF_GET_LENGTH
= 1,
419 CMD_ARRAY_REF_GET_VALUES
= 2,
420 CMD_ARRAY_REF_SET_VALUES
= 3,
424 CMD_STRING_REF_GET_VALUE
= 1,
428 CMD_OBJECT_REF_GET_TYPE
= 1,
429 CMD_OBJECT_REF_GET_VALUES
= 2,
430 CMD_OBJECT_REF_IS_COLLECTED
= 3,
431 CMD_OBJECT_REF_GET_ADDRESS
= 4,
432 CMD_OBJECT_REF_GET_DOMAIN
= 5,
433 CMD_OBJECT_REF_SET_VALUES
= 6
439 int count
; /* For kind == MOD_KIND_COUNT */
440 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
441 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
442 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
444 gboolean caught
, uncaught
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
453 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
457 * Describes a single step request.
461 MonoInternalThread
*thread
;
466 MonoMethod
*last_method
;
468 /* Whenever single stepping is performed using start/stop_single_stepping () */
470 /* The list of breakpoints used to implement step-over */
475 * Contains additional information for an event
478 /* For EVENT_KIND_EXCEPTION */
480 MonoContext catch_ctx
;
484 /* Dummy structure used for the profiler callbacks */
489 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
495 static AgentConfig agent_config
;
498 * Whenever the agent is fully initialized.
499 * When using the onuncaught or onthrow options, only some parts of the agent are
500 * initialized on startup, and the full initialization which includes connection
501 * establishment and the startup of the agent thread is only done in response to
504 static gint32 inited
;
508 static int packet_id
= 0;
510 static int objref_id
= 0;
512 static int event_request_id
= 0;
514 static int frame_id
= 0;
516 static GPtrArray
*event_requests
;
518 static guint32 debugger_tls_id
;
520 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
522 /* Maps MonoInternalThread -> DebuggerTlsData */
523 static MonoGHashTable
*thread_to_tls
;
525 /* Maps tid -> MonoInternalThread */
526 static MonoGHashTable
*tid_to_thread
;
528 /* Maps tid -> MonoThread (not MonoInternalThread) */
529 static MonoGHashTable
*tid_to_thread_obj
;
531 static gsize debugger_thread_id
;
533 static HANDLE debugger_thread_handle
;
535 static int log_level
;
537 static FILE *log_file
;
539 /* Classes whose class load event has been sent */
540 static GHashTable
*loaded_classes
;
542 /* Assemblies whose assembly load event has no been sent yet */
543 static GPtrArray
*pending_assembly_loads
;
545 /* Types whose type load event has no been sent yet */
546 static GPtrArray
*pending_type_loads
;
548 /* Whenever the debugger thread has exited */
549 static gboolean debugger_thread_exited
;
551 /* Cond variable used to wait for debugger_thread_exited becoming true */
552 static mono_cond_t debugger_thread_exited_cond
;
554 /* Mutex for the cond var above */
555 static mono_mutex_t debugger_thread_exited_mutex
;
557 static DebuggerProfiler debugger_profiler
;
559 /* The single step request instance */
560 static SingleStepReq
*ss_req
= NULL
;
561 static gpointer ss_invoke_addr
= NULL
;
563 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
564 /* Number of single stepping operations in progress */
568 /* The protocol version of the client */
569 static int major_version
, minor_version
;
571 /* Whenever the variables above are set by the client */
572 static gboolean protocol_version_set
;
574 /* A hash table containing all active domains */
575 static GHashTable
*domains
;
577 static void transport_connect (const char *host
, int port
);
579 static guint32 WINAPI
debugger_thread (void *arg
);
581 static void runtime_initialized (MonoProfiler
*prof
);
583 static void runtime_shutdown (MonoProfiler
*prof
);
585 static void thread_startup (MonoProfiler
*prof
, intptr_t tid
);
587 static void thread_end (MonoProfiler
*prof
, intptr_t tid
);
589 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
591 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
593 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
595 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
597 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
599 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
601 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
603 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
605 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
607 static void start_single_stepping (void);
609 static void stop_single_stepping (void);
611 static void suspend_current (void);
613 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
615 static void clear_breakpoints_for_domain (MonoDomain
*domain
);
617 static void clear_types_for_assembly (MonoAssembly
*assembly
);
619 /* Submodule init/cleanup */
620 static void breakpoints_init (void);
621 static void breakpoints_cleanup (void);
623 static void objrefs_init (void);
624 static void objrefs_cleanup (void);
626 static void ids_init (void);
627 static void ids_cleanup (void);
629 static void suspend_init (void);
631 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
);
632 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
633 static void ss_destroy (SingleStepReq
*req
);
635 static void start_debugger_thread (void);
637 static void finish_agent_init (gboolean on_startup
);
640 parse_address (char *address
, char **host
, int *port
)
642 char *pos
= strchr (address
, ':');
644 if (pos
== NULL
|| pos
== address
)
647 *host
= g_malloc (pos
- address
+ 1);
648 strncpy (*host
, address
, pos
- address
);
649 (*host
) [pos
- address
] = '\0';
651 *port
= atoi (pos
+ 1);
659 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
660 fprintf (stderr
, "Available options:\n");
661 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
662 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
663 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
664 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
665 fprintf (stderr
, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
666 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
667 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
671 parse_flag (const char *option
, char *flag
)
673 if (!strcmp (flag
, "y"))
675 else if (!strcmp (flag
, "n"))
678 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
685 mono_debugger_agent_parse_options (char *options
)
691 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
692 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
696 agent_config
.enabled
= TRUE
;
697 agent_config
.suspend
= TRUE
;
698 agent_config
.server
= FALSE
;
700 args
= g_strsplit (options
, ",", -1);
701 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
704 if (strncmp (arg
, "transport=", 10) == 0) {
705 agent_config
.transport
= g_strdup (arg
+ 10);
706 } else if (strncmp (arg
, "address=", 8) == 0) {
707 agent_config
.address
= g_strdup (arg
+ 8);
708 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
709 agent_config
.log_level
= atoi (arg
+ 9);
710 } else if (strncmp (arg
, "logfile=", 8) == 0) {
711 agent_config
.log_file
= g_strdup (arg
+ 8);
712 } else if (strncmp (arg
, "suspend=", 8) == 0) {
713 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
714 } else if (strncmp (arg
, "server=", 7) == 0) {
715 agent_config
.server
= parse_flag ("server", arg
+ 7);
716 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
717 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
718 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
719 /* We support multiple onthrow= options */
720 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
721 } else if (strncmp (arg
, "onthrow", 7) == 0) {
722 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
723 } else if (strncmp (arg
, "help", 4) == 0) {
726 } else if (strncmp (arg
, "timeout=", 8) == 0) {
727 agent_config
.timeout
= atoi (arg
+ 8);
728 } else if (strncmp (arg
, "launch=", 7) == 0) {
729 agent_config
.launch
= g_strdup (arg
+ 7);
736 if (agent_config
.transport
== NULL
) {
737 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
740 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
741 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
745 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
746 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
750 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
751 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
757 mono_debugger_agent_init (void)
759 if (!agent_config
.enabled
)
762 /* Need to know whenever a thread has acquired the loader mutex */
763 mono_loader_lock_track_ownership (TRUE
);
765 event_requests
= g_ptr_array_new ();
767 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
768 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
770 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
771 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
772 mono_profiler_install_runtime_initialized (runtime_initialized
);
773 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
774 mono_profiler_install_thread (thread_startup
, thread_end
);
775 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
776 mono_profiler_install_jit_end (jit_end
);
777 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
779 debugger_tls_id
= TlsAlloc ();
781 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
782 MONO_GC_REGISTER_ROOT (thread_to_tls
);
784 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
785 MONO_GC_REGISTER_ROOT (tid_to_thread
);
787 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
788 MONO_GC_REGISTER_ROOT (tid_to_thread_obj
);
790 loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
791 pending_assembly_loads
= g_ptr_array_new ();
792 pending_type_loads
= g_ptr_array_new ();
793 domains
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
795 log_level
= agent_config
.log_level
;
797 if (agent_config
.log_file
) {
798 log_file
= fopen (agent_config
.log_file
, "w+");
800 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
812 mini_get_debug_options ()->gen_seq_points
= TRUE
;
814 * This is needed because currently we don't handle liveness info.
816 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
818 /* This is needed because we can't set local variables in registers yet */
819 mono_disable_optimizations (MONO_OPT_LINEARS
);
821 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
822 finish_agent_init (TRUE
);
828 * Finish the initialization of the agent. This involves connecting the transport
829 * and starting the agent thread. This is either done at startup, or
830 * in response to some event like an unhandled exception.
833 finish_agent_init (gboolean on_startup
)
839 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
842 if (agent_config
.launch
) {
845 // FIXME: Generated address
846 // FIXME: Races with transport_connect ()
848 argv
[0] = agent_config
.launch
;
849 argv
[1] = agent_config
.transport
;
850 argv
[2] = agent_config
.address
;
853 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
855 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
860 if (agent_config
.address
) {
861 res
= parse_address (agent_config
.address
, &host
, &port
);
868 transport_connect (host
, port
);
871 /* Do some which is usually done after sending the VMStart () event */
872 vm_start_event_sent
= TRUE
;
873 start_debugger_thread ();
878 mono_debugger_agent_cleanup (void)
883 /* This will interrupt the agent thread */
884 /* Close the read part only so it can still send back replies */
886 shutdown (conn_fd
, SD_RECEIVE
);
888 shutdown (conn_fd
, SHUT_RD
);
892 * Wait for the thread to exit.
894 * If we continue with the shutdown without waiting for it, then the client might
895 * not receive an answer to its last command like a resume.
896 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
899 //WaitForSingleObject (debugger_thread_handle, INFINITE);
900 if (GetCurrentThreadId () != debugger_thread_id
) {
901 mono_mutex_lock (&debugger_thread_exited_mutex
);
902 if (!debugger_thread_exited
) {
904 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
905 mono_mutex_unlock (&debugger_thread_exited_mutex
);
907 mono_mutex_lock (&debugger_thread_exited_mutex
);
910 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
913 mono_mutex_unlock (&debugger_thread_exited_mutex
);
916 breakpoints_cleanup ();
921 shutdown (conn_fd
, SD_BOTH
);
923 shutdown (conn_fd
, SHUT_RDWR
);
926 mono_mutex_destroy (&debugger_thread_exited_mutex
);
927 mono_cond_destroy (&debugger_thread_exited_cond
);
933 * recv() + handle incomplete reads and EINTR
936 recv_length (int fd
, void *buf
, int len
, int flags
)
942 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
945 } while ((res
> 0 && total
< len
) || (res
== -1 && errno
== EINTR
));
951 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
954 transport_connect (const char *host
, int port
)
956 struct addrinfo hints
;
957 struct addrinfo
*result
, *rp
;
959 char port_string
[128];
960 char handshake_msg
[128];
966 sprintf (port_string
, "%d", port
);
968 mono_network_init ();
970 /* Obtain address(es) matching host/port */
972 memset (&hints
, 0, sizeof (struct addrinfo
));
973 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
974 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
976 hints
.ai_protocol
= 0; /* Any protocol */
978 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
980 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d: %s\n", host
, port
, gai_strerror (s
));
985 if (agent_config
.server
) {
986 /* Wait for a connection */
988 struct sockaddr_in addr
;
991 /* No address, generate one */
992 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
995 /* This will bind the socket to a random port */
996 res
= listen (sfd
, 16);
998 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno
));
1002 addrlen
= sizeof (addr
);
1003 memset (&addr
, 0, sizeof (addr
));
1004 res
= getsockname (sfd
, &addr
, &addrlen
);
1005 g_assert (res
== 0);
1008 port
= ntohs (addr
.sin_port
);
1010 /* Emit the address to stdout */
1011 /* FIXME: Should print another interface, not localhost */
1012 printf ("%s:%d\n", host
, port
);
1014 /* Listen on the provided address */
1015 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1016 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1021 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1025 res
= listen (sfd
, 16);
1033 * this function is not present on win2000 which we still support, and the
1034 * workaround described here:
1035 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1036 * only works with MSVC.
1038 freeaddrinfo (result
);
1042 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1044 if (agent_config
.timeout
) {
1049 tv
.tv_usec
= agent_config
.timeout
* 1000;
1051 FD_SET (sfd
, &readfds
);
1052 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1054 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1059 conn_fd
= accept (sfd
, NULL
, NULL
);
1060 if (conn_fd
== -1) {
1061 fprintf (stderr
, "debugger-agent: Unable to listen on %s:%d\n", host
, port
);
1065 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1067 /* Connect to the specified address */
1068 /* FIXME: Respect the timeout */
1069 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1070 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1075 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1076 break; /* Success */
1084 /* See the comment above */
1085 freeaddrinfo (result
);
1089 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1094 /* Write handshake message */
1095 sprintf (handshake_msg
, "DWP-Handshake");
1097 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1098 } while (res
== -1 && errno
== EINTR
);
1099 g_assert (res
!= -1);
1102 res
= recv_length (conn_fd
, buf
, strlen (handshake_msg
), 0);
1103 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1104 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1109 * To support older clients, the client sends its protocol version after connecting
1110 * using a command. Until that is received, default to our protocol version.
1112 major_version
= MAJOR_VERSION
;
1113 minor_version
= MINOR_VERSION
;
1114 protocol_version_set
= FALSE
;
1117 * Set TCP_NODELAY on the socket so the client receives events/command
1118 * results immediately.
1122 int result
= setsockopt(conn_fd
,
1127 g_assert (result
>= 0);
1132 transport_send (guint8
*data
, int len
)
1137 res
= send (conn_fd
, data
, len
, 0);
1138 } while (res
== -1 && errno
== EINTR
);
1146 start_debugger_thread (void)
1150 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1151 g_assert (debugger_thread_handle
);
1155 * Functions to decode protocol data
1159 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1162 g_assert (*endbuf
<= limit
);
1167 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1170 g_assert (*endbuf
<= limit
);
1172 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1175 static inline gint64
1176 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1178 guint32 high
= decode_int (buf
, &buf
, limit
);
1179 guint32 low
= decode_int (buf
, &buf
, limit
);
1183 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1187 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1189 return decode_int (buf
, endbuf
, limit
);
1193 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1195 int len
= decode_int (buf
, &buf
, limit
);
1198 s
= g_malloc (len
+ 1);
1201 memcpy (s
, buf
, len
);
1210 * Functions to encode protocol data
1214 guint8
*buf
, *p
, *end
;
1218 buffer_init (Buffer
*buf
, int size
)
1220 buf
->buf
= g_malloc (size
);
1222 buf
->end
= buf
->buf
+ size
;
1226 buffer_make_room (Buffer
*buf
, int size
)
1228 if (buf
->end
- buf
->p
< size
) {
1229 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1230 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1231 size
= buf
->p
- buf
->buf
;
1234 buf
->end
= buf
->buf
+ new_size
;
1239 buffer_add_byte (Buffer
*buf
, guint8 val
)
1241 buffer_make_room (buf
, 1);
1247 buffer_add_int (Buffer
*buf
, guint32 val
)
1249 buffer_make_room (buf
, 4);
1250 buf
->p
[0] = (val
>> 24) & 0xff;
1251 buf
->p
[1] = (val
>> 16) & 0xff;
1252 buf
->p
[2] = (val
>> 8) & 0xff;
1253 buf
->p
[3] = (val
>> 0) & 0xff;
1258 buffer_add_long (Buffer
*buf
, guint64 l
)
1260 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1261 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1265 buffer_add_id (Buffer
*buf
, int id
)
1267 buffer_add_int (buf
, (guint64
)id
);
1271 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1273 buffer_make_room (buf
, len
);
1274 memcpy (buf
->p
, data
, len
);
1279 buffer_add_string (Buffer
*buf
, const char *str
)
1284 buffer_add_int (buf
, 0);
1287 buffer_add_int (buf
, len
);
1288 buffer_add_data (buf
, (guint8
*)str
, len
);
1293 buffer_free (Buffer
*buf
)
1299 send_packet (int command_set
, int command
, Buffer
*data
)
1305 id
= InterlockedIncrement (&packet_id
);
1307 len
= data
->p
- data
->buf
+ 11;
1308 buffer_init (&buf
, len
);
1309 buffer_add_int (&buf
, len
);
1310 buffer_add_int (&buf
, id
);
1311 buffer_add_byte (&buf
, 0); /* flags */
1312 buffer_add_byte (&buf
, command_set
);
1313 buffer_add_byte (&buf
, command
);
1314 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1316 res
= transport_send (buf
.buf
, len
);
1324 send_reply_packet (int id
, int error
, Buffer
*data
)
1330 len
= data
->p
- data
->buf
+ 11;
1331 buffer_init (&buf
, len
);
1332 buffer_add_int (&buf
, len
);
1333 buffer_add_int (&buf
, id
);
1334 buffer_add_byte (&buf
, 0x80); /* flags */
1335 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1336 buffer_add_byte (&buf
, error
);
1337 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1339 res
= transport_send (buf
.buf
, len
);
1351 * Represents an object accessible by the debugger client.
1354 /* Unique id used in the wire protocol to refer to objects */
1357 * A weakref gc handle pointing to the object. The gc handle is used to
1358 * detect if the object was garbage collected.
1363 /* Maps objid -> ObjRef */
1364 static GHashTable
*objrefs
;
1367 free_objref (gpointer value
)
1371 mono_gchandle_free (o
->handle
);
1379 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1383 objrefs_cleanup (void)
1385 g_hash_table_destroy (objrefs
);
1389 static GHashTable
*obj_to_objref
;
1392 * Return an ObjRef for OBJ.
1395 get_objref (MonoObject
*obj
)
1398 GSList
*reflist
= NULL
, *l
;
1404 mono_loader_lock ();
1407 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1409 /* FIXME: The tables can grow indefinitely */
1411 if (mono_gc_is_moving ()) {
1413 * Objects can move, so use a hash table mapping hash codes to lists of
1414 * ObjRef structures.
1416 hash
= mono_object_hash (obj
);
1418 reflist
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (hash
));
1419 for (l
= reflist
; l
; l
= l
->next
) {
1421 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1422 mono_loader_unlock ();
1427 /* Use a hash table with masked pointers to internalize object references */
1428 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1429 /* ref might refer to a different object with the same addr which was GCd */
1430 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1431 mono_loader_unlock ();
1436 ref
= g_new0 (ObjRef
, 1);
1437 ref
->id
= InterlockedIncrement (&objref_id
);
1438 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1440 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1442 if (mono_gc_is_moving ()) {
1443 reflist
= g_slist_append (reflist
, ref
);
1444 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (hash
), reflist
);
1446 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1449 mono_loader_unlock ();
1455 get_objid (MonoObject
*obj
)
1457 return get_objref (obj
)->id
;
1461 * Set OBJ to the object identified by OBJID.
1462 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1466 get_object_allow_null (int objid
, MonoObject
**obj
)
1476 return ERR_INVALID_OBJECT
;
1478 mono_loader_lock ();
1480 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1483 *obj
= mono_gchandle_get_target (ref
->handle
);
1484 mono_loader_unlock ();
1486 return ERR_INVALID_OBJECT
;
1489 mono_loader_unlock ();
1490 return ERR_INVALID_OBJECT
;
1495 get_object (int objid
, MonoObject
**obj
)
1497 int err
= get_object_allow_null (objid
, obj
);
1502 return ERR_INVALID_OBJECT
;
1507 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1509 return decode_id (buf
, endbuf
, limit
);
1513 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1515 buffer_add_id (buf
, get_objid (o
));
1534 * Represents a runtime structure accessible to the debugger client
1537 /* Unique id used in the wire protocol */
1539 /* Domain of the runtime structure, NULL if the domain was unloaded */
1546 MonoAssembly
*assembly
;
1547 MonoClassField
*field
;
1549 MonoProperty
*property
;
1554 /* Maps runtime structure -> Id */
1555 GHashTable
*val_to_id
[ID_NUM
];
1559 static GPtrArray
*ids
[ID_NUM
];
1566 for (i
= 0; i
< ID_NUM
; ++i
)
1567 ids
[i
] = g_ptr_array_new ();
1575 for (i
= 0; i
< ID_NUM
; ++i
) {
1577 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1578 g_free (g_ptr_array_index (ids
[i
], j
));
1579 g_ptr_array_free (ids
[i
], TRUE
);
1586 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1588 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1592 for (i
= 0; i
< ID_NUM
; ++i
)
1593 if (info
->val_to_id
[i
])
1594 g_hash_table_destroy (info
->val_to_id
[i
]);
1598 domain_jit_info (domain
)->agent_info
= NULL
;
1600 /* Clear ids referencing structures in the domain */
1601 for (i
= 0; i
< ID_NUM
; ++i
) {
1603 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1604 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1605 if (id
->domain
== domain
)
1611 mono_loader_lock ();
1612 g_hash_table_remove (domains
, domain
);
1613 mono_loader_unlock ();
1617 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1620 AgentDomainInfo
*info
;
1625 mono_loader_lock ();
1627 mono_domain_lock (domain
);
1629 if (!domain_jit_info (domain
)->agent_info
)
1630 domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1631 info
= domain_jit_info (domain
)->agent_info
;
1632 if (info
->val_to_id
[type
] == NULL
)
1633 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1635 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1637 mono_domain_unlock (domain
);
1638 mono_loader_unlock ();
1642 id
= g_new0 (Id
, 1);
1644 id
->id
= ids
[type
]->len
+ 1;
1645 id
->domain
= domain
;
1648 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1650 mono_domain_unlock (domain
);
1652 g_ptr_array_add (ids
[type
], id
);
1654 mono_loader_unlock ();
1659 static inline gpointer
1660 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1664 int id
= decode_id (buf
, endbuf
, limit
);
1673 // FIXME: error handling
1674 mono_loader_lock ();
1675 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1677 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1678 mono_loader_unlock ();
1680 if (res
->domain
== NULL
) {
1681 *err
= ERR_UNLOADED
;
1686 *domain
= res
->domain
;
1688 return res
->data
.val
;
1692 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1694 buffer_add_id (buf
, get_id (domain
, type
, val
));
1697 static inline MonoClass
*
1698 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1700 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1703 static inline MonoAssembly
*
1704 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1706 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1709 static inline MonoImage
*
1710 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1712 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1715 static inline MonoMethod
*
1716 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1718 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1721 static inline MonoClassField
*
1722 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1724 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1727 static inline MonoDomain
*
1728 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1730 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1733 static inline MonoProperty
*
1734 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1736 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1740 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1742 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1746 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1748 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1752 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1754 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1758 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1760 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1764 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1766 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1770 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1772 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1776 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1778 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1781 static void invoke_method (void);
1788 * save_thread_context:
1790 * Set CTX as the current threads context which is used for computing stack traces.
1791 * This function is signal-safe.
1794 save_thread_context (MonoContext
*ctx
)
1796 DebuggerTlsData
*tls
;
1798 tls
= TlsGetValue (debugger_tls_id
);
1802 memcpy (&tls
->ctx
, ctx
, sizeof (MonoContext
));
1804 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1805 MONO_INIT_CONTEXT_FROM_CURRENT (&tls
->ctx
);
1807 MONO_INIT_CONTEXT_FROM_FUNC (&tls
->ctx
, save_thread_context
);
1811 tls
->lmf
= mono_get_lmf ();
1812 tls
->domain
= mono_domain_get ();
1813 tls
->has_context
= TRUE
;
1816 /* The number of times the runtime is suspended */
1817 static gint32 suspend_count
;
1819 /* Number of threads suspended */
1821 * If this is equal to the size of thread_to_tls, the runtime is considered
1824 static gint32 threads_suspend_count
;
1826 static mono_mutex_t suspend_mutex
;
1828 /* Cond variable used to wait for suspend_count becoming 0 */
1829 static mono_cond_t suspend_cond
;
1831 /* Semaphore used to wait for a thread becoming suspended */
1832 static MonoSemType suspend_sem
;
1837 mono_mutex_init (&suspend_mutex
, NULL
);
1838 mono_cond_init (&suspend_cond
, NULL
);
1839 MONO_SEM_INIT (&suspend_sem
, 0);
1844 StackFrameInfo last_frame
;
1845 gboolean last_frame_set
;
1848 } GetLastFrameUserData
;
1851 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
1853 GetLastFrameUserData
*data
= user_data
;
1855 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
1858 if (!data
->last_frame_set
) {
1859 /* Store the last frame */
1860 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
1861 data
->last_frame_set
= TRUE
;
1864 /* Store the context/lmf for the frame above the last frame */
1865 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
1866 data
->lmf
= info
->lmf
;
1873 * mono_debugger_agent_thread_interrupt:
1875 * Called by the abort signal handler.
1876 * Should be signal safe.
1879 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
1881 DebuggerTlsData
*tls
;
1886 tls
= TlsGetValue (debugger_tls_id
);
1891 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1892 * guarantee the signal handler will be called that many times. Instead of tracking
1893 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1894 * has been requested that hasn't been handled yet, otherwise we can have threads
1895 * refuse to die when VM_EXIT is called
1897 #if defined(__APPLE__)
1898 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
1902 * We use interrupt_count to determine whenever this interrupt should be processed
1903 * by us or the normal interrupt processing code in the signal handler.
1904 * There is no race here with notify_thread (), since the signal is sent after
1905 * incrementing interrupt_count.
1907 if (tls
->interrupt_count
== 0)
1910 InterlockedDecrement (&tls
->interrupt_count
);
1913 // FIXME: Races when the thread leaves managed code before hitting a single step
1917 /* Running managed code, will be suspended by the single step code */
1918 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
1922 * Running native code, will be suspended when it returns to/enters
1923 * managed code. Treat it as already suspended.
1924 * This might interrupt the code in process_single_step_inner (), we use the
1925 * tls->suspending flag to avoid races when that happens.
1927 if (!tls
->suspended
&& !tls
->suspending
) {
1929 GetLastFrameUserData data
;
1931 // FIXME: printf is not signal safe, but this is only used during
1932 // debugger debugging
1934 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
1935 //save_thread_context (&ctx);
1938 /* Already terminated */
1942 * We are in a difficult position: we want to be able to provide stack
1943 * traces for this thread, but we can't use the current ctx+lmf, since
1944 * the thread is still running, so it might return to managed code,
1945 * making these invalid.
1946 * So we start a stack walk and save the first frame, along with the
1947 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1948 * suspended when it returns to managed code, so the parent's ctx should
1951 data
.last_frame_set
= FALSE
;
1953 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1954 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame
, mono_domain_get (), &ctx
, FALSE
, tls
->thread
, mono_get_lmf (), &data
);
1956 if (data
.last_frame_set
) {
1957 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
1958 memcpy (&tls
->async_ctx
, &data
.ctx
, sizeof (MonoContext
));
1959 tls
->async_lmf
= data
.lmf
;
1960 tls
->has_async_ctx
= TRUE
;
1961 tls
->domain
= mono_domain_get ();
1962 memcpy (&tls
->ctx
, &ctx
, sizeof (MonoContext
));
1964 tls
->has_async_ctx
= FALSE
;
1967 mono_memory_barrier ();
1969 tls
->suspended
= TRUE
;
1970 MONO_SEM_POST (&suspend_sem
);
1977 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
1980 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
1982 #endif /* HOST_WIN32 */
1985 * reset_native_thread_suspend_state:
1987 * Reset the suspended flag on native threads
1990 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
1992 DebuggerTlsData
*tls
= value
;
1994 if (!tls
->really_suspended
&& tls
->suspended
)
1995 tls
->suspended
= FALSE
;
2001 * Notify a thread that it needs to suspend.
2004 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
2006 MonoInternalThread
*thread
= key
;
2007 DebuggerTlsData
*tls
= value
;
2008 gsize tid
= thread
->tid
;
2010 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
2013 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2016 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2017 * guarantee the signal handler will be called that many times. Instead of tracking
2018 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2019 * has been requested that hasn't been handled yet, otherwise we can have threads
2020 * refuse to die when VM_EXIT is called
2022 #if defined(__APPLE__)
2023 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
2027 * Maybe we could use the normal interrupt infrastructure, but that does a lot
2028 * of things like breaking waits etc. which we don't want.
2030 InterlockedIncrement (&tls
->interrupt_count
);
2033 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
2035 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
2037 pthread_kill ((pthread_t
) tid
, mono_thread_get_abort_signal ());
2042 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2044 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2047 if (debugger_thread_id
== GetCurrentThreadId ())
2050 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2051 if (suspend_count
- tls
->resume_count
> 0)
2052 tls
->suspending
= TRUE
;
2054 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2056 if (suspend_count
- tls
->resume_count
== 0) {
2058 * We are executing a single threaded invoke but the single step for
2059 * suspending is still active.
2060 * FIXME: This slows down single threaded invokes.
2062 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2066 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2068 /* Can't suspend in these methods */
2069 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
2072 save_thread_context (ctx
);
2080 * Increase the suspend count of the VM. While the suspend count is greater
2081 * than 0, runtime threads are suspended at certain points during execution.
2086 mono_loader_lock ();
2088 mono_mutex_lock (&suspend_mutex
);
2092 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2094 if (suspend_count
== 1) {
2095 // FIXME: Is it safe to call this inside the lock ?
2096 start_single_stepping ();
2097 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2100 mono_mutex_unlock (&suspend_mutex
);
2102 mono_loader_unlock ();
2108 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2116 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2118 mono_loader_lock ();
2120 mono_mutex_lock (&suspend_mutex
);
2122 g_assert (suspend_count
> 0);
2125 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2127 if (suspend_count
== 0) {
2128 // FIXME: Is it safe to call this inside the lock ?
2129 stop_single_stepping ();
2130 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2133 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2134 err
= mono_cond_broadcast (&suspend_cond
);
2135 g_assert (err
== 0);
2137 mono_mutex_unlock (&suspend_mutex
);
2138 //g_assert (err == 0);
2140 mono_loader_unlock ();
2146 * Resume just one thread.
2149 resume_thread (MonoInternalThread
*thread
)
2152 DebuggerTlsData
*tls
;
2154 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2156 mono_loader_lock ();
2158 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2161 mono_mutex_lock (&suspend_mutex
);
2163 g_assert (suspend_count
> 0);
2165 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2167 tls
->resume_count
+= suspend_count
;
2170 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2171 * but only the one whose resume_count field is > 0 will be resumed.
2173 err
= mono_cond_broadcast (&suspend_cond
);
2174 g_assert (err
== 0);
2176 mono_mutex_unlock (&suspend_mutex
);
2177 //g_assert (err == 0);
2179 mono_loader_unlock ();
2183 invalidate_frames (DebuggerTlsData
*tls
)
2188 tls
= TlsGetValue (debugger_tls_id
);
2191 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2192 if (tls
->frames
[i
]->jit
)
2193 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2194 g_free (tls
->frames
[i
]);
2196 g_free (tls
->frames
);
2197 tls
->frame_count
= 0;
2204 * Suspend the current thread until the runtime is resumed. If the thread has a
2205 * pending invoke, then the invoke is executed before this function returns.
2208 suspend_current (void)
2211 DebuggerTlsData
*tls
;
2213 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2215 if (mono_loader_lock_is_owned_by_self ()) {
2217 * If we own the loader mutex, can't suspend until we release it, since the
2218 * whole runtime can deadlock otherwise.
2223 tls
= TlsGetValue (debugger_tls_id
);
2226 mono_mutex_lock (&suspend_mutex
);
2228 tls
->suspending
= FALSE
;
2229 tls
->really_suspended
= TRUE
;
2231 if (!tls
->suspended
) {
2232 tls
->suspended
= TRUE
;
2233 MONO_SEM_POST (&suspend_sem
);
2236 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2238 while (suspend_count
- tls
->resume_count
> 0) {
2240 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2242 mono_mutex_unlock (&suspend_mutex
);
2244 mono_mutex_lock (&suspend_mutex
);
2250 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2251 g_assert (err
== 0);
2255 tls
->suspended
= FALSE
;
2256 tls
->really_suspended
= FALSE
;
2258 threads_suspend_count
--;
2260 mono_mutex_unlock (&suspend_mutex
);
2262 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2264 if (tls
->pending_invoke
) {
2265 /* Save the original context */
2266 tls
->pending_invoke
->has_ctx
= TRUE
;
2267 memcpy (&tls
->pending_invoke
->ctx
, &tls
->ctx
, sizeof (MonoContext
));
2272 /* The frame info becomes invalid after a resume */
2273 tls
->has_context
= FALSE
;
2274 tls
->has_async_ctx
= FALSE
;
2275 invalidate_frames (NULL
);
2279 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2281 DebuggerTlsData
*tls
= value
;
2283 if (!tls
->suspended
&& !tls
->terminated
)
2284 *(int*)user_data
= *(int*)user_data
+ 1;
2288 count_threads_to_wait_for (void)
2292 mono_loader_lock ();
2293 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2294 mono_loader_unlock ();
2302 * Wait until the runtime is completely suspended.
2305 wait_for_suspend (void)
2307 int nthreads
, nwait
, err
;
2308 gboolean waited
= FALSE
;
2310 // FIXME: Threads starting/stopping ?
2311 mono_loader_lock ();
2312 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2313 mono_loader_unlock ();
2316 nwait
= count_threads_to_wait_for ();
2318 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2319 err
= MONO_SEM_WAIT (&suspend_sem
);
2320 g_assert (err
== 0);
2328 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2334 * Return whenever the runtime is suspended.
2339 return count_threads_to_wait_for () == 0;
2343 * find_seq_point_for_native_offset:
2345 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2346 * should be the location of a sequence point.
2349 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2351 MonoSeqPointInfo
*seq_points
;
2354 mono_domain_lock (domain
);
2355 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2356 mono_domain_unlock (domain
);
2357 g_assert (seq_points
);
2361 for (i
= 0; i
< seq_points
->len
; ++i
) {
2362 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2363 return &seq_points
->seq_points
[i
];
2372 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2373 * should be the location of a sequence point.
2376 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2378 MonoSeqPointInfo
*seq_points
;
2381 mono_domain_lock (domain
);
2382 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2383 mono_domain_unlock (domain
);
2384 g_assert (seq_points
);
2388 for (i
= 0; i
< seq_points
->len
; ++i
) {
2389 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2390 return &seq_points
->seq_points
[i
];
2397 * compute_il_offset:
2399 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2400 * a location of a sequence point.
2401 * We use this function instead of mono_debug_il_offset_from_address () etc,
2402 * which doesn't seem to work in a lot of cases.
2405 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2407 MonoSeqPointInfo
*seq_points
;
2408 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2410 mono_domain_lock (domain
);
2411 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2412 mono_domain_unlock (domain
);
2413 g_assert (seq_points
);
2415 last_il_offset
= -1;
2417 /* Find the sequence point */
2418 for (i
= 0; i
< seq_points
->len
; ++i
) {
2419 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2420 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2422 if (seq_native_offset
> native_offset
)
2424 last_il_offset
= seq_il_offset
;
2427 return last_il_offset
;
2431 DebuggerTlsData
*tls
;
2433 } ComputeFramesUserData
;
2436 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2438 ComputeFramesUserData
*ud
= user_data
;
2442 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2443 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2444 /* Mark the last frame as an invoke frame */
2446 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2452 method
= info
->ji
->method
;
2454 method
= info
->method
;
2456 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2459 if (info
->il_offset
== -1) {
2460 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2461 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2464 DEBUG (1, fprintf (log_file
, "\tFrame: %s %d %d %d\n", mono_method_full_name (method
, TRUE
), info
->native_offset
, info
->il_offset
, info
->managed
));
2466 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2468 * mono_arch_find_jit_info () returns the context stored in the LMF for
2469 * native frames, but it should unwind once. This is why we have duplicate
2470 * frames on the stack sometimes.
2471 * !managed also seems to be set for dynamic methods.
2476 frame
= g_new0 (StackFrame
, 1);
2477 frame
->method
= method
;
2478 frame
->il_offset
= info
->il_offset
;
2481 frame
->has_ctx
= TRUE
;
2483 frame
->domain
= info
->domain
;
2485 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2491 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2493 ComputeFramesUserData user_data
;
2495 int i
, findex
, new_frame_count
;
2496 StackFrame
**new_frames
, *f
;
2498 // FIXME: Locking on tls
2499 if (tls
->frames
&& tls
->frames_up_to_date
)
2502 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2504 user_data
.tls
= tls
;
2505 user_data
.frames
= NULL
;
2506 if (tls
->terminated
) {
2507 tls
->frame_count
= 0;
2509 } if (!tls
->really_suspended
&& tls
->has_async_ctx
) {
2510 /* Have to use the state saved by the signal handler */
2511 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2512 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->async_ctx
, FALSE
, thread
, tls
->async_lmf
, &user_data
);
2513 } else if (tls
->has_context
) {
2514 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->ctx
, FALSE
, thread
, tls
->lmf
, &user_data
);
2517 tls
->frame_count
= 0;
2521 new_frame_count
= g_slist_length (user_data
.frames
);
2522 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2524 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2528 * Reuse the id for already existing stack frames, so invokes don't invalidate
2529 * the still valid stack frames.
2531 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2532 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2533 f
->id
= tls
->frames
[i
]->id
;
2538 if (i
>= tls
->frame_count
)
2539 f
->id
= InterlockedIncrement (&frame_id
);
2541 new_frames
[findex
++] = f
;
2544 g_slist_free (user_data
.frames
);
2546 invalidate_frames (tls
);
2548 tls
->frames
= new_frames
;
2549 tls
->frame_count
= new_frame_count
;
2550 tls
->frames_up_to_date
= TRUE
;
2558 * create_event_list:
2560 * Return a list of event request ids matching EVENT, starting from REQS, which
2561 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2563 * We return request ids, instead of requests, to simplify threading, since
2564 * requests could be deleted anytime when the loader lock is not held.
2565 * LOCKING: Assumes the loader lock is held.
2568 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
2571 GSList
*events
= NULL
;
2573 *suspend_policy
= SUSPEND_POLICY_NONE
;
2576 reqs
= event_requests
;
2581 for (i
= 0; i
< reqs
->len
; ++i
) {
2582 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2583 if (req
->event_kind
== event
) {
2584 gboolean filtered
= FALSE
;
2587 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2588 Modifier
*mod
= &req
->modifiers
[j
];
2590 if (mod
->kind
== MOD_KIND_COUNT
) {
2592 if (mod
->data
.count
> 0) {
2593 if (mod
->data
.count
> 0) {
2595 if (mod
->data
.count
== 0)
2599 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2600 if (mod
->data
.thread
!= mono_thread_internal_current ())
2602 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
2603 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
2605 if (ei
->caught
&& !mod
->caught
)
2607 if (!ei
->caught
&& !mod
->uncaught
)
2609 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2611 gboolean found
= FALSE
;
2612 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2615 for (k
= 0; assemblies
[k
]; ++k
)
2616 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2625 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2626 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2631 /* Send a VM START/DEATH event by default */
2632 if (event
== EVENT_KIND_VM_START
)
2633 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2634 if (event
== EVENT_KIND_VM_DEATH
)
2635 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2640 static G_GNUC_UNUSED
const char*
2641 event_to_string (EventKind event
)
2644 case EVENT_KIND_VM_START
: return "VM_START";
2645 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2646 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2647 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2648 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2649 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2650 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2651 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2652 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2653 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2654 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2655 case EVENT_KIND_STEP
: return "STEP";
2656 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
2657 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
2659 g_assert_not_reached ();
2666 * Send an event to the client, suspending the vm if needed.
2667 * LOCKING: Since this can suspend the calling thread, no locks should be held
2669 * The EVENTS list is freed by this function.
2672 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
2676 MonoDomain
*domain
= mono_domain_get ();
2682 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
)
2683 // FIXME: We miss those events
2686 if (vm_death_event_sent
)
2689 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
)
2698 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
2699 // FIXME: Send these with a NULL thread, don't suspend the current thread
2702 buffer_init (&buf
, 128);
2703 buffer_add_byte (&buf
, suspend_policy
);
2704 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
2706 for (l
= events
; l
; l
= l
->next
) {
2707 buffer_add_byte (&buf
, event
); // event kind
2708 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
2710 thread
= mono_thread_current ();
2712 if (event
== EVENT_KIND_VM_START
)
2714 else if (event
== EVENT_KIND_THREAD_START
)
2715 g_assert (mono_thread_internal_current () == arg
);
2717 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
2720 case EVENT_KIND_THREAD_START
:
2721 case EVENT_KIND_THREAD_DEATH
:
2723 case EVENT_KIND_APPDOMAIN_CREATE
:
2724 case EVENT_KIND_APPDOMAIN_UNLOAD
:
2725 buffer_add_domainid (&buf
, arg
);
2727 case EVENT_KIND_METHOD_ENTRY
:
2728 case EVENT_KIND_METHOD_EXIT
:
2729 buffer_add_methodid (&buf
, domain
, arg
);
2731 case EVENT_KIND_ASSEMBLY_LOAD
:
2732 case EVENT_KIND_ASSEMBLY_UNLOAD
:
2733 buffer_add_assemblyid (&buf
, domain
, arg
);
2735 case EVENT_KIND_TYPE_LOAD
:
2736 buffer_add_typeid (&buf
, domain
, arg
);
2738 case EVENT_KIND_BREAKPOINT
:
2739 case EVENT_KIND_STEP
:
2740 buffer_add_methodid (&buf
, domain
, arg
);
2741 buffer_add_long (&buf
, il_offset
);
2743 case EVENT_KIND_VM_START
:
2744 buffer_add_domainid (&buf
, mono_get_root_domain ());
2746 case EVENT_KIND_VM_DEATH
:
2748 case EVENT_KIND_EXCEPTION
: {
2749 EventInfo
*ei
= arg
;
2750 buffer_add_objid (&buf
, ei
->exc
);
2754 g_assert_not_reached ();
2758 if (event
== EVENT_KIND_VM_START
) {
2759 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
2760 start_debugger_thread ();
2763 if (event
== EVENT_KIND_VM_DEATH
) {
2764 vm_death_event_sent
= TRUE
;
2766 suspend_policy
= SUSPEND_POLICY_NONE
;
2769 if (mono_runtime_is_shutting_down ())
2770 suspend_policy
= SUSPEND_POLICY_NONE
;
2772 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
2774 * Save the thread context and start suspending before sending the packet,
2775 * since we could be receiving the resume request before send_packet ()
2778 save_thread_context (ctx
);
2782 send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
2784 g_slist_free (events
);
2787 if (event
== EVENT_KIND_VM_START
)
2788 vm_start_event_sent
= TRUE
;
2790 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
2794 switch (suspend_policy
) {
2795 case SUSPEND_POLICY_NONE
:
2797 case SUSPEND_POLICY_ALL
:
2800 case SUSPEND_POLICY_EVENT_THREAD
:
2804 g_assert_not_reached ();
2809 process_profiler_event (EventKind event
, gpointer arg
)
2814 mono_loader_lock ();
2815 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
2816 mono_loader_unlock ();
2818 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
2822 runtime_initialized (MonoProfiler
*prof
)
2824 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
2828 runtime_shutdown (MonoProfiler
*prof
)
2830 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
2832 mono_debugger_agent_cleanup ();
2836 thread_startup (MonoProfiler
*prof
, intptr_t tid
)
2838 MonoInternalThread
*thread
= mono_thread_internal_current ();
2839 MonoInternalThread
*old_thread
;
2840 DebuggerTlsData
*tls
;
2842 if (tid
== debugger_thread_id
)
2845 g_assert (thread
->tid
== tid
);
2847 mono_loader_lock ();
2848 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2849 mono_loader_unlock ();
2851 if (thread
== old_thread
) {
2853 * For some reason, thread_startup () might be called for the same thread
2854 * multiple times (attach ?).
2856 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
2860 * thread_end () might not be called for some threads, and the tid could
2863 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
2864 mono_loader_lock ();
2865 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
2866 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
2867 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2868 mono_loader_unlock ();
2872 tls
= TlsGetValue (debugger_tls_id
);
2874 // FIXME: Free this somewhere
2875 tls
= g_new0 (DebuggerTlsData
, 1);
2876 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2877 MONO_GC_REGISTER_ROOT (tls
->thread
);
2878 tls
->thread
= thread
;
2879 TlsSetValue (debugger_tls_id
, tls
);
2881 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2883 mono_loader_lock ();
2884 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
2885 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
2886 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
2887 mono_loader_unlock ();
2889 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
2892 * suspend_vm () could have missed this thread, so wait for a resume.
2898 thread_end (MonoProfiler
*prof
, intptr_t tid
)
2900 MonoInternalThread
*thread
;
2901 DebuggerTlsData
*tls
= NULL
;
2903 mono_loader_lock ();
2904 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2906 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2907 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2908 tls
->terminated
= TRUE
;
2909 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2910 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2911 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
2914 mono_loader_unlock ();
2916 /* We might be called for threads started before we registered the start callback */
2918 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2919 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
2924 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
2926 mono_loader_lock ();
2927 g_hash_table_insert (domains
, domain
, domain
);
2928 mono_loader_unlock ();
2930 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
2934 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
2936 /* Invalidate each thread's frame stack */
2937 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
2938 clear_breakpoints_for_domain (domain
);
2939 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
2943 * invalidate_each_thread:
2945 * A GHFunc to invalidate frames.
2946 * value must be a DebuggerTlsData*
2949 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
2951 invalidate_frames (value
);
2955 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
2957 /* Sent later in jit_end () */
2958 mono_loader_lock ();
2959 g_ptr_array_add (pending_assembly_loads
, assembly
);
2960 mono_loader_unlock ();
2964 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
2966 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
2968 clear_event_requests_for_assembly (assembly
);
2969 clear_types_for_assembly (assembly
);
2973 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2975 #if defined(HOST_WIN32) && !defined(__GNUC__)
2976 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2978 gpointer stackptr
= __builtin_frame_address (1);
2980 MonoInternalThread
*thread
= mono_thread_internal_current ();
2981 DebuggerTlsData
*tls
;
2983 mono_loader_lock ();
2985 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2986 /* Could be the debugger thread with assembly/type load hooks */
2988 tls
->invoke_addr
= stackptr
;
2990 mono_loader_unlock ();
2994 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2997 #if defined(HOST_WIN32) && !defined(__GNUC__)
2998 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
3000 gpointer stackptr
= __builtin_frame_address (1);
3003 if (ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
3007 * We need to stop single stepping when exiting a runtime invoke, since if it is
3008 * a step out, it may return to native code, and thus never end.
3010 mono_loader_lock ();
3011 ss_invoke_addr
= NULL
;
3013 for (i
= 0; i
< event_requests
->len
; ++i
) {
3014 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
3016 if (req
->event_kind
== EVENT_KIND_STEP
) {
3017 ss_destroy (req
->info
);
3018 g_ptr_array_remove_index_fast (event_requests
, i
);
3023 mono_loader_unlock ();
3027 send_type_load (MonoClass
*klass
)
3029 gboolean type_load
= FALSE
;
3031 mono_loader_lock ();
3032 if (!g_hash_table_lookup (loaded_classes
, klass
)) {
3034 g_hash_table_insert (loaded_classes
, klass
, klass
);
3036 mono_loader_unlock ();
3038 process_profiler_event (EVENT_KIND_TYPE_LOAD
, klass
);
3042 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
3045 * We emit type load events when the first method of the type is JITted,
3046 * since the class load profiler callbacks might be called with the
3047 * loader lock held. They could also occur in the debugger thread.
3048 * Same for assembly load events.
3051 MonoAssembly
*assembly
= NULL
;
3053 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
3054 mono_loader_lock ();
3055 if (pending_assembly_loads
->len
> 0) {
3056 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
3057 g_ptr_array_remove_index (pending_assembly_loads
, 0);
3059 mono_loader_unlock ();
3062 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
3067 if (!vm_start_event_sent
) {
3068 /* Save these so they can be sent after the vm start event */
3069 mono_loader_lock ();
3070 g_ptr_array_add (pending_type_loads
, method
->klass
);
3071 mono_loader_unlock ();
3073 /* Send all pending type load events */
3077 mono_loader_lock ();
3078 if (pending_type_loads
->len
> 0) {
3079 klass
= g_ptr_array_index (pending_type_loads
, 0);
3080 g_ptr_array_remove_index (pending_type_loads
, 0);
3082 mono_loader_unlock ();
3084 send_type_load (klass
);
3089 send_type_load (method
->klass
);
3093 add_pending_breakpoints (method
, jinfo
);
3097 * BREAKPOINTS/SINGLE STEPPING
3101 * Contains information about an inserted breakpoint.
3104 long il_offset
, native_offset
;
3108 } BreakpointInstance
;
3111 * Contains generic information about a breakpoint.
3115 * The method where the breakpoint is placed. Can be NULL in which case it
3116 * is inserted into every method. This is used to implement method entry/
3117 * exit events. Can be a generic method definition, in which case the
3118 * breakpoint is inserted into every instance.
3124 * A list of BreakpointInstance structures describing where the breakpoint
3125 * was inserted. There could be more than one because of
3126 * generics/appdomains/method entry/exit.
3128 GPtrArray
*children
;
3131 /* List of breakpoints */
3132 static GPtrArray
*breakpoints
;
3133 /* Maps breakpoint locations to the number of breakpoints at that location */
3134 static GHashTable
*bp_locs
;
3137 breakpoints_init (void)
3139 breakpoints
= g_ptr_array_new ();
3140 bp_locs
= g_hash_table_new (NULL
, NULL
);
3144 * insert_breakpoint:
3146 * Insert the breakpoint described by BP into the method described by
3150 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoDomain
*domain
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
)
3153 gint32 il_offset
= -1, native_offset
;
3154 BreakpointInstance
*inst
;
3157 for (i
= 0; i
< seq_points
->len
; ++i
) {
3158 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3159 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3161 if (il_offset
== bp
->il_offset
)
3165 if (i
== seq_points
->len
) {
3166 /* Have to handle this somehow */
3167 g_error ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (ji
->method
, TRUE
), bp
->il_offset
, seq_points
->len
);
3170 inst
= g_new0 (BreakpointInstance
, 1);
3171 inst
->native_offset
= native_offset
;
3172 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3174 inst
->domain
= domain
;
3176 mono_loader_lock ();
3178 g_ptr_array_add (bp
->children
, inst
);
3180 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3181 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3182 mono_loader_unlock ();
3185 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3186 mono_arch_set_breakpoint (ji
, inst
->ip
);
3192 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (ji
->method
, TRUE
), (int)il_offset
));
3196 remove_breakpoint (BreakpointInstance
*inst
)
3198 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3200 MonoJitInfo
*ji
= inst
->ji
;
3201 guint8
*ip
= inst
->ip
;
3203 mono_loader_lock ();
3204 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3205 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3206 mono_loader_unlock ();
3208 g_assert (count
> 0);
3211 mono_arch_clear_breakpoint (ji
, ip
);
3218 static inline gboolean
3219 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
3221 return (!bp
->method
|| method
== bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
));
3225 * add_pending_breakpoints:
3227 * Insert pending breakpoints into the newly JITted method METHOD.
3230 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3233 MonoSeqPointInfo
*seq_points
;
3239 domain
= mono_domain_get ();
3241 mono_loader_lock ();
3243 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3244 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3245 gboolean found
= FALSE
;
3247 if (!bp_matches_method (bp
, method
))
3250 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3251 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3258 mono_domain_lock (domain
);
3259 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3260 mono_domain_unlock (domain
);
3262 /* Could be AOT code */
3264 g_assert (seq_points
);
3266 insert_breakpoint (seq_points
, domain
, ji
, bp
);
3270 mono_loader_unlock ();
3274 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
)
3279 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3281 /* Might be AOTed code */
3282 code
= mono_aot_get_method (domain
, method
);
3284 ji
= mono_jit_info_table_find (domain
, code
);
3289 insert_breakpoint (seq_points
, domain
, ji
, bp
);
3299 set_bp_in_method_cb (gpointer key
, gpointer value
, gpointer user_data
)
3301 MonoMethod
*method
= key
;
3302 MonoSeqPointInfo
*seq_points
= value
;
3303 SetBpUserData
*ud
= user_data
;
3304 MonoBreakpoint
*bp
= ud
->bp
;
3305 MonoDomain
*domain
= ud
->domain
;
3307 if (bp_matches_method (bp
, method
))
3308 set_bp_in_method (domain
, method
, seq_points
, bp
);
3312 set_bp_in_domain (gpointer key
, gpointer value
, gpointer user_data
)
3314 MonoDomain
*domain
= key
;
3315 MonoBreakpoint
*bp
= user_data
;
3321 mono_domain_lock (domain
);
3322 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, &ud
);
3323 mono_domain_unlock (domain
);
3329 * Set a breakpoint at IL_OFFSET in METHOD.
3330 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3331 * METHOD can also be a generic method definition, in which case a breakpoint
3332 * is placed in all instances of the method.
3334 static MonoBreakpoint
*
3335 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
)
3340 // - suspend/resume the vm to prevent code patching problems
3341 // - multiple breakpoints on the same location
3342 // - dynamic methods
3345 bp
= g_new0 (MonoBreakpoint
, 1);
3346 bp
->method
= method
;
3347 bp
->il_offset
= il_offset
;
3349 bp
->children
= g_ptr_array_new ();
3351 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
));
3353 mono_loader_lock ();
3355 g_hash_table_foreach (domains
, set_bp_in_domain
, bp
);
3357 mono_loader_unlock ();
3359 mono_loader_lock ();
3360 g_ptr_array_add (breakpoints
, bp
);
3361 mono_loader_unlock ();
3367 clear_breakpoint (MonoBreakpoint
*bp
)
3371 // FIXME: locking, races
3372 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3373 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3375 remove_breakpoint (inst
);
3380 mono_loader_lock ();
3381 g_ptr_array_remove (breakpoints
, bp
);
3382 mono_loader_unlock ();
3384 g_ptr_array_free (bp
->children
, TRUE
);
3389 breakpoints_cleanup (void)
3393 mono_loader_lock ();
3395 while (i
< event_requests
->len
) {
3396 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
3398 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
3399 clear_breakpoint (req
->info
);
3400 g_ptr_array_remove_index_fast (event_requests
, i
);
3407 for (i
= 0; i
< breakpoints
->len
; ++i
)
3408 g_free (g_ptr_array_index (breakpoints
, i
));
3410 g_ptr_array_free (breakpoints
, TRUE
);
3411 g_hash_table_destroy (bp_locs
);
3416 mono_loader_unlock ();
3420 * clear_breakpoints_for_domain:
3422 * Clear breakpoint instances which reference DOMAIN.
3425 clear_breakpoints_for_domain (MonoDomain
*domain
)
3429 /* This could be called after shutdown */
3433 mono_loader_lock ();
3434 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3435 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3438 while (j
< bp
->children
->len
) {
3439 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
3441 if (inst
->domain
== domain
) {
3442 remove_breakpoint (inst
);
3446 g_ptr_array_remove_index_fast (bp
->children
, j
);
3452 mono_loader_unlock ();
3456 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
3458 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
3462 process_breakpoint_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3465 guint8
*orig_ip
, *ip
;
3466 int i
, j
, suspend_policy
;
3467 guint32 native_offset
;
3469 BreakpointInstance
*inst
;
3470 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3471 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3472 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3474 // FIXME: Speed this up
3476 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3477 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3479 g_assert (ji
->method
);
3481 /* Compute the native offset of the breakpoint from the ip */
3482 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3483 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3484 native_offset
= ip
- (guint8
*)ji
->code_start
;
3490 * Skip the instruction causing the breakpoint signal.
3492 mono_arch_skip_breakpoint (ctx
);
3494 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3497 bp_reqs
= g_ptr_array_new ();
3498 ss_reqs
= g_ptr_array_new ();
3499 ss_reqs_orig
= g_ptr_array_new ();
3501 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3503 mono_loader_lock ();
3506 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3507 bp
= g_ptr_array_index (breakpoints
, i
);
3512 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3513 inst
= g_ptr_array_index (bp
->children
, j
);
3514 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3515 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3516 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3518 g_ptr_array_add (bp_reqs
, bp
->req
);
3523 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3524 MonoSeqPointInfo
*seq_points
;
3525 int seq_il_offset
, seq_native_offset
;
3526 MonoDomain
*domain
= mono_domain_get ();
3528 /* Maybe a method entry/exit event */
3529 mono_domain_lock (domain
);
3530 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3531 mono_domain_unlock (domain
);
3533 // FIXME: Generic sharing */
3534 mono_loader_unlock ();
3537 g_assert (seq_points
);
3539 for (i
= 0; i
< seq_points
->len
; ++i
) {
3540 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3541 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3543 if (native_offset
== seq_native_offset
) {
3544 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3545 kind
= EVENT_KIND_METHOD_ENTRY
;
3546 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3547 kind
= EVENT_KIND_METHOD_EXIT
;
3553 /* Process single step requests */
3554 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3555 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3556 SingleStepReq
*ss_req
= bp
->req
->info
;
3557 gboolean hit
= TRUE
;
3558 MonoSeqPointInfo
*info
;
3561 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3564 if (ss_req
->size
== STEP_SIZE_LINE
) {
3565 /* Have to check whenever a different source line was reached */
3566 MonoDebugMethodInfo
*minfo
;
3567 MonoDebugSourceLocation
*loc
= NULL
;
3569 minfo
= mono_debug_lookup_method (ji
->method
);
3572 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3574 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3575 /* Have to continue single stepping */
3579 ss_req
->last_method
= ji
->method
;
3580 ss_req
->last_line
= loc
->row
;
3581 mono_debug_free_source_location (loc
);
3586 g_ptr_array_add (ss_reqs
, req
);
3588 /* Start single stepping again from the current sequence point */
3589 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
);
3592 if (ss_reqs
->len
> 0)
3593 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
3594 if (bp_reqs
->len
> 0)
3595 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
3596 if (kind
!= EVENT_KIND_BREAKPOINT
)
3597 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
3599 mono_loader_unlock ();
3601 g_ptr_array_free (bp_reqs
, TRUE
);
3602 g_ptr_array_free (ss_reqs
, TRUE
);
3605 * FIXME: The first event will suspend, so the second will only be sent after the
3609 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
3611 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
3612 if (enter_leave_events
)
3613 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
3617 process_breakpoint (void)
3619 DebuggerTlsData
*tls
;
3621 static void (*restore_context
) (void *);
3623 if (!restore_context
)
3624 restore_context
= mono_get_restore_context ();
3626 tls
= TlsGetValue (debugger_tls_id
);
3627 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3629 process_breakpoint_inner (tls
, &ctx
);
3631 /* This is called when resuming from a signal handler, so it shouldn't return */
3632 restore_context (&ctx
);
3633 g_assert_not_reached ();
3637 resume_from_signal_handler (void *sigctx
, void *func
)
3639 DebuggerTlsData
*tls
;
3642 /* Save the original context in TLS */
3643 // FIXME: This might not work on an altstack ?
3644 tls
= TlsGetValue (debugger_tls_id
);
3647 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3648 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3649 // clob:c could be added to op_seq_point.
3651 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3652 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
3653 MONO_CONTEXT_SET_IP (&ctx
, func
);
3654 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3656 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3657 mono_ppc_set_func_into_sigctx (sigctx
, func
);
3662 mono_debugger_agent_breakpoint_hit (void *sigctx
)
3665 * We are called from a signal handler, and running code there causes all kinds of
3666 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3667 * So set up the signal context to return to the real breakpoint handler function.
3670 resume_from_signal_handler (sigctx
, process_breakpoint
);
3674 process_single_step_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3679 int il_offset
, suspend_policy
;
3683 // FIXME: Speed this up
3685 ip
= MONO_CONTEXT_GET_IP (ctx
);
3687 /* Skip the instruction causing the single step */
3688 mono_arch_skip_single_step (ctx
);
3690 if (suspend_count
> 0) {
3691 process_suspend (tls
, ctx
);
3696 // FIXME: A suspend race
3699 if (mono_thread_internal_current () != ss_req
->thread
)
3702 if (log_level
> 0) {
3703 const char *depth
= NULL
;
3705 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3707 switch (ss_req
->depth
) {
3708 case STEP_DEPTH_OVER
:
3711 case STEP_DEPTH_OUT
:
3714 case STEP_DEPTH_INTO
:
3718 g_assert_not_reached ();
3721 DEBUG (1, fprintf (log_file
, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer
)GetCurrentThreadId (), ss_req
->depth
== STEP_DEPTH_OVER
? "over" : "out", mono_method_full_name (ji
->method
, TRUE
), MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), ss_req
->last_sp
));
3725 * We implement step over/out by single stepping until we reach the same
3726 * frame/parent frame.
3729 * - stack growing upward
3733 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
3734 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
3736 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
3739 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
3742 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3744 g_assert (ji
->method
);
3746 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
3751 * Stopping in memset makes half-initialized vtypes visible.
3752 * Stopping in memcpy makes half-copied vtypes visible.
3754 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
3758 * The ip points to the instruction causing the single step event, convert it
3759 * to the offset stored in seq_points.
3761 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3762 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
3764 g_assert_not_reached ();
3768 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3769 * example, so do things by hand.
3771 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
3773 if (il_offset
== -1)
3776 if (ss_req
->size
== STEP_SIZE_LINE
) {
3777 /* Step until a different source line is reached */
3778 MonoDebugMethodInfo
*minfo
;
3780 minfo
= mono_debug_lookup_method (ji
->method
);
3783 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
3785 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
3786 mono_debug_free_source_location (loc
);
3791 * Step until we reach a location with line number info,
3792 * otherwise the client can't show a location.
3793 * This can happen for example with statics initialized inline
3794 * outside of a cctor.
3799 ss_req
->last_method
= ji
->method
;
3800 ss_req
->last_line
= loc
->row
;
3801 mono_debug_free_source_location (loc
);
3806 // FIXME: Has to lock earlier
3808 reqs
= g_ptr_array_new ();
3810 mono_loader_lock ();
3812 g_ptr_array_add (reqs
, ss_req
->req
);
3814 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
3816 g_ptr_array_free (reqs
, TRUE
);
3818 mono_loader_unlock ();
3820 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
3824 process_single_step (void)
3826 DebuggerTlsData
*tls
;
3828 static void (*restore_context
) (void *);
3830 if (!restore_context
)
3831 restore_context
= mono_get_restore_context ();
3833 tls
= TlsGetValue (debugger_tls_id
);
3834 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3836 process_single_step_inner (tls
, &ctx
);
3838 /* This is called when resuming from a signal handler, so it shouldn't return */
3839 restore_context (&ctx
);
3840 g_assert_not_reached ();
3844 * mono_debugger_agent_single_step_event:
3846 * Called from a signal handler to handle a single step event.
3849 mono_debugger_agent_single_step_event (void *sigctx
)
3851 /* Resume to process_single_step through the signal context */
3853 // FIXME: Since step out/over is implemented using step in, the step in case should
3854 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3857 if (GetCurrentThreadId () == debugger_thread_id
) {
3859 * This could happen despite our best effors when the runtime calls
3860 * assembly/type resolve hooks.
3861 * FIXME: Breakpoints too.
3865 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3866 mono_arch_skip_single_step (&ctx
);
3867 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3871 resume_from_signal_handler (sigctx
, process_single_step
);
3875 * start_single_stepping:
3877 * Turn on single stepping. Can be called multiple times, for example,
3878 * by a single step event request + a suspend.
3881 start_single_stepping (void)
3883 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3884 int val
= InterlockedIncrement (&ss_count
);
3887 mono_arch_start_single_stepping ();
3889 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
3890 DebuggerTlsData
*tls
;
3892 mono_loader_lock ();
3894 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
3895 ss_invoke_addr
= tls
->invoke_addr
;
3897 mono_loader_unlock ();
3900 g_assert_not_reached ();
3905 stop_single_stepping (void)
3907 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3908 int val
= InterlockedDecrement (&ss_count
);
3911 mono_arch_stop_single_stepping ();
3913 g_assert_not_reached ();
3920 * Stop the single stepping operation given by SS_REQ.
3923 ss_stop (SingleStepReq
*ss_req
)
3925 gboolean use_bps
= FALSE
;
3932 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
3933 clear_breakpoint (l
->data
);
3935 g_slist_free (ss_req
->bps
);
3939 if (ss_req
->global
) {
3940 stop_single_stepping ();
3941 ss_req
->global
= FALSE
;
3948 * Start the single stepping operation given by SS_REQ from the sequence point SP.
3951 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
)
3953 gboolean use_bp
= FALSE
;
3958 /* Stop the previous operation */
3962 * Implement single stepping using breakpoints if possible.
3964 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3967 * Find the first sequence point in the current or in a previous frame which
3968 * is not the last in its method.
3970 while (sp
&& sp
->next_len
== 0) {
3972 if (tls
&& frame_index
< tls
->frame_count
) {
3973 StackFrame
*frame
= tls
->frames
[frame_index
];
3975 method
= frame
->method
;
3976 if (frame
->il_offset
!= -1) {
3977 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3983 if (sp
&& sp
->next_len
> 0) {
3985 for (i
= 0; i
< sp
->next_len
; ++i
) {
3986 next_sp
= &info
->seq_points
[sp
->next
[i
]];
3988 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
);
3989 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
3995 ss_req
->global
= TRUE
;
3996 start_single_stepping ();
3998 ss_req
->global
= FALSE
;
4003 * Start single stepping of thread THREAD
4006 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
4008 DebuggerTlsData
*tls
;
4009 MonoSeqPointInfo
*info
;
4010 SeqPoint
*sp
= NULL
;
4011 MonoMethod
*method
= NULL
;
4013 if (suspend_count
== 0)
4014 return ERR_NOT_SUSPENDED
;
4016 wait_for_suspend ();
4018 // FIXME: Multiple requests
4020 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
4021 return ERR_NOT_IMPLEMENTED
;
4024 ss_req
= g_new0 (SingleStepReq
, 1);
4026 ss_req
->thread
= thread
;
4027 ss_req
->size
= size
;
4028 ss_req
->depth
= depth
;
4031 mono_loader_lock ();
4032 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4033 mono_loader_unlock ();
4035 g_assert (tls
->has_context
);
4036 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->ctx
);
4038 if (ss_req
->size
== STEP_SIZE_LINE
) {
4040 MonoDebugMethodInfo
*minfo
;
4042 /* Compute the initial line info */
4043 compute_frame_info (thread
, tls
);
4045 g_assert (tls
->frame_count
);
4046 frame
= tls
->frames
[0];
4048 ss_req
->last_method
= frame
->method
;
4049 ss_req
->last_line
= -1;
4051 minfo
= mono_debug_lookup_method (frame
->method
);
4052 if (minfo
&& frame
->il_offset
!= -1) {
4053 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
4056 ss_req
->last_line
= loc
->row
;
4062 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
4065 compute_frame_info (thread
, tls
);
4067 g_assert (tls
->frame_count
);
4068 frame
= tls
->frames
[0];
4070 if (frame
->il_offset
!= -1) {
4071 /* FIXME: Sort the table and use a binary search */
4072 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
4074 method
= frame
->method
;
4078 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
);
4084 ss_destroy (SingleStepReq
*req
)
4087 g_assert (ss_req
== req
);
4096 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
4097 MonoContext
*catch_ctx
)
4104 if (thread_to_tls
!= NULL
) {
4105 MonoInternalThread
*thread
= mono_thread_internal_current ();
4106 DebuggerTlsData
*tls
;
4108 mono_loader_lock ();
4109 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4110 mono_loader_unlock ();
4112 if (tls
&& tls
->abort_requested
)
4116 memset (&ei
, 0, sizeof (EventInfo
));
4118 /* Just-In-Time debugging */
4120 if (agent_config
.onuncaught
&& !inited
) {
4121 finish_agent_init (FALSE
);
4124 * Send an unsolicited EXCEPTION event with a dummy request id.
4126 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4127 ei
.exc
= (MonoObject
*)exc
;
4128 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4131 } else if (agent_config
.onthrow
&& !inited
) {
4133 gboolean found
= FALSE
;
4135 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
4136 char *ex_type
= l
->data
;
4137 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
4139 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
4146 finish_agent_init (FALSE
);
4149 * Send an unsolicited EXCEPTION event with a dummy request id.
4151 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
4152 ei
.exc
= (MonoObject
*)exc
;
4153 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
4161 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
4163 ei
.exc
= (MonoObject
*)exc
;
4164 ei
.caught
= catch_ctx
!= NULL
;
4166 mono_loader_lock ();
4167 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
4168 mono_loader_unlock ();
4170 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
4174 * buffer_add_value_full:
4176 * Add the encoding of the value at ADDR described by T to the buffer.
4177 * AS_VTYPE determines whenever to treat primitive types as primitive types or
4181 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
4187 g_assert (*(void**)addr
);
4188 addr
= *(void**)addr
;
4193 case MONO_TYPE_BOOLEAN
:
4196 case MONO_TYPE_CHAR
:
4216 case MONO_TYPE_VOID
:
4217 buffer_add_byte (buf
, t
->type
);
4219 case MONO_TYPE_BOOLEAN
:
4222 buffer_add_byte (buf
, t
->type
);
4223 buffer_add_int (buf
, *(gint8
*)addr
);
4225 case MONO_TYPE_CHAR
:
4228 buffer_add_byte (buf
, t
->type
);
4229 buffer_add_int (buf
, *(gint16
*)addr
);
4234 buffer_add_byte (buf
, t
->type
);
4235 buffer_add_int (buf
, *(gint32
*)addr
);
4240 buffer_add_byte (buf
, t
->type
);
4241 buffer_add_long (buf
, *(gint64
*)addr
);
4245 /* Treat it as a vtype */
4247 case MONO_TYPE_PTR
: {
4248 gssize val
= *(gssize
*)addr
;
4250 buffer_add_byte (buf
, t
->type
);
4251 buffer_add_long (buf
, val
);
4255 case MONO_TYPE_STRING
:
4256 case MONO_TYPE_SZARRAY
:
4257 case MONO_TYPE_OBJECT
:
4258 case MONO_TYPE_CLASS
:
4259 case MONO_TYPE_ARRAY
:
4260 obj
= *(MonoObject
**)addr
;
4263 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4265 if (obj
->vtable
->klass
->valuetype
) {
4266 t
= &obj
->vtable
->klass
->byval_arg
;
4267 addr
= mono_object_unbox (obj
);
4269 } else if (obj
->vtable
->klass
->rank
) {
4270 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4271 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4272 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4274 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4276 buffer_add_objid (buf
, obj
);
4280 case MONO_TYPE_VALUETYPE
: {
4284 MonoClass
*klass
= mono_class_from_mono_type (t
);
4286 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4287 buffer_add_byte (buf
, klass
->enumtype
);
4288 buffer_add_typeid (buf
, domain
, klass
);
4292 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4293 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4295 if (mono_field_is_deleted (f
))
4299 buffer_add_int (buf
, nfields
);
4302 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4303 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4305 if (mono_field_is_deleted (f
))
4307 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4311 case MONO_TYPE_GENERICINST
:
4312 if (mono_type_generic_inst_is_valuetype (t
)) {
4324 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4326 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4330 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4333 int type
= decode_byte (buf
, &buf
, limit
);
4335 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4336 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4337 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4338 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4339 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4340 char *name
= mono_type_full_name (t
);
4341 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
4343 return ERR_INVALID_ARGUMENT
;
4347 case MONO_TYPE_BOOLEAN
:
4348 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4350 case MONO_TYPE_CHAR
:
4351 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4354 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4357 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4360 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4363 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4366 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4369 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4372 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4375 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4378 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4381 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4384 /* We send these as I8, so we get them back as such */
4385 g_assert (type
== MONO_TYPE_I8
);
4386 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4388 case MONO_TYPE_GENERICINST
:
4389 if (MONO_TYPE_ISSTRUCT (t
)) {
4390 /* The client sends these as a valuetype */
4398 /* We send these as vtypes, so we get them back as such */
4399 g_assert (type
== MONO_TYPE_VALUETYPE
);
4402 case MONO_TYPE_VALUETYPE
: {
4403 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
4407 gpointer iter
= NULL
;
4410 /* Enums are sent as a normal vtype */
4412 return ERR_NOT_IMPLEMENTED
;
4413 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
4417 if (klass
!= mono_class_from_mono_type (t
))
4418 return ERR_INVALID_ARGUMENT
;
4420 nfields
= decode_int (buf
, &buf
, limit
);
4421 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4422 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4424 if (mono_field_is_deleted (f
))
4426 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
4431 g_assert (nfields
== 0);
4436 if (MONO_TYPE_IS_REFERENCE (t
)) {
4437 if (type
== MONO_TYPE_OBJECT
) {
4438 int objid
= decode_objid (buf
, &buf
, limit
);
4442 err
= get_object (objid
, (MonoObject
**)&obj
);
4446 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
4447 return ERR_INVALID_ARGUMENT
;
4448 if (obj
&& obj
->vtable
->domain
!= domain
)
4449 return ERR_INVALID_ARGUMENT
;
4451 mono_gc_wbarrier_generic_store (addr
, obj
);
4452 } else if (type
== VALUE_TYPE_ID_NULL
) {
4453 *(MonoObject
**)addr
= NULL
;
4455 return ERR_INVALID_ARGUMENT
;
4469 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
4476 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4477 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4480 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4481 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
4483 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
4485 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4486 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4487 addr
+= (gint32
)var
->offset
;
4489 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4491 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
4493 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4497 g_assert_not_reached ();
4502 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
)
4508 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4509 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4511 if (MONO_TYPE_IS_REFERENCE (t
))
4512 size
= sizeof (gpointer
);
4514 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
4517 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4518 // FIXME: Can't set registers, so we disable linears
4521 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4522 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4523 addr
+= (gint32
)var
->offset
;
4525 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4527 // FIXME: Write barriers
4528 memcpy (addr
, val
, size
);
4530 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4534 g_assert_not_reached ();
4539 clear_event_request (int req_id
, int etype
)
4543 mono_loader_lock ();
4544 for (i
= 0; i
< event_requests
->len
; ++i
) {
4545 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4547 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
4548 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4549 clear_breakpoint (req
->info
);
4550 if (req
->event_kind
== EVENT_KIND_STEP
)
4551 ss_destroy (req
->info
);
4552 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
4553 clear_breakpoint (req
->info
);
4554 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
4555 clear_breakpoint (req
->info
);
4556 g_ptr_array_remove_index_fast (event_requests
, i
);
4561 mono_loader_unlock ();
4565 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
4567 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4568 return breakpoint_matches_assembly (req
->info
, assembly
);
4572 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
4573 Modifier
*m
= &req
->modifiers
[i
];
4575 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
4577 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
4578 for (j
= 0; m
->data
.assemblies
[j
]; ++j
)
4579 if (m
->data
.assemblies
[j
] == assembly
)
4589 * clear_event_requests_for_assembly:
4591 * Clear all events requests which reference ASSEMBLY.
4594 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
4599 mono_loader_lock ();
4603 for (i
= 0; i
< event_requests
->len
; ++i
) {
4604 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4606 if (event_req_matches_assembly (req
, assembly
)) {
4607 clear_event_request (req
->id
, req
->event_kind
);
4613 mono_loader_unlock ();
4617 * type_comes_from_assembly:
4619 * GHRFunc that returns TRUE if klass comes from assembly
4622 type_comes_from_assembly (gpointer klass
, gpointer also_klass
, gpointer assembly
)
4624 return (mono_class_get_image ((MonoClass
*)klass
) == mono_assembly_get_image ((MonoAssembly
*)assembly
));
4628 * clear_types_for_assembly:
4630 * Clears types from loaded_classes for a given assembly
4633 clear_types_for_assembly (MonoAssembly
*assembly
)
4635 mono_loader_lock ();
4636 g_hash_table_foreach_remove (loaded_classes
, type_comes_from_assembly
, assembly
);
4637 mono_loader_unlock ();
4641 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
4643 MonoInternalThread
*thread
= value
;
4644 Buffer
*buf
= user_data
;
4646 buffer_add_objid (buf
, (MonoObject
*)thread
);
4650 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
4652 guint8
*p
= invoke
->p
;
4653 guint8
*end
= invoke
->endp
;
4656 MonoMethodSignature
*sig
;
4659 MonoObject
*this, *res
, *exc
;
4662 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4666 if (invoke
->method
) {
4668 * Invoke this method directly, currently only Environment.Exit () is supported.
4671 DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (invoke
->method
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
4672 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
4673 g_assert_not_reached ();
4676 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4679 sig
= mono_method_signature (m
);
4681 if (m
->klass
->valuetype
)
4682 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
4684 this_buf
= g_alloca (sizeof (MonoObject
*));
4685 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
4686 /* Should be null */
4687 int type
= decode_byte (p
, &p
, end
);
4688 if (type
!= VALUE_TYPE_ID_NULL
)
4689 return ERR_INVALID_ARGUMENT
;
4690 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
4692 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
4697 if (!m
->klass
->valuetype
)
4698 this = *(MonoObject
**)this_buf
;
4702 DEBUG (1, printf ("[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (m
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
4704 if (this && this->vtable
->domain
!= domain
)
4707 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
4708 if (!strcmp (m
->name
, ".ctor")) {
4709 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
4710 return ERR_INVALID_ARGUMENT
;
4712 this = mono_object_new (domain
, m
->klass
);
4714 return ERR_INVALID_ARGUMENT
;
4718 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
4719 return ERR_INVALID_ARGUMENT
;
4721 nargs
= decode_int (p
, &p
, end
);
4722 if (nargs
!= sig
->param_count
)
4723 return ERR_INVALID_ARGUMENT
;
4724 /* Use alloca to get gc tracking */
4725 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
4726 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
4727 args
= g_alloca (nargs
* sizeof (gpointer
));
4728 for (i
= 0; i
< nargs
; ++i
) {
4729 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
4730 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
4734 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
4737 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
4738 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
4741 args
[i
] = arg_buf
[i
];
4748 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
4749 tls
->disable_breakpoints
= TRUE
;
4751 tls
->disable_breakpoints
= FALSE
;
4754 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4756 /* FIXME: Move this to arch specific code */
4757 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4758 if (invoke
->has_ctx
) {
4761 lmf_addr
= mono_get_lmf_addr ();
4764 memset (&ext
, 0, sizeof (ext
));
4766 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4767 /* Mark that this is a MonoLMFExt */
4768 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4769 ext
.lmf
.rsp
= (gssize
)&ext
;
4770 #elif defined(TARGET_X86)
4771 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
4772 /* Mark that this is a MonoLMFExt */
4773 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4774 ext
.lmf
.ebp
= (gssize
)&ext
;
4775 #elif defined(TARGET_ARM)
4776 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4777 /* Mark that this is a MonoLMFExt */
4778 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4779 ext
.lmf
.ebp
= (gssize
)&ext
;
4780 #elif defined(TARGET_POWERPC)
4781 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4782 /* Mark that this is a MonoLMFExt */
4783 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4784 ext
.lmf
.ebp
= (gssize
)&ext
;
4786 g_assert_not_reached ();
4789 ext
.debugger_invoke
= TRUE
;
4790 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4792 mono_set_lmf ((MonoLMF
*)&ext
);
4796 if (m
->klass
->valuetype
)
4797 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
4799 res
= mono_runtime_invoke (m
, this, args
, &exc
);
4801 buffer_add_byte (buf
, 0);
4802 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
4804 buffer_add_byte (buf
, 1);
4805 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4806 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
4807 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
4810 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
4811 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
4812 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
4813 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
4815 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
4821 tls
->disable_breakpoints
= FALSE
;
4823 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4824 if (invoke
->has_ctx
)
4825 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
4828 // FIXME: byref arguments
4836 * Invoke the method given by tls->pending_invoke in the current thread.
4839 invoke_method (void)
4841 DebuggerTlsData
*tls
;
4846 static void (*restore_context
) (void *);
4847 MonoContext restore_ctx
;
4849 if (!restore_context
)
4850 restore_context
= mono_get_restore_context ();
4852 tls
= TlsGetValue (debugger_tls_id
);
4856 * Store the `InvokeData *' in `tls->invoke' until we're done with
4857 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
4860 mono_loader_lock ();
4862 invoke
= tls
->pending_invoke
;
4864 tls
->pending_invoke
= NULL
;
4866 invoke
->last_invoke
= tls
->invoke
;
4867 tls
->invoke
= invoke
;
4869 mono_loader_unlock ();
4871 tls
->frames_up_to_date
= FALSE
;
4875 buffer_init (&buf
, 128);
4877 err
= do_invoke_method (tls
, &buf
, invoke
);
4879 /* Start suspending before sending the reply */
4880 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
4883 send_reply_packet (id
, err
, &buf
);
4887 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4889 if (invoke
->has_ctx
)
4890 save_thread_context (&restore_ctx
);
4892 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
4893 g_assert (tls
->resume_count
);
4894 tls
->resume_count
-= invoke
->suspend_count
;
4897 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
4900 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
4902 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
4903 * after the mono_runtime_invoke() already returned, but it doesn't matter
4904 * because we reset the abort here.
4907 mono_loader_lock ();
4909 if (tls
->abort_requested
)
4910 mono_thread_internal_reset_abort (tls
->thread
);
4912 tls
->invoke
= tls
->invoke
->last_invoke
;
4913 tls
->abort_requested
= FALSE
;
4915 mono_loader_unlock ();
4924 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
4926 MonoThread
*thread
= value
;
4927 DebuggerTlsData
*tls
;
4930 mono_loader_lock ();
4931 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4933 res
= tls
->really_suspended
;
4934 mono_loader_unlock ();
4940 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4943 case CMD_VM_VERSION
: {
4944 char *build_info
, *version
;
4946 build_info
= mono_get_runtime_build_info ();
4947 version
= g_strdup_printf ("mono %s", build_info
);
4949 buffer_add_string (buf
, version
); /* vm version */
4950 buffer_add_int (buf
, MAJOR_VERSION
);
4951 buffer_add_int (buf
, MINOR_VERSION
);
4952 g_free (build_info
);
4956 case CMD_VM_SET_PROTOCOL_VERSION
: {
4957 major_version
= decode_int (p
, &p
, end
);
4958 minor_version
= decode_int (p
, &p
, end
);
4959 protocol_version_set
= TRUE
;
4960 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
4963 case CMD_VM_ALL_THREADS
: {
4965 mono_loader_lock ();
4966 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
4967 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
4968 mono_loader_unlock ();
4971 case CMD_VM_SUSPEND
:
4973 wait_for_suspend ();
4976 if (suspend_count
== 0)
4977 return ERR_NOT_SUSPENDED
;
4980 case CMD_VM_DISPOSE
:
4981 /* Clear all event requests */
4982 mono_loader_lock ();
4983 while (event_requests
->len
> 0) {
4984 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4986 clear_event_request (req
->id
, req
->event_kind
);
4988 mono_loader_unlock ();
4990 // FIXME: Count resumes
4992 disconnected
= TRUE
;
4995 MonoInternalThread
*thread
;
4996 DebuggerTlsData
*tls
;
4997 MonoClass
*env_class
;
4998 MonoMethod
*exit_method
;
5002 exit_code
= decode_int (p
, &p
, end
);
5004 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
5006 /* Have to send a reply before exiting */
5007 send_reply_packet (id
, 0, buf
);
5009 /* Clear all event requests */
5010 mono_loader_lock ();
5011 while (event_requests
->len
> 0) {
5012 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
5014 clear_event_request (req
->id
, req
->event_kind
);
5016 mono_loader_unlock ();
5019 * The JDWP documentation says that the shutdown is not orderly. It doesn't
5020 * specify whenever a VM_DEATH event is sent. We currently do an orderly
5021 * shutdown by hijacking a thread to execute Environment.Exit (). This is
5022 * better than doing the shutdown ourselves, since it avoids various races.
5026 wait_for_suspend ();
5028 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
5029 g_assert (env_class
);
5030 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
5031 g_assert (exit_method
);
5033 mono_loader_lock ();
5034 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
5035 mono_loader_unlock ();
5038 mono_loader_lock ();
5039 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5040 mono_loader_unlock ();
5042 args
= g_new0 (gpointer
, 1);
5043 args
[0] = g_malloc (sizeof (int));
5044 *(int*)(args
[0]) = exit_code
;
5046 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
5047 tls
->pending_invoke
->method
= exit_method
;
5048 tls
->pending_invoke
->args
= args
;
5050 while (suspend_count
> 0)
5054 * No thread found, do it ourselves.
5055 * FIXME: This can race with normal shutdown etc.
5057 while (suspend_count
> 0)
5060 mono_runtime_set_shutting_down ();
5062 mono_threads_set_shutting_down ();
5064 /* Suspend all managed threads since the runtime is going away */
5065 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
5066 mono_thread_suspend_all_other_threads ();
5067 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
5068 mono_runtime_quit ();
5070 shutdown (conn_fd
, SD_BOTH
);
5072 shutdown (conn_fd
, SHUT_RDWR
);
5074 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
5080 case CMD_VM_INVOKE_METHOD
: {
5081 int objid
= decode_objid (p
, &p
, end
);
5083 DebuggerTlsData
*tls
;
5086 err
= get_object (objid
, (MonoObject
**)&thread
);
5090 flags
= decode_int (p
, &p
, end
);
5092 // Wait for suspending if it already started
5094 wait_for_suspend ();
5095 if (!is_suspended ())
5096 return ERR_NOT_SUSPENDED
;
5098 mono_loader_lock ();
5099 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
5100 mono_loader_unlock ();
5103 if (!tls
->really_suspended
)
5104 /* The thread is still running native code, can't do invokes */
5105 return ERR_NOT_SUSPENDED
;
5108 * Store the invoke data into tls, the thread will execute it after it is
5111 if (tls
->pending_invoke
)
5113 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
5114 tls
->pending_invoke
->id
= id
;
5115 tls
->pending_invoke
->flags
= flags
;
5116 tls
->pending_invoke
->p
= g_malloc (end
- p
);
5117 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
5118 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
5119 tls
->pending_invoke
->suspend_count
= suspend_count
;
5121 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
5122 resume_thread (THREAD_TO_INTERNAL (thread
));
5127 case CMD_VM_ABORT_INVOKE
: {
5128 int objid
= decode_objid (p
, &p
, end
);
5130 DebuggerTlsData
*tls
;
5133 err
= get_object (objid
, (MonoObject
**)&thread
);
5137 invoke_id
= decode_int (p
, &p
, end
);
5139 mono_loader_lock ();
5140 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
5143 if (tls
->abort_requested
) {
5144 mono_loader_unlock ();
5149 * Check whether we're still inside the mono_runtime_invoke() and that it's
5150 * actually the correct invocation.
5152 * Careful, we do not stop the thread that's doing the invocation, so we can't
5153 * inspect its stack. However, invoke_method() also acquires the loader lock
5154 * when it's done, so we're safe here.
5158 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
5159 mono_loader_unlock ();
5160 return ERR_NO_INVOCATION
;
5163 tls
->abort_requested
= TRUE
;
5165 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
5166 mono_loader_unlock ();
5171 return ERR_NOT_IMPLEMENTED
;
5178 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5183 case CMD_EVENT_REQUEST_SET
: {
5185 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
5188 MonoThread
*step_thread
;
5189 int size
= 0, depth
= 0, step_thread_id
= 0;
5192 event_kind
= decode_byte (p
, &p
, end
);
5193 suspend_policy
= decode_byte (p
, &p
, end
);
5194 nmodifiers
= decode_byte (p
, &p
, end
);
5196 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
5197 req
->id
= InterlockedIncrement (&event_request_id
);
5198 req
->event_kind
= event_kind
;
5199 req
->suspend_policy
= suspend_policy
;
5200 req
->nmodifiers
= nmodifiers
;
5203 for (i
= 0; i
< nmodifiers
; ++i
) {
5204 mod
= decode_byte (p
, &p
, end
);
5206 req
->modifiers
[i
].kind
= mod
;
5207 if (mod
== MOD_KIND_COUNT
) {
5208 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
5209 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
5210 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5213 location
= decode_long (p
, &p
, end
);
5214 } else if (mod
== MOD_KIND_STEP
) {
5215 step_thread_id
= decode_id (p
, &p
, end
);
5216 size
= decode_int (p
, &p
, end
);
5217 depth
= decode_int (p
, &p
, end
);
5218 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
5219 int id
= decode_id (p
, &p
, end
);
5221 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
5226 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
5227 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5231 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
5232 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
5233 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" : ""));
5235 req
->modifiers
[i
].data
.exc_class
= exc_class
;
5237 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
5239 return ERR_INVALID_ARGUMENT
;
5242 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
5243 int n
= decode_int (p
, &p
, end
);
5246 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
5247 for (j
= 0; j
< n
; ++j
) {
5248 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5250 g_free (req
->modifiers
[i
].data
.assemblies
);
5256 return ERR_NOT_IMPLEMENTED
;
5260 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5263 req
->info
= set_breakpoint (method
, location
, req
);
5264 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
5265 g_assert (step_thread_id
);
5267 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
5273 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
5278 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
5279 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
);
5280 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
5281 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
);
5282 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
5284 if (req
->nmodifiers
) {
5286 return ERR_NOT_IMPLEMENTED
;
5290 mono_loader_lock ();
5291 g_ptr_array_add (event_requests
, req
);
5292 mono_loader_unlock ();
5294 buffer_add_int (buf
, req
->id
);
5297 case CMD_EVENT_REQUEST_CLEAR
: {
5298 int etype
= decode_byte (p
, &p
, end
);
5299 int req_id
= decode_int (p
, &p
, end
);
5301 // FIXME: Make a faster mapping from req_id to request
5302 mono_loader_lock ();
5303 clear_event_request (req_id
, etype
);
5304 mono_loader_unlock ();
5307 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
5310 mono_loader_lock ();
5312 while (i
< event_requests
->len
) {
5313 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5315 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
5316 clear_breakpoint (req
->info
);
5318 g_ptr_array_remove_index_fast (event_requests
, i
);
5324 mono_loader_unlock ();
5328 return ERR_NOT_IMPLEMENTED
;
5335 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5341 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
5342 buffer_add_domainid (buf
, mono_get_root_domain ());
5345 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
5346 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5349 buffer_add_string (buf
, domain
->friendly_name
);
5352 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
5357 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5360 mono_loader_lock ();
5362 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5365 buffer_add_int (buf
, count
);
5366 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
5368 buffer_add_assemblyid (buf
, domain
, ass
);
5370 mono_loader_unlock ();
5373 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
5374 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5378 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
5381 case CMD_APPDOMAIN_GET_CORLIB
: {
5382 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5386 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
5389 case CMD_APPDOMAIN_CREATE_STRING
: {
5393 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5396 s
= decode_string (p
, &p
, end
);
5398 o
= mono_string_new (domain
, s
);
5399 buffer_add_objid (buf
, (MonoObject
*)o
);
5402 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
5404 MonoDomain
*domain2
;
5407 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
5410 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
5415 g_assert (domain
== domain2
);
5417 o
= mono_object_new (domain
, klass
);
5419 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
5423 buffer_add_objid (buf
, o
);
5427 return ERR_NOT_IMPLEMENTED
;
5434 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5440 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
5445 case CMD_ASSEMBLY_GET_LOCATION
: {
5446 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
5449 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
5453 if (ass
->image
->dynamic
) {
5454 buffer_add_id (buf
, 0);
5456 token
= mono_image_get_entry_point (ass
->image
);
5458 buffer_add_id (buf
, 0);
5460 m
= mono_get_method (ass
->image
, token
, NULL
);
5461 buffer_add_methodid (buf
, domain
, m
);
5466 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
5467 buffer_add_moduleid (buf
, domain
, ass
->image
);
5470 case CMD_ASSEMBLY_GET_OBJECT
: {
5471 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
5472 buffer_add_objid (buf
, o
);
5475 case CMD_ASSEMBLY_GET_TYPE
: {
5476 char *s
= decode_string (p
, &p
, end
);
5477 gboolean ignorecase
= decode_byte (p
, &p
, end
);
5478 MonoTypeNameParse info
;
5480 gboolean type_resolve
;
5482 if (!mono_reflection_parse_type (s
, &info
)) {
5485 if (info
.assembly
.name
)
5487 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
5489 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
5490 mono_reflection_free_type_info (&info
);
5495 case CMD_ASSEMBLY_GET_NAME
: {
5497 MonoAssembly
*mass
= ass
;
5499 name
= g_strdup_printf (
5500 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
5502 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
5503 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
5504 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
5505 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
5507 buffer_add_string (buf
, name
);
5512 return ERR_NOT_IMPLEMENTED
;
5519 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5525 case CMD_MODULE_GET_INFO
: {
5526 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
5529 basename
= g_path_get_basename (image
->name
);
5530 buffer_add_string (buf
, basename
); // name
5531 buffer_add_string (buf
, image
->module_name
); // scopename
5532 buffer_add_string (buf
, image
->name
); // fqname
5533 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
5534 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
5539 return ERR_NOT_IMPLEMENTED
;
5546 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
5548 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
5549 /* Special case these so the client doesn't have to handle Type objects */
5551 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
5552 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
5553 } else if (MONO_TYPE_IS_REFERENCE (t
))
5554 buffer_add_value (buf
, t
, &val
, domain
);
5556 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
5560 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
5566 buffer_add_int (buf
, 0);
5570 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5571 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
5574 buffer_add_int (buf
, nattrs
);
5576 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5577 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
5578 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
5579 MonoArray
*typed_args
, *named_args
;
5581 CattrNamedArg
*arginfo
;
5583 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
5585 buffer_add_methodid (buf
, domain
, attr
->ctor
);
5589 buffer_add_int (buf
, mono_array_length (typed_args
));
5590 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
5591 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
5593 t
= mono_method_signature (attr
->ctor
)->params
[j
];
5595 buffer_add_cattr_arg (buf
, t
, domain
, val
);
5598 buffer_add_int (buf
, 0);
5603 buffer_add_int (buf
, mono_array_length (named_args
));
5605 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
5606 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
5608 if (arginfo
[j
].prop
) {
5609 buffer_add_byte (buf
, 0x54);
5610 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
5611 } else if (arginfo
[j
].field
) {
5612 buffer_add_byte (buf
, 0x53);
5614 g_assert_not_reached ();
5617 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
5620 buffer_add_int (buf
, 0);
5627 type_commands_internal (int command
, MonoClass
*klass
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5637 case CMD_TYPE_GET_INFO
: {
5638 buffer_add_string (buf
, klass
->name_space
);
5639 buffer_add_string (buf
, klass
->name
);
5641 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
5642 buffer_add_string (buf
, name
);
5644 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
5645 buffer_add_moduleid (buf
, domain
, klass
->image
);
5646 buffer_add_typeid (buf
, domain
, klass
->parent
);
5647 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
5648 buffer_add_typeid (buf
, domain
, klass
->element_class
);
5650 buffer_add_id (buf
, 0);
5651 buffer_add_int (buf
, klass
->type_token
);
5652 buffer_add_byte (buf
, klass
->rank
);
5653 buffer_add_int (buf
, klass
->flags
);
5655 type
= &klass
->byval_arg
;
5656 // FIXME: Can't decide whenever a class represents a byref type
5659 if (type
->type
== MONO_TYPE_PTR
)
5661 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
5663 if (type
->type
== MONO_TYPE_VALUETYPE
)
5665 if (klass
->enumtype
)
5667 buffer_add_byte (buf
, b
);
5670 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5672 buffer_add_int (buf
, nnested
);
5674 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5675 buffer_add_typeid (buf
, domain
, nested
);
5678 case CMD_TYPE_GET_METHODS
: {
5681 gpointer iter
= NULL
;
5684 mono_class_setup_methods (klass
);
5686 nmethods
= mono_class_num_methods (klass
);
5688 buffer_add_int (buf
, nmethods
);
5690 while ((m
= mono_class_get_methods (klass
, &iter
))) {
5691 buffer_add_methodid (buf
, domain
, m
);
5694 g_assert (i
== nmethods
);
5697 case CMD_TYPE_GET_FIELDS
: {
5700 gpointer iter
= NULL
;
5703 nfields
= mono_class_num_fields (klass
);
5705 buffer_add_int (buf
, nfields
);
5707 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5708 buffer_add_fieldid (buf
, domain
, f
);
5709 buffer_add_string (buf
, f
->name
);
5710 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
5711 buffer_add_int (buf
, f
->type
->attrs
);
5714 g_assert (i
== nfields
);
5717 case CMD_TYPE_GET_PROPERTIES
: {
5720 gpointer iter
= NULL
;
5723 nprops
= mono_class_num_properties (klass
);
5725 buffer_add_int (buf
, nprops
);
5727 while ((p
= mono_class_get_properties (klass
, &iter
))) {
5728 buffer_add_propertyid (buf
, domain
, p
);
5729 buffer_add_string (buf
, p
->name
);
5730 buffer_add_methodid (buf
, domain
, p
->get
);
5731 buffer_add_methodid (buf
, domain
, p
->set
);
5732 buffer_add_int (buf
, p
->attrs
);
5735 g_assert (i
== nprops
);
5738 case CMD_TYPE_GET_CATTRS
: {
5739 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5740 MonoCustomAttrInfo
*cinfo
;
5742 cinfo
= mono_custom_attrs_from_class (klass
);
5744 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5747 case CMD_TYPE_GET_FIELD_CATTRS
: {
5748 MonoClass
*attr_klass
;
5749 MonoCustomAttrInfo
*cinfo
;
5750 MonoClassField
*field
;
5752 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5755 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5759 cinfo
= mono_custom_attrs_from_field (klass
, field
);
5761 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5764 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
5765 MonoClass
*attr_klass
;
5766 MonoCustomAttrInfo
*cinfo
;
5769 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
5772 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5776 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
5778 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5781 case CMD_TYPE_GET_VALUES
: {
5789 len
= decode_int (p
, &p
, end
);
5790 for (i
= 0; i
< len
; ++i
) {
5791 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5795 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5796 return ERR_INVALID_FIELDID
;
5797 if (mono_class_field_is_special_static (f
))
5798 return ERR_INVALID_FIELDID
;
5800 /* Check that the field belongs to the object */
5802 for (k
= klass
; k
; k
= k
->parent
) {
5803 if (k
== f
->parent
) {
5809 return ERR_INVALID_FIELDID
;
5811 vtable
= mono_class_vtable (domain
, f
->parent
);
5812 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5813 mono_field_static_get_value (vtable
, f
, val
);
5814 buffer_add_value (buf
, f
->type
, val
, domain
);
5819 case CMD_TYPE_SET_VALUES
: {
5827 len
= decode_int (p
, &p
, end
);
5828 for (i
= 0; i
< len
; ++i
) {
5829 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5833 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5834 return ERR_INVALID_FIELDID
;
5835 if (mono_class_field_is_special_static (f
))
5836 return ERR_INVALID_FIELDID
;
5838 /* Check that the field belongs to the object */
5840 for (k
= klass
; k
; k
= k
->parent
) {
5841 if (k
== f
->parent
) {
5847 return ERR_INVALID_FIELDID
;
5849 // FIXME: Check for literal/const
5851 vtable
= mono_class_vtable (domain
, f
->parent
);
5852 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5853 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
5858 if (MONO_TYPE_IS_REFERENCE (f
->type
))
5859 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
5861 mono_field_static_set_value (vtable
, f
, val
);
5866 case CMD_TYPE_GET_OBJECT
: {
5867 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
5868 buffer_add_objid (buf
, o
);
5871 case CMD_TYPE_GET_SOURCE_FILES
:
5872 case CMD_TYPE_GET_SOURCE_FILES_2
: {
5873 gpointer iter
= NULL
;
5875 char *source_file
, *base
;
5879 files
= g_ptr_array_new ();
5881 while ((method
= mono_class_get_methods (klass
, &iter
))) {
5882 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
5885 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
5889 for (i
= 0; i
< files
->len
; ++i
)
5890 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
5892 if (i
== files
->len
)
5893 g_ptr_array_add (files
, g_strdup (source_file
));
5894 g_free (source_file
);
5898 buffer_add_int (buf
, files
->len
);
5899 for (i
= 0; i
< files
->len
; ++i
) {
5900 source_file
= g_ptr_array_index (files
, i
);
5901 if (command
== CMD_TYPE_GET_SOURCE_FILES_2
) {
5902 buffer_add_string (buf
, source_file
);
5904 base
= g_path_get_basename (source_file
);
5905 buffer_add_string (buf
, base
);
5908 g_free (source_file
);
5910 g_ptr_array_free (files
, TRUE
);
5913 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
5914 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5918 if (mono_class_is_assignable_from (klass
, oklass
))
5919 buffer_add_byte (buf
, 1);
5921 buffer_add_byte (buf
, 0);
5925 return ERR_NOT_IMPLEMENTED
;
5932 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5935 MonoDomain
*old_domain
;
5939 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5943 old_domain
= mono_domain_get ();
5945 mono_domain_set (domain
, TRUE
);
5947 err
= type_commands_internal (command
, klass
, domain
, p
, end
, buf
);
5949 mono_domain_set (old_domain
, TRUE
);
5955 method_commands_internal (int command
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5957 MonoMethodHeader
*header
;
5960 case CMD_METHOD_GET_NAME
: {
5961 buffer_add_string (buf
, method
->name
);
5964 case CMD_METHOD_GET_DECLARING_TYPE
: {
5965 buffer_add_typeid (buf
, domain
, method
->klass
);
5968 case CMD_METHOD_GET_DEBUG_INFO
: {
5969 MonoDebugMethodInfo
*minfo
;
5971 int i
, n_il_offsets
;
5975 header
= mono_method_get_header (method
);
5977 buffer_add_int (buf
, 0);
5978 buffer_add_string (buf
, "");
5979 buffer_add_int (buf
, 0);
5983 minfo
= mono_debug_lookup_method (method
);
5985 buffer_add_int (buf
, header
->code_size
);
5986 buffer_add_string (buf
, "");
5987 buffer_add_int (buf
, 0);
5988 mono_metadata_free_mh (header
);
5992 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
5993 buffer_add_int (buf
, header
->code_size
);
5994 buffer_add_string (buf
, source_file
);
5995 buffer_add_int (buf
, n_il_offsets
);
5996 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5997 for (i
= 0; i
< n_il_offsets
; ++i
) {
5998 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5999 buffer_add_int (buf
, il_offsets
[i
]);
6000 buffer_add_int (buf
, line_numbers
[i
]);
6002 g_free (source_file
);
6003 g_free (il_offsets
);
6004 g_free (line_numbers
);
6005 mono_metadata_free_mh (header
);
6008 case CMD_METHOD_GET_PARAM_INFO
: {
6009 MonoMethodSignature
*sig
= mono_method_signature (method
);
6013 /* FIXME: mono_class_from_mono_type () and byrefs */
6015 /* FIXME: Use a smaller encoding */
6016 buffer_add_int (buf
, sig
->call_convention
);
6017 buffer_add_int (buf
, sig
->param_count
);
6018 buffer_add_int (buf
, sig
->generic_param_count
);
6019 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
6020 for (i
= 0; i
< sig
->param_count
; ++i
) {
6022 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
6025 /* Emit parameter names */
6026 names
= g_new (char *, sig
->param_count
);
6027 mono_method_get_param_names (method
, (const char **) names
);
6028 for (i
= 0; i
< sig
->param_count
; ++i
)
6029 buffer_add_string (buf
, names
[i
]);
6034 case CMD_METHOD_GET_LOCALS_INFO
: {
6035 int i
, j
, num_locals
;
6036 MonoDebugLocalsInfo
*locals
;
6038 header
= mono_method_get_header (method
);
6041 buffer_add_int (buf
, header
->num_locals
);
6044 for (i
= 0; i
< header
->num_locals
; ++i
)
6045 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
6048 locals
= mono_debug_lookup_locals (method
);
6050 num_locals
= locals
->num_locals
;
6053 for (i
= 0; i
< header
->num_locals
; ++i
) {
6054 for (j
= 0; j
< num_locals
; ++j
)
6055 if (locals
->locals
[j
].index
== i
)
6058 buffer_add_string (buf
, locals
->locals
[j
].name
);
6060 buffer_add_string (buf
, "");
6064 for (i
= 0; i
< header
->num_locals
; ++i
) {
6065 for (j
= 0; j
< num_locals
; ++j
)
6066 if (locals
->locals
[j
].index
== i
)
6068 if (j
< num_locals
&& locals
->locals
[j
].block
) {
6069 buffer_add_int (buf
, locals
->locals
[j
].block
->start_offset
);
6070 buffer_add_int (buf
, locals
->locals
[j
].block
->end_offset
);
6072 buffer_add_int (buf
, 0);
6073 buffer_add_int (buf
, header
->code_size
);
6076 mono_metadata_free_mh (header
);
6079 mono_debug_symfile_free_locals (locals
);
6083 case CMD_METHOD_GET_INFO
:
6084 buffer_add_int (buf
, method
->flags
);
6085 buffer_add_int (buf
, method
->iflags
);
6086 buffer_add_int (buf
, method
->token
);
6088 case CMD_METHOD_GET_BODY
: {
6091 header
= mono_method_get_header (method
);
6093 buffer_add_int (buf
, 0);
6095 buffer_add_int (buf
, header
->code_size
);
6096 for (i
= 0; i
< header
->code_size
; ++i
)
6097 buffer_add_byte (buf
, header
->code
[i
]);
6099 mono_metadata_free_mh (header
);
6102 case CMD_METHOD_RESOLVE_TOKEN
: {
6103 guint32 token
= decode_int (p
, &p
, end
);
6106 switch (mono_metadata_token_code (token
)) {
6107 case MONO_TOKEN_STRING
: {
6111 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
6114 s2
= mono_string_to_utf8 (s
);
6116 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
6117 buffer_add_string (buf
, s2
);
6123 MonoClass
*handle_class
;
6125 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
6126 val
= mono_method_get_wrapper_data (method
, token
);
6127 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
6129 if (handle_class
== NULL
) {
6130 // Can't figure out the token type
6131 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
6135 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
6139 if (handle_class
== mono_defaults
.typehandle_class
) {
6140 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
6141 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
6142 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
6143 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
6144 buffer_add_fieldid (buf
, domain
, val
);
6145 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
6146 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
6147 buffer_add_methodid (buf
, domain
, val
);
6148 } else if (handle_class
== mono_defaults
.string_class
) {
6151 s
= mono_string_to_utf8 (val
);
6152 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
6153 buffer_add_string (buf
, s
);
6156 g_assert_not_reached ();
6164 return ERR_NOT_IMPLEMENTED
;
6171 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6174 MonoDomain
*old_domain
;
6178 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
6182 old_domain
= mono_domain_get ();
6184 mono_domain_set (domain
, TRUE
);
6186 err
= method_commands_internal (command
, method
, domain
, p
, end
, buf
);
6188 mono_domain_set (old_domain
, TRUE
);
6194 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6196 int objid
= decode_objid (p
, &p
, end
);
6198 MonoThread
*thread_obj
;
6199 MonoInternalThread
*thread
;
6201 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6205 thread
= THREAD_TO_INTERNAL (thread_obj
);
6208 case CMD_THREAD_GET_NAME
: {
6210 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
6213 buffer_add_int (buf
, 0);
6218 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
6220 buffer_add_int (buf
, len
);
6221 buffer_add_data (buf
, (guint8
*)name
, len
);
6226 case CMD_THREAD_GET_FRAME_INFO
: {
6227 DebuggerTlsData
*tls
;
6228 int i
, start_frame
, length
;
6230 // Wait for suspending if it already started
6232 wait_for_suspend ();
6233 if (!is_suspended ())
6234 return ERR_NOT_SUSPENDED
;
6236 start_frame
= decode_int (p
, &p
, end
);
6237 length
= decode_int (p
, &p
, end
);
6239 if (start_frame
!= 0 || length
!= -1)
6240 return ERR_NOT_IMPLEMENTED
;
6242 mono_loader_lock ();
6243 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6244 mono_loader_unlock ();
6247 compute_frame_info (thread
, tls
);
6249 buffer_add_int (buf
, tls
->frame_count
);
6250 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6251 buffer_add_int (buf
, tls
->frames
[i
]->id
);
6252 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->method
);
6253 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
6255 * Instead of passing the frame type directly to the client, we associate
6256 * it with the previous frame using a set of flags. This avoids lots of
6257 * conditional code in the client, since a frame whose type isn't
6258 * FRAME_TYPE_MANAGED has no method, location, etc.
6260 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
6265 case CMD_THREAD_GET_STATE
:
6266 buffer_add_int (buf
, thread
->state
);
6268 case CMD_THREAD_GET_INFO
:
6269 buffer_add_byte (buf
, thread
->threadpool_thread
);
6271 case CMD_THREAD_GET_ID
:
6272 buffer_add_long (buf
, (guint64
)(gsize
)thread
);
6275 return ERR_NOT_IMPLEMENTED
;
6282 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6286 MonoThread
*thread_obj
;
6287 MonoInternalThread
*thread
;
6289 DebuggerTlsData
*tls
;
6291 MonoDebugMethodJitInfo
*jit
;
6292 MonoDebugVarInfo
*var
;
6293 MonoMethodSignature
*sig
;
6295 MonoMethodHeader
*header
;
6297 objid
= decode_objid (p
, &p
, end
);
6298 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
6302 thread
= THREAD_TO_INTERNAL (thread_obj
);
6304 id
= decode_id (p
, &p
, end
);
6306 mono_loader_lock ();
6307 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6308 mono_loader_unlock ();
6311 for (i
= 0; i
< tls
->frame_count
; ++i
) {
6312 if (tls
->frames
[i
]->id
== id
)
6315 if (i
== tls
->frame_count
)
6316 return ERR_INVALID_FRAMEID
;
6318 frame
= tls
->frames
[i
];
6320 if (!frame
->has_ctx
)
6322 return ERR_INVALID_FRAMEID
;
6325 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
6327 /* This could happen for aot images with no jit debug info */
6328 return ERR_ABSENT_INFORMATION
;
6332 sig
= mono_method_signature (frame
->method
);
6335 case CMD_STACK_FRAME_GET_VALUES
: {
6336 len
= decode_int (p
, &p
, end
);
6337 header
= mono_method_get_header (frame
->method
);
6339 for (i
= 0; i
< len
; ++i
) {
6340 pos
= decode_int (p
, &p
, end
);
6345 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6347 var
= &jit
->params
[pos
];
6349 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6351 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6353 var
= &jit
->locals
[pos
];
6355 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
6358 mono_metadata_free_mh (header
);
6361 case CMD_STACK_FRAME_GET_THIS
: {
6362 if (frame
->method
->klass
->valuetype
) {
6363 if (!sig
->hasthis
) {
6364 MonoObject
*p
= NULL
;
6365 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
6367 add_var (buf
, &frame
->method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6370 if (!sig
->hasthis
) {
6371 MonoObject
*p
= NULL
;
6372 buffer_add_value (buf
, &frame
->method
->klass
->byval_arg
, &p
, frame
->domain
);
6374 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
6379 case CMD_STACK_FRAME_SET_VALUES
: {
6382 MonoDebugVarInfo
*var
;
6384 len
= decode_int (p
, &p
, end
);
6385 header
= mono_method_get_header (frame
->method
);
6387 for (i
= 0; i
< len
; ++i
) {
6388 pos
= decode_int (p
, &p
, end
);
6393 g_assert (pos
>= 0 && pos
< jit
->num_params
);
6395 t
= sig
->params
[pos
];
6396 var
= &jit
->params
[pos
];
6398 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
6400 t
= header
->locals
[pos
];
6401 var
= &jit
->locals
[pos
];
6404 if (MONO_TYPE_IS_REFERENCE (t
))
6405 val_buf
= g_alloca (sizeof (MonoObject
*));
6407 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
6408 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
6412 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
);
6414 mono_metadata_free_mh (header
);
6418 return ERR_NOT_IMPLEMENTED
;
6425 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6428 int objid
, err
, index
, len
, i
, esize
;
6431 objid
= decode_objid (p
, &p
, end
);
6432 err
= get_object (objid
, (MonoObject
**)&arr
);
6437 case CMD_ARRAY_REF_GET_LENGTH
:
6438 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
6440 buffer_add_int (buf
, arr
->max_length
);
6441 buffer_add_int (buf
, 0);
6443 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
6444 buffer_add_int (buf
, arr
->bounds
[i
].length
);
6445 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
6449 case CMD_ARRAY_REF_GET_VALUES
:
6450 index
= decode_int (p
, &p
, end
);
6451 len
= decode_int (p
, &p
, end
);
6453 g_assert (index
>= 0 && len
>= 0);
6454 // Reordered to avoid integer overflow
6455 g_assert (!(index
> arr
->max_length
- len
));
6457 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6458 for (i
= index
; i
< index
+ len
; ++i
) {
6459 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6460 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
6463 case CMD_ARRAY_REF_SET_VALUES
:
6464 index
= decode_int (p
, &p
, end
);
6465 len
= decode_int (p
, &p
, end
);
6467 g_assert (index
>= 0 && len
>= 0);
6468 // Reordered to avoid integer overflow
6469 g_assert (!(index
> arr
->max_length
- len
));
6471 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
6472 for (i
= index
; i
< index
+ len
; ++i
) {
6473 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
6475 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
6479 return ERR_NOT_IMPLEMENTED
;
6486 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6492 objid
= decode_objid (p
, &p
, end
);
6493 err
= get_object (objid
, (MonoObject
**)&str
);
6498 case CMD_STRING_REF_GET_VALUE
:
6499 s
= mono_string_to_utf8 (str
);
6500 buffer_add_string (buf
, s
);
6504 return ERR_NOT_IMPLEMENTED
;
6511 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6520 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
6521 objid
= decode_objid (p
, &p
, end
);
6522 err
= get_object (objid
, &obj
);
6524 buffer_add_int (buf
, 1);
6526 buffer_add_int (buf
, 0);
6530 objid
= decode_objid (p
, &p
, end
);
6531 err
= get_object (objid
, &obj
);
6536 case CMD_OBJECT_REF_GET_TYPE
:
6537 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
6539 case CMD_OBJECT_REF_GET_VALUES
:
6540 len
= decode_int (p
, &p
, end
);
6542 for (i
= 0; i
< len
; ++i
) {
6543 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6547 /* Check that the field belongs to the object */
6549 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6550 if (k
== f
->parent
) {
6556 return ERR_INVALID_FIELDID
;
6558 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6562 if (mono_class_field_is_special_static (f
))
6563 return ERR_INVALID_FIELDID
;
6565 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6566 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6567 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6568 mono_field_static_get_value (vtable
, f
, val
);
6569 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
6572 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
6576 case CMD_OBJECT_REF_SET_VALUES
:
6577 len
= decode_int (p
, &p
, end
);
6579 for (i
= 0; i
< len
; ++i
) {
6580 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6584 /* Check that the field belongs to the object */
6586 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6587 if (k
== f
->parent
) {
6593 return ERR_INVALID_FIELDID
;
6595 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6599 if (mono_class_field_is_special_static (f
))
6600 return ERR_INVALID_FIELDID
;
6602 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6603 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6605 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6606 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
6611 mono_field_static_set_value (vtable
, f
, val
);
6614 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
6620 case CMD_OBJECT_REF_GET_ADDRESS
:
6621 buffer_add_long (buf
, (gssize
)obj
);
6623 case CMD_OBJECT_REF_GET_DOMAIN
:
6624 buffer_add_domainid (buf
, obj
->vtable
->domain
);
6627 return ERR_NOT_IMPLEMENTED
;
6634 command_set_to_string (CommandSet command_set
)
6636 switch (command_set
) {
6639 case CMD_SET_OBJECT_REF
:
6640 return "OBJECT_REF";
6641 case CMD_SET_STRING_REF
:
6642 return "STRING_REF";
6643 case CMD_SET_THREAD
:
6645 case CMD_SET_ARRAY_REF
:
6647 case CMD_SET_EVENT_REQUEST
:
6648 return "EVENT_REQUEST";
6649 case CMD_SET_STACK_FRAME
:
6650 return "STACK_FRAME";
6651 case CMD_SET_APPDOMAIN
:
6653 case CMD_SET_ASSEMBLY
:
6655 case CMD_SET_METHOD
:
6659 case CMD_SET_MODULE
:
6671 * This thread handles communication with the debugger client using a JDWP
6674 static guint32 WINAPI
6675 debugger_thread (void *arg
)
6677 int res
, len
, id
, flags
, command_set
, command
;
6678 guint8 header
[HEADER_LENGTH
];
6679 guint8
*data
, *p
, *end
;
6684 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
6686 debugger_thread_id
= GetCurrentThreadId ();
6688 mono_jit_thread_attach (mono_get_root_domain ());
6690 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
6692 mono_set_is_debugger_attached (TRUE
);
6695 res
= recv_length (conn_fd
, header
, HEADER_LENGTH
, 0);
6697 /* This will break if the socket is closed during shutdown too */
6698 if (res
!= HEADER_LENGTH
)
6702 end
= header
+ HEADER_LENGTH
;
6704 len
= decode_int (p
, &p
, end
);
6705 id
= decode_int (p
, &p
, end
);
6706 flags
= decode_byte (p
, &p
, end
);
6707 command_set
= decode_byte (p
, &p
, end
);
6708 command
= decode_byte (p
, &p
, end
);
6710 g_assert (flags
== 0);
6712 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set
), command
, id
));
6714 data
= g_malloc (len
- HEADER_LENGTH
);
6715 if (len
- HEADER_LENGTH
> 0)
6717 res
= recv_length (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
6718 if (res
!= len
- HEADER_LENGTH
)
6723 end
= data
+ (len
- HEADER_LENGTH
);
6725 buffer_init (&buf
, 128);
6730 /* Process the request */
6731 switch (command_set
) {
6733 err
= vm_commands (command
, id
, p
, end
, &buf
);
6734 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
6735 /* Sent after the invoke is complete */
6738 case CMD_SET_EVENT_REQUEST
:
6739 err
= event_commands (command
, p
, end
, &buf
);
6741 case CMD_SET_APPDOMAIN
:
6742 err
= domain_commands (command
, p
, end
, &buf
);
6744 case CMD_SET_ASSEMBLY
:
6745 err
= assembly_commands (command
, p
, end
, &buf
);
6747 case CMD_SET_MODULE
:
6748 err
= module_commands (command
, p
, end
, &buf
);
6751 err
= type_commands (command
, p
, end
, &buf
);
6753 case CMD_SET_METHOD
:
6754 err
= method_commands (command
, p
, end
, &buf
);
6756 case CMD_SET_THREAD
:
6757 err
= thread_commands (command
, p
, end
, &buf
);
6759 case CMD_SET_STACK_FRAME
:
6760 err
= frame_commands (command
, p
, end
, &buf
);
6762 case CMD_SET_ARRAY_REF
:
6763 err
= array_commands (command
, p
, end
, &buf
);
6765 case CMD_SET_STRING_REF
:
6766 err
= string_commands (command
, p
, end
, &buf
);
6768 case CMD_SET_OBJECT_REF
:
6769 err
= object_commands (command
, p
, end
, &buf
);
6772 err
= ERR_NOT_IMPLEMENTED
;
6776 send_reply_packet (id
, err
, &buf
);
6781 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
6785 mono_set_is_debugger_attached (FALSE
);
6787 mono_mutex_lock (&debugger_thread_exited_mutex
);
6788 debugger_thread_exited
= TRUE
;
6789 mono_cond_signal (&debugger_thread_exited_cond
);
6790 mono_mutex_unlock (&debugger_thread_exited_mutex
);
6792 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6797 #else /* DISABLE_DEBUGGER_AGENT */
6800 mono_debugger_agent_parse_options (char *options
)
6802 g_error ("This runtime is configure with the debugger agent disabled.");
6806 mono_debugger_agent_init (void)
6811 mono_debugger_agent_breakpoint_hit (void *sigctx
)
6816 mono_debugger_agent_single_step_event (void *sigctx
)
6821 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
6826 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
6832 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
6833 MonoContext
*catch_ctx
)