2 * debugger-agent.c: Soft Debugger back-end module
5 * Zoltan Varga (vargaz@gmail.com)
7 * Copyright 2009-2010 Novell, Inc.
8 * Copyright 2011 Xamarin Inc.
15 #ifdef HAVE_SYS_TYPES_H
16 #include <sys/types.h>
18 #ifdef HAVE_SYS_SELECT_H
19 #include <sys/select.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 #include <sys/socket.h>
24 #ifdef HAVE_NETINET_TCP_H
25 #include <netinet/tcp.h>
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
43 #ifdef HAVE_UCONTEXT_H
53 /* cygwin's headers do not seem to define these */
54 void WSAAPI
freeaddrinfo (struct addrinfo
*);
55 int WSAAPI
getaddrinfo (const char*,const char*,const struct addrinfo
*,
57 int WSAAPI
getnameinfo(const struct sockaddr
*,socklen_t
,char*,DWORD
,
62 #ifdef PLATFORM_ANDROID
64 #include <linux/tcp.h>
65 #include <sys/endian.h>
68 #include <mono/metadata/mono-debug.h>
69 #include <mono/metadata/mono-debug-debugger.h>
70 #include <mono/metadata/debug-mono-symfile.h>
71 #include <mono/metadata/gc-internal.h>
72 #include <mono/metadata/environment.h>
73 #include <mono/metadata/threads-types.h>
74 #include <mono/metadata/socket-io.h>
75 #include <mono/metadata/assembly.h>
76 #include <mono/metadata/runtime.h>
77 #include <mono/metadata/threadpool.h>
78 #include <mono/metadata/verify-internals.h>
79 #include <mono/utils/mono-semaphore.h>
80 #include <mono/utils/mono-error-internals.h>
81 #include <mono/utils/mono-stack-unwinding.h>
82 #include <mono/utils/mono-time.h>
83 #include <mono/utils/mono-threads.h>
84 #include "debugger-agent.h"
88 On iOS we can't use System.Environment.Exit () as it will do the wrong
91 #if !defined (TARGET_IOS)
92 #define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
96 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
97 #define DISABLE_DEBUGGER_AGENT 1
100 #ifdef DISABLE_SOFT_DEBUG
101 #define DISABLE_DEBUGGER_AGENT 1
104 #ifndef DISABLE_DEBUGGER_AGENT
106 #include <mono/utils/mono-mutex.h>
108 /* Definitions to make backporting to 2.6 easier */
109 //#define MonoInternalThread MonoThread
110 //#define mono_thread_internal_current mono_thread_current
111 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
134 guint32 il_offset
, native_offset
;
138 * If method is gshared, this is the actual instance, otherwise this is equal to
141 MonoMethod
*actual_method
;
143 * This is the method which is visible to debugger clients. Same as method,
144 * except for native-to-managed wrappers.
146 MonoMethod
*api_method
;
148 MonoDebugMethodJitInfo
*jit
;
151 mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
153 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
154 * the frame can become invalid.
159 typedef struct _InvokeData InvokeData
;
167 /* This is the context which needs to be restored after the invoke */
171 * If this is set, invoke this method with the arguments given by ARGS.
175 guint32 suspend_count
;
178 InvokeData
*last_invoke
;
182 MonoThreadUnwindState context
;
184 /* This is computed on demand when it is requested using the wire protocol */
185 /* It is freed up when the thread is resumed */
189 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
192 gboolean frames_up_to_date
;
194 * Points to data about a pending invoke which needs to be executed after the thread
197 InvokeData
*pending_invoke
;
199 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
204 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
205 * within a finite amount of time.
209 * Set to TRUE if this thread is suspended in suspend_current ().
211 gboolean really_suspended
;
212 /* Used to pass the context to the breakpoint/single step handler */
213 MonoContext handler_ctx
;
214 /* Whenever thread_stop () was called for this thread */
217 /* Number of thread interruptions not yet processed */
218 gint32 interrupt_count
;
220 /* Whenever to disable breakpoints (used during invokes) */
221 gboolean disable_breakpoints
;
224 * Number of times this thread has been resumed using resume_thread ().
226 guint32 resume_count
;
228 MonoInternalThread
*thread
;
231 * Information about the frame which transitioned to native code for running
234 StackFrameInfo async_last_frame
;
237 * The context where the stack walk can be started for running threads.
239 MonoThreadUnwindState async_state
;
242 * The context used for filter clauses
244 MonoThreadUnwindState filter_state
;
247 * The callee address of the last mono_runtime_invoke call
249 gpointer invoke_addr
;
251 gboolean abort_requested
;
254 * The current mono_runtime_invoke invocation.
259 * The context where single stepping should resume while the thread is suspended because
260 * of an EXCEPTION event.
262 MonoThreadUnwindState catch_state
;
265 * The context which needs to be restored after handling a single step/breakpoint
266 * event. This is the same as the ctx at step/breakpoint site, but includes changes
267 * to caller saved registers done by set_var ().
269 MonoContext restore_ctx
;
274 void (*connect
) (const char *address
);
275 void (*close1
) (void);
276 void (*close2
) (void);
277 gboolean (*send
) (void *buf
, int len
);
278 int (*recv
) (void *buf
, int len
);
282 * Wire Protocol definitions
285 #define HEADER_LENGTH 11
287 #define MAJOR_VERSION 2
288 #define MINOR_VERSION 34
292 CMD_SET_OBJECT_REF
= 9,
293 CMD_SET_STRING_REF
= 10,
295 CMD_SET_ARRAY_REF
= 13,
296 CMD_SET_EVENT_REQUEST
= 15,
297 CMD_SET_STACK_FRAME
= 16,
298 CMD_SET_APPDOMAIN
= 20,
299 CMD_SET_ASSEMBLY
= 21,
308 EVENT_KIND_VM_START
= 0,
309 EVENT_KIND_VM_DEATH
= 1,
310 EVENT_KIND_THREAD_START
= 2,
311 EVENT_KIND_THREAD_DEATH
= 3,
312 EVENT_KIND_APPDOMAIN_CREATE
= 4,
313 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
314 EVENT_KIND_METHOD_ENTRY
= 6,
315 EVENT_KIND_METHOD_EXIT
= 7,
316 EVENT_KIND_ASSEMBLY_LOAD
= 8,
317 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
318 EVENT_KIND_BREAKPOINT
= 10,
319 EVENT_KIND_STEP
= 11,
320 EVENT_KIND_TYPE_LOAD
= 12,
321 EVENT_KIND_EXCEPTION
= 13,
322 EVENT_KIND_KEEPALIVE
= 14,
323 EVENT_KIND_USER_BREAK
= 15,
324 EVENT_KIND_USER_LOG
= 16
328 SUSPEND_POLICY_NONE
= 0,
329 SUSPEND_POLICY_EVENT_THREAD
= 1,
330 SUSPEND_POLICY_ALL
= 2
335 ERR_INVALID_OBJECT
= 20,
336 ERR_INVALID_FIELDID
= 25,
337 ERR_INVALID_FRAMEID
= 30,
338 ERR_NOT_IMPLEMENTED
= 100,
339 ERR_NOT_SUSPENDED
= 101,
340 ERR_INVALID_ARGUMENT
= 102,
342 ERR_NO_INVOCATION
= 104,
343 ERR_ABSENT_INFORMATION
= 105,
344 ERR_NO_SEQ_POINT_AT_IL_OFFSET
= 106,
345 ERR_LOADER_ERROR
= 200, /*XXX extend the protocol to pass this information down the pipe */
350 MOD_KIND_THREAD_ONLY
= 3,
351 MOD_KIND_LOCATION_ONLY
= 7,
352 MOD_KIND_EXCEPTION_ONLY
= 8,
354 MOD_KIND_ASSEMBLY_ONLY
= 11,
355 MOD_KIND_SOURCE_FILE_ONLY
= 12,
356 MOD_KIND_TYPE_NAME_ONLY
= 13
371 STEP_FILTER_NONE
= 0,
372 STEP_FILTER_STATIC_CTOR
= 1,
373 STEP_FILTER_DEBUGGER_HIDDEN
= 2,
374 STEP_FILTER_DEBUGGER_STEP_THROUGH
= 4,
375 STEP_FILTER_DEBUGGER_NON_USER_CODE
= 8
379 TOKEN_TYPE_STRING
= 0,
381 TOKEN_TYPE_FIELD
= 2,
382 TOKEN_TYPE_METHOD
= 3,
383 TOKEN_TYPE_UNKNOWN
= 4
387 VALUE_TYPE_ID_NULL
= 0xf0,
388 VALUE_TYPE_ID_TYPE
= 0xf1,
389 VALUE_TYPE_ID_PARENT_VTYPE
= 0xf2
393 FRAME_FLAG_DEBUGGER_INVOKE
= 1,
394 FRAME_FLAG_NATIVE_TRANSITION
= 2
398 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
399 INVOKE_FLAG_SINGLE_THREADED
= 2
403 BINDING_FLAGS_IGNORE_CASE
= 0x70000000,
404 } BindingFlagsExtensions
;
408 CMD_VM_ALL_THREADS
= 2,
413 CMD_VM_INVOKE_METHOD
= 7,
414 CMD_VM_SET_PROTOCOL_VERSION
= 8,
415 CMD_VM_ABORT_INVOKE
= 9,
416 CMD_VM_SET_KEEPALIVE
= 10,
417 CMD_VM_GET_TYPES_FOR_SOURCE_FILE
= 11,
418 CMD_VM_GET_TYPES
= 12,
419 CMD_VM_INVOKE_METHODS
= 13,
420 CMD_VM_START_BUFFERING
= 14,
421 CMD_VM_STOP_BUFFERING
= 15
425 CMD_THREAD_GET_FRAME_INFO
= 1,
426 CMD_THREAD_GET_NAME
= 2,
427 CMD_THREAD_GET_STATE
= 3,
428 CMD_THREAD_GET_INFO
= 4,
429 CMD_THREAD_GET_ID
= 5,
430 CMD_THREAD_GET_TID
= 6,
431 CMD_THREAD_SET_IP
= 7
435 CMD_EVENT_REQUEST_SET
= 1,
436 CMD_EVENT_REQUEST_CLEAR
= 2,
437 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
445 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
446 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
447 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
448 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
449 CMD_APPDOMAIN_CREATE_STRING
= 5,
450 CMD_APPDOMAIN_GET_CORLIB
= 6,
451 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7
455 CMD_ASSEMBLY_GET_LOCATION
= 1,
456 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
457 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
458 CMD_ASSEMBLY_GET_OBJECT
= 4,
459 CMD_ASSEMBLY_GET_TYPE
= 5,
460 CMD_ASSEMBLY_GET_NAME
= 6
464 CMD_MODULE_GET_INFO
= 1,
468 CMD_FIELD_GET_INFO
= 1,
472 CMD_METHOD_GET_NAME
= 1,
473 CMD_METHOD_GET_DECLARING_TYPE
= 2,
474 CMD_METHOD_GET_DEBUG_INFO
= 3,
475 CMD_METHOD_GET_PARAM_INFO
= 4,
476 CMD_METHOD_GET_LOCALS_INFO
= 5,
477 CMD_METHOD_GET_INFO
= 6,
478 CMD_METHOD_GET_BODY
= 7,
479 CMD_METHOD_RESOLVE_TOKEN
= 8,
480 CMD_METHOD_GET_CATTRS
= 9,
481 CMD_METHOD_MAKE_GENERIC_METHOD
= 10
485 CMD_TYPE_GET_INFO
= 1,
486 CMD_TYPE_GET_METHODS
= 2,
487 CMD_TYPE_GET_FIELDS
= 3,
488 CMD_TYPE_GET_VALUES
= 4,
489 CMD_TYPE_GET_OBJECT
= 5,
490 CMD_TYPE_GET_SOURCE_FILES
= 6,
491 CMD_TYPE_SET_VALUES
= 7,
492 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
493 CMD_TYPE_GET_PROPERTIES
= 9,
494 CMD_TYPE_GET_CATTRS
= 10,
495 CMD_TYPE_GET_FIELD_CATTRS
= 11,
496 CMD_TYPE_GET_PROPERTY_CATTRS
= 12,
497 CMD_TYPE_GET_SOURCE_FILES_2
= 13,
498 CMD_TYPE_GET_VALUES_2
= 14,
499 CMD_TYPE_GET_METHODS_BY_NAME_FLAGS
= 15,
500 CMD_TYPE_GET_INTERFACES
= 16,
501 CMD_TYPE_GET_INTERFACE_MAP
= 17,
502 CMD_TYPE_IS_INITIALIZED
= 18,
503 CMD_TYPE_CREATE_INSTANCE
= 19
507 CMD_STACK_FRAME_GET_VALUES
= 1,
508 CMD_STACK_FRAME_GET_THIS
= 2,
509 CMD_STACK_FRAME_SET_VALUES
= 3
513 CMD_ARRAY_REF_GET_LENGTH
= 1,
514 CMD_ARRAY_REF_GET_VALUES
= 2,
515 CMD_ARRAY_REF_SET_VALUES
= 3,
519 CMD_STRING_REF_GET_VALUE
= 1,
520 CMD_STRING_REF_GET_LENGTH
= 2,
521 CMD_STRING_REF_GET_CHARS
= 3
525 CMD_OBJECT_REF_GET_TYPE
= 1,
526 CMD_OBJECT_REF_GET_VALUES
= 2,
527 CMD_OBJECT_REF_IS_COLLECTED
= 3,
528 CMD_OBJECT_REF_GET_ADDRESS
= 4,
529 CMD_OBJECT_REF_GET_DOMAIN
= 5,
530 CMD_OBJECT_REF_SET_VALUES
= 6,
531 CMD_OBJECT_REF_GET_INFO
= 7,
537 int count
; /* For kind == MOD_KIND_COUNT */
538 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
539 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
540 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
541 GHashTable
*source_files
; /* For kind == MONO_KIND_SOURCE_FILE_ONLY */
542 GHashTable
*type_names
; /* For kind == MONO_KIND_TYPE_NAME_ONLY */
543 StepFilter filter
; /* For kind == MOD_KIND_STEP */
545 gboolean caught
, uncaught
, subclasses
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
554 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
558 * Describes a single step request.
562 MonoInternalThread
*thread
;
568 MonoMethod
*last_method
;
570 /* Whenever single stepping is performed using start/stop_single_stepping () */
572 /* The list of breakpoints used to implement step-over */
574 /* The number of frames at the start of a step-over */
579 * Contains additional information for an event
582 /* For EVENT_KIND_EXCEPTION */
584 MonoContext catch_ctx
;
586 /* For EVENT_KIND_USER_LOG */
588 char *category
, *message
;
589 /* For EVENT_KIND_TYPE_LOAD */
593 /* Dummy structure used for the profiler callbacks */
599 guint8
*buf
, *p
, *end
;
602 typedef struct ReplyPacket
{
608 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
611 #define get_last_sock_error() WSAGetLastError()
612 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
613 #define MONO_EINTR WSAEINTR
615 #define get_last_sock_error() errno
616 #define MONO_EWOULDBLOCK EWOULDBLOCK
617 #define MONO_EINTR EINTR
620 #define CHECK_PROTOCOL_VERSION(major,minor) \
621 (protocol_version_set && (major_version > (major) || (major_version == (major) && minor_version >= (minor))))
627 static AgentConfig agent_config
;
630 * Whenever the agent is fully initialized.
631 * When using the onuncaught or onthrow options, only some parts of the agent are
632 * initialized on startup, and the full initialization which includes connection
633 * establishment and the startup of the agent thread is only done in response to
636 static gint32 inited
;
638 #ifndef DISABLE_SOCKET_TRANSPORT
640 static int listen_fd
;
643 static int packet_id
= 0;
645 static int objref_id
= 0;
647 static int event_request_id
= 0;
649 static int frame_id
= 0;
651 static GPtrArray
*event_requests
;
653 static MonoNativeTlsKey debugger_tls_id
;
655 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
657 /* Maps MonoInternalThread -> DebuggerTlsData */
658 static MonoGHashTable
*thread_to_tls
;
660 /* Maps tid -> MonoInternalThread */
661 static MonoGHashTable
*tid_to_thread
;
663 /* Maps tid -> MonoThread (not MonoInternalThread) */
664 static MonoGHashTable
*tid_to_thread_obj
;
666 static gsize debugger_thread_id
;
668 static HANDLE debugger_thread_handle
;
670 static int log_level
;
672 static gboolean embedding
;
674 static FILE *log_file
;
676 /* Assemblies whose assembly load event has no been sent yet */
677 static GPtrArray
*pending_assembly_loads
;
679 /* Whenever the debugger thread has exited */
680 static gboolean debugger_thread_exited
;
682 /* Cond variable used to wait for debugger_thread_exited becoming true */
683 static mono_cond_t debugger_thread_exited_cond
;
685 /* Mutex for the cond var above */
686 static mono_mutex_t debugger_thread_exited_mutex
;
688 static DebuggerProfiler debugger_profiler
;
690 /* The single step request instance */
691 static SingleStepReq
*ss_req
= NULL
;
692 static gpointer ss_invoke_addr
= NULL
;
694 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
695 /* Number of single stepping operations in progress */
699 /* The protocol version of the client */
700 static int major_version
, minor_version
;
702 /* Whenever the variables above are set by the client */
703 static gboolean protocol_version_set
;
705 /* A hash table containing all active domains */
706 static GHashTable
*domains
;
708 /* The number of times the runtime is suspended */
709 static gint32 suspend_count
;
711 /* Whenever to buffer reply messages and send them together */
712 static gboolean buffer_replies
;
714 /* Buffered reply packets */
715 static ReplyPacket reply_packets
[128];
718 static void transport_init (void);
719 static void transport_connect (const char *address
);
720 static gboolean
transport_handshake (void);
721 static void register_transport (DebuggerTransport
*trans
);
723 static guint32 WINAPI
debugger_thread (void *arg
);
725 static void runtime_initialized (MonoProfiler
*prof
);
727 static void runtime_shutdown (MonoProfiler
*prof
);
729 static void thread_startup (MonoProfiler
*prof
, uintptr_t tid
);
731 static void thread_end (MonoProfiler
*prof
, uintptr_t tid
);
733 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
735 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
737 static void emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
);
739 static void emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
);
741 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
743 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
745 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
747 static void emit_assembly_load (gpointer assembly
, gpointer user_data
);
749 static void emit_type_load (gpointer key
, gpointer type
, gpointer user_data
);
751 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
753 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
755 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
757 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
759 static void start_single_stepping (void);
761 static void stop_single_stepping (void);
763 static void suspend_current (void);
765 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
767 static void clear_types_for_assembly (MonoAssembly
*assembly
);
769 static void clear_breakpoints_for_domain (MonoDomain
*domain
);
771 static void process_profiler_event (EventKind event
, gpointer arg
);
773 /* Submodule init/cleanup */
774 static void breakpoints_init (void);
775 static void breakpoints_cleanup (void);
777 static void objrefs_init (void);
778 static void objrefs_cleanup (void);
780 static void ids_init (void);
781 static void ids_cleanup (void);
783 static void suspend_init (void);
785 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
);
786 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
787 static void ss_destroy (SingleStepReq
*req
);
789 static void start_debugger_thread (void);
790 static void stop_debugger_thread (void);
792 static void finish_agent_init (gboolean on_startup
);
794 static void process_profiler_event (EventKind event
, gpointer arg
);
796 static void invalidate_frames (DebuggerTlsData
*tls
);
798 #ifndef DISABLE_SOCKET_TRANSPORT
800 register_socket_transport (void);
804 parse_address (char *address
, char **host
, int *port
)
806 char *pos
= strchr (address
, ':');
808 if (pos
== NULL
|| pos
== address
)
811 *host
= g_malloc (pos
- address
+ 1);
812 strncpy (*host
, address
, pos
- address
);
813 (*host
) [pos
- address
] = '\0';
815 *port
= atoi (pos
+ 1);
823 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
824 fprintf (stderr
, "Available options:\n");
825 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
826 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
827 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
828 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
829 fprintf (stderr
, " suspend=y/n\t\t\tWhether to suspend after startup.\n");
830 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
831 fprintf (stderr
, " server=y/n\t\t\tWhether to listen for a client connection.\n");
832 fprintf (stderr
, " keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
833 fprintf (stderr
, " setpgid=y/n\t\t\tWhether to call setpid(0, 0) after startup.\n");
834 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
838 parse_flag (const char *option
, char *flag
)
840 if (!strcmp (flag
, "y"))
842 else if (!strcmp (flag
, "n"))
845 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
852 mono_debugger_agent_parse_options (char *options
)
859 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
860 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
864 extra
= g_getenv ("MONO_SDB_ENV_OPTIONS");
866 options
= g_strdup_printf ("%s,%s", options
, extra
);
868 agent_config
.enabled
= TRUE
;
869 agent_config
.suspend
= TRUE
;
870 agent_config
.server
= FALSE
;
871 agent_config
.defer
= FALSE
;
872 agent_config
.address
= NULL
;
874 //agent_config.log_level = 10;
876 args
= g_strsplit (options
, ",", -1);
877 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
880 if (strncmp (arg
, "transport=", 10) == 0) {
881 agent_config
.transport
= g_strdup (arg
+ 10);
882 } else if (strncmp (arg
, "address=", 8) == 0) {
883 agent_config
.address
= g_strdup (arg
+ 8);
884 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
885 agent_config
.log_level
= atoi (arg
+ 9);
886 } else if (strncmp (arg
, "logfile=", 8) == 0) {
887 agent_config
.log_file
= g_strdup (arg
+ 8);
888 } else if (strncmp (arg
, "suspend=", 8) == 0) {
889 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
890 } else if (strncmp (arg
, "server=", 7) == 0) {
891 agent_config
.server
= parse_flag ("server", arg
+ 7);
892 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
893 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
894 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
895 /* We support multiple onthrow= options */
896 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
897 } else if (strncmp (arg
, "onthrow", 7) == 0) {
898 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
899 } else if (strncmp (arg
, "help", 4) == 0) {
902 } else if (strncmp (arg
, "timeout=", 8) == 0) {
903 agent_config
.timeout
= atoi (arg
+ 8);
904 } else if (strncmp (arg
, "launch=", 7) == 0) {
905 agent_config
.launch
= g_strdup (arg
+ 7);
906 } else if (strncmp (arg
, "embedding=", 10) == 0) {
907 agent_config
.embedding
= atoi (arg
+ 10) == 1;
908 } else if (strncmp (arg
, "keepalive=", 10) == 0) {
909 agent_config
.keepalive
= atoi (arg
+ 10);
910 } else if (strncmp (arg
, "setpgid=", 8) == 0) {
911 agent_config
.setpgid
= parse_flag ("setpgid", arg
+ 8);
918 if (agent_config
.server
&& !agent_config
.suspend
) {
919 /* Waiting for deferred attachment */
920 agent_config
.defer
= TRUE
;
921 if (agent_config
.address
== NULL
) {
922 agent_config
.address
= g_strdup_printf ("0.0.0.0:%u", 56000 + (getpid () % 1000));
926 //agent_config.log_level = 0;
928 if (agent_config
.transport
== NULL
) {
929 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
933 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
934 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
939 if (!strcmp (agent_config
.transport
, "dt_socket")) {
940 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
941 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
948 mono_debugger_agent_init (void)
950 if (!agent_config
.enabled
)
955 /* Need to know whenever a thread has acquired the loader mutex */
956 mono_loader_lock_track_ownership (TRUE
);
958 event_requests
= g_ptr_array_new ();
960 mono_mutex_init (&debugger_thread_exited_mutex
);
961 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
963 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
964 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
965 mono_profiler_install_runtime_initialized (runtime_initialized
);
966 mono_profiler_install_appdomain (NULL
, appdomain_load
, NULL
, appdomain_unload
);
967 mono_profiler_install_thread (thread_startup
, thread_end
);
968 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
969 mono_profiler_install_jit_end (jit_end
);
970 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
972 mono_native_tls_alloc (&debugger_tls_id
, NULL
);
974 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
975 MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls
);
977 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
978 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread
);
980 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
981 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj
);
983 pending_assembly_loads
= g_ptr_array_new ();
984 domains
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
986 log_level
= agent_config
.log_level
;
988 embedding
= agent_config
.embedding
;
991 if (agent_config
.log_file
) {
992 log_file
= fopen (agent_config
.log_file
, "w+");
994 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
1003 breakpoints_init ();
1006 mini_get_debug_options ()->gen_seq_points
= TRUE
;
1008 * This is needed because currently we don't handle liveness info.
1010 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
1012 #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
1013 /* This is needed because we can't set local variables in registers yet */
1014 mono_disable_optimizations (MONO_OPT_LINEARS
);
1018 * The stack walk done from thread_interrupt () needs to be signal safe, but it
1019 * isn't, since it can call into mono_aot_find_jit_info () which is not signal
1020 * safe (#3411). So load AOT info eagerly when the debugger is running as a
1023 mini_get_debug_options ()->load_aot_jit_info_eagerly
= TRUE
;
1026 if (agent_config
.setpgid
)
1030 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
1031 finish_agent_init (TRUE
);
1035 * finish_agent_init:
1037 * Finish the initialization of the agent. This involves connecting the transport
1038 * and starting the agent thread. This is either done at startup, or
1039 * in response to some event like an unhandled exception.
1042 finish_agent_init (gboolean on_startup
)
1046 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
1049 if (agent_config
.launch
) {
1052 // FIXME: Generated address
1053 // FIXME: Races with transport_connect ()
1055 argv
[0] = agent_config
.launch
;
1056 argv
[1] = agent_config
.transport
;
1057 argv
[2] = agent_config
.address
;
1060 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1062 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
1067 transport_connect (agent_config
.address
);
1070 /* Do some which is usually done after sending the VMStart () event */
1071 vm_start_event_sent
= TRUE
;
1072 start_debugger_thread ();
1077 mono_debugger_agent_cleanup (void)
1082 stop_debugger_thread ();
1084 breakpoints_cleanup ();
1088 mono_mutex_destroy (&debugger_thread_exited_mutex
);
1089 mono_cond_destroy (&debugger_thread_exited_cond
);
1096 #ifndef DISABLE_SOCKET_TRANSPORT
1101 * recv() + handle incomplete reads and EINTR
1104 socket_transport_recv (void *buf
, int len
)
1110 static gint32 last_keepalive
;
1115 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
1118 if (agent_config
.keepalive
) {
1119 gboolean need_keepalive
= FALSE
;
1120 if (res
== -1 && get_last_sock_error () == MONO_EWOULDBLOCK
) {
1121 need_keepalive
= TRUE
;
1122 } else if (res
== -1) {
1123 /* This could happen if recv () is interrupted repeatedly */
1124 msecs
= mono_msec_ticks ();
1125 if (msecs
- last_keepalive
>= agent_config
.keepalive
) {
1126 need_keepalive
= TRUE
;
1127 last_keepalive
= msecs
;
1130 if (need_keepalive
) {
1131 process_profiler_event (EVENT_KIND_KEEPALIVE
, NULL
);
1135 } while ((res
> 0 && total
< len
) || (res
== -1 && get_last_sock_error () == MONO_EINTR
));
1140 #define HAVE_GETADDRINFO 1
1144 set_keepalive (void)
1149 if (!agent_config
.keepalive
|| !conn_fd
)
1152 tv
.tv_sec
= agent_config
.keepalive
/ 1000;
1153 tv
.tv_usec
= (agent_config
.keepalive
% 1000) * 1000;
1155 result
= setsockopt (conn_fd
, SOL_SOCKET
, SO_RCVTIMEO
, (char *) &tv
, sizeof(struct timeval
));
1156 g_assert (result
>= 0);
1160 socket_transport_accept (int socket_fd
)
1162 conn_fd
= accept (socket_fd
, NULL
, NULL
);
1163 if (conn_fd
== -1) {
1164 fprintf (stderr
, "debugger-agent: Unable to listen on %d\n", socket_fd
);
1166 DEBUG (1, fprintf (log_file
, "Accepted connection from client, connection fd=%d.\n", conn_fd
));
1173 socket_transport_send (void *data
, int len
)
1178 res
= send (conn_fd
, data
, len
, 0);
1179 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1187 * socket_transport_connect:
1189 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
1192 socket_transport_connect (const char *address
)
1194 #ifdef HAVE_GETADDRINFO
1195 struct addrinfo hints
;
1196 struct addrinfo
*result
, *rp
;
1198 struct hostent
*result
;
1200 int sfd
= -1, s
, res
;
1201 char port_string
[128];
1205 if (agent_config
.address
) {
1206 res
= parse_address (agent_config
.address
, &host
, &port
);
1207 g_assert (res
== 0);
1217 sprintf (port_string
, "%d", port
);
1219 mono_network_init ();
1221 /* Obtain address(es) matching host/port */
1222 #ifdef HAVE_GETADDRINFO
1223 memset (&hints
, 0, sizeof (struct addrinfo
));
1224 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
1225 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
1227 hints
.ai_protocol
= 0; /* Any protocol */
1229 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
1231 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %s\n", host
, port
, gai_strerror (s
));
1235 /* The PS3 doesn't even have _r or hstrerror () */
1236 result
= gethostbyname (host
);
1238 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %d\n", host
, port
, h_errno
);
1243 if (agent_config
.server
) {
1244 #ifdef HAVE_GETADDRINFO
1245 /* Wait for a connection */
1247 struct sockaddr_in addr
;
1250 /* No address, generate one */
1251 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
1254 /* This will bind the socket to a random port */
1255 res
= listen (sfd
, 16);
1257 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
1262 addrlen
= sizeof (addr
);
1263 memset (&addr
, 0, sizeof (addr
));
1264 res
= getsockname (sfd
, (struct sockaddr
*)&addr
, &addrlen
);
1265 g_assert (res
== 0);
1267 host
= (char*)"127.0.0.1";
1268 port
= ntohs (addr
.sin_port
);
1270 /* Emit the address to stdout */
1271 /* FIXME: Should print another interface, not localhost */
1272 printf ("%s:%d\n", host
, port
);
1274 /* Listen on the provided address */
1275 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1278 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1283 if (setsockopt (sfd
, SOL_SOCKET
, SO_REUSEADDR
, &n
, sizeof(n
)) == -1)
1286 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1290 res
= listen (sfd
, 16);
1299 * this function is not present on win2000 which we still support, and the
1300 * workaround described here:
1301 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1302 * only works with MSVC.
1304 #ifdef HAVE_GETADDRINFO
1305 freeaddrinfo (result
);
1310 if (agent_config
.defer
)
1313 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1315 if (agent_config
.timeout
) {
1320 tv
.tv_usec
= agent_config
.timeout
* 1000;
1322 FD_SET (sfd
, &readfds
);
1323 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1325 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1330 conn_fd
= socket_transport_accept (sfd
);
1334 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1337 #endif /* HAVE_GETADDRINFO */
1339 /* Connect to the specified address */
1340 #ifdef HAVE_GETADDRINFO
1341 /* FIXME: Respect the timeout */
1342 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1343 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1348 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1349 break; /* Success */
1355 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1359 sfd
= socket (result
->h_addrtype
, SOCK_STREAM
, 0);
1361 g_assert_not_reached ();
1362 res
= connect (sfd
, (void*)result
->h_addr_list
[0], result
->h_length
);
1364 g_assert_not_reached ();
1370 /* See the comment above */
1371 #ifdef HAVE_GETADDRINFO
1372 freeaddrinfo (result
);
1377 if (!transport_handshake ())
1382 socket_transport_close1 (void)
1384 /* This will interrupt the agent thread */
1385 /* Close the read part only so it can still send back replies */
1386 /* Also shut down the connection listener so that we can exit normally */
1388 /* SD_RECEIVE doesn't break the recv in the debugger thread */
1389 shutdown (conn_fd
, SD_BOTH
);
1390 shutdown (listen_fd
, SD_BOTH
);
1391 closesocket (listen_fd
);
1393 shutdown (conn_fd
, SHUT_RD
);
1394 shutdown (listen_fd
, SHUT_RDWR
);
1400 socket_transport_close2 (void)
1403 shutdown (conn_fd
, SD_BOTH
);
1405 shutdown (conn_fd
, SHUT_RDWR
);
1410 register_socket_transport (void)
1412 DebuggerTransport trans
;
1414 trans
.name
= "dt_socket";
1415 trans
.connect
= socket_transport_connect
;
1416 trans
.close1
= socket_transport_close1
;
1417 trans
.close2
= socket_transport_close2
;
1418 trans
.send
= socket_transport_send
;
1419 trans
.recv
= socket_transport_recv
;
1421 register_transport (&trans
);
1424 #endif /* DISABLE_SOCKET_TRANSPORT */
1430 #define MAX_TRANSPORTS 16
1432 static DebuggerTransport
*transport
;
1434 static DebuggerTransport transports
[MAX_TRANSPORTS
];
1435 static int ntransports
;
1438 mono_debugger_agent_register_transport (DebuggerTransport
*trans
);
1441 mono_debugger_agent_register_transport (DebuggerTransport
*trans
)
1443 register_transport (trans
);
1447 register_transport (DebuggerTransport
*trans
)
1449 g_assert (ntransports
< MAX_TRANSPORTS
);
1451 memcpy (&transports
[ntransports
], trans
, sizeof (DebuggerTransport
));
1456 transport_init (void)
1460 #ifndef DISABLE_SOCKET_TRANSPORT
1461 register_socket_transport ();
1464 for (i
= 0; i
< ntransports
; ++i
) {
1465 if (!strcmp (agent_config
.transport
, transports
[i
].name
))
1468 if (i
== ntransports
) {
1469 fprintf (stderr
, "debugger-agent: The supported values for the 'transport' option are: ");
1470 for (i
= 0; i
< ntransports
; ++i
)
1471 fprintf (stderr
, "%s'%s'", i
> 0 ? ", " : "", transports
[i
].name
);
1472 fprintf (stderr
, "\n");
1475 transport
= &transports
[i
];
1479 transport_connect (const char *address
)
1481 transport
->connect (address
);
1485 transport_close1 (void)
1487 transport
->close1 ();
1491 transport_close2 (void)
1493 transport
->close2 ();
1497 transport_send (void *buf
, int len
)
1499 return transport
->send (buf
, len
);
1503 transport_recv (void *buf
, int len
)
1505 return transport
->recv (buf
, len
);
1509 mono_debugger_agent_transport_handshake (void)
1511 return transport_handshake ();
1515 transport_handshake (void)
1517 char handshake_msg
[128];
1521 disconnected
= TRUE
;
1523 /* Write handshake message */
1524 sprintf (handshake_msg
, "DWP-Handshake");
1526 res
= transport_send (handshake_msg
, strlen (handshake_msg
));
1527 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1528 g_assert (res
!= -1);
1531 res
= transport_recv (buf
, strlen (handshake_msg
));
1532 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1533 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1538 * To support older clients, the client sends its protocol version after connecting
1539 * using a command. Until that is received, default to our protocol version.
1541 major_version
= MAJOR_VERSION
;
1542 minor_version
= MINOR_VERSION
;
1543 protocol_version_set
= FALSE
;
1545 #ifndef DISABLE_SOCKET_TRANSPORT
1546 // FIXME: Move this somewhere else
1548 * Set TCP_NODELAY on the socket so the client receives events/command
1549 * results immediately.
1553 int result
= setsockopt (conn_fd
,
1558 g_assert (result
>= 0);
1564 disconnected
= FALSE
;
1569 stop_debugger_thread (void)
1574 transport_close1 ();
1577 * Wait for the thread to exit.
1579 * If we continue with the shutdown without waiting for it, then the client might
1580 * not receive an answer to its last command like a resume.
1581 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
1584 //WaitForSingleObject (debugger_thread_handle, INFINITE);
1585 if (GetCurrentThreadId () != debugger_thread_id
) {
1587 mono_mutex_lock (&debugger_thread_exited_mutex
);
1588 if (!debugger_thread_exited
) {
1590 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
1591 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1593 mono_mutex_lock (&debugger_thread_exited_mutex
);
1596 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
1599 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1600 } while (!debugger_thread_exited
);
1603 transport_close2 ();
1607 start_debugger_thread (void)
1609 debugger_thread_handle
= mono_threads_create_thread (debugger_thread
, NULL
, 0, 0, NULL
);
1610 g_assert (debugger_thread_handle
);
1614 * Functions to decode protocol data
1618 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1621 g_assert (*endbuf
<= limit
);
1626 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1629 g_assert (*endbuf
<= limit
);
1631 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1634 static inline gint64
1635 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1637 guint32 high
= decode_int (buf
, &buf
, limit
);
1638 guint32 low
= decode_int (buf
, &buf
, limit
);
1642 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1646 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1648 return decode_int (buf
, endbuf
, limit
);
1652 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1654 int len
= decode_int (buf
, &buf
, limit
);
1662 s
= g_malloc (len
+ 1);
1665 memcpy (s
, buf
, len
);
1674 * Functions to encode protocol data
1678 buffer_init (Buffer
*buf
, int size
)
1680 buf
->buf
= g_malloc (size
);
1682 buf
->end
= buf
->buf
+ size
;
1686 buffer_len (Buffer
*buf
)
1688 return buf
->p
- buf
->buf
;
1692 buffer_make_room (Buffer
*buf
, int size
)
1694 if (buf
->end
- buf
->p
< size
) {
1695 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1696 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1697 size
= buf
->p
- buf
->buf
;
1700 buf
->end
= buf
->buf
+ new_size
;
1705 buffer_add_byte (Buffer
*buf
, guint8 val
)
1707 buffer_make_room (buf
, 1);
1713 buffer_add_short (Buffer
*buf
, guint32 val
)
1715 buffer_make_room (buf
, 2);
1716 buf
->p
[0] = (val
>> 8) & 0xff;
1717 buf
->p
[1] = (val
>> 0) & 0xff;
1722 buffer_add_int (Buffer
*buf
, guint32 val
)
1724 buffer_make_room (buf
, 4);
1725 buf
->p
[0] = (val
>> 24) & 0xff;
1726 buf
->p
[1] = (val
>> 16) & 0xff;
1727 buf
->p
[2] = (val
>> 8) & 0xff;
1728 buf
->p
[3] = (val
>> 0) & 0xff;
1733 buffer_add_long (Buffer
*buf
, guint64 l
)
1735 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1736 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1740 buffer_add_id (Buffer
*buf
, int id
)
1742 buffer_add_int (buf
, (guint64
)id
);
1746 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1748 buffer_make_room (buf
, len
);
1749 memcpy (buf
->p
, data
, len
);
1754 buffer_add_string (Buffer
*buf
, const char *str
)
1759 buffer_add_int (buf
, 0);
1762 buffer_add_int (buf
, len
);
1763 buffer_add_data (buf
, (guint8
*)str
, len
);
1768 buffer_add_buffer (Buffer
*buf
, Buffer
*data
)
1770 buffer_add_data (buf
, data
->buf
, buffer_len (data
));
1774 buffer_free (Buffer
*buf
)
1780 send_packet (int command_set
, int command
, Buffer
*data
)
1786 id
= InterlockedIncrement (&packet_id
);
1788 len
= data
->p
- data
->buf
+ 11;
1789 buffer_init (&buf
, len
);
1790 buffer_add_int (&buf
, len
);
1791 buffer_add_int (&buf
, id
);
1792 buffer_add_byte (&buf
, 0); /* flags */
1793 buffer_add_byte (&buf
, command_set
);
1794 buffer_add_byte (&buf
, command
);
1795 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1797 res
= transport_send (buf
.buf
, len
);
1805 send_reply_packets (int npackets
, ReplyPacket
*packets
)
1812 for (i
= 0; i
< npackets
; ++i
)
1813 len
+= buffer_len (packets
[i
].data
) + 11;
1814 buffer_init (&buf
, len
);
1815 for (i
= 0; i
< npackets
; ++i
) {
1816 buffer_add_int (&buf
, buffer_len (packets
[i
].data
) + 11);
1817 buffer_add_int (&buf
, packets
[i
].id
);
1818 buffer_add_byte (&buf
, 0x80); /* flags */
1819 buffer_add_byte (&buf
, (packets
[i
].error
>> 8) & 0xff);
1820 buffer_add_byte (&buf
, packets
[i
].error
);
1821 buffer_add_buffer (&buf
, packets
[i
].data
);
1823 res
= transport_send (buf
.buf
, len
);
1831 send_reply_packet (int id
, int error
, Buffer
*data
)
1835 memset (&packet
, 0, sizeof (ReplyPacket
));
1837 packet
.error
= error
;
1840 return send_reply_packets (1, &packet
);
1844 send_buffered_reply_packets (void)
1848 send_reply_packets (nreply_packets
, reply_packets
);
1849 for (i
= 0; i
< nreply_packets
; ++i
)
1850 buffer_free (reply_packets
[i
].data
);
1851 DEBUG (1, fprintf (log_file
, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets
, (long)mono_100ns_ticks () / 10000));
1856 buffer_reply_packet (int id
, int error
, Buffer
*data
)
1860 if (nreply_packets
== 128)
1861 send_buffered_reply_packets ();
1863 p
= &reply_packets
[nreply_packets
];
1866 p
->data
= g_new0 (Buffer
, 1);
1867 buffer_init (p
->data
, buffer_len (data
));
1868 buffer_add_buffer (p
->data
, data
);
1877 * Represents an object accessible by the debugger client.
1880 /* Unique id used in the wire protocol to refer to objects */
1883 * A weakref gc handle pointing to the object. The gc handle is used to
1884 * detect if the object was garbage collected.
1889 /* Maps objid -> ObjRef */
1890 static GHashTable
*objrefs
;
1893 free_objref (gpointer value
)
1897 mono_gchandle_free (o
->handle
);
1905 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1909 objrefs_cleanup (void)
1911 g_hash_table_destroy (objrefs
);
1915 static GHashTable
*obj_to_objref
;
1916 static MonoGHashTable
*suspended_objs
;
1919 * Return an ObjRef for OBJ.
1922 get_objref (MonoObject
*obj
)
1925 GSList
*reflist
= NULL
, *l
;
1931 mono_loader_lock ();
1933 if (!obj_to_objref
) {
1934 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1935 suspended_objs
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
1936 MONO_GC_REGISTER_ROOT_FIXED (suspended_objs
);
1939 if (suspend_count
) {
1941 * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
1943 mono_g_hash_table_insert (suspended_objs
, obj
, NULL
);
1946 /* FIXME: The tables can grow indefinitely */
1948 if (mono_gc_is_moving ()) {
1950 * Objects can move, so use a hash table mapping hash codes to lists of
1951 * ObjRef structures.
1953 hash
= mono_object_hash (obj
);
1955 reflist
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (hash
));
1956 for (l
= reflist
; l
; l
= l
->next
) {
1958 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1959 mono_loader_unlock ();
1964 /* Use a hash table with masked pointers to internalize object references */
1965 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1966 /* ref might refer to a different object with the same addr which was GCd */
1967 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1968 mono_loader_unlock ();
1973 ref
= g_new0 (ObjRef
, 1);
1974 ref
->id
= InterlockedIncrement (&objref_id
);
1975 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1977 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1979 if (mono_gc_is_moving ()) {
1980 reflist
= g_slist_append (reflist
, ref
);
1981 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (hash
), reflist
);
1983 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1986 mono_loader_unlock ();
1992 true_pred (gpointer key
, gpointer value
, gpointer user_data
)
1998 clear_suspended_objs (void)
2000 mono_loader_lock ();
2001 mono_g_hash_table_foreach_remove (suspended_objs
, true_pred
, NULL
);
2002 mono_loader_unlock ();
2006 get_objid (MonoObject
*obj
)
2008 return get_objref (obj
)->id
;
2012 * Set OBJ to the object identified by OBJID.
2013 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
2017 get_object_allow_null (int objid
, MonoObject
**obj
)
2027 return ERR_INVALID_OBJECT
;
2029 mono_loader_lock ();
2031 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
2034 *obj
= mono_gchandle_get_target (ref
->handle
);
2035 mono_loader_unlock ();
2037 return ERR_INVALID_OBJECT
;
2040 mono_loader_unlock ();
2041 return ERR_INVALID_OBJECT
;
2046 get_object (int objid
, MonoObject
**obj
)
2048 int err
= get_object_allow_null (objid
, obj
);
2053 return ERR_INVALID_OBJECT
;
2058 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
2060 return decode_id (buf
, endbuf
, limit
);
2064 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
2066 buffer_add_id (buf
, get_objid (o
));
2085 * Represents a runtime structure accessible to the debugger client
2088 /* Unique id used in the wire protocol */
2090 /* Domain of the runtime structure, NULL if the domain was unloaded */
2097 MonoAssembly
*assembly
;
2098 MonoClassField
*field
;
2100 MonoProperty
*property
;
2105 /* Maps runtime structure -> Id */
2106 GHashTable
*val_to_id
[ID_NUM
];
2107 /* Classes whose class load event has been sent */
2108 GHashTable
*loaded_classes
;
2109 /* Maps MonoClass->GPtrArray of file names */
2110 GHashTable
*source_files
;
2111 /* Maps source file basename -> GSList of classes */
2112 GHashTable
*source_file_to_class
;
2113 /* Same with ignore-case */
2114 GHashTable
*source_file_to_class_ignorecase
;
2118 static GPtrArray
*ids
[ID_NUM
];
2125 for (i
= 0; i
< ID_NUM
; ++i
)
2126 ids
[i
] = g_ptr_array_new ();
2134 for (i
= 0; i
< ID_NUM
; ++i
) {
2136 for (j
= 0; j
< ids
[i
]->len
; ++j
)
2137 g_free (g_ptr_array_index (ids
[i
], j
));
2138 g_ptr_array_free (ids
[i
], TRUE
);
2145 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
2147 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
2149 GHashTableIter iter
;
2150 GPtrArray
*file_names
;
2155 for (i
= 0; i
< ID_NUM
; ++i
)
2156 if (info
->val_to_id
[i
])
2157 g_hash_table_destroy (info
->val_to_id
[i
]);
2158 g_hash_table_destroy (info
->loaded_classes
);
2160 g_hash_table_iter_init (&iter
, info
->source_files
);
2161 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&file_names
)) {
2162 for (i
= 0; i
< file_names
->len
; ++i
)
2163 g_free (g_ptr_array_index (file_names
, i
));
2164 g_ptr_array_free (file_names
, TRUE
);
2167 g_hash_table_iter_init (&iter
, info
->source_file_to_class
);
2168 while (g_hash_table_iter_next (&iter
, (void**)&basename
, (void**)&l
)) {
2173 g_hash_table_iter_init (&iter
, info
->source_file_to_class_ignorecase
);
2174 while (g_hash_table_iter_next (&iter
, (void**)&basename
, (void**)&l
)) {
2182 domain_jit_info (domain
)->agent_info
= NULL
;
2184 /* Clear ids referencing structures in the domain */
2185 for (i
= 0; i
< ID_NUM
; ++i
) {
2187 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
2188 Id
*id
= g_ptr_array_index (ids
[i
], j
);
2189 if (id
->domain
== domain
)
2195 mono_loader_lock ();
2196 g_hash_table_remove (domains
, domain
);
2197 mono_loader_unlock ();
2200 static AgentDomainInfo
*
2201 get_agent_domain_info (MonoDomain
*domain
)
2203 AgentDomainInfo
*info
= NULL
;
2205 mono_domain_lock (domain
);
2207 info
= domain_jit_info (domain
)->agent_info
;
2209 info
= domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
2210 info
->loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2211 info
->source_files
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2212 info
->source_file_to_class
= g_hash_table_new (g_str_hash
, g_str_equal
);
2213 info
->source_file_to_class_ignorecase
= g_hash_table_new (g_str_hash
, g_str_equal
);
2216 mono_domain_unlock (domain
);
2222 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
2225 AgentDomainInfo
*info
;
2230 mono_loader_lock ();
2232 mono_domain_lock (domain
);
2234 info
= get_agent_domain_info (domain
);
2236 if (info
->val_to_id
[type
] == NULL
)
2237 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2239 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
2241 mono_domain_unlock (domain
);
2242 mono_loader_unlock ();
2246 id
= g_new0 (Id
, 1);
2248 id
->id
= ids
[type
]->len
+ 1;
2249 id
->domain
= domain
;
2252 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
2254 mono_domain_unlock (domain
);
2256 g_ptr_array_add (ids
[type
], id
);
2258 mono_loader_unlock ();
2263 static inline gpointer
2264 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
2268 int id
= decode_id (buf
, endbuf
, limit
);
2277 // FIXME: error handling
2278 mono_loader_lock ();
2279 g_assert (id
> 0 && id
<= ids
[type
]->len
);
2281 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
2282 mono_loader_unlock ();
2284 if (res
->domain
== NULL
) {
2285 DEBUG (0, fprintf (log_file
, "ERR_UNLOADED, id=%d, type=%d.\n", id
, type
));
2286 *err
= ERR_UNLOADED
;
2291 *domain
= res
->domain
;
2293 return res
->data
.val
;
2297 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
2299 buffer_add_id (buf
, get_id (domain
, type
, val
));
2302 static inline MonoClass
*
2303 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2307 klass
= decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
2308 if (G_UNLIKELY (log_level
>= 2) && klass
) {
2311 s
= mono_type_full_name (&klass
->byval_arg
);
2312 DEBUG(2, fprintf (log_file
, "[dbg] recv class [%s]\n", s
));
2318 static inline MonoAssembly
*
2319 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2321 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
2324 static inline MonoImage
*
2325 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2327 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
2330 static inline MonoMethod
*
2331 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2335 m
= decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
2336 if (G_UNLIKELY (log_level
>= 2) && m
) {
2339 s
= mono_method_full_name (m
, TRUE
);
2340 DEBUG(2, fprintf (log_file
, "[dbg] recv method [%s]\n", s
));
2346 static inline MonoClassField
*
2347 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2349 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
2352 static inline MonoDomain
*
2353 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2355 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
2358 static inline MonoProperty
*
2359 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2361 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
2365 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
2367 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
2368 if (G_UNLIKELY (log_level
>= 2) && klass
) {
2371 s
= mono_type_full_name (&klass
->byval_arg
);
2372 if (GetCurrentThreadId () == debugger_thread_id
)
2373 DEBUG(2, fprintf (log_file
, "[dbg] send class [%s]\n", s
));
2375 DEBUG(2, fprintf (log_file
, "[%p] send class [%s]\n", (gpointer
)GetCurrentThreadId (), s
));
2381 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
2383 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
2384 if (G_UNLIKELY (log_level
>= 2) && method
) {
2387 s
= mono_method_full_name (method
, 1);
2388 DEBUG(2, fprintf (log_file
, "[dbg] send method [%s]\n", s
));
2394 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
2396 buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
2400 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
2402 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
2406 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
2408 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
2412 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
2414 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
2418 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
2420 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
2423 static void invoke_method (void);
2430 * save_thread_context:
2432 * Set CTX as the current threads context which is used for computing stack traces.
2433 * This function is signal-safe.
2436 save_thread_context (MonoContext
*ctx
)
2438 DebuggerTlsData
*tls
;
2440 tls
= mono_native_tls_get_value (debugger_tls_id
);
2444 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
2446 mono_thread_state_init_from_current (&tls
->context
);
2449 /* Number of threads suspended */
2451 * If this is equal to the size of thread_to_tls, the runtime is considered
2454 static gint32 threads_suspend_count
;
2456 static mono_mutex_t suspend_mutex
;
2458 /* Cond variable used to wait for suspend_count becoming 0 */
2459 static mono_cond_t suspend_cond
;
2461 /* Semaphore used to wait for a thread becoming suspended */
2462 static MonoSemType suspend_sem
;
2467 mono_mutex_init (&suspend_mutex
);
2468 mono_cond_init (&suspend_cond
, NULL
);
2469 MONO_SEM_INIT (&suspend_sem
, 0);
2474 StackFrameInfo last_frame
;
2475 gboolean last_frame_set
;
2478 } GetLastFrameUserData
;
2481 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2483 GetLastFrameUserData
*data
= user_data
;
2485 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
2488 if (!data
->last_frame_set
) {
2489 /* Store the last frame */
2490 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
2491 data
->last_frame_set
= TRUE
;
2494 /* Store the context/lmf for the frame above the last frame */
2495 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
2496 data
->lmf
= info
->lmf
;
2504 * Process interruption of a thread. If SIGCTX is set, process the current thread. If
2505 * INFO is set, process the thread described by INFO.
2506 * This should be signal safe.
2509 thread_interrupt (DebuggerTlsData
*tls
, MonoThreadInfo
*info
, void *sigctx
, MonoJitInfo
*ji
)
2513 MonoNativeThreadId tid
;
2516 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2517 * guarantee the signal handler will be called that many times. Instead of tracking
2518 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2519 * has been requested that hasn't been handled yet, otherwise we can have threads
2520 * refuse to die when VM_EXIT is called
2522 #if defined(__APPLE__)
2523 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
2527 * We use interrupt_count to determine whenever this interrupt should be processed
2528 * by us or the normal interrupt processing code in the signal handler.
2529 * There is no race here with notify_thread (), since the signal is sent after
2530 * incrementing interrupt_count.
2532 if (tls
->interrupt_count
== 0)
2535 InterlockedDecrement (&tls
->interrupt_count
);
2539 ip
= mono_arch_ip_from_context (sigctx
);
2541 ip
= MONO_CONTEXT_GET_IP (&info
->suspend_state
.ctx
);
2546 tid
= mono_thread_info_get_tid (info
);
2548 tid
= (MonoNativeThreadId
)GetCurrentThreadId ();
2550 // FIXME: Races when the thread leaves managed code before hitting a single step
2554 /* Running managed code, will be suspended by the single step code */
2555 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)(gsize
)tid
, jinfo_get_method (ji
)->name
, ip
));
2559 * Running native code, will be suspended when it returns to/enters
2560 * managed code. Treat it as already suspended.
2561 * This might interrupt the code in process_single_step_inner (), we use the
2562 * tls->suspending flag to avoid races when that happens.
2564 if (!tls
->suspended
&& !tls
->suspending
) {
2566 GetLastFrameUserData data
;
2568 // FIXME: printf is not signal safe, but this is only used during
2569 // debugger debugging
2571 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)(gsize
)tid
, ip
));
2572 //save_thread_context (&ctx);
2575 /* Already terminated */
2579 * We are in a difficult position: we want to be able to provide stack
2580 * traces for this thread, but we can't use the current ctx+lmf, since
2581 * the thread is still running, so it might return to managed code,
2582 * making these invalid.
2583 * So we start a stack walk and save the first frame, along with the
2584 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
2585 * suspended when it returns to managed code, so the parent's ctx should
2588 data
.last_frame_set
= FALSE
;
2590 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
2592 * Don't pass MONO_UNWIND_ACTUAL_METHOD, its not signal safe, and
2593 * get_last_frame () doesn't need it, the last frame cannot be a ginst
2594 * since we are not in a JITted method.
2596 mono_walk_stack_with_ctx (get_last_frame
, &ctx
, MONO_UNWIND_NONE
, &data
);
2598 mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame
, &info
->suspend_state
, MONO_UNWIND_SIGNAL_SAFE
, &data
);
2600 if (data
.last_frame_set
) {
2601 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
2602 res
= mono_thread_state_init_from_monoctx (&tls
->async_state
, &ctx
);
2604 mono_thread_state_init_from_monoctx (&tls
->context
, &ctx
);
2607 memcpy (&tls
->async_state
.ctx
, &data
.ctx
, sizeof (MonoContext
));
2608 tls
->async_state
.unwind_data
[MONO_UNWIND_DATA_LMF
] = data
.lmf
;
2609 tls
->async_state
.unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = tls
->thread
->jit_data
;
2611 tls
->async_state
.valid
= FALSE
;
2614 mono_memory_barrier ();
2616 tls
->suspended
= TRUE
;
2617 MONO_SEM_POST (&suspend_sem
);
2624 * mono_debugger_agent_thread_interrupt:
2626 * Called by the abort signal handler.
2627 * Should be signal safe.
2630 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
2632 DebuggerTlsData
*tls
;
2637 tls
= mono_native_tls_get_value (debugger_tls_id
);
2639 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer
)GetCurrentThreadId ()));
2643 return thread_interrupt (tls
, NULL
, sigctx
, ji
);
2647 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
2650 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
2652 #endif /* HOST_WIN32 */
2655 * reset_native_thread_suspend_state:
2657 * Reset the suspended flag and state on native threads
2660 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
2662 DebuggerTlsData
*tls
= value
;
2664 if (!tls
->really_suspended
&& tls
->suspended
) {
2665 tls
->suspended
= FALSE
;
2667 * The thread might still be running if it was executing native code, so the state won't be invalided by
2668 * suspend_current ().
2670 tls
->context
.valid
= FALSE
;
2671 tls
->async_state
.valid
= FALSE
;
2672 invalidate_frames (tls
);
2679 * Notify a thread that it needs to suspend.
2682 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
2684 MonoInternalThread
*thread
= key
;
2685 DebuggerTlsData
*tls
= value
;
2686 gsize tid
= thread
->tid
;
2689 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
2692 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2695 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2696 * guarantee the signal handler will be called that many times. Instead of tracking
2697 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2698 * has been requested that hasn't been handled yet, otherwise we can have threads
2699 * refuse to die when VM_EXIT is called
2701 #if defined(__APPLE__)
2702 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
2706 * Maybe we could use the normal interrupt infrastructure, but that does a lot
2707 * of things like breaking waits etc. which we don't want.
2709 InterlockedIncrement (&tls
->interrupt_count
);
2712 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
2714 QueueUserAPC (notify_thread_apc
, thread
->handle
, NULL
);
2716 if (mono_thread_info_new_interrupt_enabled ()) {
2717 MonoThreadInfo
*info
;
2720 info
= mono_thread_info_safe_suspend_sync ((MonoNativeThreadId
)(gpointer
)(gsize
)thread
->tid
, FALSE
);
2722 DEBUG(1, fprintf (log_file
, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2724 * Attached thread which died without detaching.
2726 tls
->terminated
= TRUE
;
2728 ji
= mono_jit_info_table_find (info
->suspend_state
.unwind_data
[MONO_UNWIND_DATA_DOMAIN
], MONO_CONTEXT_GET_IP (&info
->suspend_state
.ctx
));
2730 thread_interrupt (tls
, info
, NULL
, ji
);
2732 mono_thread_info_finish_suspend_and_resume (info
);
2735 res
= mono_thread_kill (thread
, mono_thread_get_abort_signal ());
2737 DEBUG(1, fprintf (log_file
, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
, res
));
2739 * Attached thread which died without detaching.
2741 tls
->terminated
= TRUE
;
2748 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2750 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2754 if (mono_loader_lock_is_owned_by_self ()) {
2756 * Shortcut for the check in suspend_current (). This speeds up processing
2757 * when executing long running code inside the loader lock, i.e. assembly load
2763 if (debugger_thread_id
== GetCurrentThreadId ())
2766 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2767 if (suspend_count
- tls
->resume_count
> 0)
2768 tls
->suspending
= TRUE
;
2770 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2772 if (suspend_count
- tls
->resume_count
== 0) {
2774 * We are executing a single threaded invoke but the single step for
2775 * suspending is still active.
2776 * FIXME: This slows down single threaded invokes.
2778 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2782 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2784 /* Can't suspend in these methods */
2785 method
= jinfo_get_method (ji
);
2786 if (method
->klass
== mono_defaults
.string_class
&& (!strcmp (method
->name
, "memset") || strstr (method
->name
, "memcpy")))
2789 save_thread_context (ctx
);
2797 * Increase the suspend count of the VM. While the suspend count is greater
2798 * than 0, runtime threads are suspended at certain points during execution.
2803 mono_loader_lock ();
2805 mono_mutex_lock (&suspend_mutex
);
2809 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2811 if (suspend_count
== 1) {
2812 // FIXME: Is it safe to call this inside the lock ?
2813 start_single_stepping ();
2814 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2817 mono_mutex_unlock (&suspend_mutex
);
2819 if (suspend_count
== 1)
2821 * Suspend creation of new threadpool threads, since they cannot run
2823 mono_thread_pool_suspend ();
2825 mono_loader_unlock ();
2831 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2839 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2841 mono_loader_lock ();
2843 mono_mutex_lock (&suspend_mutex
);
2845 g_assert (suspend_count
> 0);
2848 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm, suspend count=%d...\n", (gpointer
)GetCurrentThreadId (), suspend_count
));
2850 if (suspend_count
== 0) {
2851 // FIXME: Is it safe to call this inside the lock ?
2852 stop_single_stepping ();
2853 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2856 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2857 err
= mono_cond_broadcast (&suspend_cond
);
2858 g_assert (err
== 0);
2860 mono_mutex_unlock (&suspend_mutex
);
2861 //g_assert (err == 0);
2863 if (suspend_count
== 0)
2864 mono_thread_pool_resume ();
2866 mono_loader_unlock ();
2872 * Resume just one thread.
2875 resume_thread (MonoInternalThread
*thread
)
2878 DebuggerTlsData
*tls
;
2880 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2882 mono_loader_lock ();
2884 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2887 mono_mutex_lock (&suspend_mutex
);
2889 g_assert (suspend_count
> 0);
2891 DEBUG(1, fprintf (log_file
, "[sdb] Resuming thread %p...\n", (gpointer
)(gssize
)thread
->tid
));
2893 tls
->resume_count
+= suspend_count
;
2896 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2897 * but only the one whose resume_count field is > 0 will be resumed.
2899 err
= mono_cond_broadcast (&suspend_cond
);
2900 g_assert (err
== 0);
2902 mono_mutex_unlock (&suspend_mutex
);
2903 //g_assert (err == 0);
2905 mono_loader_unlock ();
2909 invalidate_frames (DebuggerTlsData
*tls
)
2914 tls
= mono_native_tls_get_value (debugger_tls_id
);
2917 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2918 if (tls
->frames
[i
]->jit
)
2919 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2920 g_free (tls
->frames
[i
]);
2922 g_free (tls
->frames
);
2923 tls
->frame_count
= 0;
2930 * Suspend the current thread until the runtime is resumed. If the thread has a
2931 * pending invoke, then the invoke is executed before this function returns.
2934 suspend_current (void)
2937 DebuggerTlsData
*tls
;
2939 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2941 if (mono_loader_lock_is_owned_by_self ()) {
2943 * If we own the loader mutex, can't suspend until we release it, since the
2944 * whole runtime can deadlock otherwise.
2949 tls
= mono_native_tls_get_value (debugger_tls_id
);
2952 mono_mutex_lock (&suspend_mutex
);
2954 tls
->suspending
= FALSE
;
2955 tls
->really_suspended
= TRUE
;
2957 if (!tls
->suspended
) {
2958 tls
->suspended
= TRUE
;
2959 MONO_SEM_POST (&suspend_sem
);
2962 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2964 while (suspend_count
- tls
->resume_count
> 0) {
2966 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2968 mono_mutex_unlock (&suspend_mutex
);
2970 mono_mutex_lock (&suspend_mutex
);
2976 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
2977 g_assert (err
== 0);
2981 tls
->suspended
= FALSE
;
2982 tls
->really_suspended
= FALSE
;
2984 threads_suspend_count
--;
2986 mono_mutex_unlock (&suspend_mutex
);
2988 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
2990 if (tls
->pending_invoke
) {
2991 /* Save the original context */
2992 tls
->pending_invoke
->has_ctx
= TRUE
;
2993 tls
->pending_invoke
->ctx
= tls
->context
.ctx
;
2998 /* The frame info becomes invalid after a resume */
2999 tls
->context
.valid
= FALSE
;
3000 tls
->async_state
.valid
= FALSE
;
3001 invalidate_frames (tls
);
3005 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
3007 DebuggerTlsData
*tls
= value
;
3009 if (!tls
->suspended
&& !tls
->terminated
)
3010 *(int*)user_data
= *(int*)user_data
+ 1;
3014 count_threads_to_wait_for (void)
3018 mono_loader_lock ();
3019 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
3020 mono_loader_unlock ();
3028 * Wait until the runtime is completely suspended.
3031 wait_for_suspend (void)
3033 int nthreads
, nwait
, err
;
3034 gboolean waited
= FALSE
;
3036 // FIXME: Threads starting/stopping ?
3037 mono_loader_lock ();
3038 nthreads
= mono_g_hash_table_size (thread_to_tls
);
3039 mono_loader_unlock ();
3042 nwait
= count_threads_to_wait_for ();
3044 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
3045 err
= MONO_SEM_WAIT (&suspend_sem
);
3046 g_assert (err
== 0);
3054 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
3060 * Return whenever the runtime is suspended.
3065 return count_threads_to_wait_for () == 0;
3068 static MonoSeqPointInfo
*
3069 get_seq_points (MonoDomain
*domain
, MonoMethod
*method
)
3071 MonoSeqPointInfo
*seq_points
;
3073 mono_domain_lock (domain
);
3074 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
3075 if (!seq_points
&& method
->is_inflated
) {
3076 /* generic sharing + aot */
3077 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mono_method_get_declaring_generic_method (method
));
3079 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mini_get_shared_method (method
));
3081 mono_domain_unlock (domain
);
3087 no_seq_points_found (MonoMethod
*method
)
3090 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
3092 printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method
, TRUE
));
3096 * find_next_seq_point_for_native_offset:
3098 * Find the first sequence point after NATIVE_OFFSET.
3101 find_next_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
3103 MonoSeqPointInfo
*seq_points
;
3106 seq_points
= get_seq_points (domain
, method
);
3112 g_assert (seq_points
);
3116 for (i
= 0; i
< seq_points
->len
; ++i
) {
3117 if (seq_points
->seq_points
[i
].native_offset
>= native_offset
)
3118 return &seq_points
->seq_points
[i
];
3125 * find_prev_seq_point_for_native_offset:
3127 * Find the first sequence point before NATIVE_OFFSET.
3130 find_prev_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
3132 MonoSeqPointInfo
*seq_points
;
3135 seq_points
= get_seq_points (domain
, method
);
3141 for (i
= seq_points
->len
- 1; i
>= 0; --i
) {
3142 if (seq_points
->seq_points
[i
].native_offset
<= native_offset
)
3143 return &seq_points
->seq_points
[i
];
3152 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
3153 * should be the location of a sequence point.
3155 static G_GNUC_UNUSED SeqPoint
*
3156 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
3158 MonoSeqPointInfo
*seq_points
;
3163 seq_points
= get_seq_points (domain
, method
);
3168 for (i
= 0; i
< seq_points
->len
; ++i
) {
3169 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
3170 return &seq_points
->seq_points
[i
];
3177 DebuggerTlsData
*tls
;
3179 } ComputeFramesUserData
;
3182 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
3184 ComputeFramesUserData
*ud
= user_data
;
3186 MonoMethod
*method
, *actual_method
, *api_method
;
3190 if (info
->type
!= FRAME_TYPE_MANAGED
) {
3191 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
3192 /* Mark the last frame as an invoke frame */
3194 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
3200 method
= jinfo_get_method (info
->ji
);
3202 method
= info
->method
;
3203 actual_method
= info
->actual_method
;
3204 api_method
= method
;
3209 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& method
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
))
3212 if (info
->il_offset
== -1) {
3213 /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
3214 if (ud
->frames
== NULL
) {
3215 sp
= find_prev_seq_point_for_native_offset (info
->domain
, method
, info
->native_offset
, NULL
);
3217 info
->il_offset
= sp
->il_offset
;
3219 if (info
->il_offset
== -1)
3220 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
3223 DEBUG (1, fprintf (log_file
, "\tFrame: %s:%x(%x) %d\n", mono_method_full_name (method
, TRUE
), info
->il_offset
, info
->native_offset
, info
->managed
));
3225 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) {
3226 if (!CHECK_PROTOCOL_VERSION (2, 17))
3227 /* Older clients can't handle this flag */
3229 api_method
= mono_marshal_method_from_wrapper (method
);
3232 actual_method
= api_method
;
3233 flags
|= FRAME_FLAG_NATIVE_TRANSITION
;
3236 frame
= g_new0 (StackFrame
, 1);
3237 frame
->method
= method
;
3238 frame
->actual_method
= actual_method
;
3239 frame
->api_method
= api_method
;
3240 frame
->il_offset
= info
->il_offset
;
3241 frame
->native_offset
= info
->native_offset
;
3242 frame
->flags
= flags
;
3243 frame
->ji
= info
->ji
;
3244 if (info
->reg_locations
)
3245 memcpy (frame
->reg_locations
, info
->reg_locations
, MONO_MAX_IREGS
* sizeof (mgreg_t
*));
3248 frame
->has_ctx
= TRUE
;
3250 frame
->domain
= info
->domain
;
3252 ud
->frames
= g_slist_append (ud
->frames
, frame
);
3258 process_filter_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
3260 ComputeFramesUserData
*ud
= user_data
;
3263 * 'tls->filter_ctx' is the location of the throw site.
3265 * mono_walk_stack() will never actually hit the throw site, but unwind
3266 * directly from the filter to the call site; we abort stack unwinding here
3267 * once this happens and resume from the throw site.
3270 if (MONO_CONTEXT_GET_SP (ctx
) >= MONO_CONTEXT_GET_SP (&ud
->tls
->filter_state
.ctx
))
3273 return process_frame (info
, ctx
, user_data
);
3277 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
3279 ComputeFramesUserData user_data
;
3281 int i
, findex
, new_frame_count
;
3282 StackFrame
**new_frames
, *f
;
3283 MonoUnwindOptions opts
= MONO_UNWIND_DEFAULT
|MONO_UNWIND_REG_LOCATIONS
;
3285 // FIXME: Locking on tls
3286 if (tls
->frames
&& tls
->frames_up_to_date
)
3289 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
3291 user_data
.tls
= tls
;
3292 user_data
.frames
= NULL
;
3293 if (tls
->terminated
) {
3294 tls
->frame_count
= 0;
3296 } if (!tls
->really_suspended
&& tls
->async_state
.valid
) {
3297 /* Have to use the state saved by the signal handler */
3298 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
3299 mono_walk_stack_with_state (process_frame
, &tls
->async_state
, opts
, &user_data
);
3300 } else if (tls
->filter_state
.valid
) {
3302 * We are inside an exception filter.
3304 * First we add all the frames from inside the filter; 'tls->ctx' has the current context.
3306 if (tls
->context
.valid
)
3307 mono_walk_stack_with_state (process_filter_frame
, &tls
->context
, opts
, &user_data
);
3309 * After that, we resume unwinding from the location where the exception has been thrown.
3311 mono_walk_stack_with_state (process_frame
, &tls
->filter_state
, opts
, &user_data
);
3312 } else if (tls
->context
.valid
) {
3313 mono_walk_stack_with_state (process_frame
, &tls
->context
, opts
, &user_data
);
3316 tls
->frame_count
= 0;
3320 new_frame_count
= g_slist_length (user_data
.frames
);
3321 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
3323 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
3327 * Reuse the id for already existing stack frames, so invokes don't invalidate
3328 * the still valid stack frames.
3330 for (i
= 0; i
< tls
->frame_count
; ++i
) {
3331 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
3332 f
->id
= tls
->frames
[i
]->id
;
3337 if (i
>= tls
->frame_count
)
3338 f
->id
= InterlockedIncrement (&frame_id
);
3340 new_frames
[findex
++] = f
;
3343 g_slist_free (user_data
.frames
);
3345 invalidate_frames (tls
);
3347 tls
->frames
= new_frames
;
3348 tls
->frame_count
= new_frame_count
;
3349 tls
->frames_up_to_date
= TRUE
;
3353 * GHFunc to emit an appdomain creation event
3354 * @param key Don't care
3355 * @param value A loaded appdomain
3356 * @param user_data Don't care
3359 emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
)
3361 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, value
);
3362 g_hash_table_foreach (get_agent_domain_info (value
)->loaded_classes
, emit_type_load
, NULL
);
3366 * GHFunc to emit a thread start event
3367 * @param key A thread id
3368 * @param value A thread object
3369 * @param user_data Don't care
3372 emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
)
3374 if (GPOINTER_TO_INT (key
) != debugger_thread_id
)
3375 process_profiler_event (EVENT_KIND_THREAD_START
, value
);
3379 * GFunc to emit an assembly load event
3380 * @param value A loaded assembly
3381 * @param user_data Don't care
3384 emit_assembly_load (gpointer value
, gpointer user_data
)
3386 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, value
);
3390 * GFunc to emit a type load event
3391 * @param value A loaded type
3392 * @param user_data Don't care
3395 emit_type_load (gpointer key
, gpointer value
, gpointer user_data
)
3397 process_profiler_event (EVENT_KIND_TYPE_LOAD
, value
);
3401 strdup_tolower (char *s
)
3406 for (p
= s2
; *p
; ++p
)
3416 * create_event_list:
3418 * Return a list of event request ids matching EVENT, starting from REQS, which
3419 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
3421 * We return request ids, instead of requests, to simplify threading, since
3422 * requests could be deleted anytime when the loader lock is not held.
3423 * LOCKING: Assumes the loader lock is held.
3426 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
3429 GSList
*events
= NULL
;
3431 *suspend_policy
= SUSPEND_POLICY_NONE
;
3434 reqs
= event_requests
;
3439 for (i
= 0; i
< reqs
->len
; ++i
) {
3440 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
3441 if (req
->event_kind
== event
) {
3442 gboolean filtered
= FALSE
;
3445 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
3446 Modifier
*mod
= &req
->modifiers
[j
];
3448 if (mod
->kind
== MOD_KIND_COUNT
) {
3450 if (mod
->data
.count
> 0) {
3451 if (mod
->data
.count
> 0) {
3453 if (mod
->data
.count
== 0)
3457 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
3458 if (mod
->data
.thread
!= mono_thread_internal_current ())
3460 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
3461 if (mod
->data
.exc_class
&& mod
->subclasses
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
3463 if (mod
->data
.exc_class
&& !mod
->subclasses
&& mod
->data
.exc_class
!= ei
->exc
->vtable
->klass
)
3465 if (ei
->caught
&& !mod
->caught
)
3467 if (!ei
->caught
&& !mod
->uncaught
)
3469 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
3471 gboolean found
= FALSE
;
3472 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
3475 for (k
= 0; assemblies
[k
]; ++k
)
3476 if (assemblies
[k
] == jinfo_get_method (ji
)->klass
->image
->assembly
)
3481 } else if (mod
->kind
== MOD_KIND_SOURCE_FILE_ONLY
&& ei
&& ei
->klass
) {
3482 gpointer iter
= NULL
;
3484 MonoDebugSourceInfo
*sinfo
;
3485 char *source_file
, *s
;
3486 gboolean found
= FALSE
;
3488 GPtrArray
*source_file_list
;
3490 while ((method
= mono_class_get_methods (ei
->klass
, &iter
))) {
3491 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
3494 mono_debug_symfile_get_line_numbers_full (minfo
, &source_file
, &source_file_list
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3495 for (i
= 0; i
< source_file_list
->len
; ++i
) {
3496 sinfo
= g_ptr_array_index (source_file_list
, i
);
3498 * Do a case-insesitive match by converting the file name to
3501 s
= strdup_tolower (sinfo
->source_file
);
3502 if (g_hash_table_lookup (mod
->data
.source_files
, s
))
3505 char *s2
= g_path_get_basename (sinfo
->source_file
);
3506 char *s3
= strdup_tolower (s2
);
3508 if (g_hash_table_lookup (mod
->data
.source_files
, s3
))
3515 g_ptr_array_free (source_file_list
, TRUE
);
3520 } else if (mod
->kind
== MOD_KIND_TYPE_NAME_ONLY
&& ei
&& ei
->klass
) {
3523 s
= mono_type_full_name (&ei
->klass
->byval_arg
);
3524 if (!g_hash_table_lookup (mod
->data
.type_names
, s
))
3527 } else if (mod
->kind
== MOD_KIND_STEP
) {
3528 if ((mod
->data
.filter
& STEP_FILTER_STATIC_CTOR
) && ji
&&
3529 (jinfo_get_method (ji
)->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
3530 !strcmp (jinfo_get_method (ji
)->name
, ".cctor"))
3532 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_HIDDEN
) && ji
) {
3533 MonoCustomAttrInfo
*ainfo
;
3534 static MonoClass
*klass
;
3537 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerHiddenAttribute");
3540 if (!ji
->dbg_hidden_inited
) {
3541 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3543 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3544 ji
->dbg_hidden
= TRUE
;
3545 mono_custom_attrs_free (ainfo
);
3547 ji
->dbg_hidden_inited
= TRUE
;
3552 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_STEP_THROUGH
) && ji
) {
3553 MonoCustomAttrInfo
*ainfo
;
3554 static MonoClass
*klass
;
3557 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerStepThroughAttribute");
3560 if (!ji
->dbg_step_through_inited
) {
3561 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3563 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3564 ji
->dbg_step_through
= TRUE
;
3565 mono_custom_attrs_free (ainfo
);
3567 ainfo
= mono_custom_attrs_from_class (jinfo_get_method (ji
)->klass
);
3569 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3570 ji
->dbg_step_through
= TRUE
;
3571 mono_custom_attrs_free (ainfo
);
3573 ji
->dbg_step_through_inited
= TRUE
;
3575 if (ji
->dbg_step_through
)
3578 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_NON_USER_CODE
) && ji
) {
3579 MonoCustomAttrInfo
*ainfo
;
3580 static MonoClass
*klass
;
3583 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerNonUserCodeAttribute");
3586 if (!ji
->dbg_non_user_code_inited
) {
3587 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3589 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3590 ji
->dbg_non_user_code
= TRUE
;
3591 mono_custom_attrs_free (ainfo
);
3593 ainfo
= mono_custom_attrs_from_class (jinfo_get_method (ji
)->klass
);
3595 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3596 ji
->dbg_non_user_code
= TRUE
;
3597 mono_custom_attrs_free (ainfo
);
3599 ji
->dbg_non_user_code_inited
= TRUE
;
3601 if (ji
->dbg_non_user_code
)
3608 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
3609 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
3614 /* Send a VM START/DEATH event by default */
3615 if (event
== EVENT_KIND_VM_START
)
3616 events
= g_slist_append (events
, GINT_TO_POINTER (0));
3617 if (event
== EVENT_KIND_VM_DEATH
)
3618 events
= g_slist_append (events
, GINT_TO_POINTER (0));
3623 static G_GNUC_UNUSED
const char*
3624 event_to_string (EventKind event
)
3627 case EVENT_KIND_VM_START
: return "VM_START";
3628 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
3629 case EVENT_KIND_THREAD_START
: return "THREAD_START";
3630 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
3631 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
3632 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
3633 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
3634 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
3635 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
3636 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
3637 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
3638 case EVENT_KIND_STEP
: return "STEP";
3639 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
3640 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
3641 case EVENT_KIND_KEEPALIVE
: return "KEEPALIVE";
3642 case EVENT_KIND_USER_BREAK
: return "USER_BREAK";
3643 case EVENT_KIND_USER_LOG
: return "USER_LOG";
3645 g_assert_not_reached ();
3653 * Send an event to the client, suspending the vm if needed.
3654 * LOCKING: Since this can suspend the calling thread, no locks should be held
3656 * The EVENTS list is freed by this function.
3659 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
3663 MonoDomain
*domain
= mono_domain_get ();
3664 MonoThread
*thread
= NULL
;
3665 MonoObject
*keepalive_obj
= NULL
;
3666 gboolean send_success
= FALSE
;
3671 DEBUG (2, fprintf (log_file
, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event
)));
3675 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
) {
3676 // FIXME: We miss those events
3677 DEBUG (2, fprintf (log_file
, "VM start event not sent yet: dropping %s\n", event_to_string (event
)));
3681 if (vm_death_event_sent
) {
3682 DEBUG (2, fprintf (log_file
, "VM death event has been sent: dropping %s\n", event_to_string (event
)));
3686 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
) {
3687 DEBUG (2, fprintf (log_file
, "Mono runtime is shutting down: dropping %s\n", event_to_string (event
)));
3692 DEBUG (2, fprintf (log_file
, "Debugger client is not connected: dropping %s\n", event_to_string (event
)));
3696 if (event
== EVENT_KIND_KEEPALIVE
)
3697 suspend_policy
= SUSPEND_POLICY_NONE
;
3702 if (agent_config
.defer
) {
3703 /* Make sure the thread id is always set when doing deferred debugging */
3704 if (debugger_thread_id
== GetCurrentThreadId ()) {
3705 /* Don't suspend on events from the debugger thread */
3706 suspend_policy
= SUSPEND_POLICY_NONE
;
3707 thread
= mono_thread_get_main ();
3709 else thread
= mono_thread_current ();
3711 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
3712 // FIXME: Send these with a NULL thread, don't suspend the current thread
3717 nevents
= g_slist_length (events
);
3718 buffer_init (&buf
, 128);
3719 buffer_add_byte (&buf
, suspend_policy
);
3720 buffer_add_int (&buf
, nevents
);
3722 for (l
= events
; l
; l
= l
->next
) {
3723 buffer_add_byte (&buf
, event
); // event kind
3724 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
3729 thread
= mono_thread_current ();
3731 if (event
== EVENT_KIND_VM_START
&& arg
!= NULL
)
3734 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
3737 case EVENT_KIND_THREAD_START
:
3738 case EVENT_KIND_THREAD_DEATH
:
3740 case EVENT_KIND_APPDOMAIN_CREATE
:
3741 case EVENT_KIND_APPDOMAIN_UNLOAD
:
3742 buffer_add_domainid (&buf
, arg
);
3744 case EVENT_KIND_METHOD_ENTRY
:
3745 case EVENT_KIND_METHOD_EXIT
:
3746 buffer_add_methodid (&buf
, domain
, arg
);
3748 case EVENT_KIND_ASSEMBLY_LOAD
:
3749 case EVENT_KIND_ASSEMBLY_UNLOAD
:
3750 buffer_add_assemblyid (&buf
, domain
, arg
);
3752 case EVENT_KIND_TYPE_LOAD
:
3753 buffer_add_typeid (&buf
, domain
, arg
);
3755 case EVENT_KIND_BREAKPOINT
:
3756 case EVENT_KIND_STEP
:
3757 buffer_add_methodid (&buf
, domain
, arg
);
3758 buffer_add_long (&buf
, il_offset
);
3760 case EVENT_KIND_VM_START
:
3761 buffer_add_domainid (&buf
, mono_get_root_domain ());
3763 case EVENT_KIND_VM_DEATH
:
3764 if (CHECK_PROTOCOL_VERSION (2, 27))
3765 buffer_add_int (&buf
, mono_environment_exitcode_get ());
3767 case EVENT_KIND_EXCEPTION
: {
3768 EventInfo
*ei
= arg
;
3769 buffer_add_objid (&buf
, ei
->exc
);
3771 * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it
3772 * later after the suspension. (#12494).
3774 keepalive_obj
= ei
->exc
;
3777 case EVENT_KIND_USER_BREAK
:
3779 case EVENT_KIND_USER_LOG
: {
3780 EventInfo
*ei
= arg
;
3781 buffer_add_int (&buf
, ei
->level
);
3782 buffer_add_string (&buf
, ei
->category
? ei
->category
: "");
3783 buffer_add_string (&buf
, ei
->message
? ei
->message
: "");
3786 case EVENT_KIND_KEEPALIVE
:
3787 suspend_policy
= SUSPEND_POLICY_NONE
;
3790 g_assert_not_reached ();
3794 if (event
== EVENT_KIND_VM_START
) {
3795 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
3796 if (!agent_config
.defer
)
3797 start_debugger_thread ();
3800 if (event
== EVENT_KIND_VM_DEATH
) {
3801 vm_death_event_sent
= TRUE
;
3802 suspend_policy
= SUSPEND_POLICY_NONE
;
3805 if (mono_runtime_is_shutting_down ())
3806 suspend_policy
= SUSPEND_POLICY_NONE
;
3808 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
3810 * Save the thread context and start suspending before sending the packet,
3811 * since we could be receiving the resume request before send_packet ()
3814 save_thread_context (ctx
);
3818 /* This will keep this object alive */
3819 get_objref (keepalive_obj
);
3822 send_success
= send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
3826 g_slist_free (events
);
3829 if (!send_success
) {
3830 DEBUG (2, fprintf (log_file
, "Sending command %s failed.\n", event_to_string (event
)));
3834 if (event
== EVENT_KIND_VM_START
) {
3835 vm_start_event_sent
= TRUE
;
3838 DEBUG (1, fprintf (log_file
, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer
)GetCurrentThreadId (), nevents
, event_to_string (event
), ecount
, suspend_policy
));
3840 switch (suspend_policy
) {
3841 case SUSPEND_POLICY_NONE
:
3843 case SUSPEND_POLICY_ALL
:
3846 case SUSPEND_POLICY_EVENT_THREAD
:
3850 g_assert_not_reached ();
3855 process_profiler_event (EventKind event
, gpointer arg
)
3859 EventInfo ei
, *ei_arg
= NULL
;
3861 if (event
== EVENT_KIND_TYPE_LOAD
) {
3866 mono_loader_lock ();
3867 events
= create_event_list (event
, NULL
, NULL
, ei_arg
, &suspend_policy
);
3868 mono_loader_unlock ();
3870 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
3874 runtime_initialized (MonoProfiler
*prof
)
3876 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
3877 if (agent_config
.defer
)
3878 start_debugger_thread ();
3882 runtime_shutdown (MonoProfiler
*prof
)
3884 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
3886 mono_debugger_agent_cleanup ();
3890 thread_startup (MonoProfiler
*prof
, uintptr_t tid
)
3892 MonoInternalThread
*thread
= mono_thread_internal_current ();
3893 MonoInternalThread
*old_thread
;
3894 DebuggerTlsData
*tls
;
3896 if (tid
== debugger_thread_id
)
3899 g_assert (thread
->tid
== tid
);
3901 mono_loader_lock ();
3902 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3903 mono_loader_unlock ();
3905 if (thread
== old_thread
) {
3907 * For some reason, thread_startup () might be called for the same thread
3908 * multiple times (attach ?).
3910 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
3914 * thread_end () might not be called for some threads, and the tid could
3917 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
3918 mono_loader_lock ();
3919 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
3920 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
3921 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
3922 mono_loader_unlock ();
3926 tls
= mono_native_tls_get_value (debugger_tls_id
);
3928 // FIXME: Free this somewhere
3929 tls
= g_new0 (DebuggerTlsData
, 1);
3930 MONO_GC_REGISTER_ROOT_SINGLE (tls
->thread
);
3931 tls
->thread
= thread
;
3932 mono_native_tls_set_value (debugger_tls_id
, tls
);
3934 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
3936 mono_loader_lock ();
3937 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
3938 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
3939 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
3940 mono_loader_unlock ();
3942 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
3945 * suspend_vm () could have missed this thread, so wait for a resume.
3951 thread_end (MonoProfiler
*prof
, uintptr_t tid
)
3953 MonoInternalThread
*thread
;
3954 DebuggerTlsData
*tls
= NULL
;
3956 mono_loader_lock ();
3957 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3959 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
3960 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
3962 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
3963 tls
->terminated
= TRUE
;
3964 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
3965 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
3969 mono_loader_unlock ();
3971 /* We might be called for threads started before we registered the start callback */
3973 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
3974 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
3979 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
3981 mono_loader_lock ();
3982 g_hash_table_insert (domains
, domain
, domain
);
3983 mono_loader_unlock ();
3985 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
3989 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
3991 clear_breakpoints_for_domain (domain
);
3993 mono_loader_lock ();
3994 /* Invalidate each thread's frame stack */
3995 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
3996 mono_loader_unlock ();
3998 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
4002 * invalidate_each_thread:
4004 * A GHFunc to invalidate frames.
4005 * value must be a DebuggerTlsData*
4008 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
4010 invalidate_frames (value
);
4014 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
4016 /* Sent later in jit_end () */
4017 mono_loader_lock ();
4018 g_ptr_array_add (pending_assembly_loads
, assembly
);
4019 mono_loader_unlock ();
4023 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
4025 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
4027 clear_event_requests_for_assembly (assembly
);
4028 clear_types_for_assembly (assembly
);
4032 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
4034 #if defined(HOST_WIN32) && !defined(__GNUC__)
4035 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
4037 gpointer stackptr
= __builtin_frame_address (1);
4039 MonoInternalThread
*thread
= mono_thread_internal_current ();
4040 DebuggerTlsData
*tls
;
4042 mono_loader_lock ();
4044 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4045 /* Could be the debugger thread with assembly/type load hooks */
4047 tls
->invoke_addr
= stackptr
;
4049 mono_loader_unlock ();
4053 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
4056 #if defined(HOST_WIN32) && !defined(__GNUC__)
4057 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
4059 gpointer stackptr
= __builtin_frame_address (1);
4062 if (!embedding
|| ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
4066 * We need to stop single stepping when exiting a runtime invoke, since if it is
4067 * a step out, it may return to native code, and thus never end.
4069 mono_loader_lock ();
4070 ss_invoke_addr
= NULL
;
4072 for (i
= 0; i
< event_requests
->len
; ++i
) {
4073 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4075 if (req
->event_kind
== EVENT_KIND_STEP
) {
4076 ss_destroy (req
->info
);
4077 g_ptr_array_remove_index_fast (event_requests
, i
);
4082 mono_loader_unlock ();
4086 send_type_load (MonoClass
*klass
)
4088 gboolean type_load
= FALSE
;
4089 MonoDomain
*domain
= mono_domain_get ();
4090 AgentDomainInfo
*info
= NULL
;
4092 mono_loader_lock ();
4093 mono_domain_lock (domain
);
4095 info
= get_agent_domain_info (domain
);
4097 if (!g_hash_table_lookup (info
->loaded_classes
, klass
)) {
4099 g_hash_table_insert (info
->loaded_classes
, klass
, klass
);
4102 mono_domain_unlock (domain
);
4103 mono_loader_unlock ();
4105 emit_type_load (klass
, klass
, NULL
);
4109 * Emit load events for all types currently loaded in the domain.
4110 * Takes the loader and domain locks.
4111 * user_data is unused.
4114 send_types_for_domain (MonoDomain
*domain
, void *user_data
)
4116 AgentDomainInfo
*info
= NULL
;
4118 mono_loader_lock ();
4119 mono_domain_lock (domain
);
4120 info
= get_agent_domain_info (domain
);
4122 g_hash_table_foreach (info
->loaded_classes
, emit_type_load
, NULL
);
4123 mono_domain_unlock (domain
);
4124 mono_loader_unlock ();
4128 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
4131 * We emit type load events when the first method of the type is JITted,
4132 * since the class load profiler callbacks might be called with the
4133 * loader lock held. They could also occur in the debugger thread.
4134 * Same for assembly load events.
4137 MonoAssembly
*assembly
= NULL
;
4139 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
4140 mono_loader_lock ();
4141 if (pending_assembly_loads
->len
> 0) {
4142 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
4143 g_ptr_array_remove_index (pending_assembly_loads
, 0);
4145 mono_loader_unlock ();
4148 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
4154 send_type_load (method
->klass
);
4157 add_pending_breakpoints (method
, jinfo
);
4161 * BREAKPOINTS/SINGLE STEPPING
4165 * Contains information about an inserted breakpoint.
4168 long il_offset
, native_offset
;
4173 } BreakpointInstance
;
4176 * Contains generic information about a breakpoint.
4180 * The method where the breakpoint is placed. Can be NULL in which case it
4181 * is inserted into every method. This is used to implement method entry/
4182 * exit events. Can be a generic method definition, in which case the
4183 * breakpoint is inserted into every instance.
4189 * A list of BreakpointInstance structures describing where the breakpoint
4190 * was inserted. There could be more than one because of
4191 * generics/appdomains/method entry/exit.
4193 GPtrArray
*children
;
4196 /* List of breakpoints */
4197 static GPtrArray
*breakpoints
;
4198 /* Maps breakpoint locations to the number of breakpoints at that location */
4199 static GHashTable
*bp_locs
;
4202 breakpoints_init (void)
4204 breakpoints
= g_ptr_array_new ();
4205 bp_locs
= g_hash_table_new (NULL
, NULL
);
4209 * insert_breakpoint:
4211 * Insert the breakpoint described by BP into the method described by
4215 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoDomain
*domain
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
, MonoError
*error
)
4218 BreakpointInstance
*inst
;
4219 SeqPoint
*sp
= NULL
;
4222 mono_error_init (error
);
4224 for (i
= 0; i
< seq_points
->len
; ++i
) {
4225 sp
= &seq_points
->seq_points
[i
];
4227 if (sp
->il_offset
== bp
->il_offset
)
4231 if (i
== seq_points
->len
) {
4233 * The set of IL offsets with seq points doesn't completely match the
4234 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
4236 for (i
= 0; i
< seq_points
->len
; ++i
) {
4237 sp
= &seq_points
->seq_points
[i
];
4239 if (sp
->il_offset
!= METHOD_ENTRY_IL_OFFSET
&& sp
->il_offset
!= METHOD_EXIT_IL_OFFSET
&& sp
->il_offset
+ 1 == bp
->il_offset
)
4244 if (i
== seq_points
->len
) {
4245 char *s
= g_strdup_printf ("Unable to insert breakpoint at %s:%d, seq_points=%d\n", mono_method_full_name (jinfo_get_method (ji
), TRUE
), bp
->il_offset
, seq_points
->len
);
4247 for (i
= 0; i
< seq_points
->len
; ++i
)
4248 DEBUG (1, fprintf (log_file
, "%d\n", seq_points
->seq_points
[i
].il_offset
));
4251 mono_error_set_error (error
, MONO_ERROR_GENERIC
, "%s", s
);
4252 g_warning ("%s", s
);
4256 g_warning ("%s", s
);
4262 inst
= g_new0 (BreakpointInstance
, 1);
4264 inst
->native_offset
= sp
->native_offset
;
4265 inst
->ip
= (guint8
*)ji
->code_start
+ sp
->native_offset
;
4267 inst
->domain
= domain
;
4269 mono_loader_lock ();
4271 g_ptr_array_add (bp
->children
, inst
);
4273 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
4274 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
4275 mono_loader_unlock ();
4277 if (sp
->native_offset
== SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
) {
4278 DEBUG (1, fprintf (log_file
, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp
->il_offset
));
4279 } else if (count
== 0) {
4280 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4281 mono_arch_set_breakpoint (ji
, inst
->ip
);
4287 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x.\n", mono_method_full_name (jinfo_get_method (ji
), TRUE
), (int)sp
->il_offset
));
4291 remove_breakpoint (BreakpointInstance
*inst
)
4293 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4295 MonoJitInfo
*ji
= inst
->ji
;
4296 guint8
*ip
= inst
->ip
;
4298 mono_loader_lock ();
4299 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
4300 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
4301 mono_loader_unlock ();
4303 g_assert (count
> 0);
4305 if (count
== 1 && inst
->native_offset
!= SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
) {
4306 mono_arch_clear_breakpoint (ji
, ip
);
4313 static inline gboolean
4314 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
4320 if (method
== bp
->method
)
4322 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
)
4325 if (bp
->method
->is_inflated
&& method
->is_inflated
) {
4326 MonoMethodInflated
*bpimethod
= (MonoMethodInflated
*)bp
->method
;
4327 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
4329 /* Open generic methods should match closed generic methods of the same class */
4330 if (bpimethod
->declaring
== imethod
->declaring
&& bpimethod
->context
.class_inst
== imethod
->context
.class_inst
&& bpimethod
->context
.method_inst
&& bpimethod
->context
.method_inst
->is_open
) {
4331 for (i
= 0; i
< bpimethod
->context
.method_inst
->type_argc
; ++i
) {
4332 MonoType
*t1
= bpimethod
->context
.method_inst
->type_argv
[i
];
4334 /* FIXME: Handle !mvar */
4335 if (t1
->type
!= MONO_TYPE_MVAR
)
4346 * add_pending_breakpoints:
4348 * Insert pending breakpoints into the newly JITted method METHOD.
4351 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
4354 MonoSeqPointInfo
*seq_points
;
4356 MonoMethod
*jmethod
;
4361 domain
= mono_domain_get ();
4363 mono_loader_lock ();
4365 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4366 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
4367 gboolean found
= FALSE
;
4369 if (!bp_matches_method (bp
, method
))
4372 for (j
= 0; j
< bp
->children
->len
; ++j
) {
4373 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
4380 jmethod
= jinfo_get_method (ji
);
4381 mono_domain_lock (domain
);
4382 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, jmethod
);
4383 if (!seq_points
&& jmethod
->is_inflated
)
4384 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mono_method_get_declaring_generic_method (jmethod
));
4385 mono_domain_unlock (domain
);
4387 /* Could be AOT code */
4389 g_assert (seq_points
);
4391 insert_breakpoint (seq_points
, domain
, ji
, bp
, NULL
);
4395 mono_loader_unlock ();
4399 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
, MonoError
*error
)
4405 mono_error_init (error
);
4407 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
4409 /* Might be AOTed code */
4410 code
= mono_aot_get_method (domain
, method
);
4412 ji
= mono_jit_info_table_find (domain
, code
);
4417 insert_breakpoint (seq_points
, domain
, ji
, bp
, error
);
4421 clear_breakpoint (MonoBreakpoint
*bp
);
4426 * Set a breakpoint at IL_OFFSET in METHOD.
4427 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
4428 * METHOD can also be a generic method definition, in which case a breakpoint
4429 * is placed in all instances of the method.
4430 * If ERROR is non-NULL, then it is set and NULL is returnd if some breakpoints couldn't be
4433 static MonoBreakpoint
*
4434 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
, MonoError
*error
)
4437 GHashTableIter iter
, iter2
;
4440 MonoSeqPointInfo
*seq_points
;
4443 mono_error_init (error
);
4446 // - suspend/resume the vm to prevent code patching problems
4447 // - multiple breakpoints on the same location
4448 // - dynamic methods
4451 bp
= g_new0 (MonoBreakpoint
, 1);
4452 bp
->method
= method
;
4453 bp
->il_offset
= il_offset
;
4455 bp
->children
= g_ptr_array_new ();
4457 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
));
4459 mono_loader_lock ();
4461 g_hash_table_iter_init (&iter
, domains
);
4462 while (g_hash_table_iter_next (&iter
, (void**)&domain
, NULL
)) {
4463 mono_domain_lock (domain
);
4465 g_hash_table_iter_init (&iter2
, domain_jit_info (domain
)->seq_points
);
4466 while (g_hash_table_iter_next (&iter2
, (void**)&m
, (void**)&seq_points
)) {
4467 if (bp_matches_method (bp
, m
))
4468 set_bp_in_method (domain
, m
, seq_points
, bp
, error
);
4471 mono_domain_unlock (domain
);
4474 mono_loader_unlock ();
4476 mono_loader_lock ();
4477 g_ptr_array_add (breakpoints
, bp
);
4478 mono_loader_unlock ();
4480 if (error
&& !mono_error_ok (error
)) {
4481 clear_breakpoint (bp
);
4489 clear_breakpoint (MonoBreakpoint
*bp
)
4493 // FIXME: locking, races
4494 for (i
= 0; i
< bp
->children
->len
; ++i
) {
4495 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
4497 remove_breakpoint (inst
);
4502 mono_loader_lock ();
4503 g_ptr_array_remove (breakpoints
, bp
);
4504 mono_loader_unlock ();
4506 g_ptr_array_free (bp
->children
, TRUE
);
4511 breakpoints_cleanup (void)
4515 mono_loader_lock ();
4517 while (i
< event_requests
->len
) {
4518 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4520 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
4521 clear_breakpoint (req
->info
);
4522 g_ptr_array_remove_index_fast (event_requests
, i
);
4529 for (i
= 0; i
< breakpoints
->len
; ++i
)
4530 g_free (g_ptr_array_index (breakpoints
, i
));
4532 g_ptr_array_free (breakpoints
, TRUE
);
4533 g_hash_table_destroy (bp_locs
);
4538 mono_loader_unlock ();
4542 * clear_breakpoints_for_domain:
4544 * Clear breakpoint instances which reference DOMAIN.
4547 clear_breakpoints_for_domain (MonoDomain
*domain
)
4551 /* This could be called after shutdown */
4555 mono_loader_lock ();
4556 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4557 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
4560 while (j
< bp
->children
->len
) {
4561 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
4563 if (inst
->domain
== domain
) {
4564 remove_breakpoint (inst
);
4568 g_ptr_array_remove_index_fast (bp
->children
, j
);
4574 mono_loader_unlock ();
4580 * Return FALSE if single stepping needs to continue.
4583 ss_update (SingleStepReq
*req
, MonoJitInfo
*ji
, SeqPoint
*sp
, DebuggerTlsData
*tls
, MonoContext
*ctx
)
4585 MonoDebugMethodInfo
*minfo
;
4586 MonoDebugSourceLocation
*loc
= NULL
;
4587 gboolean hit
= TRUE
;
4590 if (req
->depth
== STEP_DEPTH_OVER
&& (sp
->flags
& MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
)) {
4592 * These seq points are inserted by the JIT after calls, step over needs to skip them.
4594 DEBUG (1, fprintf (log_file
, "[%p] Seq point at nonempty stack %x while stepping over, continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), sp
->il_offset
));
4598 if (req
->depth
== STEP_DEPTH_OVER
&& hit
) {
4599 if (!tls
->context
.valid
)
4600 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
4601 compute_frame_info (tls
->thread
, tls
);
4602 if (req
->nframes
&& tls
->frame_count
&& tls
->frame_count
> req
->nframes
) {
4603 /* Hit the breakpoint in a recursive call */
4604 DEBUG (1, fprintf (log_file
, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer
)GetCurrentThreadId ()));
4609 if (req
->size
!= STEP_SIZE_LINE
)
4612 /* Have to check whenever a different source line was reached */
4613 method
= jinfo_get_method (ji
);
4614 minfo
= mono_debug_lookup_method (method
);
4617 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
4619 if (!loc
|| (loc
&& method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
)) {
4620 /* Have to continue single stepping */
4622 DEBUG(1, fprintf (log_file
, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), sp
->il_offset
));
4624 DEBUG(1, fprintf (log_file
, "[%p] Same source line (%d), continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), loc
->row
));
4629 ss_req
->last_method
= method
;
4630 ss_req
->last_line
= loc
->row
;
4631 mono_debug_free_source_location (loc
);
4638 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
4640 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
4644 process_breakpoint_inner (DebuggerTlsData
*tls
)
4648 int i
, j
, suspend_policy
;
4649 guint32 native_offset
;
4651 BreakpointInstance
*inst
;
4652 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
4653 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
4654 EventKind kind
= EVENT_KIND_BREAKPOINT
;
4655 MonoContext
*ctx
= &tls
->restore_ctx
;
4657 MonoSeqPointInfo
*info
;
4660 // FIXME: Speed this up
4662 ip
= MONO_CONTEXT_GET_IP (ctx
);
4663 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
4665 method
= jinfo_get_method (ji
);
4667 /* Compute the native offset of the breakpoint from the ip */
4668 native_offset
= ip
- (guint8
*)ji
->code_start
;
4671 * Skip the instruction causing the breakpoint signal.
4673 mono_arch_skip_breakpoint (ctx
, ji
);
4675 if (method
->wrapper_type
|| tls
->disable_breakpoints
)
4678 bp_reqs
= g_ptr_array_new ();
4679 ss_reqs
= g_ptr_array_new ();
4680 ss_reqs_orig
= g_ptr_array_new ();
4682 mono_loader_lock ();
4685 * The ip points to the instruction causing the breakpoint event, which is after
4686 * the offset recorded in the seq point map, so find the prev seq point before ip.
4688 sp
= find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
);
4690 no_seq_points_found (method
);
4693 DEBUG(1, fprintf (log_file
, "[%p] Breakpoint hit, method=%s, ip=%p, offset=0x%x, sp il offset=0x%x.\n", (gpointer
)GetCurrentThreadId (), method
->name
, ip
, native_offset
, sp
? sp
->il_offset
: -1));
4696 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4697 bp
= g_ptr_array_index (breakpoints
, i
);
4702 for (j
= 0; j
< bp
->children
->len
; ++j
) {
4703 inst
= g_ptr_array_index (bp
->children
, j
);
4704 if (inst
->ji
== ji
&& inst
->sp
== sp
) {
4705 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
4706 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
4708 g_ptr_array_add (bp_reqs
, bp
->req
);
4713 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
4714 /* Maybe a method entry/exit event */
4715 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
)
4716 kind
= EVENT_KIND_METHOD_ENTRY
;
4717 else if (sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
4718 kind
= EVENT_KIND_METHOD_EXIT
;
4721 /* Process single step requests */
4722 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
4723 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
4724 SingleStepReq
*ss_req
= req
->info
;
4727 if (mono_thread_internal_current () != ss_req
->thread
)
4730 hit
= ss_update (ss_req
, ji
, sp
, tls
, ctx
);
4732 g_ptr_array_add (ss_reqs
, req
);
4734 /* Start single stepping again from the current sequence point */
4735 ss_start (ss_req
, method
, sp
, info
, ctx
, tls
, FALSE
);
4738 if (ss_reqs
->len
> 0)
4739 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
4740 if (bp_reqs
->len
> 0)
4741 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
4742 if (kind
!= EVENT_KIND_BREAKPOINT
)
4743 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
4745 mono_loader_unlock ();
4747 g_ptr_array_free (bp_reqs
, TRUE
);
4748 g_ptr_array_free (ss_reqs
, TRUE
);
4751 * FIXME: The first event will suspend, so the second will only be sent after the
4755 process_event (EVENT_KIND_STEP
, method
, 0, ctx
, ss_events
, suspend_policy
);
4757 process_event (kind
, method
, 0, ctx
, bp_events
, suspend_policy
);
4758 if (enter_leave_events
)
4759 process_event (kind
, method
, 0, ctx
, enter_leave_events
, suspend_policy
);
4762 /* Process a breakpoint/single step event after resuming from a signal handler */
4764 process_signal_event (void (*func
) (DebuggerTlsData
*))
4766 DebuggerTlsData
*tls
;
4767 MonoContext orig_restore_ctx
, ctx
;
4769 tls
= mono_native_tls_get_value (debugger_tls_id
);
4770 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4771 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4772 memcpy (&tls
->restore_ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
4776 /* This is called when resuming from a signal handler, so it shouldn't return */
4777 memcpy (&ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4778 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
4779 mono_restore_context (&ctx
);
4780 g_assert_not_reached ();
4784 process_breakpoint (void)
4786 process_signal_event (process_breakpoint_inner
);
4790 resume_from_signal_handler (void *sigctx
, void *func
)
4792 DebuggerTlsData
*tls
;
4795 /* Save the original context in TLS */
4796 // FIXME: This might not work on an altstack ?
4797 tls
= mono_native_tls_get_value (debugger_tls_id
);
4799 fprintf (stderr
, "Thread %p is not attached to the JIT.\n", (gpointer
)GetCurrentThreadId ());
4802 // FIXME: MonoContext usually doesn't include the fp registers, so these are
4803 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
4804 // clob:c could be added to op_seq_point.
4806 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
4807 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
4808 #ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
4809 mono_arch_setup_resume_sighandler_ctx (&ctx
, func
);
4811 MONO_CONTEXT_SET_IP (&ctx
, func
);
4813 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
4815 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4816 mono_ppc_set_func_into_sigctx (sigctx
, func
);
4821 mono_debugger_agent_breakpoint_hit (void *sigctx
)
4824 * We are called from a signal handler, and running code there causes all kinds of
4825 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
4826 * So set up the signal context to return to the real breakpoint handler function.
4828 resume_from_signal_handler (sigctx
, process_breakpoint
);
4832 user_break_cb (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4834 if (frame
->managed
) {
4835 *(MonoContext
*)data
= *ctx
;
4844 * Called by System.Diagnostics.Debugger:Break ().
4847 mono_debugger_agent_user_break (void)
4849 if (agent_config
.enabled
) {
4854 /* Obtain a context */
4855 MONO_CONTEXT_SET_IP (&ctx
, NULL
);
4856 mono_walk_stack_with_ctx (user_break_cb
, NULL
, 0, &ctx
);
4857 g_assert (MONO_CONTEXT_GET_IP (&ctx
) != NULL
);
4859 mono_loader_lock ();
4860 events
= create_event_list (EVENT_KIND_USER_BREAK
, NULL
, NULL
, NULL
, &suspend_policy
);
4861 mono_loader_unlock ();
4863 process_event (EVENT_KIND_USER_BREAK
, NULL
, 0, &ctx
, events
, suspend_policy
);
4870 ss_depth_to_string (StepDepth depth
)
4873 case STEP_DEPTH_OVER
:
4875 case STEP_DEPTH_OUT
:
4877 case STEP_DEPTH_INTO
:
4880 g_assert_not_reached ();
4886 process_single_step_inner (DebuggerTlsData
*tls
)
4891 int il_offset
, suspend_policy
;
4894 MonoContext
*ctx
= &tls
->restore_ctx
;
4897 MonoSeqPointInfo
*info
;
4899 ip
= MONO_CONTEXT_GET_IP (ctx
);
4901 /* Skip the instruction causing the single step */
4902 mono_arch_skip_single_step (ctx
);
4904 if (suspend_count
> 0) {
4905 process_suspend (tls
, ctx
);
4910 // FIXME: A suspend race
4913 if (mono_thread_internal_current () != ss_req
->thread
)
4916 if (log_level
> 0) {
4917 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4919 DEBUG (1, fprintf (log_file
, "[%p] Single step event (depth=%s) at %s (%p), sp %p, last sp %p\n", (gpointer
)GetCurrentThreadId (), ss_depth_to_string (ss_req
->depth
), mono_method_full_name (jinfo_get_method (ji
), TRUE
), MONO_CONTEXT_GET_IP (ctx
), MONO_CONTEXT_GET_SP (ctx
), ss_req
->last_sp
));
4922 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4924 method
= jinfo_get_method (ji
);
4927 if (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
4932 * Stopping in memset makes half-initialized vtypes visible.
4933 * Stopping in memcpy makes half-copied vtypes visible.
4935 if (method
->klass
== mono_defaults
.string_class
&& (!strcmp (method
->name
, "memset") || strstr (method
->name
, "memcpy")))
4939 * The ip points to the instruction causing the single step event, which is before
4940 * the offset recorded in the seq point map, so find the next seq point after ip.
4942 sp
= find_next_seq_point_for_native_offset (domain
, method
, (guint8
*)ip
- (guint8
*)ji
->code_start
, &info
);
4945 il_offset
= sp
->il_offset
;
4947 if (!ss_update (ss_req
, ji
, sp
, tls
, ctx
))
4950 /* Start single stepping again from the current sequence point */
4951 ss_start (ss_req
, method
, sp
, info
, ctx
, tls
, FALSE
);
4953 if ((ss_req
->filter
& STEP_FILTER_STATIC_CTOR
) &&
4954 (method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
4955 !strcmp (method
->name
, ".cctor"))
4958 // FIXME: Has to lock earlier
4960 reqs
= g_ptr_array_new ();
4962 mono_loader_lock ();
4964 g_ptr_array_add (reqs
, ss_req
->req
);
4966 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
4968 g_ptr_array_free (reqs
, TRUE
);
4970 mono_loader_unlock ();
4972 process_event (EVENT_KIND_STEP
, jinfo_get_method (ji
), il_offset
, ctx
, events
, suspend_policy
);
4976 process_single_step (void)
4978 process_signal_event (process_single_step_inner
);
4982 * mono_debugger_agent_single_step_event:
4984 * Called from a signal handler to handle a single step event.
4987 mono_debugger_agent_single_step_event (void *sigctx
)
4989 /* Resume to process_single_step through the signal context */
4991 // FIXME: Since step out/over is implemented using step in, the step in case should
4992 // be as fast as possible. Move the relevant code from process_single_step_inner ()
4995 if (GetCurrentThreadId () == debugger_thread_id
) {
4997 * This could happen despite our best effors when the runtime calls
4998 * assembly/type resolve hooks.
4999 * FIXME: Breakpoints too.
5003 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
5004 mono_arch_skip_single_step (&ctx
);
5005 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
5009 resume_from_signal_handler (sigctx
, process_single_step
);
5013 debugger_agent_single_step_from_context (MonoContext
*ctx
)
5015 DebuggerTlsData
*tls
;
5016 MonoContext orig_restore_ctx
;
5018 tls
= mono_native_tls_get_value (debugger_tls_id
);
5021 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
5022 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5023 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
5025 process_single_step_inner (tls
);
5027 memcpy (ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5028 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
5032 debugger_agent_breakpoint_from_context (MonoContext
*ctx
)
5034 DebuggerTlsData
*tls
;
5035 MonoContext orig_restore_ctx
;
5037 tls
= mono_native_tls_get_value (debugger_tls_id
);
5039 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5040 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
5042 process_breakpoint_inner (tls
);
5044 memcpy (ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5045 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
5049 * start_single_stepping:
5051 * Turn on single stepping. Can be called multiple times, for example,
5052 * by a single step event request + a suspend.
5055 start_single_stepping (void)
5057 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5058 int val
= InterlockedIncrement (&ss_count
);
5061 mono_arch_start_single_stepping ();
5063 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
5064 DebuggerTlsData
*tls
;
5066 mono_loader_lock ();
5068 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
5069 ss_invoke_addr
= tls
->invoke_addr
;
5071 mono_loader_unlock ();
5074 g_assert_not_reached ();
5079 stop_single_stepping (void)
5081 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5082 int val
= InterlockedDecrement (&ss_count
);
5085 mono_arch_stop_single_stepping ();
5087 ss_invoke_addr
= NULL
;
5089 g_assert_not_reached ();
5096 * Stop the single stepping operation given by SS_REQ.
5099 ss_stop (SingleStepReq
*ss_req
)
5104 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
5105 clear_breakpoint (l
->data
);
5107 g_slist_free (ss_req
->bps
);
5111 if (ss_req
->global
) {
5112 stop_single_stepping ();
5113 ss_req
->global
= FALSE
;
5120 * Start the single stepping operation given by SS_REQ from the sequence point SP.
5121 * If CTX is not set, then this can target any thread. If CTX is set, then TLS should
5122 * belong to the same thread as CTX.
5125 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
)
5127 int i
, j
, frame_index
;
5130 gboolean enable_global
= FALSE
;
5132 /* Stop the previous operation */
5136 * Implement single stepping using breakpoints if possible.
5138 if (step_to_catch
) {
5139 bp
= set_breakpoint (method
, sp
->il_offset
, ss_req
->req
, NULL
);
5140 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5144 if ((!sp
|| sp
->next_len
== 0 || ss_req
->depth
== STEP_DEPTH_OUT
|| ss_req
->depth
== STEP_DEPTH_OVER
) && ctx
) {
5145 /* Need parent frames */
5146 if (!tls
->context
.valid
)
5147 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
5148 compute_frame_info (tls
->thread
, tls
);
5152 * Find the first sequence point in the current or in a previous frame which
5153 * is not the last in its method.
5155 if (ss_req
->depth
== STEP_DEPTH_OUT
) {
5156 /* Ignore seq points in current method */
5157 while (frame_index
< tls
->frame_count
) {
5158 StackFrame
*frame
= tls
->frames
[frame_index
];
5160 method
= frame
->method
;
5161 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5163 if (sp
&& sp
->next_len
!= 0)
5166 // There could be method calls before the next seq point in the caller when using nested calls
5167 //enable_global = TRUE;
5169 if (sp
&& sp
->next_len
== 0) {
5171 while (frame_index
< tls
->frame_count
) {
5172 StackFrame
*frame
= tls
->frames
[frame_index
];
5174 method
= frame
->method
;
5175 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5176 if (sp
&& sp
->next_len
!= 0)
5184 if (sp
&& sp
->next_len
> 0) {
5185 for (i
= 0; i
< sp
->next_len
; ++i
) {
5186 next_sp
= &info
->seq_points
[sp
->next
[i
]];
5188 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
, NULL
);
5189 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5193 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
5194 if (ss_req
->nframes
== 0)
5195 ss_req
->nframes
= tls
->frame_count
;
5196 /* Need to stop in catch clauses as well */
5197 for (i
= 0; i
< tls
->frame_count
; ++i
) {
5198 StackFrame
*frame
= tls
->frames
[i
];
5201 MonoJitInfo
*jinfo
= frame
->ji
;
5202 for (j
= 0; j
< jinfo
->num_clauses
; ++j
) {
5203 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[j
];
5205 sp
= find_next_seq_point_for_native_offset (frame
->domain
, frame
->method
, (char*)ei
->handler_start
- (char*)jinfo
->code_start
, NULL
);
5207 bp
= set_breakpoint (frame
->method
, sp
->il_offset
, ss_req
->req
, NULL
);
5208 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5216 if (ss_req
->depth
== STEP_DEPTH_INTO
) {
5217 /* Enable global stepping so we stop at method entry too */
5218 enable_global
= TRUE
;
5222 * The ctx/frame info computed above will become invalid when we continue.
5224 tls
->context
.valid
= FALSE
;
5225 tls
->async_state
.valid
= FALSE
;
5226 invalidate_frames (tls
);
5229 if (enable_global
) {
5230 DEBUG (1, fprintf (log_file
, "[dbg] Turning on global single stepping.\n"));
5231 ss_req
->global
= TRUE
;
5232 start_single_stepping ();
5233 } else if (!ss_req
->bps
) {
5234 DEBUG (1, fprintf (log_file
, "[dbg] Turning on global single stepping.\n"));
5235 ss_req
->global
= TRUE
;
5236 start_single_stepping ();
5238 ss_req
->global
= FALSE
;
5243 * Start single stepping of thread THREAD
5246 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
5248 DebuggerTlsData
*tls
;
5249 MonoSeqPointInfo
*info
= NULL
;
5250 SeqPoint
*sp
= NULL
;
5251 MonoMethod
*method
= NULL
;
5252 MonoDebugMethodInfo
*minfo
;
5253 gboolean step_to_catch
= FALSE
;
5255 if (suspend_count
== 0)
5256 return ERR_NOT_SUSPENDED
;
5258 wait_for_suspend ();
5260 // FIXME: Multiple requests
5262 DEBUG (0, fprintf (log_file
, "Received a single step request while the previous one was still active.\n"));
5263 return ERR_NOT_IMPLEMENTED
;
5266 DEBUG (1, fprintf (log_file
, "[dbg] Starting single step of thread %p (depth=%s).\n", thread
, ss_depth_to_string (depth
)));
5268 ss_req
= g_new0 (SingleStepReq
, 1);
5270 ss_req
->thread
= thread
;
5271 ss_req
->size
= size
;
5272 ss_req
->depth
= depth
;
5275 mono_loader_lock ();
5276 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5277 mono_loader_unlock ();
5279 g_assert (tls
->context
.valid
);
5280 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->context
.ctx
);
5282 if (tls
->catch_state
.valid
) {
5284 StackFrameInfo frame
;
5285 MonoContext new_ctx
;
5286 MonoLMF
*lmf
= NULL
;
5289 * We are stopped at a throw site. Stepping should go to the catch site.
5292 /* Find the the jit info for the catch context */
5293 res
= mono_find_jit_info_ext (tls
->catch_state
.unwind_data
[MONO_UNWIND_DATA_DOMAIN
], thread
->jit_data
, NULL
, &tls
->catch_state
.ctx
, &new_ctx
, NULL
, &lmf
, NULL
, &frame
);
5295 g_assert (frame
.type
== FRAME_TYPE_MANAGED
);
5298 * Find the seq point corresponding to the landing site ip, which is the first seq
5301 sp
= find_next_seq_point_for_native_offset (frame
.domain
, frame
.method
, frame
.native_offset
, &info
);
5303 no_seq_points_found (frame
.method
);
5306 method
= frame
.method
;
5308 step_to_catch
= TRUE
;
5309 /* This make sure the seq point is not skipped by process_single_step () */
5310 ss_req
->last_sp
= NULL
;
5313 if (!step_to_catch
&& ss_req
->size
== STEP_SIZE_LINE
) {
5316 /* Compute the initial line info */
5317 compute_frame_info (thread
, tls
);
5319 if (tls
->frame_count
) {
5320 frame
= tls
->frames
[0];
5322 ss_req
->last_method
= frame
->method
;
5323 ss_req
->last_line
= -1;
5325 minfo
= mono_debug_lookup_method (frame
->method
);
5326 if (minfo
&& frame
->il_offset
!= -1) {
5327 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
5330 ss_req
->last_line
= loc
->row
;
5337 if (!step_to_catch
) {
5340 compute_frame_info (thread
, tls
);
5342 if (tls
->frame_count
) {
5343 frame
= tls
->frames
[0];
5345 if (!method
&& frame
->il_offset
!= -1) {
5346 /* FIXME: Sort the table and use a binary search */
5347 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5349 no_seq_points_found (frame
->method
);
5351 method
= frame
->method
;
5356 ss_start (ss_req
, method
, sp
, info
, &tls
->context
.ctx
, tls
, step_to_catch
);
5362 ss_destroy (SingleStepReq
*req
)
5365 g_assert (ss_req
== req
);
5374 * Called from metadata by the icall for System.Diagnostics.Debugger:Log ().
5377 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
5383 if (!agent_config
.enabled
)
5386 mono_loader_lock ();
5387 events
= create_event_list (EVENT_KIND_USER_LOG
, NULL
, NULL
, NULL
, &suspend_policy
);
5388 mono_loader_unlock ();
5391 ei
.category
= category
? mono_string_to_utf8 (category
) : NULL
;
5392 ei
.message
= message
? mono_string_to_utf8 (message
) : NULL
;
5394 process_event (EVENT_KIND_USER_LOG
, &ei
, 0, NULL
, events
, suspend_policy
);
5396 g_free (ei
.category
);
5397 g_free (ei
.message
);
5401 mono_debugger_agent_debug_log_is_enabled (void)
5403 /* Treat this as true even if there is no event request for EVENT_KIND_USER_LOG */
5404 return agent_config
.enabled
;
5407 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
5409 mono_debugger_agent_unhandled_exception (MonoException
*exc
)
5418 memset (&ei
, 0, sizeof (EventInfo
));
5419 ei
.exc
= (MonoObject
*)exc
;
5421 mono_loader_lock ();
5422 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, NULL
, &ei
, &suspend_policy
);
5423 mono_loader_unlock ();
5425 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, NULL
, events
, suspend_policy
);
5430 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
5431 MonoContext
*catch_ctx
)
5433 int i
, j
, suspend_policy
;
5435 MonoJitInfo
*ji
, *catch_ji
;
5437 DebuggerTlsData
*tls
= NULL
;
5439 if (thread_to_tls
!= NULL
) {
5440 MonoInternalThread
*thread
= mono_thread_internal_current ();
5442 mono_loader_lock ();
5443 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5444 mono_loader_unlock ();
5446 if (tls
&& tls
->abort_requested
)
5448 if (tls
&& tls
->disable_breakpoints
)
5452 memset (&ei
, 0, sizeof (EventInfo
));
5454 /* Just-In-Time debugging */
5456 if (agent_config
.onuncaught
&& !inited
) {
5457 finish_agent_init (FALSE
);
5460 * Send an unsolicited EXCEPTION event with a dummy request id.
5462 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
5463 ei
.exc
= (MonoObject
*)exc
;
5464 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
5467 } else if (agent_config
.onthrow
&& !inited
) {
5469 gboolean found
= FALSE
;
5471 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
5472 char *ex_type
= l
->data
;
5473 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
5475 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
5482 finish_agent_init (FALSE
);
5485 * Send an unsolicited EXCEPTION event with a dummy request id.
5487 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
5488 ei
.exc
= (MonoObject
*)exc
;
5489 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
5497 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
5499 catch_ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (catch_ctx
), NULL
);
5503 ei
.exc
= (MonoObject
*)exc
;
5504 ei
.caught
= catch_ctx
!= NULL
;
5506 mono_loader_lock ();
5508 /* Treat exceptions which are caught in non-user code as unhandled */
5509 for (i
= 0; i
< event_requests
->len
; ++i
) {
5510 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5511 if (req
->event_kind
!= EVENT_KIND_EXCEPTION
)
5514 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
5515 Modifier
*mod
= &req
->modifiers
[j
];
5517 if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& catch_ji
) {
5519 gboolean found
= FALSE
;
5520 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
5523 for (k
= 0; assemblies
[k
]; ++k
)
5524 if (assemblies
[k
] == jinfo_get_method (catch_ji
)->klass
->image
->assembly
)
5533 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
5534 mono_loader_unlock ();
5536 if (tls
&& ei
.caught
&& catch_ctx
) {
5537 memset (&tls
->catch_state
, 0, sizeof (tls
->catch_state
));
5538 tls
->catch_state
.ctx
= *catch_ctx
;
5539 tls
->catch_state
.unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
5540 tls
->catch_state
.valid
= TRUE
;
5543 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
5546 tls
->catch_state
.valid
= FALSE
;
5550 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
5552 DebuggerTlsData
*tls
;
5557 tls
= mono_native_tls_get_value (debugger_tls_id
);
5562 * We're about to invoke an exception filter during the first pass of exception handling.
5564 * 'ctx' is the context that'll get passed to the filter ('call_filter (ctx, ei->data.filter)'),
5565 * 'orig_ctx' is the context where the exception has been thrown.
5568 * See mcs/class/Mono.Debugger.Soft/Tests/dtest-excfilter.il for an example.
5570 * If we're stopped in Filter(), normal stack unwinding would first unwind to
5571 * the call site (line 37) and then continue to Main(), but it would never
5572 * include the throw site (line 32).
5574 * Since exception filters are invoked during the first pass of exception handling,
5575 * the stack frames of the throw site are still intact, so we should include them
5578 * We do this here by saving the context of the throw site in 'tls->filter_state'.
5580 * Exception filters are used by MonoDroid, where we want to stop inside a call filter,
5581 * but report the location of the 'throw' to the user.
5585 g_assert (mono_thread_state_init_from_monoctx (&tls
->filter_state
, orig_ctx
));
5589 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
5591 DebuggerTlsData
*tls
;
5596 tls
= mono_native_tls_get_value (debugger_tls_id
);
5600 tls
->filter_state
.valid
= FALSE
;
5604 * buffer_add_value_full:
5606 * Add the encoding of the value at ADDR described by T to the buffer.
5607 * AS_VTYPE determines whenever to treat primitive types as primitive types or
5611 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
5612 gboolean as_vtype
, GHashTable
*parent_vtypes
)
5615 gboolean boxed_vtype
= FALSE
;
5618 if (!(*(void**)addr
)) {
5619 /* This can happen with compiler generated locals */
5620 //printf ("%s\n", mono_type_full_name (t));
5621 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5624 g_assert (*(void**)addr
);
5625 addr
= *(void**)addr
;
5630 case MONO_TYPE_BOOLEAN
:
5633 case MONO_TYPE_CHAR
:
5653 case MONO_TYPE_VOID
:
5654 buffer_add_byte (buf
, t
->type
);
5656 case MONO_TYPE_BOOLEAN
:
5659 buffer_add_byte (buf
, t
->type
);
5660 buffer_add_int (buf
, *(gint8
*)addr
);
5662 case MONO_TYPE_CHAR
:
5665 buffer_add_byte (buf
, t
->type
);
5666 buffer_add_int (buf
, *(gint16
*)addr
);
5671 buffer_add_byte (buf
, t
->type
);
5672 buffer_add_int (buf
, *(gint32
*)addr
);
5677 buffer_add_byte (buf
, t
->type
);
5678 buffer_add_long (buf
, *(gint64
*)addr
);
5682 /* Treat it as a vtype */
5684 case MONO_TYPE_PTR
: {
5685 gssize val
= *(gssize
*)addr
;
5687 buffer_add_byte (buf
, t
->type
);
5688 buffer_add_long (buf
, val
);
5692 case MONO_TYPE_STRING
:
5693 case MONO_TYPE_SZARRAY
:
5694 case MONO_TYPE_OBJECT
:
5695 case MONO_TYPE_CLASS
:
5696 case MONO_TYPE_ARRAY
:
5697 obj
= *(MonoObject
**)addr
;
5700 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5702 if (obj
->vtable
->klass
->valuetype
) {
5703 t
= &obj
->vtable
->klass
->byval_arg
;
5704 addr
= mono_object_unbox (obj
);
5707 } else if (obj
->vtable
->klass
->rank
) {
5708 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
5709 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
5710 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
5712 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
5714 buffer_add_objid (buf
, obj
);
5718 case MONO_TYPE_VALUETYPE
: {
5722 MonoClass
*klass
= mono_class_from_mono_type (t
);
5727 * Handle boxed vtypes recursively referencing themselves using fields.
5730 parent_vtypes
= g_hash_table_new (NULL
, NULL
);
5731 vtype_index
= GPOINTER_TO_INT (g_hash_table_lookup (parent_vtypes
, addr
));
5733 if (CHECK_PROTOCOL_VERSION (2, 33)) {
5734 buffer_add_byte (buf
, VALUE_TYPE_ID_PARENT_VTYPE
);
5735 buffer_add_int (buf
, vtype_index
- 1);
5737 /* The client can't handle PARENT_VTYPE */
5738 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5742 g_hash_table_insert (parent_vtypes
, addr
, GINT_TO_POINTER (g_hash_table_size (parent_vtypes
) + 1));
5746 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
5747 buffer_add_byte (buf
, klass
->enumtype
);
5748 buffer_add_typeid (buf
, domain
, klass
);
5752 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5753 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5755 if (mono_field_is_deleted (f
))
5759 buffer_add_int (buf
, nfields
);
5762 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5763 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5765 if (mono_field_is_deleted (f
))
5767 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
, parent_vtypes
);
5771 g_hash_table_remove (parent_vtypes
, addr
);
5772 if (g_hash_table_size (parent_vtypes
) == 0) {
5773 g_hash_table_destroy (parent_vtypes
);
5774 parent_vtypes
= NULL
;
5779 case MONO_TYPE_GENERICINST
:
5780 if (mono_type_generic_inst_is_valuetype (t
)) {
5792 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
5794 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
, NULL
);
5798 obj_is_of_type (MonoObject
*obj
, MonoType
*t
)
5800 MonoClass
*klass
= obj
->vtable
->klass
;
5801 if (!mono_class_is_assignable_from (mono_class_from_mono_type (t
), klass
)) {
5802 if (mono_class_is_transparent_proxy (klass
)) {
5803 klass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
5804 if (mono_class_is_assignable_from (mono_class_from_mono_type (t
), klass
)) {
5814 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
);
5817 decode_vtype (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
5823 gpointer iter
= NULL
;
5827 is_enum
= decode_byte (buf
, &buf
, limit
);
5828 /* Enums are sent as a normal vtype */
5830 return ERR_NOT_IMPLEMENTED
;
5831 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
5835 if (t
&& klass
!= mono_class_from_mono_type (t
)) {
5836 char *name
= mono_type_full_name (t
);
5837 char *name2
= mono_type_full_name (&klass
->byval_arg
);
5838 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got %s.\n", (gpointer
)GetCurrentThreadId (), name
, name2
));
5841 return ERR_INVALID_ARGUMENT
;
5844 nfields
= decode_int (buf
, &buf
, limit
);
5845 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5846 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5848 if (mono_field_is_deleted (f
))
5850 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
5855 g_assert (nfields
== 0);
5863 decode_value_internal (MonoType
*t
, int type
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
5867 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
5868 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
5869 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
5870 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
5871 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
5872 char *name
= mono_type_full_name (t
);
5873 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
5875 return ERR_INVALID_ARGUMENT
;
5879 case MONO_TYPE_BOOLEAN
:
5880 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
5882 case MONO_TYPE_CHAR
:
5883 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
5886 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
5889 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
5892 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
5895 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
5898 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
5901 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
5904 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
5907 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
5910 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
5913 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
5916 /* We send these as I8, so we get them back as such */
5917 g_assert (type
== MONO_TYPE_I8
);
5918 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
5920 case MONO_TYPE_GENERICINST
:
5921 if (MONO_TYPE_ISSTRUCT (t
)) {
5922 /* The client sends these as a valuetype */
5930 /* We send these as vtypes, so we get them back as such */
5931 g_assert (type
== MONO_TYPE_VALUETYPE
);
5934 case MONO_TYPE_VALUETYPE
:
5935 err
= decode_vtype (t
, domain
, addr
,buf
, &buf
, limit
);
5941 if (MONO_TYPE_IS_REFERENCE (t
)) {
5942 if (type
== MONO_TYPE_OBJECT
) {
5943 int objid
= decode_objid (buf
, &buf
, limit
);
5947 err
= get_object (objid
, (MonoObject
**)&obj
);
5952 if (!obj_is_of_type (obj
, t
)) {
5953 DEBUG (1, fprintf (log_file
, "Expected type '%s', got '%s'\n", mono_type_full_name (t
), obj
->vtable
->klass
->name
));
5954 return ERR_INVALID_ARGUMENT
;
5957 if (obj
&& obj
->vtable
->domain
!= domain
)
5958 return ERR_INVALID_ARGUMENT
;
5960 mono_gc_wbarrier_generic_store (addr
, obj
);
5961 } else if (type
== VALUE_TYPE_ID_NULL
) {
5962 *(MonoObject
**)addr
= NULL
;
5963 } else if (type
== MONO_TYPE_VALUETYPE
) {
5971 /* This can happen when round-tripping boxed vtypes */
5973 * Obtain vtype class.
5974 * Same as the beginning of the handle_vtype case above.
5977 is_enum
= decode_byte (buf
, &buf
, limit
);
5979 return ERR_NOT_IMPLEMENTED
;
5980 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
5984 /* Decode the vtype into a temporary buffer, then box it. */
5985 vtype_buf_size
= mono_class_value_size (klass
, NULL
);
5986 vtype_buf
= g_malloc0 (vtype_buf_size
);
5987 g_assert (vtype_buf
);
5990 err
= decode_vtype (NULL
, domain
, vtype_buf
, buf
, &buf
, limit
);
5995 *(MonoObject
**)addr
= mono_value_box (d
, klass
, vtype_buf
);
5998 char *name
= mono_type_full_name (t
);
5999 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
6001 return ERR_INVALID_ARGUMENT
;
6015 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
6018 int type
= decode_byte (buf
, &buf
, limit
);
6020 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
6021 MonoType
*targ
= t
->data
.generic_class
->context
.class_inst
->type_argv
[0];
6022 guint8
*nullable_buf
;
6025 * First try decoding it as a Nullable`1
6027 err
= decode_value_internal (t
, type
, domain
, addr
, buf
, endbuf
, limit
);
6032 * Then try decoding as a primitive value or null.
6034 if (targ
->type
== type
) {
6035 nullable_buf
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (targ
)));
6036 err
= decode_value_internal (targ
, type
, domain
, nullable_buf
, buf
, endbuf
, limit
);
6038 g_free (nullable_buf
);
6041 mono_nullable_init (addr
, mono_value_box (domain
, mono_class_from_mono_type (targ
), nullable_buf
), mono_class_from_mono_type (t
));
6042 g_free (nullable_buf
);
6045 } else if (type
== VALUE_TYPE_ID_NULL
) {
6046 mono_nullable_init (addr
, NULL
, mono_class_from_mono_type (t
));
6052 return decode_value_internal (t
, type
, domain
, addr
, buf
, endbuf
, limit
);
6056 add_var (Buffer
*buf
, MonoDebugMethodJitInfo
*jit
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
6060 guint8
*addr
, *gaddr
;
6063 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6064 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6067 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
6068 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
6070 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
, NULL
);
6072 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
6073 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6074 addr
+= (gint32
)var
->offset
;
6076 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
6078 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
, NULL
);
6080 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
6083 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR
:
6084 case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR
:
6085 /* Same as regoffset, but with an indirection */
6086 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6087 addr
+= (gint32
)var
->offset
;
6089 gaddr
= *(gpointer
*)addr
;
6091 buffer_add_value_full (buf
, t
, gaddr
, domain
, as_vtype
, NULL
);
6093 case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL
: {
6094 MonoDebugVarInfo
*info_var
= jit
->gsharedvt_info_var
;
6095 MonoDebugVarInfo
*locals_var
= jit
->gsharedvt_locals_var
;
6096 MonoGSharedVtMethodRuntimeInfo
*info
;
6102 g_assert (info_var
);
6103 g_assert (locals_var
);
6105 flags
= info_var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6106 reg
= info_var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6107 if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
) {
6108 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6109 addr
+= (gint32
)info_var
->offset
;
6110 info
= *(gpointer
*)addr
;
6111 } else if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
) {
6112 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6114 g_assert_not_reached ();
6118 flags
= locals_var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6119 reg
= locals_var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6120 if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
) {
6121 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6122 addr
+= (gint32
)locals_var
->offset
;
6123 locals
= *(gpointer
*)addr
;
6124 } else if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
) {
6125 locals
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6127 g_assert_not_reached ();
6131 addr
= locals
+ GPOINTER_TO_INT (info
->entries
[idx
]);
6133 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
, NULL
);
6138 g_assert_not_reached ();
6143 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
, mgreg_t
**reg_locations
, MonoContext
*restore_ctx
)
6147 guint8
*addr
, *gaddr
;
6149 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6150 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6152 if (MONO_TYPE_IS_REFERENCE (t
))
6153 size
= sizeof (gpointer
);
6155 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
6158 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
: {
6159 #ifdef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
6161 gboolean is_signed
= FALSE
;
6164 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6167 // FIXME: Write barriers
6168 mono_gc_memmove_atomic (addr
, val
, size
);
6173 if (!t
->byref
&& (t
->type
== MONO_TYPE_I1
|| t
->type
== MONO_TYPE_I2
|| t
->type
== MONO_TYPE_I4
|| t
->type
== MONO_TYPE_I8
))
6178 v
= is_signed
? *(gint8
*)val
: *(guint8
*)val
;
6181 v
= is_signed
? *(gint16
*)val
: *(guint16
*)val
;
6184 v
= is_signed
? *(gint32
*)val
: *(guint32
*)val
;
6187 v
= is_signed
? *(gint64
*)val
: *(guint64
*)val
;
6190 g_assert_not_reached ();
6193 /* Set value on the stack or in the return ctx */
6194 if (reg_locations
[reg
]) {
6195 /* Saved on the stack */
6196 DEBUG (1, fprintf (log_file
, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations
[reg
], reg
, (gpointer
)v
));
6197 *(reg_locations
[reg
]) = v
;
6200 DEBUG (1, fprintf (log_file
, "[dbg] Setting context location for reg %x to %p.\n", reg
, (gpointer
)v
));
6201 mono_arch_context_set_int_reg (restore_ctx
, reg
, v
);
6204 // FIXME: Move these to mono-context.h/c.
6205 mono_arch_context_set_int_reg (ctx
, reg
, v
);
6207 // FIXME: Can't set registers, so we disable linears
6212 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
6213 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6214 addr
+= (gint32
)var
->offset
;
6216 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
6219 addr
= *(guint8
**)addr
;
6225 // FIXME: Write barriers
6226 mono_gc_memmove_atomic (addr
, val
, size
);
6228 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR
:
6229 /* Same as regoffset, but with an indirection */
6230 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6231 addr
+= (gint32
)var
->offset
;
6233 gaddr
= *(gpointer
*)addr
;
6235 // FIXME: Write barriers
6236 mono_gc_memmove_atomic (gaddr
, val
, size
);
6238 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
6242 g_assert_not_reached ();
6247 clear_event_request (int req_id
, int etype
)
6251 mono_loader_lock ();
6252 for (i
= 0; i
< event_requests
->len
; ++i
) {
6253 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
6255 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
6256 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
6257 clear_breakpoint (req
->info
);
6258 if (req
->event_kind
== EVENT_KIND_STEP
)
6259 ss_destroy (req
->info
);
6260 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
6261 clear_breakpoint (req
->info
);
6262 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
6263 clear_breakpoint (req
->info
);
6264 g_ptr_array_remove_index_fast (event_requests
, i
);
6269 mono_loader_unlock ();
6273 event_req_matches_assembly (EventRequest
*req
, MonoAssembly
*assembly
)
6275 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
6276 return breakpoint_matches_assembly (req
->info
, assembly
);
6280 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
6281 Modifier
*m
= &req
->modifiers
[i
];
6283 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
6285 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
6286 for (j
= 0; m
->data
.assemblies
[j
]; ++j
)
6287 if (m
->data
.assemblies
[j
] == assembly
)
6297 * clear_event_requests_for_assembly:
6299 * Clear all events requests which reference ASSEMBLY.
6302 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
6307 mono_loader_lock ();
6311 for (i
= 0; i
< event_requests
->len
; ++i
) {
6312 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
6314 if (event_req_matches_assembly (req
, assembly
)) {
6315 clear_event_request (req
->id
, req
->event_kind
);
6321 mono_loader_unlock ();
6325 * type_comes_from_assembly:
6327 * GHRFunc that returns TRUE if klass comes from assembly
6330 type_comes_from_assembly (gpointer klass
, gpointer also_klass
, gpointer assembly
)
6332 return (mono_class_get_image ((MonoClass
*)klass
) == mono_assembly_get_image ((MonoAssembly
*)assembly
));
6336 * clear_types_for_assembly:
6338 * Clears types from loaded_classes for a given assembly
6341 clear_types_for_assembly (MonoAssembly
*assembly
)
6343 MonoDomain
*domain
= mono_domain_get ();
6344 AgentDomainInfo
*info
= NULL
;
6346 mono_loader_lock ();
6347 info
= get_agent_domain_info (domain
);
6348 g_hash_table_foreach_remove (info
->loaded_classes
, type_comes_from_assembly
, assembly
);
6349 mono_loader_unlock ();
6353 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
6355 MonoInternalThread
*thread
= value
;
6356 Buffer
*buf
= user_data
;
6358 buffer_add_objid (buf
, (MonoObject
*)thread
);
6362 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
, guint8
*p
, guint8
**endp
)
6364 guint8
*end
= invoke
->endp
;
6367 MonoMethodSignature
*sig
;
6370 MonoObject
*this, *res
, *exc
;
6373 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6376 MonoStopwatch watch
;
6378 if (invoke
->method
) {
6380 * Invoke this method directly, currently only Environment.Exit () is supported.
6383 DEBUG (1, fprintf (log_file
, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (invoke
->method
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
6384 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
6385 g_assert_not_reached ();
6388 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
6391 sig
= mono_method_signature (m
);
6393 if (m
->klass
->valuetype
)
6394 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
6396 this_buf
= g_alloca (sizeof (MonoObject
*));
6397 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
6398 /* Should be null */
6399 int type
= decode_byte (p
, &p
, end
);
6400 if (type
!= VALUE_TYPE_ID_NULL
) {
6401 DEBUG (1, fprintf (log_file
, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer
)GetCurrentThreadId ()));
6402 return ERR_INVALID_ARGUMENT
;
6404 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
6406 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
6411 if (!m
->klass
->valuetype
)
6412 this = *(MonoObject
**)this_buf
;
6416 if (MONO_CLASS_IS_INTERFACE (m
->klass
)) {
6418 DEBUG (1, fprintf (log_file
, "[%p] Error: Interface method invoked without this argument.\n", (gpointer
)GetCurrentThreadId ()));
6419 return ERR_INVALID_ARGUMENT
;
6421 m
= mono_object_get_virtual_method (this, m
);
6424 DEBUG (1, fprintf (log_file
, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer
)GetCurrentThreadId (), mono_method_full_name (m
, TRUE
), this ? this->vtable
->klass
->name
: "<null>"));
6426 if (this && this->vtable
->domain
!= domain
)
6429 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
6430 if (!strcmp (m
->name
, ".ctor")) {
6431 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
6432 return ERR_INVALID_ARGUMENT
;
6434 this = mono_object_new (domain
, m
->klass
);
6436 return ERR_INVALID_ARGUMENT
;
6440 if (this && !obj_is_of_type (this, &m
->klass
->byval_arg
))
6441 return ERR_INVALID_ARGUMENT
;
6443 nargs
= decode_int (p
, &p
, end
);
6444 if (nargs
!= sig
->param_count
)
6445 return ERR_INVALID_ARGUMENT
;
6446 /* Use alloca to get gc tracking */
6447 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
6448 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
6449 args
= g_alloca (nargs
* sizeof (gpointer
));
6450 for (i
= 0; i
< nargs
; ++i
) {
6451 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
6452 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
6456 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
6459 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
6460 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
6463 args
[i
] = arg_buf
[i
];
6470 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
6471 tls
->disable_breakpoints
= TRUE
;
6473 tls
->disable_breakpoints
= FALSE
;
6476 * Add an LMF frame to link the stack frames on the invoke method with our caller.
6478 /* FIXME: Move this to arch specific code */
6479 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6480 if (invoke
->has_ctx
) {
6483 lmf_addr
= mono_get_lmf_addr ();
6486 memset (&ext
, 0, sizeof (ext
));
6487 mono_arch_init_lmf_ext (&ext
, *lmf_addr
);
6489 ext
.debugger_invoke
= TRUE
;
6490 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
6492 mono_set_lmf ((MonoLMF
*)&ext
);
6496 mono_stopwatch_start (&watch
);
6497 if (m
->klass
->valuetype
)
6498 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
6500 res
= mono_runtime_invoke (m
, this, args
, &exc
);
6501 mono_stopwatch_stop (&watch
);
6502 DEBUG (1, fprintf (log_file
, "[%p] Invoke result: %p, exc: %s, time: %ld ms.\n", (gpointer
)GetCurrentThreadId (), res
, exc
? exc
->vtable
->klass
->name
: NULL
, (long)mono_stopwatch_elapsed_ms (&watch
)));
6504 buffer_add_byte (buf
, 0);
6505 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
6507 buffer_add_byte (buf
, 1);
6508 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
6509 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
6510 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
6513 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
6514 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
6515 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
6516 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
|| sig
->ret
->type
== MONO_TYPE_PTR
|| sig
->ret
->type
== MONO_TYPE_FNPTR
) {
6517 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->ret
))) {
6518 MonoClass
*k
= mono_class_from_mono_type (sig
->ret
);
6519 guint8
*nullable_buf
= g_alloca (mono_class_value_size (k
, NULL
));
6521 g_assert (nullable_buf
);
6522 mono_nullable_init (nullable_buf
, res
, k
);
6523 buffer_add_value (buf
, sig
->ret
, nullable_buf
, domain
);
6526 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
6533 tls
->disable_breakpoints
= FALSE
;
6535 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6536 if (invoke
->has_ctx
)
6537 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
6541 // FIXME: byref arguments
6549 * Invoke the method given by tls->pending_invoke in the current thread.
6552 invoke_method (void)
6554 DebuggerTlsData
*tls
;
6559 MonoContext restore_ctx
;
6562 tls
= mono_native_tls_get_value (debugger_tls_id
);
6566 * Store the `InvokeData *' in `tls->invoke' until we're done with
6567 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
6570 mono_loader_lock ();
6572 invoke
= tls
->pending_invoke
;
6574 tls
->pending_invoke
= NULL
;
6576 invoke
->last_invoke
= tls
->invoke
;
6577 tls
->invoke
= invoke
;
6579 mono_loader_unlock ();
6581 tls
->frames_up_to_date
= FALSE
;
6587 for (mindex
= 0; mindex
< invoke
->nmethods
; ++mindex
) {
6588 buffer_init (&buf
, 128);
6591 /* Fail the other invokes as well */
6593 err
= do_invoke_method (tls
, &buf
, invoke
, p
, &p
);
6596 /* Start suspending before sending the reply */
6597 if (mindex
== invoke
->nmethods
- 1) {
6598 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
)) {
6599 for (i
= 0; i
< invoke
->suspend_count
; ++i
)
6604 send_reply_packet (id
, err
, &buf
);
6609 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
6611 if (invoke
->has_ctx
)
6612 save_thread_context (&restore_ctx
);
6614 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
6615 g_assert (tls
->resume_count
);
6616 tls
->resume_count
-= invoke
->suspend_count
;
6619 DEBUG (1, fprintf (log_file
, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), err
, tls
->resume_count
));
6622 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
6624 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
6625 * after the mono_runtime_invoke() already returned, but it doesn't matter
6626 * because we reset the abort here.
6629 mono_loader_lock ();
6631 if (tls
->abort_requested
)
6632 mono_thread_internal_reset_abort (tls
->thread
);
6634 tls
->invoke
= tls
->invoke
->last_invoke
;
6635 tls
->abort_requested
= FALSE
;
6637 mono_loader_unlock ();
6646 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
6648 MonoThread
*thread
= value
;
6649 DebuggerTlsData
*tls
;
6652 mono_loader_lock ();
6653 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6655 res
= tls
->really_suspended
;
6656 mono_loader_unlock ();
6662 get_source_files_for_type (MonoClass
*klass
)
6664 gpointer iter
= NULL
;
6666 MonoDebugSourceInfo
*sinfo
;
6670 files
= g_ptr_array_new ();
6672 while ((method
= mono_class_get_methods (klass
, &iter
))) {
6673 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
6674 GPtrArray
*source_file_list
;
6677 mono_debug_symfile_get_line_numbers_full (minfo
, NULL
, &source_file_list
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
6678 for (j
= 0; j
< source_file_list
->len
; ++j
) {
6679 sinfo
= g_ptr_array_index (source_file_list
, j
);
6680 for (i
= 0; i
< files
->len
; ++i
)
6681 if (!strcmp (g_ptr_array_index (files
, i
), sinfo
->source_file
))
6683 if (i
== files
->len
)
6684 g_ptr_array_add (files
, g_strdup (sinfo
->source_file
));
6686 g_ptr_array_free (source_file_list
, TRUE
);
6694 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6697 case CMD_VM_VERSION
: {
6698 char *build_info
, *version
;
6700 build_info
= mono_get_runtime_build_info ();
6701 version
= g_strdup_printf ("mono %s", build_info
);
6703 buffer_add_string (buf
, version
); /* vm version */
6704 buffer_add_int (buf
, MAJOR_VERSION
);
6705 buffer_add_int (buf
, MINOR_VERSION
);
6706 g_free (build_info
);
6710 case CMD_VM_SET_PROTOCOL_VERSION
: {
6711 major_version
= decode_int (p
, &p
, end
);
6712 minor_version
= decode_int (p
, &p
, end
);
6713 protocol_version_set
= TRUE
;
6714 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
6717 case CMD_VM_ALL_THREADS
: {
6719 mono_loader_lock ();
6720 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
6721 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
6722 mono_loader_unlock ();
6725 case CMD_VM_SUSPEND
:
6727 wait_for_suspend ();
6730 if (suspend_count
== 0)
6731 return ERR_NOT_SUSPENDED
;
6733 clear_suspended_objs ();
6735 case CMD_VM_DISPOSE
:
6736 /* Clear all event requests */
6737 mono_loader_lock ();
6738 while (event_requests
->len
> 0) {
6739 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
6741 clear_event_request (req
->id
, req
->event_kind
);
6743 mono_loader_unlock ();
6745 while (suspend_count
> 0)
6747 disconnected
= TRUE
;
6748 vm_start_event_sent
= FALSE
;
6751 MonoInternalThread
*thread
;
6752 DebuggerTlsData
*tls
;
6753 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6754 MonoClass
*env_class
;
6756 MonoMethod
*exit_method
= NULL
;
6760 exit_code
= decode_int (p
, &p
, end
);
6762 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
6764 /* Have to send a reply before exiting */
6765 send_reply_packet (id
, 0, buf
);
6767 /* Clear all event requests */
6768 mono_loader_lock ();
6769 while (event_requests
->len
> 0) {
6770 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
6772 clear_event_request (req
->id
, req
->event_kind
);
6774 mono_loader_unlock ();
6777 * The JDWP documentation says that the shutdown is not orderly. It doesn't
6778 * specify whenever a VM_DEATH event is sent. We currently do an orderly
6779 * shutdown by hijacking a thread to execute Environment.Exit (). This is
6780 * better than doing the shutdown ourselves, since it avoids various races.
6784 wait_for_suspend ();
6786 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6787 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
6789 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
6792 mono_loader_lock ();
6793 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
6794 mono_loader_unlock ();
6796 if (thread
&& exit_method
) {
6797 mono_loader_lock ();
6798 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6799 mono_loader_unlock ();
6801 args
= g_new0 (gpointer
, 1);
6802 args
[0] = g_malloc (sizeof (int));
6803 *(int*)(args
[0]) = exit_code
;
6805 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
6806 tls
->pending_invoke
->method
= exit_method
;
6807 tls
->pending_invoke
->args
= args
;
6808 tls
->pending_invoke
->nmethods
= 1;
6810 while (suspend_count
> 0)
6814 * No thread found, do it ourselves.
6815 * FIXME: This can race with normal shutdown etc.
6817 while (suspend_count
> 0)
6820 if (!mono_runtime_try_shutdown ())
6823 mono_environment_exitcode_set (exit_code
);
6825 /* Suspend all managed threads since the runtime is going away */
6826 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
6827 mono_thread_suspend_all_other_threads ();
6828 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
6829 mono_runtime_quit ();
6830 transport_close2 ();
6831 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
6837 case CMD_VM_INVOKE_METHOD
:
6838 case CMD_VM_INVOKE_METHODS
: {
6839 int objid
= decode_objid (p
, &p
, end
);
6841 DebuggerTlsData
*tls
;
6842 int i
, count
, err
, flags
, nmethods
;
6844 err
= get_object (objid
, (MonoObject
**)&thread
);
6848 flags
= decode_int (p
, &p
, end
);
6850 if (command
== CMD_VM_INVOKE_METHODS
)
6851 nmethods
= decode_int (p
, &p
, end
);
6855 // Wait for suspending if it already started
6857 wait_for_suspend ();
6858 if (!is_suspended ())
6859 return ERR_NOT_SUSPENDED
;
6861 mono_loader_lock ();
6862 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
6863 mono_loader_unlock ();
6866 if (!tls
->really_suspended
)
6867 /* The thread is still running native code, can't do invokes */
6868 return ERR_NOT_SUSPENDED
;
6871 * Store the invoke data into tls, the thread will execute it after it is
6874 if (tls
->pending_invoke
)
6875 return ERR_NOT_SUSPENDED
;
6876 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
6877 tls
->pending_invoke
->id
= id
;
6878 tls
->pending_invoke
->flags
= flags
;
6879 tls
->pending_invoke
->p
= g_malloc (end
- p
);
6880 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
6881 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
6882 tls
->pending_invoke
->suspend_count
= suspend_count
;
6883 tls
->pending_invoke
->nmethods
= nmethods
;
6885 if (flags
& INVOKE_FLAG_SINGLE_THREADED
) {
6886 resume_thread (THREAD_TO_INTERNAL (thread
));
6889 count
= suspend_count
;
6890 for (i
= 0; i
< count
; ++i
)
6895 case CMD_VM_ABORT_INVOKE
: {
6896 int objid
= decode_objid (p
, &p
, end
);
6898 DebuggerTlsData
*tls
;
6901 err
= get_object (objid
, (MonoObject
**)&thread
);
6905 invoke_id
= decode_int (p
, &p
, end
);
6907 mono_loader_lock ();
6908 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
6911 if (tls
->abort_requested
) {
6912 mono_loader_unlock ();
6917 * Check whether we're still inside the mono_runtime_invoke() and that it's
6918 * actually the correct invocation.
6920 * Careful, we do not stop the thread that's doing the invocation, so we can't
6921 * inspect its stack. However, invoke_method() also acquires the loader lock
6922 * when it's done, so we're safe here.
6926 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
6927 mono_loader_unlock ();
6928 return ERR_NO_INVOCATION
;
6931 tls
->abort_requested
= TRUE
;
6933 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
6934 mono_loader_unlock ();
6938 case CMD_VM_SET_KEEPALIVE
: {
6939 int timeout
= decode_int (p
, &p
, end
);
6940 agent_config
.keepalive
= timeout
;
6942 #ifndef DISABLE_SOCKET_TRANSPORT
6949 case CMD_VM_GET_TYPES_FOR_SOURCE_FILE
: {
6950 GHashTableIter iter
, kiter
;
6955 char *fname
, *basename
;
6956 gboolean ignore_case
;
6957 GSList
*class_list
, *l
;
6958 GPtrArray
*res_classes
, *res_domains
;
6960 fname
= decode_string (p
, &p
, end
);
6961 ignore_case
= decode_byte (p
, &p
, end
);
6963 basename
= g_path_get_basename (fname
);
6965 res_classes
= g_ptr_array_new ();
6966 res_domains
= g_ptr_array_new ();
6968 mono_loader_lock ();
6969 g_hash_table_iter_init (&iter
, domains
);
6970 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&domain
)) {
6971 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
6973 /* Update 'source_file_to_class' cache */
6974 g_hash_table_iter_init (&kiter
, info
->loaded_classes
);
6975 while (g_hash_table_iter_next (&kiter
, NULL
, (void**)&klass
)) {
6976 if (!g_hash_table_lookup (info
->source_files
, klass
)) {
6977 files
= get_source_files_for_type (klass
);
6978 g_hash_table_insert (info
->source_files
, klass
, files
);
6980 for (i
= 0; i
< files
->len
; ++i
) {
6981 char *s
= g_ptr_array_index (files
, i
);
6982 char *s2
= g_path_get_basename (s
);
6985 class_list
= g_hash_table_lookup (info
->source_file_to_class
, s2
);
6987 class_list
= g_slist_prepend (class_list
, klass
);
6988 g_hash_table_insert (info
->source_file_to_class
, g_strdup (s2
), class_list
);
6990 class_list
= g_slist_prepend (class_list
, klass
);
6991 g_hash_table_insert (info
->source_file_to_class
, s2
, class_list
);
6994 /* The _ignorecase hash contains the lowercase path */
6995 s3
= strdup_tolower (s2
);
6996 class_list
= g_hash_table_lookup (info
->source_file_to_class_ignorecase
, s3
);
6998 class_list
= g_slist_prepend (class_list
, klass
);
6999 g_hash_table_insert (info
->source_file_to_class_ignorecase
, g_strdup (s3
), class_list
);
7001 class_list
= g_slist_prepend (class_list
, klass
);
7002 g_hash_table_insert (info
->source_file_to_class_ignorecase
, s3
, class_list
);
7014 s
= strdup_tolower (basename
);
7015 class_list
= g_hash_table_lookup (info
->source_file_to_class_ignorecase
, s
);
7018 class_list
= g_hash_table_lookup (info
->source_file_to_class
, basename
);
7021 for (l
= class_list
; l
; l
= l
->next
) {
7024 g_ptr_array_add (res_classes
, klass
);
7025 g_ptr_array_add (res_domains
, domain
);
7028 mono_loader_unlock ();
7033 buffer_add_int (buf
, res_classes
->len
);
7034 for (i
= 0; i
< res_classes
->len
; ++i
)
7035 buffer_add_typeid (buf
, g_ptr_array_index (res_domains
, i
), g_ptr_array_index (res_classes
, i
));
7036 g_ptr_array_free (res_classes
, TRUE
);
7037 g_ptr_array_free (res_domains
, TRUE
);
7040 case CMD_VM_GET_TYPES
: {
7041 GHashTableIter iter
;
7045 gboolean ignore_case
;
7046 GPtrArray
*res_classes
, *res_domains
;
7047 MonoTypeNameParse info
;
7049 name
= decode_string (p
, &p
, end
);
7050 ignore_case
= decode_byte (p
, &p
, end
);
7052 if (!mono_reflection_parse_type (name
, &info
)) {
7054 mono_reflection_free_type_info (&info
);
7055 return ERR_INVALID_ARGUMENT
;
7058 res_classes
= g_ptr_array_new ();
7059 res_domains
= g_ptr_array_new ();
7061 mono_loader_lock ();
7062 g_hash_table_iter_init (&iter
, domains
);
7063 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&domain
)) {
7065 gboolean type_resolve
;
7069 mono_domain_assemblies_lock (domain
);
7070 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7074 type_resolve
= TRUE
;
7075 t
= mono_reflection_get_type (ass
->image
, &info
, ignore_case
, &type_resolve
);
7077 g_ptr_array_add (res_classes
, mono_type_get_class (t
));
7078 g_ptr_array_add (res_domains
, domain
);
7082 mono_domain_assemblies_unlock (domain
);
7084 mono_loader_unlock ();
7087 mono_reflection_free_type_info (&info
);
7089 buffer_add_int (buf
, res_classes
->len
);
7090 for (i
= 0; i
< res_classes
->len
; ++i
)
7091 buffer_add_typeid (buf
, g_ptr_array_index (res_domains
, i
), g_ptr_array_index (res_classes
, i
));
7092 g_ptr_array_free (res_classes
, TRUE
);
7093 g_ptr_array_free (res_domains
, TRUE
);
7096 case CMD_VM_START_BUFFERING
:
7097 case CMD_VM_STOP_BUFFERING
:
7098 /* Handled in the main loop */
7101 return ERR_NOT_IMPLEMENTED
;
7108 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7114 case CMD_EVENT_REQUEST_SET
: {
7116 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
7119 MonoThread
*step_thread
;
7120 int size
= 0, depth
= 0, filter
= 0, step_thread_id
= 0;
7124 event_kind
= decode_byte (p
, &p
, end
);
7125 suspend_policy
= decode_byte (p
, &p
, end
);
7126 nmodifiers
= decode_byte (p
, &p
, end
);
7128 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
7129 req
->id
= InterlockedIncrement (&event_request_id
);
7130 req
->event_kind
= event_kind
;
7131 req
->suspend_policy
= suspend_policy
;
7132 req
->nmodifiers
= nmodifiers
;
7135 for (i
= 0; i
< nmodifiers
; ++i
) {
7136 mod
= decode_byte (p
, &p
, end
);
7138 req
->modifiers
[i
].kind
= mod
;
7139 if (mod
== MOD_KIND_COUNT
) {
7140 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
7141 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
7142 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
7145 location
= decode_long (p
, &p
, end
);
7146 } else if (mod
== MOD_KIND_STEP
) {
7147 step_thread_id
= decode_id (p
, &p
, end
);
7148 size
= decode_int (p
, &p
, end
);
7149 depth
= decode_int (p
, &p
, end
);
7150 if (CHECK_PROTOCOL_VERSION (2, 16))
7151 filter
= decode_int (p
, &p
, end
);
7152 req
->modifiers
[i
].data
.filter
= filter
;
7153 if (!CHECK_PROTOCOL_VERSION (2, 26) && (req
->modifiers
[i
].data
.filter
& STEP_FILTER_DEBUGGER_HIDDEN
))
7154 /* Treat STEP_THOUGH the same as HIDDEN */
7155 req
->modifiers
[i
].data
.filter
|= STEP_FILTER_DEBUGGER_STEP_THROUGH
;
7156 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
7157 int id
= decode_id (p
, &p
, end
);
7159 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
7164 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
7165 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
7169 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
7170 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
7171 if (CHECK_PROTOCOL_VERSION (2, 25))
7172 req
->modifiers
[i
].subclasses
= decode_byte (p
, &p
, end
);
7174 req
->modifiers
[i
].subclasses
= TRUE
;
7175 DEBUG(1, fprintf (log_file
, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class
? exc_class
->name
: "all", req
->modifiers
[i
].caught
? ", caught" : "", req
->modifiers
[i
].uncaught
? ", uncaught" : "", req
->modifiers
[i
].subclasses
? ", include-subclasses" : ""));
7177 req
->modifiers
[i
].data
.exc_class
= exc_class
;
7179 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
7181 return ERR_INVALID_ARGUMENT
;
7184 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
7185 int n
= decode_int (p
, &p
, end
);
7188 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
7189 for (j
= 0; j
< n
; ++j
) {
7190 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
7192 g_free (req
->modifiers
[i
].data
.assemblies
);
7196 } else if (mod
== MOD_KIND_SOURCE_FILE_ONLY
) {
7197 int n
= decode_int (p
, &p
, end
);
7200 modifier
= &req
->modifiers
[i
];
7201 modifier
->data
.source_files
= g_hash_table_new (g_str_hash
, g_str_equal
);
7202 for (j
= 0; j
< n
; ++j
) {
7203 char *s
= decode_string (p
, &p
, end
);
7207 s2
= strdup_tolower (s
);
7208 g_hash_table_insert (modifier
->data
.source_files
, s2
, s2
);
7212 } else if (mod
== MOD_KIND_TYPE_NAME_ONLY
) {
7213 int n
= decode_int (p
, &p
, end
);
7216 modifier
= &req
->modifiers
[i
];
7217 modifier
->data
.type_names
= g_hash_table_new (g_str_hash
, g_str_equal
);
7218 for (j
= 0; j
< n
; ++j
) {
7219 char *s
= decode_string (p
, &p
, end
);
7222 g_hash_table_insert (modifier
->data
.type_names
, s
, s
);
7226 return ERR_NOT_IMPLEMENTED
;
7230 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
7233 req
->info
= set_breakpoint (method
, location
, req
, &error
);
7234 if (!mono_error_ok (&error
)) {
7236 DEBUG(1, fprintf (log_file
, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (&error
)));
7237 mono_error_cleanup (&error
);
7238 return ERR_NO_SEQ_POINT_AT_IL_OFFSET
;
7240 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
7241 g_assert (step_thread_id
);
7243 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
7249 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
7254 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
7255 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
, NULL
);
7256 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
7257 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
, NULL
);
7258 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
7259 } else if (req
->event_kind
== EVENT_KIND_TYPE_LOAD
) {
7261 if (req
->nmodifiers
) {
7263 return ERR_NOT_IMPLEMENTED
;
7267 mono_loader_lock ();
7268 g_ptr_array_add (event_requests
, req
);
7270 if (agent_config
.defer
) {
7271 /* Transmit cached data to the client on receipt of the event request */
7272 switch (req
->event_kind
) {
7273 case EVENT_KIND_APPDOMAIN_CREATE
:
7274 /* Emit load events for currently loaded domains */
7275 g_hash_table_foreach (domains
, emit_appdomain_load
, NULL
);
7277 case EVENT_KIND_ASSEMBLY_LOAD
:
7278 /* Emit load events for currently loaded assemblies */
7279 mono_assembly_foreach (emit_assembly_load
, NULL
);
7281 case EVENT_KIND_THREAD_START
:
7282 /* Emit start events for currently started threads */
7283 mono_g_hash_table_foreach (tid_to_thread
, emit_thread_start
, NULL
);
7285 case EVENT_KIND_TYPE_LOAD
:
7286 /* Emit type load events for currently loaded types */
7287 mono_domain_foreach (send_types_for_domain
, NULL
);
7293 mono_loader_unlock ();
7295 buffer_add_int (buf
, req
->id
);
7298 case CMD_EVENT_REQUEST_CLEAR
: {
7299 int etype
= decode_byte (p
, &p
, end
);
7300 int req_id
= decode_int (p
, &p
, end
);
7302 // FIXME: Make a faster mapping from req_id to request
7303 mono_loader_lock ();
7304 clear_event_request (req_id
, etype
);
7305 mono_loader_unlock ();
7308 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
7311 mono_loader_lock ();
7313 while (i
< event_requests
->len
) {
7314 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
7316 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
7317 clear_breakpoint (req
->info
);
7319 g_ptr_array_remove_index_fast (event_requests
, i
);
7325 mono_loader_unlock ();
7329 return ERR_NOT_IMPLEMENTED
;
7336 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7342 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
7343 buffer_add_domainid (buf
, mono_get_root_domain ());
7346 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
7347 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7350 buffer_add_string (buf
, domain
->friendly_name
);
7353 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
7358 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7361 mono_loader_lock ();
7363 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7366 buffer_add_int (buf
, count
);
7367 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7369 buffer_add_assemblyid (buf
, domain
, ass
);
7371 mono_loader_unlock ();
7374 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
7375 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7379 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
7382 case CMD_APPDOMAIN_GET_CORLIB
: {
7383 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7387 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
7390 case CMD_APPDOMAIN_CREATE_STRING
: {
7394 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7397 s
= decode_string (p
, &p
, end
);
7399 o
= mono_string_new (domain
, s
);
7400 buffer_add_objid (buf
, (MonoObject
*)o
);
7403 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
7405 MonoDomain
*domain2
;
7408 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7411 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
7416 g_assert (domain
== domain2
);
7418 o
= mono_object_new (domain
, klass
);
7420 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
7424 buffer_add_objid (buf
, o
);
7428 return ERR_NOT_IMPLEMENTED
;
7435 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7441 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
7446 case CMD_ASSEMBLY_GET_LOCATION
: {
7447 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
7450 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
7454 if (ass
->image
->dynamic
) {
7455 buffer_add_id (buf
, 0);
7457 token
= mono_image_get_entry_point (ass
->image
);
7459 buffer_add_id (buf
, 0);
7461 m
= mono_get_method (ass
->image
, token
, NULL
);
7462 buffer_add_methodid (buf
, domain
, m
);
7467 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
7468 buffer_add_moduleid (buf
, domain
, ass
->image
);
7471 case CMD_ASSEMBLY_GET_OBJECT
: {
7472 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (domain
, ass
);
7473 buffer_add_objid (buf
, o
);
7476 case CMD_ASSEMBLY_GET_TYPE
: {
7477 char *s
= decode_string (p
, &p
, end
);
7478 gboolean ignorecase
= decode_byte (p
, &p
, end
);
7479 MonoTypeNameParse info
;
7481 gboolean type_resolve
, res
;
7482 MonoDomain
*d
= mono_domain_get ();
7484 /* This is needed to be able to find referenced assemblies */
7485 res
= mono_domain_set (domain
, FALSE
);
7488 if (!mono_reflection_parse_type (s
, &info
)) {
7491 if (info
.assembly
.name
)
7493 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
7495 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
7496 mono_reflection_free_type_info (&info
);
7499 mono_domain_set (d
, TRUE
);
7503 case CMD_ASSEMBLY_GET_NAME
: {
7505 MonoAssembly
*mass
= ass
;
7507 name
= g_strdup_printf (
7508 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
7510 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
7511 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
7512 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
7513 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
7515 buffer_add_string (buf
, name
);
7520 return ERR_NOT_IMPLEMENTED
;
7527 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7533 case CMD_MODULE_GET_INFO
: {
7534 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
7537 basename
= g_path_get_basename (image
->name
);
7538 buffer_add_string (buf
, basename
); // name
7539 buffer_add_string (buf
, image
->module_name
); // scopename
7540 buffer_add_string (buf
, image
->name
); // fqname
7541 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
7542 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
7547 return ERR_NOT_IMPLEMENTED
;
7554 field_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7560 case CMD_FIELD_GET_INFO
: {
7561 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, &domain
, &err
);
7563 buffer_add_string (buf
, f
->name
);
7564 buffer_add_typeid (buf
, domain
, f
->parent
);
7565 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
7566 buffer_add_int (buf
, f
->type
->attrs
);
7570 return ERR_NOT_IMPLEMENTED
;
7577 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
7579 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
7580 /* Special case these so the client doesn't have to handle Type objects */
7582 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
7583 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
7584 } else if (MONO_TYPE_IS_REFERENCE (t
))
7585 buffer_add_value (buf
, t
, &val
, domain
);
7587 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
7591 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
7597 buffer_add_int (buf
, 0);
7601 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
7602 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
7605 buffer_add_int (buf
, nattrs
);
7607 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
7608 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
7609 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
7610 MonoArray
*typed_args
, *named_args
;
7612 CattrNamedArg
*arginfo
= NULL
;
7615 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, &error
);
7616 g_assert (mono_error_ok (&error
));
7618 buffer_add_methodid (buf
, domain
, attr
->ctor
);
7622 buffer_add_int (buf
, mono_array_length (typed_args
));
7623 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
7624 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
7626 t
= mono_method_signature (attr
->ctor
)->params
[j
];
7628 buffer_add_cattr_arg (buf
, t
, domain
, val
);
7631 buffer_add_int (buf
, 0);
7636 buffer_add_int (buf
, mono_array_length (named_args
));
7638 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
7639 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
7641 if (arginfo
[j
].prop
) {
7642 buffer_add_byte (buf
, 0x54);
7643 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
7644 } else if (arginfo
[j
].field
) {
7645 buffer_add_byte (buf
, 0x53);
7646 buffer_add_fieldid (buf
, domain
, arginfo
[j
].field
);
7648 g_assert_not_reached ();
7651 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
7654 buffer_add_int (buf
, 0);
7661 /* FIXME: Code duplication with icall.c */
7663 collect_interfaces (MonoClass
*klass
, GHashTable
*ifaces
, MonoError
*error
)
7668 mono_class_setup_interfaces (klass
, error
);
7669 if (!mono_error_ok (error
))
7672 for (i
= 0; i
< klass
->interface_count
; i
++) {
7673 ic
= klass
->interfaces
[i
];
7674 g_hash_table_insert (ifaces
, ic
, ic
);
7676 collect_interfaces (ic
, ifaces
, error
);
7677 if (!mono_error_ok (error
))
7683 type_commands_internal (int command
, MonoClass
*klass
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7693 case CMD_TYPE_GET_INFO
: {
7694 buffer_add_string (buf
, klass
->name_space
);
7695 buffer_add_string (buf
, klass
->name
);
7697 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
7698 buffer_add_string (buf
, name
);
7700 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
7701 buffer_add_moduleid (buf
, domain
, klass
->image
);
7702 buffer_add_typeid (buf
, domain
, klass
->parent
);
7703 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
7704 buffer_add_typeid (buf
, domain
, klass
->element_class
);
7706 buffer_add_id (buf
, 0);
7707 buffer_add_int (buf
, klass
->type_token
);
7708 buffer_add_byte (buf
, klass
->rank
);
7709 buffer_add_int (buf
, klass
->flags
);
7711 type
= &klass
->byval_arg
;
7712 // FIXME: Can't decide whenever a class represents a byref type
7715 if (type
->type
== MONO_TYPE_PTR
)
7717 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
7719 if (type
->type
== MONO_TYPE_VALUETYPE
)
7721 if (klass
->enumtype
)
7723 if (klass
->generic_container
)
7725 if (klass
->generic_container
|| klass
->generic_class
)
7727 buffer_add_byte (buf
, b
);
7730 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
7732 buffer_add_int (buf
, nnested
);
7734 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
7735 buffer_add_typeid (buf
, domain
, nested
);
7736 if (CHECK_PROTOCOL_VERSION (2, 12)) {
7737 if (klass
->generic_container
)
7738 buffer_add_typeid (buf
, domain
, klass
);
7739 else if (klass
->generic_class
)
7740 buffer_add_typeid (buf
, domain
, klass
->generic_class
->container_class
);
7742 buffer_add_id (buf
, 0);
7744 if (CHECK_PROTOCOL_VERSION (2, 15)) {
7747 if (klass
->generic_class
) {
7748 MonoGenericInst
*inst
= klass
->generic_class
->context
.class_inst
;
7750 count
= inst
->type_argc
;
7751 buffer_add_int (buf
, count
);
7752 for (i
= 0; i
< count
; i
++)
7753 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (inst
->type_argv
[i
]));
7754 } else if (klass
->generic_container
) {
7755 MonoGenericContainer
*container
= klass
->generic_container
;
7758 count
= container
->type_argc
;
7759 buffer_add_int (buf
, count
);
7760 for (i
= 0; i
< count
; i
++) {
7761 pklass
= mono_class_from_generic_parameter (mono_generic_container_get_param (container
, i
), klass
->image
, FALSE
);
7762 buffer_add_typeid (buf
, domain
, pklass
);
7765 buffer_add_int (buf
, 0);
7770 case CMD_TYPE_GET_METHODS
: {
7773 gpointer iter
= NULL
;
7776 mono_class_setup_methods (klass
);
7778 nmethods
= mono_class_num_methods (klass
);
7780 buffer_add_int (buf
, nmethods
);
7782 while ((m
= mono_class_get_methods (klass
, &iter
))) {
7783 buffer_add_methodid (buf
, domain
, m
);
7786 g_assert (i
== nmethods
);
7789 case CMD_TYPE_GET_FIELDS
: {
7792 gpointer iter
= NULL
;
7795 nfields
= mono_class_num_fields (klass
);
7797 buffer_add_int (buf
, nfields
);
7799 while ((f
= mono_class_get_fields (klass
, &iter
))) {
7800 buffer_add_fieldid (buf
, domain
, f
);
7801 buffer_add_string (buf
, f
->name
);
7802 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
7803 buffer_add_int (buf
, f
->type
->attrs
);
7806 g_assert (i
== nfields
);
7809 case CMD_TYPE_GET_PROPERTIES
: {
7812 gpointer iter
= NULL
;
7815 nprops
= mono_class_num_properties (klass
);
7817 buffer_add_int (buf
, nprops
);
7819 while ((p
= mono_class_get_properties (klass
, &iter
))) {
7820 buffer_add_propertyid (buf
, domain
, p
);
7821 buffer_add_string (buf
, p
->name
);
7822 buffer_add_methodid (buf
, domain
, p
->get
);
7823 buffer_add_methodid (buf
, domain
, p
->set
);
7824 buffer_add_int (buf
, p
->attrs
);
7827 g_assert (i
== nprops
);
7830 case CMD_TYPE_GET_CATTRS
: {
7831 MonoClass
*attr_klass
;
7832 MonoCustomAttrInfo
*cinfo
;
7834 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7835 /* attr_klass can be NULL */
7839 cinfo
= mono_custom_attrs_from_class (klass
);
7841 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7844 case CMD_TYPE_GET_FIELD_CATTRS
: {
7845 MonoClass
*attr_klass
;
7846 MonoCustomAttrInfo
*cinfo
;
7847 MonoClassField
*field
;
7849 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7852 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7856 cinfo
= mono_custom_attrs_from_field (klass
, field
);
7858 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7861 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
7862 MonoClass
*attr_klass
;
7863 MonoCustomAttrInfo
*cinfo
;
7866 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
7869 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7873 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
7875 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7878 case CMD_TYPE_GET_VALUES
:
7879 case CMD_TYPE_GET_VALUES_2
: {
7886 MonoThread
*thread_obj
;
7887 MonoInternalThread
*thread
= NULL
;
7888 guint32 special_static_type
;
7890 if (command
== CMD_TYPE_GET_VALUES_2
) {
7891 int objid
= decode_objid (p
, &p
, end
);
7894 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
7898 thread
= THREAD_TO_INTERNAL (thread_obj
);
7901 len
= decode_int (p
, &p
, end
);
7902 for (i
= 0; i
< len
; ++i
) {
7903 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7907 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
7908 return ERR_INVALID_FIELDID
;
7909 special_static_type
= mono_class_field_get_special_static_type (f
);
7910 if (special_static_type
!= SPECIAL_STATIC_NONE
) {
7911 if (!(thread
&& special_static_type
== SPECIAL_STATIC_THREAD
))
7912 return ERR_INVALID_FIELDID
;
7915 /* Check that the field belongs to the object */
7917 for (k
= klass
; k
; k
= k
->parent
) {
7918 if (k
== f
->parent
) {
7924 return ERR_INVALID_FIELDID
;
7926 vtable
= mono_class_vtable (domain
, f
->parent
);
7927 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
7928 mono_field_static_get_value_for_thread (thread
? thread
: mono_thread_internal_current (), vtable
, f
, val
);
7929 buffer_add_value (buf
, f
->type
, val
, domain
);
7934 case CMD_TYPE_SET_VALUES
: {
7942 len
= decode_int (p
, &p
, end
);
7943 for (i
= 0; i
< len
; ++i
) {
7944 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7948 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
7949 return ERR_INVALID_FIELDID
;
7950 if (mono_class_field_is_special_static (f
))
7951 return ERR_INVALID_FIELDID
;
7953 /* Check that the field belongs to the object */
7955 for (k
= klass
; k
; k
= k
->parent
) {
7956 if (k
== f
->parent
) {
7962 return ERR_INVALID_FIELDID
;
7964 // FIXME: Check for literal/const
7966 vtable
= mono_class_vtable (domain
, f
->parent
);
7967 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
7968 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
7973 if (MONO_TYPE_IS_REFERENCE (f
->type
))
7974 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
7976 mono_field_static_set_value (vtable
, f
, val
);
7981 case CMD_TYPE_GET_OBJECT
: {
7982 MonoObject
*o
= (MonoObject
*)mono_type_get_object (domain
, &klass
->byval_arg
);
7983 buffer_add_objid (buf
, o
);
7986 case CMD_TYPE_GET_SOURCE_FILES
:
7987 case CMD_TYPE_GET_SOURCE_FILES_2
: {
7988 char *source_file
, *base
;
7992 files
= get_source_files_for_type (klass
);
7994 buffer_add_int (buf
, files
->len
);
7995 for (i
= 0; i
< files
->len
; ++i
) {
7996 source_file
= g_ptr_array_index (files
, i
);
7997 if (command
== CMD_TYPE_GET_SOURCE_FILES_2
) {
7998 buffer_add_string (buf
, source_file
);
8000 base
= g_path_get_basename (source_file
);
8001 buffer_add_string (buf
, base
);
8004 g_free (source_file
);
8006 g_ptr_array_free (files
, TRUE
);
8009 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
8010 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8014 if (mono_class_is_assignable_from (klass
, oklass
))
8015 buffer_add_byte (buf
, 1);
8017 buffer_add_byte (buf
, 0);
8020 case CMD_TYPE_GET_METHODS_BY_NAME_FLAGS
: {
8021 char *name
= decode_string (p
, &p
, end
);
8022 int i
, flags
= decode_int (p
, &p
, end
);
8023 MonoException
*ex
= NULL
;
8024 GPtrArray
*array
= mono_class_get_methods_by_name (klass
, name
, flags
& ~BINDING_FLAGS_IGNORE_CASE
, (flags
& BINDING_FLAGS_IGNORE_CASE
) != 0, TRUE
, &ex
);
8027 return ERR_LOADER_ERROR
;
8028 buffer_add_int (buf
, array
->len
);
8029 for (i
= 0; i
< array
->len
; ++i
) {
8030 MonoMethod
*method
= g_ptr_array_index (array
, i
);
8031 buffer_add_methodid (buf
, domain
, method
);
8034 g_ptr_array_free (array
, TRUE
);
8038 case CMD_TYPE_GET_INTERFACES
: {
8040 GHashTable
*iface_hash
= g_hash_table_new (NULL
, NULL
);
8042 MonoClass
*tclass
, *iface
;
8043 GHashTableIter iter
;
8047 for (parent
= tclass
; parent
; parent
= parent
->parent
) {
8048 mono_class_setup_interfaces (parent
, &error
);
8049 if (!mono_error_ok (&error
))
8050 return ERR_LOADER_ERROR
;
8051 collect_interfaces (parent
, iface_hash
, &error
);
8052 if (!mono_error_ok (&error
))
8053 return ERR_LOADER_ERROR
;
8056 buffer_add_int (buf
, g_hash_table_size (iface_hash
));
8058 g_hash_table_iter_init (&iter
, iface_hash
);
8059 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&iface
))
8060 buffer_add_typeid (buf
, domain
, iface
);
8061 g_hash_table_destroy (iface_hash
);
8064 case CMD_TYPE_GET_INTERFACE_MAP
: {
8065 int tindex
, ioffset
;
8066 gboolean variance_used
;
8068 int len
, nmethods
, i
;
8072 len
= decode_int (p
, &p
, end
);
8073 mono_class_setup_vtable (klass
);
8075 for (tindex
= 0; tindex
< len
; ++tindex
) {
8076 iclass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8080 ioffset
= mono_class_interface_offset_with_variance (klass
, iclass
, &variance_used
);
8082 return ERR_INVALID_ARGUMENT
;
8084 nmethods
= mono_class_num_methods (iclass
);
8085 buffer_add_int (buf
, nmethods
);
8088 while ((method
= mono_class_get_methods (iclass
, &iter
))) {
8089 buffer_add_methodid (buf
, domain
, method
);
8091 for (i
= 0; i
< nmethods
; ++i
)
8092 buffer_add_methodid (buf
, domain
, klass
->vtable
[i
+ ioffset
]);
8096 case CMD_TYPE_IS_INITIALIZED
: {
8097 MonoVTable
*vtable
= mono_class_vtable (domain
, klass
);
8100 buffer_add_int (buf
, (vtable
->initialized
|| vtable
->init_failed
) ? 1 : 0);
8102 buffer_add_int (buf
, 0);
8105 case CMD_TYPE_CREATE_INSTANCE
: {
8108 obj
= mono_object_new (domain
, klass
);
8109 buffer_add_objid (buf
, obj
);
8113 return ERR_NOT_IMPLEMENTED
;
8120 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8123 MonoDomain
*old_domain
;
8127 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
8131 old_domain
= mono_domain_get ();
8133 mono_domain_set (domain
, TRUE
);
8135 err
= type_commands_internal (command
, klass
, domain
, p
, end
, buf
);
8137 mono_domain_set (old_domain
, TRUE
);
8143 method_commands_internal (int command
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8145 MonoMethodHeader
*header
;
8149 case CMD_METHOD_GET_NAME
: {
8150 buffer_add_string (buf
, method
->name
);
8153 case CMD_METHOD_GET_DECLARING_TYPE
: {
8154 buffer_add_typeid (buf
, domain
, method
->klass
);
8157 case CMD_METHOD_GET_DEBUG_INFO
: {
8158 MonoDebugMethodInfo
*minfo
;
8160 int i
, j
, n_il_offsets
;
8163 int *column_numbers
;
8164 int *end_line_numbers
;
8165 int *end_column_numbers
;
8167 GPtrArray
*source_file_list
;
8169 header
= mono_method_get_header (method
);
8171 buffer_add_int (buf
, 0);
8172 buffer_add_string (buf
, "");
8173 buffer_add_int (buf
, 0);
8177 minfo
= mono_debug_lookup_method (method
);
8179 buffer_add_int (buf
, header
->code_size
);
8180 buffer_add_string (buf
, "");
8181 buffer_add_int (buf
, 0);
8182 mono_metadata_free_mh (header
);
8186 mono_debug_symfile_get_line_numbers_full (minfo
, &source_file
, &source_file_list
, &n_il_offsets
, &il_offsets
, &line_numbers
, &column_numbers
, &source_files
, &end_line_numbers
, &end_column_numbers
);
8187 buffer_add_int (buf
, header
->code_size
);
8188 if (CHECK_PROTOCOL_VERSION (2, 13)) {
8189 buffer_add_int (buf
, source_file_list
->len
);
8190 for (i
= 0; i
< source_file_list
->len
; ++i
) {
8191 MonoDebugSourceInfo
*sinfo
= g_ptr_array_index (source_file_list
, i
);
8192 buffer_add_string (buf
, sinfo
->source_file
);
8193 if (CHECK_PROTOCOL_VERSION (2, 14)) {
8194 for (j
= 0; j
< 16; ++j
)
8195 buffer_add_byte (buf
, sinfo
->hash
[j
]);
8199 buffer_add_string (buf
, source_file
);
8201 buffer_add_int (buf
, n_il_offsets
);
8202 DEBUG (10, fprintf (log_file
, "Line number table for method %s:\n", mono_method_full_name (method
, TRUE
)));
8203 for (i
= 0; i
< n_il_offsets
; ++i
) {
8204 const char *srcfile
= "";
8206 if (source_files
[i
] != -1) {
8207 MonoDebugSourceInfo
*sinfo
= g_ptr_array_index (source_file_list
, source_files
[i
]);
8208 srcfile
= sinfo
->source_file
;
8210 DEBUG (10, fprintf (log_file
, "IL%x -> %s:%d %d\n", il_offsets
[i
], srcfile
, line_numbers
[i
], column_numbers
? column_numbers
[i
] : -1));
8211 buffer_add_int (buf
, il_offsets
[i
]);
8212 buffer_add_int (buf
, line_numbers
[i
]);
8213 if (CHECK_PROTOCOL_VERSION (2, 13))
8214 buffer_add_int (buf
, source_files
[i
]);
8215 if (CHECK_PROTOCOL_VERSION (2, 19))
8216 buffer_add_int (buf
, column_numbers
? column_numbers
[i
] : -1);
8217 if (CHECK_PROTOCOL_VERSION (2, 32)) {
8218 buffer_add_int (buf
, end_line_numbers
? end_line_numbers
[i
] : -1);
8219 buffer_add_int (buf
, end_column_numbers
? end_column_numbers
[i
] : -1);
8222 g_free (source_file
);
8223 g_free (il_offsets
);
8224 g_free (line_numbers
);
8225 g_free (column_numbers
);
8226 g_free (end_line_numbers
);
8227 g_free (end_column_numbers
);
8228 g_free (source_files
);
8229 g_ptr_array_free (source_file_list
, TRUE
);
8230 mono_metadata_free_mh (header
);
8233 case CMD_METHOD_GET_PARAM_INFO
: {
8234 MonoMethodSignature
*sig
= mono_method_signature (method
);
8238 /* FIXME: mono_class_from_mono_type () and byrefs */
8240 /* FIXME: Use a smaller encoding */
8241 buffer_add_int (buf
, sig
->call_convention
);
8242 buffer_add_int (buf
, sig
->param_count
);
8243 buffer_add_int (buf
, sig
->generic_param_count
);
8244 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
8245 for (i
= 0; i
< sig
->param_count
; ++i
) {
8247 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
8250 /* Emit parameter names */
8251 names
= g_new (char *, sig
->param_count
);
8252 mono_method_get_param_names (method
, (const char **) names
);
8253 for (i
= 0; i
< sig
->param_count
; ++i
)
8254 buffer_add_string (buf
, names
[i
]);
8259 case CMD_METHOD_GET_LOCALS_INFO
: {
8260 int i
, j
, num_locals
;
8261 MonoDebugLocalsInfo
*locals
;
8263 header
= mono_method_get_header (method
);
8265 return ERR_INVALID_ARGUMENT
;
8267 buffer_add_int (buf
, header
->num_locals
);
8270 for (i
= 0; i
< header
->num_locals
; ++i
)
8271 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
8274 locals
= mono_debug_lookup_locals (method
);
8276 num_locals
= locals
->num_locals
;
8279 for (i
= 0; i
< header
->num_locals
; ++i
) {
8280 for (j
= 0; j
< num_locals
; ++j
)
8281 if (locals
->locals
[j
].index
== i
)
8284 buffer_add_string (buf
, locals
->locals
[j
].name
);
8286 buffer_add_string (buf
, "");
8290 for (i
= 0; i
< header
->num_locals
; ++i
) {
8291 for (j
= 0; j
< num_locals
; ++j
)
8292 if (locals
->locals
[j
].index
== i
)
8294 if (j
< num_locals
&& locals
->locals
[j
].block
) {
8295 buffer_add_int (buf
, locals
->locals
[j
].block
->start_offset
);
8296 buffer_add_int (buf
, locals
->locals
[j
].block
->end_offset
);
8298 buffer_add_int (buf
, 0);
8299 buffer_add_int (buf
, header
->code_size
);
8302 mono_metadata_free_mh (header
);
8305 mono_debug_symfile_free_locals (locals
);
8309 case CMD_METHOD_GET_INFO
:
8310 buffer_add_int (buf
, method
->flags
);
8311 buffer_add_int (buf
, method
->iflags
);
8312 buffer_add_int (buf
, method
->token
);
8313 if (CHECK_PROTOCOL_VERSION (2, 12)) {
8315 if (method
->is_generic
)
8317 if (mono_method_signature (method
)->generic_param_count
)
8319 buffer_add_byte (buf
, attrs
);
8320 if (method
->is_generic
|| method
->is_inflated
) {
8323 if (method
->is_generic
) {
8326 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
8328 result
= imethod
->declaring
;
8329 if (imethod
->context
.class_inst
) {
8330 MonoClass
*klass
= ((MonoMethod
*) imethod
)->klass
;
8331 /*Generic methods gets the context of the GTD.*/
8332 if (mono_class_get_context (klass
))
8333 result
= mono_class_inflate_generic_method_full (result
, klass
, mono_class_get_context (klass
));
8337 buffer_add_methodid (buf
, domain
, result
);
8339 buffer_add_id (buf
, 0);
8341 if (CHECK_PROTOCOL_VERSION (2, 15)) {
8342 if (mono_method_signature (method
)->generic_param_count
) {
8345 if (method
->is_inflated
) {
8346 MonoGenericInst
*inst
= mono_method_get_context (method
)->method_inst
;
8348 count
= inst
->type_argc
;
8349 buffer_add_int (buf
, count
);
8351 for (i
= 0; i
< count
; i
++)
8352 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (inst
->type_argv
[i
]));
8354 buffer_add_int (buf
, 0);
8356 } else if (method
->is_generic
) {
8357 MonoGenericContainer
*container
= mono_method_get_generic_container (method
);
8359 count
= mono_method_signature (method
)->generic_param_count
;
8360 buffer_add_int (buf
, count
);
8361 for (i
= 0; i
< count
; i
++) {
8362 MonoGenericParam
*param
= mono_generic_container_get_param (container
, i
);
8363 MonoClass
*pklass
= mono_class_from_generic_parameter (param
, method
->klass
->image
, TRUE
);
8364 buffer_add_typeid (buf
, domain
, pklass
);
8367 buffer_add_int (buf
, 0);
8370 buffer_add_int (buf
, 0);
8375 case CMD_METHOD_GET_BODY
: {
8378 header
= mono_method_get_header (method
);
8380 buffer_add_int (buf
, 0);
8382 if (CHECK_PROTOCOL_VERSION (2, 18))
8383 buffer_add_int (buf
, 0);
8385 buffer_add_int (buf
, header
->code_size
);
8386 for (i
= 0; i
< header
->code_size
; ++i
)
8387 buffer_add_byte (buf
, header
->code
[i
]);
8389 if (CHECK_PROTOCOL_VERSION (2, 18)) {
8390 buffer_add_int (buf
, header
->num_clauses
);
8391 for (i
= 0; i
< header
->num_clauses
; ++i
) {
8392 MonoExceptionClause
*clause
= &header
->clauses
[i
];
8394 buffer_add_int (buf
, clause
->flags
);
8395 buffer_add_int (buf
, clause
->try_offset
);
8396 buffer_add_int (buf
, clause
->try_len
);
8397 buffer_add_int (buf
, clause
->handler_offset
);
8398 buffer_add_int (buf
, clause
->handler_len
);
8399 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
)
8400 buffer_add_typeid (buf
, domain
, clause
->data
.catch_class
);
8401 else if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)
8402 buffer_add_int (buf
, clause
->data
.filter_offset
);
8406 mono_metadata_free_mh (header
);
8411 case CMD_METHOD_RESOLVE_TOKEN
: {
8412 guint32 token
= decode_int (p
, &p
, end
);
8415 switch (mono_metadata_token_code (token
)) {
8416 case MONO_TOKEN_STRING
: {
8420 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
8423 s2
= mono_string_to_utf8 (s
);
8425 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
8426 buffer_add_string (buf
, s2
);
8432 MonoClass
*handle_class
;
8434 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
8435 val
= mono_method_get_wrapper_data (method
, token
);
8436 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
8438 if (handle_class
== NULL
) {
8439 // Can't figure out the token type
8440 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
8444 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
8448 if (handle_class
== mono_defaults
.typehandle_class
) {
8449 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
8450 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
8451 buffer_add_typeid (buf
, domain
, (MonoClass
*) val
);
8453 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
8454 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
8455 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
8456 buffer_add_fieldid (buf
, domain
, val
);
8457 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
8458 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
8459 buffer_add_methodid (buf
, domain
, val
);
8460 } else if (handle_class
== mono_defaults
.string_class
) {
8463 s
= mono_string_to_utf8 (val
);
8464 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
8465 buffer_add_string (buf
, s
);
8468 g_assert_not_reached ();
8475 case CMD_METHOD_GET_CATTRS
: {
8476 MonoClass
*attr_klass
;
8477 MonoCustomAttrInfo
*cinfo
;
8479 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8480 /* attr_klass can be NULL */
8484 cinfo
= mono_custom_attrs_from_method (method
);
8486 buffer_add_cattrs (buf
, domain
, method
->klass
->image
, attr_klass
, cinfo
);
8489 case CMD_METHOD_MAKE_GENERIC_METHOD
: {
8490 MonoType
**type_argv
;
8494 MonoGenericInst
*ginst
;
8495 MonoGenericContext tmp_context
;
8496 MonoMethod
*inflated
;
8498 type_argc
= decode_int (p
, &p
, end
);
8499 type_argv
= g_new0 (MonoType
*, type_argc
);
8500 for (i
= 0; i
< type_argc
; ++i
) {
8501 klass
= decode_typeid (p
, &p
, end
, &d
, &err
);
8508 return ERR_INVALID_ARGUMENT
;
8510 type_argv
[i
] = &klass
->byval_arg
;
8512 ginst
= mono_metadata_get_generic_inst (type_argc
, type_argv
);
8514 tmp_context
.class_inst
= method
->klass
->generic_class
? method
->klass
->generic_class
->context
.class_inst
: NULL
;
8515 tmp_context
.method_inst
= ginst
;
8517 inflated
= mono_class_inflate_generic_method (method
, &tmp_context
);
8518 if (!mono_verifier_is_method_valid_generic_instantiation (inflated
))
8519 return ERR_INVALID_ARGUMENT
;
8520 buffer_add_methodid (buf
, domain
, inflated
);
8524 return ERR_NOT_IMPLEMENTED
;
8531 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8534 MonoDomain
*old_domain
;
8538 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
8542 old_domain
= mono_domain_get ();
8544 mono_domain_set (domain
, TRUE
);
8546 err
= method_commands_internal (command
, method
, domain
, p
, end
, buf
);
8548 mono_domain_set (old_domain
, TRUE
);
8554 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8556 int objid
= decode_objid (p
, &p
, end
);
8558 MonoThread
*thread_obj
;
8559 MonoInternalThread
*thread
;
8561 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
8565 thread
= THREAD_TO_INTERNAL (thread_obj
);
8568 case CMD_THREAD_GET_NAME
: {
8570 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
8573 buffer_add_int (buf
, 0);
8578 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
8580 buffer_add_int (buf
, len
);
8581 buffer_add_data (buf
, (guint8
*)name
, len
);
8586 case CMD_THREAD_GET_FRAME_INFO
: {
8587 DebuggerTlsData
*tls
;
8588 int i
, start_frame
, length
;
8590 // Wait for suspending if it already started
8591 // FIXME: Races with suspend_count
8592 while (!is_suspended ()) {
8594 wait_for_suspend ();
8598 wait_for_suspend ();
8599 if (!is_suspended ())
8600 return ERR_NOT_SUSPENDED;
8603 start_frame
= decode_int (p
, &p
, end
);
8604 length
= decode_int (p
, &p
, end
);
8606 if (start_frame
!= 0 || length
!= -1)
8607 return ERR_NOT_IMPLEMENTED
;
8609 mono_loader_lock ();
8610 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8611 mono_loader_unlock ();
8614 compute_frame_info (thread
, tls
);
8616 buffer_add_int (buf
, tls
->frame_count
);
8617 for (i
= 0; i
< tls
->frame_count
; ++i
) {
8618 buffer_add_int (buf
, tls
->frames
[i
]->id
);
8619 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->actual_method
);
8620 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
8622 * Instead of passing the frame type directly to the client, we associate
8623 * it with the previous frame using a set of flags. This avoids lots of
8624 * conditional code in the client, since a frame whose type isn't
8625 * FRAME_TYPE_MANAGED has no method, location, etc.
8627 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
8632 case CMD_THREAD_GET_STATE
:
8633 buffer_add_int (buf
, thread
->state
);
8635 case CMD_THREAD_GET_INFO
:
8636 buffer_add_byte (buf
, thread
->threadpool_thread
);
8638 case CMD_THREAD_GET_ID
:
8639 buffer_add_long (buf
, (guint64
)(gsize
)thread
);
8641 case CMD_THREAD_GET_TID
:
8642 buffer_add_long (buf
, (guint64
)thread
->tid
);
8644 case CMD_THREAD_SET_IP
: {
8645 DebuggerTlsData
*tls
;
8648 MonoSeqPointInfo
*seq_points
;
8649 SeqPoint
*sp
= NULL
;
8653 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
8656 il_offset
= decode_long (p
, &p
, end
);
8658 while (!is_suspended ()) {
8660 wait_for_suspend ();
8663 mono_loader_lock ();
8664 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8665 mono_loader_unlock ();
8668 compute_frame_info (thread
, tls
);
8669 if (tls
->frame_count
== 0 || tls
->frames
[0]->actual_method
!= method
)
8670 return ERR_INVALID_ARGUMENT
;
8672 seq_points
= get_seq_points (domain
, method
);
8673 g_assert (seq_points
);
8675 for (i
= 0; i
< seq_points
->len
; ++i
) {
8676 sp
= &seq_points
->seq_points
[i
];
8678 if (sp
->il_offset
== il_offset
)
8681 if (i
== seq_points
->len
)
8682 return ERR_INVALID_ARGUMENT
;
8684 // FIXME: Check that the ip change is safe
8686 DEBUG (1, fprintf (log_file
, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls
->frames
[0]->actual_method
->name
, (int)sp
->il_offset
, (int)sp
->native_offset
));
8687 MONO_CONTEXT_SET_IP (&tls
->restore_ctx
, (guint8
*)tls
->frames
[0]->ji
->code_start
+ sp
->native_offset
);
8691 return ERR_NOT_IMPLEMENTED
;
8698 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8702 MonoThread
*thread_obj
;
8703 MonoInternalThread
*thread
;
8704 int pos
, i
, len
, frame_idx
;
8705 DebuggerTlsData
*tls
;
8707 MonoDebugMethodJitInfo
*jit
;
8708 MonoDebugVarInfo
*var
;
8709 MonoMethodSignature
*sig
;
8711 MonoMethodHeader
*header
;
8713 objid
= decode_objid (p
, &p
, end
);
8714 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
8718 thread
= THREAD_TO_INTERNAL (thread_obj
);
8720 id
= decode_id (p
, &p
, end
);
8722 mono_loader_lock ();
8723 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8724 mono_loader_unlock ();
8727 for (i
= 0; i
< tls
->frame_count
; ++i
) {
8728 if (tls
->frames
[i
]->id
== id
)
8731 if (i
== tls
->frame_count
)
8732 return ERR_INVALID_FRAMEID
;
8735 frame
= tls
->frames
[frame_idx
];
8737 if (!frame
->has_ctx
)
8738 return ERR_ABSENT_INFORMATION
;
8741 frame
->jit
= mono_debug_find_method (frame
->api_method
, frame
->domain
);
8742 if (!frame
->jit
&& frame
->api_method
->is_inflated
)
8743 frame
->jit
= mono_debug_find_method (mono_method_get_declaring_generic_method (frame
->api_method
), frame
->domain
);
8747 /* This could happen for aot images with no jit debug info */
8748 s
= mono_method_full_name (frame
->api_method
, TRUE
);
8749 DEBUG (1, fprintf (log_file
, "[dbg] No debug information found for '%s'.\n", s
));
8751 return ERR_ABSENT_INFORMATION
;
8756 sig
= mono_method_signature (frame
->actual_method
);
8758 if (!get_seq_points (frame
->domain
, frame
->actual_method
))
8760 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
8762 return ERR_ABSENT_INFORMATION
;
8765 case CMD_STACK_FRAME_GET_VALUES
: {
8766 len
= decode_int (p
, &p
, end
);
8767 header
= mono_method_get_header (frame
->actual_method
);
8769 for (i
= 0; i
< len
; ++i
) {
8770 pos
= decode_int (p
, &p
, end
);
8775 g_assert (pos
>= 0 && pos
< jit
->num_params
);
8777 var
= &jit
->params
[pos
];
8779 add_var (buf
, jit
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
8781 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
8783 var
= &jit
->locals
[pos
];
8785 add_var (buf
, jit
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
8788 mono_metadata_free_mh (header
);
8791 case CMD_STACK_FRAME_GET_THIS
: {
8792 if (frame
->api_method
->klass
->valuetype
) {
8793 if (!sig
->hasthis
) {
8794 MonoObject
*p
= NULL
;
8795 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
8797 add_var (buf
, jit
, &frame
->actual_method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
8800 if (!sig
->hasthis
) {
8801 MonoObject
*p
= NULL
;
8802 buffer_add_value (buf
, &frame
->actual_method
->klass
->byval_arg
, &p
, frame
->domain
);
8804 add_var (buf
, jit
, &frame
->api_method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
8809 case CMD_STACK_FRAME_SET_VALUES
: {
8812 MonoDebugVarInfo
*var
;
8814 len
= decode_int (p
, &p
, end
);
8815 header
= mono_method_get_header (frame
->actual_method
);
8817 for (i
= 0; i
< len
; ++i
) {
8818 pos
= decode_int (p
, &p
, end
);
8823 g_assert (pos
>= 0 && pos
< jit
->num_params
);
8825 t
= sig
->params
[pos
];
8826 var
= &jit
->params
[pos
];
8828 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
8830 t
= header
->locals
[pos
];
8831 var
= &jit
->locals
[pos
];
8834 if (MONO_TYPE_IS_REFERENCE (t
))
8835 val_buf
= g_alloca (sizeof (MonoObject
*));
8837 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
8838 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
8842 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
, frame
->reg_locations
, &tls
->restore_ctx
);
8844 mono_metadata_free_mh (header
);
8848 return ERR_NOT_IMPLEMENTED
;
8855 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8858 int objid
, err
, index
, len
, i
, esize
;
8861 objid
= decode_objid (p
, &p
, end
);
8862 err
= get_object (objid
, (MonoObject
**)&arr
);
8867 case CMD_ARRAY_REF_GET_LENGTH
:
8868 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
8870 buffer_add_int (buf
, arr
->max_length
);
8871 buffer_add_int (buf
, 0);
8873 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
8874 buffer_add_int (buf
, arr
->bounds
[i
].length
);
8875 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
8879 case CMD_ARRAY_REF_GET_VALUES
:
8880 index
= decode_int (p
, &p
, end
);
8881 len
= decode_int (p
, &p
, end
);
8883 g_assert (index
>= 0 && len
>= 0);
8884 // Reordered to avoid integer overflow
8885 g_assert (!(index
> arr
->max_length
- len
));
8887 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
8888 for (i
= index
; i
< index
+ len
; ++i
) {
8889 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
8890 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
8893 case CMD_ARRAY_REF_SET_VALUES
:
8894 index
= decode_int (p
, &p
, end
);
8895 len
= decode_int (p
, &p
, end
);
8897 g_assert (index
>= 0 && len
>= 0);
8898 // Reordered to avoid integer overflow
8899 g_assert (!(index
> arr
->max_length
- len
));
8901 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
8902 for (i
= index
; i
< index
+ len
; ++i
) {
8903 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
8905 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
8909 return ERR_NOT_IMPLEMENTED
;
8916 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8921 int i
, index
, length
;
8924 objid
= decode_objid (p
, &p
, end
);
8925 err
= get_object (objid
, (MonoObject
**)&str
);
8930 case CMD_STRING_REF_GET_VALUE
:
8931 s
= mono_string_to_utf8 (str
);
8932 buffer_add_string (buf
, s
);
8935 case CMD_STRING_REF_GET_LENGTH
:
8936 buffer_add_long (buf
, mono_string_length (str
));
8938 case CMD_STRING_REF_GET_CHARS
:
8939 index
= decode_long (p
, &p
, end
);
8940 length
= decode_long (p
, &p
, end
);
8941 if (index
> mono_string_length (str
) - length
)
8942 return ERR_INVALID_ARGUMENT
;
8943 c
= mono_string_chars (str
) + index
;
8944 for (i
= 0; i
< length
; ++i
)
8945 buffer_add_short (buf
, c
[i
]);
8948 return ERR_NOT_IMPLEMENTED
;
8955 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8964 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
8965 objid
= decode_objid (p
, &p
, end
);
8966 err
= get_object (objid
, &obj
);
8968 buffer_add_int (buf
, 1);
8970 buffer_add_int (buf
, 0);
8974 objid
= decode_objid (p
, &p
, end
);
8975 err
= get_object (objid
, &obj
);
8980 case CMD_OBJECT_REF_GET_TYPE
:
8981 /* This handles transparent proxies too */
8982 buffer_add_typeid (buf
, obj
->vtable
->domain
, mono_class_from_mono_type (((MonoReflectionType
*)obj
->vtable
->type
)->type
));
8984 case CMD_OBJECT_REF_GET_VALUES
:
8985 len
= decode_int (p
, &p
, end
);
8987 for (i
= 0; i
< len
; ++i
) {
8988 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
8992 /* Check that the field belongs to the object */
8994 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
8995 if (k
== f
->parent
) {
9001 return ERR_INVALID_FIELDID
;
9003 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
9007 if (mono_class_field_is_special_static (f
))
9008 return ERR_INVALID_FIELDID
;
9010 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
9011 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
9012 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
9013 mono_field_static_get_value (vtable
, f
, val
);
9014 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
9017 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
9021 case CMD_OBJECT_REF_SET_VALUES
:
9022 len
= decode_int (p
, &p
, end
);
9024 for (i
= 0; i
< len
; ++i
) {
9025 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
9029 /* Check that the field belongs to the object */
9031 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
9032 if (k
== f
->parent
) {
9038 return ERR_INVALID_FIELDID
;
9040 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
9044 if (mono_class_field_is_special_static (f
))
9045 return ERR_INVALID_FIELDID
;
9047 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
9048 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
9050 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
9051 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
9056 mono_field_static_set_value (vtable
, f
, val
);
9059 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
9065 case CMD_OBJECT_REF_GET_ADDRESS
:
9066 buffer_add_long (buf
, (gssize
)obj
);
9068 case CMD_OBJECT_REF_GET_DOMAIN
:
9069 buffer_add_domainid (buf
, obj
->vtable
->domain
);
9071 case CMD_OBJECT_REF_GET_INFO
:
9072 buffer_add_typeid (buf
, obj
->vtable
->domain
, mono_class_from_mono_type (((MonoReflectionType
*)obj
->vtable
->type
)->type
));
9073 buffer_add_domainid (buf
, obj
->vtable
->domain
);
9076 return ERR_NOT_IMPLEMENTED
;
9083 command_set_to_string (CommandSet command_set
)
9085 switch (command_set
) {
9088 case CMD_SET_OBJECT_REF
:
9089 return "OBJECT_REF";
9090 case CMD_SET_STRING_REF
:
9091 return "STRING_REF";
9092 case CMD_SET_THREAD
:
9094 case CMD_SET_ARRAY_REF
:
9096 case CMD_SET_EVENT_REQUEST
:
9097 return "EVENT_REQUEST";
9098 case CMD_SET_STACK_FRAME
:
9099 return "STACK_FRAME";
9100 case CMD_SET_APPDOMAIN
:
9102 case CMD_SET_ASSEMBLY
:
9104 case CMD_SET_METHOD
:
9108 case CMD_SET_MODULE
:
9119 static const char* vm_cmds_str
[] = {
9127 "SET_PROTOCOL_VERSION",
9130 "GET_TYPES_FOR_SOURCE_FILE",
9135 static const char* thread_cmds_str
[] = {
9145 static const char* event_cmds_str
[] = {
9148 "REQUEST_CLEAR_ALL_BREAKPOINTS"
9151 static const char* appdomain_cmds_str
[] = {
9153 "GET_FRIENDLY_NAME",
9155 "GET_ENTRY_ASSEMBLY",
9158 "CREATE_BOXED_VALUE"
9161 static const char* assembly_cmds_str
[] = {
9164 "GET_MANIFEST_MODULE",
9170 static const char* module_cmds_str
[] = {
9174 static const char* field_cmds_str
[] = {
9178 static const char* method_cmds_str
[] = {
9180 "GET_DECLARING_TYPE",
9188 "MAKE_GENERIC_METHOD"
9191 static const char* type_cmds_str
[] = {
9199 "IS_ASSIGNABLE_FROM",
9203 "GET_PROPERTY_CATTRS",
9204 "GET_SOURCE_FILES_2",
9206 "GET_METHODS_BY_NAME_FLAGS",
9208 "GET_INTERFACE_MAP",
9212 static const char* stack_frame_cmds_str
[] = {
9218 static const char* array_cmds_str
[] = {
9224 static const char* string_cmds_str
[] = {
9230 static const char* object_cmds_str
[] = {
9241 cmd_to_string (CommandSet set
, int command
)
9249 cmds_len
= G_N_ELEMENTS (vm_cmds_str
);
9251 case CMD_SET_OBJECT_REF
:
9252 cmds
= object_cmds_str
;
9253 cmds_len
= G_N_ELEMENTS (object_cmds_str
);
9255 case CMD_SET_STRING_REF
:
9256 cmds
= string_cmds_str
;
9257 cmds_len
= G_N_ELEMENTS (string_cmds_str
);
9259 case CMD_SET_THREAD
:
9260 cmds
= thread_cmds_str
;
9261 cmds_len
= G_N_ELEMENTS (thread_cmds_str
);
9263 case CMD_SET_ARRAY_REF
:
9264 cmds
= array_cmds_str
;
9265 cmds_len
= G_N_ELEMENTS (array_cmds_str
);
9267 case CMD_SET_EVENT_REQUEST
:
9268 cmds
= event_cmds_str
;
9269 cmds_len
= G_N_ELEMENTS (event_cmds_str
);
9271 case CMD_SET_STACK_FRAME
:
9272 cmds
= stack_frame_cmds_str
;
9273 cmds_len
= G_N_ELEMENTS (stack_frame_cmds_str
);
9275 case CMD_SET_APPDOMAIN
:
9276 cmds
= appdomain_cmds_str
;
9277 cmds_len
= G_N_ELEMENTS (appdomain_cmds_str
);
9279 case CMD_SET_ASSEMBLY
:
9280 cmds
= assembly_cmds_str
;
9281 cmds_len
= G_N_ELEMENTS (assembly_cmds_str
);
9283 case CMD_SET_METHOD
:
9284 cmds
= method_cmds_str
;
9285 cmds_len
= G_N_ELEMENTS (method_cmds_str
);
9288 cmds
= type_cmds_str
;
9289 cmds_len
= G_N_ELEMENTS (type_cmds_str
);
9291 case CMD_SET_MODULE
:
9292 cmds
= module_cmds_str
;
9293 cmds_len
= G_N_ELEMENTS (module_cmds_str
);
9296 cmds
= field_cmds_str
;
9297 cmds_len
= G_N_ELEMENTS (field_cmds_str
);
9300 cmds
= event_cmds_str
;
9301 cmds_len
= G_N_ELEMENTS (event_cmds_str
);
9306 if (command
> 0 && command
<= cmds_len
)
9307 return cmds
[command
- 1];
9313 wait_for_attach (void)
9315 #ifndef DISABLE_SOCKET_TRANSPORT
9316 if (listen_fd
== -1) {
9317 DEBUG (1, fprintf (log_file
, "[dbg] Invalid listening socket\n"));
9321 /* Block and wait for client connection */
9322 conn_fd
= socket_transport_accept (listen_fd
);
9323 DEBUG (1, fprintf (log_file
, "Accepted connection on %d\n", conn_fd
));
9324 if (conn_fd
== -1) {
9325 DEBUG (1, fprintf (log_file
, "[dbg] Bad client connection\n"));
9329 g_assert_not_reached ();
9333 disconnected
= !transport_handshake ();
9335 DEBUG (1, fprintf (log_file
, "Transport handshake failed!\n"));
9345 * This thread handles communication with the debugger client using a JDWP
9348 static guint32 WINAPI
9349 debugger_thread (void *arg
)
9351 int res
, len
, id
, flags
, command_set
= 0, command
= 0;
9352 guint8 header
[HEADER_LENGTH
];
9353 guint8
*data
, *p
, *end
;
9357 gboolean attach_failed
= FALSE
;
9359 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
9361 debugger_thread_id
= GetCurrentThreadId ();
9363 mono_jit_thread_attach (mono_get_root_domain ());
9365 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
9367 mono_set_is_debugger_attached (TRUE
);
9369 if (agent_config
.defer
) {
9370 if (!wait_for_attach ()) {
9371 DEBUG (1, fprintf (log_file
, "[dbg] Can't attach, aborting debugger thread.\n"));
9372 attach_failed
= TRUE
; // Don't abort process when we can't listen
9374 /* Send start event to client */
9375 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_get_main ());
9379 while (!attach_failed
) {
9380 res
= transport_recv (header
, HEADER_LENGTH
);
9382 /* This will break if the socket is closed during shutdown too */
9383 if (res
!= HEADER_LENGTH
) {
9384 DEBUG (1, fprintf (log_file
, "[dbg] transport_recv () returned %d, expected %d.\n", res
, HEADER_LENGTH
));
9389 end
= header
+ HEADER_LENGTH
;
9391 len
= decode_int (p
, &p
, end
);
9392 id
= decode_int (p
, &p
, end
);
9393 flags
= decode_byte (p
, &p
, end
);
9394 command_set
= decode_byte (p
, &p
, end
);
9395 command
= decode_byte (p
, &p
, end
);
9397 g_assert (flags
== 0);
9400 const char *cmd_str
;
9403 cmd_str
= cmd_to_string (command_set
, command
);
9405 sprintf (cmd_num
, "%d", command
);
9409 DEBUG (1, fprintf (log_file
, "[dbg] Command %s(%s) [%d][at=%lx].\n", command_set_to_string (command_set
), cmd_str
, id
, (long)mono_100ns_ticks () / 10000));
9412 data
= g_malloc (len
- HEADER_LENGTH
);
9413 if (len
- HEADER_LENGTH
> 0)
9415 res
= transport_recv (data
, len
- HEADER_LENGTH
);
9416 if (res
!= len
- HEADER_LENGTH
) {
9417 DEBUG (1, fprintf (log_file
, "[dbg] transport_recv () returned %d, expected %d.\n", res
, len
- HEADER_LENGTH
));
9423 end
= data
+ (len
- HEADER_LENGTH
);
9425 buffer_init (&buf
, 128);
9430 /* Process the request */
9431 switch (command_set
) {
9433 err
= vm_commands (command
, id
, p
, end
, &buf
);
9434 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
9435 /* Sent after the invoke is complete */
9438 case CMD_SET_EVENT_REQUEST
:
9439 err
= event_commands (command
, p
, end
, &buf
);
9441 case CMD_SET_APPDOMAIN
:
9442 err
= domain_commands (command
, p
, end
, &buf
);
9444 case CMD_SET_ASSEMBLY
:
9445 err
= assembly_commands (command
, p
, end
, &buf
);
9447 case CMD_SET_MODULE
:
9448 err
= module_commands (command
, p
, end
, &buf
);
9451 err
= field_commands (command
, p
, end
, &buf
);
9454 err
= type_commands (command
, p
, end
, &buf
);
9456 case CMD_SET_METHOD
:
9457 err
= method_commands (command
, p
, end
, &buf
);
9459 case CMD_SET_THREAD
:
9460 err
= thread_commands (command
, p
, end
, &buf
);
9462 case CMD_SET_STACK_FRAME
:
9463 err
= frame_commands (command
, p
, end
, &buf
);
9465 case CMD_SET_ARRAY_REF
:
9466 err
= array_commands (command
, p
, end
, &buf
);
9468 case CMD_SET_STRING_REF
:
9469 err
= string_commands (command
, p
, end
, &buf
);
9471 case CMD_SET_OBJECT_REF
:
9472 err
= object_commands (command
, p
, end
, &buf
);
9475 err
= ERR_NOT_IMPLEMENTED
;
9479 if (buffer_replies
) {
9480 buffer_reply_packet (id
, err
, &buf
);
9482 send_reply_packet (id
, err
, &buf
);
9483 //DEBUG (1, fprintf (log_file, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000));
9487 if (!err
&& command_set
== CMD_SET_VM
) {
9489 case CMD_VM_STOP_BUFFERING
:
9490 send_buffered_reply_packets ();
9491 buffer_replies
= FALSE
;
9493 case CMD_VM_START_BUFFERING
:
9494 buffer_replies
= TRUE
;
9504 if (command_set
== CMD_SET_VM
&& (command
== CMD_VM_DISPOSE
|| command
== CMD_VM_EXIT
))
9508 mono_set_is_debugger_attached (FALSE
);
9510 mono_mutex_lock (&debugger_thread_exited_mutex
);
9511 debugger_thread_exited
= TRUE
;
9512 mono_cond_signal (&debugger_thread_exited_cond
);
9513 mono_mutex_unlock (&debugger_thread_exited_mutex
);
9515 DEBUG (1, fprintf (log_file
, "[dbg] Debugger thread exited.\n"));
9517 if (!attach_failed
&& command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
&& !(vm_death_event_sent
|| mono_runtime_is_shutting_down ())) {
9518 DEBUG (2, fprintf (log_file
, "[dbg] Detached - restarting clean debugger thread.\n"));
9519 start_debugger_thread ();
9525 #else /* DISABLE_DEBUGGER_AGENT */
9528 mono_debugger_agent_parse_options (char *options
)
9530 g_error ("This runtime is configured with the debugger agent disabled.");
9534 mono_debugger_agent_init (void)
9539 mono_debugger_agent_breakpoint_hit (void *sigctx
)
9544 mono_debugger_agent_single_step_event (void *sigctx
)
9549 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
9554 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
9560 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
9561 MonoContext
*catch_ctx
)
9566 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
9571 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
9576 mono_debugger_agent_user_break (void)
9582 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
9587 mono_debugger_agent_debug_log_is_enabled (void)