2 * debugger-agent.c: Debugger back-end module
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2009 Novell, Inc.
14 #ifdef HAVE_SYS_TYPES_H
15 #include <sys/types.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 #include <sys/socket.h>
20 #ifdef HAVE_NETINET_TCP_H
21 #include <netinet/tcp.h>
23 #ifdef HAVE_NETINET_IN_H
24 #include <netinet/in.h>
39 #ifdef HAVE_UCONTEXT_H
49 /* cygwin's headers do not seem to define these */
50 void WSAAPI
freeaddrinfo (struct addrinfo
*);
51 int WSAAPI
getaddrinfo (const char*,const char*,const struct addrinfo
*,
53 int WSAAPI
getnameinfo(const struct sockaddr
*,socklen_t
,char*,DWORD
,
58 #ifdef PLATFORM_ANDROID
60 #include <linux/tcp.h>
61 #include <sys/endian.h>
64 #include <mono/metadata/mono-debug.h>
65 #include <mono/metadata/mono-debug-debugger.h>
66 #include <mono/metadata/debug-mono-symfile.h>
67 #include <mono/metadata/gc-internal.h>
68 #include <mono/metadata/threads-types.h>
69 #include <mono/metadata/socket-io.h>
70 #include <mono/utils/mono-semaphore.h>
71 #include "debugger-agent.h"
74 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
75 #define DISABLE_DEBUGGER_AGENT 1
78 #ifdef DISABLE_SOFT_DEBUG
79 #define DISABLE_DEBUGGER_AGENT 1
82 #ifndef DISABLE_DEBUGGER_AGENT
83 #include <mono/io-layer/mono-mutex.h>
85 /* Definitions to make backporting to 2.6 easier */
86 //#define MonoInternalThread MonoThread
87 //#define mono_thread_internal_current mono_thread_current
88 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
111 MonoDebugMethodJitInfo
*jit
;
114 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
115 * the frame can become invalid.
126 /* This is the context which needs to be restored after the invoke */
130 * If this is set, invoke this method with the arguments given by ARGS.
134 guint32 suspend_count
;
141 gboolean has_context
;
142 gpointer resume_event
;
143 /* This is computed on demand when it is requested using the wire protocol */
144 /* It is freed up when the thread is resumed */
148 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
151 gboolean frames_up_to_date
;
153 * Points to data about a pending invoke which needs to be executed after the thread
158 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
163 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
164 * within a finite amount of time.
168 * Set to TRUE if this thread is suspended in suspend_current ().
170 gboolean really_suspended
;
171 /* Used to pass the context to the breakpoint/single step handler */
172 MonoContext handler_ctx
;
173 /* Whenever thread_stop () was called for this thread */
176 /* Number of thread interruptions not yet processed */
177 gint32 interrupt_count
;
179 /* Whenever to disable breakpoints (used during invokes) */
180 gboolean disable_breakpoints
;
183 * Number of times this thread has been resumed using resume_thread ().
185 guint32 resume_count
;
187 MonoInternalThread
*thread
;
190 * Information about the frame which transitioned to native code for running
193 StackFrameInfo async_last_frame
;
196 * The context where the stack walk can be started for running threads.
198 MonoContext async_ctx
;
200 gboolean has_async_ctx
;
203 * The lmf where the stack walk can be started for running threads.
208 * The callee address of the last mono_runtime_invoke call
210 gpointer invoke_addr
;
214 * Wire Protocol definitions
217 #define HEADER_LENGTH 11
219 #define MAJOR_VERSION 2
220 #define MINOR_VERSION 0
224 CMD_SET_OBJECT_REF
= 9,
225 CMD_SET_STRING_REF
= 10,
227 CMD_SET_ARRAY_REF
= 13,
228 CMD_SET_EVENT_REQUEST
= 15,
229 CMD_SET_STACK_FRAME
= 16,
230 CMD_SET_APPDOMAIN
= 20,
231 CMD_SET_ASSEMBLY
= 21,
239 EVENT_KIND_VM_START
= 0,
240 EVENT_KIND_VM_DEATH
= 1,
241 EVENT_KIND_THREAD_START
= 2,
242 EVENT_KIND_THREAD_DEATH
= 3,
243 EVENT_KIND_APPDOMAIN_CREATE
= 4,
244 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
245 EVENT_KIND_METHOD_ENTRY
= 6,
246 EVENT_KIND_METHOD_EXIT
= 7,
247 EVENT_KIND_ASSEMBLY_LOAD
= 8,
248 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
249 EVENT_KIND_BREAKPOINT
= 10,
250 EVENT_KIND_STEP
= 11,
251 EVENT_KIND_TYPE_LOAD
= 12,
252 EVENT_KIND_EXCEPTION
= 13
256 SUSPEND_POLICY_NONE
= 0,
257 SUSPEND_POLICY_EVENT_THREAD
= 1,
258 SUSPEND_POLICY_ALL
= 2
263 ERR_INVALID_OBJECT
= 20,
264 ERR_INVALID_FIELDID
= 25,
265 ERR_INVALID_FRAMEID
= 30,
266 ERR_NOT_IMPLEMENTED
= 100,
267 ERR_NOT_SUSPENDED
= 101,
268 ERR_INVALID_ARGUMENT
= 102,
274 MOD_KIND_THREAD_ONLY
= 3,
275 MOD_KIND_LOCATION_ONLY
= 7,
276 MOD_KIND_EXCEPTION_ONLY
= 8,
278 MOD_KIND_ASSEMBLY_ONLY
= 11
293 TOKEN_TYPE_STRING
= 0,
295 TOKEN_TYPE_FIELD
= 2,
296 TOKEN_TYPE_METHOD
= 3,
297 TOKEN_TYPE_UNKNOWN
= 4
301 VALUE_TYPE_ID_NULL
= 0xf0,
302 VALUE_TYPE_ID_TYPE
= 0xf1
306 FRAME_FLAG_DEBUGGER_INVOKE
= 1
310 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
311 INVOKE_FLAG_SINGLE_THREADED
= 2
316 CMD_VM_ALL_THREADS
= 2,
321 CMD_VM_INVOKE_METHOD
= 7
325 CMD_THREAD_GET_FRAME_INFO
= 1,
326 CMD_THREAD_GET_NAME
= 2,
327 CMD_THREAD_GET_STATE
= 3,
328 CMD_THREAD_GET_INFO
= 4
332 CMD_EVENT_REQUEST_SET
= 1,
333 CMD_EVENT_REQUEST_CLEAR
= 2,
334 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
342 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
343 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
344 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
345 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
346 CMD_APPDOMAIN_CREATE_STRING
= 5,
347 CMD_APPDOMAIN_GET_CORLIB
= 6
351 CMD_ASSEMBLY_GET_LOCATION
= 1,
352 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
353 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
354 CMD_ASSEMBLY_GET_OBJECT
= 4,
355 CMD_ASSEMBLY_GET_TYPE
= 5,
356 CMD_ASSEMBLY_GET_NAME
= 6
360 CMD_MODULE_GET_INFO
= 1,
364 CMD_METHOD_GET_NAME
= 1,
365 CMD_METHOD_GET_DECLARING_TYPE
= 2,
366 CMD_METHOD_GET_DEBUG_INFO
= 3,
367 CMD_METHOD_GET_PARAM_INFO
= 4,
368 CMD_METHOD_GET_LOCALS_INFO
= 5,
369 CMD_METHOD_GET_INFO
= 6,
370 CMD_METHOD_GET_BODY
= 7,
371 CMD_METHOD_RESOLVE_TOKEN
= 8,
375 CMD_TYPE_GET_INFO
= 1,
376 CMD_TYPE_GET_METHODS
= 2,
377 CMD_TYPE_GET_FIELDS
= 3,
378 CMD_TYPE_GET_VALUES
= 4,
379 CMD_TYPE_GET_OBJECT
= 5,
380 CMD_TYPE_GET_SOURCE_FILES
= 6,
381 CMD_TYPE_SET_VALUES
= 7,
382 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
383 CMD_TYPE_GET_PROPERTIES
= 9,
384 CMD_TYPE_GET_CATTRS
= 10,
385 CMD_TYPE_GET_FIELD_CATTRS
= 11,
386 CMD_TYPE_GET_PROPERTY_CATTRS
= 12
390 CMD_STACK_FRAME_GET_VALUES
= 1,
391 CMD_STACK_FRAME_GET_THIS
= 2,
392 CMD_STACK_FRAME_SET_VALUES
= 3
396 CMD_ARRAY_REF_GET_LENGTH
= 1,
397 CMD_ARRAY_REF_GET_VALUES
= 2,
398 CMD_ARRAY_REF_SET_VALUES
= 3,
402 CMD_STRING_REF_GET_VALUE
= 1,
406 CMD_OBJECT_REF_GET_TYPE
= 1,
407 CMD_OBJECT_REF_GET_VALUES
= 2,
408 CMD_OBJECT_REF_IS_COLLECTED
= 3,
409 CMD_OBJECT_REF_GET_ADDRESS
= 4,
410 CMD_OBJECT_REF_GET_DOMAIN
= 5,
411 CMD_OBJECT_REF_SET_VALUES
= 6
417 int count
; /* For kind == MOD_KIND_COUNT */
418 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
419 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
420 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
430 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
434 * Describes a single step request.
438 MonoInternalThread
*thread
;
443 MonoMethod
*last_method
;
445 /* Whenever single stepping is performed using start/stop_single_stepping () */
447 /* The list of breakpoints used to implement step-over */
451 /* Dummy structure used for the profiler callbacks */
456 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
462 static AgentConfig agent_config
;
465 * Whenever the agent is fully initialized.
466 * When using the onuncaught or onthrow options, only some parts of the agent are
467 * initialized on startup, and the full initialization which includes connection
468 * establishment and the startup of the agent thread is only done in response to
471 static gint32 inited
;
475 static int packet_id
= 0;
477 static int objref_id
= 0;
479 static int event_request_id
= 0;
481 static int frame_id
= 0;
483 static GPtrArray
*event_requests
;
485 static guint32 debugger_tls_id
;
487 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
489 /* Maps MonoInternalThread -> DebuggerTlsData */
490 static MonoGHashTable
*thread_to_tls
;
492 /* Maps tid -> MonoInternalThread */
493 static MonoGHashTable
*tid_to_thread
;
495 /* Maps tid -> MonoThread (not MonoInternalThread) */
496 static MonoGHashTable
*tid_to_thread_obj
;
498 static gsize debugger_thread_id
;
500 static HANDLE debugger_thread_handle
;
502 static int log_level
;
504 static FILE *log_file
;
506 /* Classes whose class load event has been sent */
507 static GHashTable
*loaded_classes
;
509 /* Assemblies whose assembly load event has no been sent yet */
510 static GPtrArray
*pending_assembly_loads
;
512 /* Whenever the debugger thread has exited */
513 static gboolean debugger_thread_exited
;
515 /* Cond variable used to wait for debugger_thread_exited becoming true */
516 static mono_cond_t debugger_thread_exited_cond
;
518 /* Mutex for the cond var above */
519 static mono_mutex_t debugger_thread_exited_mutex
;
521 static DebuggerProfiler debugger_profiler
;
523 /* The single step request instance */
524 static SingleStepReq
*ss_req
= NULL
;
525 static gpointer ss_invoke_addr
= NULL
;
527 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
528 /* Number of single stepping operations in progress */
532 static void transport_connect (const char *host
, int port
);
534 static guint32 WINAPI
debugger_thread (void *arg
);
536 static void runtime_initialized (MonoProfiler
*prof
);
538 static void runtime_shutdown (MonoProfiler
*prof
);
540 static void thread_startup (MonoProfiler
*prof
, gsize tid
);
542 static void thread_end (MonoProfiler
*prof
, gsize tid
);
544 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
546 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
548 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
550 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
552 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
554 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
556 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
558 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
560 static void start_single_stepping (void);
562 static void stop_single_stepping (void);
564 static void suspend_current (void);
566 /* Submodule init/cleanup */
567 static void breakpoints_init (void);
568 static void breakpoints_cleanup (void);
570 static void objrefs_init (void);
571 static void objrefs_cleanup (void);
573 static void ids_init (void);
574 static void ids_cleanup (void);
576 static void suspend_init (void);
578 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
);
579 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
580 static void ss_destroy (SingleStepReq
*req
);
582 static void start_debugger_thread (void);
584 static void finish_agent_init (gboolean on_startup
);
587 parse_address (char *address
, char **host
, int *port
)
589 char *pos
= strchr (address
, ':');
591 if (pos
== NULL
|| pos
== address
)
594 *host
= g_malloc (pos
- address
+ 1);
595 strncpy (*host
, address
, pos
- address
);
596 (*host
) [pos
- address
] = '\0';
598 *port
= atoi (pos
+ 1);
606 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
607 fprintf (stderr
, "Available options:\n");
608 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
609 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
610 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
611 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
612 fprintf (stderr
, " suspend=y/n\t\t\tWhenever to suspend after startup.\n");
613 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
614 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
618 parse_flag (const char *option
, char *flag
)
620 if (!strcmp (flag
, "y"))
622 else if (!strcmp (flag
, "n"))
625 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
632 mono_debugger_agent_parse_options (char *options
)
638 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
639 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
643 agent_config
.enabled
= TRUE
;
644 agent_config
.suspend
= TRUE
;
645 agent_config
.server
= FALSE
;
647 args
= g_strsplit (options
, ",", -1);
648 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
651 if (strncmp (arg
, "transport=", 10) == 0) {
652 agent_config
.transport
= g_strdup (arg
+ 10);
653 } else if (strncmp (arg
, "address=", 8) == 0) {
654 agent_config
.address
= g_strdup (arg
+ 8);
655 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
656 agent_config
.log_level
= atoi (arg
+ 9);
657 } else if (strncmp (arg
, "logfile=", 8) == 0) {
658 agent_config
.log_file
= g_strdup (arg
+ 8);
659 } else if (strncmp (arg
, "suspend=", 8) == 0) {
660 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
661 } else if (strncmp (arg
, "server=", 7) == 0) {
662 agent_config
.server
= parse_flag ("server", arg
+ 7);
663 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
664 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
665 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
666 /* We support multiple onthrow= options */
667 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
668 } else if (strncmp (arg
, "onthrow", 7) == 0) {
669 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
670 } else if (strncmp (arg
, "help", 4) == 0) {
673 } else if (strncmp (arg
, "timeout=", 8) == 0) {
674 agent_config
.timeout
= atoi (arg
+ 8);
675 } else if (strncmp (arg
, "launch=", 7) == 0) {
676 agent_config
.launch
= g_strdup (arg
+ 7);
683 if (agent_config
.transport
== NULL
) {
684 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
687 if (strcmp (agent_config
.transport
, "dt_socket") != 0) {
688 fprintf (stderr
, "debugger-agent: The only supported value for the 'transport' option is 'dt_socket'.\n");
692 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
693 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
697 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
698 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
704 mono_debugger_agent_init (void)
706 if (!agent_config
.enabled
)
709 /* Need to know whenever a thread has acquired the loader mutex */
710 mono_loader_lock_track_ownership (TRUE
);
712 event_requests
= g_ptr_array_new ();
714 mono_mutex_init (&debugger_thread_exited_mutex
, NULL
);
715 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
717 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
718 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
719 mono_profiler_install_runtime_initialized (runtime_initialized
);
720 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
721 mono_profiler_install_thread (thread_startup
, thread_end
);
722 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
723 mono_profiler_install_jit_end (jit_end
);
724 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
726 debugger_tls_id
= TlsAlloc ();
728 thread_to_tls
= mono_g_hash_table_new (NULL
, NULL
);
729 MONO_GC_REGISTER_ROOT (thread_to_tls
);
731 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
732 MONO_GC_REGISTER_ROOT (tid_to_thread
);
734 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
735 MONO_GC_REGISTER_ROOT (tid_to_thread_obj
);
737 loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
738 pending_assembly_loads
= g_ptr_array_new ();
740 log_level
= agent_config
.log_level
;
742 if (agent_config
.log_file
) {
743 log_file
= fopen (agent_config
.log_file
, "w+");
745 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
757 mini_get_debug_options ()->gen_seq_points
= TRUE
;
759 * This is needed because currently we don't handle liveness info.
761 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
763 /* This is needed because we can't set local variables in registers yet */
764 mono_disable_optimizations (MONO_OPT_LINEARS
);
766 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
767 finish_agent_init (TRUE
);
773 * Finish the initialization of the agent. This involves connecting the transport
774 * and starting the agent thread. This is either done at startup, or
775 * in response to some event like an unhandled exception.
778 finish_agent_init (gboolean on_startup
)
784 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
787 if (agent_config
.launch
) {
790 // FIXME: Generated address
791 // FIXME: Races with transport_connect ()
793 argv
[0] = agent_config
.launch
;
794 argv
[1] = agent_config
.transport
;
795 argv
[2] = agent_config
.address
;
798 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
800 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
805 if (agent_config
.address
) {
806 res
= parse_address (agent_config
.address
, &host
, &port
);
813 transport_connect (host
, port
);
816 /* Do some which is usually done after sending the VMStart () event */
817 vm_start_event_sent
= TRUE
;
818 start_debugger_thread ();
823 mono_debugger_agent_cleanup (void)
828 /* This will interrupt the agent thread */
829 /* Close the read part only so it can still send back replies */
831 shutdown (conn_fd
, SD_RECEIVE
);
833 shutdown (conn_fd
, SHUT_RD
);
837 * Wait for the thread to exit.
839 * If we continue with the shutdown without waiting for it, then the client might
840 * not receive an answer to its last command like a resume.
841 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
844 //WaitForSingleObject (debugger_thread_handle, INFINITE);
845 if (GetCurrentThreadId () != debugger_thread_id
) {
846 mono_mutex_lock (&debugger_thread_exited_mutex
);
847 if (!debugger_thread_exited
) {
849 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
850 mono_mutex_unlock (&debugger_thread_exited_mutex
);
852 mono_mutex_lock (&debugger_thread_exited_mutex
);
855 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
858 mono_mutex_unlock (&debugger_thread_exited_mutex
);
861 breakpoints_cleanup ();
866 shutdown (conn_fd
, SD_BOTH
);
868 shutdown (conn_fd
, SHUT_RDWR
);
871 mono_mutex_destroy (&debugger_thread_exited_mutex
);
872 mono_cond_destroy (&debugger_thread_exited_cond
);
878 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
881 transport_connect (const char *host
, int port
)
883 struct addrinfo hints
;
884 struct addrinfo
*result
, *rp
;
886 char port_string
[128];
887 char handshake_msg
[128];
893 sprintf (port_string
, "%d", port
);
895 mono_network_init ();
897 /* Obtain address(es) matching host/port */
899 memset (&hints
, 0, sizeof (struct addrinfo
));
900 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
901 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
903 hints
.ai_protocol
= 0; /* Any protocol */
905 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
907 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d: %s\n", host
, port
, gai_strerror (s
));
912 if (agent_config
.server
) {
913 /* Wait for a connection */
915 struct sockaddr_in addr
;
918 /* No address, generate one */
919 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
922 /* This will bind the socket to a random port */
923 res
= listen (sfd
, 16);
925 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (errno
));
929 addrlen
= sizeof (addr
);
930 memset (&addr
, 0, sizeof (addr
));
931 res
= getsockname (sfd
, &addr
, &addrlen
);
935 port
= ntohs (addr
.sin_port
);
937 /* Emit the address to stdout */
938 /* FIXME: Should print another interface, not localhost */
939 printf ("%s:%d\n", host
, port
);
941 /* Listen on the provided address */
942 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
943 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
948 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
952 res
= listen (sfd
, 16);
960 * this function is not present on win2000 which we still support, and the
961 * workaround described here:
962 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
963 * only works with MSVC.
965 freeaddrinfo (result
);
969 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
971 if (agent_config
.timeout
) {
976 tv
.tv_usec
= agent_config
.timeout
* 1000;
978 FD_SET (sfd
, &readfds
);
979 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
981 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
986 conn_fd
= accept (sfd
, NULL
, NULL
);
988 fprintf (stderr
, "debugger-agent: Unable to listen on %s:%d\n", host
, port
);
992 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
994 /* Connect to the specified address */
995 /* FIXME: Respect the timeout */
996 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
997 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1002 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1003 break; /* Success */
1011 /* See the comment above */
1012 freeaddrinfo (result
);
1016 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1021 /* Write handshake message */
1022 sprintf (handshake_msg
, "DWP-Handshake");
1023 res
= send (conn_fd
, handshake_msg
, strlen (handshake_msg
), 0);
1024 g_assert (res
!= -1);
1027 res
= recv (conn_fd
, buf
, strlen (handshake_msg
), 0);
1028 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1029 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1034 * Set TCP_NODELAY on the socket so the client receives events/command
1035 * results immediately.
1039 int result
= setsockopt(conn_fd
,
1044 g_assert (result
>= 0);
1049 transport_send (guint8
*data
, int len
)
1053 res
= send (conn_fd
, data
, len
, 0);
1061 start_debugger_thread (void)
1065 debugger_thread_handle
= mono_create_thread (NULL
, 0, debugger_thread
, NULL
, 0, &tid
);
1066 g_assert (debugger_thread_handle
);
1070 * Functions to decode protocol data
1074 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1077 g_assert (*endbuf
<= limit
);
1082 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1085 g_assert (*endbuf
<= limit
);
1087 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1090 static inline gint64
1091 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1093 guint32 high
= decode_int (buf
, &buf
, limit
);
1094 guint32 low
= decode_int (buf
, &buf
, limit
);
1098 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1102 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1104 return decode_int (buf
, endbuf
, limit
);
1108 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1110 int len
= decode_int (buf
, &buf
, limit
);
1113 s
= g_malloc (len
+ 1);
1116 memcpy (s
, buf
, len
);
1125 * Functions to encode protocol data
1129 guint8
*buf
, *p
, *end
;
1133 buffer_init (Buffer
*buf
, int size
)
1135 buf
->buf
= g_malloc (size
);
1137 buf
->end
= buf
->buf
+ size
;
1141 buffer_make_room (Buffer
*buf
, int size
)
1143 if (buf
->end
- buf
->p
< size
) {
1144 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1145 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1146 size
= buf
->p
- buf
->buf
;
1149 buf
->end
= buf
->buf
+ new_size
;
1154 buffer_add_byte (Buffer
*buf
, guint8 val
)
1156 buffer_make_room (buf
, 1);
1162 buffer_add_int (Buffer
*buf
, guint32 val
)
1164 buffer_make_room (buf
, 4);
1165 buf
->p
[0] = (val
>> 24) & 0xff;
1166 buf
->p
[1] = (val
>> 16) & 0xff;
1167 buf
->p
[2] = (val
>> 8) & 0xff;
1168 buf
->p
[3] = (val
>> 0) & 0xff;
1173 buffer_add_long (Buffer
*buf
, guint64 l
)
1175 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1176 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1180 buffer_add_id (Buffer
*buf
, int id
)
1182 buffer_add_int (buf
, (guint64
)id
);
1186 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1188 buffer_make_room (buf
, len
);
1189 memcpy (buf
->p
, data
, len
);
1194 buffer_add_string (Buffer
*buf
, const char *str
)
1199 buffer_add_int (buf
, 0);
1202 buffer_add_int (buf
, len
);
1203 buffer_add_data (buf
, (guint8
*)str
, len
);
1208 buffer_free (Buffer
*buf
)
1214 send_packet (int command_set
, int command
, Buffer
*data
)
1220 id
= InterlockedIncrement (&packet_id
);
1222 len
= data
->p
- data
->buf
+ 11;
1223 buffer_init (&buf
, len
);
1224 buffer_add_int (&buf
, len
);
1225 buffer_add_int (&buf
, id
);
1226 buffer_add_byte (&buf
, 0); /* flags */
1227 buffer_add_byte (&buf
, command_set
);
1228 buffer_add_byte (&buf
, command
);
1229 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1231 res
= transport_send (buf
.buf
, len
);
1239 send_reply_packet (int id
, int error
, Buffer
*data
)
1245 len
= data
->p
- data
->buf
+ 11;
1246 buffer_init (&buf
, len
);
1247 buffer_add_int (&buf
, len
);
1248 buffer_add_int (&buf
, id
);
1249 buffer_add_byte (&buf
, 0x80); /* flags */
1250 buffer_add_byte (&buf
, (error
>> 8) & 0xff);
1251 buffer_add_byte (&buf
, error
);
1252 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1254 res
= transport_send (buf
.buf
, len
);
1266 * Represents an object accessible by the debugger client.
1269 /* Unique id used in the wire protocol to refer to objects */
1272 * A weakref gc handle pointing to the object. The gc handle is used to
1273 * detect if the object was garbage collected.
1278 /* Maps objid -> ObjRef */
1279 static GHashTable
*objrefs
;
1282 free_objref (gpointer value
)
1286 mono_gchandle_free (o
->handle
);
1294 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1298 objrefs_cleanup (void)
1300 g_hash_table_destroy (objrefs
);
1304 static GHashTable
*obj_to_objref
;
1307 * Return an ObjRef for OBJ.
1310 get_objref (MonoObject
*obj
)
1321 /* Use a hash table with masked pointers to internalize object references */
1322 /* FIXME: This can grow indefinitely */
1323 mono_loader_lock ();
1326 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1328 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1329 /* ref might refer to a different object with the same addr which was GCd */
1330 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1331 mono_loader_unlock ();
1335 ref
= g_new0 (ObjRef
, 1);
1336 ref
->id
= InterlockedIncrement (&objref_id
);
1337 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1339 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1340 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1342 mono_loader_unlock ();
1348 get_objid (MonoObject
*obj
)
1350 return get_objref (obj
)->id
;
1354 * Set OBJ to the object identified by OBJID.
1355 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
1359 get_object_allow_null (int objid
, MonoObject
**obj
)
1369 return ERR_INVALID_OBJECT
;
1371 mono_loader_lock ();
1373 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
1376 *obj
= mono_gchandle_get_target (ref
->handle
);
1377 mono_loader_unlock ();
1379 return ERR_INVALID_OBJECT
;
1382 mono_loader_unlock ();
1383 return ERR_INVALID_OBJECT
;
1388 get_object (int objid
, MonoObject
**obj
)
1390 int err
= get_object_allow_null (objid
, obj
);
1395 return ERR_INVALID_OBJECT
;
1400 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1402 return decode_id (buf
, endbuf
, limit
);
1406 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
1408 buffer_add_id (buf
, get_objid (o
));
1427 * Represents a runtime structure accessible to the debugger client
1430 /* Unique id used in the wire protocol */
1432 /* Domain of the runtime structure, NULL if the domain was unloaded */
1439 MonoAssembly
*assembly
;
1440 MonoClassField
*field
;
1442 MonoProperty
*property
;
1447 /* Maps runtime structure -> Id */
1448 GHashTable
*val_to_id
[ID_NUM
];
1452 static GPtrArray
*ids
[ID_NUM
];
1459 for (i
= 0; i
< ID_NUM
; ++i
)
1460 ids
[i
] = g_ptr_array_new ();
1468 for (i
= 0; i
< ID_NUM
; ++i
) {
1470 for (j
= 0; j
< ids
[i
]->len
; ++j
)
1471 g_free (g_ptr_array_index (ids
[i
], j
));
1472 g_ptr_array_free (ids
[i
], TRUE
);
1479 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
1481 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
1485 for (i
= 0; i
< ID_NUM
; ++i
)
1486 if (info
->val_to_id
[i
])
1487 g_hash_table_destroy (info
->val_to_id
[i
]);
1491 domain_jit_info (domain
)->agent_info
= NULL
;
1493 /* Clear ids referencing structures in the domain */
1494 for (i
= 0; i
< ID_NUM
; ++i
) {
1496 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
1497 Id
*id
= g_ptr_array_index (ids
[i
], j
);
1498 if (id
->domain
== domain
)
1506 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
1509 AgentDomainInfo
*info
;
1514 mono_loader_lock ();
1516 mono_domain_lock (domain
);
1518 if (!domain_jit_info (domain
)->agent_info
)
1519 domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
1520 info
= domain_jit_info (domain
)->agent_info
;
1521 if (info
->val_to_id
[type
] == NULL
)
1522 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1524 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
1526 mono_domain_unlock (domain
);
1527 mono_loader_unlock ();
1531 id
= g_new0 (Id
, 1);
1533 id
->id
= ids
[type
]->len
+ 1;
1534 id
->domain
= domain
;
1537 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
1539 mono_domain_unlock (domain
);
1541 g_ptr_array_add (ids
[type
], id
);
1543 mono_loader_unlock ();
1548 static inline gpointer
1549 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
1553 int id
= decode_id (buf
, endbuf
, limit
);
1562 // FIXME: error handling
1563 mono_loader_lock ();
1564 g_assert (id
> 0 && id
<= ids
[type
]->len
);
1566 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
1567 mono_loader_unlock ();
1569 if (res
->domain
== NULL
) {
1570 *err
= ERR_UNLOADED
;
1575 *domain
= res
->domain
;
1577 return res
->data
.val
;
1581 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
1583 buffer_add_id (buf
, get_id (domain
, type
, val
));
1586 static inline MonoClass
*
1587 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1589 return decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
1592 static inline MonoAssembly
*
1593 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1595 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
1598 static inline MonoImage
*
1599 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1601 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
1604 static inline MonoMethod
*
1605 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1607 return decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
1610 static inline MonoClassField
*
1611 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1613 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
1616 static inline MonoDomain
*
1617 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1619 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
1622 static inline MonoProperty
*
1623 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
1625 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
1629 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
1631 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
1635 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
1637 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
1641 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
1643 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
1647 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
1649 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
1653 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
1655 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
1659 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
1661 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
1665 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
1667 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
1670 static void invoke_method (void);
1677 * save_thread_context:
1679 * Set CTX as the current threads context which is used for computing stack traces.
1680 * This function is signal-safe.
1683 save_thread_context (MonoContext
*ctx
)
1685 DebuggerTlsData
*tls
;
1687 tls
= TlsGetValue (debugger_tls_id
);
1691 memcpy (&tls
->ctx
, ctx
, sizeof (MonoContext
));
1693 #ifdef MONO_INIT_CONTEXT_FROM_CURRENT
1694 MONO_INIT_CONTEXT_FROM_CURRENT (&tls
->ctx
);
1696 MONO_INIT_CONTEXT_FROM_FUNC (&tls
->ctx
, save_thread_context
);
1700 tls
->lmf
= mono_get_lmf ();
1701 tls
->domain
= mono_domain_get ();
1702 tls
->has_context
= TRUE
;
1705 /* The number of times the runtime is suspended */
1706 static gint32 suspend_count
;
1708 /* Number of threads suspended */
1710 * If this is equal to the size of thread_to_tls, the runtime is considered
1713 static gint32 threads_suspend_count
;
1715 static mono_mutex_t suspend_mutex
;
1717 /* Cond variable used to wait for suspend_count becoming 0 */
1718 static mono_cond_t suspend_cond
;
1720 /* Semaphore used to wait for a thread becoming suspended */
1721 static MonoSemType suspend_sem
;
1726 mono_mutex_init (&suspend_mutex
, NULL
);
1727 mono_cond_init (&suspend_cond
, NULL
);
1728 MONO_SEM_INIT (&suspend_sem
, 0);
1733 StackFrameInfo last_frame
;
1734 gboolean last_frame_set
;
1737 } GetLastFrameUserData
;
1740 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
1742 GetLastFrameUserData
*data
= user_data
;
1744 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
1747 if (!data
->last_frame_set
) {
1748 /* Store the last frame */
1749 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
1750 data
->last_frame_set
= TRUE
;
1753 /* Store the context/lmf for the frame above the last frame */
1754 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
1755 data
->lmf
= info
->lmf
;
1762 * mono_debugger_agent_thread_interrupt:
1764 * Called by the abort signal handler.
1765 * Should be signal safe.
1768 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
1770 DebuggerTlsData
*tls
;
1775 tls
= TlsGetValue (debugger_tls_id
);
1780 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1781 * guarantee the signal handler will be called that many times. Instead of tracking
1782 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1783 * has been requested that hasn't been handled yet, otherwise we can have threads
1784 * refuse to die when VM_EXIT is called
1786 #if defined(__APPLE__)
1787 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
1791 * We use interrupt_count to determine whenever this interrupt should be processed
1792 * by us or the normal interrupt processing code in the signal handler.
1793 * There is no race here with notify_thread (), since the signal is sent after
1794 * incrementing interrupt_count.
1796 if (tls
->interrupt_count
== 0)
1799 InterlockedDecrement (&tls
->interrupt_count
);
1802 // FIXME: Races when the thread leaves managed code before hitting a single step
1806 /* Running managed code, will be suspended by the single step code */
1807 DEBUG (1, printf ("[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, mono_arch_ip_from_context (sigctx
)));
1811 * Running native code, will be suspended when it returns to/enters
1812 * managed code. Treat it as already suspended.
1813 * This might interrupt the code in process_single_step_inner (), we use the
1814 * tls->suspending flag to avoid races when that happens.
1816 if (!tls
->suspended
&& !tls
->suspending
) {
1818 GetLastFrameUserData data
;
1820 // FIXME: printf is not signal safe, but this is only used during
1821 // debugger debugging
1822 DEBUG (1, printf ("[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)GetCurrentThreadId (), mono_arch_ip_from_context (sigctx
)));
1823 //save_thread_context (&ctx);
1826 /* Already terminated */
1830 * We are in a difficult position: we want to be able to provide stack
1831 * traces for this thread, but we can't use the current ctx+lmf, since
1832 * the thread is still running, so it might return to managed code,
1833 * making these invalid.
1834 * So we start a stack walk and save the first frame, along with the
1835 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
1836 * suspended when it returns to managed code, so the parent's ctx should
1839 data
.last_frame_set
= FALSE
;
1841 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
1842 mono_jit_walk_stack_from_ctx_in_thread (get_last_frame
, mono_domain_get (), &ctx
, FALSE
, tls
->thread
, mono_get_lmf (), &data
);
1844 if (data
.last_frame_set
) {
1845 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
1846 memcpy (&tls
->async_ctx
, &data
.ctx
, sizeof (MonoContext
));
1847 tls
->async_lmf
= data
.lmf
;
1848 tls
->has_async_ctx
= TRUE
;
1849 tls
->domain
= mono_domain_get ();
1850 memcpy (&tls
->ctx
, &ctx
, sizeof (MonoContext
));
1852 tls
->has_async_ctx
= FALSE
;
1855 mono_memory_barrier ();
1857 tls
->suspended
= TRUE
;
1858 MONO_SEM_POST (&suspend_sem
);
1865 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
1868 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
1870 #endif /* HOST_WIN32 */
1873 * reset_native_thread_suspend_state:
1875 * Reset the suspended flag on native threads
1878 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
1880 DebuggerTlsData
*tls
= value
;
1882 if (!tls
->really_suspended
&& tls
->suspended
)
1883 tls
->suspended
= FALSE
;
1889 * Notify a thread that it needs to suspend.
1892 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
1894 MonoInternalThread
*thread
= key
;
1895 DebuggerTlsData
*tls
= value
;
1896 gsize tid
= thread
->tid
;
1898 if (GetCurrentThreadId () != tid
) {
1899 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
1902 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
1903 * guarantee the signal handler will be called that many times. Instead of tracking
1904 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
1905 * has been requested that hasn't been handled yet, otherwise we can have threads
1906 * refuse to die when VM_EXIT is called
1908 #if defined(__APPLE__)
1909 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
1913 * Maybe we could use the normal interrupt infrastructure, but that does a lot
1914 * of things like breaking waits etc. which we don't want.
1916 InterlockedIncrement (&tls
->interrupt_count
);
1919 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
1921 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
1923 pthread_kill ((pthread_t
) tid
, mono_thread_get_abort_signal ());
1929 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
1931 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
1934 if (debugger_thread_id
== GetCurrentThreadId ())
1937 /* Prevent races with mono_debugger_agent_thread_interrupt () */
1938 if (suspend_count
- tls
->resume_count
> 0)
1939 tls
->suspending
= TRUE
;
1941 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
1943 if (suspend_count
- tls
->resume_count
== 0) {
1945 * We are executing a single threaded invoke but the single step for
1946 * suspending is still active.
1947 * FIXME: This slows down single threaded invokes.
1949 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
1953 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
1955 /* Can't suspend in these methods */
1956 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
1959 save_thread_context (ctx
);
1967 * Increase the suspend count of the VM. While the suspend count is greater
1968 * than 0, runtime threads are suspended at certain points during execution.
1973 mono_loader_lock ();
1975 mono_mutex_lock (&suspend_mutex
);
1979 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
1981 if (suspend_count
== 1) {
1982 // FIXME: Is it safe to call this inside the lock ?
1983 start_single_stepping ();
1984 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
1987 mono_mutex_unlock (&suspend_mutex
);
1989 mono_loader_unlock ();
1995 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2003 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2005 mono_loader_lock ();
2007 mono_mutex_lock (&suspend_mutex
);
2009 g_assert (suspend_count
> 0);
2012 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm...\n", (gpointer
)GetCurrentThreadId ()));
2014 if (suspend_count
== 0) {
2015 // FIXME: Is it safe to call this inside the lock ?
2016 stop_single_stepping ();
2017 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2020 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2021 err
= mono_cond_broadcast (&suspend_cond
);
2022 g_assert (err
== 0);
2024 mono_mutex_unlock (&suspend_mutex
);
2025 //g_assert (err == 0);
2027 mono_loader_unlock ();
2033 * Resume just one thread.
2036 resume_thread (MonoInternalThread
*thread
)
2039 DebuggerTlsData
*tls
;
2041 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2043 mono_loader_lock ();
2045 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2048 mono_mutex_lock (&suspend_mutex
);
2050 g_assert (suspend_count
> 0);
2052 DEBUG(1, fprintf (log_file
, "[%p] Resuming thread...\n", (gpointer
)(gssize
)thread
->tid
));
2054 tls
->resume_count
+= suspend_count
;
2057 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2058 * but only the one whose resume_count field is > 0 will be resumed.
2060 err
= mono_cond_broadcast (&suspend_cond
);
2061 g_assert (err
== 0);
2063 mono_mutex_unlock (&suspend_mutex
);
2064 //g_assert (err == 0);
2066 mono_loader_unlock ();
2070 invalidate_frames (DebuggerTlsData
*tls
)
2075 tls
= TlsGetValue (debugger_tls_id
);
2078 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2079 if (tls
->frames
[i
]->jit
)
2080 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2081 g_free (tls
->frames
[i
]);
2083 g_free (tls
->frames
);
2084 tls
->frame_count
= 0;
2091 * Suspend the current thread until the runtime is resumed. If the thread has a
2092 * pending invoke, then the invoke is executed before this function returns.
2095 suspend_current (void)
2098 DebuggerTlsData
*tls
;
2100 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2102 if (mono_loader_lock_is_owned_by_self ()) {
2104 * If we own the loader mutex, can't suspend until we release it, since the
2105 * whole runtime can deadlock otherwise.
2110 tls
= TlsGetValue (debugger_tls_id
);
2113 mono_mutex_lock (&suspend_mutex
);
2115 tls
->suspending
= FALSE
;
2116 tls
->really_suspended
= TRUE
;
2118 if (!tls
->suspended
) {
2119 tls
->suspended
= TRUE
;
2120 MONO_SEM_POST (&suspend_sem
);
2123 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2125 while (suspend_count
- tls
->resume_count
> 0) {
2127 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2129 mono_mutex_unlock (&suspend_mutex
);
2131 mono_mutex_lock (&suspend_mutex
);
2137 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2138 g_assert (err
== 0);
2142 tls
->suspended
= FALSE
;
2143 tls
->really_suspended
= FALSE
;
2145 threads_suspend_count
--;
2147 mono_mutex_unlock (&suspend_mutex
);
2149 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2152 /* Save the original context */
2153 tls
->invoke
->has_ctx
= TRUE
;
2154 memcpy (&tls
->invoke
->ctx
, &tls
->ctx
, sizeof (MonoContext
));
2159 /* The frame info becomes invalid after a resume */
2160 tls
->has_context
= FALSE
;
2161 tls
->has_async_ctx
= FALSE
;
2162 invalidate_frames (NULL
);
2166 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
2168 DebuggerTlsData
*tls
= value
;
2170 if (!tls
->suspended
&& !tls
->terminated
)
2171 *(int*)user_data
= *(int*)user_data
+ 1;
2175 count_threads_to_wait_for (void)
2179 mono_loader_lock ();
2180 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
2181 mono_loader_unlock ();
2189 * Wait until the runtime is completely suspended.
2192 wait_for_suspend (void)
2194 int nthreads
, nwait
, err
;
2195 gboolean waited
= FALSE
;
2197 // FIXME: Threads starting/stopping ?
2198 mono_loader_lock ();
2199 nthreads
= mono_g_hash_table_size (thread_to_tls
);
2200 mono_loader_unlock ();
2203 nwait
= count_threads_to_wait_for ();
2205 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
2206 err
= MONO_SEM_WAIT (&suspend_sem
);
2207 g_assert (err
== 0);
2215 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
2221 * Return whenever the runtime is suspended.
2226 return count_threads_to_wait_for () == 0;
2230 * find_seq_point_for_native_offset:
2232 * Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
2233 * should be the location of a sequence point.
2236 find_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
2238 MonoSeqPointInfo
*seq_points
;
2241 mono_domain_lock (domain
);
2242 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2243 mono_domain_unlock (domain
);
2244 g_assert (seq_points
);
2248 for (i
= 0; i
< seq_points
->len
; ++i
) {
2249 if (seq_points
->seq_points
[i
].native_offset
== native_offset
)
2250 return &seq_points
->seq_points
[i
];
2259 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
2260 * should be the location of a sequence point.
2263 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
2265 MonoSeqPointInfo
*seq_points
;
2268 mono_domain_lock (domain
);
2269 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2270 mono_domain_unlock (domain
);
2271 g_assert (seq_points
);
2275 for (i
= 0; i
< seq_points
->len
; ++i
) {
2276 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
2277 return &seq_points
->seq_points
[i
];
2284 * compute_il_offset:
2286 * Compute the IL offset corresponding to NATIVE_OFFSET, which should be
2287 * a location of a sequence point.
2288 * We use this function instead of mono_debug_il_offset_from_address () etc,
2289 * which doesn't seem to work in a lot of cases.
2292 compute_il_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
)
2294 MonoSeqPointInfo
*seq_points
;
2295 int i
, last_il_offset
, seq_il_offset
, seq_native_offset
;
2297 mono_domain_lock (domain
);
2298 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
2299 mono_domain_unlock (domain
);
2300 g_assert (seq_points
);
2302 last_il_offset
= -1;
2304 /* Find the sequence point */
2305 for (i
= 0; i
< seq_points
->len
; ++i
) {
2306 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
2307 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
2309 if (seq_native_offset
> native_offset
)
2311 last_il_offset
= seq_il_offset
;
2314 return last_il_offset
;
2318 DebuggerTlsData
*tls
;
2320 } ComputeFramesUserData
;
2323 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2325 ComputeFramesUserData
*ud
= user_data
;
2329 if (info
->type
!= FRAME_TYPE_MANAGED
) {
2330 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
2331 /* Mark the last frame as an invoke frame */
2333 ((StackFrame
*)ud
->frames
->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
2339 method
= info
->ji
->method
;
2341 method
= info
->method
;
2343 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
))
2346 if (info
->il_offset
== -1) {
2347 /* Can't use compute_il_offset () since ip doesn't point precisely at at a seq point */
2348 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
2351 DEBUG (1, fprintf (stderr
, "\tFrame: %s %d %d %d\n", mono_method_full_name (method
, TRUE
), info
->native_offset
, info
->il_offset
, info
->managed
));
2353 if (!info
->managed
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
) {
2355 * mono_arch_find_jit_info () returns the context stored in the LMF for
2356 * native frames, but it should unwind once. This is why we have duplicate
2357 * frames on the stack sometimes.
2358 * !managed also seems to be set for dynamic methods.
2363 frame
= g_new0 (StackFrame
, 1);
2364 frame
->method
= method
;
2365 frame
->il_offset
= info
->il_offset
;
2368 frame
->has_ctx
= TRUE
;
2370 frame
->domain
= info
->domain
;
2372 ud
->frames
= g_slist_append (ud
->frames
, frame
);
2378 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
2380 ComputeFramesUserData user_data
;
2382 int i
, findex
, new_frame_count
;
2383 StackFrame
**new_frames
, *f
;
2385 // FIXME: Locking on tls
2386 if (tls
->frames
&& tls
->frames_up_to_date
)
2389 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
2391 user_data
.tls
= tls
;
2392 user_data
.frames
= NULL
;
2393 if (tls
->terminated
) {
2394 tls
->frame_count
= 0;
2396 } if (!tls
->really_suspended
&& tls
->has_async_ctx
) {
2397 /* Have to use the state saved by the signal handler */
2398 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
2399 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->async_ctx
, FALSE
, thread
, tls
->async_lmf
, &user_data
);
2400 } else if (tls
->has_context
) {
2401 mono_jit_walk_stack_from_ctx_in_thread (process_frame
, tls
->domain
, &tls
->ctx
, FALSE
, thread
, tls
->lmf
, &user_data
);
2404 tls
->frame_count
= 0;
2408 new_frame_count
= g_slist_length (user_data
.frames
);
2409 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
2411 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
2415 * Reuse the id for already existing stack frames, so invokes don't invalidate
2416 * the still valid stack frames.
2418 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2419 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
2420 f
->id
= tls
->frames
[i
]->id
;
2425 if (i
>= tls
->frame_count
)
2426 f
->id
= InterlockedIncrement (&frame_id
);
2428 new_frames
[findex
++] = f
;
2431 g_slist_free (user_data
.frames
);
2433 invalidate_frames (tls
);
2435 tls
->frames
= new_frames
;
2436 tls
->frame_count
= new_frame_count
;
2437 tls
->frames_up_to_date
= TRUE
;
2445 * create_event_list:
2447 * Return a list of event request ids matching EVENT, starting from REQS, which
2448 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
2450 * We return request ids, instead of requests, to simplify threading, since
2451 * requests could be deleted anytime when the loader lock is not held.
2452 * LOCKING: Assumes the loader lock is held.
2455 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, MonoException
*exc
, int *suspend_policy
)
2458 GSList
*events
= NULL
;
2460 *suspend_policy
= SUSPEND_POLICY_NONE
;
2463 reqs
= event_requests
;
2468 for (i
= 0; i
< reqs
->len
; ++i
) {
2469 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
2470 if (req
->event_kind
== event
) {
2471 gboolean filtered
= FALSE
;
2474 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
2475 Modifier
*mod
= &req
->modifiers
[j
];
2477 if (mod
->kind
== MOD_KIND_COUNT
) {
2479 if (mod
->data
.count
> 0) {
2480 if (mod
->data
.count
> 0) {
2482 if (mod
->data
.count
== 0)
2486 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
2487 if (mod
->data
.thread
!= mono_thread_internal_current ())
2489 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& exc
) {
2490 if (mod
->data
.exc_class
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, exc
->object
.vtable
->klass
))
2492 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
2494 gboolean found
= FALSE
;
2495 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
2498 for (k
= 0; assemblies
[k
]; ++k
)
2499 if (assemblies
[k
] == ji
->method
->klass
->image
->assembly
)
2508 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
2509 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
2514 /* Send a VM START/DEATH event by default */
2515 if (event
== EVENT_KIND_VM_START
)
2516 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2517 if (event
== EVENT_KIND_VM_DEATH
)
2518 events
= g_slist_append (events
, GINT_TO_POINTER (0));
2523 static G_GNUC_UNUSED
const char*
2524 event_to_string (EventKind event
)
2527 case EVENT_KIND_VM_START
: return "VM_START";
2528 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
2529 case EVENT_KIND_THREAD_START
: return "THREAD_START";
2530 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
2531 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
2532 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
2533 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
2534 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
2535 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
2536 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
2537 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
2538 case EVENT_KIND_STEP
: return "STEP";
2539 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
2540 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
2542 g_assert_not_reached ();
2549 * Send an event to the client, suspending the vm if needed.
2550 * LOCKING: Since this can suspend the calling thread, no locks should be held
2552 * The EVENTS list is freed by this function.
2555 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
2559 MonoDomain
*domain
= mono_domain_get ();
2565 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
)
2566 // FIXME: We miss those events
2569 if (vm_death_event_sent
)
2572 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
)
2581 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
2582 // FIXME: Send these with a NULL thread, don't suspend the current thread
2585 buffer_init (&buf
, 128);
2586 buffer_add_byte (&buf
, suspend_policy
);
2587 buffer_add_int (&buf
, g_slist_length (events
)); // n of events
2589 for (l
= events
; l
; l
= l
->next
) {
2590 buffer_add_byte (&buf
, event
); // event kind
2591 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
2593 thread
= mono_thread_current ();
2595 if (event
== EVENT_KIND_VM_START
)
2597 else if (event
== EVENT_KIND_THREAD_START
)
2598 g_assert (mono_thread_internal_current () == arg
);
2600 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
2603 case EVENT_KIND_THREAD_START
:
2604 case EVENT_KIND_THREAD_DEATH
:
2606 case EVENT_KIND_APPDOMAIN_CREATE
:
2607 case EVENT_KIND_APPDOMAIN_UNLOAD
:
2608 buffer_add_domainid (&buf
, arg
);
2610 case EVENT_KIND_METHOD_ENTRY
:
2611 case EVENT_KIND_METHOD_EXIT
:
2612 buffer_add_methodid (&buf
, domain
, arg
);
2614 case EVENT_KIND_ASSEMBLY_LOAD
:
2615 case EVENT_KIND_ASSEMBLY_UNLOAD
:
2616 buffer_add_assemblyid (&buf
, domain
, arg
);
2618 case EVENT_KIND_TYPE_LOAD
:
2619 buffer_add_typeid (&buf
, domain
, arg
);
2621 case EVENT_KIND_BREAKPOINT
:
2622 case EVENT_KIND_STEP
:
2623 buffer_add_methodid (&buf
, domain
, arg
);
2624 buffer_add_long (&buf
, il_offset
);
2626 case EVENT_KIND_VM_START
:
2627 buffer_add_domainid (&buf
, mono_get_root_domain ());
2629 case EVENT_KIND_VM_DEATH
:
2631 case EVENT_KIND_EXCEPTION
:
2632 buffer_add_objid (&buf
, (MonoObject
*)arg
);
2635 g_assert_not_reached ();
2639 if (event
== EVENT_KIND_VM_START
) {
2640 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
2641 start_debugger_thread ();
2644 if (event
== EVENT_KIND_VM_DEATH
) {
2645 vm_death_event_sent
= TRUE
;
2647 suspend_policy
= SUSPEND_POLICY_NONE
;
2650 if (mono_runtime_is_shutting_down ())
2651 suspend_policy
= SUSPEND_POLICY_NONE
;
2653 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
2655 * Save the thread context and start suspending before sending the packet,
2656 * since we could be receiving the resume request before send_packet ()
2659 save_thread_context (ctx
);
2663 send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
2665 g_slist_free (events
);
2668 if (event
== EVENT_KIND_VM_START
)
2669 vm_start_event_sent
= TRUE
;
2671 DEBUG (1, fprintf (log_file
, "[%p] Sent event %s, suspend=%d.\n", (gpointer
)GetCurrentThreadId (), event_to_string (event
), suspend_policy
));
2675 switch (suspend_policy
) {
2676 case SUSPEND_POLICY_NONE
:
2678 case SUSPEND_POLICY_ALL
:
2681 case SUSPEND_POLICY_EVENT_THREAD
:
2685 g_assert_not_reached ();
2690 process_profiler_event (EventKind event
, gpointer arg
)
2695 mono_loader_lock ();
2696 events
= create_event_list (event
, NULL
, NULL
, NULL
, &suspend_policy
);
2697 mono_loader_unlock ();
2699 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
2703 runtime_initialized (MonoProfiler
*prof
)
2705 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
2709 runtime_shutdown (MonoProfiler
*prof
)
2711 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
2713 mono_debugger_agent_cleanup ();
2717 thread_startup (MonoProfiler
*prof
, gsize tid
)
2719 MonoInternalThread
*thread
= mono_thread_internal_current ();
2720 MonoInternalThread
*old_thread
;
2721 DebuggerTlsData
*tls
;
2723 if (tid
== debugger_thread_id
)
2726 g_assert (thread
->tid
== tid
);
2728 mono_loader_lock ();
2729 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2730 mono_loader_unlock ();
2732 if (thread
== old_thread
) {
2734 * For some reason, thread_startup () might be called for the same thread
2735 * multiple times (attach ?).
2737 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
2741 * thread_end () might not be called for some threads, and the tid could
2744 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
2745 mono_loader_lock ();
2746 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
2747 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
2748 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2749 mono_loader_unlock ();
2753 tls
= TlsGetValue (debugger_tls_id
);
2755 // FIXME: Free this somewhere
2756 tls
= g_new0 (DebuggerTlsData
, 1);
2757 tls
->resume_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2758 MONO_GC_REGISTER_ROOT (tls
->thread
);
2759 tls
->thread
= thread
;
2760 TlsSetValue (debugger_tls_id
, tls
);
2762 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2764 mono_loader_lock ();
2765 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
2766 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
2767 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
2768 mono_loader_unlock ();
2770 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
2773 * suspend_vm () could have missed this thread, so wait for a resume.
2779 thread_end (MonoProfiler
*prof
, gsize tid
)
2781 MonoInternalThread
*thread
;
2782 DebuggerTlsData
*tls
= NULL
;
2784 mono_loader_lock ();
2785 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
2787 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2788 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
2789 tls
->terminated
= TRUE
;
2790 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
2791 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
2792 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
2795 mono_loader_unlock ();
2797 /* We might be called for threads started before we registered the start callback */
2799 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
2800 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
2805 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
2807 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
2811 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
2813 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
2817 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
2819 /* Sent later in jit_end () */
2820 mono_loader_lock ();
2821 g_ptr_array_add (pending_assembly_loads
, assembly
);
2822 mono_loader_unlock ();
2826 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
2828 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
2832 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2834 #if defined(HOST_WIN32) && !defined(__GNUC__)
2835 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2837 gpointer stackptr
= __builtin_frame_address (1);
2839 MonoInternalThread
*thread
= mono_thread_internal_current ();
2840 DebuggerTlsData
*tls
;
2842 mono_loader_lock ();
2844 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2845 /* Could be the debugger thread with assembly/type load hooks */
2847 tls
->invoke_addr
= stackptr
;
2849 mono_loader_unlock ();
2853 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
2856 #if defined(HOST_WIN32) && !defined(__GNUC__)
2857 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
2859 gpointer stackptr
= __builtin_frame_address (1);
2862 if (ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
2866 * We need to stop single stepping when exiting a runtime invoke, since if it is
2867 * a step out, it may return to native code, and thus never end.
2869 mono_loader_lock ();
2870 ss_invoke_addr
= NULL
;
2872 for (i
= 0; i
< event_requests
->len
; ++i
) {
2873 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
2875 if (req
->event_kind
== EVENT_KIND_STEP
) {
2876 ss_destroy (req
->info
);
2877 g_ptr_array_remove_index_fast (event_requests
, i
);
2882 mono_loader_unlock ();
2886 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
2889 * We emit type load events when the first method of the type is JITted,
2890 * since the class load profiler callbacks might be called with the
2891 * loader lock held. They could also occur in the debugger thread.
2892 * Same for assembly load events.
2894 gboolean type_load
= FALSE
;
2897 MonoAssembly
*assembly
= NULL
;
2899 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
2900 mono_loader_lock ();
2901 if (pending_assembly_loads
->len
> 0) {
2902 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
2903 g_ptr_array_remove_index (pending_assembly_loads
, 0);
2905 mono_loader_unlock ();
2908 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
2913 mono_loader_lock ();
2914 if (!g_hash_table_lookup (loaded_classes
, method
->klass
)) {
2916 g_hash_table_insert (loaded_classes
, method
->klass
, method
->klass
);
2918 mono_loader_unlock ();
2920 process_profiler_event (EVENT_KIND_TYPE_LOAD
, method
->klass
);
2923 add_pending_breakpoints (method
, jinfo
);
2927 * BREAKPOINTS/SINGLE STEPPING
2931 * Contains information about an inserted breakpoint.
2934 long il_offset
, native_offset
;
2936 gboolean pending
, entry
;
2938 } BreakpointInstance
;
2941 * Contains generic information about a breakpoint.
2945 * The method where the breakpoint is placed. Can be NULL in which case it
2946 * is inserted into every method. This is used to implement method entry/
2947 * exit events. Can be a generic method definition, in which case the
2948 * breakpoint is inserted into every instance.
2952 gboolean pending
, entry
;
2955 * A list of BreakpointInstance structures describing where the breakpoint
2956 * was inserted. There could be more than one because of
2957 * generics/appdomains/method entry/exit.
2959 GPtrArray
*children
;
2962 /* List of breakpoints */
2963 static GPtrArray
*breakpoints
;
2964 /* Maps breakpoint locations to the number of breakpoints at that location */
2965 static GHashTable
*bp_locs
;
2968 breakpoints_init (void)
2970 breakpoints
= g_ptr_array_new ();
2971 bp_locs
= g_hash_table_new (NULL
, NULL
);
2975 breakpoints_cleanup (void)
2979 mono_loader_lock ();
2981 for (i
= 0; i
< breakpoints
->len
; ++i
)
2982 g_free (g_ptr_array_index (breakpoints
, i
));
2984 g_ptr_array_free (breakpoints
, TRUE
);
2985 g_hash_table_destroy (bp_locs
);
2987 mono_loader_unlock ();
2991 * insert_breakpoint:
2993 * Insert the breakpoint described by BP into the method described by
2997 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
)
3000 gint32 il_offset
, native_offset
;
3001 BreakpointInstance
*inst
;
3004 for (i
= 0; i
< seq_points
->len
; ++i
) {
3005 il_offset
= seq_points
->seq_points
[i
].il_offset
;
3006 native_offset
= seq_points
->seq_points
[i
].native_offset
;
3008 if (il_offset
== bp
->il_offset
)
3012 if (i
== seq_points
->len
)
3013 /* Have to handle this somehow */
3016 inst
= g_new0 (BreakpointInstance
, 1);
3017 inst
->native_offset
= native_offset
;
3018 inst
->ip
= (guint8
*)ji
->code_start
+ native_offset
;
3021 mono_loader_lock ();
3023 g_ptr_array_add (bp
->children
, inst
);
3025 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
3026 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
3027 mono_loader_unlock ();
3030 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3031 mono_arch_set_breakpoint (ji
, inst
->ip
);
3039 remove_breakpoint (BreakpointInstance
*inst
)
3041 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3043 MonoJitInfo
*ji
= inst
->ji
;
3044 guint8
*ip
= inst
->ip
;
3046 mono_loader_lock ();
3047 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
3048 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
3049 mono_loader_unlock ();
3051 g_assert (count
> 0);
3054 mono_arch_clear_breakpoint (ji
, ip
);
3062 * add_pending_breakpoints:
3064 * Insert pending breakpoints into the newly JITted method METHOD.
3067 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
3070 MonoSeqPointInfo
*seq_points
;
3076 domain
= mono_domain_get ();
3078 mono_loader_lock ();
3080 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3081 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
3083 if (bp
->pending
&& (bp
->method
== method
|| !bp
->method
|| (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
))) {
3084 mono_domain_lock (domain
);
3085 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3086 mono_domain_unlock (domain
);
3088 /* Could be AOT code */
3090 g_assert (seq_points
);
3092 insert_breakpoint (seq_points
, ji
, bp
);
3096 mono_loader_unlock ();
3100 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
)
3105 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
3107 /* Might be AOTed code */
3108 code
= mono_aot_get_method (domain
, method
);
3110 ji
= mono_jit_info_table_find (domain
, code
);
3115 insert_breakpoint (seq_points
, ji
, bp
);
3119 set_bp_in_method_cb (gpointer key
, gpointer value
, gpointer user_data
)
3121 MonoMethod
*method
= key
;
3122 MonoSeqPointInfo
*seq_points
= value
;
3123 MonoBreakpoint
*bp
= user_data
;
3124 MonoDomain
*domain
= mono_domain_get ();
3127 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
) {
3128 /* Generic instance */
3129 set_bp_in_method (domain
, method
, seq_points
, bp
);
3132 /* Method entry/exit */
3133 set_bp_in_method (domain
, method
, seq_points
, bp
);
3140 * Set a breakpoint at IL_OFFSET in METHOD.
3141 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
3142 * METHOD can also be a generic method definition, in which case a breakpoint
3143 * is placed in all instances of the method.
3145 static MonoBreakpoint
*
3146 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
)
3148 MonoSeqPointInfo
*seq_points
;
3153 // - suspend/resume the vm to prevent code patching problems
3155 // - multiple breakpoints on the same location
3156 // - dynamic methods
3159 bp
= g_new0 (MonoBreakpoint
, 1);
3160 bp
->method
= method
;
3161 bp
->il_offset
= il_offset
;
3163 bp
->children
= g_ptr_array_new ();
3165 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
));
3167 domain
= mono_domain_get ();
3168 mono_domain_lock (domain
);
3170 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
3172 set_bp_in_method (domain
, method
, seq_points
, bp
);
3174 if (method
->is_generic
)
3175 /* There might be already JITted instances */
3176 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, bp
);
3178 /* Not yet JITted */
3182 g_hash_table_foreach (domain_jit_info (domain
)->seq_points
, set_bp_in_method_cb
, bp
);
3185 mono_domain_unlock (domain
);
3187 mono_loader_lock ();
3188 g_ptr_array_add (breakpoints
, bp
);
3189 mono_loader_unlock ();
3195 clear_breakpoint (MonoBreakpoint
*bp
)
3199 // FIXME: locking, races
3200 for (i
= 0; i
< bp
->children
->len
; ++i
) {
3201 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
3203 remove_breakpoint (inst
);
3208 mono_loader_lock ();
3209 g_ptr_array_remove (breakpoints
, bp
);
3210 mono_loader_unlock ();
3212 g_ptr_array_free (bp
->children
, TRUE
);
3217 process_breakpoint_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3220 guint8
*orig_ip
, *ip
;
3221 int i
, j
, suspend_policy
;
3222 guint32 native_offset
;
3224 BreakpointInstance
*inst
;
3225 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
3226 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
3227 EventKind kind
= EVENT_KIND_BREAKPOINT
;
3229 // FIXME: Speed this up
3231 orig_ip
= ip
= MONO_CONTEXT_GET_IP (ctx
);
3232 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
3234 g_assert (ji
->method
);
3236 /* Compute the native offset of the breakpoint from the ip */
3237 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3238 ip
= mono_arch_get_ip_for_breakpoint (ji
, ctx
);
3239 native_offset
= ip
- (guint8
*)ji
->code_start
;
3245 * Skip the instruction causing the breakpoint signal.
3247 mono_arch_skip_breakpoint (ctx
);
3249 if (ji
->method
->wrapper_type
|| tls
->disable_breakpoints
)
3252 bp_reqs
= g_ptr_array_new ();
3253 ss_reqs
= g_ptr_array_new ();
3254 ss_reqs_orig
= g_ptr_array_new ();
3256 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), ji
->method
->name
, native_offset
));
3258 mono_loader_lock ();
3261 for (i
= 0; i
< breakpoints
->len
; ++i
) {
3262 bp
= g_ptr_array_index (breakpoints
, i
);
3267 for (j
= 0; j
< bp
->children
->len
; ++j
) {
3268 inst
= g_ptr_array_index (bp
->children
, j
);
3269 if (inst
->ji
== ji
&& inst
->native_offset
== native_offset
) {
3270 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
3271 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
3273 g_ptr_array_add (bp_reqs
, bp
->req
);
3278 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
3279 MonoSeqPointInfo
*seq_points
;
3280 int seq_il_offset
, seq_native_offset
;
3281 MonoDomain
*domain
= mono_domain_get ();
3283 /* Maybe a method entry/exit event */
3284 mono_domain_lock (domain
);
3285 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, ji
->method
);
3286 mono_domain_unlock (domain
);
3288 // FIXME: Generic sharing */
3289 mono_loader_unlock ();
3292 g_assert (seq_points
);
3294 for (i
= 0; i
< seq_points
->len
; ++i
) {
3295 seq_il_offset
= seq_points
->seq_points
[i
].il_offset
;
3296 seq_native_offset
= seq_points
->seq_points
[i
].native_offset
;
3298 if (native_offset
== seq_native_offset
) {
3299 if (seq_il_offset
== METHOD_ENTRY_IL_OFFSET
)
3300 kind
= EVENT_KIND_METHOD_ENTRY
;
3301 else if (seq_il_offset
== METHOD_EXIT_IL_OFFSET
)
3302 kind
= EVENT_KIND_METHOD_EXIT
;
3308 /* Process single step requests */
3309 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
3310 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
3311 SingleStepReq
*ss_req
= bp
->req
->info
;
3312 gboolean hit
= TRUE
;
3313 MonoSeqPointInfo
*info
;
3316 sp
= find_seq_point_for_native_offset (mono_domain_get (), ji
->method
, native_offset
, &info
);
3319 if (ss_req
->size
== STEP_SIZE_LINE
) {
3320 /* Have to check whenever a different source line was reached */
3321 MonoDebugMethodInfo
*minfo
;
3322 MonoDebugSourceLocation
*loc
= NULL
;
3324 minfo
= mono_debug_lookup_method (ji
->method
);
3327 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
3329 if (!loc
|| (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
))
3330 /* Have to continue single stepping */
3334 ss_req
->last_method
= ji
->method
;
3335 ss_req
->last_line
= loc
->row
;
3336 mono_debug_free_source_location (loc
);
3341 g_ptr_array_add (ss_reqs
, req
);
3343 /* Start single stepping again from the current sequence point */
3344 ss_start (ss_req
, ji
->method
, sp
, info
, ctx
, NULL
);
3347 if (ss_reqs
->len
> 0)
3348 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
3349 if (bp_reqs
->len
> 0)
3350 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
3351 if (kind
!= EVENT_KIND_BREAKPOINT
)
3352 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
3354 mono_loader_unlock ();
3356 g_ptr_array_free (bp_reqs
, TRUE
);
3357 g_ptr_array_free (ss_reqs
, TRUE
);
3360 * FIXME: The first event will suspend, so the second will only be sent after the
3364 process_event (EVENT_KIND_STEP
, ji
->method
, 0, ctx
, ss_events
, suspend_policy
);
3366 process_event (kind
, ji
->method
, 0, ctx
, bp_events
, suspend_policy
);
3367 if (enter_leave_events
)
3368 process_event (kind
, ji
->method
, 0, ctx
, enter_leave_events
, suspend_policy
);
3372 process_breakpoint (void)
3374 DebuggerTlsData
*tls
;
3376 static void (*restore_context
) (void *);
3378 if (!restore_context
)
3379 restore_context
= mono_get_restore_context ();
3381 tls
= TlsGetValue (debugger_tls_id
);
3382 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3384 process_breakpoint_inner (tls
, &ctx
);
3386 /* This is called when resuming from a signal handler, so it shouldn't return */
3387 restore_context (&ctx
);
3388 g_assert_not_reached ();
3392 resume_from_signal_handler (void *sigctx
, void *func
)
3394 DebuggerTlsData
*tls
;
3397 /* Save the original context in TLS */
3398 // FIXME: This might not work on an altstack ?
3399 tls
= TlsGetValue (debugger_tls_id
);
3402 // FIXME: MonoContext usually doesn't include the fp registers, so these are
3403 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
3404 // clob:c could be added to op_seq_point.
3406 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3407 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
3408 MONO_CONTEXT_SET_IP (&ctx
, func
);
3409 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3411 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
3412 mono_ppc_set_func_into_sigctx (sigctx
, func
);
3417 mono_debugger_agent_breakpoint_hit (void *sigctx
)
3420 * We are called from a signal handler, and running code there causes all kinds of
3421 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
3422 * So set up the signal context to return to the real breakpoint handler function.
3425 resume_from_signal_handler (sigctx
, process_breakpoint
);
3429 process_single_step_inner (DebuggerTlsData
*tls
, MonoContext
*ctx
)
3434 int il_offset
, suspend_policy
;
3438 // FIXME: Speed this up
3440 ip
= MONO_CONTEXT_GET_IP (ctx
);
3442 /* Skip the instruction causing the single step */
3443 mono_arch_skip_single_step (ctx
);
3445 if (suspend_count
> 0) {
3446 process_suspend (tls
, ctx
);
3451 // FIXME: A suspend race
3454 if (mono_thread_internal_current () != ss_req
->thread
)
3457 if (log_level
> 0) {
3458 const char *depth
= NULL
;
3460 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3462 switch (ss_req
->depth
) {
3463 case STEP_DEPTH_OVER
:
3466 case STEP_DEPTH_OUT
:
3469 case STEP_DEPTH_INTO
:
3473 g_assert_not_reached ();
3476 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
));
3480 * We implement step over/out by single stepping until we reach the same
3481 * frame/parent frame.
3484 * - stack growing upward
3488 if (ss_req
->depth
!= STEP_DEPTH_INTO
) {
3489 if (ss_req
->depth
== STEP_DEPTH_OVER
&& MONO_CONTEXT_GET_SP (ctx
) < ss_req
->last_sp
)
3491 if (ss_req
->depth
== STEP_DEPTH_OUT
&& MONO_CONTEXT_GET_SP (ctx
) <= ss_req
->last_sp
)
3494 ss_req
->last_sp
= MONO_CONTEXT_GET_SP (ctx
);
3497 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
3499 g_assert (ji
->method
);
3501 if (ji
->method
->wrapper_type
&& ji
->method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
3506 * Stopping in memset makes half-initialized vtypes visible.
3507 * Stopping in memcpy makes half-copied vtypes visible.
3509 if (ji
->method
->klass
== mono_defaults
.string_class
&& (!strcmp (ji
->method
->name
, "memset") || strstr (ji
->method
->name
, "memcpy")))
3513 * The ip points to the instruction causing the single step event, convert it
3514 * to the offset stored in seq_points.
3516 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3517 ip
= mono_arch_get_ip_for_single_step (ji
, ctx
);
3519 g_assert_not_reached ();
3523 * mono_debug_lookup_source_location () doesn't work for IL offset 0 for
3524 * example, so do things by hand.
3526 il_offset
= compute_il_offset (domain
, ji
->method
, (guint8
*)ip
- (guint8
*)ji
->code_start
);
3528 if (il_offset
== -1)
3531 if (ss_req
->size
== STEP_SIZE_LINE
) {
3532 /* Step until a different source line is reached */
3533 MonoDebugMethodInfo
*minfo
;
3535 minfo
= mono_debug_lookup_method (ji
->method
);
3538 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, il_offset
);
3540 if (loc
&& ji
->method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
) {
3541 mono_debug_free_source_location (loc
);
3546 * Step until we reach a location with line number info,
3547 * otherwise the client can't show a location.
3548 * This can happen for example with statics initialized inline
3549 * outside of a cctor.
3554 ss_req
->last_method
= ji
->method
;
3555 ss_req
->last_line
= loc
->row
;
3556 mono_debug_free_source_location (loc
);
3561 // FIXME: Has to lock earlier
3563 reqs
= g_ptr_array_new ();
3565 mono_loader_lock ();
3567 g_ptr_array_add (reqs
, ss_req
->req
);
3569 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
3571 g_ptr_array_free (reqs
, TRUE
);
3573 mono_loader_unlock ();
3575 process_event (EVENT_KIND_STEP
, ji
->method
, il_offset
, ctx
, events
, suspend_policy
);
3579 process_single_step (void)
3581 DebuggerTlsData
*tls
;
3583 static void (*restore_context
) (void *);
3585 if (!restore_context
)
3586 restore_context
= mono_get_restore_context ();
3588 tls
= TlsGetValue (debugger_tls_id
);
3589 memcpy (&ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
3591 process_single_step_inner (tls
, &ctx
);
3593 /* This is called when resuming from a signal handler, so it shouldn't return */
3594 restore_context (&ctx
);
3595 g_assert_not_reached ();
3599 * mono_debugger_agent_single_step_event:
3601 * Called from a signal handler to handle a single step event.
3604 mono_debugger_agent_single_step_event (void *sigctx
)
3606 /* Resume to process_single_step through the signal context */
3608 // FIXME: Since step out/over is implemented using step in, the step in case should
3609 // be as fast as possible. Move the relevant code from process_single_step_inner ()
3612 if (GetCurrentThreadId () == debugger_thread_id
) {
3614 * This could happen despite our best effors when the runtime calls
3615 * assembly/type resolve hooks.
3616 * FIXME: Breakpoints too.
3620 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
3621 mono_arch_skip_single_step (&ctx
);
3622 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
3626 resume_from_signal_handler (sigctx
, process_single_step
);
3630 * start_single_stepping:
3632 * Turn on single stepping. Can be called multiple times, for example,
3633 * by a single step event request + a suspend.
3636 start_single_stepping (void)
3638 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3639 int val
= InterlockedIncrement (&ss_count
);
3642 mono_arch_start_single_stepping ();
3644 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
3645 DebuggerTlsData
*tls
;
3647 mono_loader_lock ();
3649 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
3650 ss_invoke_addr
= tls
->invoke_addr
;
3652 mono_loader_unlock ();
3655 g_assert_not_reached ();
3660 stop_single_stepping (void)
3662 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
3663 int val
= InterlockedDecrement (&ss_count
);
3666 mono_arch_stop_single_stepping ();
3668 g_assert_not_reached ();
3675 * Stop the single stepping operation given by SS_REQ.
3678 ss_stop (SingleStepReq
*ss_req
)
3680 gboolean use_bps
= FALSE
;
3687 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
3688 clear_breakpoint (l
->data
);
3690 g_slist_free (ss_req
->bps
);
3694 if (ss_req
->global
) {
3695 stop_single_stepping ();
3696 ss_req
->global
= FALSE
;
3703 * Start the single stepping operation given by SS_REQ from the sequence point SP.
3706 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
)
3708 gboolean use_bp
= FALSE
;
3713 /* Stop the previous operation */
3717 * Implement single stepping using breakpoints if possible.
3719 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3722 * Find the first sequence point in the current or in a previous frame which
3723 * is not the last in its method.
3725 while (sp
&& sp
->next_len
== 0) {
3727 if (tls
&& frame_index
< tls
->frame_count
) {
3728 StackFrame
*frame
= tls
->frames
[frame_index
];
3730 method
= frame
->method
;
3731 if (frame
->il_offset
!= -1) {
3732 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3738 if (sp
&& sp
->next_len
> 0) {
3740 for (i
= 0; i
< sp
->next_len
; ++i
) {
3741 next_sp
= &info
->seq_points
[sp
->next
[i
]];
3743 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
);
3744 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
3750 ss_req
->global
= TRUE
;
3751 start_single_stepping ();
3753 ss_req
->global
= FALSE
;
3758 * Start single stepping of thread THREAD
3761 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
3763 DebuggerTlsData
*tls
;
3764 MonoSeqPointInfo
*info
;
3765 SeqPoint
*sp
= NULL
;
3766 MonoMethod
*method
= NULL
;
3768 if (suspend_count
== 0)
3769 return ERR_NOT_SUSPENDED
;
3771 wait_for_suspend ();
3773 // FIXME: Multiple requests
3775 DEBUG (0, printf ("Received a single step request while the previous one was still active.\n"));
3776 return ERR_NOT_IMPLEMENTED
;
3779 ss_req
= g_new0 (SingleStepReq
, 1);
3781 ss_req
->thread
= thread
;
3782 ss_req
->size
= size
;
3783 ss_req
->depth
= depth
;
3786 mono_loader_lock ();
3787 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3788 mono_loader_unlock ();
3790 g_assert (tls
->has_context
);
3791 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->ctx
);
3793 if (ss_req
->size
== STEP_SIZE_LINE
) {
3795 MonoDebugMethodInfo
*minfo
;
3797 /* Compute the initial line info */
3798 compute_frame_info (thread
, tls
);
3800 g_assert (tls
->frame_count
);
3801 frame
= tls
->frames
[0];
3803 ss_req
->last_method
= frame
->method
;
3804 ss_req
->last_line
= -1;
3806 minfo
= mono_debug_lookup_method (frame
->method
);
3807 if (minfo
&& frame
->il_offset
!= -1) {
3808 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
3811 ss_req
->last_line
= loc
->row
;
3817 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
3820 compute_frame_info (thread
, tls
);
3822 g_assert (tls
->frame_count
);
3823 frame
= tls
->frames
[0];
3825 if (frame
->il_offset
!= -1) {
3826 /* FIXME: Sort the table and use a binary search */
3827 sp
= find_seq_point (frame
->domain
, frame
->method
, frame
->il_offset
, &info
);
3829 method
= frame
->method
;
3833 ss_start (ss_req
, method
, sp
, info
, NULL
, tls
);
3839 ss_destroy (SingleStepReq
*req
)
3842 g_assert (ss_req
== req
);
3851 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*ctx
)
3857 /* Just-In-Time debugging */
3858 if (agent_config
.onthrow
&& !inited
) {
3860 gboolean found
= FALSE
;
3862 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
3863 char *ex_type
= l
->data
;
3864 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
3866 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
3873 finish_agent_init (FALSE
);
3876 * Send an unsolicited EXCEPTION event with a dummy request id.
3878 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
3879 process_event (EVENT_KIND_EXCEPTION
, exc
, 0, ctx
, events
, SUSPEND_POLICY_ALL
);
3887 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (ctx
), NULL
);
3889 mono_loader_lock ();
3890 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, exc
, &suspend_policy
);
3891 mono_loader_unlock ();
3893 process_event (EVENT_KIND_EXCEPTION
, exc
, 0, ctx
, events
, suspend_policy
);
3897 mono_debugger_agent_handle_unhandled_exception (MonoException
*exc
, MonoContext
*ctx
)
3901 if (!agent_config
.onuncaught
)
3904 finish_agent_init (FALSE
);
3907 * Send an unsolicited EXCEPTION event with a dummy request id.
3909 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
3910 process_event (EVENT_KIND_EXCEPTION
, exc
, 0, ctx
, events
, SUSPEND_POLICY_ALL
);
3914 * buffer_add_value_full:
3916 * Add the encoding of the value at ADDR described by T to the buffer.
3917 * AS_VTYPE determines whenever to treat primitive types as primitive types or
3921 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
3927 g_assert (*(void**)addr
);
3928 addr
= *(void**)addr
;
3933 case MONO_TYPE_BOOLEAN
:
3936 case MONO_TYPE_CHAR
:
3956 case MONO_TYPE_VOID
:
3957 buffer_add_byte (buf
, t
->type
);
3959 case MONO_TYPE_BOOLEAN
:
3962 buffer_add_byte (buf
, t
->type
);
3963 buffer_add_int (buf
, *(gint8
*)addr
);
3965 case MONO_TYPE_CHAR
:
3968 buffer_add_byte (buf
, t
->type
);
3969 buffer_add_int (buf
, *(gint16
*)addr
);
3974 buffer_add_byte (buf
, t
->type
);
3975 buffer_add_int (buf
, *(gint32
*)addr
);
3980 buffer_add_byte (buf
, t
->type
);
3981 buffer_add_long (buf
, *(gint64
*)addr
);
3985 /* Treat it as a vtype */
3987 case MONO_TYPE_PTR
: {
3988 gssize val
= *(gssize
*)addr
;
3990 buffer_add_byte (buf
, t
->type
);
3991 buffer_add_long (buf
, val
);
3995 case MONO_TYPE_STRING
:
3996 case MONO_TYPE_SZARRAY
:
3997 case MONO_TYPE_OBJECT
:
3998 case MONO_TYPE_CLASS
:
3999 case MONO_TYPE_ARRAY
:
4000 obj
= *(MonoObject
**)addr
;
4003 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
4005 if (obj
->vtable
->klass
->valuetype
) {
4006 t
= &obj
->vtable
->klass
->byval_arg
;
4007 addr
= mono_object_unbox (obj
);
4009 } else if (obj
->vtable
->klass
->rank
) {
4010 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4011 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
4012 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
4014 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
4016 buffer_add_objid (buf
, obj
);
4020 case MONO_TYPE_VALUETYPE
: {
4024 MonoClass
*klass
= mono_class_from_mono_type (t
);
4026 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
4027 buffer_add_byte (buf
, klass
->enumtype
);
4028 buffer_add_typeid (buf
, domain
, klass
);
4032 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4033 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4035 if (mono_field_is_deleted (f
))
4039 buffer_add_int (buf
, nfields
);
4042 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4043 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4045 if (mono_field_is_deleted (f
))
4047 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
);
4051 case MONO_TYPE_GENERICINST
:
4052 if (mono_type_generic_inst_is_valuetype (t
)) {
4064 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
4066 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
);
4070 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
4073 int type
= decode_byte (buf
, &buf
, limit
);
4075 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
4076 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
4077 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
4078 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
4079 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
4080 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type 0x%0x, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), t
->type
, type
));
4081 return ERR_INVALID_ARGUMENT
;
4085 case MONO_TYPE_BOOLEAN
:
4086 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4088 case MONO_TYPE_CHAR
:
4089 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
4092 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
4095 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
4098 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
4101 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
4104 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
4107 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4110 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
4113 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4116 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
4119 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
4122 /* We send these as I8, so we get them back as such */
4123 g_assert (type
== MONO_TYPE_I8
);
4124 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
4126 case MONO_TYPE_GENERICINST
:
4127 if (MONO_TYPE_ISSTRUCT (t
)) {
4128 /* The client sends these as a valuetype */
4136 /* We send these as vtypes, so we get them back as such */
4137 g_assert (type
== MONO_TYPE_VALUETYPE
);
4140 case MONO_TYPE_VALUETYPE
: {
4141 gboolean is_enum
= decode_byte (buf
, &buf
, limit
);
4145 gpointer iter
= NULL
;
4148 /* Enums are sent as a normal vtype */
4150 return ERR_NOT_IMPLEMENTED
;
4151 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
4155 if (klass
!= mono_class_from_mono_type (t
))
4156 return ERR_INVALID_ARGUMENT
;
4158 nfields
= decode_int (buf
, &buf
, limit
);
4159 while ((f
= mono_class_get_fields (klass
, &iter
))) {
4160 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4162 if (mono_field_is_deleted (f
))
4164 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
4169 g_assert (nfields
== 0);
4174 if (MONO_TYPE_IS_REFERENCE (t
)) {
4175 if (type
== MONO_TYPE_OBJECT
) {
4176 int objid
= decode_objid (buf
, &buf
, limit
);
4180 err
= get_object (objid
, (MonoObject
**)&obj
);
4184 if (obj
&& !mono_class_is_assignable_from (mono_class_from_mono_type (t
), obj
->vtable
->klass
))
4185 return ERR_INVALID_ARGUMENT
;
4186 if (obj
&& obj
->vtable
->domain
!= domain
)
4187 return ERR_INVALID_ARGUMENT
;
4189 mono_gc_wbarrier_generic_store (addr
, obj
);
4190 } else if (type
== VALUE_TYPE_ID_NULL
) {
4191 *(MonoObject
**)addr
= NULL
;
4193 return ERR_INVALID_ARGUMENT
;
4207 add_var (Buffer
*buf
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
4214 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4215 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4218 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4219 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
4221 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
);
4223 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4224 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4225 addr
+= (gint32
)var
->offset
;
4227 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4229 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
);
4231 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4235 g_assert_not_reached ();
4240 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
)
4246 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4247 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
4249 if (MONO_TYPE_IS_REFERENCE (t
))
4250 size
= sizeof (gpointer
);
4252 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
4255 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
4256 // FIXME: Can't set registers, so we disable linears
4259 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
4260 addr
= mono_arch_context_get_int_reg (ctx
, reg
);
4261 addr
+= (gint32
)var
->offset
;
4263 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
4265 // FIXME: Write barriers
4266 memcpy (addr
, val
, size
);
4268 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
4272 g_assert_not_reached ();
4277 clear_event_request (int req_id
, int etype
)
4281 mono_loader_lock ();
4282 for (i
= 0; i
< event_requests
->len
; ++i
) {
4283 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4285 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
4286 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
4287 clear_breakpoint (req
->info
);
4288 if (req
->event_kind
== EVENT_KIND_STEP
)
4289 ss_destroy (req
->info
);
4290 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
4291 clear_breakpoint (req
->info
);
4292 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
4293 clear_breakpoint (req
->info
);
4294 g_ptr_array_remove_index_fast (event_requests
, i
);
4299 mono_loader_unlock ();
4303 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
4305 MonoInternalThread
*thread
= value
;
4306 Buffer
*buf
= user_data
;
4308 buffer_add_objid (buf
, (MonoObject
*)thread
);
4312 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
)
4314 guint8
*p
= invoke
->p
;
4315 guint8
*end
= invoke
->endp
;
4318 MonoMethodSignature
*sig
;
4321 MonoObject
*this, *res
, *exc
;
4324 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4328 if (invoke
->method
) {
4330 * Invoke this method directly, currently only Environment.Exit () is supported.
4333 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>"));
4334 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
4335 g_assert_not_reached ();
4338 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4341 sig
= mono_method_signature (m
);
4343 if (m
->klass
->valuetype
)
4344 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
4346 this_buf
= g_alloca (sizeof (MonoObject
*));
4347 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
4351 if (!m
->klass
->valuetype
)
4352 this = *(MonoObject
**)this_buf
;
4356 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>"));
4358 if (this && this->vtable
->domain
!= domain
)
4361 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
4362 if (!strcmp (m
->name
, ".ctor")) {
4363 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
4364 return ERR_INVALID_ARGUMENT
;
4366 this = mono_object_new (domain
, m
->klass
);
4368 return ERR_INVALID_ARGUMENT
;
4372 if (this && !mono_class_is_assignable_from (m
->klass
, this->vtable
->klass
))
4373 return ERR_INVALID_ARGUMENT
;
4375 nargs
= decode_int (p
, &p
, end
);
4376 if (nargs
!= sig
->param_count
)
4377 return ERR_INVALID_ARGUMENT
;
4378 /* Use alloca to get gc tracking */
4379 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
4380 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
4381 args
= g_alloca (nargs
* sizeof (gpointer
));
4382 for (i
= 0; i
< nargs
; ++i
) {
4383 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
4384 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
4388 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
4391 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
4392 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
4395 args
[i
] = arg_buf
[i
];
4402 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
4403 tls
->disable_breakpoints
= TRUE
;
4405 tls
->disable_breakpoints
= FALSE
;
4408 * Add an LMF frame to link the stack frames on the invoke method with our caller.
4410 /* FIXME: Move this to arch specific code */
4411 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4412 if (invoke
->has_ctx
) {
4415 lmf_addr
= mono_get_lmf_addr ();
4418 memset (&ext
, 0, sizeof (ext
));
4420 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4421 /* Mark that this is a MonoLMFExt */
4422 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4423 ext
.lmf
.rsp
= (gssize
)&ext
;
4424 #elif defined(TARGET_X86)
4425 ext
.lmf
.previous_lmf
= (gsize
)*(lmf_addr
);
4426 /* Mark that this is a MonoLMFExt */
4427 ext
.lmf
.previous_lmf
= (gsize
)(gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4428 ext
.lmf
.ebp
= (gssize
)&ext
;
4429 #elif defined(TARGET_ARM)
4430 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4431 /* Mark that this is a MonoLMFExt */
4432 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4433 ext
.lmf
.ebp
= (gssize
)&ext
;
4434 #elif defined(TARGET_POWERPC)
4435 ext
.lmf
.previous_lmf
= *(lmf_addr
);
4436 /* Mark that this is a MonoLMFExt */
4437 ext
.lmf
.previous_lmf
= (gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) | 2);
4438 ext
.lmf
.ebp
= (gssize
)&ext
;
4440 g_assert_not_reached ();
4443 ext
.debugger_invoke
= TRUE
;
4444 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4446 mono_set_lmf ((MonoLMF
*)&ext
);
4450 if (m
->klass
->valuetype
)
4451 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
4453 res
= mono_runtime_invoke (m
, this, args
, &exc
);
4455 buffer_add_byte (buf
, 0);
4456 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
4458 buffer_add_byte (buf
, 1);
4459 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
4460 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
4461 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
4464 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
4465 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
4466 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
4467 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
) {
4469 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
4475 tls
->disable_breakpoints
= FALSE
;
4477 #ifdef MONO_ARCH_HAVE_FIND_JIT_INFO_EXT
4478 if (invoke
->has_ctx
)
4479 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
4482 // FIXME: byref arguments
4490 * Invoke the method given by tls->invoke in the current thread.
4493 invoke_method (void)
4495 DebuggerTlsData
*tls
;
4500 static void (*restore_context
) (void *);
4501 MonoContext restore_ctx
;
4503 if (!restore_context
)
4504 restore_context
= mono_get_restore_context ();
4506 tls
= TlsGetValue (debugger_tls_id
);
4509 invoke
= tls
->invoke
;
4513 tls
->frames_up_to_date
= FALSE
;
4517 buffer_init (&buf
, 128);
4519 err
= do_invoke_method (tls
, &buf
, invoke
);
4521 /* Start suspending before sending the reply */
4522 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
))
4525 send_reply_packet (id
, err
, &buf
);
4529 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
4531 if (invoke
->has_ctx
)
4532 save_thread_context (&restore_ctx
);
4534 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
4535 g_assert (tls
->resume_count
);
4536 tls
->resume_count
-= invoke
->suspend_count
;
4539 DEBUG (1, printf ("[%p] Invoke finished, resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), tls
->resume_count
));
4548 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
4550 MonoThread
*thread
= value
;
4551 DebuggerTlsData
*tls
;
4554 mono_loader_lock ();
4555 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4557 res
= tls
->really_suspended
;
4558 mono_loader_unlock ();
4564 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4567 case CMD_VM_VERSION
: {
4568 char *build_info
, *version
;
4570 build_info
= mono_get_runtime_build_info ();
4571 version
= g_strdup_printf ("mono %s", build_info
);
4573 buffer_add_string (buf
, version
); /* vm version */
4574 buffer_add_int (buf
, MAJOR_VERSION
);
4575 buffer_add_int (buf
, MINOR_VERSION
);
4576 g_free (build_info
);
4580 case CMD_VM_ALL_THREADS
: {
4582 mono_loader_lock ();
4583 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
4584 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
4585 mono_loader_unlock ();
4588 case CMD_VM_SUSPEND
:
4590 wait_for_suspend ();
4593 if (suspend_count
== 0)
4594 return ERR_NOT_SUSPENDED
;
4597 case CMD_VM_DISPOSE
:
4598 /* Clear all event requests */
4599 mono_loader_lock ();
4600 while (event_requests
->len
> 0) {
4601 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4603 clear_event_request (req
->id
, req
->event_kind
);
4605 mono_loader_unlock ();
4607 // FIXME: Count resumes
4609 disconnected
= TRUE
;
4612 MonoInternalThread
*thread
;
4613 DebuggerTlsData
*tls
;
4614 MonoClass
*env_class
;
4615 MonoMethod
*exit_method
;
4619 exit_code
= decode_int (p
, &p
, end
);
4621 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
4623 /* Have to send a reply before exiting */
4624 send_reply_packet (id
, 0, buf
);
4626 /* Clear all event requests */
4627 mono_loader_lock ();
4628 while (event_requests
->len
> 0) {
4629 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
4631 clear_event_request (req
->id
, req
->event_kind
);
4633 mono_loader_unlock ();
4636 * The JDWP documentation says that the shutdown is not orderly. It doesn't
4637 * specify whenever a VM_DEATH event is sent. We currently do an orderly
4638 * shutdown by hijacking a thread to execute Environment.Exit (). This is
4639 * better than doing the shutdown ourselves, since it avoids various races.
4643 wait_for_suspend ();
4645 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
4646 g_assert (env_class
);
4647 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
4648 g_assert (exit_method
);
4650 mono_loader_lock ();
4651 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
4652 mono_loader_unlock ();
4655 mono_loader_lock ();
4656 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4657 mono_loader_unlock ();
4659 args
= g_new0 (gpointer
, 1);
4660 args
[0] = g_malloc (sizeof (int));
4661 *(int*)(args
[0]) = exit_code
;
4663 tls
->invoke
= g_new0 (InvokeData
, 1);
4664 tls
->invoke
->method
= exit_method
;
4665 tls
->invoke
->args
= args
;
4667 while (suspend_count
> 0)
4671 * No thread found, do it ourselves.
4672 * FIXME: This can race with normal shutdown etc.
4674 while (suspend_count
> 0)
4677 mono_runtime_set_shutting_down ();
4679 mono_threads_set_shutting_down ();
4681 /* Suspend all managed threads since the runtime is going away */
4682 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
4683 mono_thread_suspend_all_other_threads ();
4684 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
4685 mono_runtime_quit ();
4687 shutdown (conn_fd
, SD_BOTH
);
4689 shutdown (conn_fd
, SHUT_RDWR
);
4691 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
4697 case CMD_VM_INVOKE_METHOD
: {
4698 int objid
= decode_objid (p
, &p
, end
);
4700 DebuggerTlsData
*tls
;
4703 err
= get_object (objid
, (MonoObject
**)&thread
);
4707 flags
= decode_int (p
, &p
, end
);
4709 // Wait for suspending if it already started
4711 wait_for_suspend ();
4712 if (!is_suspended ())
4713 return ERR_NOT_SUSPENDED
;
4715 mono_loader_lock ();
4716 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
4717 mono_loader_unlock ();
4720 if (!tls
->really_suspended
)
4721 /* The thread is still running native code, can't do invokes */
4722 return ERR_NOT_SUSPENDED
;
4725 * Store the invoke data into tls, the thread will execute it after it is
4730 tls
->invoke
= g_new0 (InvokeData
, 1);
4731 tls
->invoke
->id
= id
;
4732 tls
->invoke
->flags
= flags
;
4733 tls
->invoke
->p
= g_malloc (end
- p
);
4734 memcpy (tls
->invoke
->p
, p
, end
- p
);
4735 tls
->invoke
->endp
= tls
->invoke
->p
+ (end
- p
);
4736 tls
->invoke
->suspend_count
= suspend_count
;
4738 if (flags
& INVOKE_FLAG_SINGLE_THREADED
)
4739 resume_thread (THREAD_TO_INTERNAL (thread
));
4745 return ERR_NOT_IMPLEMENTED
;
4752 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4757 case CMD_EVENT_REQUEST_SET
: {
4759 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
4762 MonoThread
*step_thread
;
4763 int size
= 0, depth
= 0, step_thread_id
= 0;
4766 event_kind
= decode_byte (p
, &p
, end
);
4767 suspend_policy
= decode_byte (p
, &p
, end
);
4768 nmodifiers
= decode_byte (p
, &p
, end
);
4770 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
4771 req
->id
= InterlockedIncrement (&event_request_id
);
4772 req
->event_kind
= event_kind
;
4773 req
->suspend_policy
= suspend_policy
;
4774 req
->nmodifiers
= nmodifiers
;
4777 for (i
= 0; i
< nmodifiers
; ++i
) {
4778 mod
= decode_byte (p
, &p
, end
);
4780 req
->modifiers
[i
].kind
= mod
;
4781 if (mod
== MOD_KIND_COUNT
) {
4782 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
4783 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
4784 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
4787 location
= decode_long (p
, &p
, end
);
4788 } else if (mod
== MOD_KIND_STEP
) {
4789 step_thread_id
= decode_id (p
, &p
, end
);
4790 size
= decode_int (p
, &p
, end
);
4791 depth
= decode_int (p
, &p
, end
);
4792 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
4793 int id
= decode_id (p
, &p
, end
);
4795 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
4800 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
4801 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
4806 req
->modifiers
[i
].data
.exc_class
= exc_class
;
4808 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
4810 return ERR_INVALID_ARGUMENT
;
4813 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
4814 int n
= decode_int (p
, &p
, end
);
4817 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
4818 for (j
= 0; j
< n
; ++j
) {
4819 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
4821 g_free (req
->modifiers
[i
].data
.assemblies
);
4827 return ERR_NOT_IMPLEMENTED
;
4831 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
4834 req
->info
= set_breakpoint (method
, location
, req
);
4835 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
4836 g_assert (step_thread_id
);
4838 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
4844 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
4849 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
4850 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
);
4851 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
4852 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
);
4853 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
4855 if (req
->nmodifiers
) {
4857 return ERR_NOT_IMPLEMENTED
;
4861 mono_loader_lock ();
4862 g_ptr_array_add (event_requests
, req
);
4863 mono_loader_unlock ();
4865 buffer_add_int (buf
, req
->id
);
4868 case CMD_EVENT_REQUEST_CLEAR
: {
4869 int etype
= decode_byte (p
, &p
, end
);
4870 int req_id
= decode_int (p
, &p
, end
);
4872 // FIXME: Make a faster mapping from req_id to request
4873 mono_loader_lock ();
4874 clear_event_request (req_id
, etype
);
4875 mono_loader_unlock ();
4878 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
4881 mono_loader_lock ();
4883 while (i
< event_requests
->len
) {
4884 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4886 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
4887 clear_breakpoint (req
->info
);
4889 g_ptr_array_remove_index_fast (event_requests
, i
);
4895 mono_loader_unlock ();
4899 return ERR_NOT_IMPLEMENTED
;
4906 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4912 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
4913 buffer_add_domainid (buf
, mono_get_root_domain ());
4916 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
4917 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
4920 buffer_add_string (buf
, domain
->friendly_name
);
4923 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
4928 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
4931 mono_loader_lock ();
4933 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
4936 buffer_add_int (buf
, count
);
4937 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
4939 buffer_add_assemblyid (buf
, domain
, ass
);
4941 mono_loader_unlock ();
4944 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
4945 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
4949 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
4952 case CMD_APPDOMAIN_GET_CORLIB
: {
4953 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
4957 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
4960 case CMD_APPDOMAIN_CREATE_STRING
: {
4964 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
4967 s
= decode_string (p
, &p
, end
);
4969 o
= mono_string_new (domain
, s
);
4970 buffer_add_objid (buf
, (MonoObject
*)o
);
4974 return ERR_NOT_IMPLEMENTED
;
4981 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
4987 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
4992 case CMD_ASSEMBLY_GET_LOCATION
: {
4993 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
4996 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
5000 if (ass
->image
->dynamic
) {
5001 buffer_add_id (buf
, 0);
5003 token
= mono_image_get_entry_point (ass
->image
);
5005 buffer_add_id (buf
, 0);
5007 m
= mono_get_method (ass
->image
, token
, NULL
);
5008 buffer_add_methodid (buf
, domain
, m
);
5013 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
5014 buffer_add_moduleid (buf
, domain
, ass
->image
);
5017 case CMD_ASSEMBLY_GET_OBJECT
: {
5018 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (mono_domain_get (), ass
);
5019 buffer_add_objid (buf
, o
);
5022 case CMD_ASSEMBLY_GET_TYPE
: {
5023 char *s
= decode_string (p
, &p
, end
);
5024 gboolean ignorecase
= decode_byte (p
, &p
, end
);
5025 MonoTypeNameParse info
;
5027 gboolean type_resolve
;
5029 if (!mono_reflection_parse_type (s
, &info
)) {
5032 if (info
.assembly
.name
)
5034 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
5036 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
5037 mono_reflection_free_type_info (&info
);
5042 case CMD_ASSEMBLY_GET_NAME
: {
5044 MonoAssembly
*mass
= ass
;
5046 name
= g_strdup_printf (
5047 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
5049 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
5050 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
5051 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
5052 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
5054 buffer_add_string (buf
, name
);
5059 return ERR_NOT_IMPLEMENTED
;
5066 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5072 case CMD_MODULE_GET_INFO
: {
5073 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
5076 basename
= g_path_get_basename (image
->name
);
5077 buffer_add_string (buf
, basename
); // name
5078 buffer_add_string (buf
, image
->module_name
); // scopename
5079 buffer_add_string (buf
, image
->name
); // fqname
5080 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
5081 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
5086 return ERR_NOT_IMPLEMENTED
;
5093 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
5095 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
5096 /* Special case these so the client doesn't have to handle Type objects */
5098 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
5099 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
5100 } else if (MONO_TYPE_IS_REFERENCE (t
))
5101 buffer_add_value (buf
, t
, &val
, domain
);
5103 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
5107 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
5113 buffer_add_int (buf
, 0);
5117 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5118 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
5121 buffer_add_int (buf
, nattrs
);
5123 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
5124 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
5125 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
5126 MonoArray
*typed_args
, *named_args
;
5128 CattrNamedArg
*arginfo
;
5130 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
);
5132 buffer_add_methodid (buf
, domain
, attr
->ctor
);
5136 buffer_add_int (buf
, mono_array_length (typed_args
));
5137 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
5138 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
5140 t
= mono_method_signature (attr
->ctor
)->params
[j
];
5142 buffer_add_cattr_arg (buf
, t
, domain
, val
);
5145 buffer_add_int (buf
, 0);
5150 buffer_add_int (buf
, mono_array_length (named_args
));
5152 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
5153 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
5155 if (arginfo
[j
].prop
) {
5156 buffer_add_byte (buf
, 0x54);
5157 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
5158 } else if (arginfo
[j
].field
) {
5159 buffer_add_byte (buf
, 0x53);
5161 g_assert_not_reached ();
5164 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
5167 buffer_add_int (buf
, 0);
5174 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5185 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
5190 case CMD_TYPE_GET_INFO
: {
5191 buffer_add_string (buf
, klass
->name_space
);
5192 buffer_add_string (buf
, klass
->name
);
5194 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
5195 buffer_add_string (buf
, name
);
5197 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
5198 buffer_add_moduleid (buf
, domain
, klass
->image
);
5199 buffer_add_typeid (buf
, domain
, klass
->parent
);
5200 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
5201 buffer_add_typeid (buf
, domain
, klass
->element_class
);
5203 buffer_add_id (buf
, 0);
5204 buffer_add_int (buf
, klass
->type_token
);
5205 buffer_add_byte (buf
, klass
->rank
);
5206 buffer_add_int (buf
, klass
->flags
);
5208 type
= &klass
->byval_arg
;
5209 // FIXME: Can't decide whenever a class represents a byref type
5212 if (type
->type
== MONO_TYPE_PTR
)
5214 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
5216 if (type
->type
== MONO_TYPE_VALUETYPE
)
5218 if (klass
->enumtype
)
5220 buffer_add_byte (buf
, b
);
5223 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5225 buffer_add_int (buf
, nnested
);
5227 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
5228 buffer_add_typeid (buf
, domain
, nested
);
5231 case CMD_TYPE_GET_METHODS
: {
5234 gpointer iter
= NULL
;
5237 nmethods
= mono_class_num_methods (klass
);
5239 buffer_add_int (buf
, nmethods
);
5241 while ((m
= mono_class_get_methods (klass
, &iter
))) {
5242 buffer_add_methodid (buf
, domain
, m
);
5245 g_assert (i
== nmethods
);
5248 case CMD_TYPE_GET_FIELDS
: {
5251 gpointer iter
= NULL
;
5254 nfields
= mono_class_num_fields (klass
);
5256 buffer_add_int (buf
, nfields
);
5258 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5259 buffer_add_fieldid (buf
, domain
, f
);
5260 buffer_add_string (buf
, f
->name
);
5261 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
5262 buffer_add_int (buf
, f
->type
->attrs
);
5265 g_assert (i
== nfields
);
5268 case CMD_TYPE_GET_PROPERTIES
: {
5271 gpointer iter
= NULL
;
5274 nprops
= mono_class_num_properties (klass
);
5276 buffer_add_int (buf
, nprops
);
5278 while ((p
= mono_class_get_properties (klass
, &iter
))) {
5279 buffer_add_propertyid (buf
, domain
, p
);
5280 buffer_add_string (buf
, p
->name
);
5281 buffer_add_methodid (buf
, domain
, p
->get
);
5282 buffer_add_methodid (buf
, domain
, p
->set
);
5283 buffer_add_int (buf
, p
->attrs
);
5286 g_assert (i
== nprops
);
5289 case CMD_TYPE_GET_CATTRS
: {
5290 MonoClass
*attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5291 MonoCustomAttrInfo
*cinfo
;
5293 cinfo
= mono_custom_attrs_from_class (klass
);
5295 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5298 case CMD_TYPE_GET_FIELD_CATTRS
: {
5299 MonoClass
*attr_klass
;
5300 MonoCustomAttrInfo
*cinfo
;
5301 MonoClassField
*field
;
5303 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5306 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5310 cinfo
= mono_custom_attrs_from_field (klass
, field
);
5312 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5315 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
5316 MonoClass
*attr_klass
;
5317 MonoCustomAttrInfo
*cinfo
;
5320 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
5323 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5327 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
5329 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
5332 case CMD_TYPE_GET_VALUES
: {
5340 len
= decode_int (p
, &p
, end
);
5341 for (i
= 0; i
< len
; ++i
) {
5342 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5346 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5347 return ERR_INVALID_FIELDID
;
5348 if (mono_class_field_is_special_static (f
))
5349 return ERR_INVALID_FIELDID
;
5351 /* Check that the field belongs to the object */
5353 for (k
= klass
; k
; k
= k
->parent
) {
5354 if (k
== f
->parent
) {
5360 return ERR_INVALID_FIELDID
;
5362 vtable
= mono_class_vtable (domain
, f
->parent
);
5363 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5364 mono_field_static_get_value (vtable
, f
, val
);
5365 buffer_add_value (buf
, f
->type
, val
, domain
);
5370 case CMD_TYPE_SET_VALUES
: {
5378 len
= decode_int (p
, &p
, end
);
5379 for (i
= 0; i
< len
; ++i
) {
5380 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
5384 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
5385 return ERR_INVALID_FIELDID
;
5386 if (mono_class_field_is_special_static (f
))
5387 return ERR_INVALID_FIELDID
;
5389 /* Check that the field belongs to the object */
5391 for (k
= klass
; k
; k
= k
->parent
) {
5392 if (k
== f
->parent
) {
5398 return ERR_INVALID_FIELDID
;
5400 // FIXME: Check for literal/const
5402 vtable
= mono_class_vtable (domain
, f
->parent
);
5403 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
5404 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
5409 mono_field_static_set_value (vtable
, f
, val
);
5414 case CMD_TYPE_GET_OBJECT
: {
5415 MonoObject
*o
= (MonoObject
*)mono_type_get_object (mono_domain_get (), &klass
->byval_arg
);
5416 buffer_add_objid (buf
, o
);
5419 case CMD_TYPE_GET_SOURCE_FILES
: {
5420 gpointer iter
= NULL
;
5422 char *source_file
, *base
;
5426 files
= g_ptr_array_new ();
5428 while ((method
= mono_class_get_methods (klass
, &iter
))) {
5429 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
5432 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, NULL
, NULL
, NULL
);
5434 for (i
= 0; i
< files
->len
; ++i
)
5435 if (!strcmp (g_ptr_array_index (files
, i
), source_file
))
5437 if (i
== files
->len
)
5438 g_ptr_array_add (files
, g_strdup (source_file
));
5439 g_free (source_file
);
5443 buffer_add_int (buf
, files
->len
);
5444 for (i
= 0; i
< files
->len
; ++i
) {
5445 source_file
= g_ptr_array_index (files
, i
);
5446 base
= g_path_get_basename (source_file
);
5447 buffer_add_string (buf
, base
);
5449 g_free (source_file
);
5451 g_ptr_array_free (files
, TRUE
);
5454 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
5455 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
5459 if (mono_class_is_assignable_from (klass
, oklass
))
5460 buffer_add_byte (buf
, 1);
5462 buffer_add_byte (buf
, 0);
5466 return ERR_NOT_IMPLEMENTED
;
5473 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5478 MonoMethodHeader
*header
;
5480 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
5485 case CMD_METHOD_GET_NAME
: {
5486 buffer_add_string (buf
, method
->name
);
5489 case CMD_METHOD_GET_DECLARING_TYPE
: {
5490 buffer_add_typeid (buf
, domain
, method
->klass
);
5493 case CMD_METHOD_GET_DEBUG_INFO
: {
5494 MonoDebugMethodInfo
*minfo
;
5496 int i
, n_il_offsets
;
5500 header
= mono_method_get_header (method
);
5502 buffer_add_int (buf
, 0);
5503 buffer_add_string (buf
, "");
5504 buffer_add_int (buf
, 0);
5508 minfo
= mono_debug_lookup_method (method
);
5510 buffer_add_int (buf
, header
->code_size
);
5511 buffer_add_string (buf
, "");
5512 buffer_add_int (buf
, 0);
5516 mono_debug_symfile_get_line_numbers (minfo
, &source_file
, &n_il_offsets
, &il_offsets
, &line_numbers
);
5517 buffer_add_int (buf
, header
->code_size
);
5518 buffer_add_string (buf
, source_file
);
5519 buffer_add_int (buf
, n_il_offsets
);
5520 //printf ("Line number table for method %s:\n", mono_method_full_name (method, TRUE));
5521 for (i
= 0; i
< n_il_offsets
; ++i
) {
5522 //printf ("IL%d -> %d\n", il_offsets [i], line_numbers [i]);
5523 buffer_add_int (buf
, il_offsets
[i
]);
5524 buffer_add_int (buf
, line_numbers
[i
]);
5526 g_free (source_file
);
5527 g_free (il_offsets
);
5528 g_free (line_numbers
);
5531 case CMD_METHOD_GET_PARAM_INFO
: {
5532 MonoMethodSignature
*sig
= mono_method_signature (method
);
5536 /* FIXME: mono_class_from_mono_type () and byrefs */
5538 /* FIXME: Use a smaller encoding */
5539 buffer_add_int (buf
, sig
->call_convention
);
5540 buffer_add_int (buf
, sig
->param_count
);
5541 buffer_add_int (buf
, sig
->generic_param_count
);
5542 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
5543 for (i
= 0; i
< sig
->param_count
; ++i
) {
5545 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
5548 /* Emit parameter names */
5549 names
= g_new (char *, sig
->param_count
);
5550 mono_method_get_param_names (method
, (const char **) names
);
5551 for (i
= 0; i
< sig
->param_count
; ++i
)
5552 buffer_add_string (buf
, names
[i
]);
5557 case CMD_METHOD_GET_LOCALS_INFO
: {
5558 int i
, j
, num_locals
;
5562 header
= mono_method_get_header (method
);
5565 buffer_add_int (buf
, header
->num_locals
);
5568 for (i
= 0; i
< header
->num_locals
; ++i
)
5569 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
5572 num_locals
= mono_debug_lookup_locals (method
, &local_names
, &local_indexes
);
5573 for (i
= 0; i
< header
->num_locals
; ++i
) {
5574 for (j
= 0; j
< num_locals
; ++j
)
5575 if (local_indexes
[j
] == i
)
5578 buffer_add_string (buf
, local_names
[j
]);
5580 buffer_add_string (buf
, "");
5582 g_free (local_names
);
5583 g_free (local_indexes
);
5586 /* FIXME: This works because we set debug_options.mdb_optimizations */
5587 for (i
= 0; i
< header
->num_locals
; ++i
) {
5588 buffer_add_int (buf
, 0);
5589 buffer_add_int (buf
, header
->code_size
);
5594 case CMD_METHOD_GET_INFO
:
5595 buffer_add_int (buf
, method
->flags
);
5596 buffer_add_int (buf
, method
->iflags
);
5597 buffer_add_int (buf
, method
->token
);
5599 case CMD_METHOD_GET_BODY
: {
5602 header
= mono_method_get_header (method
);
5604 buffer_add_int (buf
, 0);
5606 buffer_add_int (buf
, header
->code_size
);
5607 for (i
= 0; i
< header
->code_size
; ++i
)
5608 buffer_add_byte (buf
, header
->code
[i
]);
5612 case CMD_METHOD_RESOLVE_TOKEN
: {
5613 guint32 token
= decode_int (p
, &p
, end
);
5616 switch (mono_metadata_token_code (token
)) {
5617 case MONO_TOKEN_STRING
: {
5621 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
5624 s2
= mono_string_to_utf8 (s
);
5626 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5627 buffer_add_string (buf
, s2
);
5633 MonoClass
*handle_class
;
5635 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
5636 val
= mono_method_get_wrapper_data (method
, token
);
5637 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
5639 if (handle_class
== NULL
) {
5640 // Can't figure out the token type
5641 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
5645 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
5649 if (handle_class
== mono_defaults
.typehandle_class
) {
5650 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
5651 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
5652 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
5653 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
5654 buffer_add_fieldid (buf
, domain
, val
);
5655 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
5656 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
5657 buffer_add_methodid (buf
, domain
, val
);
5658 } else if (handle_class
== mono_defaults
.string_class
) {
5661 s
= mono_string_to_utf8 (val
);
5662 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
5663 buffer_add_string (buf
, s
);
5666 g_assert_not_reached ();
5674 return ERR_NOT_IMPLEMENTED
;
5681 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5683 int objid
= decode_objid (p
, &p
, end
);
5685 MonoThread
*thread_obj
;
5686 MonoInternalThread
*thread
;
5688 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
5692 thread
= THREAD_TO_INTERNAL (thread_obj
);
5695 case CMD_THREAD_GET_NAME
: {
5697 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
5700 buffer_add_int (buf
, 0);
5705 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
5707 buffer_add_int (buf
, len
);
5708 buffer_add_data (buf
, (guint8
*)name
, len
);
5713 case CMD_THREAD_GET_FRAME_INFO
: {
5714 DebuggerTlsData
*tls
;
5715 int i
, start_frame
, length
;
5717 // Wait for suspending if it already started
5719 wait_for_suspend ();
5720 if (!is_suspended ())
5721 return ERR_NOT_SUSPENDED
;
5723 start_frame
= decode_int (p
, &p
, end
);
5724 length
= decode_int (p
, &p
, end
);
5726 if (start_frame
!= 0 || length
!= -1)
5727 return ERR_NOT_IMPLEMENTED
;
5729 mono_loader_lock ();
5730 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5731 mono_loader_unlock ();
5734 compute_frame_info (thread
, tls
);
5736 buffer_add_int (buf
, tls
->frame_count
);
5737 for (i
= 0; i
< tls
->frame_count
; ++i
) {
5738 buffer_add_int (buf
, tls
->frames
[i
]->id
);
5739 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->method
);
5740 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
5742 * Instead of passing the frame type directly to the client, we associate
5743 * it with the previous frame using a set of flags. This avoids lots of
5744 * conditional code in the client, since a frame whose type isn't
5745 * FRAME_TYPE_MANAGED has no method, location, etc.
5747 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
5752 case CMD_THREAD_GET_STATE
:
5753 buffer_add_int (buf
, thread
->state
);
5755 case CMD_THREAD_GET_INFO
:
5756 buffer_add_byte (buf
, thread
->threadpool_thread
);
5759 return ERR_NOT_IMPLEMENTED
;
5766 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5770 MonoThread
*thread_obj
;
5771 MonoInternalThread
*thread
;
5773 DebuggerTlsData
*tls
;
5775 MonoDebugMethodJitInfo
*jit
;
5776 MonoDebugVarInfo
*var
;
5777 MonoMethodSignature
*sig
;
5779 MonoMethodHeader
*header
;
5781 objid
= decode_objid (p
, &p
, end
);
5782 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
5786 thread
= THREAD_TO_INTERNAL (thread_obj
);
5788 id
= decode_id (p
, &p
, end
);
5790 mono_loader_lock ();
5791 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5792 mono_loader_unlock ();
5795 for (i
= 0; i
< tls
->frame_count
; ++i
) {
5796 if (tls
->frames
[i
]->id
== id
)
5799 if (i
== tls
->frame_count
)
5800 return ERR_INVALID_FRAMEID
;
5802 frame
= tls
->frames
[i
];
5804 if (!frame
->has_ctx
)
5806 return ERR_INVALID_FRAMEID
;
5809 frame
->jit
= mono_debug_find_method (frame
->method
, frame
->domain
);
5810 g_assert (frame
->jit
);
5814 sig
= mono_method_signature (frame
->method
);
5817 case CMD_STACK_FRAME_GET_VALUES
: {
5818 len
= decode_int (p
, &p
, end
);
5819 header
= mono_method_get_header (frame
->method
);
5821 for (i
= 0; i
< len
; ++i
) {
5822 pos
= decode_int (p
, &p
, end
);
5827 g_assert (pos
>= 0 && pos
< jit
->num_params
);
5829 var
= &jit
->params
[pos
];
5831 add_var (buf
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
5833 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
5835 var
= &jit
->locals
[pos
];
5837 add_var (buf
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
5842 case CMD_STACK_FRAME_GET_THIS
: {
5843 if (frame
->method
->klass
->valuetype
) {
5844 if (!sig
->hasthis
) {
5845 MonoObject
*p
= NULL
;
5846 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
5848 add_var (buf
, &frame
->method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
5851 if (!sig
->hasthis
) {
5852 MonoObject
*p
= NULL
;
5853 buffer_add_value (buf
, &frame
->method
->klass
->byval_arg
, &p
, frame
->domain
);
5855 add_var (buf
, &frame
->method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
5860 case CMD_STACK_FRAME_SET_VALUES
: {
5863 MonoDebugVarInfo
*var
;
5865 len
= decode_int (p
, &p
, end
);
5866 header
= mono_method_get_header (frame
->method
);
5868 for (i
= 0; i
< len
; ++i
) {
5869 pos
= decode_int (p
, &p
, end
);
5874 g_assert (pos
>= 0 && pos
< jit
->num_params
);
5876 t
= sig
->params
[pos
];
5877 var
= &jit
->params
[pos
];
5879 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
5881 t
= header
->locals
[pos
];
5882 var
= &jit
->locals
[pos
];
5885 if (MONO_TYPE_IS_REFERENCE (t
))
5886 val_buf
= g_alloca (sizeof (MonoObject
*));
5888 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
5889 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
5893 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
);
5898 return ERR_NOT_IMPLEMENTED
;
5905 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5908 int objid
, err
, index
, len
, i
, esize
;
5911 objid
= decode_objid (p
, &p
, end
);
5912 err
= get_object (objid
, (MonoObject
**)&arr
);
5917 case CMD_ARRAY_REF_GET_LENGTH
:
5918 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
5920 buffer_add_int (buf
, arr
->max_length
);
5921 buffer_add_int (buf
, 0);
5923 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
5924 buffer_add_int (buf
, arr
->bounds
[i
].length
);
5925 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
5929 case CMD_ARRAY_REF_GET_VALUES
:
5930 index
= decode_int (p
, &p
, end
);
5931 len
= decode_int (p
, &p
, end
);
5933 g_assert (index
>= 0 && len
>= 0);
5934 // Reordered to avoid integer overflow
5935 g_assert (!(index
> arr
->max_length
- len
));
5937 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
5938 for (i
= index
; i
< index
+ len
; ++i
) {
5939 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
5940 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
5943 case CMD_ARRAY_REF_SET_VALUES
:
5944 index
= decode_int (p
, &p
, end
);
5945 len
= decode_int (p
, &p
, end
);
5947 g_assert (index
>= 0 && len
>= 0);
5948 // Reordered to avoid integer overflow
5949 g_assert (!(index
> arr
->max_length
- len
));
5951 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
5952 for (i
= index
; i
< index
+ len
; ++i
) {
5953 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
5955 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
5959 return ERR_NOT_IMPLEMENTED
;
5966 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
5972 objid
= decode_objid (p
, &p
, end
);
5973 err
= get_object (objid
, (MonoObject
**)&str
);
5978 case CMD_STRING_REF_GET_VALUE
:
5979 s
= mono_string_to_utf8 (str
);
5980 buffer_add_string (buf
, s
);
5984 return ERR_NOT_IMPLEMENTED
;
5991 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6000 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
6001 objid
= decode_objid (p
, &p
, end
);
6002 err
= get_object (objid
, &obj
);
6004 buffer_add_int (buf
, 1);
6006 buffer_add_int (buf
, 0);
6010 objid
= decode_objid (p
, &p
, end
);
6011 err
= get_object (objid
, &obj
);
6016 case CMD_OBJECT_REF_GET_TYPE
:
6017 buffer_add_typeid (buf
, obj
->vtable
->domain
, obj
->vtable
->klass
);
6019 case CMD_OBJECT_REF_GET_VALUES
:
6020 len
= decode_int (p
, &p
, end
);
6022 for (i
= 0; i
< len
; ++i
) {
6023 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6027 /* Check that the field belongs to the object */
6029 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6030 if (k
== f
->parent
) {
6036 return ERR_INVALID_FIELDID
;
6038 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6042 if (mono_class_field_is_special_static (f
))
6043 return ERR_INVALID_FIELDID
;
6045 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6046 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6047 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6048 mono_field_static_get_value (vtable
, f
, val
);
6049 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
6052 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
6056 case CMD_OBJECT_REF_SET_VALUES
:
6057 len
= decode_int (p
, &p
, end
);
6059 for (i
= 0; i
< len
; ++i
) {
6060 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
6064 /* Check that the field belongs to the object */
6066 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
6067 if (k
== f
->parent
) {
6073 return ERR_INVALID_FIELDID
;
6075 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
6079 if (mono_class_field_is_special_static (f
))
6080 return ERR_INVALID_FIELDID
;
6082 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
6083 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
6085 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
6086 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
6091 mono_field_static_set_value (vtable
, f
, val
);
6094 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
6100 case CMD_OBJECT_REF_GET_ADDRESS
:
6101 buffer_add_long (buf
, (gssize
)obj
);
6103 case CMD_OBJECT_REF_GET_DOMAIN
:
6104 buffer_add_domainid (buf
, obj
->vtable
->domain
);
6107 return ERR_NOT_IMPLEMENTED
;
6114 command_set_to_string (CommandSet command_set
)
6116 switch (command_set
) {
6119 case CMD_SET_OBJECT_REF
:
6120 return "OBJECT_REF";
6121 case CMD_SET_STRING_REF
:
6122 return "STRING_REF";
6123 case CMD_SET_THREAD
:
6125 case CMD_SET_ARRAY_REF
:
6127 case CMD_SET_EVENT_REQUEST
:
6128 return "EVENT_REQUEST";
6129 case CMD_SET_STACK_FRAME
:
6130 return "STACK_FRAME";
6131 case CMD_SET_APPDOMAIN
:
6133 case CMD_SET_ASSEMBLY
:
6135 case CMD_SET_METHOD
:
6139 case CMD_SET_MODULE
:
6151 * This thread handles communication with the debugger client using a JDWP
6154 static guint32 WINAPI
6155 debugger_thread (void *arg
)
6157 int res
, len
, id
, flags
, command_set
, command
;
6158 guint8 header
[HEADER_LENGTH
];
6159 guint8
*data
, *p
, *end
;
6164 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
6166 debugger_thread_id
= GetCurrentThreadId ();
6168 mono_jit_thread_attach (mono_get_root_domain ());
6170 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
6172 mono_set_is_debugger_attached (TRUE
);
6175 res
= recv (conn_fd
, header
, HEADER_LENGTH
, 0);
6177 /* This will break if the socket is closed during shutdown too */
6178 if (res
!= HEADER_LENGTH
)
6182 end
= header
+ HEADER_LENGTH
;
6184 len
= decode_int (p
, &p
, end
);
6185 id
= decode_int (p
, &p
, end
);
6186 flags
= decode_byte (p
, &p
, end
);
6187 command_set
= decode_byte (p
, &p
, end
);
6188 command
= decode_byte (p
, &p
, end
);
6190 g_assert (flags
== 0);
6192 DEBUG (1, fprintf (log_file
, "[dbg] Received command %s(%d), id=%d.\n", command_set_to_string (command_set
), command
, id
));
6194 data
= g_malloc (len
- HEADER_LENGTH
);
6195 if (len
- HEADER_LENGTH
> 0)
6197 res
= recv (conn_fd
, data
, len
- HEADER_LENGTH
, 0);
6198 if (res
!= len
- HEADER_LENGTH
)
6203 end
= data
+ (len
- HEADER_LENGTH
);
6205 buffer_init (&buf
, 128);
6210 /* Process the request */
6211 switch (command_set
) {
6213 err
= vm_commands (command
, id
, p
, end
, &buf
);
6214 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
6215 /* Sent after the invoke is complete */
6218 case CMD_SET_EVENT_REQUEST
:
6219 err
= event_commands (command
, p
, end
, &buf
);
6221 case CMD_SET_APPDOMAIN
:
6222 err
= domain_commands (command
, p
, end
, &buf
);
6224 case CMD_SET_ASSEMBLY
:
6225 err
= assembly_commands (command
, p
, end
, &buf
);
6227 case CMD_SET_MODULE
:
6228 err
= module_commands (command
, p
, end
, &buf
);
6231 err
= type_commands (command
, p
, end
, &buf
);
6233 case CMD_SET_METHOD
:
6234 err
= method_commands (command
, p
, end
, &buf
);
6236 case CMD_SET_THREAD
:
6237 err
= thread_commands (command
, p
, end
, &buf
);
6239 case CMD_SET_STACK_FRAME
:
6240 err
= frame_commands (command
, p
, end
, &buf
);
6242 case CMD_SET_ARRAY_REF
:
6243 err
= array_commands (command
, p
, end
, &buf
);
6245 case CMD_SET_STRING_REF
:
6246 err
= string_commands (command
, p
, end
, &buf
);
6248 case CMD_SET_OBJECT_REF
:
6249 err
= object_commands (command
, p
, end
, &buf
);
6252 err
= ERR_NOT_IMPLEMENTED
;
6256 send_reply_packet (id
, err
, &buf
);
6261 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
)
6265 mono_set_is_debugger_attached (FALSE
);
6267 mono_mutex_lock (&debugger_thread_exited_mutex
);
6268 debugger_thread_exited
= TRUE
;
6269 mono_cond_signal (&debugger_thread_exited_cond
);
6270 mono_mutex_unlock (&debugger_thread_exited_mutex
);
6272 DEBUG (1, printf ("[dbg] Debugger thread exited.\n"));
6277 #else /* DISABLE_DEBUGGER_AGENT */
6280 mono_debugger_agent_parse_options (char *options
)
6282 g_error ("This runtime is configure with the debugger agent disabled.");
6286 mono_debugger_agent_init (void)
6291 mono_debugger_agent_breakpoint_hit (void *sigctx
)
6296 mono_debugger_agent_single_step_event (void *sigctx
)
6301 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
6306 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
6312 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*ctx
)
6317 mono_debugger_agent_handle_unhandled_exception (MonoException
*exc
, MonoContext
*ctx
)