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
54 /* cygwin's headers do not seem to define these */
55 void WSAAPI
freeaddrinfo (struct addrinfo
*);
56 int WSAAPI
getaddrinfo (const char*,const char*,const struct addrinfo
*,
58 int WSAAPI
getnameinfo(const struct sockaddr
*,socklen_t
,char*,DWORD
,
63 #ifdef PLATFORM_ANDROID
65 #include <linux/tcp.h>
66 #include <sys/endian.h>
69 #include <mono/metadata/mono-debug.h>
70 #include <mono/metadata/mono-debug-debugger.h>
71 #include <mono/metadata/debug-mono-symfile.h>
72 #include <mono/metadata/gc-internal.h>
73 #include <mono/metadata/environment.h>
74 #include <mono/metadata/threads-types.h>
75 #include <mono/metadata/socket-io.h>
76 #include <mono/metadata/assembly.h>
77 #include <mono/metadata/runtime.h>
78 #include <mono/metadata/threadpool.h>
79 #include <mono/metadata/verify-internals.h>
80 #include <mono/utils/mono-semaphore.h>
81 #include <mono/utils/mono-error-internals.h>
82 #include <mono/utils/mono-stack-unwinding.h>
83 #include <mono/utils/mono-time.h>
84 #include <mono/utils/mono-threads.h>
85 #include "debugger-agent.h"
89 On iOS we can't use System.Environment.Exit () as it will do the wrong
92 #if !defined (TARGET_IOS)
93 #define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
97 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
98 #define DISABLE_DEBUGGER_AGENT 1
101 #ifdef DISABLE_SOFT_DEBUG
102 #define DISABLE_DEBUGGER_AGENT 1
105 #ifndef DISABLE_DEBUGGER_AGENT
107 #include <mono/utils/mono-mutex.h>
109 /* Definitions to make backporting to 2.6 easier */
110 //#define MonoInternalThread MonoThread
111 //#define mono_thread_internal_current mono_thread_current
112 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
135 guint32 il_offset
, native_offset
;
139 * If method is gshared, this is the actual instance, otherwise this is equal to
142 MonoMethod
*actual_method
;
144 * This is the method which is visible to debugger clients. Same as method,
145 * except for native-to-managed wrappers.
147 MonoMethod
*api_method
;
149 MonoDebugMethodJitInfo
*jit
;
152 mgreg_t
*reg_locations
[MONO_MAX_IREGS
];
154 * Whenever ctx is set. This is FALSE for the last frame of running threads, since
155 * the frame can become invalid.
160 typedef struct _InvokeData InvokeData
;
168 /* This is the context which needs to be restored after the invoke */
172 * If this is set, invoke this method with the arguments given by ARGS.
176 guint32 suspend_count
;
179 InvokeData
*last_invoke
;
183 MonoThreadUnwindState context
;
185 /* This is computed on demand when it is requested using the wire protocol */
186 /* It is freed up when the thread is resumed */
190 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
193 gboolean frames_up_to_date
;
195 * Points to data about a pending invoke which needs to be executed after the thread
198 InvokeData
*pending_invoke
;
200 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
205 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
206 * within a finite amount of time.
210 * Set to TRUE if this thread is suspended in suspend_current ().
212 gboolean really_suspended
;
213 /* Used to pass the context to the breakpoint/single step handler */
214 MonoContext handler_ctx
;
215 /* Whenever thread_stop () was called for this thread */
218 /* Number of thread interruptions not yet processed */
219 gint32 interrupt_count
;
221 /* Whenever to disable breakpoints (used during invokes) */
222 gboolean disable_breakpoints
;
225 * Number of times this thread has been resumed using resume_thread ().
227 guint32 resume_count
;
229 MonoInternalThread
*thread
;
232 * Information about the frame which transitioned to native code for running
235 StackFrameInfo async_last_frame
;
238 * The context where the stack walk can be started for running threads.
240 MonoThreadUnwindState async_state
;
243 * The context used for filter clauses
245 MonoThreadUnwindState filter_state
;
248 * The callee address of the last mono_runtime_invoke call
250 gpointer invoke_addr
;
252 gboolean abort_requested
;
255 * The current mono_runtime_invoke invocation.
260 * The context where single stepping should resume while the thread is suspended because
261 * of an EXCEPTION event.
263 MonoThreadUnwindState catch_state
;
266 * The context which needs to be restored after handling a single step/breakpoint
267 * event. This is the same as the ctx at step/breakpoint site, but includes changes
268 * to caller saved registers done by set_var ().
270 MonoContext restore_ctx
;
272 /* The currently unloading appdomain */
273 MonoDomain
*domain_unloading
;
278 void (*connect
) (const char *address
);
279 void (*close1
) (void);
280 void (*close2
) (void);
281 gboolean (*send
) (void *buf
, int len
);
282 int (*recv
) (void *buf
, int len
);
286 * Wire Protocol definitions
289 #define HEADER_LENGTH 11
291 #define MAJOR_VERSION 2
292 #define MINOR_VERSION 34
296 CMD_SET_OBJECT_REF
= 9,
297 CMD_SET_STRING_REF
= 10,
299 CMD_SET_ARRAY_REF
= 13,
300 CMD_SET_EVENT_REQUEST
= 15,
301 CMD_SET_STACK_FRAME
= 16,
302 CMD_SET_APPDOMAIN
= 20,
303 CMD_SET_ASSEMBLY
= 21,
312 EVENT_KIND_VM_START
= 0,
313 EVENT_KIND_VM_DEATH
= 1,
314 EVENT_KIND_THREAD_START
= 2,
315 EVENT_KIND_THREAD_DEATH
= 3,
316 EVENT_KIND_APPDOMAIN_CREATE
= 4,
317 EVENT_KIND_APPDOMAIN_UNLOAD
= 5,
318 EVENT_KIND_METHOD_ENTRY
= 6,
319 EVENT_KIND_METHOD_EXIT
= 7,
320 EVENT_KIND_ASSEMBLY_LOAD
= 8,
321 EVENT_KIND_ASSEMBLY_UNLOAD
= 9,
322 EVENT_KIND_BREAKPOINT
= 10,
323 EVENT_KIND_STEP
= 11,
324 EVENT_KIND_TYPE_LOAD
= 12,
325 EVENT_KIND_EXCEPTION
= 13,
326 EVENT_KIND_KEEPALIVE
= 14,
327 EVENT_KIND_USER_BREAK
= 15,
328 EVENT_KIND_USER_LOG
= 16
332 SUSPEND_POLICY_NONE
= 0,
333 SUSPEND_POLICY_EVENT_THREAD
= 1,
334 SUSPEND_POLICY_ALL
= 2
339 ERR_INVALID_OBJECT
= 20,
340 ERR_INVALID_FIELDID
= 25,
341 ERR_INVALID_FRAMEID
= 30,
342 ERR_NOT_IMPLEMENTED
= 100,
343 ERR_NOT_SUSPENDED
= 101,
344 ERR_INVALID_ARGUMENT
= 102,
346 ERR_NO_INVOCATION
= 104,
347 ERR_ABSENT_INFORMATION
= 105,
348 ERR_NO_SEQ_POINT_AT_IL_OFFSET
= 106,
349 ERR_LOADER_ERROR
= 200, /*XXX extend the protocol to pass this information down the pipe */
354 MOD_KIND_THREAD_ONLY
= 3,
355 MOD_KIND_LOCATION_ONLY
= 7,
356 MOD_KIND_EXCEPTION_ONLY
= 8,
358 MOD_KIND_ASSEMBLY_ONLY
= 11,
359 MOD_KIND_SOURCE_FILE_ONLY
= 12,
360 MOD_KIND_TYPE_NAME_ONLY
= 13,
376 STEP_FILTER_NONE
= 0,
377 STEP_FILTER_STATIC_CTOR
= 1,
378 STEP_FILTER_DEBUGGER_HIDDEN
= 2,
379 STEP_FILTER_DEBUGGER_STEP_THROUGH
= 4,
380 STEP_FILTER_DEBUGGER_NON_USER_CODE
= 8
384 TOKEN_TYPE_STRING
= 0,
386 TOKEN_TYPE_FIELD
= 2,
387 TOKEN_TYPE_METHOD
= 3,
388 TOKEN_TYPE_UNKNOWN
= 4
392 VALUE_TYPE_ID_NULL
= 0xf0,
393 VALUE_TYPE_ID_TYPE
= 0xf1,
394 VALUE_TYPE_ID_PARENT_VTYPE
= 0xf2
398 FRAME_FLAG_DEBUGGER_INVOKE
= 1,
399 FRAME_FLAG_NATIVE_TRANSITION
= 2
403 INVOKE_FLAG_DISABLE_BREAKPOINTS
= 1,
404 INVOKE_FLAG_SINGLE_THREADED
= 2
408 BINDING_FLAGS_IGNORE_CASE
= 0x70000000,
409 } BindingFlagsExtensions
;
413 CMD_VM_ALL_THREADS
= 2,
418 CMD_VM_INVOKE_METHOD
= 7,
419 CMD_VM_SET_PROTOCOL_VERSION
= 8,
420 CMD_VM_ABORT_INVOKE
= 9,
421 CMD_VM_SET_KEEPALIVE
= 10,
422 CMD_VM_GET_TYPES_FOR_SOURCE_FILE
= 11,
423 CMD_VM_GET_TYPES
= 12,
424 CMD_VM_INVOKE_METHODS
= 13,
425 CMD_VM_START_BUFFERING
= 14,
426 CMD_VM_STOP_BUFFERING
= 15
430 CMD_THREAD_GET_FRAME_INFO
= 1,
431 CMD_THREAD_GET_NAME
= 2,
432 CMD_THREAD_GET_STATE
= 3,
433 CMD_THREAD_GET_INFO
= 4,
434 CMD_THREAD_GET_ID
= 5,
435 CMD_THREAD_GET_TID
= 6,
436 CMD_THREAD_SET_IP
= 7
440 CMD_EVENT_REQUEST_SET
= 1,
441 CMD_EVENT_REQUEST_CLEAR
= 2,
442 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
= 3
450 CMD_APPDOMAIN_GET_ROOT_DOMAIN
= 1,
451 CMD_APPDOMAIN_GET_FRIENDLY_NAME
= 2,
452 CMD_APPDOMAIN_GET_ASSEMBLIES
= 3,
453 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
= 4,
454 CMD_APPDOMAIN_CREATE_STRING
= 5,
455 CMD_APPDOMAIN_GET_CORLIB
= 6,
456 CMD_APPDOMAIN_CREATE_BOXED_VALUE
= 7
460 CMD_ASSEMBLY_GET_LOCATION
= 1,
461 CMD_ASSEMBLY_GET_ENTRY_POINT
= 2,
462 CMD_ASSEMBLY_GET_MANIFEST_MODULE
= 3,
463 CMD_ASSEMBLY_GET_OBJECT
= 4,
464 CMD_ASSEMBLY_GET_TYPE
= 5,
465 CMD_ASSEMBLY_GET_NAME
= 6
469 CMD_MODULE_GET_INFO
= 1,
473 CMD_FIELD_GET_INFO
= 1,
477 CMD_METHOD_GET_NAME
= 1,
478 CMD_METHOD_GET_DECLARING_TYPE
= 2,
479 CMD_METHOD_GET_DEBUG_INFO
= 3,
480 CMD_METHOD_GET_PARAM_INFO
= 4,
481 CMD_METHOD_GET_LOCALS_INFO
= 5,
482 CMD_METHOD_GET_INFO
= 6,
483 CMD_METHOD_GET_BODY
= 7,
484 CMD_METHOD_RESOLVE_TOKEN
= 8,
485 CMD_METHOD_GET_CATTRS
= 9,
486 CMD_METHOD_MAKE_GENERIC_METHOD
= 10
490 CMD_TYPE_GET_INFO
= 1,
491 CMD_TYPE_GET_METHODS
= 2,
492 CMD_TYPE_GET_FIELDS
= 3,
493 CMD_TYPE_GET_VALUES
= 4,
494 CMD_TYPE_GET_OBJECT
= 5,
495 CMD_TYPE_GET_SOURCE_FILES
= 6,
496 CMD_TYPE_SET_VALUES
= 7,
497 CMD_TYPE_IS_ASSIGNABLE_FROM
= 8,
498 CMD_TYPE_GET_PROPERTIES
= 9,
499 CMD_TYPE_GET_CATTRS
= 10,
500 CMD_TYPE_GET_FIELD_CATTRS
= 11,
501 CMD_TYPE_GET_PROPERTY_CATTRS
= 12,
502 CMD_TYPE_GET_SOURCE_FILES_2
= 13,
503 CMD_TYPE_GET_VALUES_2
= 14,
504 CMD_TYPE_GET_METHODS_BY_NAME_FLAGS
= 15,
505 CMD_TYPE_GET_INTERFACES
= 16,
506 CMD_TYPE_GET_INTERFACE_MAP
= 17,
507 CMD_TYPE_IS_INITIALIZED
= 18,
508 CMD_TYPE_CREATE_INSTANCE
= 19
512 CMD_STACK_FRAME_GET_VALUES
= 1,
513 CMD_STACK_FRAME_GET_THIS
= 2,
514 CMD_STACK_FRAME_SET_VALUES
= 3
518 CMD_ARRAY_REF_GET_LENGTH
= 1,
519 CMD_ARRAY_REF_GET_VALUES
= 2,
520 CMD_ARRAY_REF_SET_VALUES
= 3,
524 CMD_STRING_REF_GET_VALUE
= 1,
525 CMD_STRING_REF_GET_LENGTH
= 2,
526 CMD_STRING_REF_GET_CHARS
= 3
530 CMD_OBJECT_REF_GET_TYPE
= 1,
531 CMD_OBJECT_REF_GET_VALUES
= 2,
532 CMD_OBJECT_REF_IS_COLLECTED
= 3,
533 CMD_OBJECT_REF_GET_ADDRESS
= 4,
534 CMD_OBJECT_REF_GET_DOMAIN
= 5,
535 CMD_OBJECT_REF_SET_VALUES
= 6,
536 CMD_OBJECT_REF_GET_INFO
= 7,
542 int count
; /* For kind == MOD_KIND_COUNT */
543 MonoInternalThread
*thread
; /* For kind == MOD_KIND_THREAD_ONLY */
544 MonoClass
*exc_class
; /* For kind == MONO_KIND_EXCEPTION_ONLY */
545 MonoAssembly
**assemblies
; /* For kind == MONO_KIND_ASSEMBLY_ONLY */
546 GHashTable
*source_files
; /* For kind == MONO_KIND_SOURCE_FILE_ONLY */
547 GHashTable
*type_names
; /* For kind == MONO_KIND_TYPE_NAME_ONLY */
548 StepFilter filter
; /* For kind == MOD_KIND_STEP */
550 gboolean caught
, uncaught
, subclasses
; /* For kind == MOD_KIND_EXCEPTION_ONLY */
559 Modifier modifiers
[MONO_ZERO_LEN_ARRAY
];
563 * Describes a single step request.
567 MonoInternalThread
*thread
;
573 MonoMethod
*last_method
;
575 /* Whenever single stepping is performed using start/stop_single_stepping () */
577 /* The list of breakpoints used to implement step-over */
579 /* The number of frames at the start of a step-over */
584 * Contains additional information for an event
587 /* For EVENT_KIND_EXCEPTION */
589 MonoContext catch_ctx
;
591 /* For EVENT_KIND_USER_LOG */
593 char *category
, *message
;
594 /* For EVENT_KIND_TYPE_LOAD */
598 /* Dummy structure used for the profiler callbacks */
604 guint8
*buf
, *p
, *end
;
607 typedef struct ReplyPacket
{
613 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
616 #define get_last_sock_error() WSAGetLastError()
617 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
618 #define MONO_EINTR WSAEINTR
620 #define get_last_sock_error() errno
621 #define MONO_EWOULDBLOCK EWOULDBLOCK
622 #define MONO_EINTR EINTR
625 #define CHECK_PROTOCOL_VERSION(major,minor) \
626 (protocol_version_set && (major_version > (major) || (major_version == (major) && minor_version >= (minor))))
632 static AgentConfig agent_config
;
635 * Whenever the agent is fully initialized.
636 * When using the onuncaught or onthrow options, only some parts of the agent are
637 * initialized on startup, and the full initialization which includes connection
638 * establishment and the startup of the agent thread is only done in response to
641 static gint32 inited
;
643 #ifndef DISABLE_SOCKET_TRANSPORT
645 static int listen_fd
;
648 static int packet_id
= 0;
650 static int objref_id
= 0;
652 static int event_request_id
= 0;
654 static int frame_id
= 0;
656 static GPtrArray
*event_requests
;
658 static MonoNativeTlsKey debugger_tls_id
;
660 static gboolean vm_start_event_sent
, vm_death_event_sent
, disconnected
;
662 /* Maps MonoInternalThread -> DebuggerTlsData */
663 static MonoGHashTable
*thread_to_tls
;
665 /* Maps tid -> MonoInternalThread */
666 static MonoGHashTable
*tid_to_thread
;
668 /* Maps tid -> MonoThread (not MonoInternalThread) */
669 static MonoGHashTable
*tid_to_thread_obj
;
671 static gsize debugger_thread_id
;
673 static HANDLE debugger_thread_handle
;
675 static int log_level
;
677 static gboolean embedding
;
679 static FILE *log_file
;
681 /* Assemblies whose assembly load event has no been sent yet */
682 /* Protected by the dbg lock */
683 static GPtrArray
*pending_assembly_loads
;
685 /* Whenever the debugger thread has exited */
686 static gboolean debugger_thread_exited
;
688 /* Cond variable used to wait for debugger_thread_exited becoming true */
689 static mono_cond_t debugger_thread_exited_cond
;
691 /* Mutex for the cond var above */
692 static mono_mutex_t debugger_thread_exited_mutex
;
694 static DebuggerProfiler debugger_profiler
;
696 /* The single step request instance */
697 static SingleStepReq
*ss_req
= NULL
;
698 static gpointer ss_invoke_addr
= NULL
;
700 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
701 /* Number of single stepping operations in progress */
705 /* The protocol version of the client */
706 static int major_version
, minor_version
;
708 /* Whenever the variables above are set by the client */
709 static gboolean protocol_version_set
;
711 /* A hash table containing all active domains */
712 static GHashTable
*domains
;
714 /* The number of times the runtime is suspended */
715 static gint32 suspend_count
;
717 /* Whenever to buffer reply messages and send them together */
718 static gboolean buffer_replies
;
720 /* Buffered reply packets */
721 static ReplyPacket reply_packets
[128];
724 #define dbg_lock() EnterCriticalSection (&debug_mutex)
725 #define dbg_unlock() LeaveCriticalSection (&debug_mutex)
726 static CRITICAL_SECTION debug_mutex
;
728 static void transport_init (void);
729 static void transport_connect (const char *address
);
730 static gboolean
transport_handshake (void);
731 static void register_transport (DebuggerTransport
*trans
);
733 static guint32 WINAPI
debugger_thread (void *arg
);
735 static void runtime_initialized (MonoProfiler
*prof
);
737 static void runtime_shutdown (MonoProfiler
*prof
);
739 static void thread_startup (MonoProfiler
*prof
, uintptr_t tid
);
741 static void thread_end (MonoProfiler
*prof
, uintptr_t tid
);
743 static void appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
);
745 static void appdomain_start_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
747 static void appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
);
749 static void emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
);
751 static void emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
);
753 static void invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
);
755 static void assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
);
757 static void assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
);
759 static void emit_assembly_load (gpointer assembly
, gpointer user_data
);
761 static void emit_type_load (gpointer key
, gpointer type
, gpointer user_data
);
763 static void start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
765 static void end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
);
767 static void jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
);
769 static void add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*jinfo
);
771 static void start_single_stepping (void);
773 static void stop_single_stepping (void);
775 static void suspend_current (void);
777 static void clear_event_requests_for_assembly (MonoAssembly
*assembly
);
779 static void clear_types_for_assembly (MonoAssembly
*assembly
);
781 static void clear_breakpoints_for_domain (MonoDomain
*domain
);
783 static void process_profiler_event (EventKind event
, gpointer arg
);
785 /* Submodule init/cleanup */
786 static void breakpoints_init (void);
787 static void breakpoints_cleanup (void);
789 static void objrefs_init (void);
790 static void objrefs_cleanup (void);
792 static void ids_init (void);
793 static void ids_cleanup (void);
795 static void suspend_init (void);
797 static void ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
);
798 static ErrorCode
ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
);
799 static void ss_destroy (SingleStepReq
*req
);
801 static void start_debugger_thread (void);
802 static void stop_debugger_thread (void);
804 static void finish_agent_init (gboolean on_startup
);
806 static void process_profiler_event (EventKind event
, gpointer arg
);
808 static void invalidate_frames (DebuggerTlsData
*tls
);
810 #ifndef DISABLE_SOCKET_TRANSPORT
812 register_socket_transport (void);
816 parse_address (char *address
, char **host
, int *port
)
818 char *pos
= strchr (address
, ':');
820 if (pos
== NULL
|| pos
== address
)
823 *host
= g_malloc (pos
- address
+ 1);
824 strncpy (*host
, address
, pos
- address
);
825 (*host
) [pos
- address
] = '\0';
827 *port
= atoi (pos
+ 1);
835 fprintf (stderr
, "Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
836 fprintf (stderr
, "Available options:\n");
837 fprintf (stderr
, " transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
838 fprintf (stderr
, " address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
839 fprintf (stderr
, " loglevel=<n>\t\t\tLog level (defaults to 0)\n");
840 fprintf (stderr
, " logfile=<file>\t\tFile to log to (defaults to stdout)\n");
841 fprintf (stderr
, " suspend=y/n\t\t\tWhether to suspend after startup.\n");
842 fprintf (stderr
, " timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
843 fprintf (stderr
, " server=y/n\t\t\tWhether to listen for a client connection.\n");
844 fprintf (stderr
, " keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
845 fprintf (stderr
, " setpgid=y/n\t\t\tWhether to call setpid(0, 0) after startup.\n");
846 fprintf (stderr
, " help\t\t\t\tPrint this help.\n");
850 parse_flag (const char *option
, char *flag
)
852 if (!strcmp (flag
, "y"))
854 else if (!strcmp (flag
, "n"))
857 fprintf (stderr
, "debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option
);
864 mono_debugger_agent_parse_options (char *options
)
871 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
872 fprintf (stderr
, "--debugger-agent is not supported on this platform.\n");
876 extra
= g_getenv ("MONO_SDB_ENV_OPTIONS");
878 options
= g_strdup_printf ("%s,%s", options
, extra
);
880 agent_config
.enabled
= TRUE
;
881 agent_config
.suspend
= TRUE
;
882 agent_config
.server
= FALSE
;
883 agent_config
.defer
= FALSE
;
884 agent_config
.address
= NULL
;
886 //agent_config.log_level = 10;
888 args
= g_strsplit (options
, ",", -1);
889 for (ptr
= args
; ptr
&& *ptr
; ptr
++) {
892 if (strncmp (arg
, "transport=", 10) == 0) {
893 agent_config
.transport
= g_strdup (arg
+ 10);
894 } else if (strncmp (arg
, "address=", 8) == 0) {
895 agent_config
.address
= g_strdup (arg
+ 8);
896 } else if (strncmp (arg
, "loglevel=", 9) == 0) {
897 agent_config
.log_level
= atoi (arg
+ 9);
898 } else if (strncmp (arg
, "logfile=", 8) == 0) {
899 agent_config
.log_file
= g_strdup (arg
+ 8);
900 } else if (strncmp (arg
, "suspend=", 8) == 0) {
901 agent_config
.suspend
= parse_flag ("suspend", arg
+ 8);
902 } else if (strncmp (arg
, "server=", 7) == 0) {
903 agent_config
.server
= parse_flag ("server", arg
+ 7);
904 } else if (strncmp (arg
, "onuncaught=", 11) == 0) {
905 agent_config
.onuncaught
= parse_flag ("onuncaught", arg
+ 11);
906 } else if (strncmp (arg
, "onthrow=", 8) == 0) {
907 /* We support multiple onthrow= options */
908 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (arg
+ 8));
909 } else if (strncmp (arg
, "onthrow", 7) == 0) {
910 agent_config
.onthrow
= g_slist_append (agent_config
.onthrow
, g_strdup (""));
911 } else if (strncmp (arg
, "help", 4) == 0) {
914 } else if (strncmp (arg
, "timeout=", 8) == 0) {
915 agent_config
.timeout
= atoi (arg
+ 8);
916 } else if (strncmp (arg
, "launch=", 7) == 0) {
917 agent_config
.launch
= g_strdup (arg
+ 7);
918 } else if (strncmp (arg
, "embedding=", 10) == 0) {
919 agent_config
.embedding
= atoi (arg
+ 10) == 1;
920 } else if (strncmp (arg
, "keepalive=", 10) == 0) {
921 agent_config
.keepalive
= atoi (arg
+ 10);
922 } else if (strncmp (arg
, "setpgid=", 8) == 0) {
923 agent_config
.setpgid
= parse_flag ("setpgid", arg
+ 8);
930 if (agent_config
.server
&& !agent_config
.suspend
) {
931 /* Waiting for deferred attachment */
932 agent_config
.defer
= TRUE
;
933 if (agent_config
.address
== NULL
) {
934 agent_config
.address
= g_strdup_printf ("0.0.0.0:%u", 56000 + (getpid () % 1000));
938 //agent_config.log_level = 0;
940 if (agent_config
.transport
== NULL
) {
941 fprintf (stderr
, "debugger-agent: The 'transport' option is mandatory.\n");
945 if (agent_config
.address
== NULL
&& !agent_config
.server
) {
946 fprintf (stderr
, "debugger-agent: The 'address' option is mandatory.\n");
951 if (!strcmp (agent_config
.transport
, "dt_socket")) {
952 if (agent_config
.address
&& parse_address (agent_config
.address
, &host
, &port
)) {
953 fprintf (stderr
, "debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
960 mono_debugger_agent_init (void)
962 InitializeCriticalSection (&debug_mutex
);
964 if (!agent_config
.enabled
)
969 /* Need to know whenever a thread has acquired the loader mutex */
970 mono_loader_lock_track_ownership (TRUE
);
972 event_requests
= g_ptr_array_new ();
974 mono_mutex_init (&debugger_thread_exited_mutex
);
975 mono_cond_init (&debugger_thread_exited_cond
, NULL
);
977 mono_profiler_install ((MonoProfiler
*)&debugger_profiler
, runtime_shutdown
);
978 mono_profiler_set_events (MONO_PROFILE_APPDOMAIN_EVENTS
| MONO_PROFILE_THREADS
| MONO_PROFILE_ASSEMBLY_EVENTS
| MONO_PROFILE_JIT_COMPILATION
| MONO_PROFILE_METHOD_EVENTS
);
979 mono_profiler_install_runtime_initialized (runtime_initialized
);
980 mono_profiler_install_appdomain (NULL
, appdomain_load
, appdomain_start_unload
, appdomain_unload
);
981 mono_profiler_install_thread (thread_startup
, thread_end
);
982 mono_profiler_install_assembly (NULL
, assembly_load
, assembly_unload
, NULL
);
983 mono_profiler_install_jit_end (jit_end
);
984 mono_profiler_install_method_invoke (start_runtime_invoke
, end_runtime_invoke
);
986 mono_native_tls_alloc (&debugger_tls_id
, NULL
);
988 thread_to_tls
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
989 MONO_GC_REGISTER_ROOT_FIXED (thread_to_tls
);
991 tid_to_thread
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
992 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread
);
994 tid_to_thread_obj
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_VALUE_GC
);
995 MONO_GC_REGISTER_ROOT_FIXED (tid_to_thread_obj
);
997 pending_assembly_loads
= g_ptr_array_new ();
998 domains
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1000 log_level
= agent_config
.log_level
;
1002 embedding
= agent_config
.embedding
;
1003 disconnected
= TRUE
;
1005 if (agent_config
.log_file
) {
1006 log_file
= fopen (agent_config
.log_file
, "w+");
1008 fprintf (stderr
, "Unable to create log file '%s': %s.\n", agent_config
.log_file
, strerror (errno
));
1017 breakpoints_init ();
1020 mini_get_debug_options ()->gen_seq_points
= TRUE
;
1022 * This is needed because currently we don't handle liveness info.
1024 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
1026 #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
1027 /* This is needed because we can't set local variables in registers yet */
1028 mono_disable_optimizations (MONO_OPT_LINEARS
);
1032 * The stack walk done from thread_interrupt () needs to be signal safe, but it
1033 * isn't, since it can call into mono_aot_find_jit_info () which is not signal
1034 * safe (#3411). So load AOT info eagerly when the debugger is running as a
1037 mini_get_debug_options ()->load_aot_jit_info_eagerly
= TRUE
;
1040 if (agent_config
.setpgid
)
1044 if (!agent_config
.onuncaught
&& !agent_config
.onthrow
)
1045 finish_agent_init (TRUE
);
1049 * finish_agent_init:
1051 * Finish the initialization of the agent. This involves connecting the transport
1052 * and starting the agent thread. This is either done at startup, or
1053 * in response to some event like an unhandled exception.
1056 finish_agent_init (gboolean on_startup
)
1060 if (InterlockedCompareExchange (&inited
, 1, 0) == 1)
1063 if (agent_config
.launch
) {
1066 // FIXME: Generated address
1067 // FIXME: Races with transport_connect ()
1069 argv
[0] = agent_config
.launch
;
1070 argv
[1] = agent_config
.transport
;
1071 argv
[2] = agent_config
.address
;
1074 res
= g_spawn_async_with_pipes (NULL
, argv
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1076 fprintf (stderr
, "Failed to execute '%s'.\n", agent_config
.launch
);
1081 transport_connect (agent_config
.address
);
1084 /* Do some which is usually done after sending the VMStart () event */
1085 vm_start_event_sent
= TRUE
;
1086 start_debugger_thread ();
1091 mono_debugger_agent_cleanup (void)
1096 stop_debugger_thread ();
1098 breakpoints_cleanup ();
1102 mono_mutex_destroy (&debugger_thread_exited_mutex
);
1103 mono_cond_destroy (&debugger_thread_exited_cond
);
1110 #ifndef DISABLE_SOCKET_TRANSPORT
1115 * recv() + handle incomplete reads and EINTR
1118 socket_transport_recv (void *buf
, int len
)
1124 static gint32 last_keepalive
;
1129 res
= recv (fd
, (char *) buf
+ total
, len
- total
, flags
);
1132 if (agent_config
.keepalive
) {
1133 gboolean need_keepalive
= FALSE
;
1134 if (res
== -1 && get_last_sock_error () == MONO_EWOULDBLOCK
) {
1135 need_keepalive
= TRUE
;
1136 } else if (res
== -1) {
1137 /* This could happen if recv () is interrupted repeatedly */
1138 msecs
= mono_msec_ticks ();
1139 if (msecs
- last_keepalive
>= agent_config
.keepalive
) {
1140 need_keepalive
= TRUE
;
1141 last_keepalive
= msecs
;
1144 if (need_keepalive
) {
1145 process_profiler_event (EVENT_KIND_KEEPALIVE
, NULL
);
1149 } while ((res
> 0 && total
< len
) || (res
== -1 && get_last_sock_error () == MONO_EINTR
));
1154 #define HAVE_GETADDRINFO 1
1158 set_keepalive (void)
1163 if (!agent_config
.keepalive
|| !conn_fd
)
1166 tv
.tv_sec
= agent_config
.keepalive
/ 1000;
1167 tv
.tv_usec
= (agent_config
.keepalive
% 1000) * 1000;
1169 result
= setsockopt (conn_fd
, SOL_SOCKET
, SO_RCVTIMEO
, (char *) &tv
, sizeof(struct timeval
));
1170 g_assert (result
>= 0);
1174 socket_transport_accept (int socket_fd
)
1176 conn_fd
= accept (socket_fd
, NULL
, NULL
);
1177 if (conn_fd
== -1) {
1178 fprintf (stderr
, "debugger-agent: Unable to listen on %d\n", socket_fd
);
1180 DEBUG (1, fprintf (log_file
, "Accepted connection from client, connection fd=%d.\n", conn_fd
));
1187 socket_transport_send (void *data
, int len
)
1192 res
= send (conn_fd
, data
, len
, 0);
1193 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1201 * socket_transport_connect:
1203 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
1206 socket_transport_connect (const char *address
)
1208 #ifdef HAVE_GETADDRINFO
1209 struct addrinfo hints
;
1210 struct addrinfo
*result
, *rp
;
1212 struct hostent
*result
;
1214 int sfd
= -1, s
, res
;
1215 char port_string
[128];
1219 if (agent_config
.address
) {
1220 res
= parse_address (agent_config
.address
, &host
, &port
);
1221 g_assert (res
== 0);
1231 sprintf (port_string
, "%d", port
);
1233 mono_network_init ();
1235 /* Obtain address(es) matching host/port */
1236 #ifdef HAVE_GETADDRINFO
1237 memset (&hints
, 0, sizeof (struct addrinfo
));
1238 hints
.ai_family
= AF_UNSPEC
; /* Allow IPv4 or IPv6 */
1239 hints
.ai_socktype
= SOCK_STREAM
; /* Datagram socket */
1241 hints
.ai_protocol
= 0; /* Any protocol */
1243 s
= getaddrinfo (host
, port_string
, &hints
, &result
);
1245 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %s\n", host
, port
, gai_strerror (s
));
1249 /* The PS3 doesn't even have _r or hstrerror () */
1250 result
= gethostbyname (host
);
1252 fprintf (stderr
, "debugger-agent: Unable to resolve %s:%d: %d\n", host
, port
, h_errno
);
1257 if (agent_config
.server
) {
1258 #ifdef HAVE_GETADDRINFO
1259 /* Wait for a connection */
1261 struct sockaddr_in addr
;
1264 /* No address, generate one */
1265 sfd
= socket (AF_INET
, SOCK_STREAM
, 0);
1268 /* This will bind the socket to a random port */
1269 res
= listen (sfd
, 16);
1271 fprintf (stderr
, "debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
1276 addrlen
= sizeof (addr
);
1277 memset (&addr
, 0, sizeof (addr
));
1278 res
= getsockname (sfd
, (struct sockaddr
*)&addr
, &addrlen
);
1279 g_assert (res
== 0);
1281 host
= (char*)"127.0.0.1";
1282 port
= ntohs (addr
.sin_port
);
1284 /* Emit the address to stdout */
1285 /* FIXME: Should print another interface, not localhost */
1286 printf ("%s:%d\n", host
, port
);
1288 /* Listen on the provided address */
1289 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1292 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1297 if (setsockopt (sfd
, SOL_SOCKET
, SO_REUSEADDR
, &n
, sizeof(n
)) == -1)
1300 res
= bind (sfd
, rp
->ai_addr
, rp
->ai_addrlen
);
1304 res
= listen (sfd
, 16);
1313 * this function is not present on win2000 which we still support, and the
1314 * workaround described here:
1315 * http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx
1316 * only works with MSVC.
1318 #ifdef HAVE_GETADDRINFO
1319 freeaddrinfo (result
);
1324 if (agent_config
.defer
)
1327 DEBUG (1, fprintf (log_file
, "Listening on %s:%d (timeout=%d ms)...\n", host
, port
, agent_config
.timeout
));
1329 if (agent_config
.timeout
) {
1334 tv
.tv_usec
= agent_config
.timeout
* 1000;
1336 FD_SET (sfd
, &readfds
);
1337 res
= select (sfd
+ 1, &readfds
, NULL
, NULL
, &tv
);
1339 fprintf (stderr
, "debugger-agent: Timed out waiting to connect.\n");
1344 conn_fd
= socket_transport_accept (sfd
);
1348 DEBUG (1, fprintf (log_file
, "Accepted connection from client, socket fd=%d.\n", conn_fd
));
1351 #endif /* HAVE_GETADDRINFO */
1353 /* Connect to the specified address */
1354 #ifdef HAVE_GETADDRINFO
1355 /* FIXME: Respect the timeout */
1356 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
1357 sfd
= socket (rp
->ai_family
, rp
->ai_socktype
,
1362 if (connect (sfd
, rp
->ai_addr
, rp
->ai_addrlen
) != -1)
1363 break; /* Success */
1369 fprintf (stderr
, "debugger-agent: Unable to connect to %s:%d\n", host
, port
);
1373 sfd
= socket (result
->h_addrtype
, SOCK_STREAM
, 0);
1375 g_assert_not_reached ();
1376 res
= connect (sfd
, (void*)result
->h_addr_list
[0], result
->h_length
);
1378 g_assert_not_reached ();
1384 /* See the comment above */
1385 #ifdef HAVE_GETADDRINFO
1386 freeaddrinfo (result
);
1391 if (!transport_handshake ())
1396 socket_transport_close1 (void)
1398 /* This will interrupt the agent thread */
1399 /* Close the read part only so it can still send back replies */
1400 /* Also shut down the connection listener so that we can exit normally */
1402 /* SD_RECEIVE doesn't break the recv in the debugger thread */
1403 shutdown (conn_fd
, SD_BOTH
);
1404 shutdown (listen_fd
, SD_BOTH
);
1405 closesocket (listen_fd
);
1407 shutdown (conn_fd
, SHUT_RD
);
1408 shutdown (listen_fd
, SHUT_RDWR
);
1414 socket_transport_close2 (void)
1417 shutdown (conn_fd
, SD_BOTH
);
1419 shutdown (conn_fd
, SHUT_RDWR
);
1424 register_socket_transport (void)
1426 DebuggerTransport trans
;
1428 trans
.name
= "dt_socket";
1429 trans
.connect
= socket_transport_connect
;
1430 trans
.close1
= socket_transport_close1
;
1431 trans
.close2
= socket_transport_close2
;
1432 trans
.send
= socket_transport_send
;
1433 trans
.recv
= socket_transport_recv
;
1435 register_transport (&trans
);
1438 #endif /* DISABLE_SOCKET_TRANSPORT */
1444 #define MAX_TRANSPORTS 16
1446 static DebuggerTransport
*transport
;
1448 static DebuggerTransport transports
[MAX_TRANSPORTS
];
1449 static int ntransports
;
1452 mono_debugger_agent_register_transport (DebuggerTransport
*trans
);
1455 mono_debugger_agent_register_transport (DebuggerTransport
*trans
)
1457 register_transport (trans
);
1461 register_transport (DebuggerTransport
*trans
)
1463 g_assert (ntransports
< MAX_TRANSPORTS
);
1465 memcpy (&transports
[ntransports
], trans
, sizeof (DebuggerTransport
));
1470 transport_init (void)
1474 #ifndef DISABLE_SOCKET_TRANSPORT
1475 register_socket_transport ();
1478 for (i
= 0; i
< ntransports
; ++i
) {
1479 if (!strcmp (agent_config
.transport
, transports
[i
].name
))
1482 if (i
== ntransports
) {
1483 fprintf (stderr
, "debugger-agent: The supported values for the 'transport' option are: ");
1484 for (i
= 0; i
< ntransports
; ++i
)
1485 fprintf (stderr
, "%s'%s'", i
> 0 ? ", " : "", transports
[i
].name
);
1486 fprintf (stderr
, "\n");
1489 transport
= &transports
[i
];
1493 transport_connect (const char *address
)
1495 transport
->connect (address
);
1499 transport_close1 (void)
1501 transport
->close1 ();
1505 transport_close2 (void)
1507 transport
->close2 ();
1511 transport_send (void *buf
, int len
)
1513 return transport
->send (buf
, len
);
1517 transport_recv (void *buf
, int len
)
1519 return transport
->recv (buf
, len
);
1523 mono_debugger_agent_transport_handshake (void)
1525 return transport_handshake ();
1529 transport_handshake (void)
1531 char handshake_msg
[128];
1535 disconnected
= TRUE
;
1537 /* Write handshake message */
1538 sprintf (handshake_msg
, "DWP-Handshake");
1540 res
= transport_send (handshake_msg
, strlen (handshake_msg
));
1541 } while (res
== -1 && get_last_sock_error () == MONO_EINTR
);
1542 g_assert (res
!= -1);
1545 res
= transport_recv (buf
, strlen (handshake_msg
));
1546 if ((res
!= strlen (handshake_msg
)) || (memcmp (buf
, handshake_msg
, strlen (handshake_msg
) != 0))) {
1547 fprintf (stderr
, "debugger-agent: DWP handshake failed.\n");
1552 * To support older clients, the client sends its protocol version after connecting
1553 * using a command. Until that is received, default to our protocol version.
1555 major_version
= MAJOR_VERSION
;
1556 minor_version
= MINOR_VERSION
;
1557 protocol_version_set
= FALSE
;
1559 #ifndef DISABLE_SOCKET_TRANSPORT
1560 // FIXME: Move this somewhere else
1562 * Set TCP_NODELAY on the socket so the client receives events/command
1563 * results immediately.
1567 int result
= setsockopt (conn_fd
,
1572 g_assert (result
>= 0);
1578 disconnected
= FALSE
;
1583 stop_debugger_thread (void)
1588 transport_close1 ();
1591 * Wait for the thread to exit.
1593 * If we continue with the shutdown without waiting for it, then the client might
1594 * not receive an answer to its last command like a resume.
1595 * The WaitForSingleObject infrastructure doesn't seem to work during shutdown, so
1598 //WaitForSingleObject (debugger_thread_handle, INFINITE);
1599 if (GetCurrentThreadId () != debugger_thread_id
) {
1601 mono_mutex_lock (&debugger_thread_exited_mutex
);
1602 if (!debugger_thread_exited
) {
1604 if (WAIT_TIMEOUT
== WaitForSingleObject(debugger_thread_exited_cond
, 0)) {
1605 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1607 mono_mutex_lock (&debugger_thread_exited_mutex
);
1610 mono_cond_wait (&debugger_thread_exited_cond
, &debugger_thread_exited_mutex
);
1613 mono_mutex_unlock (&debugger_thread_exited_mutex
);
1614 } while (!debugger_thread_exited
);
1617 transport_close2 ();
1621 start_debugger_thread (void)
1623 debugger_thread_handle
= mono_threads_create_thread (debugger_thread
, NULL
, 0, 0, NULL
);
1624 g_assert (debugger_thread_handle
);
1628 * Functions to decode protocol data
1632 decode_byte (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1635 g_assert (*endbuf
<= limit
);
1640 decode_int (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1643 g_assert (*endbuf
<= limit
);
1645 return (((int)buf
[0]) << 24) | (((int)buf
[1]) << 16) | (((int)buf
[2]) << 8) | (((int)buf
[3]) << 0);
1648 static inline gint64
1649 decode_long (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1651 guint32 high
= decode_int (buf
, &buf
, limit
);
1652 guint32 low
= decode_int (buf
, &buf
, limit
);
1656 return ((((guint64
)high
) << 32) | ((guint64
)low
));
1660 decode_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1662 return decode_int (buf
, endbuf
, limit
);
1666 decode_string (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
1668 int len
= decode_int (buf
, &buf
, limit
);
1676 s
= g_malloc (len
+ 1);
1679 memcpy (s
, buf
, len
);
1688 * Functions to encode protocol data
1692 buffer_init (Buffer
*buf
, int size
)
1694 buf
->buf
= g_malloc (size
);
1696 buf
->end
= buf
->buf
+ size
;
1700 buffer_len (Buffer
*buf
)
1702 return buf
->p
- buf
->buf
;
1706 buffer_make_room (Buffer
*buf
, int size
)
1708 if (buf
->end
- buf
->p
< size
) {
1709 int new_size
= buf
->end
- buf
->buf
+ size
+ 32;
1710 guint8
*p
= g_realloc (buf
->buf
, new_size
);
1711 size
= buf
->p
- buf
->buf
;
1714 buf
->end
= buf
->buf
+ new_size
;
1719 buffer_add_byte (Buffer
*buf
, guint8 val
)
1721 buffer_make_room (buf
, 1);
1727 buffer_add_short (Buffer
*buf
, guint32 val
)
1729 buffer_make_room (buf
, 2);
1730 buf
->p
[0] = (val
>> 8) & 0xff;
1731 buf
->p
[1] = (val
>> 0) & 0xff;
1736 buffer_add_int (Buffer
*buf
, guint32 val
)
1738 buffer_make_room (buf
, 4);
1739 buf
->p
[0] = (val
>> 24) & 0xff;
1740 buf
->p
[1] = (val
>> 16) & 0xff;
1741 buf
->p
[2] = (val
>> 8) & 0xff;
1742 buf
->p
[3] = (val
>> 0) & 0xff;
1747 buffer_add_long (Buffer
*buf
, guint64 l
)
1749 buffer_add_int (buf
, (l
>> 32) & 0xffffffff);
1750 buffer_add_int (buf
, (l
>> 0) & 0xffffffff);
1754 buffer_add_id (Buffer
*buf
, int id
)
1756 buffer_add_int (buf
, (guint64
)id
);
1760 buffer_add_data (Buffer
*buf
, guint8
*data
, int len
)
1762 buffer_make_room (buf
, len
);
1763 memcpy (buf
->p
, data
, len
);
1768 buffer_add_string (Buffer
*buf
, const char *str
)
1773 buffer_add_int (buf
, 0);
1776 buffer_add_int (buf
, len
);
1777 buffer_add_data (buf
, (guint8
*)str
, len
);
1782 buffer_add_buffer (Buffer
*buf
, Buffer
*data
)
1784 buffer_add_data (buf
, data
->buf
, buffer_len (data
));
1788 buffer_free (Buffer
*buf
)
1794 send_packet (int command_set
, int command
, Buffer
*data
)
1800 id
= InterlockedIncrement (&packet_id
);
1802 len
= data
->p
- data
->buf
+ 11;
1803 buffer_init (&buf
, len
);
1804 buffer_add_int (&buf
, len
);
1805 buffer_add_int (&buf
, id
);
1806 buffer_add_byte (&buf
, 0); /* flags */
1807 buffer_add_byte (&buf
, command_set
);
1808 buffer_add_byte (&buf
, command
);
1809 memcpy (buf
.buf
+ 11, data
->buf
, data
->p
- data
->buf
);
1811 res
= transport_send (buf
.buf
, len
);
1819 send_reply_packets (int npackets
, ReplyPacket
*packets
)
1826 for (i
= 0; i
< npackets
; ++i
)
1827 len
+= buffer_len (packets
[i
].data
) + 11;
1828 buffer_init (&buf
, len
);
1829 for (i
= 0; i
< npackets
; ++i
) {
1830 buffer_add_int (&buf
, buffer_len (packets
[i
].data
) + 11);
1831 buffer_add_int (&buf
, packets
[i
].id
);
1832 buffer_add_byte (&buf
, 0x80); /* flags */
1833 buffer_add_byte (&buf
, (packets
[i
].error
>> 8) & 0xff);
1834 buffer_add_byte (&buf
, packets
[i
].error
);
1835 buffer_add_buffer (&buf
, packets
[i
].data
);
1837 res
= transport_send (buf
.buf
, len
);
1845 send_reply_packet (int id
, int error
, Buffer
*data
)
1849 memset (&packet
, 0, sizeof (ReplyPacket
));
1851 packet
.error
= error
;
1854 return send_reply_packets (1, &packet
);
1858 send_buffered_reply_packets (void)
1862 send_reply_packets (nreply_packets
, reply_packets
);
1863 for (i
= 0; i
< nreply_packets
; ++i
)
1864 buffer_free (reply_packets
[i
].data
);
1865 DEBUG (1, fprintf (log_file
, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets
, (long)mono_100ns_ticks () / 10000));
1870 buffer_reply_packet (int id
, int error
, Buffer
*data
)
1874 if (nreply_packets
== 128)
1875 send_buffered_reply_packets ();
1877 p
= &reply_packets
[nreply_packets
];
1880 p
->data
= g_new0 (Buffer
, 1);
1881 buffer_init (p
->data
, buffer_len (data
));
1882 buffer_add_buffer (p
->data
, data
);
1891 * Represents an object accessible by the debugger client.
1894 /* Unique id used in the wire protocol to refer to objects */
1897 * A weakref gc handle pointing to the object. The gc handle is used to
1898 * detect if the object was garbage collected.
1903 /* Maps objid -> ObjRef */
1904 static GHashTable
*objrefs
;
1905 static GHashTable
*obj_to_objref
;
1906 /* Protected by the dbg lock */
1907 static MonoGHashTable
*suspended_objs
;
1910 free_objref (gpointer value
)
1914 mono_gchandle_free (o
->handle
);
1922 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, free_objref
);
1923 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
1924 suspended_objs
= mono_g_hash_table_new_type (NULL
, NULL
, MONO_HASH_KEY_GC
);
1925 MONO_GC_REGISTER_ROOT_FIXED (suspended_objs
);
1929 objrefs_cleanup (void)
1931 g_hash_table_destroy (objrefs
);
1936 * Return an ObjRef for OBJ.
1939 get_objref (MonoObject
*obj
)
1942 GSList
*reflist
= NULL
, *l
;
1948 if (suspend_count
) {
1950 * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
1953 mono_g_hash_table_insert (suspended_objs
, obj
, NULL
);
1957 mono_loader_lock ();
1959 /* FIXME: The tables can grow indefinitely */
1961 if (mono_gc_is_moving ()) {
1963 * Objects can move, so use a hash table mapping hash codes to lists of
1964 * ObjRef structures.
1966 hash
= mono_object_hash (obj
);
1968 reflist
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (hash
));
1969 for (l
= reflist
; l
; l
= l
->next
) {
1971 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1972 mono_loader_unlock ();
1977 /* Use a hash table with masked pointers to internalize object references */
1978 ref
= g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
1979 /* ref might refer to a different object with the same addr which was GCd */
1980 if (ref
&& mono_gchandle_get_target (ref
->handle
) == obj
) {
1981 mono_loader_unlock ();
1986 ref
= g_new0 (ObjRef
, 1);
1987 ref
->id
= InterlockedIncrement (&objref_id
);
1988 ref
->handle
= mono_gchandle_new_weakref (obj
, FALSE
);
1990 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
1992 if (mono_gc_is_moving ()) {
1993 reflist
= g_slist_append (reflist
, ref
);
1994 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (hash
), reflist
);
1996 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
1999 mono_loader_unlock ();
2005 true_pred (gpointer key
, gpointer value
, gpointer user_data
)
2011 clear_suspended_objs (void)
2014 mono_g_hash_table_foreach_remove (suspended_objs
, true_pred
, NULL
);
2019 get_objid (MonoObject
*obj
)
2021 return get_objref (obj
)->id
;
2025 * Set OBJ to the object identified by OBJID.
2026 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
2030 get_object_allow_null (int objid
, MonoObject
**obj
)
2040 return ERR_INVALID_OBJECT
;
2042 mono_loader_lock ();
2044 ref
= g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objid
));
2047 *obj
= mono_gchandle_get_target (ref
->handle
);
2048 mono_loader_unlock ();
2050 return ERR_INVALID_OBJECT
;
2053 mono_loader_unlock ();
2054 return ERR_INVALID_OBJECT
;
2059 get_object (int objid
, MonoObject
**obj
)
2061 int err
= get_object_allow_null (objid
, obj
);
2066 return ERR_INVALID_OBJECT
;
2071 decode_objid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
2073 return decode_id (buf
, endbuf
, limit
);
2077 buffer_add_objid (Buffer
*buf
, MonoObject
*o
)
2079 buffer_add_id (buf
, get_objid (o
));
2098 * Represents a runtime structure accessible to the debugger client
2101 /* Unique id used in the wire protocol */
2103 /* Domain of the runtime structure, NULL if the domain was unloaded */
2110 MonoAssembly
*assembly
;
2111 MonoClassField
*field
;
2113 MonoProperty
*property
;
2118 /* Maps runtime structure -> Id */
2119 GHashTable
*val_to_id
[ID_NUM
];
2120 /* Classes whose class load event has been sent */
2121 GHashTable
*loaded_classes
;
2122 /* Maps MonoClass->GPtrArray of file names */
2123 GHashTable
*source_files
;
2124 /* Maps source file basename -> GSList of classes */
2125 GHashTable
*source_file_to_class
;
2126 /* Same with ignore-case */
2127 GHashTable
*source_file_to_class_ignorecase
;
2131 /* Protected by the dbg lock */
2132 static GPtrArray
*ids
[ID_NUM
];
2139 for (i
= 0; i
< ID_NUM
; ++i
)
2140 ids
[i
] = g_ptr_array_new ();
2148 for (i
= 0; i
< ID_NUM
; ++i
) {
2150 for (j
= 0; j
< ids
[i
]->len
; ++j
)
2151 g_free (g_ptr_array_index (ids
[i
], j
));
2152 g_ptr_array_free (ids
[i
], TRUE
);
2159 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
2161 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
2163 GHashTableIter iter
;
2164 GPtrArray
*file_names
;
2169 for (i
= 0; i
< ID_NUM
; ++i
)
2170 if (info
->val_to_id
[i
])
2171 g_hash_table_destroy (info
->val_to_id
[i
]);
2172 g_hash_table_destroy (info
->loaded_classes
);
2174 g_hash_table_iter_init (&iter
, info
->source_files
);
2175 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&file_names
)) {
2176 for (i
= 0; i
< file_names
->len
; ++i
)
2177 g_free (g_ptr_array_index (file_names
, i
));
2178 g_ptr_array_free (file_names
, TRUE
);
2181 g_hash_table_iter_init (&iter
, info
->source_file_to_class
);
2182 while (g_hash_table_iter_next (&iter
, (void**)&basename
, (void**)&l
)) {
2187 g_hash_table_iter_init (&iter
, info
->source_file_to_class_ignorecase
);
2188 while (g_hash_table_iter_next (&iter
, (void**)&basename
, (void**)&l
)) {
2196 domain_jit_info (domain
)->agent_info
= NULL
;
2198 /* Clear ids referencing structures in the domain */
2200 for (i
= 0; i
< ID_NUM
; ++i
) {
2202 for (j
= 0; j
< ids
[i
]->len
; ++j
) {
2203 Id
*id
= g_ptr_array_index (ids
[i
], j
);
2204 if (id
->domain
== domain
)
2211 mono_loader_lock ();
2212 g_hash_table_remove (domains
, domain
);
2213 mono_loader_unlock ();
2216 static AgentDomainInfo
*
2217 get_agent_domain_info (MonoDomain
*domain
)
2219 AgentDomainInfo
*info
= NULL
;
2221 mono_domain_lock (domain
);
2223 info
= domain_jit_info (domain
)->agent_info
;
2225 info
= domain_jit_info (domain
)->agent_info
= g_new0 (AgentDomainInfo
, 1);
2226 info
->loaded_classes
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2227 info
->source_files
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2228 info
->source_file_to_class
= g_hash_table_new (g_str_hash
, g_str_equal
);
2229 info
->source_file_to_class_ignorecase
= g_hash_table_new (g_str_hash
, g_str_equal
);
2232 mono_domain_unlock (domain
);
2238 get_id (MonoDomain
*domain
, IdType type
, gpointer val
)
2241 AgentDomainInfo
*info
;
2246 mono_loader_lock ();
2248 mono_domain_lock (domain
);
2250 info
= get_agent_domain_info (domain
);
2252 if (info
->val_to_id
[type
] == NULL
)
2253 info
->val_to_id
[type
] = g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2255 id
= g_hash_table_lookup (info
->val_to_id
[type
], val
);
2257 mono_domain_unlock (domain
);
2258 mono_loader_unlock ();
2264 id
= g_new0 (Id
, 1);
2266 id
->id
= ids
[type
]->len
+ 1;
2267 id
->domain
= domain
;
2270 g_hash_table_insert (info
->val_to_id
[type
], val
, id
);
2271 g_ptr_array_add (ids
[type
], id
);
2275 mono_domain_unlock (domain
);
2277 mono_loader_unlock ();
2282 static inline gpointer
2283 decode_ptr_id (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, IdType type
, MonoDomain
**domain
, int *err
)
2287 int id
= decode_id (buf
, endbuf
, limit
);
2296 // FIXME: error handling
2298 g_assert (id
> 0 && id
<= ids
[type
]->len
);
2300 res
= g_ptr_array_index (ids
[type
], GPOINTER_TO_INT (id
- 1));
2303 if (res
->domain
== NULL
) {
2304 DEBUG (0, fprintf (log_file
, "ERR_UNLOADED, id=%d, type=%d.\n", id
, type
));
2305 *err
= ERR_UNLOADED
;
2310 *domain
= res
->domain
;
2312 return res
->data
.val
;
2316 buffer_add_ptr_id (Buffer
*buf
, MonoDomain
*domain
, IdType type
, gpointer val
)
2318 int id
= get_id (domain
, type
, val
);
2320 buffer_add_id (buf
, id
);
2324 static inline MonoClass
*
2325 decode_typeid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2329 klass
= decode_ptr_id (buf
, endbuf
, limit
, ID_TYPE
, domain
, err
);
2330 if (G_UNLIKELY (log_level
>= 2) && klass
) {
2333 s
= mono_type_full_name (&klass
->byval_arg
);
2334 DEBUG(2, fprintf (log_file
, "[dbg] recv class [%s]\n", s
));
2340 static inline MonoAssembly
*
2341 decode_assemblyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2343 return decode_ptr_id (buf
, endbuf
, limit
, ID_ASSEMBLY
, domain
, err
);
2346 static inline MonoImage
*
2347 decode_moduleid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2349 return decode_ptr_id (buf
, endbuf
, limit
, ID_MODULE
, domain
, err
);
2352 static inline MonoMethod
*
2353 decode_methodid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2357 m
= decode_ptr_id (buf
, endbuf
, limit
, ID_METHOD
, domain
, err
);
2358 if (G_UNLIKELY (log_level
>= 2) && m
) {
2361 s
= mono_method_full_name (m
, TRUE
);
2362 DEBUG(2, fprintf (log_file
, "[dbg] recv method [%s]\n", s
));
2368 static inline MonoClassField
*
2369 decode_fieldid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2371 return decode_ptr_id (buf
, endbuf
, limit
, ID_FIELD
, domain
, err
);
2374 static inline MonoDomain
*
2375 decode_domainid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2377 return decode_ptr_id (buf
, endbuf
, limit
, ID_DOMAIN
, domain
, err
);
2380 static inline MonoProperty
*
2381 decode_propertyid (guint8
*buf
, guint8
**endbuf
, guint8
*limit
, MonoDomain
**domain
, int *err
)
2383 return decode_ptr_id (buf
, endbuf
, limit
, ID_PROPERTY
, domain
, err
);
2387 buffer_add_typeid (Buffer
*buf
, MonoDomain
*domain
, MonoClass
*klass
)
2389 buffer_add_ptr_id (buf
, domain
, ID_TYPE
, klass
);
2390 if (G_UNLIKELY (log_level
>= 2) && klass
) {
2393 s
= mono_type_full_name (&klass
->byval_arg
);
2394 if (GetCurrentThreadId () == debugger_thread_id
)
2395 DEBUG(2, fprintf (log_file
, "[dbg] send class [%s]\n", s
));
2397 DEBUG(2, fprintf (log_file
, "[%p] send class [%s]\n", (gpointer
)GetCurrentThreadId (), s
));
2403 buffer_add_methodid (Buffer
*buf
, MonoDomain
*domain
, MonoMethod
*method
)
2405 buffer_add_ptr_id (buf
, domain
, ID_METHOD
, method
);
2406 if (G_UNLIKELY (log_level
>= 2) && method
) {
2409 s
= mono_method_full_name (method
, 1);
2410 DEBUG(2, fprintf (log_file
, "[dbg] send method [%s]\n", s
));
2416 buffer_add_assemblyid (Buffer
*buf
, MonoDomain
*domain
, MonoAssembly
*assembly
)
2420 id
= buffer_add_ptr_id (buf
, domain
, ID_ASSEMBLY
, assembly
);
2421 if (G_UNLIKELY (log_level
>= 2) && assembly
)
2422 DEBUG(2, fprintf (log_file
, "[dbg] send assembly [%s][%s][%d]\n", assembly
->aname
.name
, domain
->friendly_name
, id
));
2426 buffer_add_moduleid (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
)
2428 buffer_add_ptr_id (buf
, domain
, ID_MODULE
, image
);
2432 buffer_add_fieldid (Buffer
*buf
, MonoDomain
*domain
, MonoClassField
*field
)
2434 buffer_add_ptr_id (buf
, domain
, ID_FIELD
, field
);
2438 buffer_add_propertyid (Buffer
*buf
, MonoDomain
*domain
, MonoProperty
*property
)
2440 buffer_add_ptr_id (buf
, domain
, ID_PROPERTY
, property
);
2444 buffer_add_domainid (Buffer
*buf
, MonoDomain
*domain
)
2446 buffer_add_ptr_id (buf
, domain
, ID_DOMAIN
, domain
);
2449 static void invoke_method (void);
2456 * save_thread_context:
2458 * Set CTX as the current threads context which is used for computing stack traces.
2459 * This function is signal-safe.
2462 save_thread_context (MonoContext
*ctx
)
2464 DebuggerTlsData
*tls
;
2466 tls
= mono_native_tls_get_value (debugger_tls_id
);
2470 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
2472 mono_thread_state_init_from_current (&tls
->context
);
2475 /* Number of threads suspended */
2477 * If this is equal to the size of thread_to_tls, the runtime is considered
2480 static gint32 threads_suspend_count
;
2482 static mono_mutex_t suspend_mutex
;
2484 /* Cond variable used to wait for suspend_count becoming 0 */
2485 static mono_cond_t suspend_cond
;
2487 /* Semaphore used to wait for a thread becoming suspended */
2488 static MonoSemType suspend_sem
;
2493 mono_mutex_init (&suspend_mutex
);
2494 mono_cond_init (&suspend_cond
, NULL
);
2495 MONO_SEM_INIT (&suspend_sem
, 0);
2500 StackFrameInfo last_frame
;
2501 gboolean last_frame_set
;
2504 } GetLastFrameUserData
;
2507 get_last_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
2509 GetLastFrameUserData
*data
= user_data
;
2511 if (info
->type
== FRAME_TYPE_MANAGED_TO_NATIVE
)
2514 if (!data
->last_frame_set
) {
2515 /* Store the last frame */
2516 memcpy (&data
->last_frame
, info
, sizeof (StackFrameInfo
));
2517 data
->last_frame_set
= TRUE
;
2520 /* Store the context/lmf for the frame above the last frame */
2521 memcpy (&data
->ctx
, ctx
, sizeof (MonoContext
));
2522 data
->lmf
= info
->lmf
;
2530 * Process interruption of a thread. If SIGCTX is set, process the current thread. If
2531 * INFO is set, process the thread described by INFO.
2532 * This should be signal safe.
2535 thread_interrupt (DebuggerTlsData
*tls
, MonoThreadInfo
*info
, void *sigctx
, MonoJitInfo
*ji
)
2539 MonoNativeThreadId tid
;
2542 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2543 * guarantee the signal handler will be called that many times. Instead of tracking
2544 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2545 * has been requested that hasn't been handled yet, otherwise we can have threads
2546 * refuse to die when VM_EXIT is called
2548 #if defined(__APPLE__)
2549 if (InterlockedCompareExchange (&tls
->interrupt_count
, 0, 1) == 0)
2553 * We use interrupt_count to determine whenever this interrupt should be processed
2554 * by us or the normal interrupt processing code in the signal handler.
2555 * There is no race here with notify_thread (), since the signal is sent after
2556 * incrementing interrupt_count.
2558 if (tls
->interrupt_count
== 0)
2561 InterlockedDecrement (&tls
->interrupt_count
);
2565 ip
= mono_arch_ip_from_context (sigctx
);
2567 ip
= MONO_CONTEXT_GET_IP (&info
->suspend_state
.ctx
);
2572 tid
= mono_thread_info_get_tid (info
);
2574 tid
= (MonoNativeThreadId
)GetCurrentThreadId ();
2576 // FIXME: Races when the thread leaves managed code before hitting a single step
2580 /* Running managed code, will be suspended by the single step code */
2581 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer
)(gsize
)tid
, jinfo_get_method (ji
)->name
, ip
));
2585 * Running native code, will be suspended when it returns to/enters
2586 * managed code. Treat it as already suspended.
2587 * This might interrupt the code in process_single_step_inner (), we use the
2588 * tls->suspending flag to avoid races when that happens.
2590 if (!tls
->suspended
&& !tls
->suspending
) {
2592 GetLastFrameUserData data
;
2594 // FIXME: printf is not signal safe, but this is only used during
2595 // debugger debugging
2597 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer
)(gsize
)tid
, ip
));
2598 //save_thread_context (&ctx);
2601 /* Already terminated */
2605 * We are in a difficult position: we want to be able to provide stack
2606 * traces for this thread, but we can't use the current ctx+lmf, since
2607 * the thread is still running, so it might return to managed code,
2608 * making these invalid.
2609 * So we start a stack walk and save the first frame, along with the
2610 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
2611 * suspended when it returns to managed code, so the parent's ctx should
2614 data
.last_frame_set
= FALSE
;
2616 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
2618 * Don't pass MONO_UNWIND_ACTUAL_METHOD, its not signal safe, and
2619 * get_last_frame () doesn't need it, the last frame cannot be a ginst
2620 * since we are not in a JITted method.
2622 mono_walk_stack_with_ctx (get_last_frame
, &ctx
, MONO_UNWIND_NONE
, &data
);
2624 mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame
, &info
->suspend_state
, MONO_UNWIND_SIGNAL_SAFE
, &data
);
2626 if (data
.last_frame_set
) {
2627 memcpy (&tls
->async_last_frame
, &data
.last_frame
, sizeof (StackFrameInfo
));
2628 res
= mono_thread_state_init_from_monoctx (&tls
->async_state
, &ctx
);
2630 mono_thread_state_init_from_monoctx (&tls
->context
, &ctx
);
2633 memcpy (&tls
->async_state
.ctx
, &data
.ctx
, sizeof (MonoContext
));
2634 tls
->async_state
.unwind_data
[MONO_UNWIND_DATA_LMF
] = data
.lmf
;
2635 tls
->async_state
.unwind_data
[MONO_UNWIND_DATA_JIT_TLS
] = tls
->thread
->jit_data
;
2637 tls
->async_state
.valid
= FALSE
;
2640 mono_memory_barrier ();
2642 tls
->suspended
= TRUE
;
2643 MONO_SEM_POST (&suspend_sem
);
2650 * mono_debugger_agent_thread_interrupt:
2652 * Called by the abort signal handler.
2653 * Should be signal safe.
2656 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
2658 DebuggerTlsData
*tls
;
2663 tls
= mono_native_tls_get_value (debugger_tls_id
);
2665 DEBUG (1, fprintf (log_file
, "[%p] Received interrupt with no TLS, continuing.\n", (gpointer
)GetCurrentThreadId ()));
2669 return thread_interrupt (tls
, NULL
, sigctx
, ji
);
2673 static void CALLBACK
notify_thread_apc (ULONG_PTR param
)
2676 mono_debugger_agent_thread_interrupt (NULL
, NULL
);
2678 #endif /* HOST_WIN32 */
2681 * reset_native_thread_suspend_state:
2683 * Reset the suspended flag and state on native threads
2686 reset_native_thread_suspend_state (gpointer key
, gpointer value
, gpointer user_data
)
2688 DebuggerTlsData
*tls
= value
;
2690 if (!tls
->really_suspended
&& tls
->suspended
) {
2691 tls
->suspended
= FALSE
;
2693 * The thread might still be running if it was executing native code, so the state won't be invalided by
2694 * suspend_current ().
2696 tls
->context
.valid
= FALSE
;
2697 tls
->async_state
.valid
= FALSE
;
2698 invalidate_frames (tls
);
2705 * Notify a thread that it needs to suspend.
2708 notify_thread (gpointer key
, gpointer value
, gpointer user_data
)
2710 MonoInternalThread
*thread
= key
;
2711 DebuggerTlsData
*tls
= value
;
2712 gsize tid
= thread
->tid
;
2717 if (GetCurrentThreadId () == tid
|| tls
->terminated
)
2720 DEBUG(1, fprintf (log_file
, "[%p] Interrupting %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2723 * OSX can (and will) coalesce signals, so sending multiple pthread_kills does not
2724 * guarantee the signal handler will be called that many times. Instead of tracking
2725 * interrupt_count on osx, we use this as a boolean flag to determine if a interrupt
2726 * has been requested that hasn't been handled yet, otherwise we can have threads
2727 * refuse to die when VM_EXIT is called
2729 #if defined(__APPLE__)
2730 if (InterlockedCompareExchange (&tls
->interrupt_count
, 1, 0) == 1)
2734 * Maybe we could use the normal interrupt infrastructure, but that does a lot
2735 * of things like breaking waits etc. which we don't want.
2737 InterlockedIncrement (&tls
->interrupt_count
);
2740 /* This is _not_ equivalent to ves_icall_System_Threading_Thread_Abort () */
2742 QueueUserAPC (notify_thread_apc
, thread
->handle
, (ULONG_PTR
)NULL
);
2744 if (mono_thread_info_new_interrupt_enabled ()) {
2745 MonoThreadInfo
*info
;
2748 info
= mono_thread_info_safe_suspend_sync ((MonoNativeThreadId
)(gpointer
)(gsize
)thread
->tid
, FALSE
);
2750 DEBUG(1, fprintf (log_file
, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
));
2752 * Attached thread which died without detaching.
2754 tls
->terminated
= TRUE
;
2756 ji
= mono_jit_info_table_find (info
->suspend_state
.unwind_data
[MONO_UNWIND_DATA_DOMAIN
], MONO_CONTEXT_GET_IP (&info
->suspend_state
.ctx
));
2758 thread_interrupt (tls
, info
, NULL
, ji
);
2760 mono_thread_info_finish_suspend_and_resume (info
);
2763 res
= mono_thread_kill (thread
, mono_thread_get_abort_signal ());
2765 DEBUG(1, fprintf (log_file
, "[%p] mono_thread_kill () failed for %p: %d...\n", (gpointer
)GetCurrentThreadId (), (gpointer
)tid
, res
));
2767 * Attached thread which died without detaching.
2769 tls
->terminated
= TRUE
;
2776 process_suspend (DebuggerTlsData
*tls
, MonoContext
*ctx
)
2778 guint8
*ip
= MONO_CONTEXT_GET_IP (ctx
);
2782 if (mono_loader_lock_is_owned_by_self ()) {
2784 * Shortcut for the check in suspend_current (). This speeds up processing
2785 * when executing long running code inside the loader lock, i.e. assembly load
2791 if (debugger_thread_id
== GetCurrentThreadId ())
2794 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2795 if (suspend_count
- tls
->resume_count
> 0)
2796 tls
->suspending
= TRUE
;
2798 DEBUG(1, fprintf (log_file
, "[%p] Received single step event for suspending.\n", (gpointer
)GetCurrentThreadId ()));
2800 if (suspend_count
- tls
->resume_count
== 0) {
2802 * We are executing a single threaded invoke but the single step for
2803 * suspending is still active.
2804 * FIXME: This slows down single threaded invokes.
2806 DEBUG(1, fprintf (log_file
, "[%p] Ignored during single threaded invoke.\n", (gpointer
)GetCurrentThreadId ()));
2810 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
2812 /* Can't suspend in these methods */
2813 method
= jinfo_get_method (ji
);
2814 if (method
->klass
== mono_defaults
.string_class
&& (!strcmp (method
->name
, "memset") || strstr (method
->name
, "memcpy")))
2817 save_thread_context (ctx
);
2825 * Increase the suspend count of the VM. While the suspend count is greater
2826 * than 0, runtime threads are suspended at certain points during execution.
2831 mono_loader_lock ();
2833 mono_mutex_lock (&suspend_mutex
);
2837 DEBUG(1, fprintf (log_file
, "[%p] Suspending vm...\n", (gpointer
)GetCurrentThreadId ()));
2839 if (suspend_count
== 1) {
2840 // FIXME: Is it safe to call this inside the lock ?
2841 start_single_stepping ();
2842 mono_g_hash_table_foreach (thread_to_tls
, notify_thread
, NULL
);
2845 mono_mutex_unlock (&suspend_mutex
);
2847 if (suspend_count
== 1)
2849 * Suspend creation of new threadpool threads, since they cannot run
2851 mono_thread_pool_suspend ();
2853 mono_loader_unlock ();
2859 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2867 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2869 mono_loader_lock ();
2871 mono_mutex_lock (&suspend_mutex
);
2873 g_assert (suspend_count
> 0);
2876 DEBUG(1, fprintf (log_file
, "[%p] Resuming vm, suspend count=%d...\n", (gpointer
)GetCurrentThreadId (), suspend_count
));
2878 if (suspend_count
== 0) {
2879 // FIXME: Is it safe to call this inside the lock ?
2880 stop_single_stepping ();
2881 mono_g_hash_table_foreach (thread_to_tls
, reset_native_thread_suspend_state
, NULL
);
2884 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2885 err
= mono_cond_broadcast (&suspend_cond
);
2886 g_assert (err
== 0);
2888 mono_mutex_unlock (&suspend_mutex
);
2889 //g_assert (err == 0);
2891 if (suspend_count
== 0)
2892 mono_thread_pool_resume ();
2894 mono_loader_unlock ();
2900 * Resume just one thread.
2903 resume_thread (MonoInternalThread
*thread
)
2906 DebuggerTlsData
*tls
;
2908 g_assert (debugger_thread_id
== GetCurrentThreadId ());
2910 mono_loader_lock ();
2912 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
2915 mono_mutex_lock (&suspend_mutex
);
2917 g_assert (suspend_count
> 0);
2919 DEBUG(1, fprintf (log_file
, "[sdb] Resuming thread %p...\n", (gpointer
)(gssize
)thread
->tid
));
2921 tls
->resume_count
+= suspend_count
;
2924 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2925 * but only the one whose resume_count field is > 0 will be resumed.
2927 err
= mono_cond_broadcast (&suspend_cond
);
2928 g_assert (err
== 0);
2930 mono_mutex_unlock (&suspend_mutex
);
2931 //g_assert (err == 0);
2933 mono_loader_unlock ();
2937 invalidate_frames (DebuggerTlsData
*tls
)
2942 tls
= mono_native_tls_get_value (debugger_tls_id
);
2945 for (i
= 0; i
< tls
->frame_count
; ++i
) {
2946 if (tls
->frames
[i
]->jit
)
2947 mono_debug_free_method_jit_info (tls
->frames
[i
]->jit
);
2948 g_free (tls
->frames
[i
]);
2950 g_free (tls
->frames
);
2951 tls
->frame_count
= 0;
2958 * Suspend the current thread until the runtime is resumed. If the thread has a
2959 * pending invoke, then the invoke is executed before this function returns.
2962 suspend_current (void)
2967 DebuggerTlsData
*tls
;
2969 g_assert (debugger_thread_id
!= GetCurrentThreadId ());
2971 if (mono_loader_lock_is_owned_by_self ()) {
2973 * If we own the loader mutex, can't suspend until we release it, since the
2974 * whole runtime can deadlock otherwise.
2979 tls
= mono_native_tls_get_value (debugger_tls_id
);
2982 mono_mutex_lock (&suspend_mutex
);
2984 tls
->suspending
= FALSE
;
2985 tls
->really_suspended
= TRUE
;
2987 if (!tls
->suspended
) {
2988 tls
->suspended
= TRUE
;
2989 MONO_SEM_POST (&suspend_sem
);
2992 DEBUG(1, fprintf (log_file
, "[%p] Suspended.\n", (gpointer
)GetCurrentThreadId ()));
2994 while (suspend_count
- tls
->resume_count
> 0) {
2996 if (WAIT_TIMEOUT
== WaitForSingleObject(suspend_cond
, 0))
2998 mono_mutex_unlock (&suspend_mutex
);
3000 mono_mutex_lock (&suspend_mutex
);
3006 err
= mono_cond_wait (&suspend_cond
, &suspend_mutex
);
3007 g_assert (err
== 0);
3011 tls
->suspended
= FALSE
;
3012 tls
->really_suspended
= FALSE
;
3014 threads_suspend_count
--;
3016 mono_mutex_unlock (&suspend_mutex
);
3018 DEBUG(1, fprintf (log_file
, "[%p] Resumed.\n", (gpointer
)GetCurrentThreadId ()));
3020 if (tls
->pending_invoke
) {
3021 /* Save the original context */
3022 tls
->pending_invoke
->has_ctx
= TRUE
;
3023 tls
->pending_invoke
->ctx
= tls
->context
.ctx
;
3028 /* The frame info becomes invalid after a resume */
3029 tls
->context
.valid
= FALSE
;
3030 tls
->async_state
.valid
= FALSE
;
3031 invalidate_frames (tls
);
3035 count_thread (gpointer key
, gpointer value
, gpointer user_data
)
3037 DebuggerTlsData
*tls
= value
;
3039 if (!tls
->suspended
&& !tls
->terminated
)
3040 *(int*)user_data
= *(int*)user_data
+ 1;
3044 count_threads_to_wait_for (void)
3048 mono_loader_lock ();
3049 mono_g_hash_table_foreach (thread_to_tls
, count_thread
, &count
);
3050 mono_loader_unlock ();
3058 * Wait until the runtime is completely suspended.
3061 wait_for_suspend (void)
3063 int nthreads
, nwait
, err
;
3064 gboolean waited
= FALSE
;
3066 // FIXME: Threads starting/stopping ?
3067 mono_loader_lock ();
3068 nthreads
= mono_g_hash_table_size (thread_to_tls
);
3069 mono_loader_unlock ();
3072 nwait
= count_threads_to_wait_for ();
3074 DEBUG(1, fprintf (log_file
, "Waiting for %d(%d) threads to suspend...\n", nwait
, nthreads
));
3075 err
= MONO_SEM_WAIT (&suspend_sem
);
3076 g_assert (err
== 0);
3084 DEBUG(1, fprintf (log_file
, "%d threads suspended.\n", nthreads
));
3090 * Return whenever the runtime is suspended.
3095 return count_threads_to_wait_for () == 0;
3098 static MonoSeqPointInfo
*
3099 get_seq_points (MonoDomain
*domain
, MonoMethod
*method
)
3101 MonoSeqPointInfo
*seq_points
;
3103 mono_domain_lock (domain
);
3104 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, method
);
3105 if (!seq_points
&& method
->is_inflated
) {
3106 /* generic sharing + aot */
3107 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mono_method_get_declaring_generic_method (method
));
3109 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mini_get_shared_method (method
));
3111 mono_domain_unlock (domain
);
3117 no_seq_points_found (MonoMethod
*method
)
3120 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
3122 printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method
, TRUE
));
3126 * find_next_seq_point_for_native_offset:
3128 * Find the first sequence point after NATIVE_OFFSET.
3131 find_next_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
3133 MonoSeqPointInfo
*seq_points
;
3136 seq_points
= get_seq_points (domain
, method
);
3142 g_assert (seq_points
);
3146 for (i
= 0; i
< seq_points
->len
; ++i
) {
3147 if (seq_points
->seq_points
[i
].native_offset
>= native_offset
)
3148 return &seq_points
->seq_points
[i
];
3155 * find_prev_seq_point_for_native_offset:
3157 * Find the first sequence point before NATIVE_OFFSET.
3160 find_prev_seq_point_for_native_offset (MonoDomain
*domain
, MonoMethod
*method
, gint32 native_offset
, MonoSeqPointInfo
**info
)
3162 MonoSeqPointInfo
*seq_points
;
3165 seq_points
= get_seq_points (domain
, method
);
3171 for (i
= seq_points
->len
- 1; i
>= 0; --i
) {
3172 if (seq_points
->seq_points
[i
].native_offset
<= native_offset
)
3173 return &seq_points
->seq_points
[i
];
3182 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
3183 * should be the location of a sequence point.
3185 static G_GNUC_UNUSED SeqPoint
*
3186 find_seq_point (MonoDomain
*domain
, MonoMethod
*method
, gint32 il_offset
, MonoSeqPointInfo
**info
)
3188 MonoSeqPointInfo
*seq_points
;
3193 seq_points
= get_seq_points (domain
, method
);
3198 for (i
= 0; i
< seq_points
->len
; ++i
) {
3199 if (seq_points
->seq_points
[i
].il_offset
== il_offset
)
3200 return &seq_points
->seq_points
[i
];
3207 DebuggerTlsData
*tls
;
3209 } ComputeFramesUserData
;
3212 process_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
3214 ComputeFramesUserData
*ud
= user_data
;
3216 MonoMethod
*method
, *actual_method
, *api_method
;
3220 if (info
->type
!= FRAME_TYPE_MANAGED
) {
3221 if (info
->type
== FRAME_TYPE_DEBUGGER_INVOKE
) {
3222 /* Mark the last frame as an invoke frame */
3224 ((StackFrame
*)g_slist_last (ud
->frames
)->data
)->flags
|= FRAME_FLAG_DEBUGGER_INVOKE
;
3230 method
= jinfo_get_method (info
->ji
);
3232 method
= info
->method
;
3233 actual_method
= info
->actual_method
;
3234 api_method
= method
;
3239 if (!method
|| (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
&& method
->wrapper_type
!= MONO_WRAPPER_MANAGED_TO_NATIVE
))
3242 if (info
->il_offset
== -1) {
3243 /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
3244 if (ud
->frames
== NULL
) {
3245 sp
= find_prev_seq_point_for_native_offset (info
->domain
, method
, info
->native_offset
, NULL
);
3247 info
->il_offset
= sp
->il_offset
;
3249 if (info
->il_offset
== -1)
3250 info
->il_offset
= mono_debug_il_offset_from_address (method
, info
->domain
, info
->native_offset
);
3253 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
));
3255 if (method
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_NATIVE
) {
3256 if (!CHECK_PROTOCOL_VERSION (2, 17))
3257 /* Older clients can't handle this flag */
3259 api_method
= mono_marshal_method_from_wrapper (method
);
3262 actual_method
= api_method
;
3263 flags
|= FRAME_FLAG_NATIVE_TRANSITION
;
3266 frame
= g_new0 (StackFrame
, 1);
3267 frame
->method
= method
;
3268 frame
->actual_method
= actual_method
;
3269 frame
->api_method
= api_method
;
3270 frame
->il_offset
= info
->il_offset
;
3271 frame
->native_offset
= info
->native_offset
;
3272 frame
->flags
= flags
;
3273 frame
->ji
= info
->ji
;
3274 if (info
->reg_locations
)
3275 memcpy (frame
->reg_locations
, info
->reg_locations
, MONO_MAX_IREGS
* sizeof (mgreg_t
*));
3278 frame
->has_ctx
= TRUE
;
3280 frame
->domain
= info
->domain
;
3282 ud
->frames
= g_slist_append (ud
->frames
, frame
);
3288 process_filter_frame (StackFrameInfo
*info
, MonoContext
*ctx
, gpointer user_data
)
3290 ComputeFramesUserData
*ud
= user_data
;
3293 * 'tls->filter_ctx' is the location of the throw site.
3295 * mono_walk_stack() will never actually hit the throw site, but unwind
3296 * directly from the filter to the call site; we abort stack unwinding here
3297 * once this happens and resume from the throw site.
3300 if (MONO_CONTEXT_GET_SP (ctx
) >= MONO_CONTEXT_GET_SP (&ud
->tls
->filter_state
.ctx
))
3303 return process_frame (info
, ctx
, user_data
);
3307 compute_frame_info (MonoInternalThread
*thread
, DebuggerTlsData
*tls
)
3309 ComputeFramesUserData user_data
;
3311 int i
, findex
, new_frame_count
;
3312 StackFrame
**new_frames
, *f
;
3313 MonoUnwindOptions opts
= MONO_UNWIND_DEFAULT
|MONO_UNWIND_REG_LOCATIONS
;
3315 // FIXME: Locking on tls
3316 if (tls
->frames
&& tls
->frames_up_to_date
)
3319 DEBUG(1, fprintf (log_file
, "Frames for %p(tid=%lx):\n", thread
, (glong
)thread
->tid
));
3321 user_data
.tls
= tls
;
3322 user_data
.frames
= NULL
;
3323 if (tls
->terminated
) {
3324 tls
->frame_count
= 0;
3326 } if (!tls
->really_suspended
&& tls
->async_state
.valid
) {
3327 /* Have to use the state saved by the signal handler */
3328 process_frame (&tls
->async_last_frame
, NULL
, &user_data
);
3329 mono_walk_stack_with_state (process_frame
, &tls
->async_state
, opts
, &user_data
);
3330 } else if (tls
->filter_state
.valid
) {
3332 * We are inside an exception filter.
3334 * First we add all the frames from inside the filter; 'tls->ctx' has the current context.
3336 if (tls
->context
.valid
)
3337 mono_walk_stack_with_state (process_filter_frame
, &tls
->context
, opts
, &user_data
);
3339 * After that, we resume unwinding from the location where the exception has been thrown.
3341 mono_walk_stack_with_state (process_frame
, &tls
->filter_state
, opts
, &user_data
);
3342 } else if (tls
->context
.valid
) {
3343 mono_walk_stack_with_state (process_frame
, &tls
->context
, opts
, &user_data
);
3346 tls
->frame_count
= 0;
3350 new_frame_count
= g_slist_length (user_data
.frames
);
3351 new_frames
= g_new0 (StackFrame
*, new_frame_count
);
3353 for (tmp
= user_data
.frames
; tmp
; tmp
= tmp
->next
) {
3357 * Reuse the id for already existing stack frames, so invokes don't invalidate
3358 * the still valid stack frames.
3360 for (i
= 0; i
< tls
->frame_count
; ++i
) {
3361 if (MONO_CONTEXT_GET_SP (&tls
->frames
[i
]->ctx
) == MONO_CONTEXT_GET_SP (&f
->ctx
)) {
3362 f
->id
= tls
->frames
[i
]->id
;
3367 if (i
>= tls
->frame_count
)
3368 f
->id
= InterlockedIncrement (&frame_id
);
3370 new_frames
[findex
++] = f
;
3373 g_slist_free (user_data
.frames
);
3375 invalidate_frames (tls
);
3377 tls
->frames
= new_frames
;
3378 tls
->frame_count
= new_frame_count
;
3379 tls
->frames_up_to_date
= TRUE
;
3383 * GHFunc to emit an appdomain creation event
3384 * @param key Don't care
3385 * @param value A loaded appdomain
3386 * @param user_data Don't care
3389 emit_appdomain_load (gpointer key
, gpointer value
, gpointer user_data
)
3391 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, value
);
3392 g_hash_table_foreach (get_agent_domain_info (value
)->loaded_classes
, emit_type_load
, NULL
);
3396 * GHFunc to emit a thread start event
3397 * @param key A thread id
3398 * @param value A thread object
3399 * @param user_data Don't care
3402 emit_thread_start (gpointer key
, gpointer value
, gpointer user_data
)
3404 if (GPOINTER_TO_INT (key
) != debugger_thread_id
)
3405 process_profiler_event (EVENT_KIND_THREAD_START
, value
);
3409 * GFunc to emit an assembly load event
3410 * @param value A loaded assembly
3411 * @param user_data Don't care
3414 emit_assembly_load (gpointer value
, gpointer user_data
)
3416 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, value
);
3420 * GFunc to emit a type load event
3421 * @param value A loaded type
3422 * @param user_data Don't care
3425 emit_type_load (gpointer key
, gpointer value
, gpointer user_data
)
3427 process_profiler_event (EVENT_KIND_TYPE_LOAD
, value
);
3431 strdup_tolower (char *s
)
3436 for (p
= s2
; *p
; ++p
)
3446 * create_event_list:
3448 * Return a list of event request ids matching EVENT, starting from REQS, which
3449 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
3451 * We return request ids, instead of requests, to simplify threading, since
3452 * requests could be deleted anytime when the loader lock is not held.
3453 * LOCKING: Assumes the loader lock is held.
3456 create_event_list (EventKind event
, GPtrArray
*reqs
, MonoJitInfo
*ji
, EventInfo
*ei
, int *suspend_policy
)
3459 GSList
*events
= NULL
;
3461 *suspend_policy
= SUSPEND_POLICY_NONE
;
3464 reqs
= event_requests
;
3469 for (i
= 0; i
< reqs
->len
; ++i
) {
3470 EventRequest
*req
= g_ptr_array_index (reqs
, i
);
3471 if (req
->event_kind
== event
) {
3472 gboolean filtered
= FALSE
;
3475 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
3476 Modifier
*mod
= &req
->modifiers
[j
];
3478 if (mod
->kind
== MOD_KIND_COUNT
) {
3480 if (mod
->data
.count
> 0) {
3481 if (mod
->data
.count
> 0) {
3483 if (mod
->data
.count
== 0)
3487 } else if (mod
->kind
== MOD_KIND_THREAD_ONLY
) {
3488 if (mod
->data
.thread
!= mono_thread_internal_current ())
3490 } else if (mod
->kind
== MOD_KIND_EXCEPTION_ONLY
&& ei
) {
3491 if (mod
->data
.exc_class
&& mod
->subclasses
&& !mono_class_is_assignable_from (mod
->data
.exc_class
, ei
->exc
->vtable
->klass
))
3493 if (mod
->data
.exc_class
&& !mod
->subclasses
&& mod
->data
.exc_class
!= ei
->exc
->vtable
->klass
)
3495 if (ei
->caught
&& !mod
->caught
)
3497 if (!ei
->caught
&& !mod
->uncaught
)
3499 } else if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& ji
) {
3501 gboolean found
= FALSE
;
3502 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
3505 for (k
= 0; assemblies
[k
]; ++k
)
3506 if (assemblies
[k
] == jinfo_get_method (ji
)->klass
->image
->assembly
)
3511 } else if (mod
->kind
== MOD_KIND_SOURCE_FILE_ONLY
&& ei
&& ei
->klass
) {
3512 gpointer iter
= NULL
;
3514 MonoDebugSourceInfo
*sinfo
;
3515 char *source_file
, *s
;
3516 gboolean found
= FALSE
;
3518 GPtrArray
*source_file_list
;
3520 while ((method
= mono_class_get_methods (ei
->klass
, &iter
))) {
3521 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
3524 mono_debug_symfile_get_line_numbers_full (minfo
, &source_file
, &source_file_list
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3525 for (i
= 0; i
< source_file_list
->len
; ++i
) {
3526 sinfo
= g_ptr_array_index (source_file_list
, i
);
3528 * Do a case-insesitive match by converting the file name to
3531 s
= strdup_tolower (sinfo
->source_file
);
3532 if (g_hash_table_lookup (mod
->data
.source_files
, s
))
3535 char *s2
= g_path_get_basename (sinfo
->source_file
);
3536 char *s3
= strdup_tolower (s2
);
3538 if (g_hash_table_lookup (mod
->data
.source_files
, s3
))
3545 g_ptr_array_free (source_file_list
, TRUE
);
3550 } else if (mod
->kind
== MOD_KIND_TYPE_NAME_ONLY
&& ei
&& ei
->klass
) {
3553 s
= mono_type_full_name (&ei
->klass
->byval_arg
);
3554 if (!g_hash_table_lookup (mod
->data
.type_names
, s
))
3557 } else if (mod
->kind
== MOD_KIND_STEP
) {
3558 if ((mod
->data
.filter
& STEP_FILTER_STATIC_CTOR
) && ji
&&
3559 (jinfo_get_method (ji
)->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
3560 !strcmp (jinfo_get_method (ji
)->name
, ".cctor"))
3562 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_HIDDEN
) && ji
) {
3563 MonoCustomAttrInfo
*ainfo
;
3564 static MonoClass
*klass
;
3567 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerHiddenAttribute");
3570 if (!ji
->dbg_hidden_inited
) {
3571 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3573 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3574 ji
->dbg_hidden
= TRUE
;
3575 mono_custom_attrs_free (ainfo
);
3577 ji
->dbg_hidden_inited
= TRUE
;
3582 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_STEP_THROUGH
) && ji
) {
3583 MonoCustomAttrInfo
*ainfo
;
3584 static MonoClass
*klass
;
3587 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerStepThroughAttribute");
3590 if (!ji
->dbg_step_through_inited
) {
3591 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3593 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3594 ji
->dbg_step_through
= TRUE
;
3595 mono_custom_attrs_free (ainfo
);
3597 ainfo
= mono_custom_attrs_from_class (jinfo_get_method (ji
)->klass
);
3599 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3600 ji
->dbg_step_through
= TRUE
;
3601 mono_custom_attrs_free (ainfo
);
3603 ji
->dbg_step_through_inited
= TRUE
;
3605 if (ji
->dbg_step_through
)
3608 if ((mod
->data
.filter
& STEP_FILTER_DEBUGGER_NON_USER_CODE
) && ji
) {
3609 MonoCustomAttrInfo
*ainfo
;
3610 static MonoClass
*klass
;
3613 klass
= mono_class_from_name (mono_defaults
.corlib
, "System.Diagnostics", "DebuggerNonUserCodeAttribute");
3616 if (!ji
->dbg_non_user_code_inited
) {
3617 ainfo
= mono_custom_attrs_from_method (jinfo_get_method (ji
));
3619 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3620 ji
->dbg_non_user_code
= TRUE
;
3621 mono_custom_attrs_free (ainfo
);
3623 ainfo
= mono_custom_attrs_from_class (jinfo_get_method (ji
)->klass
);
3625 if (mono_custom_attrs_has_attr (ainfo
, klass
))
3626 ji
->dbg_non_user_code
= TRUE
;
3627 mono_custom_attrs_free (ainfo
);
3629 ji
->dbg_non_user_code_inited
= TRUE
;
3631 if (ji
->dbg_non_user_code
)
3638 *suspend_policy
= MAX (*suspend_policy
, req
->suspend_policy
);
3639 events
= g_slist_append (events
, GINT_TO_POINTER (req
->id
));
3644 /* Send a VM START/DEATH event by default */
3645 if (event
== EVENT_KIND_VM_START
)
3646 events
= g_slist_append (events
, GINT_TO_POINTER (0));
3647 if (event
== EVENT_KIND_VM_DEATH
)
3648 events
= g_slist_append (events
, GINT_TO_POINTER (0));
3653 static G_GNUC_UNUSED
const char*
3654 event_to_string (EventKind event
)
3657 case EVENT_KIND_VM_START
: return "VM_START";
3658 case EVENT_KIND_VM_DEATH
: return "VM_DEATH";
3659 case EVENT_KIND_THREAD_START
: return "THREAD_START";
3660 case EVENT_KIND_THREAD_DEATH
: return "THREAD_DEATH";
3661 case EVENT_KIND_APPDOMAIN_CREATE
: return "APPDOMAIN_CREATE";
3662 case EVENT_KIND_APPDOMAIN_UNLOAD
: return "APPDOMAIN_UNLOAD";
3663 case EVENT_KIND_METHOD_ENTRY
: return "METHOD_ENTRY";
3664 case EVENT_KIND_METHOD_EXIT
: return "METHOD_EXIT";
3665 case EVENT_KIND_ASSEMBLY_LOAD
: return "ASSEMBLY_LOAD";
3666 case EVENT_KIND_ASSEMBLY_UNLOAD
: return "ASSEMBLY_UNLOAD";
3667 case EVENT_KIND_BREAKPOINT
: return "BREAKPOINT";
3668 case EVENT_KIND_STEP
: return "STEP";
3669 case EVENT_KIND_TYPE_LOAD
: return "TYPE_LOAD";
3670 case EVENT_KIND_EXCEPTION
: return "EXCEPTION";
3671 case EVENT_KIND_KEEPALIVE
: return "KEEPALIVE";
3672 case EVENT_KIND_USER_BREAK
: return "USER_BREAK";
3673 case EVENT_KIND_USER_LOG
: return "USER_LOG";
3675 g_assert_not_reached ();
3683 * Send an event to the client, suspending the vm if needed.
3684 * LOCKING: Since this can suspend the calling thread, no locks should be held
3686 * The EVENTS list is freed by this function.
3689 process_event (EventKind event
, gpointer arg
, gint32 il_offset
, MonoContext
*ctx
, GSList
*events
, int suspend_policy
)
3693 MonoDomain
*domain
= mono_domain_get ();
3694 MonoThread
*thread
= NULL
;
3695 MonoObject
*keepalive_obj
= NULL
;
3696 gboolean send_success
= FALSE
;
3701 DEBUG (2, fprintf (log_file
, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event
)));
3705 if (!vm_start_event_sent
&& event
!= EVENT_KIND_VM_START
) {
3706 // FIXME: We miss those events
3707 DEBUG (2, fprintf (log_file
, "VM start event not sent yet: dropping %s\n", event_to_string (event
)));
3711 if (vm_death_event_sent
) {
3712 DEBUG (2, fprintf (log_file
, "VM death event has been sent: dropping %s\n", event_to_string (event
)));
3716 if (mono_runtime_is_shutting_down () && event
!= EVENT_KIND_VM_DEATH
) {
3717 DEBUG (2, fprintf (log_file
, "Mono runtime is shutting down: dropping %s\n", event_to_string (event
)));
3722 DEBUG (2, fprintf (log_file
, "Debugger client is not connected: dropping %s\n", event_to_string (event
)));
3726 if (event
== EVENT_KIND_KEEPALIVE
)
3727 suspend_policy
= SUSPEND_POLICY_NONE
;
3732 if (agent_config
.defer
) {
3733 /* Make sure the thread id is always set when doing deferred debugging */
3734 if (debugger_thread_id
== GetCurrentThreadId ()) {
3735 /* Don't suspend on events from the debugger thread */
3736 suspend_policy
= SUSPEND_POLICY_NONE
;
3737 thread
= mono_thread_get_main ();
3739 else thread
= mono_thread_current ();
3741 if (debugger_thread_id
== GetCurrentThreadId () && event
!= EVENT_KIND_VM_DEATH
)
3742 // FIXME: Send these with a NULL thread, don't suspend the current thread
3747 nevents
= g_slist_length (events
);
3748 buffer_init (&buf
, 128);
3749 buffer_add_byte (&buf
, suspend_policy
);
3750 buffer_add_int (&buf
, nevents
);
3752 for (l
= events
; l
; l
= l
->next
) {
3753 buffer_add_byte (&buf
, event
); // event kind
3754 buffer_add_int (&buf
, GPOINTER_TO_INT (l
->data
)); // request id
3759 thread
= mono_thread_current ();
3761 if (event
== EVENT_KIND_VM_START
&& arg
!= NULL
)
3764 buffer_add_objid (&buf
, (MonoObject
*)thread
); // thread
3767 case EVENT_KIND_THREAD_START
:
3768 case EVENT_KIND_THREAD_DEATH
:
3770 case EVENT_KIND_APPDOMAIN_CREATE
:
3771 case EVENT_KIND_APPDOMAIN_UNLOAD
:
3772 buffer_add_domainid (&buf
, arg
);
3774 case EVENT_KIND_METHOD_ENTRY
:
3775 case EVENT_KIND_METHOD_EXIT
:
3776 buffer_add_methodid (&buf
, domain
, arg
);
3778 case EVENT_KIND_ASSEMBLY_LOAD
:
3779 buffer_add_assemblyid (&buf
, domain
, arg
);
3781 case EVENT_KIND_ASSEMBLY_UNLOAD
: {
3782 DebuggerTlsData
*tls
;
3784 /* The domain the assembly belonged to is not equal to the current domain */
3785 tls
= mono_native_tls_get_value (debugger_tls_id
);
3787 g_assert (tls
->domain_unloading
);
3789 buffer_add_assemblyid (&buf
, tls
->domain_unloading
, arg
);
3792 case EVENT_KIND_TYPE_LOAD
:
3793 buffer_add_typeid (&buf
, domain
, arg
);
3795 case EVENT_KIND_BREAKPOINT
:
3796 case EVENT_KIND_STEP
:
3797 buffer_add_methodid (&buf
, domain
, arg
);
3798 buffer_add_long (&buf
, il_offset
);
3800 case EVENT_KIND_VM_START
:
3801 buffer_add_domainid (&buf
, mono_get_root_domain ());
3803 case EVENT_KIND_VM_DEATH
:
3804 if (CHECK_PROTOCOL_VERSION (2, 27))
3805 buffer_add_int (&buf
, mono_environment_exitcode_get ());
3807 case EVENT_KIND_EXCEPTION
: {
3808 EventInfo
*ei
= arg
;
3809 buffer_add_objid (&buf
, ei
->exc
);
3811 * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it
3812 * later after the suspension. (#12494).
3814 keepalive_obj
= ei
->exc
;
3817 case EVENT_KIND_USER_BREAK
:
3819 case EVENT_KIND_USER_LOG
: {
3820 EventInfo
*ei
= arg
;
3821 buffer_add_int (&buf
, ei
->level
);
3822 buffer_add_string (&buf
, ei
->category
? ei
->category
: "");
3823 buffer_add_string (&buf
, ei
->message
? ei
->message
: "");
3826 case EVENT_KIND_KEEPALIVE
:
3827 suspend_policy
= SUSPEND_POLICY_NONE
;
3830 g_assert_not_reached ();
3834 if (event
== EVENT_KIND_VM_START
) {
3835 suspend_policy
= agent_config
.suspend
? SUSPEND_POLICY_ALL
: SUSPEND_POLICY_NONE
;
3836 if (!agent_config
.defer
)
3837 start_debugger_thread ();
3840 if (event
== EVENT_KIND_VM_DEATH
) {
3841 vm_death_event_sent
= TRUE
;
3842 suspend_policy
= SUSPEND_POLICY_NONE
;
3845 if (mono_runtime_is_shutting_down ())
3846 suspend_policy
= SUSPEND_POLICY_NONE
;
3848 if (suspend_policy
!= SUSPEND_POLICY_NONE
) {
3850 * Save the thread context and start suspending before sending the packet,
3851 * since we could be receiving the resume request before send_packet ()
3854 save_thread_context (ctx
);
3858 /* This will keep this object alive */
3859 get_objref (keepalive_obj
);
3862 send_success
= send_packet (CMD_SET_EVENT
, CMD_COMPOSITE
, &buf
);
3866 g_slist_free (events
);
3869 if (!send_success
) {
3870 DEBUG (2, fprintf (log_file
, "Sending command %s failed.\n", event_to_string (event
)));
3874 if (event
== EVENT_KIND_VM_START
) {
3875 vm_start_event_sent
= TRUE
;
3878 DEBUG (1, fprintf (log_file
, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer
)GetCurrentThreadId (), nevents
, event_to_string (event
), ecount
, suspend_policy
));
3880 switch (suspend_policy
) {
3881 case SUSPEND_POLICY_NONE
:
3883 case SUSPEND_POLICY_ALL
:
3886 case SUSPEND_POLICY_EVENT_THREAD
:
3890 g_assert_not_reached ();
3895 process_profiler_event (EventKind event
, gpointer arg
)
3899 EventInfo ei
, *ei_arg
= NULL
;
3901 if (event
== EVENT_KIND_TYPE_LOAD
) {
3906 mono_loader_lock ();
3907 events
= create_event_list (event
, NULL
, NULL
, ei_arg
, &suspend_policy
);
3908 mono_loader_unlock ();
3910 process_event (event
, arg
, 0, NULL
, events
, suspend_policy
);
3914 runtime_initialized (MonoProfiler
*prof
)
3916 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_current ());
3917 if (agent_config
.defer
)
3918 start_debugger_thread ();
3922 runtime_shutdown (MonoProfiler
*prof
)
3924 process_profiler_event (EVENT_KIND_VM_DEATH
, mono_thread_current ());
3926 mono_debugger_agent_cleanup ();
3930 thread_startup (MonoProfiler
*prof
, uintptr_t tid
)
3932 MonoInternalThread
*thread
= mono_thread_internal_current ();
3933 MonoInternalThread
*old_thread
;
3934 DebuggerTlsData
*tls
;
3936 if (tid
== debugger_thread_id
)
3939 g_assert (thread
->tid
== tid
);
3941 mono_loader_lock ();
3942 old_thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3943 mono_loader_unlock ();
3945 if (thread
== old_thread
) {
3947 * For some reason, thread_startup () might be called for the same thread
3948 * multiple times (attach ?).
3950 DEBUG (1, fprintf (log_file
, "[%p] thread_start () called multiple times for %p, ignored.\n", (gpointer
)tid
, (gpointer
)tid
));
3954 * thread_end () might not be called for some threads, and the tid could
3957 DEBUG (1, fprintf (log_file
, "[%p] Removing stale data for tid %p.\n", (gpointer
)tid
, (gpointer
)tid
));
3958 mono_loader_lock ();
3959 mono_g_hash_table_remove (thread_to_tls
, old_thread
);
3960 mono_g_hash_table_remove (tid_to_thread
, (gpointer
)tid
);
3961 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
3962 mono_loader_unlock ();
3966 tls
= mono_native_tls_get_value (debugger_tls_id
);
3968 // FIXME: Free this somewhere
3969 tls
= g_new0 (DebuggerTlsData
, 1);
3970 MONO_GC_REGISTER_ROOT_SINGLE (tls
->thread
);
3971 tls
->thread
= thread
;
3972 mono_native_tls_set_value (debugger_tls_id
, tls
);
3974 DEBUG (1, fprintf (log_file
, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
3976 mono_loader_lock ();
3977 mono_g_hash_table_insert (thread_to_tls
, thread
, tls
);
3978 mono_g_hash_table_insert (tid_to_thread
, (gpointer
)tid
, thread
);
3979 mono_g_hash_table_insert (tid_to_thread_obj
, (gpointer
)tid
, mono_thread_current ());
3980 mono_loader_unlock ();
3982 process_profiler_event (EVENT_KIND_THREAD_START
, thread
);
3985 * suspend_vm () could have missed this thread, so wait for a resume.
3991 thread_end (MonoProfiler
*prof
, uintptr_t tid
)
3993 MonoInternalThread
*thread
;
3994 DebuggerTlsData
*tls
= NULL
;
3996 mono_loader_lock ();
3997 thread
= mono_g_hash_table_lookup (tid_to_thread
, (gpointer
)tid
);
3999 mono_g_hash_table_remove (tid_to_thread_obj
, (gpointer
)tid
);
4000 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4002 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
4003 tls
->terminated
= TRUE
;
4004 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
4005 MONO_GC_UNREGISTER_ROOT (tls
->thread
);
4009 mono_loader_unlock ();
4011 /* We might be called for threads started before we registered the start callback */
4013 DEBUG (1, fprintf (log_file
, "[%p] Thread terminated, obj=%p, tls=%p.\n", (gpointer
)tid
, thread
, tls
));
4014 process_profiler_event (EVENT_KIND_THREAD_DEATH
, thread
);
4019 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
, int result
)
4021 mono_loader_lock ();
4022 g_hash_table_insert (domains
, domain
, domain
);
4023 mono_loader_unlock ();
4025 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE
, domain
);
4029 appdomain_start_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
4031 DebuggerTlsData
*tls
;
4034 * Remember the currently unloading appdomain as it is needed to generate
4035 * proper ids for unloading assemblies.
4037 tls
= mono_native_tls_get_value (debugger_tls_id
);
4039 tls
->domain_unloading
= domain
;
4043 appdomain_unload (MonoProfiler
*prof
, MonoDomain
*domain
)
4045 DebuggerTlsData
*tls
;
4047 tls
= mono_native_tls_get_value (debugger_tls_id
);
4049 tls
->domain_unloading
= NULL
;
4051 clear_breakpoints_for_domain (domain
);
4053 mono_loader_lock ();
4054 /* Invalidate each thread's frame stack */
4055 mono_g_hash_table_foreach (thread_to_tls
, invalidate_each_thread
, NULL
);
4056 mono_loader_unlock ();
4058 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD
, domain
);
4062 * invalidate_each_thread:
4064 * A GHFunc to invalidate frames.
4065 * value must be a DebuggerTlsData*
4068 invalidate_each_thread (gpointer key
, gpointer value
, gpointer user_data
)
4070 invalidate_frames (value
);
4074 assembly_load (MonoProfiler
*prof
, MonoAssembly
*assembly
, int result
)
4076 /* Sent later in jit_end () */
4078 g_ptr_array_add (pending_assembly_loads
, assembly
);
4083 assembly_unload (MonoProfiler
*prof
, MonoAssembly
*assembly
)
4085 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD
, assembly
);
4087 clear_event_requests_for_assembly (assembly
);
4088 clear_types_for_assembly (assembly
);
4092 start_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
4094 #if defined(HOST_WIN32) && !defined(__GNUC__)
4095 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
4097 gpointer stackptr
= __builtin_frame_address (1);
4099 MonoInternalThread
*thread
= mono_thread_internal_current ();
4100 DebuggerTlsData
*tls
;
4102 mono_loader_lock ();
4104 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
4105 /* Could be the debugger thread with assembly/type load hooks */
4107 tls
->invoke_addr
= stackptr
;
4109 mono_loader_unlock ();
4113 end_runtime_invoke (MonoProfiler
*prof
, MonoMethod
*method
)
4116 #if defined(HOST_WIN32) && !defined(__GNUC__)
4117 gpointer stackptr
= ((guint64
)_AddressOfReturnAddress () - sizeof (void*));
4119 gpointer stackptr
= __builtin_frame_address (1);
4122 if (!embedding
|| ss_req
== NULL
|| stackptr
!= ss_invoke_addr
|| ss_req
->thread
!= mono_thread_internal_current ())
4126 * We need to stop single stepping when exiting a runtime invoke, since if it is
4127 * a step out, it may return to native code, and thus never end.
4129 mono_loader_lock ();
4130 ss_invoke_addr
= NULL
;
4132 for (i
= 0; i
< event_requests
->len
; ++i
) {
4133 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4135 if (req
->event_kind
== EVENT_KIND_STEP
) {
4136 ss_destroy (req
->info
);
4137 g_ptr_array_remove_index_fast (event_requests
, i
);
4142 mono_loader_unlock ();
4146 send_type_load (MonoClass
*klass
)
4148 gboolean type_load
= FALSE
;
4149 MonoDomain
*domain
= mono_domain_get ();
4150 AgentDomainInfo
*info
= NULL
;
4152 mono_loader_lock ();
4153 mono_domain_lock (domain
);
4155 info
= get_agent_domain_info (domain
);
4157 if (!g_hash_table_lookup (info
->loaded_classes
, klass
)) {
4159 g_hash_table_insert (info
->loaded_classes
, klass
, klass
);
4162 mono_domain_unlock (domain
);
4163 mono_loader_unlock ();
4165 emit_type_load (klass
, klass
, NULL
);
4169 * Emit load events for all types currently loaded in the domain.
4170 * Takes the loader and domain locks.
4171 * user_data is unused.
4174 send_types_for_domain (MonoDomain
*domain
, void *user_data
)
4176 AgentDomainInfo
*info
= NULL
;
4178 mono_loader_lock ();
4179 mono_domain_lock (domain
);
4180 info
= get_agent_domain_info (domain
);
4182 g_hash_table_foreach (info
->loaded_classes
, emit_type_load
, NULL
);
4183 mono_domain_unlock (domain
);
4184 mono_loader_unlock ();
4188 jit_end (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
, int result
)
4191 * We emit type load events when the first method of the type is JITted,
4192 * since the class load profiler callbacks might be called with the
4193 * loader lock held. They could also occur in the debugger thread.
4194 * Same for assembly load events.
4197 MonoAssembly
*assembly
= NULL
;
4199 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
4201 if (pending_assembly_loads
->len
> 0) {
4202 assembly
= g_ptr_array_index (pending_assembly_loads
, 0);
4203 g_ptr_array_remove_index (pending_assembly_loads
, 0);
4208 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD
, assembly
);
4214 send_type_load (method
->klass
);
4217 add_pending_breakpoints (method
, jinfo
);
4221 * BREAKPOINTS/SINGLE STEPPING
4225 * Contains information about an inserted breakpoint.
4228 long il_offset
, native_offset
;
4233 } BreakpointInstance
;
4236 * Contains generic information about a breakpoint.
4240 * The method where the breakpoint is placed. Can be NULL in which case it
4241 * is inserted into every method. This is used to implement method entry/
4242 * exit events. Can be a generic method definition, in which case the
4243 * breakpoint is inserted into every instance.
4249 * A list of BreakpointInstance structures describing where the breakpoint
4250 * was inserted. There could be more than one because of
4251 * generics/appdomains/method entry/exit.
4253 GPtrArray
*children
;
4256 /* List of breakpoints */
4257 static GPtrArray
*breakpoints
;
4258 /* Maps breakpoint locations to the number of breakpoints at that location */
4259 static GHashTable
*bp_locs
;
4262 breakpoints_init (void)
4264 breakpoints
= g_ptr_array_new ();
4265 bp_locs
= g_hash_table_new (NULL
, NULL
);
4269 * insert_breakpoint:
4271 * Insert the breakpoint described by BP into the method described by
4275 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoDomain
*domain
, MonoJitInfo
*ji
, MonoBreakpoint
*bp
, MonoError
*error
)
4278 BreakpointInstance
*inst
;
4279 SeqPoint
*sp
= NULL
;
4282 mono_error_init (error
);
4284 for (i
= 0; i
< seq_points
->len
; ++i
) {
4285 sp
= &seq_points
->seq_points
[i
];
4287 if (sp
->il_offset
== bp
->il_offset
)
4291 if (i
== seq_points
->len
) {
4293 * The set of IL offsets with seq points doesn't completely match the
4294 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
4296 for (i
= 0; i
< seq_points
->len
; ++i
) {
4297 sp
= &seq_points
->seq_points
[i
];
4299 if (sp
->il_offset
!= METHOD_ENTRY_IL_OFFSET
&& sp
->il_offset
!= METHOD_EXIT_IL_OFFSET
&& sp
->il_offset
+ 1 == bp
->il_offset
)
4304 if (i
== seq_points
->len
) {
4305 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
);
4307 for (i
= 0; i
< seq_points
->len
; ++i
)
4308 DEBUG (1, fprintf (log_file
, "%d\n", seq_points
->seq_points
[i
].il_offset
));
4311 mono_error_set_error (error
, MONO_ERROR_GENERIC
, "%s", s
);
4312 g_warning ("%s", s
);
4316 g_warning ("%s", s
);
4322 inst
= g_new0 (BreakpointInstance
, 1);
4324 inst
->native_offset
= sp
->native_offset
;
4325 inst
->ip
= (guint8
*)ji
->code_start
+ sp
->native_offset
;
4327 inst
->domain
= domain
;
4329 mono_loader_lock ();
4331 g_ptr_array_add (bp
->children
, inst
);
4333 mono_loader_unlock ();
4336 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
4337 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
4340 if (sp
->native_offset
== SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
) {
4341 DEBUG (1, fprintf (log_file
, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp
->il_offset
));
4342 } else if (count
== 0) {
4343 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4344 mono_arch_set_breakpoint (ji
, inst
->ip
);
4350 DEBUG(1, fprintf (log_file
, "[dbg] Inserted breakpoint at %s:0x%x [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji
), TRUE
), (int)sp
->il_offset
, inst
->ip
, count
));
4354 remove_breakpoint (BreakpointInstance
*inst
)
4356 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
4358 MonoJitInfo
*ji
= inst
->ji
;
4359 guint8
*ip
= inst
->ip
;
4362 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, ip
));
4363 g_hash_table_insert (bp_locs
, ip
, GINT_TO_POINTER (count
- 1));
4366 g_assert (count
> 0);
4368 if (count
== 1 && inst
->native_offset
!= SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
) {
4369 mono_arch_clear_breakpoint (ji
, ip
);
4370 DEBUG(1, fprintf (log_file
, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji
), TRUE
), ip
));
4377 static inline gboolean
4378 bp_matches_method (MonoBreakpoint
*bp
, MonoMethod
*method
)
4384 if (method
== bp
->method
)
4386 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
)
4389 if (bp
->method
->is_inflated
&& method
->is_inflated
) {
4390 MonoMethodInflated
*bpimethod
= (MonoMethodInflated
*)bp
->method
;
4391 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
4393 /* Open generic methods should match closed generic methods of the same class */
4394 if (bpimethod
->declaring
== imethod
->declaring
&& bpimethod
->context
.class_inst
== imethod
->context
.class_inst
&& bpimethod
->context
.method_inst
&& bpimethod
->context
.method_inst
->is_open
) {
4395 for (i
= 0; i
< bpimethod
->context
.method_inst
->type_argc
; ++i
) {
4396 MonoType
*t1
= bpimethod
->context
.method_inst
->type_argv
[i
];
4398 /* FIXME: Handle !mvar */
4399 if (t1
->type
!= MONO_TYPE_MVAR
)
4410 * add_pending_breakpoints:
4412 * Insert pending breakpoints into the newly JITted method METHOD.
4415 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
4418 MonoSeqPointInfo
*seq_points
;
4420 MonoMethod
*jmethod
;
4425 domain
= mono_domain_get ();
4427 mono_loader_lock ();
4429 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4430 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
4431 gboolean found
= FALSE
;
4433 if (!bp_matches_method (bp
, method
))
4436 for (j
= 0; j
< bp
->children
->len
; ++j
) {
4437 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
4444 jmethod
= jinfo_get_method (ji
);
4445 mono_domain_lock (domain
);
4446 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, jmethod
);
4447 if (!seq_points
&& jmethod
->is_inflated
)
4448 seq_points
= g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, mono_method_get_declaring_generic_method (jmethod
));
4449 mono_domain_unlock (domain
);
4451 /* Could be AOT code */
4453 g_assert (seq_points
);
4455 insert_breakpoint (seq_points
, domain
, ji
, bp
, NULL
);
4459 mono_loader_unlock ();
4463 set_bp_in_method (MonoDomain
*domain
, MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, MonoBreakpoint
*bp
, MonoError
*error
)
4469 mono_error_init (error
);
4471 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
4473 /* Might be AOTed code */
4474 code
= mono_aot_get_method (domain
, method
);
4476 ji
= mono_jit_info_table_find (domain
, code
);
4481 insert_breakpoint (seq_points
, domain
, ji
, bp
, error
);
4485 clear_breakpoint (MonoBreakpoint
*bp
);
4490 * Set a breakpoint at IL_OFFSET in METHOD.
4491 * METHOD can be NULL, in which case a breakpoint is placed in all methods.
4492 * METHOD can also be a generic method definition, in which case a breakpoint
4493 * is placed in all instances of the method.
4494 * If ERROR is non-NULL, then it is set and NULL is returnd if some breakpoints couldn't be
4497 static MonoBreakpoint
*
4498 set_breakpoint (MonoMethod
*method
, long il_offset
, EventRequest
*req
, MonoError
*error
)
4501 GHashTableIter iter
, iter2
;
4504 MonoSeqPointInfo
*seq_points
;
4507 mono_error_init (error
);
4510 // - suspend/resume the vm to prevent code patching problems
4511 // - multiple breakpoints on the same location
4512 // - dynamic methods
4515 bp
= g_new0 (MonoBreakpoint
, 1);
4516 bp
->method
= method
;
4517 bp
->il_offset
= il_offset
;
4519 bp
->children
= g_ptr_array_new ();
4521 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
));
4523 mono_loader_lock ();
4525 g_hash_table_iter_init (&iter
, domains
);
4526 while (g_hash_table_iter_next (&iter
, (void**)&domain
, NULL
)) {
4527 mono_domain_lock (domain
);
4529 g_hash_table_iter_init (&iter2
, domain_jit_info (domain
)->seq_points
);
4530 while (g_hash_table_iter_next (&iter2
, (void**)&m
, (void**)&seq_points
)) {
4531 if (bp_matches_method (bp
, m
))
4532 set_bp_in_method (domain
, m
, seq_points
, bp
, error
);
4535 mono_domain_unlock (domain
);
4538 mono_loader_unlock ();
4540 mono_loader_lock ();
4541 g_ptr_array_add (breakpoints
, bp
);
4542 mono_loader_unlock ();
4544 if (error
&& !mono_error_ok (error
)) {
4545 clear_breakpoint (bp
);
4553 clear_breakpoint (MonoBreakpoint
*bp
)
4557 // FIXME: locking, races
4558 for (i
= 0; i
< bp
->children
->len
; ++i
) {
4559 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, i
);
4561 remove_breakpoint (inst
);
4566 mono_loader_lock ();
4567 g_ptr_array_remove (breakpoints
, bp
);
4568 mono_loader_unlock ();
4570 g_ptr_array_free (bp
->children
, TRUE
);
4575 breakpoints_cleanup (void)
4579 mono_loader_lock ();
4581 while (i
< event_requests
->len
) {
4582 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
4584 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
4585 clear_breakpoint (req
->info
);
4586 g_ptr_array_remove_index_fast (event_requests
, i
);
4593 for (i
= 0; i
< breakpoints
->len
; ++i
)
4594 g_free (g_ptr_array_index (breakpoints
, i
));
4596 g_ptr_array_free (breakpoints
, TRUE
);
4597 g_hash_table_destroy (bp_locs
);
4602 mono_loader_unlock ();
4606 * clear_breakpoints_for_domain:
4608 * Clear breakpoint instances which reference DOMAIN.
4611 clear_breakpoints_for_domain (MonoDomain
*domain
)
4615 /* This could be called after shutdown */
4619 mono_loader_lock ();
4620 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4621 MonoBreakpoint
*bp
= g_ptr_array_index (breakpoints
, i
);
4624 while (j
< bp
->children
->len
) {
4625 BreakpointInstance
*inst
= g_ptr_array_index (bp
->children
, j
);
4627 if (inst
->domain
== domain
) {
4628 remove_breakpoint (inst
);
4632 g_ptr_array_remove_index_fast (bp
->children
, j
);
4638 mono_loader_unlock ();
4644 * Return FALSE if single stepping needs to continue.
4647 ss_update (SingleStepReq
*req
, MonoJitInfo
*ji
, SeqPoint
*sp
, DebuggerTlsData
*tls
, MonoContext
*ctx
)
4649 MonoDebugMethodInfo
*minfo
;
4650 MonoDebugSourceLocation
*loc
= NULL
;
4651 gboolean hit
= TRUE
;
4654 if (req
->depth
== STEP_DEPTH_OVER
&& (sp
->flags
& MONO_SEQ_POINT_FLAG_NONEMPTY_STACK
)) {
4656 * These seq points are inserted by the JIT after calls, step over needs to skip them.
4658 DEBUG (1, fprintf (log_file
, "[%p] Seq point at nonempty stack %x while stepping over, continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), sp
->il_offset
));
4662 if (req
->depth
== STEP_DEPTH_OVER
&& hit
) {
4663 if (!tls
->context
.valid
)
4664 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
4665 compute_frame_info (tls
->thread
, tls
);
4666 if (req
->nframes
&& tls
->frame_count
&& tls
->frame_count
> req
->nframes
) {
4667 /* Hit the breakpoint in a recursive call */
4668 DEBUG (1, fprintf (log_file
, "[%p] Breakpoint at lower frame while stepping over, continuing single stepping.\n", (gpointer
)GetCurrentThreadId ()));
4673 if (req
->size
!= STEP_SIZE_LINE
)
4676 /* Have to check whenever a different source line was reached */
4677 method
= jinfo_get_method (ji
);
4678 minfo
= mono_debug_lookup_method (method
);
4681 loc
= mono_debug_symfile_lookup_location (minfo
, sp
->il_offset
);
4683 if (!loc
|| (loc
&& method
== ss_req
->last_method
&& loc
->row
== ss_req
->last_line
)) {
4684 /* Have to continue single stepping */
4686 DEBUG(1, fprintf (log_file
, "[%p] No line number info for il offset %x, continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), sp
->il_offset
));
4688 DEBUG(1, fprintf (log_file
, "[%p] Same source line (%d), continuing single stepping.\n", (gpointer
)GetCurrentThreadId (), loc
->row
));
4693 ss_req
->last_method
= method
;
4694 ss_req
->last_line
= loc
->row
;
4695 mono_debug_free_source_location (loc
);
4702 breakpoint_matches_assembly (MonoBreakpoint
*bp
, MonoAssembly
*assembly
)
4704 return bp
->method
&& bp
->method
->klass
->image
->assembly
== assembly
;
4708 process_breakpoint_inner (DebuggerTlsData
*tls
)
4712 int i
, j
, suspend_policy
;
4713 guint32 native_offset
;
4715 BreakpointInstance
*inst
;
4716 GPtrArray
*bp_reqs
, *ss_reqs_orig
, *ss_reqs
;
4717 GSList
*bp_events
= NULL
, *ss_events
= NULL
, *enter_leave_events
= NULL
;
4718 EventKind kind
= EVENT_KIND_BREAKPOINT
;
4719 MonoContext
*ctx
= &tls
->restore_ctx
;
4721 MonoSeqPointInfo
*info
;
4724 // FIXME: Speed this up
4726 ip
= MONO_CONTEXT_GET_IP (ctx
);
4727 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, NULL
);
4729 method
= jinfo_get_method (ji
);
4731 /* Compute the native offset of the breakpoint from the ip */
4732 native_offset
= ip
- (guint8
*)ji
->code_start
;
4735 * Skip the instruction causing the breakpoint signal.
4737 mono_arch_skip_breakpoint (ctx
, ji
);
4739 if (method
->wrapper_type
|| tls
->disable_breakpoints
)
4742 bp_reqs
= g_ptr_array_new ();
4743 ss_reqs
= g_ptr_array_new ();
4744 ss_reqs_orig
= g_ptr_array_new ();
4746 mono_loader_lock ();
4749 * The ip points to the instruction causing the breakpoint event, which is after
4750 * the offset recorded in the seq point map, so find the prev seq point before ip.
4752 sp
= find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
);
4754 no_seq_points_found (method
);
4757 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));
4760 for (i
= 0; i
< breakpoints
->len
; ++i
) {
4761 bp
= g_ptr_array_index (breakpoints
, i
);
4766 for (j
= 0; j
< bp
->children
->len
; ++j
) {
4767 inst
= g_ptr_array_index (bp
->children
, j
);
4768 if (inst
->ji
== ji
&& inst
->sp
== sp
) {
4769 if (bp
->req
->event_kind
== EVENT_KIND_STEP
) {
4770 g_ptr_array_add (ss_reqs_orig
, bp
->req
);
4772 g_ptr_array_add (bp_reqs
, bp
->req
);
4777 if (bp_reqs
->len
== 0 && ss_reqs_orig
->len
== 0) {
4778 /* Maybe a method entry/exit event */
4779 if (sp
->il_offset
== METHOD_ENTRY_IL_OFFSET
)
4780 kind
= EVENT_KIND_METHOD_ENTRY
;
4781 else if (sp
->il_offset
== METHOD_EXIT_IL_OFFSET
)
4782 kind
= EVENT_KIND_METHOD_EXIT
;
4785 /* Process single step requests */
4786 for (i
= 0; i
< ss_reqs_orig
->len
; ++i
) {
4787 EventRequest
*req
= g_ptr_array_index (ss_reqs_orig
, i
);
4788 SingleStepReq
*ss_req
= req
->info
;
4791 if (mono_thread_internal_current () != ss_req
->thread
)
4794 hit
= ss_update (ss_req
, ji
, sp
, tls
, ctx
);
4796 g_ptr_array_add (ss_reqs
, req
);
4798 /* Start single stepping again from the current sequence point */
4799 ss_start (ss_req
, method
, sp
, info
, ctx
, tls
, FALSE
);
4802 if (ss_reqs
->len
> 0)
4803 ss_events
= create_event_list (EVENT_KIND_STEP
, ss_reqs
, ji
, NULL
, &suspend_policy
);
4804 if (bp_reqs
->len
> 0)
4805 bp_events
= create_event_list (EVENT_KIND_BREAKPOINT
, bp_reqs
, ji
, NULL
, &suspend_policy
);
4806 if (kind
!= EVENT_KIND_BREAKPOINT
)
4807 enter_leave_events
= create_event_list (kind
, NULL
, ji
, NULL
, &suspend_policy
);
4809 mono_loader_unlock ();
4811 g_ptr_array_free (bp_reqs
, TRUE
);
4812 g_ptr_array_free (ss_reqs
, TRUE
);
4815 * FIXME: The first event will suspend, so the second will only be sent after the
4819 process_event (EVENT_KIND_STEP
, method
, 0, ctx
, ss_events
, suspend_policy
);
4821 process_event (kind
, method
, 0, ctx
, bp_events
, suspend_policy
);
4822 if (enter_leave_events
)
4823 process_event (kind
, method
, 0, ctx
, enter_leave_events
, suspend_policy
);
4826 /* Process a breakpoint/single step event after resuming from a signal handler */
4828 process_signal_event (void (*func
) (DebuggerTlsData
*))
4830 DebuggerTlsData
*tls
;
4831 MonoContext orig_restore_ctx
, ctx
;
4833 tls
= mono_native_tls_get_value (debugger_tls_id
);
4834 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4835 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4836 memcpy (&tls
->restore_ctx
, &tls
->handler_ctx
, sizeof (MonoContext
));
4840 /* This is called when resuming from a signal handler, so it shouldn't return */
4841 memcpy (&ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
4842 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
4843 mono_restore_context (&ctx
);
4844 g_assert_not_reached ();
4848 process_breakpoint (void)
4850 process_signal_event (process_breakpoint_inner
);
4854 resume_from_signal_handler (void *sigctx
, void *func
)
4856 DebuggerTlsData
*tls
;
4859 /* Save the original context in TLS */
4860 // FIXME: This might not work on an altstack ?
4861 tls
= mono_native_tls_get_value (debugger_tls_id
);
4863 fprintf (stderr
, "Thread %p is not attached to the JIT.\n", (gpointer
)GetCurrentThreadId ());
4866 // FIXME: MonoContext usually doesn't include the fp registers, so these are
4867 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
4868 // clob:c could be added to op_seq_point.
4870 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
4871 memcpy (&tls
->handler_ctx
, &ctx
, sizeof (MonoContext
));
4872 #ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
4873 mono_arch_setup_resume_sighandler_ctx (&ctx
, func
);
4875 MONO_CONTEXT_SET_IP (&ctx
, func
);
4877 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
4879 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
4880 mono_ppc_set_func_into_sigctx (sigctx
, func
);
4885 mono_debugger_agent_breakpoint_hit (void *sigctx
)
4888 * We are called from a signal handler, and running code there causes all kinds of
4889 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
4890 * So set up the signal context to return to the real breakpoint handler function.
4892 resume_from_signal_handler (sigctx
, process_breakpoint
);
4896 user_break_cb (StackFrameInfo
*frame
, MonoContext
*ctx
, gpointer data
)
4898 if (frame
->managed
) {
4899 *(MonoContext
*)data
= *ctx
;
4908 * Called by System.Diagnostics.Debugger:Break ().
4911 mono_debugger_agent_user_break (void)
4913 if (agent_config
.enabled
) {
4918 /* Obtain a context */
4919 MONO_CONTEXT_SET_IP (&ctx
, NULL
);
4920 mono_walk_stack_with_ctx (user_break_cb
, NULL
, 0, &ctx
);
4921 g_assert (MONO_CONTEXT_GET_IP (&ctx
) != NULL
);
4923 mono_loader_lock ();
4924 events
= create_event_list (EVENT_KIND_USER_BREAK
, NULL
, NULL
, NULL
, &suspend_policy
);
4925 mono_loader_unlock ();
4927 process_event (EVENT_KIND_USER_BREAK
, NULL
, 0, &ctx
, events
, suspend_policy
);
4934 ss_depth_to_string (StepDepth depth
)
4937 case STEP_DEPTH_OVER
:
4939 case STEP_DEPTH_OUT
:
4941 case STEP_DEPTH_INTO
:
4944 g_assert_not_reached ();
4950 process_single_step_inner (DebuggerTlsData
*tls
)
4955 int il_offset
, suspend_policy
;
4958 MonoContext
*ctx
= &tls
->restore_ctx
;
4961 MonoSeqPointInfo
*info
;
4963 ip
= MONO_CONTEXT_GET_IP (ctx
);
4965 /* Skip the instruction causing the single step */
4966 mono_arch_skip_single_step (ctx
);
4968 if (suspend_count
> 0) {
4969 process_suspend (tls
, ctx
);
4974 // FIXME: A suspend race
4977 if (mono_thread_internal_current () != ss_req
->thread
)
4980 if (log_level
> 0) {
4981 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4983 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
));
4986 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)ip
, &domain
);
4988 method
= jinfo_get_method (ji
);
4991 if (method
->wrapper_type
&& method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)
4996 * Stopping in memset makes half-initialized vtypes visible.
4997 * Stopping in memcpy makes half-copied vtypes visible.
4999 if (method
->klass
== mono_defaults
.string_class
&& (!strcmp (method
->name
, "memset") || strstr (method
->name
, "memcpy")))
5003 * The ip points to the instruction causing the single step event, which is before
5004 * the offset recorded in the seq point map, so find the next seq point after ip.
5006 sp
= find_next_seq_point_for_native_offset (domain
, method
, (guint8
*)ip
- (guint8
*)ji
->code_start
, &info
);
5009 il_offset
= sp
->il_offset
;
5011 if (!ss_update (ss_req
, ji
, sp
, tls
, ctx
))
5014 /* Start single stepping again from the current sequence point */
5015 ss_start (ss_req
, method
, sp
, info
, ctx
, tls
, FALSE
);
5017 if ((ss_req
->filter
& STEP_FILTER_STATIC_CTOR
) &&
5018 (method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
5019 !strcmp (method
->name
, ".cctor"))
5022 // FIXME: Has to lock earlier
5024 reqs
= g_ptr_array_new ();
5026 mono_loader_lock ();
5028 g_ptr_array_add (reqs
, ss_req
->req
);
5030 events
= create_event_list (EVENT_KIND_STEP
, reqs
, ji
, NULL
, &suspend_policy
);
5032 g_ptr_array_free (reqs
, TRUE
);
5034 mono_loader_unlock ();
5036 process_event (EVENT_KIND_STEP
, jinfo_get_method (ji
), il_offset
, ctx
, events
, suspend_policy
);
5040 process_single_step (void)
5042 process_signal_event (process_single_step_inner
);
5046 * mono_debugger_agent_single_step_event:
5048 * Called from a signal handler to handle a single step event.
5051 mono_debugger_agent_single_step_event (void *sigctx
)
5053 /* Resume to process_single_step through the signal context */
5055 // FIXME: Since step out/over is implemented using step in, the step in case should
5056 // be as fast as possible. Move the relevant code from process_single_step_inner ()
5059 if (GetCurrentThreadId () == debugger_thread_id
) {
5061 * This could happen despite our best effors when the runtime calls
5062 * assembly/type resolve hooks.
5063 * FIXME: Breakpoints too.
5067 mono_arch_sigctx_to_monoctx (sigctx
, &ctx
);
5068 mono_arch_skip_single_step (&ctx
);
5069 mono_arch_monoctx_to_sigctx (&ctx
, sigctx
);
5073 resume_from_signal_handler (sigctx
, process_single_step
);
5077 debugger_agent_single_step_from_context (MonoContext
*ctx
)
5079 DebuggerTlsData
*tls
;
5080 MonoContext orig_restore_ctx
;
5082 tls
= mono_native_tls_get_value (debugger_tls_id
);
5085 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
5086 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5087 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
5089 process_single_step_inner (tls
);
5091 memcpy (ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5092 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
5096 debugger_agent_breakpoint_from_context (MonoContext
*ctx
)
5098 DebuggerTlsData
*tls
;
5099 MonoContext orig_restore_ctx
;
5101 tls
= mono_native_tls_get_value (debugger_tls_id
);
5103 memcpy (&orig_restore_ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5104 memcpy (&tls
->restore_ctx
, ctx
, sizeof (MonoContext
));
5106 process_breakpoint_inner (tls
);
5108 memcpy (ctx
, &tls
->restore_ctx
, sizeof (MonoContext
));
5109 memcpy (&tls
->restore_ctx
, &orig_restore_ctx
, sizeof (MonoContext
));
5113 * start_single_stepping:
5115 * Turn on single stepping. Can be called multiple times, for example,
5116 * by a single step event request + a suspend.
5119 start_single_stepping (void)
5121 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5122 int val
= InterlockedIncrement (&ss_count
);
5125 mono_arch_start_single_stepping ();
5127 if (ss_req
!= NULL
&& ss_invoke_addr
== NULL
) {
5128 DebuggerTlsData
*tls
;
5130 mono_loader_lock ();
5132 tls
= mono_g_hash_table_lookup (thread_to_tls
, ss_req
->thread
);
5133 ss_invoke_addr
= tls
->invoke_addr
;
5135 mono_loader_unlock ();
5138 g_assert_not_reached ();
5143 stop_single_stepping (void)
5145 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5146 int val
= InterlockedDecrement (&ss_count
);
5149 mono_arch_stop_single_stepping ();
5151 ss_invoke_addr
= NULL
;
5153 g_assert_not_reached ();
5160 * Stop the single stepping operation given by SS_REQ.
5163 ss_stop (SingleStepReq
*ss_req
)
5168 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
5169 clear_breakpoint (l
->data
);
5171 g_slist_free (ss_req
->bps
);
5175 if (ss_req
->global
) {
5176 stop_single_stepping ();
5177 ss_req
->global
= FALSE
;
5184 * Start the single stepping operation given by SS_REQ from the sequence point SP.
5185 * If CTX is not set, then this can target any thread. If CTX is set, then TLS should
5186 * belong to the same thread as CTX.
5189 ss_start (SingleStepReq
*ss_req
, MonoMethod
*method
, SeqPoint
*sp
, MonoSeqPointInfo
*info
, MonoContext
*ctx
, DebuggerTlsData
*tls
, gboolean step_to_catch
)
5191 int i
, j
, frame_index
;
5194 gboolean enable_global
= FALSE
;
5196 /* Stop the previous operation */
5200 * Implement single stepping using breakpoints if possible.
5202 if (step_to_catch
) {
5203 bp
= set_breakpoint (method
, sp
->il_offset
, ss_req
->req
, NULL
);
5204 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5208 if ((!sp
|| sp
->next_len
== 0 || ss_req
->depth
== STEP_DEPTH_OUT
|| ss_req
->depth
== STEP_DEPTH_OVER
) && ctx
) {
5209 /* Need parent frames */
5210 if (!tls
->context
.valid
)
5211 mono_thread_state_init_from_monoctx (&tls
->context
, ctx
);
5212 compute_frame_info (tls
->thread
, tls
);
5216 * Find the first sequence point in the current or in a previous frame which
5217 * is not the last in its method.
5219 if (ss_req
->depth
== STEP_DEPTH_OUT
) {
5220 /* Ignore seq points in current method */
5221 while (frame_index
< tls
->frame_count
) {
5222 StackFrame
*frame
= tls
->frames
[frame_index
];
5224 method
= frame
->method
;
5225 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5227 if (sp
&& sp
->next_len
!= 0)
5230 // There could be method calls before the next seq point in the caller when using nested calls
5231 //enable_global = TRUE;
5233 if (sp
&& sp
->next_len
== 0) {
5235 while (frame_index
< tls
->frame_count
) {
5236 StackFrame
*frame
= tls
->frames
[frame_index
];
5238 method
= frame
->method
;
5239 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5240 if (sp
&& sp
->next_len
!= 0)
5248 if (sp
&& sp
->next_len
> 0) {
5249 for (i
= 0; i
< sp
->next_len
; ++i
) {
5250 next_sp
= &info
->seq_points
[sp
->next
[i
]];
5252 bp
= set_breakpoint (method
, next_sp
->il_offset
, ss_req
->req
, NULL
);
5253 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5257 if (ss_req
->depth
== STEP_DEPTH_OVER
) {
5258 if (ss_req
->nframes
== 0)
5259 ss_req
->nframes
= tls
->frame_count
;
5260 /* Need to stop in catch clauses as well */
5261 for (i
= 0; i
< tls
->frame_count
; ++i
) {
5262 StackFrame
*frame
= tls
->frames
[i
];
5265 MonoJitInfo
*jinfo
= frame
->ji
;
5266 for (j
= 0; j
< jinfo
->num_clauses
; ++j
) {
5267 MonoJitExceptionInfo
*ei
= &jinfo
->clauses
[j
];
5269 sp
= find_next_seq_point_for_native_offset (frame
->domain
, frame
->method
, (char*)ei
->handler_start
- (char*)jinfo
->code_start
, NULL
);
5271 bp
= set_breakpoint (frame
->method
, sp
->il_offset
, ss_req
->req
, NULL
);
5272 ss_req
->bps
= g_slist_append (ss_req
->bps
, bp
);
5280 if (ss_req
->depth
== STEP_DEPTH_INTO
) {
5281 /* Enable global stepping so we stop at method entry too */
5282 enable_global
= TRUE
;
5286 * The ctx/frame info computed above will become invalid when we continue.
5288 tls
->context
.valid
= FALSE
;
5289 tls
->async_state
.valid
= FALSE
;
5290 invalidate_frames (tls
);
5293 if (enable_global
) {
5294 DEBUG (1, fprintf (log_file
, "[dbg] Turning on global single stepping.\n"));
5295 ss_req
->global
= TRUE
;
5296 start_single_stepping ();
5297 } else if (!ss_req
->bps
) {
5298 DEBUG (1, fprintf (log_file
, "[dbg] Turning on global single stepping.\n"));
5299 ss_req
->global
= TRUE
;
5300 start_single_stepping ();
5302 ss_req
->global
= FALSE
;
5307 * Start single stepping of thread THREAD
5310 ss_create (MonoInternalThread
*thread
, StepSize size
, StepDepth depth
, EventRequest
*req
)
5312 DebuggerTlsData
*tls
;
5313 MonoSeqPointInfo
*info
= NULL
;
5314 SeqPoint
*sp
= NULL
;
5315 MonoMethod
*method
= NULL
;
5316 MonoDebugMethodInfo
*minfo
;
5317 gboolean step_to_catch
= FALSE
;
5319 if (suspend_count
== 0)
5320 return ERR_NOT_SUSPENDED
;
5322 wait_for_suspend ();
5324 // FIXME: Multiple requests
5326 DEBUG (0, fprintf (log_file
, "Received a single step request while the previous one was still active.\n"));
5327 return ERR_NOT_IMPLEMENTED
;
5330 DEBUG (1, fprintf (log_file
, "[dbg] Starting single step of thread %p (depth=%s).\n", thread
, ss_depth_to_string (depth
)));
5332 ss_req
= g_new0 (SingleStepReq
, 1);
5334 ss_req
->thread
= thread
;
5335 ss_req
->size
= size
;
5336 ss_req
->depth
= depth
;
5339 mono_loader_lock ();
5340 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5341 mono_loader_unlock ();
5343 g_assert (tls
->context
.valid
);
5344 ss_req
->start_sp
= ss_req
->last_sp
= MONO_CONTEXT_GET_SP (&tls
->context
.ctx
);
5346 if (tls
->catch_state
.valid
) {
5348 StackFrameInfo frame
;
5349 MonoContext new_ctx
;
5350 MonoLMF
*lmf
= NULL
;
5353 * We are stopped at a throw site. Stepping should go to the catch site.
5356 /* Find the the jit info for the catch context */
5357 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
);
5359 g_assert (frame
.type
== FRAME_TYPE_MANAGED
);
5362 * Find the seq point corresponding to the landing site ip, which is the first seq
5365 sp
= find_next_seq_point_for_native_offset (frame
.domain
, frame
.method
, frame
.native_offset
, &info
);
5367 no_seq_points_found (frame
.method
);
5370 method
= frame
.method
;
5372 step_to_catch
= TRUE
;
5373 /* This make sure the seq point is not skipped by process_single_step () */
5374 ss_req
->last_sp
= NULL
;
5377 if (!step_to_catch
&& ss_req
->size
== STEP_SIZE_LINE
) {
5380 /* Compute the initial line info */
5381 compute_frame_info (thread
, tls
);
5383 if (tls
->frame_count
) {
5384 frame
= tls
->frames
[0];
5386 ss_req
->last_method
= frame
->method
;
5387 ss_req
->last_line
= -1;
5389 minfo
= mono_debug_lookup_method (frame
->method
);
5390 if (minfo
&& frame
->il_offset
!= -1) {
5391 MonoDebugSourceLocation
*loc
= mono_debug_symfile_lookup_location (minfo
, frame
->il_offset
);
5394 ss_req
->last_line
= loc
->row
;
5401 if (!step_to_catch
) {
5404 compute_frame_info (thread
, tls
);
5406 if (tls
->frame_count
) {
5407 frame
= tls
->frames
[0];
5409 if (!method
&& frame
->il_offset
!= -1) {
5410 /* FIXME: Sort the table and use a binary search */
5411 sp
= find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &info
);
5413 no_seq_points_found (frame
->method
);
5415 method
= frame
->method
;
5420 ss_start (ss_req
, method
, sp
, info
, &tls
->context
.ctx
, tls
, step_to_catch
);
5426 ss_destroy (SingleStepReq
*req
)
5429 g_assert (ss_req
== req
);
5438 ss_clear_for_assembly (SingleStepReq
*req
, MonoAssembly
*assembly
)
5441 gboolean found
= TRUE
;
5445 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
5446 if (breakpoint_matches_assembly (l
->data
, assembly
)) {
5447 clear_breakpoint (l
->data
);
5448 ss_req
->bps
= g_slist_delete_link (ss_req
->bps
, l
);
5457 * Called from metadata by the icall for System.Diagnostics.Debugger:Log ().
5460 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
5466 if (!agent_config
.enabled
)
5469 mono_loader_lock ();
5470 events
= create_event_list (EVENT_KIND_USER_LOG
, NULL
, NULL
, NULL
, &suspend_policy
);
5471 mono_loader_unlock ();
5474 ei
.category
= category
? mono_string_to_utf8 (category
) : NULL
;
5475 ei
.message
= message
? mono_string_to_utf8 (message
) : NULL
;
5477 process_event (EVENT_KIND_USER_LOG
, &ei
, 0, NULL
, events
, suspend_policy
);
5479 g_free (ei
.category
);
5480 g_free (ei
.message
);
5484 mono_debugger_agent_debug_log_is_enabled (void)
5486 /* Treat this as true even if there is no event request for EVENT_KIND_USER_LOG */
5487 return agent_config
.enabled
;
5490 #if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
5492 mono_debugger_agent_unhandled_exception (MonoException
*exc
)
5501 memset (&ei
, 0, sizeof (EventInfo
));
5502 ei
.exc
= (MonoObject
*)exc
;
5504 mono_loader_lock ();
5505 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, NULL
, &ei
, &suspend_policy
);
5506 mono_loader_unlock ();
5508 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, NULL
, events
, suspend_policy
);
5513 mono_debugger_agent_handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
,
5514 MonoContext
*catch_ctx
)
5516 int i
, j
, suspend_policy
;
5518 MonoJitInfo
*ji
, *catch_ji
;
5520 DebuggerTlsData
*tls
= NULL
;
5522 if (thread_to_tls
!= NULL
) {
5523 MonoInternalThread
*thread
= mono_thread_internal_current ();
5525 mono_loader_lock ();
5526 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
5527 mono_loader_unlock ();
5529 if (tls
&& tls
->abort_requested
)
5531 if (tls
&& tls
->disable_breakpoints
)
5535 memset (&ei
, 0, sizeof (EventInfo
));
5537 /* Just-In-Time debugging */
5539 if (agent_config
.onuncaught
&& !inited
) {
5540 finish_agent_init (FALSE
);
5543 * Send an unsolicited EXCEPTION event with a dummy request id.
5545 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
5546 ei
.exc
= (MonoObject
*)exc
;
5547 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
5550 } else if (agent_config
.onthrow
&& !inited
) {
5552 gboolean found
= FALSE
;
5554 for (l
= agent_config
.onthrow
; l
; l
= l
->next
) {
5555 char *ex_type
= l
->data
;
5556 char *f
= mono_type_full_name (&exc
->object
.vtable
->klass
->byval_arg
);
5558 if (!strcmp (ex_type
, "") || !strcmp (ex_type
, f
))
5565 finish_agent_init (FALSE
);
5568 * Send an unsolicited EXCEPTION event with a dummy request id.
5570 events
= g_slist_append (NULL
, GUINT_TO_POINTER (0xffffff));
5571 ei
.exc
= (MonoObject
*)exc
;
5572 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, SUSPEND_POLICY_ALL
);
5580 ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (throw_ctx
), NULL
);
5582 catch_ji
= mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (catch_ctx
), NULL
);
5586 ei
.exc
= (MonoObject
*)exc
;
5587 ei
.caught
= catch_ctx
!= NULL
;
5589 mono_loader_lock ();
5591 /* Treat exceptions which are caught in non-user code as unhandled */
5592 for (i
= 0; i
< event_requests
->len
; ++i
) {
5593 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
5594 if (req
->event_kind
!= EVENT_KIND_EXCEPTION
)
5597 for (j
= 0; j
< req
->nmodifiers
; ++j
) {
5598 Modifier
*mod
= &req
->modifiers
[j
];
5600 if (mod
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& catch_ji
) {
5602 gboolean found
= FALSE
;
5603 MonoAssembly
**assemblies
= mod
->data
.assemblies
;
5606 for (k
= 0; assemblies
[k
]; ++k
)
5607 if (assemblies
[k
] == jinfo_get_method (catch_ji
)->klass
->image
->assembly
)
5616 events
= create_event_list (EVENT_KIND_EXCEPTION
, NULL
, ji
, &ei
, &suspend_policy
);
5617 mono_loader_unlock ();
5619 if (tls
&& ei
.caught
&& catch_ctx
) {
5620 memset (&tls
->catch_state
, 0, sizeof (tls
->catch_state
));
5621 tls
->catch_state
.ctx
= *catch_ctx
;
5622 tls
->catch_state
.unwind_data
[MONO_UNWIND_DATA_DOMAIN
] = mono_domain_get ();
5623 tls
->catch_state
.valid
= TRUE
;
5626 process_event (EVENT_KIND_EXCEPTION
, &ei
, 0, throw_ctx
, events
, suspend_policy
);
5629 tls
->catch_state
.valid
= FALSE
;
5633 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
5635 DebuggerTlsData
*tls
;
5640 tls
= mono_native_tls_get_value (debugger_tls_id
);
5645 * We're about to invoke an exception filter during the first pass of exception handling.
5647 * 'ctx' is the context that'll get passed to the filter ('call_filter (ctx, ei->data.filter)'),
5648 * 'orig_ctx' is the context where the exception has been thrown.
5651 * See mcs/class/Mono.Debugger.Soft/Tests/dtest-excfilter.il for an example.
5653 * If we're stopped in Filter(), normal stack unwinding would first unwind to
5654 * the call site (line 37) and then continue to Main(), but it would never
5655 * include the throw site (line 32).
5657 * Since exception filters are invoked during the first pass of exception handling,
5658 * the stack frames of the throw site are still intact, so we should include them
5661 * We do this here by saving the context of the throw site in 'tls->filter_state'.
5663 * Exception filters are used by MonoDroid, where we want to stop inside a call filter,
5664 * but report the location of the 'throw' to the user.
5668 g_assert (mono_thread_state_init_from_monoctx (&tls
->filter_state
, orig_ctx
));
5672 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
5674 DebuggerTlsData
*tls
;
5679 tls
= mono_native_tls_get_value (debugger_tls_id
);
5683 tls
->filter_state
.valid
= FALSE
;
5687 * buffer_add_value_full:
5689 * Add the encoding of the value at ADDR described by T to the buffer.
5690 * AS_VTYPE determines whenever to treat primitive types as primitive types or
5694 buffer_add_value_full (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
,
5695 gboolean as_vtype
, GHashTable
*parent_vtypes
)
5698 gboolean boxed_vtype
= FALSE
;
5701 if (!(*(void**)addr
)) {
5702 /* This can happen with compiler generated locals */
5703 //printf ("%s\n", mono_type_full_name (t));
5704 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5707 g_assert (*(void**)addr
);
5708 addr
= *(void**)addr
;
5713 case MONO_TYPE_BOOLEAN
:
5716 case MONO_TYPE_CHAR
:
5736 case MONO_TYPE_VOID
:
5737 buffer_add_byte (buf
, t
->type
);
5739 case MONO_TYPE_BOOLEAN
:
5742 buffer_add_byte (buf
, t
->type
);
5743 buffer_add_int (buf
, *(gint8
*)addr
);
5745 case MONO_TYPE_CHAR
:
5748 buffer_add_byte (buf
, t
->type
);
5749 buffer_add_int (buf
, *(gint16
*)addr
);
5754 buffer_add_byte (buf
, t
->type
);
5755 buffer_add_int (buf
, *(gint32
*)addr
);
5760 buffer_add_byte (buf
, t
->type
);
5761 buffer_add_long (buf
, *(gint64
*)addr
);
5765 /* Treat it as a vtype */
5767 case MONO_TYPE_PTR
: {
5768 gssize val
= *(gssize
*)addr
;
5770 buffer_add_byte (buf
, t
->type
);
5771 buffer_add_long (buf
, val
);
5775 case MONO_TYPE_STRING
:
5776 case MONO_TYPE_SZARRAY
:
5777 case MONO_TYPE_OBJECT
:
5778 case MONO_TYPE_CLASS
:
5779 case MONO_TYPE_ARRAY
:
5780 obj
= *(MonoObject
**)addr
;
5783 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5785 if (obj
->vtable
->klass
->valuetype
) {
5786 t
= &obj
->vtable
->klass
->byval_arg
;
5787 addr
= mono_object_unbox (obj
);
5790 } else if (obj
->vtable
->klass
->rank
) {
5791 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
5792 } else if (obj
->vtable
->klass
->byval_arg
.type
== MONO_TYPE_GENERICINST
) {
5793 buffer_add_byte (buf
, MONO_TYPE_CLASS
);
5795 buffer_add_byte (buf
, obj
->vtable
->klass
->byval_arg
.type
);
5797 buffer_add_objid (buf
, obj
);
5801 case MONO_TYPE_VALUETYPE
: {
5805 MonoClass
*klass
= mono_class_from_mono_type (t
);
5810 * Handle boxed vtypes recursively referencing themselves using fields.
5813 parent_vtypes
= g_hash_table_new (NULL
, NULL
);
5814 vtype_index
= GPOINTER_TO_INT (g_hash_table_lookup (parent_vtypes
, addr
));
5816 if (CHECK_PROTOCOL_VERSION (2, 33)) {
5817 buffer_add_byte (buf
, VALUE_TYPE_ID_PARENT_VTYPE
);
5818 buffer_add_int (buf
, vtype_index
- 1);
5820 /* The client can't handle PARENT_VTYPE */
5821 buffer_add_byte (buf
, VALUE_TYPE_ID_NULL
);
5825 g_hash_table_insert (parent_vtypes
, addr
, GINT_TO_POINTER (g_hash_table_size (parent_vtypes
) + 1));
5829 buffer_add_byte (buf
, MONO_TYPE_VALUETYPE
);
5830 buffer_add_byte (buf
, klass
->enumtype
);
5831 buffer_add_typeid (buf
, domain
, klass
);
5835 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5836 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5838 if (mono_field_is_deleted (f
))
5842 buffer_add_int (buf
, nfields
);
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 buffer_add_value_full (buf
, f
->type
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), domain
, FALSE
, parent_vtypes
);
5854 g_hash_table_remove (parent_vtypes
, addr
);
5855 if (g_hash_table_size (parent_vtypes
) == 0) {
5856 g_hash_table_destroy (parent_vtypes
);
5857 parent_vtypes
= NULL
;
5862 case MONO_TYPE_GENERICINST
:
5863 if (mono_type_generic_inst_is_valuetype (t
)) {
5875 buffer_add_value (Buffer
*buf
, MonoType
*t
, void *addr
, MonoDomain
*domain
)
5877 buffer_add_value_full (buf
, t
, addr
, domain
, FALSE
, NULL
);
5881 obj_is_of_type (MonoObject
*obj
, MonoType
*t
)
5883 MonoClass
*klass
= obj
->vtable
->klass
;
5884 if (!mono_class_is_assignable_from (mono_class_from_mono_type (t
), klass
)) {
5885 if (mono_class_is_transparent_proxy (klass
)) {
5886 klass
= ((MonoTransparentProxy
*)obj
)->remote_class
->proxy_class
;
5887 if (mono_class_is_assignable_from (mono_class_from_mono_type (t
), klass
)) {
5897 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
);
5900 decode_vtype (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
5906 gpointer iter
= NULL
;
5910 is_enum
= decode_byte (buf
, &buf
, limit
);
5911 /* Enums are sent as a normal vtype */
5913 return ERR_NOT_IMPLEMENTED
;
5914 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
5918 if (t
&& klass
!= mono_class_from_mono_type (t
)) {
5919 char *name
= mono_type_full_name (t
);
5920 char *name2
= mono_type_full_name (&klass
->byval_arg
);
5921 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got %s.\n", (gpointer
)GetCurrentThreadId (), name
, name2
));
5924 return ERR_INVALID_ARGUMENT
;
5927 nfields
= decode_int (buf
, &buf
, limit
);
5928 while ((f
= mono_class_get_fields (klass
, &iter
))) {
5929 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
5931 if (mono_field_is_deleted (f
))
5933 err
= decode_value (f
->type
, domain
, (guint8
*)addr
+ f
->offset
- sizeof (MonoObject
), buf
, &buf
, limit
);
5938 g_assert (nfields
== 0);
5946 decode_value_internal (MonoType
*t
, int type
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
5950 if (type
!= t
->type
&& !MONO_TYPE_IS_REFERENCE (t
) &&
5951 !(t
->type
== MONO_TYPE_I
&& type
== MONO_TYPE_VALUETYPE
) &&
5952 !(t
->type
== MONO_TYPE_U
&& type
== MONO_TYPE_VALUETYPE
) &&
5953 !(t
->type
== MONO_TYPE_PTR
&& type
== MONO_TYPE_I8
) &&
5954 !(t
->type
== MONO_TYPE_GENERICINST
&& type
== MONO_TYPE_VALUETYPE
)) {
5955 char *name
= mono_type_full_name (t
);
5956 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
5958 return ERR_INVALID_ARGUMENT
;
5962 case MONO_TYPE_BOOLEAN
:
5963 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
5965 case MONO_TYPE_CHAR
:
5966 *(gunichar2
*)addr
= decode_int (buf
, &buf
, limit
);
5969 *(gint8
*)addr
= decode_int (buf
, &buf
, limit
);
5972 *(guint8
*)addr
= decode_int (buf
, &buf
, limit
);
5975 *(gint16
*)addr
= decode_int (buf
, &buf
, limit
);
5978 *(guint16
*)addr
= decode_int (buf
, &buf
, limit
);
5981 *(gint32
*)addr
= decode_int (buf
, &buf
, limit
);
5984 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
5987 *(gint64
*)addr
= decode_long (buf
, &buf
, limit
);
5990 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
5993 *(guint32
*)addr
= decode_int (buf
, &buf
, limit
);
5996 *(guint64
*)addr
= decode_long (buf
, &buf
, limit
);
5999 /* We send these as I8, so we get them back as such */
6000 g_assert (type
== MONO_TYPE_I8
);
6001 *(gssize
*)addr
= decode_long (buf
, &buf
, limit
);
6003 case MONO_TYPE_GENERICINST
:
6004 if (MONO_TYPE_ISSTRUCT (t
)) {
6005 /* The client sends these as a valuetype */
6013 /* We send these as vtypes, so we get them back as such */
6014 g_assert (type
== MONO_TYPE_VALUETYPE
);
6017 case MONO_TYPE_VALUETYPE
:
6018 err
= decode_vtype (t
, domain
, addr
,buf
, &buf
, limit
);
6024 if (MONO_TYPE_IS_REFERENCE (t
)) {
6025 if (type
== MONO_TYPE_OBJECT
) {
6026 int objid
= decode_objid (buf
, &buf
, limit
);
6030 err
= get_object (objid
, (MonoObject
**)&obj
);
6035 if (!obj_is_of_type (obj
, t
)) {
6036 DEBUG (1, fprintf (log_file
, "Expected type '%s', got '%s'\n", mono_type_full_name (t
), obj
->vtable
->klass
->name
));
6037 return ERR_INVALID_ARGUMENT
;
6040 if (obj
&& obj
->vtable
->domain
!= domain
)
6041 return ERR_INVALID_ARGUMENT
;
6043 mono_gc_wbarrier_generic_store (addr
, obj
);
6044 } else if (type
== VALUE_TYPE_ID_NULL
) {
6045 *(MonoObject
**)addr
= NULL
;
6046 } else if (type
== MONO_TYPE_VALUETYPE
) {
6054 /* This can happen when round-tripping boxed vtypes */
6056 * Obtain vtype class.
6057 * Same as the beginning of the handle_vtype case above.
6060 is_enum
= decode_byte (buf
, &buf
, limit
);
6062 return ERR_NOT_IMPLEMENTED
;
6063 klass
= decode_typeid (buf
, &buf
, limit
, &d
, &err
);
6067 /* Decode the vtype into a temporary buffer, then box it. */
6068 vtype_buf_size
= mono_class_value_size (klass
, NULL
);
6069 vtype_buf
= g_malloc0 (vtype_buf_size
);
6070 g_assert (vtype_buf
);
6073 err
= decode_vtype (NULL
, domain
, vtype_buf
, buf
, &buf
, limit
);
6078 *(MonoObject
**)addr
= mono_value_box (d
, klass
, vtype_buf
);
6081 char *name
= mono_type_full_name (t
);
6082 DEBUG(1, fprintf (log_file
, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer
)GetCurrentThreadId (), name
, type
));
6084 return ERR_INVALID_ARGUMENT
;
6098 decode_value (MonoType
*t
, MonoDomain
*domain
, guint8
*addr
, guint8
*buf
, guint8
**endbuf
, guint8
*limit
)
6101 int type
= decode_byte (buf
, &buf
, limit
);
6103 if (t
->type
== MONO_TYPE_GENERICINST
&& mono_class_is_nullable (mono_class_from_mono_type (t
))) {
6104 MonoType
*targ
= t
->data
.generic_class
->context
.class_inst
->type_argv
[0];
6105 guint8
*nullable_buf
;
6108 * First try decoding it as a Nullable`1
6110 err
= decode_value_internal (t
, type
, domain
, addr
, buf
, endbuf
, limit
);
6115 * Then try decoding as a primitive value or null.
6117 if (targ
->type
== type
) {
6118 nullable_buf
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (targ
)));
6119 err
= decode_value_internal (targ
, type
, domain
, nullable_buf
, buf
, endbuf
, limit
);
6121 g_free (nullable_buf
);
6124 mono_nullable_init (addr
, mono_value_box (domain
, mono_class_from_mono_type (targ
), nullable_buf
), mono_class_from_mono_type (t
));
6125 g_free (nullable_buf
);
6128 } else if (type
== VALUE_TYPE_ID_NULL
) {
6129 mono_nullable_init (addr
, NULL
, mono_class_from_mono_type (t
));
6135 return decode_value_internal (t
, type
, domain
, addr
, buf
, endbuf
, limit
);
6139 add_var (Buffer
*buf
, MonoDebugMethodJitInfo
*jit
, MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, gboolean as_vtype
)
6143 guint8
*addr
, *gaddr
;
6146 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6147 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6150 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
6151 reg_val
= mono_arch_context_get_int_reg (ctx
, reg
);
6153 buffer_add_value_full (buf
, t
, ®_val
, domain
, as_vtype
, NULL
);
6155 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
6156 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6157 addr
+= (gint32
)var
->offset
;
6159 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
6161 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
, NULL
);
6163 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
6166 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR
:
6167 case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR
:
6168 /* Same as regoffset, but with an indirection */
6169 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6170 addr
+= (gint32
)var
->offset
;
6172 gaddr
= *(gpointer
*)addr
;
6174 buffer_add_value_full (buf
, t
, gaddr
, domain
, as_vtype
, NULL
);
6176 case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL
: {
6177 MonoDebugVarInfo
*info_var
= jit
->gsharedvt_info_var
;
6178 MonoDebugVarInfo
*locals_var
= jit
->gsharedvt_locals_var
;
6179 MonoGSharedVtMethodRuntimeInfo
*info
;
6185 g_assert (info_var
);
6186 g_assert (locals_var
);
6188 flags
= info_var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6189 reg
= info_var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6190 if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
) {
6191 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6192 addr
+= (gint32
)info_var
->offset
;
6193 info
= *(gpointer
*)addr
;
6194 } else if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
) {
6195 info
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6197 g_assert_not_reached ();
6201 flags
= locals_var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6202 reg
= locals_var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6203 if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
) {
6204 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6205 addr
+= (gint32
)locals_var
->offset
;
6206 locals
= *(gpointer
*)addr
;
6207 } else if (flags
== MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
) {
6208 locals
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6210 g_assert_not_reached ();
6214 addr
= locals
+ GPOINTER_TO_INT (info
->entries
[idx
]);
6216 buffer_add_value_full (buf
, t
, addr
, domain
, as_vtype
, NULL
);
6221 g_assert_not_reached ();
6226 set_var (MonoType
*t
, MonoDebugVarInfo
*var
, MonoContext
*ctx
, MonoDomain
*domain
, guint8
*val
, mgreg_t
**reg_locations
, MonoContext
*restore_ctx
)
6230 guint8
*addr
, *gaddr
;
6232 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6233 reg
= var
->index
& ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
6235 if (MONO_TYPE_IS_REFERENCE (t
))
6236 size
= sizeof (gpointer
);
6238 size
= mono_class_value_size (mono_class_from_mono_type (t
), NULL
);
6241 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
: {
6242 #ifdef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
6244 gboolean is_signed
= FALSE
;
6247 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6250 // FIXME: Write barriers
6251 mono_gc_memmove_atomic (addr
, val
, size
);
6256 if (!t
->byref
&& (t
->type
== MONO_TYPE_I1
|| t
->type
== MONO_TYPE_I2
|| t
->type
== MONO_TYPE_I4
|| t
->type
== MONO_TYPE_I8
))
6261 v
= is_signed
? *(gint8
*)val
: *(guint8
*)val
;
6264 v
= is_signed
? *(gint16
*)val
: *(guint16
*)val
;
6267 v
= is_signed
? *(gint32
*)val
: *(guint32
*)val
;
6270 v
= is_signed
? *(gint64
*)val
: *(guint64
*)val
;
6273 g_assert_not_reached ();
6276 /* Set value on the stack or in the return ctx */
6277 if (reg_locations
[reg
]) {
6278 /* Saved on the stack */
6279 DEBUG (1, fprintf (log_file
, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations
[reg
], reg
, (gpointer
)v
));
6280 *(reg_locations
[reg
]) = v
;
6283 DEBUG (1, fprintf (log_file
, "[dbg] Setting context location for reg %x to %p.\n", reg
, (gpointer
)v
));
6284 mono_arch_context_set_int_reg (restore_ctx
, reg
, v
);
6287 // FIXME: Move these to mono-context.h/c.
6288 mono_arch_context_set_int_reg (ctx
, reg
, v
);
6290 // FIXME: Can't set registers, so we disable linears
6295 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
6296 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6297 addr
+= (gint32
)var
->offset
;
6299 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
6302 addr
= *(guint8
**)addr
;
6308 // FIXME: Write barriers
6309 mono_gc_memmove_atomic (addr
, val
, size
);
6311 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR
:
6312 /* Same as regoffset, but with an indirection */
6313 addr
= (gpointer
)mono_arch_context_get_int_reg (ctx
, reg
);
6314 addr
+= (gint32
)var
->offset
;
6316 gaddr
= *(gpointer
*)addr
;
6318 // FIXME: Write barriers
6319 mono_gc_memmove_atomic (gaddr
, val
, size
);
6321 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
6325 g_assert_not_reached ();
6330 clear_event_request (int req_id
, int etype
)
6334 mono_loader_lock ();
6335 for (i
= 0; i
< event_requests
->len
; ++i
) {
6336 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
6338 if (req
->id
== req_id
&& req
->event_kind
== etype
) {
6339 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
)
6340 clear_breakpoint (req
->info
);
6341 if (req
->event_kind
== EVENT_KIND_STEP
)
6342 ss_destroy (req
->info
);
6343 if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
)
6344 clear_breakpoint (req
->info
);
6345 if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
)
6346 clear_breakpoint (req
->info
);
6347 g_ptr_array_remove_index_fast (event_requests
, i
);
6352 mono_loader_unlock ();
6356 clear_assembly_from_modifier (EventRequest
*req
, Modifier
*m
, MonoAssembly
*assembly
)
6360 if (m
->kind
== MOD_KIND_EXCEPTION_ONLY
&& m
->data
.exc_class
&& m
->data
.exc_class
->image
->assembly
== assembly
)
6361 m
->kind
= MOD_KIND_NONE
;
6362 if (m
->kind
== MOD_KIND_ASSEMBLY_ONLY
&& m
->data
.assemblies
) {
6363 int count
= 0, match_count
= 0, pos
;
6364 MonoAssembly
**newassemblies
;
6366 for (i
= 0; m
->data
.assemblies
[i
]; ++i
) {
6368 if (m
->data
.assemblies
[i
] == assembly
)
6373 newassemblies
= g_new0 (MonoAssembly
*, count
- match_count
);
6376 for (i
= 0; i
< count
; ++i
)
6377 if (m
->data
.assemblies
[i
] != assembly
)
6378 newassemblies
[pos
++] = m
->data
.assemblies
[i
];
6379 g_assert (pos
== count
- match_count
);
6380 g_free (m
->data
.assemblies
);
6381 m
->data
.assemblies
= newassemblies
;
6387 clear_assembly_from_modifiers (EventRequest
*req
, MonoAssembly
*assembly
)
6391 for (i
= 0; i
< req
->nmodifiers
; ++i
) {
6392 Modifier
*m
= &req
->modifiers
[i
];
6394 clear_assembly_from_modifier (req
, m
, assembly
);
6399 * clear_event_requests_for_assembly:
6401 * Clear all events requests which reference ASSEMBLY.
6404 clear_event_requests_for_assembly (MonoAssembly
*assembly
)
6409 mono_loader_lock ();
6413 for (i
= 0; i
< event_requests
->len
; ++i
) {
6414 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
6416 clear_assembly_from_modifiers (req
, assembly
);
6418 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
&& breakpoint_matches_assembly (req
->info
, assembly
)) {
6419 clear_event_request (req
->id
, req
->event_kind
);
6424 if (req
->event_kind
== EVENT_KIND_STEP
)
6425 ss_clear_for_assembly (req
->info
, assembly
);
6428 mono_loader_unlock ();
6432 * type_comes_from_assembly:
6434 * GHRFunc that returns TRUE if klass comes from assembly
6437 type_comes_from_assembly (gpointer klass
, gpointer also_klass
, gpointer assembly
)
6439 return (mono_class_get_image ((MonoClass
*)klass
) == mono_assembly_get_image ((MonoAssembly
*)assembly
));
6443 * clear_types_for_assembly:
6445 * Clears types from loaded_classes for a given assembly
6448 clear_types_for_assembly (MonoAssembly
*assembly
)
6450 MonoDomain
*domain
= mono_domain_get ();
6451 AgentDomainInfo
*info
= NULL
;
6453 mono_loader_lock ();
6454 info
= get_agent_domain_info (domain
);
6455 g_hash_table_foreach_remove (info
->loaded_classes
, type_comes_from_assembly
, assembly
);
6456 mono_loader_unlock ();
6460 add_thread (gpointer key
, gpointer value
, gpointer user_data
)
6462 MonoInternalThread
*thread
= value
;
6463 Buffer
*buf
= user_data
;
6465 buffer_add_objid (buf
, (MonoObject
*)thread
);
6469 do_invoke_method (DebuggerTlsData
*tls
, Buffer
*buf
, InvokeData
*invoke
, guint8
*p
, guint8
**endp
)
6471 guint8
*end
= invoke
->endp
;
6474 MonoMethodSignature
*sig
;
6477 MonoObject
*this, *res
, *exc
;
6480 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6483 MonoStopwatch watch
;
6485 if (invoke
->method
) {
6487 * Invoke this method directly, currently only Environment.Exit () is supported.
6490 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>"));
6491 mono_runtime_invoke (invoke
->method
, NULL
, invoke
->args
, &exc
);
6492 g_assert_not_reached ();
6495 m
= decode_methodid (p
, &p
, end
, &domain
, &err
);
6498 sig
= mono_method_signature (m
);
6500 if (m
->klass
->valuetype
)
6501 this_buf
= g_alloca (mono_class_instance_size (m
->klass
));
6503 this_buf
= g_alloca (sizeof (MonoObject
*));
6504 if (m
->klass
->valuetype
&& (m
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
6505 /* Should be null */
6506 int type
= decode_byte (p
, &p
, end
);
6507 if (type
!= VALUE_TYPE_ID_NULL
) {
6508 DEBUG (1, fprintf (log_file
, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer
)GetCurrentThreadId ()));
6509 return ERR_INVALID_ARGUMENT
;
6511 memset (this_buf
, 0, mono_class_instance_size (m
->klass
));
6513 err
= decode_value (&m
->klass
->byval_arg
, domain
, this_buf
, p
, &p
, end
);
6518 if (!m
->klass
->valuetype
)
6519 this = *(MonoObject
**)this_buf
;
6523 if (MONO_CLASS_IS_INTERFACE (m
->klass
)) {
6525 DEBUG (1, fprintf (log_file
, "[%p] Error: Interface method invoked without this argument.\n", (gpointer
)GetCurrentThreadId ()));
6526 return ERR_INVALID_ARGUMENT
;
6528 m
= mono_object_get_virtual_method (this, m
);
6531 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>"));
6533 if (this && this->vtable
->domain
!= domain
)
6536 if (!m
->klass
->valuetype
&& !(m
->flags
& METHOD_ATTRIBUTE_STATIC
) && !this) {
6537 if (!strcmp (m
->name
, ".ctor")) {
6538 if (m
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
)
6539 return ERR_INVALID_ARGUMENT
;
6541 this = mono_object_new (domain
, m
->klass
);
6543 return ERR_INVALID_ARGUMENT
;
6547 if (this && !obj_is_of_type (this, &m
->klass
->byval_arg
))
6548 return ERR_INVALID_ARGUMENT
;
6550 nargs
= decode_int (p
, &p
, end
);
6551 if (nargs
!= sig
->param_count
)
6552 return ERR_INVALID_ARGUMENT
;
6553 /* Use alloca to get gc tracking */
6554 arg_buf
= g_alloca (nargs
* sizeof (gpointer
));
6555 memset (arg_buf
, 0, nargs
* sizeof (gpointer
));
6556 args
= g_alloca (nargs
* sizeof (gpointer
));
6557 for (i
= 0; i
< nargs
; ++i
) {
6558 if (MONO_TYPE_IS_REFERENCE (sig
->params
[i
])) {
6559 err
= decode_value (sig
->params
[i
], domain
, (guint8
*)&args
[i
], p
, &p
, end
);
6563 if (args
[i
] && ((MonoObject
*)args
[i
])->vtable
->domain
!= domain
)
6566 arg_buf
[i
] = g_alloca (mono_class_instance_size (mono_class_from_mono_type (sig
->params
[i
])));
6567 err
= decode_value (sig
->params
[i
], domain
, arg_buf
[i
], p
, &p
, end
);
6570 args
[i
] = arg_buf
[i
];
6577 if (invoke
->flags
& INVOKE_FLAG_DISABLE_BREAKPOINTS
)
6578 tls
->disable_breakpoints
= TRUE
;
6580 tls
->disable_breakpoints
= FALSE
;
6583 * Add an LMF frame to link the stack frames on the invoke method with our caller.
6585 /* FIXME: Move this to arch specific code */
6586 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6587 if (invoke
->has_ctx
) {
6590 lmf_addr
= mono_get_lmf_addr ();
6593 memset (&ext
, 0, sizeof (ext
));
6594 mono_arch_init_lmf_ext (&ext
, *lmf_addr
);
6596 ext
.debugger_invoke
= TRUE
;
6597 memcpy (&ext
.ctx
, &invoke
->ctx
, sizeof (MonoContext
));
6599 mono_set_lmf ((MonoLMF
*)&ext
);
6603 mono_stopwatch_start (&watch
);
6604 if (m
->klass
->valuetype
)
6605 res
= mono_runtime_invoke (m
, this_buf
, args
, &exc
);
6607 res
= mono_runtime_invoke (m
, this, args
, &exc
);
6608 mono_stopwatch_stop (&watch
);
6609 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
)));
6611 buffer_add_byte (buf
, 0);
6612 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &exc
, domain
);
6614 buffer_add_byte (buf
, 1);
6615 if (sig
->ret
->type
== MONO_TYPE_VOID
) {
6616 if (!strcmp (m
->name
, ".ctor") && !m
->klass
->valuetype
) {
6617 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &this, domain
);
6620 buffer_add_value (buf
, &mono_defaults
.void_class
->byval_arg
, NULL
, domain
);
6621 } else if (MONO_TYPE_IS_REFERENCE (sig
->ret
)) {
6622 buffer_add_value (buf
, sig
->ret
, &res
, domain
);
6623 } else if (mono_class_from_mono_type (sig
->ret
)->valuetype
|| sig
->ret
->type
== MONO_TYPE_PTR
|| sig
->ret
->type
== MONO_TYPE_FNPTR
) {
6624 if (mono_class_is_nullable (mono_class_from_mono_type (sig
->ret
))) {
6625 MonoClass
*k
= mono_class_from_mono_type (sig
->ret
);
6626 guint8
*nullable_buf
= g_alloca (mono_class_value_size (k
, NULL
));
6628 g_assert (nullable_buf
);
6629 mono_nullable_init (nullable_buf
, res
, k
);
6630 buffer_add_value (buf
, sig
->ret
, nullable_buf
, domain
);
6633 buffer_add_value (buf
, sig
->ret
, mono_object_unbox (res
), domain
);
6640 tls
->disable_breakpoints
= FALSE
;
6642 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6643 if (invoke
->has_ctx
)
6644 mono_set_lmf ((gpointer
)(((gssize
)ext
.lmf
.previous_lmf
) & ~3));
6648 // FIXME: byref arguments
6656 * Invoke the method given by tls->pending_invoke in the current thread.
6659 invoke_method (void)
6661 DebuggerTlsData
*tls
;
6666 MonoContext restore_ctx
;
6669 tls
= mono_native_tls_get_value (debugger_tls_id
);
6673 * Store the `InvokeData *' in `tls->invoke' until we're done with
6674 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
6677 mono_loader_lock ();
6679 invoke
= tls
->pending_invoke
;
6681 tls
->pending_invoke
= NULL
;
6683 invoke
->last_invoke
= tls
->invoke
;
6684 tls
->invoke
= invoke
;
6686 mono_loader_unlock ();
6688 tls
->frames_up_to_date
= FALSE
;
6694 for (mindex
= 0; mindex
< invoke
->nmethods
; ++mindex
) {
6695 buffer_init (&buf
, 128);
6698 /* Fail the other invokes as well */
6700 err
= do_invoke_method (tls
, &buf
, invoke
, p
, &p
);
6703 /* Start suspending before sending the reply */
6704 if (mindex
== invoke
->nmethods
- 1) {
6705 if (!(invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
)) {
6706 for (i
= 0; i
< invoke
->suspend_count
; ++i
)
6711 send_reply_packet (id
, err
, &buf
);
6716 memcpy (&restore_ctx
, &invoke
->ctx
, sizeof (MonoContext
));
6718 if (invoke
->has_ctx
)
6719 save_thread_context (&restore_ctx
);
6721 if (invoke
->flags
& INVOKE_FLAG_SINGLE_THREADED
) {
6722 g_assert (tls
->resume_count
);
6723 tls
->resume_count
-= invoke
->suspend_count
;
6726 DEBUG (1, fprintf (log_file
, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer
)GetCurrentThreadId (), err
, tls
->resume_count
));
6729 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
6731 * It is possible that ves_icall_System_Threading_Thread_Abort () was called
6732 * after the mono_runtime_invoke() already returned, but it doesn't matter
6733 * because we reset the abort here.
6736 mono_loader_lock ();
6738 if (tls
->abort_requested
)
6739 mono_thread_internal_reset_abort (tls
->thread
);
6741 tls
->invoke
= tls
->invoke
->last_invoke
;
6742 tls
->abort_requested
= FALSE
;
6744 mono_loader_unlock ();
6753 is_really_suspended (gpointer key
, gpointer value
, gpointer user_data
)
6755 MonoThread
*thread
= value
;
6756 DebuggerTlsData
*tls
;
6759 mono_loader_lock ();
6760 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6762 res
= tls
->really_suspended
;
6763 mono_loader_unlock ();
6769 get_source_files_for_type (MonoClass
*klass
)
6771 gpointer iter
= NULL
;
6773 MonoDebugSourceInfo
*sinfo
;
6777 files
= g_ptr_array_new ();
6779 while ((method
= mono_class_get_methods (klass
, &iter
))) {
6780 MonoDebugMethodInfo
*minfo
= mono_debug_lookup_method (method
);
6781 GPtrArray
*source_file_list
;
6784 mono_debug_symfile_get_line_numbers_full (minfo
, NULL
, &source_file_list
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
6785 for (j
= 0; j
< source_file_list
->len
; ++j
) {
6786 sinfo
= g_ptr_array_index (source_file_list
, j
);
6787 for (i
= 0; i
< files
->len
; ++i
)
6788 if (!strcmp (g_ptr_array_index (files
, i
), sinfo
->source_file
))
6790 if (i
== files
->len
)
6791 g_ptr_array_add (files
, g_strdup (sinfo
->source_file
));
6793 g_ptr_array_free (source_file_list
, TRUE
);
6801 vm_commands (int command
, int id
, guint8
*p
, guint8
*end
, Buffer
*buf
)
6804 case CMD_VM_VERSION
: {
6805 char *build_info
, *version
;
6807 build_info
= mono_get_runtime_build_info ();
6808 version
= g_strdup_printf ("mono %s", build_info
);
6810 buffer_add_string (buf
, version
); /* vm version */
6811 buffer_add_int (buf
, MAJOR_VERSION
);
6812 buffer_add_int (buf
, MINOR_VERSION
);
6813 g_free (build_info
);
6817 case CMD_VM_SET_PROTOCOL_VERSION
: {
6818 major_version
= decode_int (p
, &p
, end
);
6819 minor_version
= decode_int (p
, &p
, end
);
6820 protocol_version_set
= TRUE
;
6821 DEBUG(1, fprintf (log_file
, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION
, MINOR_VERSION
, major_version
, minor_version
));
6824 case CMD_VM_ALL_THREADS
: {
6826 mono_loader_lock ();
6827 buffer_add_int (buf
, mono_g_hash_table_size (tid_to_thread_obj
));
6828 mono_g_hash_table_foreach (tid_to_thread_obj
, add_thread
, buf
);
6829 mono_loader_unlock ();
6832 case CMD_VM_SUSPEND
:
6834 wait_for_suspend ();
6837 if (suspend_count
== 0)
6838 return ERR_NOT_SUSPENDED
;
6840 clear_suspended_objs ();
6842 case CMD_VM_DISPOSE
:
6843 /* Clear all event requests */
6844 mono_loader_lock ();
6845 while (event_requests
->len
> 0) {
6846 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
6848 clear_event_request (req
->id
, req
->event_kind
);
6850 mono_loader_unlock ();
6852 while (suspend_count
> 0)
6854 disconnected
= TRUE
;
6855 vm_start_event_sent
= FALSE
;
6858 MonoInternalThread
*thread
;
6859 DebuggerTlsData
*tls
;
6860 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6861 MonoClass
*env_class
;
6863 MonoMethod
*exit_method
= NULL
;
6867 exit_code
= decode_int (p
, &p
, end
);
6869 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
6871 /* Have to send a reply before exiting */
6872 send_reply_packet (id
, 0, buf
);
6874 /* Clear all event requests */
6875 mono_loader_lock ();
6876 while (event_requests
->len
> 0) {
6877 EventRequest
*req
= g_ptr_array_index (event_requests
, 0);
6879 clear_event_request (req
->id
, req
->event_kind
);
6881 mono_loader_unlock ();
6884 * The JDWP documentation says that the shutdown is not orderly. It doesn't
6885 * specify whenever a VM_DEATH event is sent. We currently do an orderly
6886 * shutdown by hijacking a thread to execute Environment.Exit (). This is
6887 * better than doing the shutdown ourselves, since it avoids various races.
6891 wait_for_suspend ();
6893 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6894 env_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
6896 exit_method
= mono_class_get_method_from_name (env_class
, "Exit", 1);
6899 mono_loader_lock ();
6900 thread
= mono_g_hash_table_find (tid_to_thread
, is_really_suspended
, NULL
);
6901 mono_loader_unlock ();
6903 if (thread
&& exit_method
) {
6904 mono_loader_lock ();
6905 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
6906 mono_loader_unlock ();
6908 args
= g_new0 (gpointer
, 1);
6909 args
[0] = g_malloc (sizeof (int));
6910 *(int*)(args
[0]) = exit_code
;
6912 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
6913 tls
->pending_invoke
->method
= exit_method
;
6914 tls
->pending_invoke
->args
= args
;
6915 tls
->pending_invoke
->nmethods
= 1;
6917 while (suspend_count
> 0)
6921 * No thread found, do it ourselves.
6922 * FIXME: This can race with normal shutdown etc.
6924 while (suspend_count
> 0)
6927 if (!mono_runtime_try_shutdown ())
6930 mono_environment_exitcode_set (exit_code
);
6932 /* Suspend all managed threads since the runtime is going away */
6933 DEBUG(1, fprintf (log_file
, "Suspending all threads...\n"));
6934 mono_thread_suspend_all_other_threads ();
6935 DEBUG(1, fprintf (log_file
, "Shutting down the runtime...\n"));
6936 mono_runtime_quit ();
6937 transport_close2 ();
6938 DEBUG(1, fprintf (log_file
, "Exiting...\n"));
6944 case CMD_VM_INVOKE_METHOD
:
6945 case CMD_VM_INVOKE_METHODS
: {
6946 int objid
= decode_objid (p
, &p
, end
);
6948 DebuggerTlsData
*tls
;
6949 int i
, count
, err
, flags
, nmethods
;
6951 err
= get_object (objid
, (MonoObject
**)&thread
);
6955 flags
= decode_int (p
, &p
, end
);
6957 if (command
== CMD_VM_INVOKE_METHODS
)
6958 nmethods
= decode_int (p
, &p
, end
);
6962 // Wait for suspending if it already started
6964 wait_for_suspend ();
6965 if (!is_suspended ())
6966 return ERR_NOT_SUSPENDED
;
6968 mono_loader_lock ();
6969 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
6970 mono_loader_unlock ();
6973 if (!tls
->really_suspended
)
6974 /* The thread is still running native code, can't do invokes */
6975 return ERR_NOT_SUSPENDED
;
6978 * Store the invoke data into tls, the thread will execute it after it is
6981 if (tls
->pending_invoke
)
6982 return ERR_NOT_SUSPENDED
;
6983 tls
->pending_invoke
= g_new0 (InvokeData
, 1);
6984 tls
->pending_invoke
->id
= id
;
6985 tls
->pending_invoke
->flags
= flags
;
6986 tls
->pending_invoke
->p
= g_malloc (end
- p
);
6987 memcpy (tls
->pending_invoke
->p
, p
, end
- p
);
6988 tls
->pending_invoke
->endp
= tls
->pending_invoke
->p
+ (end
- p
);
6989 tls
->pending_invoke
->suspend_count
= suspend_count
;
6990 tls
->pending_invoke
->nmethods
= nmethods
;
6992 if (flags
& INVOKE_FLAG_SINGLE_THREADED
) {
6993 resume_thread (THREAD_TO_INTERNAL (thread
));
6996 count
= suspend_count
;
6997 for (i
= 0; i
< count
; ++i
)
7002 case CMD_VM_ABORT_INVOKE
: {
7003 int objid
= decode_objid (p
, &p
, end
);
7005 DebuggerTlsData
*tls
;
7008 err
= get_object (objid
, (MonoObject
**)&thread
);
7012 invoke_id
= decode_int (p
, &p
, end
);
7014 mono_loader_lock ();
7015 tls
= mono_g_hash_table_lookup (thread_to_tls
, THREAD_TO_INTERNAL (thread
));
7018 if (tls
->abort_requested
) {
7019 mono_loader_unlock ();
7024 * Check whether we're still inside the mono_runtime_invoke() and that it's
7025 * actually the correct invocation.
7027 * Careful, we do not stop the thread that's doing the invocation, so we can't
7028 * inspect its stack. However, invoke_method() also acquires the loader lock
7029 * when it's done, so we're safe here.
7033 if (!tls
->invoke
|| (tls
->invoke
->id
!= invoke_id
)) {
7034 mono_loader_unlock ();
7035 return ERR_NO_INVOCATION
;
7038 tls
->abort_requested
= TRUE
;
7040 ves_icall_System_Threading_Thread_Abort (THREAD_TO_INTERNAL (thread
), NULL
);
7041 mono_loader_unlock ();
7045 case CMD_VM_SET_KEEPALIVE
: {
7046 int timeout
= decode_int (p
, &p
, end
);
7047 agent_config
.keepalive
= timeout
;
7049 #ifndef DISABLE_SOCKET_TRANSPORT
7056 case CMD_VM_GET_TYPES_FOR_SOURCE_FILE
: {
7057 GHashTableIter iter
, kiter
;
7062 char *fname
, *basename
;
7063 gboolean ignore_case
;
7064 GSList
*class_list
, *l
;
7065 GPtrArray
*res_classes
, *res_domains
;
7067 fname
= decode_string (p
, &p
, end
);
7068 ignore_case
= decode_byte (p
, &p
, end
);
7070 basename
= g_path_get_basename (fname
);
7072 res_classes
= g_ptr_array_new ();
7073 res_domains
= g_ptr_array_new ();
7075 mono_loader_lock ();
7076 g_hash_table_iter_init (&iter
, domains
);
7077 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&domain
)) {
7078 AgentDomainInfo
*info
= domain_jit_info (domain
)->agent_info
;
7080 /* Update 'source_file_to_class' cache */
7081 g_hash_table_iter_init (&kiter
, info
->loaded_classes
);
7082 while (g_hash_table_iter_next (&kiter
, NULL
, (void**)&klass
)) {
7083 if (!g_hash_table_lookup (info
->source_files
, klass
)) {
7084 files
= get_source_files_for_type (klass
);
7085 g_hash_table_insert (info
->source_files
, klass
, files
);
7087 for (i
= 0; i
< files
->len
; ++i
) {
7088 char *s
= g_ptr_array_index (files
, i
);
7089 char *s2
= g_path_get_basename (s
);
7092 class_list
= g_hash_table_lookup (info
->source_file_to_class
, s2
);
7094 class_list
= g_slist_prepend (class_list
, klass
);
7095 g_hash_table_insert (info
->source_file_to_class
, g_strdup (s2
), class_list
);
7097 class_list
= g_slist_prepend (class_list
, klass
);
7098 g_hash_table_insert (info
->source_file_to_class
, s2
, class_list
);
7101 /* The _ignorecase hash contains the lowercase path */
7102 s3
= strdup_tolower (s2
);
7103 class_list
= g_hash_table_lookup (info
->source_file_to_class_ignorecase
, s3
);
7105 class_list
= g_slist_prepend (class_list
, klass
);
7106 g_hash_table_insert (info
->source_file_to_class_ignorecase
, g_strdup (s3
), class_list
);
7108 class_list
= g_slist_prepend (class_list
, klass
);
7109 g_hash_table_insert (info
->source_file_to_class_ignorecase
, s3
, class_list
);
7121 s
= strdup_tolower (basename
);
7122 class_list
= g_hash_table_lookup (info
->source_file_to_class_ignorecase
, s
);
7125 class_list
= g_hash_table_lookup (info
->source_file_to_class
, basename
);
7128 for (l
= class_list
; l
; l
= l
->next
) {
7131 g_ptr_array_add (res_classes
, klass
);
7132 g_ptr_array_add (res_domains
, domain
);
7135 mono_loader_unlock ();
7140 buffer_add_int (buf
, res_classes
->len
);
7141 for (i
= 0; i
< res_classes
->len
; ++i
)
7142 buffer_add_typeid (buf
, g_ptr_array_index (res_domains
, i
), g_ptr_array_index (res_classes
, i
));
7143 g_ptr_array_free (res_classes
, TRUE
);
7144 g_ptr_array_free (res_domains
, TRUE
);
7147 case CMD_VM_GET_TYPES
: {
7148 GHashTableIter iter
;
7152 gboolean ignore_case
;
7153 GPtrArray
*res_classes
, *res_domains
;
7154 MonoTypeNameParse info
;
7156 name
= decode_string (p
, &p
, end
);
7157 ignore_case
= decode_byte (p
, &p
, end
);
7159 if (!mono_reflection_parse_type (name
, &info
)) {
7161 mono_reflection_free_type_info (&info
);
7162 return ERR_INVALID_ARGUMENT
;
7165 res_classes
= g_ptr_array_new ();
7166 res_domains
= g_ptr_array_new ();
7168 mono_loader_lock ();
7169 g_hash_table_iter_init (&iter
, domains
);
7170 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&domain
)) {
7172 gboolean type_resolve
;
7176 mono_domain_assemblies_lock (domain
);
7177 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7181 type_resolve
= TRUE
;
7182 t
= mono_reflection_get_type (ass
->image
, &info
, ignore_case
, &type_resolve
);
7184 g_ptr_array_add (res_classes
, mono_type_get_class (t
));
7185 g_ptr_array_add (res_domains
, domain
);
7189 mono_domain_assemblies_unlock (domain
);
7191 mono_loader_unlock ();
7194 mono_reflection_free_type_info (&info
);
7196 buffer_add_int (buf
, res_classes
->len
);
7197 for (i
= 0; i
< res_classes
->len
; ++i
)
7198 buffer_add_typeid (buf
, g_ptr_array_index (res_domains
, i
), g_ptr_array_index (res_classes
, i
));
7199 g_ptr_array_free (res_classes
, TRUE
);
7200 g_ptr_array_free (res_domains
, TRUE
);
7203 case CMD_VM_START_BUFFERING
:
7204 case CMD_VM_STOP_BUFFERING
:
7205 /* Handled in the main loop */
7208 return ERR_NOT_IMPLEMENTED
;
7215 event_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7221 case CMD_EVENT_REQUEST_SET
: {
7223 int i
, event_kind
, suspend_policy
, nmodifiers
, mod
;
7226 MonoThread
*step_thread
;
7227 int size
= 0, depth
= 0, filter
= 0, step_thread_id
= 0;
7231 event_kind
= decode_byte (p
, &p
, end
);
7232 suspend_policy
= decode_byte (p
, &p
, end
);
7233 nmodifiers
= decode_byte (p
, &p
, end
);
7235 req
= g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
7236 req
->id
= InterlockedIncrement (&event_request_id
);
7237 req
->event_kind
= event_kind
;
7238 req
->suspend_policy
= suspend_policy
;
7239 req
->nmodifiers
= nmodifiers
;
7242 for (i
= 0; i
< nmodifiers
; ++i
) {
7243 mod
= decode_byte (p
, &p
, end
);
7245 req
->modifiers
[i
].kind
= mod
;
7246 if (mod
== MOD_KIND_COUNT
) {
7247 req
->modifiers
[i
].data
.count
= decode_int (p
, &p
, end
);
7248 } else if (mod
== MOD_KIND_LOCATION_ONLY
) {
7249 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
7252 location
= decode_long (p
, &p
, end
);
7253 } else if (mod
== MOD_KIND_STEP
) {
7254 step_thread_id
= decode_id (p
, &p
, end
);
7255 size
= decode_int (p
, &p
, end
);
7256 depth
= decode_int (p
, &p
, end
);
7257 if (CHECK_PROTOCOL_VERSION (2, 16))
7258 filter
= decode_int (p
, &p
, end
);
7259 req
->modifiers
[i
].data
.filter
= filter
;
7260 if (!CHECK_PROTOCOL_VERSION (2, 26) && (req
->modifiers
[i
].data
.filter
& STEP_FILTER_DEBUGGER_HIDDEN
))
7261 /* Treat STEP_THOUGH the same as HIDDEN */
7262 req
->modifiers
[i
].data
.filter
|= STEP_FILTER_DEBUGGER_STEP_THROUGH
;
7263 } else if (mod
== MOD_KIND_THREAD_ONLY
) {
7264 int id
= decode_id (p
, &p
, end
);
7266 err
= get_object (id
, (MonoObject
**)&req
->modifiers
[i
].data
.thread
);
7271 } else if (mod
== MOD_KIND_EXCEPTION_ONLY
) {
7272 MonoClass
*exc_class
= decode_typeid (p
, &p
, end
, &domain
, &err
);
7276 req
->modifiers
[i
].caught
= decode_byte (p
, &p
, end
);
7277 req
->modifiers
[i
].uncaught
= decode_byte (p
, &p
, end
);
7278 if (CHECK_PROTOCOL_VERSION (2, 25))
7279 req
->modifiers
[i
].subclasses
= decode_byte (p
, &p
, end
);
7281 req
->modifiers
[i
].subclasses
= TRUE
;
7282 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" : ""));
7284 req
->modifiers
[i
].data
.exc_class
= exc_class
;
7286 if (!mono_class_is_assignable_from (mono_defaults
.exception_class
, exc_class
)) {
7288 return ERR_INVALID_ARGUMENT
;
7291 } else if (mod
== MOD_KIND_ASSEMBLY_ONLY
) {
7292 int n
= decode_int (p
, &p
, end
);
7295 req
->modifiers
[i
].data
.assemblies
= g_new0 (MonoAssembly
*, n
);
7296 for (j
= 0; j
< n
; ++j
) {
7297 req
->modifiers
[i
].data
.assemblies
[j
] = decode_assemblyid (p
, &p
, end
, &domain
, &err
);
7299 g_free (req
->modifiers
[i
].data
.assemblies
);
7303 } else if (mod
== MOD_KIND_SOURCE_FILE_ONLY
) {
7304 int n
= decode_int (p
, &p
, end
);
7307 modifier
= &req
->modifiers
[i
];
7308 modifier
->data
.source_files
= g_hash_table_new (g_str_hash
, g_str_equal
);
7309 for (j
= 0; j
< n
; ++j
) {
7310 char *s
= decode_string (p
, &p
, end
);
7314 s2
= strdup_tolower (s
);
7315 g_hash_table_insert (modifier
->data
.source_files
, s2
, s2
);
7319 } else if (mod
== MOD_KIND_TYPE_NAME_ONLY
) {
7320 int n
= decode_int (p
, &p
, end
);
7323 modifier
= &req
->modifiers
[i
];
7324 modifier
->data
.type_names
= g_hash_table_new (g_str_hash
, g_str_equal
);
7325 for (j
= 0; j
< n
; ++j
) {
7326 char *s
= decode_string (p
, &p
, end
);
7329 g_hash_table_insert (modifier
->data
.type_names
, s
, s
);
7333 return ERR_NOT_IMPLEMENTED
;
7337 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
7340 req
->info
= set_breakpoint (method
, location
, req
, &error
);
7341 if (!mono_error_ok (&error
)) {
7343 DEBUG(1, fprintf (log_file
, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (&error
)));
7344 mono_error_cleanup (&error
);
7345 return ERR_NO_SEQ_POINT_AT_IL_OFFSET
;
7347 } else if (req
->event_kind
== EVENT_KIND_STEP
) {
7348 g_assert (step_thread_id
);
7350 err
= get_object (step_thread_id
, (MonoObject
**)&step_thread
);
7356 err
= ss_create (THREAD_TO_INTERNAL (step_thread
), size
, depth
, req
);
7361 } else if (req
->event_kind
== EVENT_KIND_METHOD_ENTRY
) {
7362 req
->info
= set_breakpoint (NULL
, METHOD_ENTRY_IL_OFFSET
, req
, NULL
);
7363 } else if (req
->event_kind
== EVENT_KIND_METHOD_EXIT
) {
7364 req
->info
= set_breakpoint (NULL
, METHOD_EXIT_IL_OFFSET
, req
, NULL
);
7365 } else if (req
->event_kind
== EVENT_KIND_EXCEPTION
) {
7366 } else if (req
->event_kind
== EVENT_KIND_TYPE_LOAD
) {
7368 if (req
->nmodifiers
) {
7370 return ERR_NOT_IMPLEMENTED
;
7374 mono_loader_lock ();
7375 g_ptr_array_add (event_requests
, req
);
7377 if (agent_config
.defer
) {
7378 /* Transmit cached data to the client on receipt of the event request */
7379 switch (req
->event_kind
) {
7380 case EVENT_KIND_APPDOMAIN_CREATE
:
7381 /* Emit load events for currently loaded domains */
7382 g_hash_table_foreach (domains
, emit_appdomain_load
, NULL
);
7384 case EVENT_KIND_ASSEMBLY_LOAD
:
7385 /* Emit load events for currently loaded assemblies */
7386 mono_assembly_foreach (emit_assembly_load
, NULL
);
7388 case EVENT_KIND_THREAD_START
:
7389 /* Emit start events for currently started threads */
7390 mono_g_hash_table_foreach (tid_to_thread
, emit_thread_start
, NULL
);
7392 case EVENT_KIND_TYPE_LOAD
:
7393 /* Emit type load events for currently loaded types */
7394 mono_domain_foreach (send_types_for_domain
, NULL
);
7400 mono_loader_unlock ();
7402 buffer_add_int (buf
, req
->id
);
7405 case CMD_EVENT_REQUEST_CLEAR
: {
7406 int etype
= decode_byte (p
, &p
, end
);
7407 int req_id
= decode_int (p
, &p
, end
);
7409 // FIXME: Make a faster mapping from req_id to request
7410 mono_loader_lock ();
7411 clear_event_request (req_id
, etype
);
7412 mono_loader_unlock ();
7415 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS
: {
7418 mono_loader_lock ();
7420 while (i
< event_requests
->len
) {
7421 EventRequest
*req
= g_ptr_array_index (event_requests
, i
);
7423 if (req
->event_kind
== EVENT_KIND_BREAKPOINT
) {
7424 clear_breakpoint (req
->info
);
7426 g_ptr_array_remove_index_fast (event_requests
, i
);
7432 mono_loader_unlock ();
7436 return ERR_NOT_IMPLEMENTED
;
7443 domain_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7449 case CMD_APPDOMAIN_GET_ROOT_DOMAIN
: {
7450 buffer_add_domainid (buf
, mono_get_root_domain ());
7453 case CMD_APPDOMAIN_GET_FRIENDLY_NAME
: {
7454 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7457 buffer_add_string (buf
, domain
->friendly_name
);
7460 case CMD_APPDOMAIN_GET_ASSEMBLIES
: {
7465 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7468 mono_loader_lock ();
7470 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7473 buffer_add_int (buf
, count
);
7474 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
7476 buffer_add_assemblyid (buf
, domain
, ass
);
7478 mono_loader_unlock ();
7481 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY
: {
7482 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7486 buffer_add_assemblyid (buf
, domain
, domain
->entry_assembly
);
7489 case CMD_APPDOMAIN_GET_CORLIB
: {
7490 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7494 buffer_add_assemblyid (buf
, domain
, domain
->domain
->mbr
.obj
.vtable
->klass
->image
->assembly
);
7497 case CMD_APPDOMAIN_CREATE_STRING
: {
7501 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7504 s
= decode_string (p
, &p
, end
);
7506 o
= mono_string_new (domain
, s
);
7507 buffer_add_objid (buf
, (MonoObject
*)o
);
7510 case CMD_APPDOMAIN_CREATE_BOXED_VALUE
: {
7512 MonoDomain
*domain2
;
7515 domain
= decode_domainid (p
, &p
, end
, NULL
, &err
);
7518 klass
= decode_typeid (p
, &p
, end
, &domain2
, &err
);
7523 g_assert (domain
== domain2
);
7525 o
= mono_object_new (domain
, klass
);
7527 err
= decode_value (&klass
->byval_arg
, domain
, mono_object_unbox (o
), p
, &p
, end
);
7531 buffer_add_objid (buf
, o
);
7535 return ERR_NOT_IMPLEMENTED
;
7542 assembly_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7548 ass
= decode_assemblyid (p
, &p
, end
, &domain
, &err
);
7553 case CMD_ASSEMBLY_GET_LOCATION
: {
7554 buffer_add_string (buf
, mono_image_get_filename (ass
->image
));
7557 case CMD_ASSEMBLY_GET_ENTRY_POINT
: {
7561 if (ass
->image
->dynamic
) {
7562 buffer_add_id (buf
, 0);
7564 token
= mono_image_get_entry_point (ass
->image
);
7566 buffer_add_id (buf
, 0);
7568 m
= mono_get_method (ass
->image
, token
, NULL
);
7569 buffer_add_methodid (buf
, domain
, m
);
7574 case CMD_ASSEMBLY_GET_MANIFEST_MODULE
: {
7575 buffer_add_moduleid (buf
, domain
, ass
->image
);
7578 case CMD_ASSEMBLY_GET_OBJECT
: {
7579 MonoObject
*o
= (MonoObject
*)mono_assembly_get_object (domain
, ass
);
7580 buffer_add_objid (buf
, o
);
7583 case CMD_ASSEMBLY_GET_TYPE
: {
7584 char *s
= decode_string (p
, &p
, end
);
7585 gboolean ignorecase
= decode_byte (p
, &p
, end
);
7586 MonoTypeNameParse info
;
7588 gboolean type_resolve
, res
;
7589 MonoDomain
*d
= mono_domain_get ();
7591 /* This is needed to be able to find referenced assemblies */
7592 res
= mono_domain_set (domain
, FALSE
);
7595 if (!mono_reflection_parse_type (s
, &info
)) {
7598 if (info
.assembly
.name
)
7600 t
= mono_reflection_get_type (ass
->image
, &info
, ignorecase
, &type_resolve
);
7602 buffer_add_typeid (buf
, domain
, t
? mono_class_from_mono_type (t
) : NULL
);
7603 mono_reflection_free_type_info (&info
);
7606 mono_domain_set (d
, TRUE
);
7610 case CMD_ASSEMBLY_GET_NAME
: {
7612 MonoAssembly
*mass
= ass
;
7614 name
= g_strdup_printf (
7615 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
7617 mass
->aname
.major
, mass
->aname
.minor
, mass
->aname
.build
, mass
->aname
.revision
,
7618 mass
->aname
.culture
&& *mass
->aname
.culture
? mass
->aname
.culture
: "neutral",
7619 mass
->aname
.public_key_token
[0] ? (char *)mass
->aname
.public_key_token
: "null",
7620 (mass
->aname
.flags
& ASSEMBLYREF_RETARGETABLE_FLAG
) ? ", Retargetable=Yes" : "");
7622 buffer_add_string (buf
, name
);
7627 return ERR_NOT_IMPLEMENTED
;
7634 module_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7640 case CMD_MODULE_GET_INFO
: {
7641 MonoImage
*image
= decode_moduleid (p
, &p
, end
, &domain
, &err
);
7644 basename
= g_path_get_basename (image
->name
);
7645 buffer_add_string (buf
, basename
); // name
7646 buffer_add_string (buf
, image
->module_name
); // scopename
7647 buffer_add_string (buf
, image
->name
); // fqname
7648 buffer_add_string (buf
, mono_image_get_guid (image
)); // guid
7649 buffer_add_assemblyid (buf
, domain
, image
->assembly
); // assembly
7654 return ERR_NOT_IMPLEMENTED
;
7661 field_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7667 case CMD_FIELD_GET_INFO
: {
7668 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, &domain
, &err
);
7670 buffer_add_string (buf
, f
->name
);
7671 buffer_add_typeid (buf
, domain
, f
->parent
);
7672 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
7673 buffer_add_int (buf
, f
->type
->attrs
);
7677 return ERR_NOT_IMPLEMENTED
;
7684 buffer_add_cattr_arg (Buffer
*buf
, MonoType
*t
, MonoDomain
*domain
, MonoObject
*val
)
7686 if (val
&& val
->vtable
->klass
== mono_defaults
.monotype_class
) {
7687 /* Special case these so the client doesn't have to handle Type objects */
7689 buffer_add_byte (buf
, VALUE_TYPE_ID_TYPE
);
7690 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (((MonoReflectionType
*)val
)->type
));
7691 } else if (MONO_TYPE_IS_REFERENCE (t
))
7692 buffer_add_value (buf
, t
, &val
, domain
);
7694 buffer_add_value (buf
, t
, mono_object_unbox (val
), domain
);
7698 buffer_add_cattrs (Buffer
*buf
, MonoDomain
*domain
, MonoImage
*image
, MonoClass
*attr_klass
, MonoCustomAttrInfo
*cinfo
)
7704 buffer_add_int (buf
, 0);
7708 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
7709 if (!attr_klass
|| mono_class_has_parent (cinfo
->attrs
[i
].ctor
->klass
, attr_klass
))
7712 buffer_add_int (buf
, nattrs
);
7714 for (i
= 0; i
< cinfo
->num_attrs
; ++i
) {
7715 MonoCustomAttrEntry
*attr
= &cinfo
->attrs
[i
];
7716 if (!attr_klass
|| mono_class_has_parent (attr
->ctor
->klass
, attr_klass
)) {
7717 MonoArray
*typed_args
, *named_args
;
7719 CattrNamedArg
*arginfo
= NULL
;
7722 mono_reflection_create_custom_attr_data_args (image
, attr
->ctor
, attr
->data
, attr
->data_size
, &typed_args
, &named_args
, &arginfo
, &error
);
7723 g_assert (mono_error_ok (&error
));
7725 buffer_add_methodid (buf
, domain
, attr
->ctor
);
7729 buffer_add_int (buf
, mono_array_length (typed_args
));
7730 for (j
= 0; j
< mono_array_length (typed_args
); ++j
) {
7731 MonoObject
*val
= mono_array_get (typed_args
, MonoObject
*, j
);
7733 t
= mono_method_signature (attr
->ctor
)->params
[j
];
7735 buffer_add_cattr_arg (buf
, t
, domain
, val
);
7738 buffer_add_int (buf
, 0);
7743 buffer_add_int (buf
, mono_array_length (named_args
));
7745 for (j
= 0; j
< mono_array_length (named_args
); ++j
) {
7746 MonoObject
*val
= mono_array_get (named_args
, MonoObject
*, j
);
7748 if (arginfo
[j
].prop
) {
7749 buffer_add_byte (buf
, 0x54);
7750 buffer_add_propertyid (buf
, domain
, arginfo
[j
].prop
);
7751 } else if (arginfo
[j
].field
) {
7752 buffer_add_byte (buf
, 0x53);
7753 buffer_add_fieldid (buf
, domain
, arginfo
[j
].field
);
7755 g_assert_not_reached ();
7758 buffer_add_cattr_arg (buf
, arginfo
[j
].type
, domain
, val
);
7761 buffer_add_int (buf
, 0);
7768 /* FIXME: Code duplication with icall.c */
7770 collect_interfaces (MonoClass
*klass
, GHashTable
*ifaces
, MonoError
*error
)
7775 mono_class_setup_interfaces (klass
, error
);
7776 if (!mono_error_ok (error
))
7779 for (i
= 0; i
< klass
->interface_count
; i
++) {
7780 ic
= klass
->interfaces
[i
];
7781 g_hash_table_insert (ifaces
, ic
, ic
);
7783 collect_interfaces (ic
, ifaces
, error
);
7784 if (!mono_error_ok (error
))
7790 type_commands_internal (int command
, MonoClass
*klass
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
7800 case CMD_TYPE_GET_INFO
: {
7801 buffer_add_string (buf
, klass
->name_space
);
7802 buffer_add_string (buf
, klass
->name
);
7804 name
= mono_type_get_name_full (&klass
->byval_arg
, MONO_TYPE_NAME_FORMAT_FULL_NAME
);
7805 buffer_add_string (buf
, name
);
7807 buffer_add_assemblyid (buf
, domain
, klass
->image
->assembly
);
7808 buffer_add_moduleid (buf
, domain
, klass
->image
);
7809 buffer_add_typeid (buf
, domain
, klass
->parent
);
7810 if (klass
->rank
|| klass
->byval_arg
.type
== MONO_TYPE_PTR
)
7811 buffer_add_typeid (buf
, domain
, klass
->element_class
);
7813 buffer_add_id (buf
, 0);
7814 buffer_add_int (buf
, klass
->type_token
);
7815 buffer_add_byte (buf
, klass
->rank
);
7816 buffer_add_int (buf
, klass
->flags
);
7818 type
= &klass
->byval_arg
;
7819 // FIXME: Can't decide whenever a class represents a byref type
7822 if (type
->type
== MONO_TYPE_PTR
)
7824 if (!type
->byref
&& (((type
->type
>= MONO_TYPE_BOOLEAN
) && (type
->type
<= MONO_TYPE_R8
)) || (type
->type
== MONO_TYPE_I
) || (type
->type
== MONO_TYPE_U
)))
7826 if (type
->type
== MONO_TYPE_VALUETYPE
)
7828 if (klass
->enumtype
)
7830 if (klass
->generic_container
)
7832 if (klass
->generic_container
|| klass
->generic_class
)
7834 buffer_add_byte (buf
, b
);
7837 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
7839 buffer_add_int (buf
, nnested
);
7841 while ((nested
= mono_class_get_nested_types (klass
, &iter
)))
7842 buffer_add_typeid (buf
, domain
, nested
);
7843 if (CHECK_PROTOCOL_VERSION (2, 12)) {
7844 if (klass
->generic_container
)
7845 buffer_add_typeid (buf
, domain
, klass
);
7846 else if (klass
->generic_class
)
7847 buffer_add_typeid (buf
, domain
, klass
->generic_class
->container_class
);
7849 buffer_add_id (buf
, 0);
7851 if (CHECK_PROTOCOL_VERSION (2, 15)) {
7854 if (klass
->generic_class
) {
7855 MonoGenericInst
*inst
= klass
->generic_class
->context
.class_inst
;
7857 count
= inst
->type_argc
;
7858 buffer_add_int (buf
, count
);
7859 for (i
= 0; i
< count
; i
++)
7860 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (inst
->type_argv
[i
]));
7861 } else if (klass
->generic_container
) {
7862 MonoGenericContainer
*container
= klass
->generic_container
;
7865 count
= container
->type_argc
;
7866 buffer_add_int (buf
, count
);
7867 for (i
= 0; i
< count
; i
++) {
7868 pklass
= mono_class_from_generic_parameter (mono_generic_container_get_param (container
, i
), klass
->image
, FALSE
);
7869 buffer_add_typeid (buf
, domain
, pklass
);
7872 buffer_add_int (buf
, 0);
7877 case CMD_TYPE_GET_METHODS
: {
7880 gpointer iter
= NULL
;
7883 mono_class_setup_methods (klass
);
7885 nmethods
= mono_class_num_methods (klass
);
7887 buffer_add_int (buf
, nmethods
);
7889 while ((m
= mono_class_get_methods (klass
, &iter
))) {
7890 buffer_add_methodid (buf
, domain
, m
);
7893 g_assert (i
== nmethods
);
7896 case CMD_TYPE_GET_FIELDS
: {
7899 gpointer iter
= NULL
;
7902 nfields
= mono_class_num_fields (klass
);
7904 buffer_add_int (buf
, nfields
);
7906 while ((f
= mono_class_get_fields (klass
, &iter
))) {
7907 buffer_add_fieldid (buf
, domain
, f
);
7908 buffer_add_string (buf
, f
->name
);
7909 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (f
->type
));
7910 buffer_add_int (buf
, f
->type
->attrs
);
7913 g_assert (i
== nfields
);
7916 case CMD_TYPE_GET_PROPERTIES
: {
7919 gpointer iter
= NULL
;
7922 nprops
= mono_class_num_properties (klass
);
7924 buffer_add_int (buf
, nprops
);
7926 while ((p
= mono_class_get_properties (klass
, &iter
))) {
7927 buffer_add_propertyid (buf
, domain
, p
);
7928 buffer_add_string (buf
, p
->name
);
7929 buffer_add_methodid (buf
, domain
, p
->get
);
7930 buffer_add_methodid (buf
, domain
, p
->set
);
7931 buffer_add_int (buf
, p
->attrs
);
7934 g_assert (i
== nprops
);
7937 case CMD_TYPE_GET_CATTRS
: {
7938 MonoClass
*attr_klass
;
7939 MonoCustomAttrInfo
*cinfo
;
7941 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7942 /* attr_klass can be NULL */
7946 cinfo
= mono_custom_attrs_from_class (klass
);
7948 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7951 case CMD_TYPE_GET_FIELD_CATTRS
: {
7952 MonoClass
*attr_klass
;
7953 MonoCustomAttrInfo
*cinfo
;
7954 MonoClassField
*field
;
7956 field
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
7959 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7963 cinfo
= mono_custom_attrs_from_field (klass
, field
);
7965 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7968 case CMD_TYPE_GET_PROPERTY_CATTRS
: {
7969 MonoClass
*attr_klass
;
7970 MonoCustomAttrInfo
*cinfo
;
7973 prop
= decode_propertyid (p
, &p
, end
, NULL
, &err
);
7976 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
7980 cinfo
= mono_custom_attrs_from_property (klass
, prop
);
7982 buffer_add_cattrs (buf
, domain
, klass
->image
, attr_klass
, cinfo
);
7985 case CMD_TYPE_GET_VALUES
:
7986 case CMD_TYPE_GET_VALUES_2
: {
7993 MonoThread
*thread_obj
;
7994 MonoInternalThread
*thread
= NULL
;
7995 guint32 special_static_type
;
7997 if (command
== CMD_TYPE_GET_VALUES_2
) {
7998 int objid
= decode_objid (p
, &p
, end
);
8001 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
8005 thread
= THREAD_TO_INTERNAL (thread_obj
);
8008 len
= decode_int (p
, &p
, end
);
8009 for (i
= 0; i
< len
; ++i
) {
8010 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
8014 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
8015 return ERR_INVALID_FIELDID
;
8016 special_static_type
= mono_class_field_get_special_static_type (f
);
8017 if (special_static_type
!= SPECIAL_STATIC_NONE
) {
8018 if (!(thread
&& special_static_type
== SPECIAL_STATIC_THREAD
))
8019 return ERR_INVALID_FIELDID
;
8022 /* Check that the field belongs to the object */
8024 for (k
= klass
; k
; k
= k
->parent
) {
8025 if (k
== f
->parent
) {
8031 return ERR_INVALID_FIELDID
;
8033 vtable
= mono_class_vtable (domain
, f
->parent
);
8034 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
8035 mono_field_static_get_value_for_thread (thread
? thread
: mono_thread_internal_current (), vtable
, f
, val
);
8036 buffer_add_value (buf
, f
->type
, val
, domain
);
8041 case CMD_TYPE_SET_VALUES
: {
8049 len
= decode_int (p
, &p
, end
);
8050 for (i
= 0; i
< len
; ++i
) {
8051 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
8055 if (!(f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
8056 return ERR_INVALID_FIELDID
;
8057 if (mono_class_field_is_special_static (f
))
8058 return ERR_INVALID_FIELDID
;
8060 /* Check that the field belongs to the object */
8062 for (k
= klass
; k
; k
= k
->parent
) {
8063 if (k
== f
->parent
) {
8069 return ERR_INVALID_FIELDID
;
8071 // FIXME: Check for literal/const
8073 vtable
= mono_class_vtable (domain
, f
->parent
);
8074 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
8075 err
= decode_value (f
->type
, domain
, val
, p
, &p
, end
);
8080 if (MONO_TYPE_IS_REFERENCE (f
->type
))
8081 mono_field_static_set_value (vtable
, f
, *(gpointer
*)val
);
8083 mono_field_static_set_value (vtable
, f
, val
);
8088 case CMD_TYPE_GET_OBJECT
: {
8089 MonoObject
*o
= (MonoObject
*)mono_type_get_object (domain
, &klass
->byval_arg
);
8090 buffer_add_objid (buf
, o
);
8093 case CMD_TYPE_GET_SOURCE_FILES
:
8094 case CMD_TYPE_GET_SOURCE_FILES_2
: {
8095 char *source_file
, *base
;
8099 files
= get_source_files_for_type (klass
);
8101 buffer_add_int (buf
, files
->len
);
8102 for (i
= 0; i
< files
->len
; ++i
) {
8103 source_file
= g_ptr_array_index (files
, i
);
8104 if (command
== CMD_TYPE_GET_SOURCE_FILES_2
) {
8105 buffer_add_string (buf
, source_file
);
8107 base
= g_path_get_basename (source_file
);
8108 buffer_add_string (buf
, base
);
8111 g_free (source_file
);
8113 g_ptr_array_free (files
, TRUE
);
8116 case CMD_TYPE_IS_ASSIGNABLE_FROM
: {
8117 MonoClass
*oklass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8121 if (mono_class_is_assignable_from (klass
, oklass
))
8122 buffer_add_byte (buf
, 1);
8124 buffer_add_byte (buf
, 0);
8127 case CMD_TYPE_GET_METHODS_BY_NAME_FLAGS
: {
8128 char *name
= decode_string (p
, &p
, end
);
8129 int i
, flags
= decode_int (p
, &p
, end
);
8130 MonoException
*ex
= NULL
;
8131 GPtrArray
*array
= mono_class_get_methods_by_name (klass
, name
, flags
& ~BINDING_FLAGS_IGNORE_CASE
, (flags
& BINDING_FLAGS_IGNORE_CASE
) != 0, TRUE
, &ex
);
8134 return ERR_LOADER_ERROR
;
8135 buffer_add_int (buf
, array
->len
);
8136 for (i
= 0; i
< array
->len
; ++i
) {
8137 MonoMethod
*method
= g_ptr_array_index (array
, i
);
8138 buffer_add_methodid (buf
, domain
, method
);
8141 g_ptr_array_free (array
, TRUE
);
8145 case CMD_TYPE_GET_INTERFACES
: {
8147 GHashTable
*iface_hash
= g_hash_table_new (NULL
, NULL
);
8149 MonoClass
*tclass
, *iface
;
8150 GHashTableIter iter
;
8154 for (parent
= tclass
; parent
; parent
= parent
->parent
) {
8155 mono_class_setup_interfaces (parent
, &error
);
8156 if (!mono_error_ok (&error
))
8157 return ERR_LOADER_ERROR
;
8158 collect_interfaces (parent
, iface_hash
, &error
);
8159 if (!mono_error_ok (&error
))
8160 return ERR_LOADER_ERROR
;
8163 buffer_add_int (buf
, g_hash_table_size (iface_hash
));
8165 g_hash_table_iter_init (&iter
, iface_hash
);
8166 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&iface
))
8167 buffer_add_typeid (buf
, domain
, iface
);
8168 g_hash_table_destroy (iface_hash
);
8171 case CMD_TYPE_GET_INTERFACE_MAP
: {
8172 int tindex
, ioffset
;
8173 gboolean variance_used
;
8175 int len
, nmethods
, i
;
8179 len
= decode_int (p
, &p
, end
);
8180 mono_class_setup_vtable (klass
);
8182 for (tindex
= 0; tindex
< len
; ++tindex
) {
8183 iclass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8187 ioffset
= mono_class_interface_offset_with_variance (klass
, iclass
, &variance_used
);
8189 return ERR_INVALID_ARGUMENT
;
8191 nmethods
= mono_class_num_methods (iclass
);
8192 buffer_add_int (buf
, nmethods
);
8195 while ((method
= mono_class_get_methods (iclass
, &iter
))) {
8196 buffer_add_methodid (buf
, domain
, method
);
8198 for (i
= 0; i
< nmethods
; ++i
)
8199 buffer_add_methodid (buf
, domain
, klass
->vtable
[i
+ ioffset
]);
8203 case CMD_TYPE_IS_INITIALIZED
: {
8204 MonoVTable
*vtable
= mono_class_vtable (domain
, klass
);
8207 buffer_add_int (buf
, (vtable
->initialized
|| vtable
->init_failed
) ? 1 : 0);
8209 buffer_add_int (buf
, 0);
8212 case CMD_TYPE_CREATE_INSTANCE
: {
8215 obj
= mono_object_new (domain
, klass
);
8216 buffer_add_objid (buf
, obj
);
8220 return ERR_NOT_IMPLEMENTED
;
8227 type_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8230 MonoDomain
*old_domain
;
8234 klass
= decode_typeid (p
, &p
, end
, &domain
, &err
);
8238 old_domain
= mono_domain_get ();
8240 mono_domain_set (domain
, TRUE
);
8242 err
= type_commands_internal (command
, klass
, domain
, p
, end
, buf
);
8244 mono_domain_set (old_domain
, TRUE
);
8250 method_commands_internal (int command
, MonoMethod
*method
, MonoDomain
*domain
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8252 MonoMethodHeader
*header
;
8256 case CMD_METHOD_GET_NAME
: {
8257 buffer_add_string (buf
, method
->name
);
8260 case CMD_METHOD_GET_DECLARING_TYPE
: {
8261 buffer_add_typeid (buf
, domain
, method
->klass
);
8264 case CMD_METHOD_GET_DEBUG_INFO
: {
8265 MonoDebugMethodInfo
*minfo
;
8267 int i
, j
, n_il_offsets
;
8270 int *column_numbers
;
8271 int *end_line_numbers
;
8272 int *end_column_numbers
;
8274 GPtrArray
*source_file_list
;
8276 header
= mono_method_get_header (method
);
8278 buffer_add_int (buf
, 0);
8279 buffer_add_string (buf
, "");
8280 buffer_add_int (buf
, 0);
8284 minfo
= mono_debug_lookup_method (method
);
8286 buffer_add_int (buf
, header
->code_size
);
8287 buffer_add_string (buf
, "");
8288 buffer_add_int (buf
, 0);
8289 mono_metadata_free_mh (header
);
8293 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
);
8294 buffer_add_int (buf
, header
->code_size
);
8295 if (CHECK_PROTOCOL_VERSION (2, 13)) {
8296 buffer_add_int (buf
, source_file_list
->len
);
8297 for (i
= 0; i
< source_file_list
->len
; ++i
) {
8298 MonoDebugSourceInfo
*sinfo
= g_ptr_array_index (source_file_list
, i
);
8299 buffer_add_string (buf
, sinfo
->source_file
);
8300 if (CHECK_PROTOCOL_VERSION (2, 14)) {
8301 for (j
= 0; j
< 16; ++j
)
8302 buffer_add_byte (buf
, sinfo
->hash
[j
]);
8306 buffer_add_string (buf
, source_file
);
8308 buffer_add_int (buf
, n_il_offsets
);
8309 DEBUG (10, fprintf (log_file
, "Line number table for method %s:\n", mono_method_full_name (method
, TRUE
)));
8310 for (i
= 0; i
< n_il_offsets
; ++i
) {
8311 const char *srcfile
= "";
8313 if (source_files
[i
] != -1) {
8314 MonoDebugSourceInfo
*sinfo
= g_ptr_array_index (source_file_list
, source_files
[i
]);
8315 srcfile
= sinfo
->source_file
;
8317 DEBUG (10, fprintf (log_file
, "IL%x -> %s:%d %d\n", il_offsets
[i
], srcfile
, line_numbers
[i
], column_numbers
? column_numbers
[i
] : -1));
8318 buffer_add_int (buf
, il_offsets
[i
]);
8319 buffer_add_int (buf
, line_numbers
[i
]);
8320 if (CHECK_PROTOCOL_VERSION (2, 13))
8321 buffer_add_int (buf
, source_files
[i
]);
8322 if (CHECK_PROTOCOL_VERSION (2, 19))
8323 buffer_add_int (buf
, column_numbers
? column_numbers
[i
] : -1);
8324 if (CHECK_PROTOCOL_VERSION (2, 32)) {
8325 buffer_add_int (buf
, end_line_numbers
? end_line_numbers
[i
] : -1);
8326 buffer_add_int (buf
, end_column_numbers
? end_column_numbers
[i
] : -1);
8329 g_free (source_file
);
8330 g_free (il_offsets
);
8331 g_free (line_numbers
);
8332 g_free (column_numbers
);
8333 g_free (end_line_numbers
);
8334 g_free (end_column_numbers
);
8335 g_free (source_files
);
8336 g_ptr_array_free (source_file_list
, TRUE
);
8337 mono_metadata_free_mh (header
);
8340 case CMD_METHOD_GET_PARAM_INFO
: {
8341 MonoMethodSignature
*sig
= mono_method_signature (method
);
8345 /* FIXME: mono_class_from_mono_type () and byrefs */
8347 /* FIXME: Use a smaller encoding */
8348 buffer_add_int (buf
, sig
->call_convention
);
8349 buffer_add_int (buf
, sig
->param_count
);
8350 buffer_add_int (buf
, sig
->generic_param_count
);
8351 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->ret
));
8352 for (i
= 0; i
< sig
->param_count
; ++i
) {
8354 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (sig
->params
[i
]));
8357 /* Emit parameter names */
8358 names
= g_new (char *, sig
->param_count
);
8359 mono_method_get_param_names (method
, (const char **) names
);
8360 for (i
= 0; i
< sig
->param_count
; ++i
)
8361 buffer_add_string (buf
, names
[i
]);
8366 case CMD_METHOD_GET_LOCALS_INFO
: {
8367 int i
, j
, num_locals
;
8368 MonoDebugLocalsInfo
*locals
;
8370 header
= mono_method_get_header (method
);
8372 return ERR_INVALID_ARGUMENT
;
8374 buffer_add_int (buf
, header
->num_locals
);
8377 for (i
= 0; i
< header
->num_locals
; ++i
)
8378 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (header
->locals
[i
]));
8381 locals
= mono_debug_lookup_locals (method
);
8383 num_locals
= locals
->num_locals
;
8386 for (i
= 0; i
< header
->num_locals
; ++i
) {
8387 for (j
= 0; j
< num_locals
; ++j
)
8388 if (locals
->locals
[j
].index
== i
)
8391 buffer_add_string (buf
, locals
->locals
[j
].name
);
8393 buffer_add_string (buf
, "");
8397 for (i
= 0; i
< header
->num_locals
; ++i
) {
8398 for (j
= 0; j
< num_locals
; ++j
)
8399 if (locals
->locals
[j
].index
== i
)
8401 if (j
< num_locals
&& locals
->locals
[j
].block
) {
8402 buffer_add_int (buf
, locals
->locals
[j
].block
->start_offset
);
8403 buffer_add_int (buf
, locals
->locals
[j
].block
->end_offset
);
8405 buffer_add_int (buf
, 0);
8406 buffer_add_int (buf
, header
->code_size
);
8409 mono_metadata_free_mh (header
);
8412 mono_debug_symfile_free_locals (locals
);
8416 case CMD_METHOD_GET_INFO
:
8417 buffer_add_int (buf
, method
->flags
);
8418 buffer_add_int (buf
, method
->iflags
);
8419 buffer_add_int (buf
, method
->token
);
8420 if (CHECK_PROTOCOL_VERSION (2, 12)) {
8422 if (method
->is_generic
)
8424 if (mono_method_signature (method
)->generic_param_count
)
8426 buffer_add_byte (buf
, attrs
);
8427 if (method
->is_generic
|| method
->is_inflated
) {
8430 if (method
->is_generic
) {
8433 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
8435 result
= imethod
->declaring
;
8436 if (imethod
->context
.class_inst
) {
8437 MonoClass
*klass
= ((MonoMethod
*) imethod
)->klass
;
8438 /*Generic methods gets the context of the GTD.*/
8439 if (mono_class_get_context (klass
))
8440 result
= mono_class_inflate_generic_method_full (result
, klass
, mono_class_get_context (klass
));
8444 buffer_add_methodid (buf
, domain
, result
);
8446 buffer_add_id (buf
, 0);
8448 if (CHECK_PROTOCOL_VERSION (2, 15)) {
8449 if (mono_method_signature (method
)->generic_param_count
) {
8452 if (method
->is_inflated
) {
8453 MonoGenericInst
*inst
= mono_method_get_context (method
)->method_inst
;
8455 count
= inst
->type_argc
;
8456 buffer_add_int (buf
, count
);
8458 for (i
= 0; i
< count
; i
++)
8459 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type (inst
->type_argv
[i
]));
8461 buffer_add_int (buf
, 0);
8463 } else if (method
->is_generic
) {
8464 MonoGenericContainer
*container
= mono_method_get_generic_container (method
);
8466 count
= mono_method_signature (method
)->generic_param_count
;
8467 buffer_add_int (buf
, count
);
8468 for (i
= 0; i
< count
; i
++) {
8469 MonoGenericParam
*param
= mono_generic_container_get_param (container
, i
);
8470 MonoClass
*pklass
= mono_class_from_generic_parameter (param
, method
->klass
->image
, TRUE
);
8471 buffer_add_typeid (buf
, domain
, pklass
);
8474 buffer_add_int (buf
, 0);
8477 buffer_add_int (buf
, 0);
8482 case CMD_METHOD_GET_BODY
: {
8485 header
= mono_method_get_header (method
);
8487 buffer_add_int (buf
, 0);
8489 if (CHECK_PROTOCOL_VERSION (2, 18))
8490 buffer_add_int (buf
, 0);
8492 buffer_add_int (buf
, header
->code_size
);
8493 for (i
= 0; i
< header
->code_size
; ++i
)
8494 buffer_add_byte (buf
, header
->code
[i
]);
8496 if (CHECK_PROTOCOL_VERSION (2, 18)) {
8497 buffer_add_int (buf
, header
->num_clauses
);
8498 for (i
= 0; i
< header
->num_clauses
; ++i
) {
8499 MonoExceptionClause
*clause
= &header
->clauses
[i
];
8501 buffer_add_int (buf
, clause
->flags
);
8502 buffer_add_int (buf
, clause
->try_offset
);
8503 buffer_add_int (buf
, clause
->try_len
);
8504 buffer_add_int (buf
, clause
->handler_offset
);
8505 buffer_add_int (buf
, clause
->handler_len
);
8506 if (clause
->flags
== MONO_EXCEPTION_CLAUSE_NONE
)
8507 buffer_add_typeid (buf
, domain
, clause
->data
.catch_class
);
8508 else if (clause
->flags
== MONO_EXCEPTION_CLAUSE_FILTER
)
8509 buffer_add_int (buf
, clause
->data
.filter_offset
);
8513 mono_metadata_free_mh (header
);
8518 case CMD_METHOD_RESOLVE_TOKEN
: {
8519 guint32 token
= decode_int (p
, &p
, end
);
8522 switch (mono_metadata_token_code (token
)) {
8523 case MONO_TOKEN_STRING
: {
8527 s
= mono_ldstr (domain
, method
->klass
->image
, mono_metadata_token_index (token
));
8530 s2
= mono_string_to_utf8 (s
);
8532 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
8533 buffer_add_string (buf
, s2
);
8539 MonoClass
*handle_class
;
8541 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
) {
8542 val
= mono_method_get_wrapper_data (method
, token
);
8543 handle_class
= mono_method_get_wrapper_data (method
, token
+ 1);
8545 if (handle_class
== NULL
) {
8546 // Can't figure out the token type
8547 buffer_add_byte (buf
, TOKEN_TYPE_UNKNOWN
);
8551 val
= mono_ldtoken (method
->klass
->image
, token
, &handle_class
, NULL
);
8555 if (handle_class
== mono_defaults
.typehandle_class
) {
8556 buffer_add_byte (buf
, TOKEN_TYPE_TYPE
);
8557 if (method
->wrapper_type
== MONO_WRAPPER_DYNAMIC_METHOD
)
8558 buffer_add_typeid (buf
, domain
, (MonoClass
*) val
);
8560 buffer_add_typeid (buf
, domain
, mono_class_from_mono_type ((MonoType
*)val
));
8561 } else if (handle_class
== mono_defaults
.fieldhandle_class
) {
8562 buffer_add_byte (buf
, TOKEN_TYPE_FIELD
);
8563 buffer_add_fieldid (buf
, domain
, val
);
8564 } else if (handle_class
== mono_defaults
.methodhandle_class
) {
8565 buffer_add_byte (buf
, TOKEN_TYPE_METHOD
);
8566 buffer_add_methodid (buf
, domain
, val
);
8567 } else if (handle_class
== mono_defaults
.string_class
) {
8570 s
= mono_string_to_utf8 (val
);
8571 buffer_add_byte (buf
, TOKEN_TYPE_STRING
);
8572 buffer_add_string (buf
, s
);
8575 g_assert_not_reached ();
8582 case CMD_METHOD_GET_CATTRS
: {
8583 MonoClass
*attr_klass
;
8584 MonoCustomAttrInfo
*cinfo
;
8586 attr_klass
= decode_typeid (p
, &p
, end
, NULL
, &err
);
8587 /* attr_klass can be NULL */
8591 cinfo
= mono_custom_attrs_from_method (method
);
8593 buffer_add_cattrs (buf
, domain
, method
->klass
->image
, attr_klass
, cinfo
);
8596 case CMD_METHOD_MAKE_GENERIC_METHOD
: {
8597 MonoType
**type_argv
;
8601 MonoGenericInst
*ginst
;
8602 MonoGenericContext tmp_context
;
8603 MonoMethod
*inflated
;
8605 type_argc
= decode_int (p
, &p
, end
);
8606 type_argv
= g_new0 (MonoType
*, type_argc
);
8607 for (i
= 0; i
< type_argc
; ++i
) {
8608 klass
= decode_typeid (p
, &p
, end
, &d
, &err
);
8615 return ERR_INVALID_ARGUMENT
;
8617 type_argv
[i
] = &klass
->byval_arg
;
8619 ginst
= mono_metadata_get_generic_inst (type_argc
, type_argv
);
8621 tmp_context
.class_inst
= method
->klass
->generic_class
? method
->klass
->generic_class
->context
.class_inst
: NULL
;
8622 tmp_context
.method_inst
= ginst
;
8624 inflated
= mono_class_inflate_generic_method (method
, &tmp_context
);
8625 if (!mono_verifier_is_method_valid_generic_instantiation (inflated
))
8626 return ERR_INVALID_ARGUMENT
;
8627 buffer_add_methodid (buf
, domain
, inflated
);
8631 return ERR_NOT_IMPLEMENTED
;
8638 method_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8641 MonoDomain
*old_domain
;
8645 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
8649 old_domain
= mono_domain_get ();
8651 mono_domain_set (domain
, TRUE
);
8653 err
= method_commands_internal (command
, method
, domain
, p
, end
, buf
);
8655 mono_domain_set (old_domain
, TRUE
);
8661 thread_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8663 int objid
= decode_objid (p
, &p
, end
);
8665 MonoThread
*thread_obj
;
8666 MonoInternalThread
*thread
;
8668 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
8672 thread
= THREAD_TO_INTERNAL (thread_obj
);
8675 case CMD_THREAD_GET_NAME
: {
8677 gunichar2
*s
= mono_thread_get_name (thread
, &name_len
);
8680 buffer_add_int (buf
, 0);
8685 name
= g_utf16_to_utf8 (s
, name_len
, NULL
, &len
, NULL
);
8687 buffer_add_int (buf
, len
);
8688 buffer_add_data (buf
, (guint8
*)name
, len
);
8693 case CMD_THREAD_GET_FRAME_INFO
: {
8694 DebuggerTlsData
*tls
;
8695 int i
, start_frame
, length
;
8697 // Wait for suspending if it already started
8698 // FIXME: Races with suspend_count
8699 while (!is_suspended ()) {
8701 wait_for_suspend ();
8705 wait_for_suspend ();
8706 if (!is_suspended ())
8707 return ERR_NOT_SUSPENDED;
8710 start_frame
= decode_int (p
, &p
, end
);
8711 length
= decode_int (p
, &p
, end
);
8713 if (start_frame
!= 0 || length
!= -1)
8714 return ERR_NOT_IMPLEMENTED
;
8716 mono_loader_lock ();
8717 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8718 mono_loader_unlock ();
8721 compute_frame_info (thread
, tls
);
8723 buffer_add_int (buf
, tls
->frame_count
);
8724 for (i
= 0; i
< tls
->frame_count
; ++i
) {
8725 buffer_add_int (buf
, tls
->frames
[i
]->id
);
8726 buffer_add_methodid (buf
, tls
->frames
[i
]->domain
, tls
->frames
[i
]->actual_method
);
8727 buffer_add_int (buf
, tls
->frames
[i
]->il_offset
);
8729 * Instead of passing the frame type directly to the client, we associate
8730 * it with the previous frame using a set of flags. This avoids lots of
8731 * conditional code in the client, since a frame whose type isn't
8732 * FRAME_TYPE_MANAGED has no method, location, etc.
8734 buffer_add_byte (buf
, tls
->frames
[i
]->flags
);
8739 case CMD_THREAD_GET_STATE
:
8740 buffer_add_int (buf
, thread
->state
);
8742 case CMD_THREAD_GET_INFO
:
8743 buffer_add_byte (buf
, thread
->threadpool_thread
);
8745 case CMD_THREAD_GET_ID
:
8746 buffer_add_long (buf
, (guint64
)(gsize
)thread
);
8748 case CMD_THREAD_GET_TID
:
8749 buffer_add_long (buf
, (guint64
)thread
->tid
);
8751 case CMD_THREAD_SET_IP
: {
8752 DebuggerTlsData
*tls
;
8755 MonoSeqPointInfo
*seq_points
;
8756 SeqPoint
*sp
= NULL
;
8760 method
= decode_methodid (p
, &p
, end
, &domain
, &err
);
8763 il_offset
= decode_long (p
, &p
, end
);
8765 while (!is_suspended ()) {
8767 wait_for_suspend ();
8770 mono_loader_lock ();
8771 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8772 mono_loader_unlock ();
8775 compute_frame_info (thread
, tls
);
8776 if (tls
->frame_count
== 0 || tls
->frames
[0]->actual_method
!= method
)
8777 return ERR_INVALID_ARGUMENT
;
8779 seq_points
= get_seq_points (domain
, method
);
8780 g_assert (seq_points
);
8782 for (i
= 0; i
< seq_points
->len
; ++i
) {
8783 sp
= &seq_points
->seq_points
[i
];
8785 if (sp
->il_offset
== il_offset
)
8788 if (i
== seq_points
->len
)
8789 return ERR_INVALID_ARGUMENT
;
8791 // FIXME: Check that the ip change is safe
8793 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
));
8794 MONO_CONTEXT_SET_IP (&tls
->restore_ctx
, (guint8
*)tls
->frames
[0]->ji
->code_start
+ sp
->native_offset
);
8798 return ERR_NOT_IMPLEMENTED
;
8805 frame_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8809 MonoThread
*thread_obj
;
8810 MonoInternalThread
*thread
;
8811 int pos
, i
, len
, frame_idx
;
8812 DebuggerTlsData
*tls
;
8814 MonoDebugMethodJitInfo
*jit
;
8815 MonoDebugVarInfo
*var
;
8816 MonoMethodSignature
*sig
;
8818 MonoMethodHeader
*header
;
8820 objid
= decode_objid (p
, &p
, end
);
8821 err
= get_object (objid
, (MonoObject
**)&thread_obj
);
8825 thread
= THREAD_TO_INTERNAL (thread_obj
);
8827 id
= decode_id (p
, &p
, end
);
8829 mono_loader_lock ();
8830 tls
= mono_g_hash_table_lookup (thread_to_tls
, thread
);
8831 mono_loader_unlock ();
8834 for (i
= 0; i
< tls
->frame_count
; ++i
) {
8835 if (tls
->frames
[i
]->id
== id
)
8838 if (i
== tls
->frame_count
)
8839 return ERR_INVALID_FRAMEID
;
8842 frame
= tls
->frames
[frame_idx
];
8844 if (!frame
->has_ctx
)
8845 return ERR_ABSENT_INFORMATION
;
8848 frame
->jit
= mono_debug_find_method (frame
->api_method
, frame
->domain
);
8849 if (!frame
->jit
&& frame
->api_method
->is_inflated
)
8850 frame
->jit
= mono_debug_find_method (mono_method_get_declaring_generic_method (frame
->api_method
), frame
->domain
);
8854 /* This could happen for aot images with no jit debug info */
8855 s
= mono_method_full_name (frame
->api_method
, TRUE
);
8856 DEBUG (1, fprintf (log_file
, "[dbg] No debug information found for '%s'.\n", s
));
8858 return ERR_ABSENT_INFORMATION
;
8863 sig
= mono_method_signature (frame
->actual_method
);
8865 if (!get_seq_points (frame
->domain
, frame
->actual_method
))
8867 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
8869 return ERR_ABSENT_INFORMATION
;
8872 case CMD_STACK_FRAME_GET_VALUES
: {
8873 len
= decode_int (p
, &p
, end
);
8874 header
= mono_method_get_header (frame
->actual_method
);
8876 for (i
= 0; i
< len
; ++i
) {
8877 pos
= decode_int (p
, &p
, end
);
8882 g_assert (pos
>= 0 && pos
< jit
->num_params
);
8884 var
= &jit
->params
[pos
];
8886 add_var (buf
, jit
, sig
->params
[pos
], &jit
->params
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
8888 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
8890 var
= &jit
->locals
[pos
];
8892 add_var (buf
, jit
, header
->locals
[pos
], &jit
->locals
[pos
], &frame
->ctx
, frame
->domain
, FALSE
);
8895 mono_metadata_free_mh (header
);
8898 case CMD_STACK_FRAME_GET_THIS
: {
8899 if (frame
->api_method
->klass
->valuetype
) {
8900 if (!sig
->hasthis
) {
8901 MonoObject
*p
= NULL
;
8902 buffer_add_value (buf
, &mono_defaults
.object_class
->byval_arg
, &p
, frame
->domain
);
8904 add_var (buf
, jit
, &frame
->actual_method
->klass
->this_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
8907 if (!sig
->hasthis
) {
8908 MonoObject
*p
= NULL
;
8909 buffer_add_value (buf
, &frame
->actual_method
->klass
->byval_arg
, &p
, frame
->domain
);
8911 add_var (buf
, jit
, &frame
->api_method
->klass
->byval_arg
, jit
->this_var
, &frame
->ctx
, frame
->domain
, TRUE
);
8916 case CMD_STACK_FRAME_SET_VALUES
: {
8919 MonoDebugVarInfo
*var
;
8921 len
= decode_int (p
, &p
, end
);
8922 header
= mono_method_get_header (frame
->actual_method
);
8924 for (i
= 0; i
< len
; ++i
) {
8925 pos
= decode_int (p
, &p
, end
);
8930 g_assert (pos
>= 0 && pos
< jit
->num_params
);
8932 t
= sig
->params
[pos
];
8933 var
= &jit
->params
[pos
];
8935 g_assert (pos
>= 0 && pos
< jit
->num_locals
);
8937 t
= header
->locals
[pos
];
8938 var
= &jit
->locals
[pos
];
8941 if (MONO_TYPE_IS_REFERENCE (t
))
8942 val_buf
= g_alloca (sizeof (MonoObject
*));
8944 val_buf
= g_alloca (mono_class_instance_size (mono_class_from_mono_type (t
)));
8945 err
= decode_value (t
, frame
->domain
, val_buf
, p
, &p
, end
);
8949 set_var (t
, var
, &frame
->ctx
, frame
->domain
, val_buf
, frame
->reg_locations
, &tls
->restore_ctx
);
8951 mono_metadata_free_mh (header
);
8955 return ERR_NOT_IMPLEMENTED
;
8962 array_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
8965 int objid
, err
, index
, len
, i
, esize
;
8968 objid
= decode_objid (p
, &p
, end
);
8969 err
= get_object (objid
, (MonoObject
**)&arr
);
8974 case CMD_ARRAY_REF_GET_LENGTH
:
8975 buffer_add_int (buf
, arr
->obj
.vtable
->klass
->rank
);
8977 buffer_add_int (buf
, arr
->max_length
);
8978 buffer_add_int (buf
, 0);
8980 for (i
= 0; i
< arr
->obj
.vtable
->klass
->rank
; ++i
) {
8981 buffer_add_int (buf
, arr
->bounds
[i
].length
);
8982 buffer_add_int (buf
, arr
->bounds
[i
].lower_bound
);
8986 case CMD_ARRAY_REF_GET_VALUES
:
8987 index
= decode_int (p
, &p
, end
);
8988 len
= decode_int (p
, &p
, end
);
8990 g_assert (index
>= 0 && len
>= 0);
8991 // Reordered to avoid integer overflow
8992 g_assert (!(index
> arr
->max_length
- len
));
8994 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
8995 for (i
= index
; i
< index
+ len
; ++i
) {
8996 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
8997 buffer_add_value (buf
, &arr
->obj
.vtable
->klass
->element_class
->byval_arg
, elem
, arr
->obj
.vtable
->domain
);
9000 case CMD_ARRAY_REF_SET_VALUES
:
9001 index
= decode_int (p
, &p
, end
);
9002 len
= decode_int (p
, &p
, end
);
9004 g_assert (index
>= 0 && len
>= 0);
9005 // Reordered to avoid integer overflow
9006 g_assert (!(index
> arr
->max_length
- len
));
9008 esize
= mono_array_element_size (arr
->obj
.vtable
->klass
);
9009 for (i
= index
; i
< index
+ len
; ++i
) {
9010 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
9012 decode_value (&arr
->obj
.vtable
->klass
->element_class
->byval_arg
, arr
->obj
.vtable
->domain
, elem
, p
, &p
, end
);
9016 return ERR_NOT_IMPLEMENTED
;
9023 string_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
9028 int i
, index
, length
;
9031 objid
= decode_objid (p
, &p
, end
);
9032 err
= get_object (objid
, (MonoObject
**)&str
);
9037 case CMD_STRING_REF_GET_VALUE
:
9038 s
= mono_string_to_utf8 (str
);
9039 buffer_add_string (buf
, s
);
9042 case CMD_STRING_REF_GET_LENGTH
:
9043 buffer_add_long (buf
, mono_string_length (str
));
9045 case CMD_STRING_REF_GET_CHARS
:
9046 index
= decode_long (p
, &p
, end
);
9047 length
= decode_long (p
, &p
, end
);
9048 if (index
> mono_string_length (str
) - length
)
9049 return ERR_INVALID_ARGUMENT
;
9050 c
= mono_string_chars (str
) + index
;
9051 for (i
= 0; i
< length
; ++i
)
9052 buffer_add_short (buf
, c
[i
]);
9055 return ERR_NOT_IMPLEMENTED
;
9062 object_commands (int command
, guint8
*p
, guint8
*end
, Buffer
*buf
)
9071 if (command
== CMD_OBJECT_REF_IS_COLLECTED
) {
9072 objid
= decode_objid (p
, &p
, end
);
9073 err
= get_object (objid
, &obj
);
9075 buffer_add_int (buf
, 1);
9077 buffer_add_int (buf
, 0);
9081 objid
= decode_objid (p
, &p
, end
);
9082 err
= get_object (objid
, &obj
);
9087 case CMD_OBJECT_REF_GET_TYPE
:
9088 /* This handles transparent proxies too */
9089 buffer_add_typeid (buf
, obj
->vtable
->domain
, mono_class_from_mono_type (((MonoReflectionType
*)obj
->vtable
->type
)->type
));
9091 case CMD_OBJECT_REF_GET_VALUES
:
9092 len
= decode_int (p
, &p
, end
);
9094 for (i
= 0; i
< len
; ++i
) {
9095 MonoClassField
*f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
9099 /* Check that the field belongs to the object */
9101 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
9102 if (k
== f
->parent
) {
9108 return ERR_INVALID_FIELDID
;
9110 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
9114 if (mono_class_field_is_special_static (f
))
9115 return ERR_INVALID_FIELDID
;
9117 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
9118 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
9119 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
9120 mono_field_static_get_value (vtable
, f
, val
);
9121 buffer_add_value (buf
, f
->type
, val
, obj
->vtable
->domain
);
9124 buffer_add_value (buf
, f
->type
, (guint8
*)obj
+ f
->offset
, obj
->vtable
->domain
);
9128 case CMD_OBJECT_REF_SET_VALUES
:
9129 len
= decode_int (p
, &p
, end
);
9131 for (i
= 0; i
< len
; ++i
) {
9132 f
= decode_fieldid (p
, &p
, end
, NULL
, &err
);
9136 /* Check that the field belongs to the object */
9138 for (k
= obj
->vtable
->klass
; k
; k
= k
->parent
) {
9139 if (k
== f
->parent
) {
9145 return ERR_INVALID_FIELDID
;
9147 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
9151 if (mono_class_field_is_special_static (f
))
9152 return ERR_INVALID_FIELDID
;
9154 g_assert (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
);
9155 vtable
= mono_class_vtable (obj
->vtable
->domain
, f
->parent
);
9157 val
= g_malloc (mono_class_instance_size (mono_class_from_mono_type (f
->type
)));
9158 err
= decode_value (f
->type
, obj
->vtable
->domain
, val
, p
, &p
, end
);
9163 mono_field_static_set_value (vtable
, f
, val
);
9166 err
= decode_value (f
->type
, obj
->vtable
->domain
, (guint8
*)obj
+ f
->offset
, p
, &p
, end
);
9172 case CMD_OBJECT_REF_GET_ADDRESS
:
9173 buffer_add_long (buf
, (gssize
)obj
);
9175 case CMD_OBJECT_REF_GET_DOMAIN
:
9176 buffer_add_domainid (buf
, obj
->vtable
->domain
);
9178 case CMD_OBJECT_REF_GET_INFO
:
9179 buffer_add_typeid (buf
, obj
->vtable
->domain
, mono_class_from_mono_type (((MonoReflectionType
*)obj
->vtable
->type
)->type
));
9180 buffer_add_domainid (buf
, obj
->vtable
->domain
);
9183 return ERR_NOT_IMPLEMENTED
;
9190 command_set_to_string (CommandSet command_set
)
9192 switch (command_set
) {
9195 case CMD_SET_OBJECT_REF
:
9196 return "OBJECT_REF";
9197 case CMD_SET_STRING_REF
:
9198 return "STRING_REF";
9199 case CMD_SET_THREAD
:
9201 case CMD_SET_ARRAY_REF
:
9203 case CMD_SET_EVENT_REQUEST
:
9204 return "EVENT_REQUEST";
9205 case CMD_SET_STACK_FRAME
:
9206 return "STACK_FRAME";
9207 case CMD_SET_APPDOMAIN
:
9209 case CMD_SET_ASSEMBLY
:
9211 case CMD_SET_METHOD
:
9215 case CMD_SET_MODULE
:
9226 static const char* vm_cmds_str
[] = {
9234 "SET_PROTOCOL_VERSION",
9237 "GET_TYPES_FOR_SOURCE_FILE",
9242 static const char* thread_cmds_str
[] = {
9252 static const char* event_cmds_str
[] = {
9255 "REQUEST_CLEAR_ALL_BREAKPOINTS"
9258 static const char* appdomain_cmds_str
[] = {
9260 "GET_FRIENDLY_NAME",
9262 "GET_ENTRY_ASSEMBLY",
9265 "CREATE_BOXED_VALUE"
9268 static const char* assembly_cmds_str
[] = {
9271 "GET_MANIFEST_MODULE",
9277 static const char* module_cmds_str
[] = {
9281 static const char* field_cmds_str
[] = {
9285 static const char* method_cmds_str
[] = {
9287 "GET_DECLARING_TYPE",
9295 "MAKE_GENERIC_METHOD"
9298 static const char* type_cmds_str
[] = {
9306 "IS_ASSIGNABLE_FROM",
9310 "GET_PROPERTY_CATTRS",
9311 "GET_SOURCE_FILES_2",
9313 "GET_METHODS_BY_NAME_FLAGS",
9315 "GET_INTERFACE_MAP",
9319 static const char* stack_frame_cmds_str
[] = {
9325 static const char* array_cmds_str
[] = {
9331 static const char* string_cmds_str
[] = {
9337 static const char* object_cmds_str
[] = {
9348 cmd_to_string (CommandSet set
, int command
)
9356 cmds_len
= G_N_ELEMENTS (vm_cmds_str
);
9358 case CMD_SET_OBJECT_REF
:
9359 cmds
= object_cmds_str
;
9360 cmds_len
= G_N_ELEMENTS (object_cmds_str
);
9362 case CMD_SET_STRING_REF
:
9363 cmds
= string_cmds_str
;
9364 cmds_len
= G_N_ELEMENTS (string_cmds_str
);
9366 case CMD_SET_THREAD
:
9367 cmds
= thread_cmds_str
;
9368 cmds_len
= G_N_ELEMENTS (thread_cmds_str
);
9370 case CMD_SET_ARRAY_REF
:
9371 cmds
= array_cmds_str
;
9372 cmds_len
= G_N_ELEMENTS (array_cmds_str
);
9374 case CMD_SET_EVENT_REQUEST
:
9375 cmds
= event_cmds_str
;
9376 cmds_len
= G_N_ELEMENTS (event_cmds_str
);
9378 case CMD_SET_STACK_FRAME
:
9379 cmds
= stack_frame_cmds_str
;
9380 cmds_len
= G_N_ELEMENTS (stack_frame_cmds_str
);
9382 case CMD_SET_APPDOMAIN
:
9383 cmds
= appdomain_cmds_str
;
9384 cmds_len
= G_N_ELEMENTS (appdomain_cmds_str
);
9386 case CMD_SET_ASSEMBLY
:
9387 cmds
= assembly_cmds_str
;
9388 cmds_len
= G_N_ELEMENTS (assembly_cmds_str
);
9390 case CMD_SET_METHOD
:
9391 cmds
= method_cmds_str
;
9392 cmds_len
= G_N_ELEMENTS (method_cmds_str
);
9395 cmds
= type_cmds_str
;
9396 cmds_len
= G_N_ELEMENTS (type_cmds_str
);
9398 case CMD_SET_MODULE
:
9399 cmds
= module_cmds_str
;
9400 cmds_len
= G_N_ELEMENTS (module_cmds_str
);
9403 cmds
= field_cmds_str
;
9404 cmds_len
= G_N_ELEMENTS (field_cmds_str
);
9407 cmds
= event_cmds_str
;
9408 cmds_len
= G_N_ELEMENTS (event_cmds_str
);
9413 if (command
> 0 && command
<= cmds_len
)
9414 return cmds
[command
- 1];
9420 wait_for_attach (void)
9422 #ifndef DISABLE_SOCKET_TRANSPORT
9423 if (listen_fd
== -1) {
9424 DEBUG (1, fprintf (log_file
, "[dbg] Invalid listening socket\n"));
9428 /* Block and wait for client connection */
9429 conn_fd
= socket_transport_accept (listen_fd
);
9430 DEBUG (1, fprintf (log_file
, "Accepted connection on %d\n", conn_fd
));
9431 if (conn_fd
== -1) {
9432 DEBUG (1, fprintf (log_file
, "[dbg] Bad client connection\n"));
9436 g_assert_not_reached ();
9440 disconnected
= !transport_handshake ();
9442 DEBUG (1, fprintf (log_file
, "Transport handshake failed!\n"));
9452 * This thread handles communication with the debugger client using a JDWP
9455 static guint32 WINAPI
9456 debugger_thread (void *arg
)
9458 int res
, len
, id
, flags
, command_set
= 0, command
= 0;
9459 guint8 header
[HEADER_LENGTH
];
9460 guint8
*data
, *p
, *end
;
9464 gboolean attach_failed
= FALSE
;
9466 DEBUG (1, fprintf (log_file
, "[dbg] Agent thread started, pid=%p\n", (gpointer
)GetCurrentThreadId ()));
9468 debugger_thread_id
= GetCurrentThreadId ();
9470 mono_jit_thread_attach (mono_get_root_domain ());
9472 mono_thread_internal_current ()->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
9474 mono_set_is_debugger_attached (TRUE
);
9476 if (agent_config
.defer
) {
9477 if (!wait_for_attach ()) {
9478 DEBUG (1, fprintf (log_file
, "[dbg] Can't attach, aborting debugger thread.\n"));
9479 attach_failed
= TRUE
; // Don't abort process when we can't listen
9481 /* Send start event to client */
9482 process_profiler_event (EVENT_KIND_VM_START
, mono_thread_get_main ());
9486 while (!attach_failed
) {
9487 res
= transport_recv (header
, HEADER_LENGTH
);
9489 /* This will break if the socket is closed during shutdown too */
9490 if (res
!= HEADER_LENGTH
) {
9491 DEBUG (1, fprintf (log_file
, "[dbg] transport_recv () returned %d, expected %d.\n", res
, HEADER_LENGTH
));
9496 end
= header
+ HEADER_LENGTH
;
9498 len
= decode_int (p
, &p
, end
);
9499 id
= decode_int (p
, &p
, end
);
9500 flags
= decode_byte (p
, &p
, end
);
9501 command_set
= decode_byte (p
, &p
, end
);
9502 command
= decode_byte (p
, &p
, end
);
9504 g_assert (flags
== 0);
9507 const char *cmd_str
;
9510 cmd_str
= cmd_to_string (command_set
, command
);
9512 sprintf (cmd_num
, "%d", command
);
9516 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));
9519 data
= g_malloc (len
- HEADER_LENGTH
);
9520 if (len
- HEADER_LENGTH
> 0)
9522 res
= transport_recv (data
, len
- HEADER_LENGTH
);
9523 if (res
!= len
- HEADER_LENGTH
) {
9524 DEBUG (1, fprintf (log_file
, "[dbg] transport_recv () returned %d, expected %d.\n", res
, len
- HEADER_LENGTH
));
9530 end
= data
+ (len
- HEADER_LENGTH
);
9532 buffer_init (&buf
, 128);
9537 /* Process the request */
9538 switch (command_set
) {
9540 err
= vm_commands (command
, id
, p
, end
, &buf
);
9541 if (!err
&& command
== CMD_VM_INVOKE_METHOD
)
9542 /* Sent after the invoke is complete */
9545 case CMD_SET_EVENT_REQUEST
:
9546 err
= event_commands (command
, p
, end
, &buf
);
9548 case CMD_SET_APPDOMAIN
:
9549 err
= domain_commands (command
, p
, end
, &buf
);
9551 case CMD_SET_ASSEMBLY
:
9552 err
= assembly_commands (command
, p
, end
, &buf
);
9554 case CMD_SET_MODULE
:
9555 err
= module_commands (command
, p
, end
, &buf
);
9558 err
= field_commands (command
, p
, end
, &buf
);
9561 err
= type_commands (command
, p
, end
, &buf
);
9563 case CMD_SET_METHOD
:
9564 err
= method_commands (command
, p
, end
, &buf
);
9566 case CMD_SET_THREAD
:
9567 err
= thread_commands (command
, p
, end
, &buf
);
9569 case CMD_SET_STACK_FRAME
:
9570 err
= frame_commands (command
, p
, end
, &buf
);
9572 case CMD_SET_ARRAY_REF
:
9573 err
= array_commands (command
, p
, end
, &buf
);
9575 case CMD_SET_STRING_REF
:
9576 err
= string_commands (command
, p
, end
, &buf
);
9578 case CMD_SET_OBJECT_REF
:
9579 err
= object_commands (command
, p
, end
, &buf
);
9582 err
= ERR_NOT_IMPLEMENTED
;
9585 if (command_set
== CMD_SET_VM
&& command
== CMD_VM_START_BUFFERING
) {
9586 buffer_replies
= TRUE
;
9590 if (buffer_replies
) {
9591 buffer_reply_packet (id
, err
, &buf
);
9593 send_reply_packet (id
, err
, &buf
);
9594 //DEBUG (1, fprintf (log_file, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000));
9598 if (!err
&& command_set
== CMD_SET_VM
&& command
== CMD_VM_STOP_BUFFERING
) {
9599 send_buffered_reply_packets ();
9600 buffer_replies
= FALSE
;
9606 if (command_set
== CMD_SET_VM
&& (command
== CMD_VM_DISPOSE
|| command
== CMD_VM_EXIT
))
9610 mono_set_is_debugger_attached (FALSE
);
9612 mono_mutex_lock (&debugger_thread_exited_mutex
);
9613 debugger_thread_exited
= TRUE
;
9614 mono_cond_signal (&debugger_thread_exited_cond
);
9615 mono_mutex_unlock (&debugger_thread_exited_mutex
);
9617 DEBUG (1, fprintf (log_file
, "[dbg] Debugger thread exited.\n"));
9619 if (!attach_failed
&& command_set
== CMD_SET_VM
&& command
== CMD_VM_DISPOSE
&& !(vm_death_event_sent
|| mono_runtime_is_shutting_down ())) {
9620 DEBUG (2, fprintf (log_file
, "[dbg] Detached - restarting clean debugger thread.\n"));
9621 start_debugger_thread ();
9627 #else /* DISABLE_DEBUGGER_AGENT */
9630 mono_debugger_agent_parse_options (char *options
)
9632 g_error ("This runtime is configured with the debugger agent disabled.");
9636 mono_debugger_agent_init (void)
9641 mono_debugger_agent_breakpoint_hit (void *sigctx
)
9646 mono_debugger_agent_single_step_event (void *sigctx
)
9651 mono_debugger_agent_free_domain_info (MonoDomain
*domain
)
9656 mono_debugger_agent_thread_interrupt (void *sigctx
, MonoJitInfo
*ji
)
9662 mono_debugger_agent_handle_exception (MonoException
*ext
, MonoContext
*throw_ctx
,
9663 MonoContext
*catch_ctx
)
9668 mono_debugger_agent_begin_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
9673 mono_debugger_agent_end_exception_filter (MonoException
*exc
, MonoContext
*ctx
, MonoContext
*orig_ctx
)
9678 mono_debugger_agent_user_break (void)
9684 mono_debugger_agent_debug_log (int level
, MonoString
*category
, MonoString
*message
)
9689 mono_debugger_agent_debug_log_is_enabled (void)