Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / mini / debugger-agent.c
blob2fab2d77082bbf64c8c9e91d468fefd5bcbc9440
1 /**
2 * \file
3 * Soft Debugger back-end module
5 * Author:
6 * Zoltan Varga (vargaz@gmail.com)
8 * Copyright 2009-2010 Novell, Inc.
9 * Copyright 2011 Xamarin Inc.
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
19 #endif
20 #ifdef HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23 #ifdef HAVE_SYS_SOCKET_H
24 #include <sys/socket.h>
25 #endif
26 #ifdef HAVE_NETINET_TCP_H
27 #include <netinet/tcp.h>
28 #endif
29 #ifdef HAVE_NETINET_IN_H
30 #include <netinet/in.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #include <errno.h>
36 #include <glib.h>
38 #ifdef HAVE_PTHREAD_H
39 #include <pthread.h>
40 #endif
42 #ifdef HOST_WIN32
43 #ifdef _MSC_VER
44 #include <winsock2.h>
45 #include <process.h>
46 #endif
47 #include <ws2tcpip.h>
48 #include <windows.h>
49 #endif
51 #ifdef HOST_ANDROID
52 #include <linux/in.h>
53 #include <linux/tcp.h>
54 #include <sys/endian.h>
55 #endif
57 #include <mono/metadata/mono-debug.h>
58 #include <mono/metadata/debug-internals.h>
59 #include <mono/metadata/domain-internals.h>
60 #include <mono/metadata/gc-internals.h>
61 #include <mono/metadata/environment.h>
62 #include <mono/metadata/mono-hash-internals.h>
63 #include <mono/metadata/threads-types.h>
64 #include <mono/metadata/threadpool.h>
65 #include <mono/metadata/assembly.h>
66 #include <mono/metadata/assembly-internals.h>
67 #include <mono/metadata/runtime.h>
68 #include <mono/metadata/verify-internals.h>
69 #include <mono/metadata/reflection-internals.h>
70 #include <mono/metadata/w32socket.h>
71 #include <mono/utils/mono-coop-mutex.h>
72 #include <mono/utils/mono-coop-semaphore.h>
73 #include <mono/utils/mono-error-internals.h>
74 #include <mono/utils/mono-stack-unwinding.h>
75 #include <mono/utils/mono-time.h>
76 #include <mono/utils/mono-threads.h>
77 #include <mono/utils/networking.h>
78 #include <mono/utils/mono-proclib.h>
79 #include <mono/utils/w32api.h>
80 #include <mono/utils/mono-logger-internals.h>
81 #include "debugger-state-machine.h"
82 #include "debugger-agent.h"
83 #include "mini.h"
84 #include "seq-points.h"
85 #include "aot-runtime.h"
86 #include "mini-runtime.h"
87 #include "interp/interp.h"
88 #include "debugger-engine.h"
89 #include "mono/metadata/debug-mono-ppdb.h"
90 #include "mono/metadata/custom-attrs-internals.h"
93 * On iOS we can't use System.Environment.Exit () as it will do the wrong
94 * shutdown sequence.
96 #if !defined (TARGET_IOS)
97 #define TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
98 #endif
100 #if DISABLE_SOCKETS
101 #define DISABLE_SOCKET_TRANSPORT
102 #endif
104 #ifndef DISABLE_SDB
106 #include <mono/utils/mono-os-mutex.h>
108 #include <fcntl.h>
109 #include <sys/stat.h>
111 #ifndef S_IWUSR
112 #define S_IWUSR S_IWRITE
113 #endif
115 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
117 #if _MSC_VER
118 #pragma warning(disable:4312) // FIXME pointer cast to different size
119 #endif
121 typedef struct {
122 gboolean enabled;
123 char *transport;
124 char *address;
125 int log_level;
126 char *log_file;
127 gboolean suspend;
128 gboolean server;
129 gboolean onuncaught;
130 GSList *onthrow;
131 int timeout;
132 char *launch;
133 gboolean embedding;
134 gboolean defer;
135 int keepalive;
136 gboolean setpgid;
137 } AgentConfig;
139 typedef struct _InvokeData InvokeData;
141 struct _InvokeData
143 int id;
144 int flags;
145 guint8 *p;
146 guint8 *endp;
147 /* This is the context which needs to be restored after the invoke */
148 MonoContext ctx;
149 gboolean has_ctx;
151 * If this is set, invoke this method with the arguments given by ARGS.
153 MonoMethod *method;
154 gpointer *args;
155 guint32 suspend_count;
156 int nmethods;
158 InvokeData *last_invoke;
161 struct _DebuggerTlsData {
162 MonoThreadUnwindState context;
164 /* This is computed on demand when it is requested using the wire protocol */
165 /* It is freed up when the thread is resumed */
166 int frame_count;
167 StackFrame **frames;
169 * Whenever the frame info is up-to-date. If not, compute_frame_info () will need to
170 * re-compute it.
172 gboolean frames_up_to_date;
174 * Points to data about a pending invoke which needs to be executed after the thread
175 * resumes.
177 InvokeData *pending_invoke;
179 * Set to TRUE if this thread is suspended in suspend_current () or it is executing
180 * native code.
182 gboolean suspended;
184 * Signals whenever the thread is in the process of suspending, i.e. it will suspend
185 * within a finite amount of time.
187 gboolean suspending;
189 * Set to TRUE if this thread is suspended in suspend_current ().
191 gboolean really_suspended;
192 /* Used to pass the context to the breakpoint/single step handler */
193 MonoContext handler_ctx;
194 /* Whenever thread_stop () was called for this thread */
195 gboolean terminated;
197 /* Whenever to disable breakpoints (used during invokes) */
198 gboolean disable_breakpoints;
201 * Number of times this thread has been resumed using resume_thread ().
203 guint32 resume_count;
204 guint32 resume_count_internal;
205 guint32 suspend_count;
207 MonoInternalThread *thread;
208 intptr_t thread_id;
211 * Information about the frame which transitioned to native code for running
212 * threads.
214 StackFrameInfo async_last_frame;
217 * The context where the stack walk can be started for running threads.
219 MonoThreadUnwindState async_state;
222 * The context used for filter clauses
224 MonoThreadUnwindState filter_state;
226 gboolean abort_requested;
229 * The current mono_runtime_invoke_checked invocation.
231 InvokeData *invoke;
233 StackFrameInfo catch_frame;
234 gboolean has_catch_frame;
237 * The context which needs to be restored after handling a single step/breakpoint
238 * event. This is the same as the ctx at step/breakpoint site, but includes changes
239 * to caller saved registers done by set_var ().
241 MonoThreadUnwindState restore_state;
242 /* Frames computed from restore_state */
243 int restore_frame_count;
244 StackFrame **restore_frames;
246 /* The currently unloading appdomain */
247 MonoDomain *domain_unloading;
249 // The state that the debugger expects the thread to be in
250 MonoDebuggerThreadState thread_state;
251 MonoStopwatch step_time;
253 gboolean gc_finalizing;
256 typedef struct {
257 const char *name;
258 void (*connect) (const char *address);
259 void (*close1) (void);
260 void (*close2) (void);
261 gboolean (*send) (void *buf, int len);
262 int (*recv) (void *buf, int len);
263 } DebuggerTransport;
266 * Wire Protocol definitions
269 #define HEADER_LENGTH 11
271 #define MAJOR_VERSION 2
272 #define MINOR_VERSION 57
274 typedef enum {
275 CMD_SET_VM = 1,
276 CMD_SET_OBJECT_REF = 9,
277 CMD_SET_STRING_REF = 10,
278 CMD_SET_THREAD = 11,
279 CMD_SET_ARRAY_REF = 13,
280 CMD_SET_EVENT_REQUEST = 15,
281 CMD_SET_STACK_FRAME = 16,
282 CMD_SET_APPDOMAIN = 20,
283 CMD_SET_ASSEMBLY = 21,
284 CMD_SET_METHOD = 22,
285 CMD_SET_TYPE = 23,
286 CMD_SET_MODULE = 24,
287 CMD_SET_FIELD = 25,
288 CMD_SET_EVENT = 64,
289 CMD_SET_POINTER = 65
290 } CommandSet;
292 typedef enum {
293 SUSPEND_POLICY_NONE = 0,
294 SUSPEND_POLICY_EVENT_THREAD = 1,
295 SUSPEND_POLICY_ALL = 2
296 } SuspendPolicy;
298 typedef enum {
299 ERR_NONE = 0,
300 ERR_INVALID_OBJECT = 20,
301 ERR_INVALID_FIELDID = 25,
302 ERR_INVALID_FRAMEID = 30,
303 ERR_NOT_IMPLEMENTED = 100,
304 ERR_NOT_SUSPENDED = 101,
305 ERR_INVALID_ARGUMENT = 102,
306 ERR_UNLOADED = 103,
307 ERR_NO_INVOCATION = 104,
308 ERR_ABSENT_INFORMATION = 105,
309 ERR_NO_SEQ_POINT_AT_IL_OFFSET = 106,
310 ERR_INVOKE_ABORTED = 107,
311 ERR_LOADER_ERROR = 200, /*XXX extend the protocol to pass this information down the pipe */
312 } ErrorCode;
314 typedef enum {
315 TOKEN_TYPE_STRING = 0,
316 TOKEN_TYPE_TYPE = 1,
317 TOKEN_TYPE_FIELD = 2,
318 TOKEN_TYPE_METHOD = 3,
319 TOKEN_TYPE_UNKNOWN = 4
320 } DebuggerTokenType;
322 typedef enum {
323 VALUE_TYPE_ID_NULL = 0xf0,
324 VALUE_TYPE_ID_TYPE = 0xf1,
325 VALUE_TYPE_ID_PARENT_VTYPE = 0xf2,
326 VALUE_TYPE_ID_FIXED_ARRAY = 0xf3
327 } ValueTypeId;
329 typedef enum {
330 FRAME_FLAG_DEBUGGER_INVOKE = 1,
331 FRAME_FLAG_NATIVE_TRANSITION = 2
332 } StackFrameFlags;
334 typedef enum {
335 INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
336 INVOKE_FLAG_SINGLE_THREADED = 2,
337 INVOKE_FLAG_RETURN_OUT_THIS = 4,
338 INVOKE_FLAG_RETURN_OUT_ARGS = 8,
339 INVOKE_FLAG_VIRTUAL = 16
340 } InvokeFlags;
342 typedef enum {
343 BINDING_FLAGS_IGNORE_CASE = 0x70000000,
344 } BindingFlagsExtensions;
346 typedef enum {
347 CMD_VM_VERSION = 1,
348 CMD_VM_ALL_THREADS = 2,
349 CMD_VM_SUSPEND = 3,
350 CMD_VM_RESUME = 4,
351 CMD_VM_EXIT = 5,
352 CMD_VM_DISPOSE = 6,
353 CMD_VM_INVOKE_METHOD = 7,
354 CMD_VM_SET_PROTOCOL_VERSION = 8,
355 CMD_VM_ABORT_INVOKE = 9,
356 CMD_VM_SET_KEEPALIVE = 10,
357 CMD_VM_GET_TYPES_FOR_SOURCE_FILE = 11,
358 CMD_VM_GET_TYPES = 12,
359 CMD_VM_INVOKE_METHODS = 13,
360 CMD_VM_START_BUFFERING = 14,
361 CMD_VM_STOP_BUFFERING = 15
362 } CmdVM;
364 typedef enum {
365 CMD_THREAD_GET_FRAME_INFO = 1,
366 CMD_THREAD_GET_NAME = 2,
367 CMD_THREAD_GET_STATE = 3,
368 CMD_THREAD_GET_INFO = 4,
369 CMD_THREAD_GET_ID = 5,
370 CMD_THREAD_GET_TID = 6,
371 CMD_THREAD_SET_IP = 7,
372 CMD_THREAD_ELAPSED_TIME = 8
373 } CmdThread;
375 typedef enum {
376 CMD_EVENT_REQUEST_SET = 1,
377 CMD_EVENT_REQUEST_CLEAR = 2,
378 CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS = 3
379 } CmdEvent;
381 typedef enum {
382 CMD_COMPOSITE = 100
383 } CmdComposite;
385 typedef enum {
386 CMD_APPDOMAIN_GET_ROOT_DOMAIN = 1,
387 CMD_APPDOMAIN_GET_FRIENDLY_NAME = 2,
388 CMD_APPDOMAIN_GET_ASSEMBLIES = 3,
389 CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY = 4,
390 CMD_APPDOMAIN_CREATE_STRING = 5,
391 CMD_APPDOMAIN_GET_CORLIB = 6,
392 CMD_APPDOMAIN_CREATE_BOXED_VALUE = 7,
393 CMD_APPDOMAIN_CREATE_BYTE_ARRAY = 8,
394 } CmdAppDomain;
396 typedef enum {
397 CMD_ASSEMBLY_GET_LOCATION = 1,
398 CMD_ASSEMBLY_GET_ENTRY_POINT = 2,
399 CMD_ASSEMBLY_GET_MANIFEST_MODULE = 3,
400 CMD_ASSEMBLY_GET_OBJECT = 4,
401 CMD_ASSEMBLY_GET_TYPE = 5,
402 CMD_ASSEMBLY_GET_NAME = 6,
403 CMD_ASSEMBLY_GET_DOMAIN = 7,
404 CMD_ASSEMBLY_GET_METADATA_BLOB = 8,
405 CMD_ASSEMBLY_GET_IS_DYNAMIC = 9,
406 CMD_ASSEMBLY_GET_PDB_BLOB = 10,
407 CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN = 11,
408 CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN = 12,
409 CMD_ASSEMBLY_HAS_DEBUG_INFO = 13
410 } CmdAssembly;
412 typedef enum {
413 CMD_MODULE_GET_INFO = 1,
414 } CmdModule;
416 typedef enum {
417 CMD_FIELD_GET_INFO = 1,
418 } CmdField;
420 typedef enum {
421 CMD_METHOD_GET_NAME = 1,
422 CMD_METHOD_GET_DECLARING_TYPE = 2,
423 CMD_METHOD_GET_DEBUG_INFO = 3,
424 CMD_METHOD_GET_PARAM_INFO = 4,
425 CMD_METHOD_GET_LOCALS_INFO = 5,
426 CMD_METHOD_GET_INFO = 6,
427 CMD_METHOD_GET_BODY = 7,
428 CMD_METHOD_RESOLVE_TOKEN = 8,
429 CMD_METHOD_GET_CATTRS = 9,
430 CMD_METHOD_MAKE_GENERIC_METHOD = 10
431 } CmdMethod;
433 typedef enum {
434 CMD_TYPE_GET_INFO = 1,
435 CMD_TYPE_GET_METHODS = 2,
436 CMD_TYPE_GET_FIELDS = 3,
437 CMD_TYPE_GET_VALUES = 4,
438 CMD_TYPE_GET_OBJECT = 5,
439 CMD_TYPE_GET_SOURCE_FILES = 6,
440 CMD_TYPE_SET_VALUES = 7,
441 CMD_TYPE_IS_ASSIGNABLE_FROM = 8,
442 CMD_TYPE_GET_PROPERTIES = 9,
443 CMD_TYPE_GET_CATTRS = 10,
444 CMD_TYPE_GET_FIELD_CATTRS = 11,
445 CMD_TYPE_GET_PROPERTY_CATTRS = 12,
446 CMD_TYPE_GET_SOURCE_FILES_2 = 13,
447 CMD_TYPE_GET_VALUES_2 = 14,
448 CMD_TYPE_GET_METHODS_BY_NAME_FLAGS = 15,
449 CMD_TYPE_GET_INTERFACES = 16,
450 CMD_TYPE_GET_INTERFACE_MAP = 17,
451 CMD_TYPE_IS_INITIALIZED = 18,
452 CMD_TYPE_CREATE_INSTANCE = 19,
453 CMD_TYPE_GET_VALUE_SIZE = 20
454 } CmdType;
456 typedef enum {
457 CMD_STACK_FRAME_GET_VALUES = 1,
458 CMD_STACK_FRAME_GET_THIS = 2,
459 CMD_STACK_FRAME_SET_VALUES = 3,
460 CMD_STACK_FRAME_GET_DOMAIN = 4,
461 CMD_STACK_FRAME_SET_THIS = 5,
462 } CmdStackFrame;
464 typedef enum {
465 CMD_ARRAY_REF_GET_LENGTH = 1,
466 CMD_ARRAY_REF_GET_VALUES = 2,
467 CMD_ARRAY_REF_SET_VALUES = 3,
468 } CmdArray;
470 typedef enum {
471 CMD_STRING_REF_GET_VALUE = 1,
472 CMD_STRING_REF_GET_LENGTH = 2,
473 CMD_STRING_REF_GET_CHARS = 3
474 } CmdString;
476 typedef enum {
477 CMD_POINTER_GET_VALUE = 1
478 } CmdPointer;
480 typedef enum {
481 CMD_OBJECT_REF_GET_TYPE = 1,
482 CMD_OBJECT_REF_GET_VALUES = 2,
483 CMD_OBJECT_REF_IS_COLLECTED = 3,
484 CMD_OBJECT_REF_GET_ADDRESS = 4,
485 CMD_OBJECT_REF_GET_DOMAIN = 5,
486 CMD_OBJECT_REF_SET_VALUES = 6,
487 CMD_OBJECT_REF_GET_INFO = 7,
488 } CmdObject;
491 * Contains additional information for an event
493 typedef struct {
494 /* For EVENT_KIND_EXCEPTION */
495 MonoObject *exc;
496 MonoContext catch_ctx;
497 gboolean caught;
498 /* For EVENT_KIND_USER_LOG */
499 int level;
500 char *category, *message;
501 /* For EVENT_KIND_TYPE_LOAD */
502 MonoClass *klass;
503 /* For EVENT_KIND_CRASH */
504 char *dump;
505 MonoStackHash *hashes;
506 } EventInfo;
508 typedef struct {
509 guint8 *buf, *p, *end;
510 } Buffer;
512 typedef struct ReplyPacket {
513 int id;
514 int error;
515 Buffer *data;
516 } ReplyPacket;
518 #define DEBUG(level,s) do { if (G_UNLIKELY ((level) <= log_level)) { s; fflush (log_file); } } while (0)
520 #ifdef HOST_ANDROID
521 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { g_print (__VA_ARGS__); } } while (0)
522 #else
523 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (log_file, __VA_ARGS__); fflush (log_file); } } while (0)
524 #endif
526 #ifdef HOST_WIN32
527 #define get_last_sock_error() WSAGetLastError()
528 #define MONO_EWOULDBLOCK WSAEWOULDBLOCK
529 #define MONO_EINTR WSAEINTR
530 #else
531 #define get_last_sock_error() errno
532 #define MONO_EWOULDBLOCK EWOULDBLOCK
533 #define MONO_EINTR EINTR
534 #endif
536 #define CHECK_PROTOCOL_VERSION(major,minor) \
537 (protocol_version_set && (major_version > (major) || (major_version == (major) && minor_version >= (minor))))
540 * Globals
543 static AgentConfig agent_config;
546 * Whenever the agent is fully initialized.
547 * When using the onuncaught or onthrow options, only some parts of the agent are
548 * initialized on startup, and the full initialization which includes connection
549 * establishment and the startup of the agent thread is only done in response to
550 * an event.
552 static gint32 agent_inited;
554 #ifndef DISABLE_SOCKET_TRANSPORT
555 static int conn_fd;
556 static int listen_fd;
557 #endif
559 static int packet_id = 0;
561 static int objref_id = 0;
563 static int event_request_id = 0;
565 static int frame_id = 0;
567 static GPtrArray *event_requests;
569 static MonoNativeTlsKey debugger_tls_id;
571 static gboolean vm_start_event_sent, vm_death_event_sent, disconnected;
573 /* Maps MonoInternalThread -> DebuggerTlsData */
574 /* Protected by the loader lock */
575 static MonoGHashTable *thread_to_tls;
577 /* Maps tid -> MonoInternalThread */
578 /* Protected by the loader lock */
579 static MonoGHashTable *tid_to_thread;
581 /* Maps tid -> MonoThread (not MonoInternalThread) */
582 /* Protected by the loader lock */
583 static MonoGHashTable *tid_to_thread_obj;
585 static MonoNativeThreadId debugger_thread_id;
587 static MonoThreadHandle *debugger_thread_handle;
589 static int log_level;
591 static int file_check_valid_memory = -1;
593 static char* filename_check_valid_memory;
595 static gboolean embedding;
597 static FILE *log_file;
599 /* Assemblies whose assembly load event has no been sent yet */
600 /* Protected by the dbg lock */
601 static GPtrArray *pending_assembly_loads;
603 /* Whenever the debugger thread has exited */
604 static gboolean debugger_thread_exited;
606 /* Cond variable used to wait for debugger_thread_exited becoming true */
607 static MonoCoopCond debugger_thread_exited_cond;
609 /* Mutex for the cond var above */
610 static MonoCoopMutex debugger_thread_exited_mutex;
612 /* The protocol version of the client */
613 static int major_version, minor_version;
615 /* Whenever the variables above are set by the client */
616 static gboolean protocol_version_set;
618 /* The number of times the runtime is suspended */
619 static gint32 suspend_count;
621 /* Whenever to buffer reply messages and send them together */
622 static gboolean buffer_replies;
624 /* Buffered reply packets */
625 static ReplyPacket reply_packets [128];
626 static int nreply_packets;
628 #define dbg_lock mono_de_lock
629 #define dbg_unlock mono_de_unlock
631 static void transport_init (void);
632 static void transport_connect (const char *address);
633 static gboolean transport_handshake (void);
634 static void register_transport (DebuggerTransport *trans);
636 static gsize WINAPI debugger_thread (void *arg);
638 static void runtime_initialized (MonoProfiler *prof);
640 static void runtime_shutdown (MonoProfiler *prof);
642 static void thread_startup (MonoProfiler *prof, uintptr_t tid);
644 static void thread_end (MonoProfiler *prof, uintptr_t tid);
646 static void appdomain_load (MonoProfiler *prof, MonoDomain *domain);
648 static void appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain);
650 static void appdomain_unload (MonoProfiler *prof, MonoDomain *domain);
652 static void emit_appdomain_load (gpointer key, gpointer value, gpointer user_data);
654 static void emit_thread_start (gpointer key, gpointer value, gpointer user_data);
656 static void invalidate_each_thread (gpointer key, gpointer value, gpointer user_data);
658 static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly);
660 static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly);
662 static void gc_finalizing (MonoProfiler *prof);
664 static void gc_finalized (MonoProfiler *prof);
666 static void emit_assembly_load (gpointer assembly, gpointer user_data);
668 static void emit_type_load (gpointer key, gpointer type, gpointer user_data);
670 static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
672 static void jit_failed (MonoProfiler *prof, MonoMethod *method);
674 static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo);
676 static void suspend_current (void);
678 static void clear_event_requests_for_assembly (MonoAssembly *assembly);
680 static void clear_types_for_assembly (MonoAssembly *assembly);
682 static void process_profiler_event (EventKind event, gpointer arg);
684 /* Submodule init/cleanup */
685 static void event_requests_cleanup (void);
687 static void objrefs_init (void);
688 static void objrefs_cleanup (void);
690 static void ids_init (void);
691 static void ids_cleanup (void);
693 static void suspend_init (void);
695 static void start_debugger_thread (MonoError *error);
696 static void stop_debugger_thread (void);
698 static void finish_agent_init (gboolean on_startup);
700 static void process_profiler_event (EventKind event, gpointer arg);
702 static void invalidate_frames (DebuggerTlsData *tls);
704 /* Callbacks used by debugger-engine */
705 static MonoContext* tls_get_restore_state (void *the_tls);
706 static gboolean try_process_suspend (void *tls, MonoContext *ctx, gboolean from_breakpoint);
707 static gboolean begin_breakpoint_processing (void *tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal);
708 static void begin_single_step_processing (MonoContext *ctx, gboolean from_signal);
709 static void ss_discard_frame_context (void *the_tls);
710 static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes);
711 static gboolean ensure_jit (DbgEngineStackFrame* the_frame);
712 static int ensure_runtime_is_suspended (void);
713 static int get_this_async_id (DbgEngineStackFrame *frame);
714 static void* create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind);
715 static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset);
716 static int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args);
717 static void ss_args_destroy (SingleStepArgs *ss_args);
718 static int handle_multiple_ss_requests (void);
720 static GENERATE_TRY_GET_CLASS_WITH_CACHE (fixed_buffer, "System.Runtime.CompilerServices", "FixedBufferAttribute")
722 #ifndef DISABLE_SOCKET_TRANSPORT
723 static void
724 register_socket_transport (void);
725 #endif
727 static gboolean
728 is_debugger_thread (void)
730 MonoInternalThread *internal;
732 internal = mono_thread_internal_current ();
733 if (!internal)
734 return FALSE;
736 return internal->debugger_thread;
739 static int
740 parse_address (char *address, char **host, int *port)
742 char *pos = strchr (address, ':');
744 if (pos == NULL || pos == address)
745 return 1;
747 size_t len = pos - address;
748 *host = (char *)g_malloc (len + 1);
749 memcpy (*host, address, len);
750 (*host) [len] = '\0';
752 *port = atoi (pos + 1);
754 return 0;
757 static void
758 print_usage (void)
760 g_printerr ("Usage: mono --debugger-agent=[<option>=<value>,...] ...\n");
761 g_printerr ("Available options:\n");
762 g_printerr (" transport=<transport>\t\tTransport to use for connecting to the debugger (mandatory, possible values: 'dt_socket')\n");
763 g_printerr (" address=<hostname>:<port>\tAddress to connect to (mandatory)\n");
764 g_printerr (" loglevel=<n>\t\t\tLog level (defaults to 0)\n");
765 g_printerr (" logfile=<file>\t\tFile to log to (defaults to stdout)\n");
766 g_printerr (" suspend=y/n\t\t\tWhether to suspend after startup.\n");
767 g_printerr (" timeout=<n>\t\t\tTimeout for connecting in milliseconds.\n");
768 g_printerr (" server=y/n\t\t\tWhether to listen for a client connection.\n");
769 g_printerr (" keepalive=<n>\t\t\tSend keepalive events every n milliseconds.\n");
770 g_printerr (" setpgid=y/n\t\t\tWhether to call setpid(0, 0) after startup.\n");
771 g_printerr (" help\t\t\t\tPrint this help.\n");
774 static gboolean
775 parse_flag (const char *option, char *flag)
777 if (!strcmp (flag, "y"))
778 return TRUE;
779 else if (!strcmp (flag, "n"))
780 return FALSE;
781 else {
782 g_printerr ("debugger-agent: The valid values for the '%s' option are 'y' and 'n'.\n", option);
783 exit (1);
784 return FALSE;
788 static void
789 debugger_agent_parse_options (char *options)
791 char **args, **ptr;
792 char *host;
793 int port;
794 char *extra;
796 #ifndef MONO_ARCH_SOFT_DEBUG_SUPPORTED
797 g_printerr ("--debugger-agent is not supported on this platform.\n");
798 exit (1);
799 #endif
801 extra = g_getenv ("MONO_SDB_ENV_OPTIONS");
802 if (extra) {
803 options = g_strdup_printf ("%s,%s", options, extra);
804 g_free (extra);
807 agent_config.enabled = TRUE;
808 agent_config.suspend = TRUE;
809 agent_config.server = FALSE;
810 agent_config.defer = FALSE;
811 agent_config.address = NULL;
813 //agent_config.log_level = 10;
815 args = g_strsplit (options, ",", -1);
816 for (ptr = args; ptr && *ptr; ptr ++) {
817 char *arg = *ptr;
819 if (strncmp (arg, "transport=", 10) == 0) {
820 agent_config.transport = g_strdup (arg + 10);
821 } else if (strncmp (arg, "address=", 8) == 0) {
822 agent_config.address = g_strdup (arg + 8);
823 } else if (strncmp (arg, "loglevel=", 9) == 0) {
824 agent_config.log_level = atoi (arg + 9);
825 } else if (strncmp (arg, "logfile=", 8) == 0) {
826 agent_config.log_file = g_strdup (arg + 8);
827 } else if (strncmp (arg, "suspend=", 8) == 0) {
828 agent_config.suspend = parse_flag ("suspend", arg + 8);
829 } else if (strncmp (arg, "server=", 7) == 0) {
830 agent_config.server = parse_flag ("server", arg + 7);
831 } else if (strncmp (arg, "onuncaught=", 11) == 0) {
832 agent_config.onuncaught = parse_flag ("onuncaught", arg + 11);
833 } else if (strncmp (arg, "onthrow=", 8) == 0) {
834 /* We support multiple onthrow= options */
835 agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (arg + 8));
836 } else if (strncmp (arg, "onthrow", 7) == 0) {
837 agent_config.onthrow = g_slist_append (agent_config.onthrow, g_strdup (""));
838 } else if (strncmp (arg, "help", 4) == 0) {
839 print_usage ();
840 exit (0);
841 } else if (strncmp (arg, "timeout=", 8) == 0) {
842 agent_config.timeout = atoi (arg + 8);
843 } else if (strncmp (arg, "launch=", 7) == 0) {
844 agent_config.launch = g_strdup (arg + 7);
845 } else if (strncmp (arg, "embedding=", 10) == 0) {
846 agent_config.embedding = atoi (arg + 10) == 1;
847 } else if (strncmp (arg, "keepalive=", 10) == 0) {
848 agent_config.keepalive = atoi (arg + 10);
849 } else if (strncmp (arg, "setpgid=", 8) == 0) {
850 agent_config.setpgid = parse_flag ("setpgid", arg + 8);
851 } else {
852 print_usage ();
853 exit (1);
857 if (agent_config.server && !agent_config.suspend) {
858 /* Waiting for deferred attachment */
859 agent_config.defer = TRUE;
860 if (agent_config.address == NULL) {
861 agent_config.address = g_strdup_printf ("0.0.0.0:%u", 56000 + (mono_process_current_pid () % 1000));
865 //agent_config.log_level = 0;
867 if (agent_config.transport == NULL) {
868 g_printerr ("debugger-agent: The 'transport' option is mandatory.\n");
869 exit (1);
872 if (agent_config.address == NULL && !agent_config.server) {
873 g_printerr ("debugger-agent: The 'address' option is mandatory.\n");
874 exit (1);
877 // FIXME:
878 if (!strcmp (agent_config.transport, "dt_socket")) {
879 if (agent_config.address && parse_address (agent_config.address, &host, &port)) {
880 g_printerr ("debugger-agent: The format of the 'address' options is '<host>:<port>'\n");
881 exit (1);
886 void
887 mono_debugger_set_thread_state (DebuggerTlsData *tls, MonoDebuggerThreadState expected, MonoDebuggerThreadState set)
889 g_assertf (tls, "Cannot get state of null thread", NULL);
891 g_assert (tls->thread_state == expected);
893 tls->thread_state = set;
896 MonoDebuggerThreadState
897 mono_debugger_get_thread_state (DebuggerTlsData *tls)
899 g_assertf (tls, "Cannot get state of null thread", NULL);
901 return tls->thread_state;
904 gsize
905 mono_debugger_tls_thread_id (DebuggerTlsData *tls)
907 if (!tls)
908 return 0;
910 return tls->thread_id;
913 // Only call this function with the loader lock held
914 MonoGHashTable *
915 mono_debugger_get_thread_states (void)
917 return thread_to_tls;
920 gboolean
921 mono_debugger_is_disconnected (void)
923 return disconnected;
926 static void
927 debugger_agent_init (void)
929 if (!agent_config.enabled)
930 return;
932 DebuggerEngineCallbacks cbs;
933 memset (&cbs, 0, sizeof (cbs));
934 cbs.tls_get_restore_state = tls_get_restore_state;
935 cbs.try_process_suspend = try_process_suspend;
936 cbs.begin_breakpoint_processing = begin_breakpoint_processing;
937 cbs.begin_single_step_processing = begin_single_step_processing;
938 cbs.ss_discard_frame_context = ss_discard_frame_context;
939 cbs.ss_calculate_framecount = ss_calculate_framecount;
940 cbs.ensure_jit = ensure_jit;
941 cbs.ensure_runtime_is_suspended = ensure_runtime_is_suspended;
942 cbs.get_this_async_id = get_this_async_id;
943 cbs.set_set_notification_for_wait_completion_flag = set_set_notification_for_wait_completion_flag;
944 cbs.get_notify_debugger_of_wait_completion_method = get_notify_debugger_of_wait_completion_method;
945 cbs.create_breakpoint_events = create_breakpoint_events;
946 cbs.process_breakpoint_events = process_breakpoint_events;
947 cbs.ss_create_init_args = ss_create_init_args;
948 cbs.ss_args_destroy = ss_args_destroy;
949 cbs.handle_multiple_ss_requests = handle_multiple_ss_requests;
951 mono_de_init (&cbs);
953 transport_init ();
955 /* Need to know whenever a thread has acquired the loader mutex */
956 mono_loader_lock_track_ownership (TRUE);
958 event_requests = g_ptr_array_new ();
960 mono_coop_mutex_init (&debugger_thread_exited_mutex);
961 mono_coop_cond_init (&debugger_thread_exited_cond);
963 MonoProfilerHandle prof = mono_profiler_create (NULL);
964 mono_profiler_set_runtime_shutdown_end_callback (prof, runtime_shutdown);
965 mono_profiler_set_runtime_initialized_callback (prof, runtime_initialized);
966 mono_profiler_set_domain_loaded_callback (prof, appdomain_load);
967 mono_profiler_set_domain_unloading_callback (prof, appdomain_start_unload);
968 mono_profiler_set_domain_unloaded_callback (prof, appdomain_unload);
969 mono_profiler_set_thread_started_callback (prof, thread_startup);
970 mono_profiler_set_thread_stopped_callback (prof, thread_end);
971 mono_profiler_set_assembly_loaded_callback (prof, assembly_load);
972 mono_profiler_set_assembly_unloading_callback (prof, assembly_unload);
973 mono_profiler_set_jit_done_callback (prof, jit_done);
974 mono_profiler_set_jit_failed_callback (prof, jit_failed);
975 mono_profiler_set_gc_finalizing_callback (prof, gc_finalizing);
976 mono_profiler_set_gc_finalized_callback (prof, gc_finalized);
978 mono_native_tls_alloc (&debugger_tls_id, NULL);
980 /* Needed by the hash_table_new_type () call below */
981 mono_gc_base_init ();
983 thread_to_tls = mono_g_hash_table_new_type_internal ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger TLS Table");
985 tid_to_thread = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Table");
987 tid_to_thread_obj = mono_g_hash_table_new_type_internal (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Object Table");
989 pending_assembly_loads = g_ptr_array_new ();
991 log_level = agent_config.log_level;
993 embedding = agent_config.embedding;
994 disconnected = TRUE;
996 if (agent_config.log_file) {
997 log_file = fopen (agent_config.log_file, "w+");
998 if (!log_file) {
999 g_printerr ("Unable to create log file '%s': %s.\n", agent_config.log_file, strerror (errno));
1000 exit (1);
1002 } else {
1003 log_file = stdout;
1005 mono_de_set_log_level (log_level, log_file);
1007 ids_init ();
1008 objrefs_init ();
1009 suspend_init ();
1011 mini_get_debug_options ()->gen_sdb_seq_points = TRUE;
1013 * This is needed because currently we don't handle liveness info.
1015 mini_get_debug_options ()->mdb_optimizations = TRUE;
1017 #ifndef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
1018 /* This is needed because we can't set local variables in registers yet */
1019 mono_disable_optimizations (MONO_OPT_LINEARS);
1020 #endif
1023 * The stack walk done from thread_interrupt () needs to be signal safe, but it
1024 * isn't, since it can call into mono_aot_find_jit_info () which is not signal
1025 * safe (#3411). So load AOT info eagerly when the debugger is running as a
1026 * workaround.
1028 mini_get_debug_options ()->load_aot_jit_info_eagerly = TRUE;
1030 #ifdef HAVE_SETPGID
1031 if (agent_config.setpgid)
1032 setpgid (0, 0);
1033 #endif
1035 if (!agent_config.onuncaught && !agent_config.onthrow)
1036 finish_agent_init (TRUE);
1040 * finish_agent_init:
1042 * Finish the initialization of the agent. This involves connecting the transport
1043 * and starting the agent thread. This is either done at startup, or
1044 * in response to some event like an unhandled exception.
1046 static void
1047 finish_agent_init (gboolean on_startup)
1049 if (mono_atomic_cas_i32 (&agent_inited, 1, 0) == 1)
1050 return;
1052 if (agent_config.launch) {
1054 // FIXME: Generated address
1055 // FIXME: Races with transport_connect ()
1057 #ifdef G_OS_WIN32
1058 // Nothing. FIXME? g_spawn_async_with_pipes is easy enough to provide for Windows if needed.
1059 #elif !HAVE_G_SPAWN
1060 g_printerr ("g_spawn_async_with_pipes not supported on this platform\n");
1061 exit (1);
1062 #else
1063 char *argv [ ] = {
1064 agent_config.launch,
1065 agent_config.transport,
1066 agent_config.address,
1067 NULL
1069 int res = g_spawn_async_with_pipes (NULL, argv, NULL, (GSpawnFlags)0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1070 if (!res) {
1071 g_printerr ("Failed to execute '%s'.\n", agent_config.launch);
1072 exit (1);
1074 #endif
1077 transport_connect (agent_config.address);
1079 if (!on_startup) {
1080 /* Do some which is usually done after sending the VMStart () event */
1081 vm_start_event_sent = TRUE;
1082 ERROR_DECL (error);
1083 start_debugger_thread (error);
1084 mono_error_assert_ok (error);
1088 static void
1089 mono_debugger_agent_cleanup (void)
1091 if (!agent_inited)
1092 return;
1094 stop_debugger_thread ();
1096 event_requests_cleanup ();
1097 objrefs_cleanup ();
1098 ids_cleanup ();
1100 mono_de_cleanup ();
1102 if (file_check_valid_memory != -1) {
1103 remove (filename_check_valid_memory);
1104 g_free (filename_check_valid_memory);
1105 close (file_check_valid_memory);
1110 * SOCKET TRANSPORT
1113 #ifndef DISABLE_SOCKET_TRANSPORT
1116 * recv_length:
1118 * recv() + handle incomplete reads and EINTR
1120 static int
1121 socket_transport_recv (void *buf, int len)
1123 int res;
1124 int total = 0;
1125 int fd = conn_fd;
1126 int flags = 0;
1127 static gint64 last_keepalive;
1128 gint64 msecs;
1130 MONO_ENTER_GC_SAFE;
1132 do {
1133 again:
1134 res = recv (fd, (char *) buf + total, len - total, flags);
1135 if (res > 0)
1136 total += res;
1137 if (agent_config.keepalive) {
1138 gboolean need_keepalive = FALSE;
1139 if (res == -1 && get_last_sock_error () == MONO_EWOULDBLOCK) {
1140 need_keepalive = TRUE;
1141 } else if (res == -1) {
1142 /* This could happen if recv () is interrupted repeatedly */
1143 msecs = mono_msec_ticks ();
1144 if (msecs - last_keepalive >= agent_config.keepalive) {
1145 need_keepalive = TRUE;
1146 last_keepalive = msecs;
1149 if (need_keepalive) {
1150 process_profiler_event (EVENT_KIND_KEEPALIVE, NULL);
1151 goto again;
1154 } while ((res > 0 && total < len) || (res == -1 && get_last_sock_error () == MONO_EINTR));
1156 MONO_EXIT_GC_SAFE;
1158 return total;
1161 static void
1162 set_keepalive (void)
1164 struct timeval tv;
1165 int result;
1167 if (!agent_config.keepalive || !conn_fd)
1168 return;
1170 tv.tv_sec = agent_config.keepalive / 1000;
1171 tv.tv_usec = (agent_config.keepalive % 1000) * 1000;
1173 result = setsockopt (conn_fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(struct timeval));
1174 g_assert (result >= 0);
1177 static int
1178 socket_transport_accept (int socket_fd)
1180 MONO_ENTER_GC_SAFE;
1181 conn_fd = accept (socket_fd, NULL, NULL);
1182 MONO_EXIT_GC_SAFE;
1184 if (conn_fd == -1) {
1185 g_printerr ("debugger-agent: Unable to listen on %d\n", socket_fd);
1186 } else {
1187 DEBUG_PRINTF (1, "Accepted connection from client, connection fd=%d.\n", conn_fd);
1190 return conn_fd;
1193 static gboolean
1194 socket_transport_send (void *data, int len)
1196 int res;
1198 MONO_ENTER_GC_SAFE;
1200 do {
1201 res = send (conn_fd, (const char*)data, len, 0);
1202 } while (res == -1 && get_last_sock_error () == MONO_EINTR);
1204 MONO_EXIT_GC_SAFE;
1206 if (res != len)
1207 return FALSE;
1208 else
1209 return TRUE;
1213 * socket_transport_connect:
1215 * Connect/Listen on HOST:PORT. If HOST is NULL, generate an address and listen on it.
1217 static void
1218 socket_transport_connect (const char *address)
1220 MonoAddressInfo *result;
1221 MonoAddressEntry *rp;
1222 int sfd = -1, s, res;
1223 char *host;
1224 int port;
1226 if (agent_config.address) {
1227 res = parse_address (agent_config.address, &host, &port);
1228 g_assert (res == 0);
1229 } else {
1230 host = NULL;
1231 port = 0;
1234 conn_fd = -1;
1235 listen_fd = -1;
1237 if (host) {
1238 int hints[] = {
1239 MONO_HINT_IPV4 | MONO_HINT_NUMERIC_HOST,
1240 MONO_HINT_IPV6 | MONO_HINT_NUMERIC_HOST,
1241 MONO_HINT_UNSPECIFIED
1244 mono_network_init ();
1246 for (int i = 0; i < sizeof(hints) / sizeof(int); i++) {
1247 /* Obtain address(es) matching host/port */
1248 s = mono_get_address_info (host, port, hints[i], &result);
1249 if (s == 0)
1250 break;
1252 if (s != 0) {
1253 g_printerr ("debugger-agent: Unable to resolve %s:%d: %d\n", host, port, s); // FIXME add portable error conversion functions
1254 exit (1);
1258 if (agent_config.server) {
1259 /* Wait for a connection */
1260 if (!host) {
1261 struct sockaddr_in addr;
1262 socklen_t addrlen;
1264 /* No address, generate one */
1265 sfd = socket (AF_INET, SOCK_STREAM, 0);
1266 if (sfd == -1) {
1267 g_printerr ("debugger-agent: Unable to create a socket: %s\n", strerror (get_last_sock_error ()));
1268 exit (1);
1271 /* This will bind the socket to a random port */
1272 res = listen (sfd, 16);
1273 if (res == -1) {
1274 g_printerr ("debugger-agent: Unable to setup listening socket: %s\n", strerror (get_last_sock_error ()));
1275 exit (1);
1277 listen_fd = sfd;
1279 addrlen = sizeof (addr);
1280 memset (&addr, 0, sizeof (addr));
1281 res = getsockname (sfd, (struct sockaddr*)&addr, &addrlen);
1282 g_assert (res == 0);
1284 host = (char*)"127.0.0.1";
1285 port = ntohs (addr.sin_port);
1287 /* Emit the address to stdout */
1288 /* FIXME: Should print another interface, not localhost */
1289 printf ("%s:%d\n", host, port);
1290 } else {
1291 /* Listen on the provided address */
1292 for (rp = result->entries; rp != NULL; rp = rp->next) {
1293 MonoSocketAddress sockaddr;
1294 socklen_t sock_len;
1295 int n = 1;
1297 mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
1299 sfd = socket (rp->family, rp->socktype,
1300 rp->protocol);
1301 if (sfd == -1)
1302 continue;
1304 if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&n, sizeof(n)) == -1)
1305 continue;
1307 res = bind (sfd, &sockaddr.addr, sock_len);
1308 if (res == -1)
1309 continue;
1311 res = listen (sfd, 16);
1312 if (res == -1)
1313 continue;
1314 listen_fd = sfd;
1315 break;
1318 mono_free_address_info (result);
1321 if (agent_config.defer)
1322 return;
1324 DEBUG_PRINTF (1, "Listening on %s:%d (timeout=%d ms)...\n", host, port, agent_config.timeout);
1326 if (agent_config.timeout) {
1327 fd_set readfds;
1328 struct timeval tv;
1330 tv.tv_sec = 0;
1331 tv.tv_usec = agent_config.timeout * 1000;
1332 FD_ZERO (&readfds);
1333 FD_SET (sfd, &readfds);
1335 MONO_ENTER_GC_SAFE;
1336 res = select (sfd + 1, &readfds, NULL, NULL, &tv);
1337 MONO_EXIT_GC_SAFE;
1339 if (res == 0) {
1340 g_printerr ("debugger-agent: Timed out waiting to connect.\n");
1341 exit (1);
1345 conn_fd = socket_transport_accept (sfd);
1346 if (conn_fd == -1)
1347 exit (1);
1349 DEBUG_PRINTF (1, "Accepted connection from client, socket fd=%d.\n", conn_fd);
1350 } else {
1351 /* Connect to the specified address */
1352 /* FIXME: Respect the timeout */
1353 for (rp = result->entries; rp != NULL; rp = rp->next) {
1354 MonoSocketAddress sockaddr;
1355 socklen_t sock_len;
1357 mono_socket_address_init (&sockaddr, &sock_len, rp->family, &rp->address, port);
1359 sfd = socket (rp->family, rp->socktype,
1360 rp->protocol);
1361 if (sfd == -1)
1362 continue;
1364 MONO_ENTER_GC_SAFE;
1365 res = connect (sfd, &sockaddr.addr, sock_len);
1366 MONO_EXIT_GC_SAFE;
1368 if (res != -1)
1369 break; /* Success */
1371 MONO_ENTER_GC_SAFE;
1372 #ifdef HOST_WIN32
1373 closesocket (sfd);
1374 #else
1375 close (sfd);
1376 #endif
1377 MONO_EXIT_GC_SAFE;
1380 if (rp == 0) {
1381 g_printerr ("debugger-agent: Unable to connect to %s:%d\n", host, port);
1382 exit (1);
1385 conn_fd = sfd;
1387 mono_free_address_info (result);
1390 if (!transport_handshake ())
1391 exit (1);
1394 static void
1395 socket_transport_close1 (void)
1397 /* This will interrupt the agent thread */
1398 /* Close the read part only so it can still send back replies */
1399 /* Also shut down the connection listener so that we can exit normally */
1400 #ifdef HOST_WIN32
1401 /* SD_RECEIVE doesn't break the recv in the debugger thread */
1402 shutdown (conn_fd, SD_BOTH);
1403 shutdown (listen_fd, SD_BOTH);
1404 closesocket (listen_fd);
1405 #else
1406 shutdown (conn_fd, SHUT_RD);
1407 shutdown (listen_fd, SHUT_RDWR);
1408 MONO_ENTER_GC_SAFE;
1409 close (listen_fd);
1410 MONO_EXIT_GC_SAFE;
1411 #endif
1414 static void
1415 socket_transport_close2 (void)
1417 #ifdef HOST_WIN32
1418 shutdown (conn_fd, SD_BOTH);
1419 #else
1420 shutdown (conn_fd, SHUT_RDWR);
1421 #endif
1424 static void
1425 register_socket_transport (void)
1427 DebuggerTransport trans;
1429 trans.name = "dt_socket";
1430 trans.connect = socket_transport_connect;
1431 trans.close1 = socket_transport_close1;
1432 trans.close2 = socket_transport_close2;
1433 trans.send = socket_transport_send;
1434 trans.recv = socket_transport_recv;
1436 register_transport (&trans);
1440 * socket_fd_transport_connect:
1443 static void
1444 socket_fd_transport_connect (const char *address)
1446 int res;
1448 res = sscanf (address, "%d", &conn_fd);
1449 if (res != 1) {
1450 g_printerr ("debugger-agent: socket-fd transport address is invalid: '%s'\n", address);
1451 exit (1);
1454 if (!transport_handshake ())
1455 exit (1);
1458 static void
1459 register_socket_fd_transport (void)
1461 DebuggerTransport trans;
1463 /* This is the same as the 'dt_socket' transport, but receives an already connected socket fd */
1464 trans.name = "socket-fd";
1465 trans.connect = socket_fd_transport_connect;
1466 trans.close1 = socket_transport_close1;
1467 trans.close2 = socket_transport_close2;
1468 trans.send = socket_transport_send;
1469 trans.recv = socket_transport_recv;
1471 register_transport (&trans);
1474 #endif /* DISABLE_SOCKET_TRANSPORT */
1477 * TRANSPORT CODE
1480 #define MAX_TRANSPORTS 16
1482 static DebuggerTransport *transport;
1484 static DebuggerTransport transports [MAX_TRANSPORTS];
1485 static int ntransports;
1487 MONO_API void
1488 mono_debugger_agent_register_transport (DebuggerTransport *trans);
1490 void
1491 mono_debugger_agent_register_transport (DebuggerTransport *trans)
1493 register_transport (trans);
1496 static void
1497 register_transport (DebuggerTransport *trans)
1499 g_assert (ntransports < MAX_TRANSPORTS);
1501 memcpy (&transports [ntransports], trans, sizeof (DebuggerTransport));
1502 ntransports ++;
1505 static void
1506 transport_init (void)
1508 int i;
1510 #ifndef DISABLE_SOCKET_TRANSPORT
1511 register_socket_transport ();
1512 register_socket_fd_transport ();
1513 #endif
1515 for (i = 0; i < ntransports; ++i) {
1516 if (!strcmp (agent_config.transport, transports [i].name))
1517 break;
1519 if (i == ntransports) {
1520 g_printerr ("debugger-agent: The supported values for the 'transport' option are: ");
1521 for (i = 0; i < ntransports; ++i)
1522 g_printerr ("%s'%s'", i > 0 ? ", " : "", transports [i].name);
1523 g_printerr ("\n");
1524 exit (1);
1526 transport = &transports [i];
1529 void
1530 transport_connect (const char *address)
1532 transport->connect (address);
1535 static void
1536 transport_close1 (void)
1538 transport->close1 ();
1541 static void
1542 transport_close2 (void)
1544 transport->close2 ();
1547 static int
1548 transport_send (void *buf, int len)
1550 return transport->send (buf, len);
1553 static int
1554 transport_recv (void *buf, int len)
1556 return transport->recv (buf, len);
1559 gboolean
1560 mono_debugger_agent_transport_handshake (void)
1562 return transport_handshake ();
1565 static gboolean
1566 transport_handshake (void)
1568 char handshake_msg [128];
1569 guint8 buf [128];
1570 int res;
1572 disconnected = TRUE;
1574 /* Write handshake message */
1575 sprintf (handshake_msg, "DWP-Handshake");
1577 do {
1578 res = transport_send (handshake_msg, strlen (handshake_msg));
1579 } while (res == -1 && get_last_sock_error () == MONO_EINTR);
1581 g_assert (res != -1);
1583 /* Read answer */
1584 res = transport_recv (buf, strlen (handshake_msg));
1585 if ((res != strlen (handshake_msg)) || (memcmp (buf, handshake_msg, strlen (handshake_msg)) != 0)) {
1586 g_printerr ("debugger-agent: DWP handshake failed.\n");
1587 return FALSE;
1591 * To support older clients, the client sends its protocol version after connecting
1592 * using a command. Until that is received, default to our protocol version.
1594 major_version = MAJOR_VERSION;
1595 minor_version = MINOR_VERSION;
1596 protocol_version_set = FALSE;
1598 #ifndef DISABLE_SOCKET_TRANSPORT
1599 // FIXME: Move this somewhere else
1601 * Set TCP_NODELAY on the socket so the client receives events/command
1602 * results immediately.
1604 if (conn_fd) {
1605 int flag = 1;
1606 int result = setsockopt (conn_fd,
1607 IPPROTO_TCP,
1608 TCP_NODELAY,
1609 (char *) &flag,
1610 sizeof(int));
1611 g_assert (result >= 0);
1614 set_keepalive ();
1615 #endif
1617 disconnected = FALSE;
1618 return TRUE;
1621 static void
1622 stop_debugger_thread (void)
1624 if (!agent_inited)
1625 return;
1627 transport_close1 ();
1630 * Wait for the thread to exit.
1632 * If we continue with the shutdown without waiting for it, then the client might
1633 * not receive an answer to its last command like a resume.
1635 if (!is_debugger_thread ()) {
1636 do {
1637 mono_coop_mutex_lock (&debugger_thread_exited_mutex);
1638 if (!debugger_thread_exited)
1639 mono_coop_cond_wait (&debugger_thread_exited_cond, &debugger_thread_exited_mutex);
1640 mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
1641 } while (!debugger_thread_exited);
1643 if (debugger_thread_handle)
1644 mono_thread_info_wait_one_handle (debugger_thread_handle, MONO_INFINITE_WAIT, TRUE);
1647 transport_close2 ();
1650 static void
1651 start_debugger_thread (MonoError *error)
1653 MonoInternalThread *thread;
1655 thread = mono_thread_create_internal (mono_get_root_domain (), (gpointer)debugger_thread, NULL, MONO_THREAD_CREATE_FLAGS_DEBUGGER, error);
1656 return_if_nok (error);
1658 /* Is it possible for the thread to be dead alreay ? */
1659 debugger_thread_handle = mono_threads_open_thread_handle (thread->handle);
1660 g_assert (debugger_thread_handle);
1665 * Functions to decode protocol data
1668 static int
1669 decode_byte (guint8 *buf, guint8 **endbuf, guint8 *limit)
1671 *endbuf = buf + 1;
1672 g_assert (*endbuf <= limit);
1673 return buf [0];
1676 static int
1677 decode_int (guint8 *buf, guint8 **endbuf, guint8 *limit)
1679 *endbuf = buf + 4;
1680 g_assert (*endbuf <= limit);
1682 return (((int)buf [0]) << 24) | (((int)buf [1]) << 16) | (((int)buf [2]) << 8) | (((int)buf [3]) << 0);
1685 static gint64
1686 decode_long (guint8 *buf, guint8 **endbuf, guint8 *limit)
1688 guint32 high = decode_int (buf, &buf, limit);
1689 guint32 low = decode_int (buf, &buf, limit);
1691 *endbuf = buf;
1693 return ((((guint64)high) << 32) | ((guint64)low));
1696 static int
1697 decode_id (guint8 *buf, guint8 **endbuf, guint8 *limit)
1699 return decode_int (buf, endbuf, limit);
1702 static char*
1703 decode_string (guint8 *buf, guint8 **endbuf, guint8 *limit)
1705 int len = decode_int (buf, &buf, limit);
1706 char *s;
1708 if (len < 0) {
1709 *endbuf = buf;
1710 return NULL;
1713 s = (char *)g_malloc (len + 1);
1714 g_assert (s);
1716 memcpy (s, buf, len);
1717 s [len] = '\0';
1718 buf += len;
1719 *endbuf = buf;
1721 return s;
1725 * Functions to encode protocol data
1728 static void
1729 buffer_init (Buffer *buf, int size)
1731 buf->buf = (guint8 *)g_malloc (size);
1732 buf->p = buf->buf;
1733 buf->end = buf->buf + size;
1736 static int
1737 buffer_len (Buffer *buf)
1739 return buf->p - buf->buf;
1742 static void
1743 buffer_make_room (Buffer *buf, int size)
1745 if (buf->end - buf->p < size) {
1746 int new_size = buf->end - buf->buf + size + 32;
1747 guint8 *p = (guint8 *)g_realloc (buf->buf, new_size);
1748 size = buf->p - buf->buf;
1749 buf->buf = p;
1750 buf->p = p + size;
1751 buf->end = buf->buf + new_size;
1755 static void
1756 buffer_add_byte (Buffer *buf, guint8 val)
1758 buffer_make_room (buf, 1);
1759 buf->p [0] = val;
1760 buf->p++;
1763 static void
1764 buffer_add_short (Buffer *buf, guint32 val)
1766 buffer_make_room (buf, 2);
1767 buf->p [0] = (val >> 8) & 0xff;
1768 buf->p [1] = (val >> 0) & 0xff;
1769 buf->p += 2;
1772 static void
1773 buffer_add_int (Buffer *buf, guint32 val)
1775 buffer_make_room (buf, 4);
1776 buf->p [0] = (val >> 24) & 0xff;
1777 buf->p [1] = (val >> 16) & 0xff;
1778 buf->p [2] = (val >> 8) & 0xff;
1779 buf->p [3] = (val >> 0) & 0xff;
1780 buf->p += 4;
1783 static void
1784 buffer_add_long (Buffer *buf, guint64 l)
1786 buffer_add_int (buf, (l >> 32) & 0xffffffff);
1787 buffer_add_int (buf, (l >> 0) & 0xffffffff);
1790 static void
1791 buffer_add_id (Buffer *buf, int id)
1793 buffer_add_int (buf, (guint64)id);
1796 static void
1797 buffer_add_data (Buffer *buf, guint8 *data, int len)
1799 buffer_make_room (buf, len);
1800 memcpy (buf->p, data, len);
1801 buf->p += len;
1804 static void
1805 buffer_add_utf16 (Buffer *buf, guint8 *data, int len)
1807 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1808 buffer_make_room (buf, len);
1809 memcpy (buf->p, data, len);
1810 #else
1811 for (int i=0; i<len; i +=2) {
1812 buf->p[i] = data[i+1];
1813 buf->p[i+1] = data[i];
1815 #endif
1816 buf->p += len;
1819 static void
1820 buffer_add_string (Buffer *buf, const char *str)
1822 int len;
1824 if (str == NULL) {
1825 buffer_add_int (buf, 0);
1826 } else {
1827 len = strlen (str);
1828 buffer_add_int (buf, len);
1829 buffer_add_data (buf, (guint8*)str, len);
1833 static void
1834 buffer_add_byte_array (Buffer *buf, guint8 *bytes, guint32 arr_len)
1836 buffer_add_int (buf, arr_len);
1837 buffer_add_data (buf, bytes, arr_len);
1840 static void
1841 buffer_add_buffer (Buffer *buf, Buffer *data)
1843 buffer_add_data (buf, data->buf, buffer_len (data));
1846 static void
1847 buffer_free (Buffer *buf)
1849 g_free (buf->buf);
1852 static gboolean
1853 send_packet (int command_set, int command, Buffer *data)
1855 Buffer buf;
1856 int len, id;
1857 gboolean res;
1859 id = mono_atomic_inc_i32 (&packet_id);
1861 len = data->p - data->buf + 11;
1862 buffer_init (&buf, len);
1863 buffer_add_int (&buf, len);
1864 buffer_add_int (&buf, id);
1865 buffer_add_byte (&buf, 0); /* flags */
1866 buffer_add_byte (&buf, command_set);
1867 buffer_add_byte (&buf, command);
1868 memcpy (buf.buf + 11, data->buf, data->p - data->buf);
1870 res = transport_send (buf.buf, len);
1872 buffer_free (&buf);
1874 return res;
1877 static gboolean
1878 send_reply_packets (int npackets, ReplyPacket *packets)
1880 Buffer buf;
1881 int i, len;
1882 gboolean res;
1884 len = 0;
1885 for (i = 0; i < npackets; ++i)
1886 len += buffer_len (packets [i].data) + 11;
1887 buffer_init (&buf, len);
1888 for (i = 0; i < npackets; ++i) {
1889 buffer_add_int (&buf, buffer_len (packets [i].data) + 11);
1890 buffer_add_int (&buf, packets [i].id);
1891 buffer_add_byte (&buf, 0x80); /* flags */
1892 buffer_add_byte (&buf, (packets [i].error >> 8) & 0xff);
1893 buffer_add_byte (&buf, packets [i].error);
1894 buffer_add_buffer (&buf, packets [i].data);
1897 res = transport_send (buf.buf, len);
1899 buffer_free (&buf);
1901 return res;
1904 static gboolean
1905 send_reply_packet (int id, int error, Buffer *data)
1907 ReplyPacket packet;
1909 memset (&packet, 0, sizeof (packet));
1910 packet.id = id;
1911 packet.error = error;
1912 packet.data = data;
1914 return send_reply_packets (1, &packet);
1917 static void
1918 send_buffered_reply_packets (void)
1920 int i;
1922 send_reply_packets (nreply_packets, reply_packets);
1923 for (i = 0; i < nreply_packets; ++i)
1924 buffer_free (reply_packets [i].data);
1925 DEBUG_PRINTF (1, "[dbg] Sent %d buffered reply packets [at=%lx].\n", nreply_packets, (long)mono_100ns_ticks () / 10000);
1926 nreply_packets = 0;
1929 static void
1930 buffer_reply_packet (int id, int error, Buffer *data)
1932 ReplyPacket *p;
1934 if (nreply_packets == 128)
1935 send_buffered_reply_packets ();
1937 p = &reply_packets [nreply_packets];
1938 p->id = id;
1939 p->error = error;
1940 p->data = g_new0 (Buffer, 1);
1941 buffer_init (p->data, buffer_len (data));
1942 buffer_add_buffer (p->data, data);
1943 nreply_packets ++;
1947 /* Maps objid -> ObjRef */
1948 /* Protected by the loader lock */
1949 static GHashTable *objrefs;
1950 /* Protected by the loader lock */
1951 static GHashTable *obj_to_objref;
1952 /* Protected by the dbg lock */
1953 static MonoGHashTable *suspended_objs;
1957 static void
1958 objrefs_init (void)
1960 objrefs = g_hash_table_new_full (NULL, NULL, NULL, mono_debugger_free_objref);
1961 obj_to_objref = g_hash_table_new (NULL, NULL);
1962 suspended_objs = mono_g_hash_table_new_type_internal ((GHashFunc)mono_object_hash_internal, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Suspended Object Table");
1965 static void
1966 objrefs_cleanup (void)
1968 g_hash_table_destroy (objrefs);
1969 objrefs = NULL;
1973 * Return an ObjRef for OBJ.
1975 static ObjRef*
1976 get_objref (MonoObject *obj)
1978 ObjRef *ref;
1979 GSList *reflist = NULL, *l;
1980 int hash = 0;
1982 if (obj == NULL)
1983 return NULL;
1985 if (suspend_count) {
1987 * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
1989 dbg_lock ();
1990 mono_g_hash_table_insert_internal (suspended_objs, obj, NULL);
1991 dbg_unlock ();
1994 mono_loader_lock ();
1996 /* FIXME: The tables can grow indefinitely */
1998 if (mono_gc_is_moving ()) {
2000 * Objects can move, so use a hash table mapping hash codes to lists of
2001 * ObjRef structures.
2003 hash = mono_object_hash_internal (obj);
2005 reflist = (GSList *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (hash));
2006 for (l = reflist; l; l = l->next) {
2007 ref = (ObjRef *)l->data;
2008 if (ref && mono_gchandle_get_target_internal (ref->handle) == obj) {
2009 mono_loader_unlock ();
2010 return ref;
2013 } else {
2014 /* Use a hash table with masked pointers to internalize object references */
2015 ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
2016 /* ref might refer to a different object with the same addr which was GCd */
2017 if (ref && mono_gchandle_get_target_internal (ref->handle) == obj) {
2018 mono_loader_unlock ();
2019 return ref;
2023 ref = g_new0 (ObjRef, 1);
2024 ref->id = mono_atomic_inc_i32 (&objref_id);
2025 ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE);
2027 g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
2029 if (mono_gc_is_moving ()) {
2030 reflist = g_slist_append (reflist, ref);
2031 g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (hash), reflist);
2032 } else {
2033 g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
2036 mono_loader_unlock ();
2038 return ref;
2041 static gboolean
2042 true_pred (gpointer key, gpointer value, gpointer user_data)
2044 return TRUE;
2047 static void
2048 clear_suspended_objs (void)
2050 dbg_lock ();
2051 mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL);
2052 dbg_unlock ();
2055 static int
2056 get_objid (MonoObject *obj)
2058 if (!obj)
2059 return 0;
2060 else
2061 return get_objref (obj)->id;
2065 * Set OBJ to the object identified by OBJID.
2066 * Returns 0 or an error code if OBJID is invalid or the object has been garbage
2067 * collected.
2069 static ErrorCode
2070 get_object_allow_null (int objid, MonoObject **obj)
2072 ObjRef *ref;
2074 if (objid == 0) {
2075 *obj = NULL;
2076 return ERR_NONE;
2079 if (!objrefs)
2080 return ERR_INVALID_OBJECT;
2082 mono_loader_lock ();
2084 ref = (ObjRef *)g_hash_table_lookup (objrefs, GINT_TO_POINTER (objid));
2086 if (ref) {
2087 *obj = mono_gchandle_get_target_internal (ref->handle);
2088 mono_loader_unlock ();
2089 if (!(*obj))
2090 return ERR_INVALID_OBJECT;
2091 return ERR_NONE;
2092 } else {
2093 mono_loader_unlock ();
2094 return ERR_INVALID_OBJECT;
2098 static ErrorCode
2099 get_object (int objid, MonoObject **obj)
2101 ErrorCode err = get_object_allow_null (objid, obj);
2103 if (err != ERR_NONE)
2104 return err;
2105 if (!(*obj))
2106 return ERR_INVALID_OBJECT;
2107 return ERR_NONE;
2110 static int
2111 decode_objid (guint8 *buf, guint8 **endbuf, guint8 *limit)
2113 return decode_id (buf, endbuf, limit);
2116 static void
2117 buffer_add_objid (Buffer *buf, MonoObject *o)
2119 buffer_add_id (buf, get_objid (o));
2123 * IDS
2126 typedef enum {
2127 ID_ASSEMBLY = 0,
2128 ID_MODULE = 1,
2129 ID_TYPE = 2,
2130 ID_METHOD = 3,
2131 ID_FIELD = 4,
2132 ID_DOMAIN = 5,
2133 ID_PROPERTY = 6,
2134 ID_NUM
2135 } IdType;
2138 * Represents a runtime structure accessible to the debugger client
2140 typedef struct {
2141 /* Unique id used in the wire protocol */
2142 int id;
2143 /* Domain of the runtime structure, NULL if the domain was unloaded */
2144 MonoDomain *domain;
2145 union {
2146 gpointer val;
2147 MonoClass *klass;
2148 MonoMethod *method;
2149 MonoImage *image;
2150 MonoAssembly *assembly;
2151 MonoClassField *field;
2152 MonoDomain *domain;
2153 MonoProperty *property;
2154 } data;
2155 } Id;
2157 typedef struct {
2158 /* Maps runtime structure -> Id */
2159 /* Protected by the dbg lock */
2160 GHashTable *val_to_id [ID_NUM];
2161 /* Classes whose class load event has been sent */
2162 /* Protected by the loader lock */
2163 GHashTable *loaded_classes;
2164 /* Maps MonoClass->GPtrArray of file names */
2165 GHashTable *source_files;
2166 /* Maps source file basename -> GSList of classes */
2167 GHashTable *source_file_to_class;
2168 /* Same with ignore-case */
2169 GHashTable *source_file_to_class_ignorecase;
2170 } AgentDomainInfo;
2172 /* Maps id -> Id */
2173 /* Protected by the dbg lock */
2174 static GPtrArray *ids [ID_NUM];
2176 static void
2177 ids_init (void)
2179 int i;
2181 for (i = 0; i < ID_NUM; ++i)
2182 ids [i] = g_ptr_array_new ();
2185 static void
2186 ids_cleanup (void)
2188 int i, j;
2190 for (i = 0; i < ID_NUM; ++i) {
2191 if (ids [i]) {
2192 for (j = 0; j < ids [i]->len; ++j)
2193 g_free (g_ptr_array_index (ids [i], j));
2194 g_ptr_array_free (ids [i], TRUE);
2196 ids [i] = NULL;
2200 static void
2201 debugger_agent_free_domain_info (MonoDomain *domain)
2203 AgentDomainInfo *info = (AgentDomainInfo *)domain_jit_info (domain)->agent_info;
2204 int i, j;
2205 GHashTableIter iter;
2206 GPtrArray *file_names;
2207 char *basename;
2208 GSList *l;
2210 if (info) {
2211 for (i = 0; i < ID_NUM; ++i)
2212 g_hash_table_destroy (info->val_to_id [i]);
2213 g_hash_table_destroy (info->loaded_classes);
2215 g_hash_table_iter_init (&iter, info->source_files);
2216 while (g_hash_table_iter_next (&iter, NULL, (void**)&file_names)) {
2217 for (i = 0; i < file_names->len; ++i)
2218 g_free (g_ptr_array_index (file_names, i));
2219 g_ptr_array_free (file_names, TRUE);
2222 g_hash_table_iter_init (&iter, info->source_file_to_class);
2223 while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
2224 g_free (basename);
2225 g_slist_free (l);
2228 g_hash_table_iter_init (&iter, info->source_file_to_class_ignorecase);
2229 while (g_hash_table_iter_next (&iter, (void**)&basename, (void**)&l)) {
2230 g_free (basename);
2231 g_slist_free (l);
2234 g_free (info);
2237 domain_jit_info (domain)->agent_info = NULL;
2239 /* Clear ids referencing structures in the domain */
2240 dbg_lock ();
2241 for (i = 0; i < ID_NUM; ++i) {
2242 if (ids [i]) {
2243 for (j = 0; j < ids [i]->len; ++j) {
2244 Id *id = (Id *)g_ptr_array_index (ids [i], j);
2245 if (id->domain == domain)
2246 id->domain = NULL;
2250 dbg_unlock ();
2252 mono_de_domain_remove (domain);
2255 static AgentDomainInfo*
2256 get_agent_domain_info (MonoDomain *domain)
2258 AgentDomainInfo *info = NULL;
2259 MonoJitDomainInfo *jit_info = domain_jit_info (domain);
2261 info = (AgentDomainInfo *)jit_info->agent_info;
2263 if (info) {
2264 mono_memory_read_barrier ();
2265 return info;
2268 info = g_new0 (AgentDomainInfo, 1);
2269 info->loaded_classes = g_hash_table_new (mono_aligned_addr_hash, NULL);
2270 info->source_files = g_hash_table_new (mono_aligned_addr_hash, NULL);
2271 info->source_file_to_class = g_hash_table_new (g_str_hash, g_str_equal);
2272 info->source_file_to_class_ignorecase = g_hash_table_new (g_str_hash, g_str_equal);
2274 mono_memory_write_barrier ();
2276 gpointer other_info = mono_atomic_cas_ptr (&jit_info->agent_info, info, NULL);
2278 if (other_info != NULL) {
2279 g_hash_table_destroy (info->loaded_classes);
2280 g_hash_table_destroy (info->source_files);
2281 g_hash_table_destroy (info->source_file_to_class);
2282 g_hash_table_destroy (info->source_file_to_class_ignorecase);
2283 g_free (info);
2286 return (AgentDomainInfo *)jit_info->agent_info;
2289 static int
2290 get_id (MonoDomain *domain, IdType type, gpointer val)
2292 Id *id;
2293 AgentDomainInfo *info;
2295 if (val == NULL)
2296 return 0;
2298 info = get_agent_domain_info (domain);
2300 dbg_lock ();
2302 if (info->val_to_id [type] == NULL)
2303 info->val_to_id [type] = g_hash_table_new (mono_aligned_addr_hash, NULL);
2305 id = (Id *)g_hash_table_lookup (info->val_to_id [type], val);
2306 if (id) {
2307 dbg_unlock ();
2308 return id->id;
2311 id = g_new0 (Id, 1);
2312 /* Reserve id 0 */
2313 id->id = ids [type]->len + 1;
2314 id->domain = domain;
2315 id->data.val = val;
2317 g_hash_table_insert (info->val_to_id [type], val, id);
2318 g_ptr_array_add (ids [type], id);
2320 dbg_unlock ();
2322 return id->id;
2325 static gpointer
2326 decode_ptr_id (guint8 *buf, guint8 **endbuf, guint8 *limit, IdType type, MonoDomain **domain, ErrorCode *err)
2328 Id *res;
2330 int id = decode_id (buf, endbuf, limit);
2332 *err = ERR_NONE;
2333 if (domain)
2334 *domain = NULL;
2336 if (id == 0)
2337 return NULL;
2339 // FIXME: error handling
2340 dbg_lock ();
2341 g_assert (id > 0 && id <= ids [type]->len);
2343 res = (Id *)g_ptr_array_index (ids [type], GPOINTER_TO_INT (id - 1));
2344 dbg_unlock ();
2346 if (res->domain == NULL || res->domain->state == MONO_APPDOMAIN_UNLOADED) {
2347 DEBUG_PRINTF (1, "ERR_UNLOADED, id=%d, type=%d.\n", id, type);
2348 *err = ERR_UNLOADED;
2349 return NULL;
2352 if (domain)
2353 *domain = res->domain;
2355 return res->data.val;
2358 static int
2359 buffer_add_ptr_id (Buffer *buf, MonoDomain *domain, IdType type, gpointer val)
2361 int id = get_id (domain, type, val);
2363 buffer_add_id (buf, id);
2364 return id;
2367 static MonoClass*
2368 decode_typeid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2370 MonoClass *klass;
2372 klass = (MonoClass *)decode_ptr_id (buf, endbuf, limit, ID_TYPE, domain, err);
2373 if (G_UNLIKELY (log_level >= 2) && klass) {
2374 char *s;
2376 s = mono_type_full_name (m_class_get_byval_arg (klass));
2377 DEBUG_PRINTF (2, "[dbg] recv class [%s]\n", s);
2378 g_free (s);
2380 return klass;
2383 static MonoAssembly*
2384 decode_assemblyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2386 return (MonoAssembly *)decode_ptr_id (buf, endbuf, limit, ID_ASSEMBLY, domain, err);
2389 static MonoImage*
2390 decode_moduleid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2392 return (MonoImage *)decode_ptr_id (buf, endbuf, limit, ID_MODULE, domain, err);
2395 static MonoMethod*
2396 decode_methodid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2398 MonoMethod *m;
2400 m = (MonoMethod *)decode_ptr_id (buf, endbuf, limit, ID_METHOD, domain, err);
2401 if (G_UNLIKELY (log_level >= 2) && m) {
2402 char *s;
2404 s = mono_method_full_name (m, TRUE);
2405 DEBUG_PRINTF (2, "[dbg] recv method [%s]\n", s);
2406 g_free (s);
2408 return m;
2411 static MonoClassField*
2412 decode_fieldid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2414 return (MonoClassField *)decode_ptr_id (buf, endbuf, limit, ID_FIELD, domain, err);
2417 static MonoDomain*
2418 decode_domainid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2420 return (MonoDomain *)decode_ptr_id (buf, endbuf, limit, ID_DOMAIN, domain, err);
2423 static MonoProperty*
2424 decode_propertyid (guint8 *buf, guint8 **endbuf, guint8 *limit, MonoDomain **domain, ErrorCode *err)
2426 return (MonoProperty *)decode_ptr_id (buf, endbuf, limit, ID_PROPERTY, domain, err);
2429 static void
2430 buffer_add_typeid (Buffer *buf, MonoDomain *domain, MonoClass *klass)
2432 buffer_add_ptr_id (buf, domain, ID_TYPE, klass);
2433 if (G_UNLIKELY (log_level >= 2) && klass) {
2434 char *s;
2436 s = mono_type_full_name (m_class_get_byval_arg (klass));
2437 if (is_debugger_thread ())
2438 DEBUG_PRINTF (2, "[dbg] send class [%s]\n", s);
2439 else
2440 DEBUG_PRINTF (2, "[%p] send class [%s]\n", (gpointer) (gsize) mono_native_thread_id_get (), s);
2441 g_free (s);
2445 static void
2446 buffer_add_methodid (Buffer *buf, MonoDomain *domain, MonoMethod *method)
2448 buffer_add_ptr_id (buf, domain, ID_METHOD, method);
2449 if (G_UNLIKELY (log_level >= 2) && method) {
2450 char *s;
2452 s = mono_method_full_name (method, 1);
2453 if (is_debugger_thread ())
2454 DEBUG_PRINTF (2, "[dbg] send method [%s]\n", s);
2455 else
2456 DEBUG_PRINTF (2, "[%p] send method [%s]\n", (gpointer) (gsize) mono_native_thread_id_get (), s);
2457 g_free (s);
2461 static void
2462 buffer_add_assemblyid (Buffer *buf, MonoDomain *domain, MonoAssembly *assembly)
2464 int id;
2466 id = buffer_add_ptr_id (buf, domain, ID_ASSEMBLY, assembly);
2467 if (G_UNLIKELY (log_level >= 2) && assembly)
2468 DEBUG_PRINTF (2, "[dbg] send assembly [%s][%s][%d]\n", assembly->aname.name, domain->friendly_name, id);
2471 static void
2472 buffer_add_moduleid (Buffer *buf, MonoDomain *domain, MonoImage *image)
2474 buffer_add_ptr_id (buf, domain, ID_MODULE, image);
2477 static void
2478 buffer_add_fieldid (Buffer *buf, MonoDomain *domain, MonoClassField *field)
2480 buffer_add_ptr_id (buf, domain, ID_FIELD, field);
2483 static void
2484 buffer_add_propertyid (Buffer *buf, MonoDomain *domain, MonoProperty *property)
2486 buffer_add_ptr_id (buf, domain, ID_PROPERTY, property);
2489 static void
2490 buffer_add_domainid (Buffer *buf, MonoDomain *domain)
2492 buffer_add_ptr_id (buf, domain, ID_DOMAIN, domain);
2495 static void invoke_method (void);
2498 * SUSPEND/RESUME
2501 static MonoJitInfo*
2502 get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip)
2504 MonoJitInfo *ji;
2506 if (out_ip)
2507 *out_ip = ip;
2509 ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain);
2510 if (!ji) {
2511 /* Could be an interpreter method */
2513 MonoLMF *lmf = mono_get_lmf ();
2514 MonoInterpFrameHandle *frame;
2516 g_assert (((gsize)lmf->previous_lmf) & 2);
2517 MonoLMFExt *ext = (MonoLMFExt*)lmf;
2519 g_assert (ext->kind == MONO_LMFEXT_INTERP_EXIT || ext->kind == MONO_LMFEXT_INTERP_EXIT_WITH_CTX);
2520 frame = (MonoInterpFrameHandle*)ext->interp_exit_data;
2521 ji = mini_get_interp_callbacks ()->frame_get_jit_info (frame);
2522 if (domain)
2523 *domain = mono_domain_get ();
2524 if (out_ip)
2525 *out_ip = mini_get_interp_callbacks ()->frame_get_ip (frame);
2527 return ji;
2531 * save_thread_context:
2533 * Set CTX as the current threads context which is used for computing stack traces.
2534 * This function is signal-safe.
2536 static void
2537 save_thread_context (MonoContext *ctx)
2539 DebuggerTlsData *tls;
2541 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
2542 g_assert (tls);
2544 if (ctx)
2545 mono_thread_state_init_from_monoctx (&tls->context, ctx);
2546 else
2547 mono_thread_state_init_from_current (&tls->context);
2550 static MonoCoopMutex suspend_mutex;
2552 /* Cond variable used to wait for suspend_count becoming 0 */
2553 static MonoCoopCond suspend_cond;
2555 /* Semaphore used to wait for a thread becoming suspended */
2556 static MonoCoopSem suspend_sem;
2558 static void
2559 suspend_init (void)
2561 mono_coop_mutex_init (&suspend_mutex);
2562 mono_coop_cond_init (&suspend_cond);
2563 mono_coop_sem_init (&suspend_sem, 0);
2566 typedef struct
2568 StackFrameInfo last_frame;
2569 gboolean last_frame_set;
2570 MonoContext ctx;
2571 gpointer lmf;
2572 MonoDomain *domain;
2573 } GetLastFrameUserData;
2575 static gboolean
2576 get_last_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
2578 GetLastFrameUserData *data = (GetLastFrameUserData *)user_data;
2580 if (info->type == FRAME_TYPE_MANAGED_TO_NATIVE || info->type == FRAME_TYPE_TRAMPOLINE)
2581 return FALSE;
2583 if (!data->last_frame_set) {
2584 /* Store the last frame */
2585 memcpy (&data->last_frame, info, sizeof (StackFrameInfo));
2586 data->last_frame_set = TRUE;
2587 return FALSE;
2588 } else {
2589 /* Store the context/lmf for the frame above the last frame */
2590 memcpy (&data->ctx, ctx, sizeof (MonoContext));
2591 data->lmf = info->lmf;
2592 data->domain = info->domain;
2593 return TRUE;
2597 static void
2598 copy_unwind_state_from_frame_data (MonoThreadUnwindState *to, GetLastFrameUserData *data, gpointer jit_tls)
2600 memcpy (&to->ctx, &data->ctx, sizeof (MonoContext));
2602 to->unwind_data [MONO_UNWIND_DATA_DOMAIN] = data->domain;
2603 to->unwind_data [MONO_UNWIND_DATA_LMF] = data->lmf;
2604 to->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = jit_tls;
2605 to->valid = TRUE;
2609 * thread_interrupt:
2611 * Process interruption of a thread. This should be signal safe.
2613 * This always runs in the debugger thread.
2615 static void
2616 thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
2618 gpointer ip;
2619 MonoNativeThreadId tid;
2621 g_assert (info);
2623 ip = MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx);
2624 tid = mono_thread_info_get_tid (info);
2626 // FIXME: Races when the thread leaves managed code before hitting a single step
2627 // event.
2629 if (ji && !ji->is_trampoline) {
2630 /* Running managed code, will be suspended by the single step code */
2631 DEBUG_PRINTF (1, "[%p] Received interrupt while at %s(%p), continuing.\n", (gpointer)(gsize)tid, jinfo_get_method (ji)->name, ip);
2632 } else {
2634 * Running native code, will be suspended when it returns to/enters
2635 * managed code. Treat it as already suspended.
2636 * This might interrupt the code in mono_de_process_single_step (), we use the
2637 * tls->suspending flag to avoid races when that happens.
2639 if (!tls->suspended && !tls->suspending) {
2640 GetLastFrameUserData data;
2642 // FIXME: printf is not signal safe, but this is only used during
2643 // debugger debugging
2644 if (ip)
2645 DEBUG_PRINTF (1, "[%p] Received interrupt while at %p, treating as suspended.\n", (gpointer)(gsize)tid, ip);
2646 //save_thread_context (&ctx);
2648 if (!tls->thread)
2649 /* Already terminated */
2650 return;
2653 * We are in a difficult position: we want to be able to provide stack
2654 * traces for this thread, but we can't use the current ctx+lmf, since
2655 * the thread is still running, so it might return to managed code,
2656 * making these invalid.
2657 * So we start a stack walk and save the first frame, along with the
2658 * parent frame's ctx+lmf. This (hopefully) works because the thread will be
2659 * suspended when it returns to managed code, so the parent's ctx should
2660 * remain valid.
2662 MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info);
2664 data.last_frame_set = FALSE;
2665 mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, MONO_UNWIND_SIGNAL_SAFE, &data);
2666 if (data.last_frame_set) {
2667 gpointer jit_tls = tls->thread->thread_info->jit_data;
2669 memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
2671 if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED || data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
2673 * Store the current lmf instead of the parent one, since that
2674 * contains the interp exit data.
2676 data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF];
2679 copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
2680 /* Don't set tls->context, it could race with the thread processing a breakpoint etc. */
2681 } else {
2682 tls->async_state.valid = FALSE;
2685 mono_memory_barrier ();
2687 tls->suspended = TRUE;
2688 mono_coop_sem_post (&suspend_sem);
2694 * reset_native_thread_suspend_state:
2696 * Reset the suspended flag and state on native threads
2698 static void
2699 reset_native_thread_suspend_state (gpointer key, gpointer value, gpointer user_data)
2701 DebuggerTlsData *tls = (DebuggerTlsData *)value;
2703 if (!tls->really_suspended && tls->suspended) {
2704 tls->suspended = FALSE;
2706 * The thread might still be running if it was executing native code, so the state won't be invalided by
2707 * suspend_current ().
2709 tls->context.valid = FALSE;
2710 tls->async_state.valid = FALSE;
2711 invalidate_frames (tls);
2713 tls->resume_count_internal++;
2717 typedef struct {
2718 DebuggerTlsData *tls;
2719 gboolean valid_info;
2720 } InterruptData;
2722 static SuspendThreadResult
2723 debugger_interrupt_critical (MonoThreadInfo *info, gpointer user_data)
2725 InterruptData *data = (InterruptData *)user_data;
2726 MonoJitInfo *ji;
2728 data->valid_info = TRUE;
2729 MonoDomain *domain = (MonoDomain *) mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN];
2730 if (!domain) {
2731 /* not attached */
2732 ji = NULL;
2733 } else {
2734 ji = mono_jit_info_table_find_internal ( domain, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx), TRUE, TRUE);
2737 /* This is signal safe */
2738 thread_interrupt (data->tls, info, ji);
2739 return MonoResumeThread;
2743 * notify_thread:
2745 * Notify a thread that it needs to suspend.
2747 static void
2748 notify_thread (gpointer key, gpointer value, gpointer user_data)
2750 MonoInternalThread *thread = (MonoInternalThread *)key;
2751 DebuggerTlsData *tls = (DebuggerTlsData *)value;
2752 MonoNativeThreadId tid = MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
2754 if (mono_thread_internal_is_current (thread) || tls->terminated)
2755 return;
2757 DEBUG_PRINTF (1, "[%p] Interrupting %p...\n", (gpointer) (gsize) mono_native_thread_id_get (), (gpointer)(gsize)tid);
2759 /* This is _not_ equivalent to mono_thread_internal_abort () */
2760 InterruptData interrupt_data = { 0 };
2761 interrupt_data.tls = tls;
2763 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, debugger_interrupt_critical, &interrupt_data);
2764 if (!interrupt_data.valid_info) {
2765 DEBUG_PRINTF (1, "[%p] mono_thread_info_suspend_sync () failed for %p...\n", (gpointer) (gsize) mono_native_thread_id_get (), (gpointer)tid);
2767 * Attached thread which died without detaching.
2769 tls->terminated = TRUE;
2773 static void
2774 process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
2776 guint8 *ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
2777 MonoJitInfo *ji;
2778 MonoMethod *method;
2780 if (mono_loader_lock_is_owned_by_self ()) {
2782 * Shortcut for the check in suspend_current (). This speeds up processing
2783 * when executing long running code inside the loader lock, i.e. assembly load
2784 * hooks.
2786 return;
2789 if (is_debugger_thread ())
2790 return;
2792 /* Prevent races with mono_debugger_agent_thread_interrupt () */
2793 if (suspend_count - tls->resume_count > 0)
2794 tls->suspending = TRUE;
2796 DEBUG_PRINTF (1, "[%p] Received single step event for suspending.\n", (gpointer) (gsize) mono_native_thread_id_get ());
2798 if (suspend_count - tls->resume_count == 0) {
2800 * We are executing a single threaded invoke but the single step for
2801 * suspending is still active.
2802 * FIXME: This slows down single threaded invokes.
2804 DEBUG_PRINTF (1, "[%p] Ignored during single threaded invoke.\n", (gpointer) (gsize) mono_native_thread_id_get ());
2805 return;
2808 ji = get_top_method_ji (ip, NULL, NULL);
2809 g_assert (ji);
2810 /* Can't suspend in these methods */
2811 method = jinfo_get_method (ji);
2812 if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
2813 return;
2815 save_thread_context (ctx);
2817 suspend_current ();
2821 /* Conditionally call process_suspend depending oh the current state */
2822 static gboolean
2823 try_process_suspend (void *the_tls, MonoContext *ctx, gboolean from_breakpoint)
2825 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
2826 /* if there is a suspend pending that is not executed yes */
2827 if (suspend_count > 0) {
2828 /* Fastpath during invokes, see in process_suspend () */
2829 /* if there is a suspend pending but this thread is already resumed, we shouldn't suspend it again and the breakpoint/ss can run */
2830 if (suspend_count - tls->resume_count == 0)
2831 return FALSE;
2832 /* if there is in a invoke the breakpoint/step should be executed even with the suspend pending */
2833 if (tls->invoke)
2834 return FALSE;
2835 /* with the multithreaded single step check if there is a suspend_count pending in the current thread and not in the vm */
2836 if (from_breakpoint && tls->suspend_count <= tls->resume_count_internal)
2837 return FALSE;
2838 process_suspend (tls, ctx);
2839 return TRUE;
2840 } /* if there isn't any suspend pending, the breakpoint/ss will be executed and will suspend then vm when the event is sent */
2841 return FALSE;
2845 * suspend_vm:
2847 * Increase the suspend count of the VM. While the suspend count is greater
2848 * than 0, runtime threads are suspended at certain points during execution.
2850 static void
2851 suspend_vm (void)
2853 gboolean tp_suspend = FALSE;
2854 mono_loader_lock ();
2856 mono_coop_mutex_lock (&suspend_mutex);
2858 suspend_count ++;
2860 DEBUG_PRINTF (1, "[%p] Suspending vm...\n", (gpointer) (gsize) mono_native_thread_id_get ());
2862 if (suspend_count == 1) {
2863 // FIXME: Is it safe to call this inside the lock ?
2864 mono_de_start_single_stepping ();
2865 mono_g_hash_table_foreach (thread_to_tls, notify_thread, NULL);
2868 mono_coop_mutex_unlock (&suspend_mutex);
2870 if (suspend_count == 1)
2872 * Suspend creation of new threadpool threads, since they cannot run
2874 tp_suspend = TRUE;
2875 mono_loader_unlock ();
2877 #ifndef ENABLE_NETCORE
2878 if (tp_suspend)
2879 mono_threadpool_suspend ();
2880 #endif
2884 * resume_vm:
2886 * Decrease the suspend count of the VM. If the count reaches 0, runtime threads
2887 * are resumed.
2889 static void
2890 resume_vm (void)
2892 g_assert (is_debugger_thread ());
2893 gboolean tp_resume = FALSE;
2895 mono_loader_lock ();
2897 mono_coop_mutex_lock (&suspend_mutex);
2899 g_assert (suspend_count > 0);
2900 suspend_count --;
2902 DEBUG_PRINTF (1, "[%p] Resuming vm, suspend count=%d...\n", (gpointer) (gsize) mono_native_thread_id_get (), suspend_count);
2904 if (suspend_count == 0) {
2905 // FIXME: Is it safe to call this inside the lock ?
2906 mono_de_stop_single_stepping ();
2907 mono_g_hash_table_foreach (thread_to_tls, reset_native_thread_suspend_state, NULL);
2910 /* Signal this even when suspend_count > 0, since some threads might have resume_count > 0 */
2911 mono_coop_cond_broadcast (&suspend_cond);
2913 mono_coop_mutex_unlock (&suspend_mutex);
2914 //g_assert (err == 0);
2916 if (suspend_count == 0)
2917 tp_resume = TRUE;
2918 mono_loader_unlock ();
2920 #ifndef ENABLE_NETCORE
2921 if (tp_resume)
2922 mono_threadpool_resume ();
2923 #endif
2927 * resume_thread:
2929 * Resume just one thread.
2931 static void
2932 resume_thread (MonoInternalThread *thread)
2934 DebuggerTlsData *tls;
2936 g_assert (is_debugger_thread ());
2938 mono_loader_lock ();
2940 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
2941 g_assert (tls);
2943 mono_coop_mutex_lock (&suspend_mutex);
2945 g_assert (suspend_count > 0);
2947 DEBUG_PRINTF (1, "[sdb] Resuming thread %p...\n", (gpointer)(gssize)thread->tid);
2949 tls->resume_count += suspend_count;
2950 tls->resume_count_internal += tls->suspend_count;
2951 tls->suspend_count = 0;
2954 * Signal suspend_count without decreasing suspend_count, the threads will wake up
2955 * but only the one whose resume_count field is > 0 will be resumed.
2957 mono_coop_cond_broadcast (&suspend_cond);
2959 mono_coop_mutex_unlock (&suspend_mutex);
2960 //g_assert (err == 0);
2962 mono_loader_unlock ();
2965 static void
2966 free_frames (StackFrame **frames, int nframes)
2968 int i;
2970 for (i = 0; i < nframes; ++i) {
2971 if (frames [i]->jit)
2972 mono_debug_free_method_jit_info (frames [i]->jit);
2973 g_free (frames [i]);
2975 g_free (frames);
2978 static void
2979 invalidate_frames (DebuggerTlsData *tls)
2981 mono_loader_lock ();
2983 if (!tls)
2984 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
2985 g_assert (tls);
2987 free_frames (tls->frames, tls->frame_count);
2988 tls->frame_count = 0;
2989 tls->frames = NULL;
2991 free_frames (tls->restore_frames, tls->restore_frame_count);
2992 tls->restore_frame_count = 0;
2993 tls->restore_frames = NULL;
2995 mono_loader_unlock ();
2999 * suspend_current:
3001 * Suspend the current thread until the runtime is resumed. If the thread has a
3002 * pending invoke, then the invoke is executed before this function returns.
3004 static void
3005 suspend_current (void)
3007 DebuggerTlsData *tls;
3009 g_assert (!is_debugger_thread ());
3011 if (mono_loader_lock_is_owned_by_self ()) {
3013 * If we own the loader mutex, can't suspend until we release it, since the
3014 * whole runtime can deadlock otherwise.
3016 return;
3019 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3020 g_assert (tls);
3022 gboolean do_resume = FALSE;
3023 while (!do_resume) {
3024 mono_coop_mutex_lock (&suspend_mutex);
3026 tls->suspending = FALSE;
3027 tls->really_suspended = TRUE;
3029 if (!tls->suspended) {
3030 tls->suspended = TRUE;
3031 mono_coop_sem_post (&suspend_sem);
3034 mono_debugger_log_suspend (tls);
3035 DEBUG_PRINTF (1, "[%p] Suspended.\n", (gpointer) (gsize) mono_native_thread_id_get ());
3037 while (suspend_count - tls->resume_count > 0) {
3038 mono_coop_cond_wait (&suspend_cond, &suspend_mutex);
3041 tls->suspended = FALSE;
3042 tls->really_suspended = FALSE;
3044 mono_coop_mutex_unlock (&suspend_mutex);
3046 mono_debugger_log_resume (tls);
3047 DEBUG_PRINTF (1, "[%p] Resumed.\n", (gpointer) (gsize) mono_native_thread_id_get ());
3049 if (tls->pending_invoke) {
3050 /* Save the original context */
3051 tls->pending_invoke->has_ctx = TRUE;
3052 tls->pending_invoke->ctx = tls->context.ctx;
3054 invoke_method ();
3056 /* Have to suspend again */
3057 } else {
3058 do_resume = TRUE;
3062 /* The frame info becomes invalid after a resume */
3063 tls->context.valid = FALSE;
3064 tls->async_state.valid = FALSE;
3065 invalidate_frames (tls);
3066 mono_stopwatch_start (&tls->step_time);
3069 static void
3070 count_thread (gpointer key, gpointer value, gpointer user_data)
3072 DebuggerTlsData *tls = (DebuggerTlsData *)value;
3074 if (!tls->suspended && !tls->terminated && !mono_thread_internal_is_current (tls->thread))
3075 *(int*)user_data = *(int*)user_data + 1;
3078 static int
3079 count_threads_to_wait_for (void)
3081 int count = 0;
3083 mono_loader_lock ();
3084 mono_g_hash_table_foreach (thread_to_tls, count_thread, &count);
3085 mono_loader_unlock ();
3087 return count;
3091 * wait_for_suspend:
3093 * Wait until the runtime is completely suspended.
3095 static void
3096 wait_for_suspend (void)
3098 int nthreads, nwait, err;
3099 gboolean waited = FALSE;
3101 // FIXME: Threads starting/stopping ?
3102 mono_loader_lock ();
3103 nthreads = mono_g_hash_table_size (thread_to_tls);
3104 mono_loader_unlock ();
3106 while (TRUE) {
3107 nwait = count_threads_to_wait_for ();
3108 if (nwait) {
3109 DEBUG_PRINTF (1, "Waiting for %d(%d) threads to suspend...\n", nwait, nthreads);
3110 err = mono_coop_sem_wait (&suspend_sem, MONO_SEM_FLAGS_NONE);
3111 g_assert (err == 0);
3112 waited = TRUE;
3113 } else {
3114 break;
3118 if (waited)
3119 DEBUG_PRINTF (1, "%d threads suspended.\n", nthreads);
3123 * is_suspended:
3125 * Return whenever the runtime is suspended.
3127 static gboolean
3128 is_suspended (void)
3130 return count_threads_to_wait_for () == 0;
3133 static void
3134 no_seq_points_found (MonoMethod *method, int offset)
3137 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
3139 printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method, TRUE), offset);
3142 static int
3143 calc_il_offset (MonoDomain *domain, MonoMethod *method, int native_offset, gboolean is_top_frame)
3145 int ret = -1;
3146 if (is_top_frame) {
3147 SeqPoint sp;
3148 /* mono_debug_il_offset_from_address () doesn't seem to be precise enough (#2092) */
3149 if (mono_find_prev_seq_point_for_native_offset (domain, method, native_offset, NULL, &sp))
3150 ret = sp.il_offset;
3152 if (ret == -1)
3153 ret = mono_debug_il_offset_from_address (method, domain, native_offset);
3154 return ret;
3157 typedef struct {
3158 DebuggerTlsData *tls;
3159 GSList *frames;
3160 gboolean set_debugger_flag;
3161 } ComputeFramesUserData;
3163 static gboolean
3164 process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
3166 ComputeFramesUserData *ud = (ComputeFramesUserData *)user_data;
3167 StackFrame *frame;
3168 MonoMethod *method, *actual_method, *api_method;
3169 int flags = 0;
3171 mono_loader_lock ();
3172 if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP && info->type != FRAME_TYPE_MANAGED_TO_NATIVE) {
3173 if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
3174 /* Mark the last frame as an invoke frame */
3175 if (ud->frames)
3176 ((StackFrame*)g_slist_last (ud->frames)->data)->flags |= FRAME_FLAG_DEBUGGER_INVOKE;
3177 else
3178 ud->set_debugger_flag = TRUE;
3180 mono_loader_unlock ();
3181 return FALSE;
3184 if (info->ji)
3185 method = jinfo_get_method (info->ji);
3186 else
3187 method = info->method;
3188 actual_method = info->actual_method;
3189 api_method = method;
3191 if (!method) {
3192 mono_loader_unlock ();
3193 return FALSE;
3196 if (!method || (method->wrapper_type && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && method->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE)) {
3197 mono_loader_unlock ();
3198 return FALSE;
3201 if (info->il_offset == -1) {
3202 info->il_offset = calc_il_offset (info->domain, method, info->native_offset, ud->frames == NULL);
3205 DEBUG_PRINTF (1, "\tFrame: %s:[il=0x%x, native=0x%x] %d\n", mono_method_full_name (method, TRUE), info->il_offset, info->native_offset, info->managed);
3207 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
3208 if (!CHECK_PROTOCOL_VERSION (2, 17)) {
3209 /* Older clients can't handle this flag */
3210 mono_loader_unlock ();
3211 return FALSE;
3213 api_method = mono_marshal_method_from_wrapper (method);
3214 if (!api_method) {
3215 mono_loader_unlock ();
3216 return FALSE;
3218 actual_method = api_method;
3219 flags |= FRAME_FLAG_NATIVE_TRANSITION;
3222 if (ud->set_debugger_flag) {
3223 g_assert (g_slist_length (ud->frames) == 0);
3224 flags |= FRAME_FLAG_DEBUGGER_INVOKE;
3225 ud->set_debugger_flag = FALSE;
3228 frame = g_new0 (StackFrame, 1);
3229 frame->de.ji = info->ji;
3230 frame->de.domain = info->domain;
3231 frame->de.method = method;
3232 frame->de.native_offset = info->native_offset;
3234 frame->actual_method = actual_method;
3235 frame->api_method = api_method;
3236 frame->il_offset = info->il_offset;
3237 frame->flags = flags;
3238 frame->interp_frame = info->interp_frame;
3239 frame->frame_addr = info->frame_addr;
3240 if (info->reg_locations)
3241 memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (host_mgreg_t*));
3242 if (ctx) {
3243 frame->ctx = *ctx;
3244 frame->has_ctx = TRUE;
3247 ud->frames = g_slist_append (ud->frames, frame);
3249 mono_loader_unlock ();
3250 return FALSE;
3253 static gint32 isFixedSizeArray (MonoClassField *f)
3255 ERROR_DECL (error);
3256 if (!CHECK_PROTOCOL_VERSION (2, 53) || f->type->type != MONO_TYPE_VALUETYPE) {
3257 return 1;
3259 MonoCustomAttrInfo *cinfo;
3260 MonoCustomAttrEntry *attr;
3261 int aindex;
3262 gint32 ret = 1;
3263 cinfo = mono_custom_attrs_from_field_checked (f->parent, f, error);
3264 goto_if_nok (error, leave);
3265 attr = NULL;
3266 if (cinfo) {
3267 for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) {
3268 MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass;
3269 MonoClass *fixed_size_class = mono_class_try_get_fixed_buffer_class ();
3270 if (fixed_size_class != NULL && mono_class_has_parent (ctor_class, fixed_size_class)) {
3271 attr = &cinfo->attrs [aindex];
3272 gpointer *typed_args, *named_args;
3273 CattrNamedArg *arginfo;
3274 int num_named_args;
3276 mono_reflection_create_custom_attr_data_args_noalloc (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size,
3277 &typed_args, &named_args, &num_named_args, &arginfo, error);
3278 if (!is_ok (error)) {
3279 ret = 0;
3280 goto leave;
3282 ret = *(gint32*)typed_args [1];
3283 g_free (typed_args [1]);
3284 g_free (typed_args);
3285 g_free (named_args);
3286 g_free (arginfo);
3287 return ret;
3291 leave:
3292 mono_error_cleanup (error);
3293 return ret;
3296 static gboolean
3297 process_filter_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
3299 ComputeFramesUserData *ud = (ComputeFramesUserData *)user_data;
3302 * 'tls->filter_ctx' is the location of the throw site.
3304 * mono_walk_stack() will never actually hit the throw site, but unwind
3305 * directly from the filter to the call site; we abort stack unwinding here
3306 * once this happens and resume from the throw site.
3308 if (info->frame_addr >= MONO_CONTEXT_GET_SP (&ud->tls->filter_state.ctx))
3309 return TRUE;
3311 return process_frame (info, ctx, user_data);
3315 * Return a malloc-ed list of StackFrame structures.
3317 static StackFrame**
3318 compute_frame_info_from (MonoInternalThread *thread, DebuggerTlsData *tls, MonoThreadUnwindState *state, int *out_nframes)
3320 ComputeFramesUserData user_data;
3321 MonoUnwindOptions opts = (MonoUnwindOptions)(MONO_UNWIND_DEFAULT | MONO_UNWIND_REG_LOCATIONS);
3322 StackFrame **res;
3323 int i, nframes;
3324 GSList *l;
3326 user_data.tls = tls;
3327 user_data.frames = NULL;
3329 mono_walk_stack_with_state (process_frame, state, opts, &user_data);
3331 nframes = g_slist_length (user_data.frames);
3332 res = g_new0 (StackFrame*, nframes);
3333 l = user_data.frames;
3334 for (i = 0; i < nframes; ++i) {
3335 res [i] = (StackFrame *)l->data;
3336 l = l->next;
3338 *out_nframes = nframes;
3340 return res;
3343 static void
3344 compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls, gboolean force_update)
3346 ComputeFramesUserData user_data;
3347 GSList *tmp;
3348 int i, findex, new_frame_count;
3349 StackFrame **new_frames, *f;
3350 MonoUnwindOptions opts = (MonoUnwindOptions)(MONO_UNWIND_DEFAULT | MONO_UNWIND_REG_LOCATIONS);
3352 // FIXME: Locking on tls
3353 if (tls->frames && tls->frames_up_to_date && !force_update)
3354 return;
3356 DEBUG_PRINTF (1, "Frames for %p(tid=%lx):\n", thread, (glong)thread->tid);
3358 if (CHECK_PROTOCOL_VERSION (2, 52)) {
3359 if (tls->restore_state.valid && MONO_CONTEXT_GET_IP (&tls->context.ctx) != MONO_CONTEXT_GET_IP (&tls->restore_state.ctx)) {
3360 new_frames = compute_frame_info_from (thread, tls, &tls->restore_state, &new_frame_count);
3361 invalidate_frames (tls);
3363 tls->frames = new_frames;
3364 tls->frame_count = new_frame_count;
3365 tls->frames_up_to_date = TRUE;
3366 return;
3370 user_data.tls = tls;
3371 user_data.frames = NULL;
3372 if (tls->terminated) {
3373 tls->frame_count = 0;
3374 return;
3375 } if (!tls->really_suspended && tls->async_state.valid) {
3376 /* Have to use the state saved by the signal handler */
3377 process_frame (&tls->async_last_frame, NULL, &user_data);
3378 mono_walk_stack_with_state (process_frame, &tls->async_state, opts, &user_data);
3379 } else if (tls->filter_state.valid) {
3381 * We are inside an exception filter.
3383 * First we add all the frames from inside the filter; 'tls->ctx' has the current context.
3385 if (tls->context.valid) {
3386 mono_walk_stack_with_state (process_filter_frame, &tls->context, opts, &user_data);
3387 DEBUG_PRINTF (1, "\tFrame: <call filter>\n");
3390 * After that, we resume unwinding from the location where the exception has been thrown.
3392 mono_walk_stack_with_state (process_frame, &tls->filter_state, opts, &user_data);
3393 } else if (tls->context.valid) {
3394 mono_walk_stack_with_state (process_frame, &tls->context, opts, &user_data);
3395 } else {
3396 // FIXME:
3397 tls->frame_count = 0;
3398 return;
3401 new_frame_count = g_slist_length (user_data.frames);
3402 new_frames = g_new0 (StackFrame*, new_frame_count);
3403 findex = 0;
3404 for (tmp = user_data.frames; tmp; tmp = tmp->next) {
3405 f = (StackFrame *)tmp->data;
3408 * Reuse the id for already existing stack frames, so invokes don't invalidate
3409 * the still valid stack frames.
3411 for (i = 0; i < tls->frame_count; ++i) {
3412 if (tls->frames [i]->frame_addr == f->frame_addr) {
3413 f->id = tls->frames [i]->id;
3414 break;
3418 if (i >= tls->frame_count)
3419 f->id = mono_atomic_inc_i32 (&frame_id);
3421 new_frames [findex ++] = f;
3424 g_slist_free (user_data.frames);
3426 invalidate_frames (tls);
3428 tls->frames = new_frames;
3429 tls->frame_count = new_frame_count;
3430 tls->frames_up_to_date = TRUE;
3432 if (CHECK_PROTOCOL_VERSION (2, 52)) {
3433 MonoJitTlsData *jit_data = thread->thread_info->jit_data;
3434 gboolean has_interp_resume_state = FALSE;
3435 MonoInterpFrameHandle interp_resume_frame = NULL;
3436 gpointer interp_resume_ip = 0;
3437 mini_get_interp_callbacks ()->get_resume_state (jit_data, &has_interp_resume_state, &interp_resume_frame, &interp_resume_ip);
3438 if (has_interp_resume_state && tls->frame_count > 0) {
3439 StackFrame *top_frame = tls->frames [0];
3440 if (interp_resume_frame == top_frame->interp_frame) {
3441 int native_offset = (int) ((uintptr_t) interp_resume_ip - (uintptr_t) top_frame->de.ji->code_start);
3442 top_frame->il_offset = calc_il_offset (top_frame->de.domain, top_frame->de.method, native_offset, TRUE);
3449 * GHFunc to emit an appdomain creation event
3450 * @param key Don't care
3451 * @param value A loaded appdomain
3452 * @param user_data Don't care
3454 static void
3455 emit_appdomain_load (gpointer key, gpointer value, gpointer user_data)
3457 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE, value);
3458 g_hash_table_foreach (get_agent_domain_info ((MonoDomain *)value)->loaded_classes, emit_type_load, NULL);
3462 * GHFunc to emit a thread start event
3463 * @param key A thread id
3464 * @param value A thread object
3465 * @param user_data Don't care
3467 static void
3468 emit_thread_start (gpointer key, gpointer value, gpointer user_data)
3470 g_assert (!mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (key)), debugger_thread_id));
3471 process_profiler_event (EVENT_KIND_THREAD_START, value);
3475 * GFunc to emit an assembly load event
3476 * @param value A loaded assembly
3477 * @param user_data Don't care
3479 static void
3480 emit_assembly_load (gpointer value, gpointer user_data)
3482 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, value);
3486 * GFunc to emit a type load event
3487 * @param value A loaded type
3488 * @param user_data Don't care
3490 static void
3491 emit_type_load (gpointer key, gpointer value, gpointer user_data)
3493 process_profiler_event (EVENT_KIND_TYPE_LOAD, value);
3497 static void gc_finalizing (MonoProfiler *prof)
3499 DebuggerTlsData *tls;
3501 if (is_debugger_thread ())
3502 return;
3504 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3505 g_assert (tls);
3506 tls->gc_finalizing = TRUE;
3509 static void gc_finalized (MonoProfiler *prof)
3511 DebuggerTlsData *tls;
3513 if (is_debugger_thread ())
3514 return;
3516 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3517 g_assert (tls);
3518 tls->gc_finalizing = FALSE;
3522 static char*
3523 strdup_tolower (char *s)
3525 char *s2, *p;
3527 s2 = g_strdup (s);
3528 for (p = s2; *p; ++p)
3529 *p = tolower (*p);
3530 return s2;
3534 * Same as g_path_get_basename () but handles windows paths as well,
3535 * which can occur in .mdb files created by pdb2mdb.
3537 static char*
3538 dbg_path_get_basename (const char *filename)
3540 char *r;
3542 if (!filename || strchr (filename, '/') || !strchr (filename, '\\'))
3543 return g_path_get_basename (filename);
3545 /* From gpath.c */
3547 /* No separator -> filename */
3548 r = (char*)strrchr (filename, '\\');
3549 if (r == NULL)
3550 return g_strdup (filename);
3552 /* Trailing slash, remove component */
3553 if (r [1] == 0){
3554 char *copy = g_strdup (filename);
3555 copy [r-filename] = 0;
3556 r = strrchr (copy, '\\');
3558 if (r == NULL){
3559 g_free (copy);
3560 return g_strdup ("/");
3562 r = g_strdup (&r[1]);
3563 g_free (copy);
3564 return r;
3567 return g_strdup (&r[1]);
3570 static GENERATE_TRY_GET_CLASS_WITH_CACHE(hidden_klass, "System.Diagnostics", "DebuggerHiddenAttribute")
3571 static GENERATE_TRY_GET_CLASS_WITH_CACHE(step_through_klass, "System.Diagnostics", "DebuggerStepThroughAttribute")
3572 static GENERATE_TRY_GET_CLASS_WITH_CACHE(non_user_klass, "System.Diagnostics", "DebuggerNonUserCodeAttribute")
3574 static void
3575 init_jit_info_dbg_attrs (MonoJitInfo *ji)
3577 ERROR_DECL (error);
3578 MonoCustomAttrInfo *ainfo;
3580 if (ji->dbg_attrs_inited)
3581 return;
3583 // NOTE: The following Debugger attributes may not exist if they are trimmed away by the ILLinker
3584 MonoClass *hidden_klass = mono_class_try_get_hidden_klass_class ();
3585 MonoClass *step_through_klass = mono_class_try_get_step_through_klass_class ();
3586 MonoClass *non_user_klass = mono_class_try_get_non_user_klass_class ();
3588 ainfo = mono_custom_attrs_from_method_checked (jinfo_get_method (ji), error);
3589 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3590 if (ainfo) {
3591 if (hidden_klass && mono_custom_attrs_has_attr (ainfo, hidden_klass))
3592 ji->dbg_hidden = TRUE;
3593 if (step_through_klass && mono_custom_attrs_has_attr (ainfo, step_through_klass))
3594 ji->dbg_step_through = TRUE;
3595 if (non_user_klass && mono_custom_attrs_has_attr (ainfo, non_user_klass))
3596 ji->dbg_non_user_code = TRUE;
3597 mono_custom_attrs_free (ainfo);
3600 ainfo = mono_custom_attrs_from_class_checked (jinfo_get_method (ji)->klass, error);
3601 mono_error_cleanup (error); /* FIXME don't swallow the error? */
3602 if (ainfo) {
3603 if (step_through_klass && mono_custom_attrs_has_attr (ainfo, step_through_klass))
3604 ji->dbg_step_through = TRUE;
3605 if (non_user_klass && mono_custom_attrs_has_attr (ainfo, non_user_klass))
3606 ji->dbg_non_user_code = TRUE;
3607 mono_custom_attrs_free (ainfo);
3610 mono_memory_barrier ();
3611 ji->dbg_attrs_inited = TRUE;
3615 * EVENT HANDLING
3619 * create_event_list:
3621 * Return a list of event request ids matching EVENT, starting from REQS, which
3622 * can be NULL to include all event requests. Set SUSPEND_POLICY to the suspend
3623 * policy.
3624 * We return request ids, instead of requests, to simplify threading, since
3625 * requests could be deleted anytime when the loader lock is not held.
3626 * LOCKING: Assumes the loader lock is held.
3628 static GSList*
3629 create_event_list (EventKind event, GPtrArray *reqs, MonoJitInfo *ji, EventInfo *ei, int *suspend_policy)
3631 int i, j;
3632 GSList *events = NULL;
3634 *suspend_policy = SUSPEND_POLICY_NONE;
3636 if (!reqs)
3637 reqs = event_requests;
3639 if (!reqs)
3640 return NULL;
3641 gboolean has_everything_else = FALSE;
3642 gboolean is_new_filtered_exception = FALSE;
3643 gboolean filteredException = TRUE;
3644 gint filtered_suspend_policy = 0;
3645 gint filtered_req_id = 0;
3646 gint everything_else_suspend_policy = 0;
3647 gint everything_else_req_id = 0;
3648 gboolean is_already_filtered = FALSE;
3649 for (i = 0; i < reqs->len; ++i) {
3650 EventRequest *req = (EventRequest *)g_ptr_array_index (reqs, i);
3651 if (req->event_kind == event) {
3652 gboolean filtered = FALSE;
3654 /* Apply filters */
3655 for (j = 0; j < req->nmodifiers; ++j) {
3656 Modifier *mod = &req->modifiers [j];
3658 if (mod->kind == MOD_KIND_COUNT) {
3659 filtered = TRUE;
3660 if (mod->data.count > 0) {
3661 if (mod->data.count > 0) {
3662 mod->data.count --;
3663 if (mod->data.count == 0)
3664 filtered = FALSE;
3667 } else if (mod->kind == MOD_KIND_THREAD_ONLY) {
3668 if (mod->data.thread != mono_thread_internal_current ())
3669 filtered = TRUE;
3670 } else if (mod->kind == MOD_KIND_EXCEPTION_ONLY && !mod->not_filtered_feature && ei) {
3671 if (mod->data.exc_class && mod->subclasses && !mono_class_is_assignable_from_internal (mod->data.exc_class, ei->exc->vtable->klass))
3672 filtered = TRUE;
3673 if (mod->data.exc_class && !mod->subclasses && mod->data.exc_class != ei->exc->vtable->klass)
3674 filtered = TRUE;
3675 if (ei->caught && !mod->caught)
3676 filtered = TRUE;
3677 if (!ei->caught && !mod->uncaught)
3678 filtered = TRUE;
3679 } else if (mod->kind == MOD_KIND_EXCEPTION_ONLY && mod->not_filtered_feature && ei) {
3680 is_new_filtered_exception = TRUE;
3681 if ((mod->data.exc_class && mod->subclasses && mono_class_is_assignable_from_internal (mod->data.exc_class, ei->exc->vtable->klass)) ||
3682 (mod->data.exc_class && !mod->subclasses && mod->data.exc_class != ei->exc->vtable->klass)) {
3683 is_already_filtered = TRUE;
3684 if ((ei->caught && mod->caught) || (!ei->caught && mod->uncaught)) {
3685 filteredException = FALSE;
3686 filtered_suspend_policy = req->suspend_policy;
3687 filtered_req_id = req->id;
3690 if (!mod->data.exc_class && mod->everything_else) {
3691 if ((ei->caught && mod->caught) || (!ei->caught && mod->uncaught)) {
3692 has_everything_else = TRUE;
3693 everything_else_req_id = req->id;
3694 everything_else_suspend_policy = req->suspend_policy;
3697 if (!mod->data.exc_class && !mod->everything_else) {
3698 if ((ei->caught && mod->caught) || (!ei->caught && mod->uncaught)) {
3699 filteredException = FALSE;
3700 filtered_suspend_policy = req->suspend_policy;
3701 filtered_req_id = req->id;
3704 } else if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && ji) {
3705 int k;
3706 gboolean found = FALSE;
3707 MonoAssembly **assemblies = mod->data.assemblies;
3709 if (assemblies) {
3710 for (k = 0; assemblies [k]; ++k)
3711 if (assemblies [k] == m_class_get_image (jinfo_get_method (ji)->klass)->assembly)
3712 found = TRUE;
3714 if (!found)
3715 filtered = TRUE;
3716 } else if (mod->kind == MOD_KIND_SOURCE_FILE_ONLY && ei && ei->klass) {
3717 gpointer iter = NULL;
3718 MonoMethod *method;
3719 MonoDebugSourceInfo *sinfo;
3720 char *s;
3721 gboolean found = FALSE;
3722 int i;
3723 GPtrArray *source_file_list;
3725 while ((method = mono_class_get_methods (ei->klass, &iter))) {
3726 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
3728 if (minfo) {
3729 mono_debug_get_seq_points (minfo, NULL, &source_file_list, NULL, NULL, NULL);
3730 for (i = 0; i < source_file_list->len; ++i) {
3731 sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
3733 * Do a case-insesitive match by converting the file name to
3734 * lowercase.
3736 s = strdup_tolower (sinfo->source_file);
3737 if (g_hash_table_lookup (mod->data.source_files, s))
3738 found = TRUE;
3739 else {
3740 char *s2 = dbg_path_get_basename (sinfo->source_file);
3741 char *s3 = strdup_tolower (s2);
3743 if (g_hash_table_lookup (mod->data.source_files, s3))
3744 found = TRUE;
3745 g_free (s2);
3746 g_free (s3);
3748 g_free (s);
3750 g_ptr_array_free (source_file_list, TRUE);
3753 if (!found)
3754 filtered = TRUE;
3755 } else if (mod->kind == MOD_KIND_TYPE_NAME_ONLY && ei && ei->klass) {
3756 char *s;
3758 s = mono_type_full_name (m_class_get_byval_arg (ei->klass));
3759 if (!g_hash_table_lookup (mod->data.type_names, s))
3760 filtered = TRUE;
3761 g_free (s);
3762 } else if (mod->kind == MOD_KIND_STEP) {
3763 if ((mod->data.filter & STEP_FILTER_STATIC_CTOR) && ji &&
3764 (jinfo_get_method (ji)->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
3765 !strcmp (jinfo_get_method (ji)->name, ".cctor") &&
3766 (jinfo_get_method (ji) != ((SingleStepReq*)req->info)->start_method))
3767 filtered = TRUE;
3768 if ((mod->data.filter & STEP_FILTER_DEBUGGER_HIDDEN) && ji) {
3769 init_jit_info_dbg_attrs (ji);
3770 if (ji->dbg_hidden)
3771 filtered = TRUE;
3773 if ((mod->data.filter & STEP_FILTER_DEBUGGER_STEP_THROUGH) && ji) {
3774 init_jit_info_dbg_attrs (ji);
3775 if (ji->dbg_step_through)
3776 filtered = TRUE;
3778 if ((mod->data.filter & STEP_FILTER_DEBUGGER_NON_USER_CODE) && ji) {
3779 init_jit_info_dbg_attrs (ji);
3780 if (ji->dbg_non_user_code)
3781 filtered = TRUE;
3786 if (!filtered && !is_new_filtered_exception) {
3787 *suspend_policy = MAX (*suspend_policy, req->suspend_policy);
3788 events = g_slist_append (events, GINT_TO_POINTER (req->id));
3793 if (has_everything_else && !is_already_filtered) {
3794 filteredException = FALSE;
3795 filtered_suspend_policy = everything_else_suspend_policy;
3796 filtered_req_id = everything_else_req_id;
3799 if (!filteredException) {
3800 *suspend_policy = MAX (*suspend_policy, filtered_suspend_policy);
3801 events = g_slist_append (events, GINT_TO_POINTER (filtered_req_id));
3804 /* Send a VM START/DEATH event by default */
3805 if (event == EVENT_KIND_VM_START)
3806 events = g_slist_append (events, GINT_TO_POINTER (0));
3807 if (event == EVENT_KIND_VM_DEATH)
3808 events = g_slist_append (events, GINT_TO_POINTER (0));
3810 return events;
3813 static G_GNUC_UNUSED const char*
3814 event_to_string (EventKind event)
3816 switch (event) {
3817 case EVENT_KIND_VM_START: return "VM_START";
3818 case EVENT_KIND_VM_DEATH: return "VM_DEATH";
3819 case EVENT_KIND_THREAD_START: return "THREAD_START";
3820 case EVENT_KIND_THREAD_DEATH: return "THREAD_DEATH";
3821 case EVENT_KIND_APPDOMAIN_CREATE: return "APPDOMAIN_CREATE";
3822 case EVENT_KIND_APPDOMAIN_UNLOAD: return "APPDOMAIN_UNLOAD";
3823 case EVENT_KIND_METHOD_ENTRY: return "METHOD_ENTRY";
3824 case EVENT_KIND_METHOD_EXIT: return "METHOD_EXIT";
3825 case EVENT_KIND_ASSEMBLY_LOAD: return "ASSEMBLY_LOAD";
3826 case EVENT_KIND_ASSEMBLY_UNLOAD: return "ASSEMBLY_UNLOAD";
3827 case EVENT_KIND_BREAKPOINT: return "BREAKPOINT";
3828 case EVENT_KIND_STEP: return "STEP";
3829 case EVENT_KIND_TYPE_LOAD: return "TYPE_LOAD";
3830 case EVENT_KIND_EXCEPTION: return "EXCEPTION";
3831 case EVENT_KIND_KEEPALIVE: return "KEEPALIVE";
3832 case EVENT_KIND_USER_BREAK: return "USER_BREAK";
3833 case EVENT_KIND_USER_LOG: return "USER_LOG";
3834 case EVENT_KIND_CRASH: return "CRASH";
3835 default:
3836 g_assert_not_reached ();
3837 return "";
3842 * process_event:
3844 * Send an event to the client, suspending the vm if needed.
3845 * LOCKING: Since this can suspend the calling thread, no locks should be held
3846 * by the caller.
3847 * The EVENTS list is freed by this function.
3849 static void
3850 process_event (EventKind event, gpointer arg, gint32 il_offset, MonoContext *ctx, GSList *events, int suspend_policy)
3852 Buffer buf;
3853 GSList *l;
3854 MonoDomain *domain = mono_domain_get ();
3855 MonoThread *thread = NULL;
3856 MonoObject *keepalive_obj = NULL;
3857 gboolean send_success = FALSE;
3858 static int ecount;
3859 int nevents;
3861 if (!agent_inited) {
3862 DEBUG_PRINTF (2, "Debugger agent not initialized yet: dropping %s\n", event_to_string (event));
3863 return;
3866 if (!vm_start_event_sent && event != EVENT_KIND_VM_START) {
3867 // FIXME: We miss those events
3868 DEBUG_PRINTF (2, "VM start event not sent yet: dropping %s\n", event_to_string (event));
3869 return;
3872 if (vm_death_event_sent) {
3873 DEBUG_PRINTF (2, "VM death event has been sent: dropping %s\n", event_to_string (event));
3874 return;
3877 if (mono_runtime_is_shutting_down () && event != EVENT_KIND_VM_DEATH) {
3878 DEBUG_PRINTF (2, "Mono runtime is shutting down: dropping %s\n", event_to_string (event));
3879 return;
3882 if (disconnected) {
3883 DEBUG_PRINTF (2, "Debugger client is not connected: dropping %s\n", event_to_string (event));
3884 return;
3887 if (event == EVENT_KIND_KEEPALIVE)
3888 suspend_policy = SUSPEND_POLICY_NONE;
3889 else {
3890 if (events == NULL)
3891 return;
3893 if (agent_config.defer) {
3894 if (is_debugger_thread ()) {
3895 /* Don't suspend on events from the debugger thread */
3896 suspend_policy = SUSPEND_POLICY_NONE;
3898 } else {
3899 if (is_debugger_thread () && event != EVENT_KIND_VM_DEATH)
3900 // FIXME: Send these with a NULL thread, don't suspend the current thread
3901 return;
3905 if (event == EVENT_KIND_VM_START)
3906 suspend_policy = agent_config.suspend ? SUSPEND_POLICY_ALL : SUSPEND_POLICY_NONE;
3908 nevents = g_slist_length (events);
3909 buffer_init (&buf, 128);
3910 buffer_add_byte (&buf, suspend_policy);
3911 buffer_add_int (&buf, nevents);
3913 for (l = events; l; l = l->next) {
3914 buffer_add_byte (&buf, event); // event kind
3915 buffer_add_int (&buf, GPOINTER_TO_INT (l->data)); // request id
3917 ecount ++;
3919 if (event == EVENT_KIND_VM_DEATH) {
3920 thread = NULL;
3921 } else {
3922 if (!thread)
3923 thread = is_debugger_thread () ? mono_thread_get_main () : mono_thread_current ();
3925 if (event == EVENT_KIND_VM_START && arg != NULL)
3926 thread = (MonoThread *)arg;
3929 buffer_add_objid (&buf, (MonoObject*)thread); // thread
3931 switch (event) {
3932 case EVENT_KIND_THREAD_START:
3933 case EVENT_KIND_THREAD_DEATH:
3934 break;
3935 case EVENT_KIND_APPDOMAIN_CREATE:
3936 case EVENT_KIND_APPDOMAIN_UNLOAD:
3937 buffer_add_domainid (&buf, (MonoDomain *)arg);
3938 break;
3939 case EVENT_KIND_METHOD_ENTRY:
3940 case EVENT_KIND_METHOD_EXIT:
3941 buffer_add_methodid (&buf, domain, (MonoMethod *)arg);
3942 break;
3943 case EVENT_KIND_ASSEMBLY_LOAD:
3944 buffer_add_assemblyid (&buf, domain, (MonoAssembly *)arg);
3945 break;
3946 case EVENT_KIND_ASSEMBLY_UNLOAD: {
3947 DebuggerTlsData *tls;
3949 /* The domain the assembly belonged to is not equal to the current domain */
3950 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3951 g_assert (tls);
3952 g_assert (tls->domain_unloading);
3954 buffer_add_assemblyid (&buf, tls->domain_unloading, (MonoAssembly *)arg);
3955 break;
3957 case EVENT_KIND_TYPE_LOAD:
3958 buffer_add_typeid (&buf, domain, (MonoClass *)arg);
3959 break;
3960 case EVENT_KIND_BREAKPOINT:
3961 case EVENT_KIND_STEP: {
3962 DebuggerTlsData *tls;
3963 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3964 g_assert (tls);
3965 mono_stopwatch_stop (&tls->step_time);
3966 MonoMethod *method = (MonoMethod *)arg;
3968 buffer_add_methodid (&buf, domain, method);
3969 buffer_add_long (&buf, il_offset);
3970 break;
3972 case EVENT_KIND_VM_START:
3973 buffer_add_domainid (&buf, mono_get_root_domain ());
3974 break;
3975 case EVENT_KIND_VM_DEATH:
3976 if (CHECK_PROTOCOL_VERSION (2, 27))
3977 buffer_add_int (&buf, mono_environment_exitcode_get ());
3978 break;
3979 case EVENT_KIND_CRASH: {
3980 EventInfo *ei = (EventInfo *)arg;
3981 buffer_add_long (&buf, ei->hashes->offset_free_hash);
3982 buffer_add_string (&buf, ei->dump);
3983 break;
3985 case EVENT_KIND_EXCEPTION: {
3986 EventInfo *ei = (EventInfo *)arg;
3987 buffer_add_objid (&buf, ei->exc);
3989 * We are not yet suspending, so get_objref () will not keep this object alive. So we need to do it
3990 * later after the suspension. (#12494).
3992 keepalive_obj = ei->exc;
3993 break;
3995 case EVENT_KIND_USER_BREAK: {
3996 DebuggerTlsData *tls;
3997 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
3998 g_assert (tls);
3999 // We are already processing a breakpoint event
4000 if (tls->disable_breakpoints)
4001 return;
4002 mono_stopwatch_stop (&tls->step_time);
4003 break;
4005 case EVENT_KIND_USER_LOG: {
4006 EventInfo *ei = (EventInfo *)arg;
4007 buffer_add_int (&buf, ei->level);
4008 buffer_add_string (&buf, ei->category ? ei->category : "");
4009 buffer_add_string (&buf, ei->message ? ei->message : "");
4010 break;
4012 case EVENT_KIND_KEEPALIVE:
4013 suspend_policy = SUSPEND_POLICY_NONE;
4014 break;
4015 default:
4016 g_assert_not_reached ();
4020 if (event == EVENT_KIND_VM_START) {
4021 if (!agent_config.defer) {
4022 ERROR_DECL (error);
4023 start_debugger_thread (error);
4024 mono_error_assert_ok (error);
4028 if (event == EVENT_KIND_VM_DEATH) {
4029 vm_death_event_sent = TRUE;
4030 suspend_policy = SUSPEND_POLICY_NONE;
4033 if (mono_runtime_is_shutting_down ())
4034 suspend_policy = SUSPEND_POLICY_NONE;
4036 if (suspend_policy != SUSPEND_POLICY_NONE) {
4038 * Save the thread context and start suspending before sending the packet,
4039 * since we could be receiving the resume request before send_packet ()
4040 * returns.
4042 save_thread_context (ctx);
4043 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, mono_thread_internal_current ());
4044 tls->suspend_count++;
4045 suspend_vm ();
4047 if (keepalive_obj)
4048 /* This will keep this object alive */
4049 get_objref (keepalive_obj);
4052 send_success = send_packet (CMD_SET_EVENT, CMD_COMPOSITE, &buf);
4054 if (send_success) {
4055 DebuggerTlsData *tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4056 mono_debugger_log_event (tls, event_to_string (event), buf.buf, buffer_len (&buf));
4059 buffer_free (&buf);
4061 g_slist_free (events);
4062 events = NULL;
4064 if (!send_success) {
4065 DEBUG_PRINTF (2, "Sending command %s failed.\n", event_to_string (event));
4066 return;
4069 if (event == EVENT_KIND_VM_START) {
4070 vm_start_event_sent = TRUE;
4073 DEBUG_PRINTF (1, "[%p] Sent %d events %s(%d), suspend=%d.\n", (gpointer) (gsize) mono_native_thread_id_get (), nevents, event_to_string (event), ecount, suspend_policy);
4075 switch (suspend_policy) {
4076 case SUSPEND_POLICY_NONE:
4077 break;
4078 case SUSPEND_POLICY_ALL:
4079 suspend_current ();
4080 break;
4081 case SUSPEND_POLICY_EVENT_THREAD:
4082 NOT_IMPLEMENTED;
4083 break;
4084 default:
4085 g_assert_not_reached ();
4089 static void
4090 process_profiler_event (EventKind event, gpointer arg)
4092 int suspend_policy;
4093 GSList *events;
4094 EventInfo ei, *ei_arg = NULL;
4096 if (event == EVENT_KIND_TYPE_LOAD) {
4097 ei.klass = (MonoClass *)arg;
4098 ei_arg = &ei;
4101 mono_loader_lock ();
4102 events = create_event_list (event, NULL, NULL, ei_arg, &suspend_policy);
4103 mono_loader_unlock ();
4105 process_event (event, arg, 0, NULL, events, suspend_policy);
4108 static void
4109 runtime_initialized (MonoProfiler *prof)
4111 process_profiler_event (EVENT_KIND_VM_START, mono_thread_current ());
4112 if (agent_config.defer) {
4113 ERROR_DECL (error);
4114 start_debugger_thread (error);
4115 mono_error_assert_ok (error);
4119 static void
4120 runtime_shutdown (MonoProfiler *prof)
4122 process_profiler_event (EVENT_KIND_VM_DEATH, NULL);
4124 mono_debugger_agent_cleanup ();
4127 static void
4128 thread_startup (MonoProfiler *prof, uintptr_t tid)
4130 MonoInternalThread *thread = mono_thread_internal_current ();
4131 MonoInternalThread *old_thread;
4132 DebuggerTlsData *tls;
4134 if (is_debugger_thread ())
4135 return;
4137 g_assert (mono_native_thread_id_equals (MONO_UINT_TO_NATIVE_THREAD_ID (tid), MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid)));
4139 mono_loader_lock ();
4140 old_thread = (MonoInternalThread *)mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
4141 mono_loader_unlock ();
4142 if (old_thread) {
4143 if (thread == old_thread) {
4145 * For some reason, thread_startup () might be called for the same thread
4146 * multiple times (attach ?).
4148 DEBUG_PRINTF (1, "[%p] thread_start () called multiple times for %p, ignored.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
4149 return;
4150 } else {
4152 * thread_end () might not be called for some threads, and the tid could
4153 * get reused.
4155 DEBUG_PRINTF (1, "[%p] Removing stale data for tid %p.\n", GUINT_TO_POINTER (tid), GUINT_TO_POINTER (tid));
4156 mono_loader_lock ();
4157 mono_g_hash_table_remove (thread_to_tls, old_thread);
4158 mono_g_hash_table_remove (tid_to_thread, GUINT_TO_POINTER (tid));
4159 mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
4160 mono_loader_unlock ();
4164 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4165 g_assert (!tls);
4166 // FIXME: Free this somewhere
4167 tls = g_new0 (DebuggerTlsData, 1);
4168 MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, NULL, "Debugger Thread Reference");
4169 tls->thread = thread;
4170 // Do so we have thread id even after termination
4171 tls->thread_id = (intptr_t) thread->tid;
4172 mono_native_tls_set_value (debugger_tls_id, tls);
4174 DEBUG_PRINTF (1, "[%p] Thread started, obj=%p, tls=%p.\n", (gpointer)tid, thread, tls);
4176 mono_loader_lock ();
4177 mono_g_hash_table_insert_internal (thread_to_tls, thread, tls);
4178 mono_g_hash_table_insert_internal (tid_to_thread, (gpointer)tid, thread);
4179 mono_g_hash_table_insert_internal (tid_to_thread_obj, GUINT_TO_POINTER (tid), mono_thread_current ());
4180 mono_loader_unlock ();
4182 process_profiler_event (EVENT_KIND_THREAD_START, thread);
4185 * suspend_vm () could have missed this thread, so wait for a resume.
4188 suspend_current ();
4191 static void
4192 thread_end (MonoProfiler *prof, uintptr_t tid)
4194 MonoInternalThread *thread;
4195 DebuggerTlsData *tls = NULL;
4197 mono_loader_lock ();
4198 thread = (MonoInternalThread *)mono_g_hash_table_lookup (tid_to_thread, GUINT_TO_POINTER (tid));
4199 if (thread) {
4200 mono_g_hash_table_remove (tid_to_thread_obj, GUINT_TO_POINTER (tid));
4201 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
4202 if (tls) {
4203 /* FIXME: Maybe we need to free this instead, but some code can't handle that */
4204 tls->terminated = TRUE;
4205 /* Can't remove from tid_to_thread, as that would defeat the check in thread_start () */
4206 MONO_GC_UNREGISTER_ROOT (tls->thread);
4207 tls->thread = NULL;
4210 mono_loader_unlock ();
4212 /* We might be called for threads started before we registered the start callback */
4213 if (thread) {
4214 DEBUG_PRINTF (1, "[%p] Thread terminated, obj=%p, tls=%p (domain=%p).\n", (gpointer)tid, thread, tls, (gpointer)mono_domain_get ());
4216 if (mono_thread_internal_is_current (thread) &&
4217 (!mono_native_tls_get_value (debugger_tls_id) ||
4218 !mono_domain_get ())
4221 * This can happen on darwin and android since we
4222 * deregister threads using pthread dtors.
4223 * process_profiler_event () and the code it calls
4224 * cannot handle a null TLS value.
4226 return;
4229 process_profiler_event (EVENT_KIND_THREAD_DEATH, thread);
4233 static void
4234 appdomain_load (MonoProfiler *prof, MonoDomain *domain)
4236 mono_de_domain_add (domain);
4238 process_profiler_event (EVENT_KIND_APPDOMAIN_CREATE, domain);
4241 static void
4242 appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain)
4244 DebuggerTlsData *tls;
4246 /* This might be called during shutdown on the debugger thread from the CMD_VM_EXIT code */
4247 if (is_debugger_thread ())
4248 return;
4251 * Remember the currently unloading appdomain as it is needed to generate
4252 * proper ids for unloading assemblies.
4254 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4255 g_assert (tls);
4256 tls->domain_unloading = domain;
4259 static void
4260 appdomain_unload (MonoProfiler *prof, MonoDomain *domain)
4262 DebuggerTlsData *tls;
4264 if (is_debugger_thread ())
4265 return;
4267 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4268 g_assert (tls);
4269 tls->domain_unloading = NULL;
4271 mono_de_clear_breakpoints_for_domain (domain);
4273 mono_loader_lock ();
4274 /* Invalidate each thread's frame stack */
4275 mono_g_hash_table_foreach (thread_to_tls, invalidate_each_thread, NULL);
4276 mono_loader_unlock ();
4278 process_profiler_event (EVENT_KIND_APPDOMAIN_UNLOAD, domain);
4282 * invalidate_each_thread:
4284 * A GHFunc to invalidate frames.
4285 * value must be a DebuggerTlsData*
4287 static void
4288 invalidate_each_thread (gpointer key, gpointer value, gpointer user_data)
4290 invalidate_frames ((DebuggerTlsData *)value);
4293 static void
4294 assembly_load (MonoProfiler *prof, MonoAssembly *assembly)
4296 /* Sent later in jit_end () */
4297 dbg_lock ();
4298 g_ptr_array_add (pending_assembly_loads, assembly);
4299 dbg_unlock ();
4302 static void
4303 assembly_unload (MonoProfiler *prof, MonoAssembly *assembly)
4305 if (is_debugger_thread ())
4306 return;
4308 process_profiler_event (EVENT_KIND_ASSEMBLY_UNLOAD, assembly);
4310 clear_event_requests_for_assembly (assembly);
4311 clear_types_for_assembly (assembly);
4314 static void
4315 send_type_load (MonoClass *klass)
4317 gboolean type_load = FALSE;
4318 MonoDomain *domain = mono_domain_get ();
4319 AgentDomainInfo *info = NULL;
4321 info = get_agent_domain_info (domain);
4323 mono_loader_lock ();
4325 if (!g_hash_table_lookup (info->loaded_classes, klass)) {
4326 type_load = TRUE;
4327 g_hash_table_insert (info->loaded_classes, klass, klass);
4330 mono_loader_unlock ();
4332 if (type_load)
4333 emit_type_load (klass, klass, NULL);
4337 * Emit load events for all types currently loaded in the domain.
4338 * Takes the loader and domain locks.
4339 * user_data is unused.
4341 static void
4342 send_types_for_domain (MonoDomain *domain, void *user_data)
4344 MonoDomain* old_domain;
4345 AgentDomainInfo *info = NULL;
4347 if (mono_domain_is_unloading (domain))
4348 return;
4350 info = get_agent_domain_info (domain);
4351 g_assert (info);
4353 old_domain = mono_domain_get ();
4355 mono_domain_set_fast (domain, TRUE);
4357 mono_loader_lock ();
4358 g_hash_table_foreach (info->loaded_classes, emit_type_load, NULL);
4359 mono_loader_unlock ();
4361 mono_domain_set_fast (old_domain, TRUE);
4364 static void
4365 send_assemblies_for_domain (MonoDomain *domain, void *user_data)
4367 GSList *tmp;
4368 MonoDomain* old_domain;
4370 if (mono_domain_is_unloading (domain))
4371 return;
4373 old_domain = mono_domain_get ();
4375 mono_domain_set_fast (domain, TRUE);
4377 mono_domain_assemblies_lock (domain);
4378 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
4379 MonoAssembly* ass = (MonoAssembly *)tmp->data;
4380 emit_assembly_load (ass, NULL);
4382 mono_domain_assemblies_unlock (domain);
4384 mono_domain_set_fast (old_domain, TRUE);
4387 static void
4388 jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
4390 jit_end (prof, method, jinfo);
4393 static void
4394 jit_failed (MonoProfiler *prof, MonoMethod *method)
4396 jit_end (prof, method, NULL);
4399 static void
4400 jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
4403 * We emit type load events when the first method of the type is JITted,
4404 * since the class load profiler callbacks might be called with the
4405 * loader lock held. They could also occur in the debugger thread.
4406 * Same for assembly load events.
4408 while (TRUE) {
4409 MonoAssembly *assembly = NULL;
4411 // FIXME: Maybe store this in TLS so the thread of the event is correct ?
4412 dbg_lock ();
4413 if (pending_assembly_loads->len > 0) {
4414 assembly = (MonoAssembly *)g_ptr_array_index (pending_assembly_loads, 0);
4415 g_ptr_array_remove_index (pending_assembly_loads, 0);
4417 dbg_unlock ();
4419 if (assembly) {
4420 process_profiler_event (EVENT_KIND_ASSEMBLY_LOAD, assembly);
4421 } else {
4422 break;
4426 send_type_load (method->klass);
4428 if (jinfo)
4429 mono_de_add_pending_breakpoints (method, jinfo);
4433 * SINGLE STEPPING
4436 static void
4437 event_requests_cleanup (void)
4439 mono_loader_lock ();
4440 int i = 0;
4441 while (i < event_requests->len) {
4442 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
4444 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
4445 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
4446 g_ptr_array_remove_index_fast (event_requests, i);
4447 g_free (req);
4448 } else {
4449 i ++;
4452 mono_loader_unlock ();
4456 * ss_calculate_framecount:
4458 * Ensure DebuggerTlsData fields are filled out.
4460 static void
4461 ss_calculate_framecount (void *the_tls, MonoContext *ctx, gboolean force_use_ctx, DbgEngineStackFrame ***frames, int *nframes)
4463 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4465 if (force_use_ctx || !tls->context.valid)
4466 mono_thread_state_init_from_monoctx (&tls->context, ctx);
4467 compute_frame_info (tls->thread, tls, FALSE);
4468 if (frames)
4469 *frames = (DbgEngineStackFrame**)tls->frames;
4470 if (nframes)
4471 *nframes = tls->frame_count;
4475 * ss_discard_frame_data:
4477 * Discard frame data and invalidate any context
4479 static void
4480 ss_discard_frame_context (void *the_tls)
4482 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4483 tls->context.valid = FALSE;
4484 tls->async_state.valid = FALSE;
4485 invalidate_frames (tls);
4488 static MonoContext*
4489 tls_get_restore_state (void *the_tls)
4491 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4493 return &tls->restore_state.ctx;
4496 static gboolean
4497 ensure_jit (DbgEngineStackFrame* the_frame)
4499 StackFrame *frame = (StackFrame*)the_frame;
4500 if (!frame->jit) {
4501 frame->jit = mono_debug_find_method (frame->api_method, frame->de.domain);
4502 if (!frame->jit && frame->api_method->is_inflated)
4503 frame->jit = mono_debug_find_method(mono_method_get_declaring_generic_method (frame->api_method), frame->de.domain);
4504 if (!frame->jit) {
4505 char *s;
4507 /* This could happen for aot images with no jit debug info */
4508 s = mono_method_full_name (frame->api_method, TRUE);
4509 DEBUG_PRINTF(1, "[dbg] No debug information found for '%s'.\n", s);
4510 g_free (s);
4511 return FALSE;
4514 return TRUE;
4517 static gboolean
4518 breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
4520 return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly;
4523 //This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
4524 //since thread probably changed...
4525 static int
4526 get_this_async_id (DbgEngineStackFrame *frame)
4528 MonoClassField *builder_field;
4529 gpointer builder;
4530 MonoMethod *method;
4531 MonoObject *ex;
4532 ERROR_DECL (error);
4533 MonoObject *obj;
4534 gboolean old_disable_breakpoints = FALSE;
4535 DebuggerTlsData *tls;
4538 * FRAME points to a method in a state machine class/struct.
4539 * Call the ObjectIdForDebugger method of the associated method builder type.
4541 builder = get_async_method_builder (frame);
4542 if (!builder)
4543 return 0;
4545 builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
4546 if (!builder_field)
4547 return 0;
4549 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4550 if (tls) {
4551 old_disable_breakpoints = tls->disable_breakpoints;
4552 tls->disable_breakpoints = TRUE;
4555 method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type));
4556 if (!method) {
4557 if (tls)
4558 tls->disable_breakpoints = old_disable_breakpoints;
4559 return 0;
4561 obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error);
4562 mono_error_assert_ok (error);
4564 if (tls)
4565 tls->disable_breakpoints = old_disable_breakpoints;
4567 return get_objid (obj);
4570 static gboolean
4571 begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
4573 DebuggerTlsData *tls = (DebuggerTlsData*)the_tls;
4576 * Skip the instruction causing the breakpoint signal.
4578 if (from_signal)
4579 mono_arch_skip_breakpoint (ctx, ji);
4581 if (tls->disable_breakpoints)
4582 return FALSE;
4583 return TRUE;
4586 typedef struct {
4587 GSList *bp_events, *ss_events, *enter_leave_events;
4588 EventKind kind;
4589 int suspend_policy;
4590 } BreakPointEvents;
4592 static void*
4593 create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind)
4595 int suspend_policy = 0;
4596 BreakPointEvents *evts = g_new0 (BreakPointEvents, 1);
4597 if (ss_reqs && ss_reqs->len > 0)
4598 evts->ss_events = create_event_list (EVENT_KIND_STEP, ss_reqs, ji, NULL, &suspend_policy);
4599 else if (bp_reqs && bp_reqs->len > 0)
4600 evts->bp_events = create_event_list (EVENT_KIND_BREAKPOINT, bp_reqs, ji, NULL, &suspend_policy);
4601 else if (kind != EVENT_KIND_BREAKPOINT)
4602 evts->enter_leave_events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
4604 evts->kind = kind;
4605 evts->suspend_policy = suspend_policy;
4606 return evts;
4609 static void
4610 process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset)
4612 BreakPointEvents *evts = (BreakPointEvents*)_evts;
4614 * FIXME: The first event will suspend, so the second will only be sent after the
4615 * resume.
4617 if (evts->ss_events)
4618 process_event (EVENT_KIND_STEP, method, il_offset, ctx, evts->ss_events, evts->suspend_policy);
4619 if (evts->bp_events)
4620 process_event (evts->kind, method, il_offset, ctx, evts->bp_events, evts->suspend_policy);
4621 if (evts->enter_leave_events)
4622 process_event (evts->kind, method, il_offset, ctx, evts->enter_leave_events, evts->suspend_policy);
4624 g_free (evts);
4627 /* Process a breakpoint/single step event after resuming from a signal handler */
4628 static void
4629 process_signal_event (void (*func) (void*, gboolean))
4631 DebuggerTlsData *tls;
4632 MonoThreadUnwindState orig_restore_state;
4633 MonoContext ctx;
4635 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4636 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4637 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4638 mono_thread_state_init_from_monoctx (&tls->restore_state, &tls->handler_ctx);
4640 func (tls, TRUE);
4642 /* This is called when resuming from a signal handler, so it shouldn't return */
4643 memcpy (&ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4644 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4645 mono_restore_context (&ctx);
4646 g_assert_not_reached ();
4649 static void
4650 process_breakpoint_from_signal (void)
4652 process_signal_event (mono_de_process_breakpoint);
4655 static void
4656 resume_from_signal_handler (void *sigctx, void *func)
4658 DebuggerTlsData *tls;
4659 MonoContext ctx;
4661 /* Save the original context in TLS */
4662 // FIXME: This might not work on an altstack ?
4663 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4664 if (!tls)
4665 g_printerr ("Thread %p is not attached to the JIT.\n", (gpointer) (gsize) mono_native_thread_id_get ());
4666 g_assert (tls);
4668 // FIXME: MonoContext usually doesn't include the fp registers, so these are
4669 // clobbered by a single step/breakpoint event. If this turns out to be a problem,
4670 // clob:c could be added to op_seq_point.
4672 mono_sigctx_to_monoctx (sigctx, &ctx);
4673 memcpy (&tls->handler_ctx, &ctx, sizeof (MonoContext));
4674 #ifdef MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX
4675 mono_arch_setup_resume_sighandler_ctx (&ctx, func);
4676 #else
4677 MONO_CONTEXT_SET_IP (&ctx, func);
4678 #endif
4679 mono_monoctx_to_sigctx (&ctx, sigctx);
4682 static void
4683 debugger_agent_breakpoint_hit (void *sigctx)
4686 * We are called from a signal handler, and running code there causes all kinds of
4687 * problems, like the original signal is disabled, libgc can't handle altstack, etc.
4688 * So set up the signal context to return to the real breakpoint handler function.
4690 resume_from_signal_handler (sigctx, (gpointer)process_breakpoint_from_signal);
4693 typedef struct {
4694 gboolean found;
4695 MonoContext *ctx;
4696 } UserBreakCbData;
4698 static gboolean
4699 user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data)
4701 UserBreakCbData *data = (UserBreakCbData*)user_data;
4703 if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED || frame->type == FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX) {
4704 data->found = TRUE;
4705 return TRUE;
4707 if (frame->managed) {
4708 data->found = TRUE;
4709 *data->ctx = *ctx;
4711 return TRUE;
4713 return FALSE;
4717 * Called by System.Diagnostics.Debugger:Break ().
4719 static void
4720 debugger_agent_user_break (void)
4722 if (agent_config.enabled) {
4723 MonoContext ctx;
4724 int suspend_policy;
4725 GSList *events;
4726 UserBreakCbData data;
4728 memset (&data, 0, sizeof (data));
4729 data.ctx = &ctx;
4731 /* Obtain a context */
4732 MONO_CONTEXT_SET_IP (&ctx, NULL);
4733 mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data);
4734 g_assert (data.found);
4736 mono_loader_lock ();
4737 events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy);
4738 mono_loader_unlock ();
4740 process_event (EVENT_KIND_USER_BREAK, NULL, 0, &ctx, events, suspend_policy);
4741 } else if (mini_debug_options.native_debugger_break) {
4742 G_BREAKPOINT ();
4746 static void
4747 begin_single_step_processing (MonoContext *ctx, gboolean from_signal)
4749 if (from_signal)
4750 mono_arch_skip_single_step (ctx);
4753 static void
4754 process_single_step (void)
4756 process_signal_event (mono_de_process_single_step);
4760 * debugger_agent_single_step_event:
4762 * Called from a signal handler to handle a single step event.
4764 static void
4765 debugger_agent_single_step_event (void *sigctx)
4767 /* Resume to process_single_step through the signal context */
4769 // FIXME: Since step out/over is implemented using step in, the step in case should
4770 // be as fast as possible. Move the relevant code from mono_de_process_single_step ()
4771 // here
4773 if (is_debugger_thread ()) {
4775 * This could happen despite our best effors when the runtime calls
4776 * assembly/type resolve hooks.
4777 * FIXME: Breakpoints too.
4779 MonoContext ctx;
4781 mono_sigctx_to_monoctx (sigctx, &ctx);
4782 mono_arch_skip_single_step (&ctx);
4783 mono_monoctx_to_sigctx (&ctx, sigctx);
4784 return;
4787 resume_from_signal_handler (sigctx, (gpointer)process_single_step);
4790 static void
4791 debugger_agent_single_step_from_context (MonoContext *ctx)
4793 DebuggerTlsData *tls;
4794 MonoThreadUnwindState orig_restore_state;
4796 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4797 /* Fastpath during invokes, see in process_suspend () */
4798 if (tls && suspend_count && suspend_count - tls->resume_count == 0)
4799 return;
4801 if (is_debugger_thread ())
4802 return;
4804 g_assert (tls);
4806 tls->terminated = FALSE;
4808 /* Have to save/restore the restore_ctx as we can be called recursively during invokes etc. */
4809 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4810 mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
4811 memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
4813 mono_de_process_single_step (tls, FALSE);
4815 memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4816 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4819 static void
4820 debugger_agent_breakpoint_from_context (MonoContext *ctx)
4822 DebuggerTlsData *tls;
4823 MonoThreadUnwindState orig_restore_state;
4824 guint8 *orig_ip;
4826 if (is_debugger_thread ())
4827 return;
4829 orig_ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
4830 MONO_CONTEXT_SET_IP (ctx, orig_ip - 1);
4832 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
4833 g_assert (tls);
4835 //if a thread was suspended and doesn't have any managed stack, it was considered as terminated,
4836 //but it wasn't really terminated because it can execute managed code again, and stop in a breakpoint so here we set terminated as FALSE
4837 tls->terminated = FALSE;
4839 memcpy (&orig_restore_state, &tls->restore_state, sizeof (MonoThreadUnwindState));
4840 mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
4841 memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
4843 mono_de_process_breakpoint (tls, FALSE);
4845 memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
4846 memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
4847 if (MONO_CONTEXT_GET_IP (ctx) == orig_ip - 1)
4848 MONO_CONTEXT_SET_IP (ctx, orig_ip);
4850 static void
4851 ss_args_destroy (SingleStepArgs *ss_args)
4853 if (ss_args->frames)
4854 free_frames ((StackFrame**)ss_args->frames, ss_args->nframes);
4857 static int
4858 handle_multiple_ss_requests (void)
4860 if (!CHECK_PROTOCOL_VERSION (2, 57))
4861 return DE_ERR_NOT_IMPLEMENTED;
4862 return 1;
4865 static int
4866 ensure_runtime_is_suspended (void)
4868 if (suspend_count == 0)
4869 return ERR_NOT_SUSPENDED;
4871 wait_for_suspend ();
4873 return ERR_NONE;
4876 static int
4877 ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args)
4879 MonoSeqPointInfo *info = NULL;
4880 gboolean found_sp;
4881 MonoMethod *method = NULL;
4882 MonoDebugMethodInfo *minfo;
4883 gboolean step_to_catch = FALSE;
4884 gboolean set_ip = FALSE;
4885 StackFrame **frames = NULL;
4886 int nframes = 0;
4888 mono_loader_lock ();
4889 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, ss_req->thread);
4890 mono_loader_unlock ();
4891 g_assert (tls);
4892 if (!tls->context.valid) {
4893 DEBUG_PRINTF (1, "Received a single step request on a thread with no managed frames.\n");
4894 return ERR_INVALID_ARGUMENT;
4897 if (tls->restore_state.valid && MONO_CONTEXT_GET_IP (&tls->context.ctx) != MONO_CONTEXT_GET_IP (&tls->restore_state.ctx)) {
4899 * Need to start single stepping from restore_state and not from the current state
4901 set_ip = TRUE;
4902 frames = compute_frame_info_from (ss_req->thread, tls, &tls->restore_state, &nframes);
4905 ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx);
4907 if (tls->has_catch_frame) {
4908 StackFrameInfo frame;
4911 * We are stopped at a throw site. Stepping should go to the catch site.
4913 frame = tls->catch_frame;
4914 if (frame.type != FRAME_TYPE_MANAGED && frame.type != FRAME_TYPE_INTERP) {
4915 DEBUG_PRINTF (1, "Current frame is not managed nor interpreter.\n");
4916 return ERR_INVALID_ARGUMENT;
4920 * Find the seq point corresponding to the landing site ip, which is the first seq
4921 * point after ip.
4923 found_sp = mono_find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &args->sp);
4924 if (!found_sp)
4925 no_seq_points_found (frame.method, frame.native_offset);
4926 if (!found_sp) {
4927 DEBUG_PRINTF (1, "Could not find next sequence point.\n");
4928 return ERR_INVALID_ARGUMENT;
4931 method = frame.method;
4933 step_to_catch = TRUE;
4934 /* This make sure the seq point is not skipped by process_single_step () */
4935 ss_req->last_sp = NULL;
4938 if (!step_to_catch) {
4939 StackFrame *frame = NULL;
4941 if (set_ip) {
4942 if (frames && nframes)
4943 frame = frames [0];
4944 } else {
4945 compute_frame_info (ss_req->thread, tls, FALSE);
4947 if (tls->frame_count)
4948 frame = tls->frames [0];
4951 if (ss_req->size == STEP_SIZE_LINE) {
4952 if (frame) {
4953 ss_req->last_method = frame->de.method;
4954 ss_req->last_line = -1;
4956 minfo = mono_debug_lookup_method (frame->de.method);
4957 if (minfo && frame->il_offset != -1) {
4958 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, frame->il_offset);
4960 if (loc) {
4961 ss_req->last_line = loc->row;
4962 g_free (loc);
4968 if (frame) {
4969 if (!method && frame->il_offset != -1) {
4970 /* FIXME: Sort the table and use a binary search */
4971 found_sp = mono_find_prev_seq_point_for_native_offset (frame->de.domain, frame->de.method, frame->de.native_offset, &info, &args->sp);
4972 if (!found_sp)
4973 no_seq_points_found (frame->de.method, frame->de.native_offset);
4974 if (!found_sp) {
4975 DEBUG_PRINTF (1, "Could not find next sequence point.\n");
4976 return ERR_INVALID_ARGUMENT;
4978 method = frame->de.method;
4983 ss_req->start_method = method;
4985 args->method = method;
4986 args->ctx = set_ip ? &tls->restore_state.ctx : &tls->context.ctx;
4987 args->tls = tls;
4988 args->step_to_catch = step_to_catch;
4989 args->info = info;
4990 args->frames = (DbgEngineStackFrame**)frames;
4991 args->nframes = nframes;
4993 return ERR_NONE;
4996 static void
4997 ss_clear_for_assembly (SingleStepReq *req, MonoAssembly *assembly)
4999 GSList *l;
5000 gboolean found = TRUE;
5002 while (found) {
5003 found = FALSE;
5004 for (l = req->bps; l; l = l->next) {
5005 if (breakpoint_matches_assembly ((MonoBreakpoint *)l->data, assembly)) {
5006 mono_de_clear_breakpoint ((MonoBreakpoint *)l->data);
5007 req->bps = g_slist_delete_link (req->bps, l);
5008 found = TRUE;
5009 break;
5016 * This takes a lot of locks and stuff. Do this at the end, after
5017 * other things have dumped us, so that getting stuck here won't
5018 * prevent seeing other crash information
5020 static void
5021 mono_debugger_agent_send_crash (char *json_dump, MonoStackHash *hashes, int pause)
5023 MONO_ENTER_GC_UNSAFE;
5024 #ifndef DISABLE_CRASH_REPORTING
5025 int suspend_policy;
5026 GSList *events;
5027 EventInfo ei;
5029 if (!agent_config.enabled)
5030 return;
5032 // Don't send the event if the client doesn't expect it
5033 if (!CHECK_PROTOCOL_VERSION (2, 49))
5034 return;
5036 // It doesn't make sense to wait for lldb/gdb to finish if we're not
5037 // actually enabled. Therefore we do the wait here.
5038 sleep (pause);
5040 // Don't heap allocate when we can avoid it
5041 EventRequest request;
5042 memset (&request, 0, sizeof (request));
5043 request.event_kind = EVENT_KIND_CRASH;
5045 gpointer pdata [1];
5046 pdata [0] = &request;
5047 GPtrArray array;
5048 memset (&array, 0, sizeof (array));
5049 array.pdata = pdata;
5050 array.len = 1;
5052 mono_loader_lock ();
5053 events = create_event_list (EVENT_KIND_CRASH, &array, NULL, NULL, &suspend_policy);
5054 mono_loader_unlock ();
5056 ei.dump = json_dump;
5057 ei.hashes = hashes;
5059 g_assert (events != NULL);
5061 process_event (EVENT_KIND_CRASH, &ei, 0, NULL, events, suspend_policy);
5063 // Don't die before it is sent.
5064 sleep (4);
5065 #endif
5066 MONO_EXIT_GC_UNSAFE;
5070 * Called from metadata by the icall for System.Diagnostics.Debugger:Log ().
5072 static void
5073 debugger_agent_debug_log (int level, MonoString *category, MonoString *message)
5075 ERROR_DECL (error);
5076 int suspend_policy;
5077 GSList *events;
5078 EventInfo ei;
5080 if (!agent_config.enabled)
5081 return;
5083 memset (&ei, 0, sizeof (ei));
5085 mono_loader_lock ();
5086 events = create_event_list (EVENT_KIND_USER_LOG, NULL, NULL, NULL, &suspend_policy);
5087 mono_loader_unlock ();
5089 ei.level = level;
5090 if (category) {
5091 ei.category = mono_string_to_utf8_checked_internal (category, error);
5092 mono_error_cleanup (error);
5093 error_init (error);
5095 if (message) {
5096 ei.message = mono_string_to_utf8_checked_internal (message, error);
5097 mono_error_cleanup (error);
5100 process_event (EVENT_KIND_USER_LOG, &ei, 0, NULL, events, suspend_policy);
5102 g_free (ei.category);
5103 g_free (ei.message);
5106 static gboolean
5107 debugger_agent_debug_log_is_enabled (void)
5109 /* Treat this as true even if there is no event request for EVENT_KIND_USER_LOG */
5110 return agent_config.enabled;
5113 static void
5114 debugger_agent_unhandled_exception (MonoException *exc)
5116 int suspend_policy;
5117 GSList *events;
5118 EventInfo ei;
5120 if (!agent_inited)
5121 return;
5123 memset (&ei, 0, sizeof (ei));
5124 ei.exc = (MonoObject*)exc;
5126 mono_loader_lock ();
5127 events = create_event_list (EVENT_KIND_EXCEPTION, NULL, NULL, &ei, &suspend_policy);
5128 mono_loader_unlock ();
5130 process_event (EVENT_KIND_EXCEPTION, &ei, 0, NULL, events, suspend_policy);
5133 static void
5134 debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx,
5135 MonoContext *catch_ctx, StackFrameInfo *catch_frame)
5137 if (catch_ctx == NULL && catch_frame == NULL && mini_debug_options.suspend_on_unhandled && mono_object_class (exc) != mono_defaults.threadabortexception_class) {
5138 mono_runtime_printf_err ("Unhandled exception, suspending...");
5139 while (1)
5143 int i, j, suspend_policy;
5144 GSList *events;
5145 MonoJitInfo *ji, *catch_ji;
5146 EventInfo ei;
5147 DebuggerTlsData *tls = NULL;
5149 if (thread_to_tls != NULL) {
5150 MonoInternalThread *thread = mono_thread_internal_current ();
5152 mono_loader_lock ();
5153 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
5154 mono_loader_unlock ();
5156 if (tls && tls->abort_requested)
5157 return;
5158 if (tls && tls->disable_breakpoints)
5159 return;
5162 memset (&ei, 0, sizeof (ei));
5164 /* Just-In-Time debugging */
5165 if (!catch_ctx) {
5166 if (agent_config.onuncaught && !agent_inited) {
5167 finish_agent_init (FALSE);
5170 * Send an unsolicited EXCEPTION event with a dummy request id.
5172 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
5173 ei.exc = (MonoObject*)exc;
5174 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, SUSPEND_POLICY_ALL);
5175 return;
5177 } else if (agent_config.onthrow && !agent_inited) {
5178 GSList *l;
5179 gboolean found = FALSE;
5181 for (l = agent_config.onthrow; l; l = l->next) {
5182 char *ex_type = (char *)l->data;
5183 char *f = mono_type_full_name (m_class_get_byval_arg (exc->object.vtable->klass));
5185 if (!strcmp (ex_type, "") || !strcmp (ex_type, f))
5186 found = TRUE;
5188 g_free (f);
5191 if (found) {
5192 finish_agent_init (FALSE);
5195 * Send an unsolicited EXCEPTION event with a dummy request id.
5197 events = g_slist_append (NULL, GUINT_TO_POINTER (0xffffff));
5198 ei.exc = (MonoObject*)exc;
5199 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, SUSPEND_POLICY_ALL);
5200 return;
5204 if (!agent_inited)
5205 return;
5207 ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_CONTEXT_GET_IP (throw_ctx), NULL);
5208 if (catch_frame)
5209 catch_ji = catch_frame->ji;
5210 else
5211 catch_ji = NULL;
5213 ei.exc = (MonoObject*)exc;
5214 ei.caught = catch_ctx != NULL;
5216 mono_loader_lock ();
5218 /* Treat exceptions which are caught in non-user code as unhandled */
5219 for (i = 0; i < event_requests->len; ++i) {
5220 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
5221 if (req->event_kind != EVENT_KIND_EXCEPTION)
5222 continue;
5224 for (j = 0; j < req->nmodifiers; ++j) {
5225 Modifier *mod = &req->modifiers [j];
5227 if (mod->kind == MOD_KIND_ASSEMBLY_ONLY && catch_ji) {
5228 int k;
5229 gboolean found = FALSE;
5230 MonoAssembly **assemblies = mod->data.assemblies;
5232 if (assemblies) {
5233 for (k = 0; assemblies [k]; ++k)
5234 if (assemblies [k] == m_class_get_image (jinfo_get_method (catch_ji)->klass)->assembly)
5235 found = TRUE;
5237 if (!found)
5238 ei.caught = FALSE;
5243 events = create_event_list (EVENT_KIND_EXCEPTION, NULL, ji, &ei, &suspend_policy);
5244 mono_loader_unlock ();
5246 if (tls && ei.caught && catch_ctx) {
5247 if (catch_frame) {
5248 tls->has_catch_frame = TRUE;
5249 tls->catch_frame = *catch_frame;
5250 } else {
5251 memset (&tls->catch_frame, 0, sizeof (tls->catch_frame));
5255 process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, suspend_policy);
5257 if (tls)
5258 tls->has_catch_frame = FALSE;
5261 static void
5262 debugger_agent_begin_exception_filter (MonoException *exc, MonoContext *ctx, MonoContext *orig_ctx)
5264 DebuggerTlsData *tls;
5266 if (!agent_inited)
5267 return;
5269 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
5270 if (!tls)
5271 return;
5274 * We're about to invoke an exception filter during the first pass of exception handling.
5276 * 'ctx' is the context that'll get passed to the filter ('call_filter (ctx, ei->data.filter)'),
5277 * 'orig_ctx' is the context where the exception has been thrown.
5280 * See mcs/class/Mono.Debugger.Soft/Tests/dtest-excfilter.il for an example.
5282 * If we're stopped in Filter(), normal stack unwinding would first unwind to
5283 * the call site (line 37) and then continue to Main(), but it would never
5284 * include the throw site (line 32).
5286 * Since exception filters are invoked during the first pass of exception handling,
5287 * the stack frames of the throw site are still intact, so we should include them
5288 * in a stack trace.
5290 * We do this here by saving the context of the throw site in 'tls->filter_state'.
5292 * Exception filters are used by MonoDroid, where we want to stop inside a call filter,
5293 * but report the location of the 'throw' to the user.
5297 g_assert (mono_thread_state_init_from_monoctx (&tls->filter_state, orig_ctx));
5300 static void
5301 debugger_agent_end_exception_filter (MonoException *exc, MonoContext *ctx, MonoContext *orig_ctx)
5303 DebuggerTlsData *tls;
5305 if (!agent_inited)
5306 return;
5308 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
5309 if (!tls)
5310 return;
5312 tls->filter_state.valid = FALSE;
5315 static void
5316 buffer_add_fixed_array (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
5317 gboolean as_vtype, GHashTable *parent_vtypes, gint32 len_fixed_array)
5319 buffer_add_byte (buf, VALUE_TYPE_ID_FIXED_ARRAY);
5320 buffer_add_byte (buf, t->type);
5321 buffer_add_int (buf, len_fixed_array );
5322 for (int i = 0; i < len_fixed_array; i++) {
5323 switch (t->type) {
5324 case MONO_TYPE_BOOLEAN:
5325 case MONO_TYPE_I1:
5326 case MONO_TYPE_U1:
5327 buffer_add_int (buf, ((gint8*)addr)[i]);
5328 break;
5329 case MONO_TYPE_CHAR:
5330 case MONO_TYPE_I2:
5331 case MONO_TYPE_U2:
5332 buffer_add_int (buf, ((gint16*)addr)[i]);
5333 break;
5334 case MONO_TYPE_I4:
5335 case MONO_TYPE_U4:
5336 case MONO_TYPE_R4:
5337 buffer_add_int (buf, ((gint32*)addr)[i]);
5338 break;
5339 case MONO_TYPE_I8:
5340 case MONO_TYPE_U8:
5341 case MONO_TYPE_R8:
5342 buffer_add_long (buf, ((gint64*)addr)[i]);
5343 break;
5344 case MONO_TYPE_PTR: {
5345 gssize val = *(gssize*)addr;
5347 buffer_add_byte (buf, t->type);
5348 buffer_add_long (buf, val);
5349 if (CHECK_PROTOCOL_VERSION(2, 46))
5350 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t));
5351 break;
5357 * buffer_add_value_full:
5359 * Add the encoding of the value at ADDR described by T to the buffer.
5360 * AS_VTYPE determines whenever to treat primitive types as primitive types or
5361 * vtypes.
5363 static void
5364 buffer_add_value_full (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain,
5365 gboolean as_vtype, GHashTable *parent_vtypes, gint32 len_fixed_array)
5367 MonoObject *obj;
5368 gboolean boxed_vtype = FALSE;
5370 if (t->byref) {
5371 if (!(*(void**)addr)) {
5372 /* This can happen with compiler generated locals */
5373 //printf ("%s\n", mono_type_full_name (t));
5374 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5375 return;
5377 g_assert (*(void**)addr);
5378 addr = *(void**)addr;
5381 if (as_vtype) {
5382 switch (t->type) {
5383 case MONO_TYPE_BOOLEAN:
5384 case MONO_TYPE_I1:
5385 case MONO_TYPE_U1:
5386 case MONO_TYPE_CHAR:
5387 case MONO_TYPE_I2:
5388 case MONO_TYPE_U2:
5389 case MONO_TYPE_I4:
5390 case MONO_TYPE_U4:
5391 case MONO_TYPE_R4:
5392 case MONO_TYPE_I8:
5393 case MONO_TYPE_U8:
5394 case MONO_TYPE_R8:
5395 case MONO_TYPE_I:
5396 case MONO_TYPE_U:
5397 case MONO_TYPE_PTR:
5398 goto handle_vtype;
5399 break;
5400 default:
5401 break;
5405 if (len_fixed_array > 1 && t->type != MONO_TYPE_VALUETYPE && CHECK_PROTOCOL_VERSION (2, 53))
5407 buffer_add_fixed_array(buf, t, addr, domain, as_vtype, parent_vtypes, len_fixed_array);
5408 return;
5410 switch (t->type) {
5411 case MONO_TYPE_VOID:
5412 buffer_add_byte (buf, t->type);
5413 break;
5414 case MONO_TYPE_BOOLEAN:
5415 case MONO_TYPE_I1:
5416 case MONO_TYPE_U1:
5417 buffer_add_byte (buf, t->type);
5418 buffer_add_int (buf, *(gint8*)addr);
5419 break;
5420 case MONO_TYPE_CHAR:
5421 case MONO_TYPE_I2:
5422 case MONO_TYPE_U2:
5423 buffer_add_byte (buf, t->type);
5424 buffer_add_int (buf, *(gint16*)addr);
5425 break;
5426 case MONO_TYPE_I4:
5427 case MONO_TYPE_U4:
5428 case MONO_TYPE_R4:
5429 buffer_add_byte (buf, t->type);
5430 buffer_add_int (buf, *(gint32*)addr);
5431 break;
5432 case MONO_TYPE_I8:
5433 case MONO_TYPE_U8:
5434 case MONO_TYPE_R8:
5435 buffer_add_byte (buf, t->type);
5436 buffer_add_long (buf, *(gint64*)addr);
5437 break;
5438 case MONO_TYPE_I:
5439 case MONO_TYPE_U:
5440 /* Treat it as a vtype */
5441 goto handle_vtype;
5442 case MONO_TYPE_PTR:
5443 case MONO_TYPE_FNPTR: {
5444 gssize val = *(gssize*)addr;
5446 buffer_add_byte (buf, t->type);
5447 buffer_add_long (buf, val);
5448 if (CHECK_PROTOCOL_VERSION(2, 46))
5449 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (t));
5450 break;
5452 handle_ref:
5453 case MONO_TYPE_STRING:
5454 case MONO_TYPE_SZARRAY:
5455 case MONO_TYPE_OBJECT:
5456 case MONO_TYPE_CLASS:
5457 case MONO_TYPE_ARRAY:
5458 obj = *(MonoObject**)addr;
5460 if (!obj) {
5461 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5462 } else {
5463 if (m_class_is_valuetype (obj->vtable->klass)) {
5464 t = m_class_get_byval_arg (obj->vtable->klass);
5465 addr = mono_object_unbox_internal (obj);
5466 boxed_vtype = TRUE;
5467 goto handle_vtype;
5468 } else if (m_class_get_rank (obj->vtable->klass)) {
5469 buffer_add_byte (buf, m_class_get_byval_arg (obj->vtable->klass)->type);
5470 } else if (m_class_get_byval_arg (obj->vtable->klass)->type == MONO_TYPE_GENERICINST) {
5471 buffer_add_byte (buf, MONO_TYPE_CLASS);
5472 } else {
5473 buffer_add_byte (buf, m_class_get_byval_arg (obj->vtable->klass)->type);
5475 buffer_add_objid (buf, obj);
5477 break;
5478 handle_vtype:
5479 case MONO_TYPE_VALUETYPE:
5480 case MONO_TYPE_TYPEDBYREF: {
5481 int nfields;
5482 gpointer iter;
5483 MonoClassField *f;
5484 MonoClass *klass = mono_class_from_mono_type_internal (t);
5485 int vtype_index;
5487 if (boxed_vtype) {
5489 * Handle boxed vtypes recursively referencing themselves using fields.
5491 if (!parent_vtypes)
5492 parent_vtypes = g_hash_table_new (NULL, NULL);
5493 vtype_index = GPOINTER_TO_INT (g_hash_table_lookup (parent_vtypes, addr));
5494 if (vtype_index) {
5495 if (CHECK_PROTOCOL_VERSION (2, 33)) {
5496 buffer_add_byte (buf, VALUE_TYPE_ID_PARENT_VTYPE);
5497 buffer_add_int (buf, vtype_index - 1);
5498 } else {
5499 /* The client can't handle PARENT_VTYPE */
5500 buffer_add_byte (buf, VALUE_TYPE_ID_NULL);
5502 break;
5503 } else {
5504 g_hash_table_insert (parent_vtypes, addr, GINT_TO_POINTER (g_hash_table_size (parent_vtypes) + 1));
5508 buffer_add_byte (buf, MONO_TYPE_VALUETYPE);
5509 buffer_add_byte (buf, m_class_is_enumtype (klass));
5510 buffer_add_typeid (buf, domain, klass);
5512 nfields = 0;
5513 iter = NULL;
5514 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5515 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5516 continue;
5517 if (mono_field_is_deleted (f))
5518 continue;
5519 nfields ++;
5521 buffer_add_int (buf, nfields);
5523 iter = NULL;
5524 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5525 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5526 continue;
5527 if (mono_field_is_deleted (f))
5528 continue;
5529 buffer_add_value_full (buf, f->type, mono_vtype_get_field_addr (addr, f), domain, FALSE, parent_vtypes, len_fixed_array != 1 ? len_fixed_array : isFixedSizeArray(f));
5532 if (boxed_vtype) {
5533 g_hash_table_remove (parent_vtypes, addr);
5534 if (g_hash_table_size (parent_vtypes) == 0) {
5535 g_hash_table_destroy (parent_vtypes);
5536 parent_vtypes = NULL;
5539 break;
5541 case MONO_TYPE_GENERICINST:
5542 if (mono_type_generic_inst_is_valuetype (t)) {
5543 goto handle_vtype;
5544 } else {
5545 goto handle_ref;
5547 break;
5548 default:
5549 NOT_IMPLEMENTED;
5553 static void
5554 buffer_add_value (Buffer *buf, MonoType *t, void *addr, MonoDomain *domain)
5556 buffer_add_value_full (buf, t, addr, domain, FALSE, NULL, 1);
5559 static gboolean
5560 obj_is_of_type (MonoObject *obj, MonoType *t)
5562 MonoClass *klass = obj->vtable->klass;
5563 if (!mono_class_is_assignable_from_internal (mono_class_from_mono_type_internal (t), klass)) {
5564 if (mono_class_is_transparent_proxy (klass)) {
5565 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5566 if (mono_class_is_assignable_from_internal (mono_class_from_mono_type_internal (t), klass)) {
5567 return TRUE;
5570 return FALSE;
5572 return TRUE;
5575 static ErrorCode
5576 decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype);
5578 static ErrorCode
5579 decode_vtype (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
5581 guint8 *addr = (guint8*)void_addr;
5582 guint8 *buf = (guint8*)void_buf;
5583 gboolean is_enum;
5584 MonoClass *klass;
5585 MonoClassField *f;
5586 int nfields;
5587 gpointer iter = NULL;
5588 MonoDomain *d;
5589 ErrorCode err;
5591 is_enum = decode_byte (buf, &buf, limit);
5592 /* Enums are sent as a normal vtype */
5593 if (is_enum)
5594 return ERR_NOT_IMPLEMENTED;
5595 klass = decode_typeid (buf, &buf, limit, &d, &err);
5596 if (err != ERR_NONE)
5597 return err;
5599 if (t && klass != mono_class_from_mono_type_internal (t)) {
5600 char *name = mono_type_full_name (t);
5601 char *name2 = mono_type_full_name (m_class_get_byval_arg (klass));
5602 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got %s.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, name2);
5603 g_free (name);
5604 g_free (name2);
5605 return ERR_INVALID_ARGUMENT;
5608 nfields = decode_int (buf, &buf, limit);
5609 while ((f = mono_class_get_fields_internal (klass, &iter))) {
5610 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC)
5611 continue;
5612 if (mono_field_is_deleted (f))
5613 continue;
5614 err = decode_value (f->type, domain, mono_vtype_get_field_addr (addr, f), buf, &buf, limit, check_field_datatype);
5615 if (err != ERR_NONE)
5616 return err;
5617 nfields --;
5619 g_assert (nfields == 0);
5621 *endbuf = buf;
5623 return ERR_NONE;
5625 static ErrorCode decode_fixed_size_array_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
5627 ErrorCode err = ERR_NONE;
5628 int fixedSizeLen = 1;
5629 int newType = MONO_TYPE_END;
5630 if (CHECK_PROTOCOL_VERSION (2, 53)) {
5631 newType = decode_byte (buf, &buf, limit);
5632 fixedSizeLen = decode_int (buf, &buf, limit);
5633 //t->type = newType;
5635 for (int i = 0 ; i < fixedSizeLen; i++) {
5636 switch (newType) {
5637 case MONO_TYPE_BOOLEAN:
5638 ((guint8*)addr)[i] = decode_int (buf, &buf, limit);
5639 break;
5640 case MONO_TYPE_CHAR:
5641 ((gunichar2*)addr)[i] = decode_int (buf, &buf, limit);
5642 break;
5643 case MONO_TYPE_I1:
5644 ((gint8*)addr)[i] = decode_int (buf, &buf, limit);
5645 break;
5646 case MONO_TYPE_U1:
5647 ((guint8*)addr)[i] = decode_int (buf, &buf, limit);
5648 break;
5649 case MONO_TYPE_I2:
5650 ((gint16*)addr)[i] = decode_int (buf, &buf, limit);
5651 break;
5652 case MONO_TYPE_U2:
5653 ((guint16*)addr)[i] = decode_int (buf, &buf, limit);
5654 break;
5655 case MONO_TYPE_I4:
5656 ((gint32*)addr)[i] = decode_int (buf, &buf, limit);
5657 break;
5658 case MONO_TYPE_U4:
5659 ((guint32*)addr)[i] = decode_int (buf, &buf, limit);
5660 break;
5661 case MONO_TYPE_I8:
5662 ((gint64*)addr)[i] = decode_long (buf, &buf, limit);
5663 break;
5664 case MONO_TYPE_U8:
5665 ((guint64*)addr)[i] = decode_long (buf, &buf, limit);
5666 break;
5667 case MONO_TYPE_R4:
5668 ((guint32*)addr)[i] = decode_int (buf, &buf, limit);
5669 break;
5670 case MONO_TYPE_R8:
5671 ((guint64*)addr)[i] = decode_long (buf, &buf, limit);
5672 break;
5675 *endbuf = buf;
5676 return err;
5678 static ErrorCode
5679 decode_value_internal (MonoType *t, int type, MonoDomain *domain, guint8 *addr, guint8 *buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
5681 ErrorCode err;
5682 if (type != t->type && !MONO_TYPE_IS_REFERENCE (t) &&
5683 !(t->type == MONO_TYPE_I && type == MONO_TYPE_VALUETYPE) &&
5684 !(type == VALUE_TYPE_ID_FIXED_ARRAY) &&
5685 !(t->type == MONO_TYPE_U && type == MONO_TYPE_VALUETYPE) &&
5686 !(t->type == MONO_TYPE_PTR && type == MONO_TYPE_I8) &&
5687 !(t->type == MONO_TYPE_FNPTR && type == MONO_TYPE_I8) &&
5688 !(t->type == MONO_TYPE_GENERICINST && type == MONO_TYPE_VALUETYPE) &&
5689 !(t->type == MONO_TYPE_VALUETYPE && type == MONO_TYPE_OBJECT)) {
5690 char *name = mono_type_full_name (t);
5691 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type);
5692 g_free (name);
5693 return ERR_INVALID_ARGUMENT;
5695 if (type == VALUE_TYPE_ID_FIXED_ARRAY && t->type != MONO_TYPE_VALUETYPE) {
5696 decode_fixed_size_array_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype);
5697 return ERR_NONE;
5700 switch (t->type) {
5701 case MONO_TYPE_BOOLEAN:
5702 *(guint8*)addr = decode_int (buf, &buf, limit);
5703 break;
5704 case MONO_TYPE_CHAR:
5705 *(gunichar2*)addr = decode_int (buf, &buf, limit);
5706 break;
5707 case MONO_TYPE_I1:
5708 *(gint8*)addr = decode_int (buf, &buf, limit);
5709 break;
5710 case MONO_TYPE_U1:
5711 *(guint8*)addr = decode_int (buf, &buf, limit);
5712 break;
5713 case MONO_TYPE_I2:
5714 *(gint16*)addr = decode_int (buf, &buf, limit);
5715 break;
5716 case MONO_TYPE_U2:
5717 *(guint16*)addr = decode_int (buf, &buf, limit);
5718 break;
5719 case MONO_TYPE_I4:
5720 *(gint32*)addr = decode_int (buf, &buf, limit);
5721 break;
5722 case MONO_TYPE_U4:
5723 *(guint32*)addr = decode_int (buf, &buf, limit);
5724 break;
5725 case MONO_TYPE_I8:
5726 *(gint64*)addr = decode_long (buf, &buf, limit);
5727 break;
5728 case MONO_TYPE_U8:
5729 *(guint64*)addr = decode_long (buf, &buf, limit);
5730 break;
5731 case MONO_TYPE_R4:
5732 *(guint32*)addr = decode_int (buf, &buf, limit);
5733 break;
5734 case MONO_TYPE_R8:
5735 *(guint64*)addr = decode_long (buf, &buf, limit);
5736 break;
5737 case MONO_TYPE_PTR:
5738 case MONO_TYPE_FNPTR:
5739 /* We send these as I8, so we get them back as such */
5740 g_assert (type == MONO_TYPE_I8);
5741 *(gssize*)addr = decode_long (buf, &buf, limit);
5742 break;
5743 case MONO_TYPE_GENERICINST:
5744 if (MONO_TYPE_ISSTRUCT (t)) {
5745 /* The client sends these as a valuetype */
5746 goto handle_vtype;
5747 } else {
5748 goto handle_ref;
5750 break;
5751 case MONO_TYPE_I:
5752 case MONO_TYPE_U:
5753 /* We send these as vtypes, so we get them back as such */
5754 g_assert (type == MONO_TYPE_VALUETYPE);
5755 /* Fall through */
5756 handle_vtype:
5757 case MONO_TYPE_VALUETYPE:
5758 if (type == MONO_TYPE_OBJECT) {
5759 /* Boxed vtype */
5760 int objid = decode_objid (buf, &buf, limit);
5761 ErrorCode err;
5762 MonoObject *obj;
5764 err = get_object (objid, (MonoObject**)&obj);
5765 if (err != ERR_NONE)
5766 return err;
5767 if (!obj)
5768 return ERR_INVALID_ARGUMENT;
5769 if (obj->vtable->klass != mono_class_from_mono_type_internal (t)) {
5770 DEBUG_PRINTF (1, "Expected type '%s', got object '%s'\n", mono_type_full_name (t), m_class_get_name (obj->vtable->klass));
5771 return ERR_INVALID_ARGUMENT;
5773 memcpy (addr, mono_object_unbox_internal (obj), mono_class_value_size (obj->vtable->klass, NULL));
5774 } else {
5775 err = decode_vtype (t, domain, addr, buf, &buf, limit, check_field_datatype);
5776 if (err != ERR_NONE)
5777 return err;
5779 break;
5780 handle_ref:
5781 default:
5782 if (MONO_TYPE_IS_REFERENCE (t)) {
5783 if (type == MONO_TYPE_OBJECT) {
5784 int objid = decode_objid (buf, &buf, limit);
5785 ErrorCode err;
5786 MonoObject *obj;
5788 err = get_object (objid, (MonoObject**)&obj);
5789 if (err != ERR_NONE)
5790 return err;
5792 if (obj) {
5793 if (!obj_is_of_type (obj, t)) {
5794 if (check_field_datatype) { //if it's not executing a invoke method check the datatypes.
5795 DEBUG_PRINTF (1, "Expected type '%s', got '%s'\n", mono_type_full_name (t), m_class_get_name (obj->vtable->klass));
5796 return ERR_INVALID_ARGUMENT;
5800 if (obj && obj->vtable->domain != domain)
5801 return ERR_INVALID_ARGUMENT;
5803 mono_gc_wbarrier_generic_store_internal (addr, obj);
5804 } else if (type == VALUE_TYPE_ID_NULL) {
5805 *(MonoObject**)addr = NULL;
5806 } else if (type == MONO_TYPE_VALUETYPE) {
5807 ERROR_DECL (error);
5808 guint8 *buf2;
5809 gboolean is_enum;
5810 MonoClass *klass;
5811 MonoDomain *d;
5812 guint8 *vtype_buf;
5813 int vtype_buf_size;
5815 /* This can happen when round-tripping boxed vtypes */
5817 * Obtain vtype class.
5818 * Same as the beginning of the handle_vtype case above.
5820 buf2 = buf;
5821 is_enum = decode_byte (buf, &buf, limit);
5822 if (is_enum)
5823 return ERR_NOT_IMPLEMENTED;
5824 klass = decode_typeid (buf, &buf, limit, &d, &err);
5825 if (err != ERR_NONE)
5826 return err;
5828 /* Decode the vtype into a temporary buffer, then box it. */
5829 vtype_buf_size = mono_class_value_size (klass, NULL);
5830 vtype_buf = (guint8 *)g_malloc0 (vtype_buf_size);
5831 g_assert (vtype_buf);
5833 buf = buf2;
5834 err = decode_vtype (NULL, domain, vtype_buf, buf, &buf, limit, check_field_datatype);
5835 if (err != ERR_NONE) {
5836 g_free (vtype_buf);
5837 return err;
5839 *(MonoObject**)addr = mono_value_box_checked (d, klass, vtype_buf, error);
5840 mono_error_cleanup (error);
5841 g_free (vtype_buf);
5842 } else {
5843 char *name = mono_type_full_name (t);
5844 DEBUG_PRINTF (1, "[%p] Expected value of type %s, got 0x%0x.\n", (gpointer) (gsize) mono_native_thread_id_get (), name, type);
5845 g_free (name);
5846 return ERR_INVALID_ARGUMENT;
5848 } else if ((t->type == MONO_TYPE_GENERICINST) &&
5849 mono_metadata_generic_class_is_valuetype (t->data.generic_class) &&
5850 m_class_is_enumtype (t->data.generic_class->container_class)){
5851 err = decode_vtype (t, domain, addr, buf, &buf, limit, check_field_datatype);
5852 if (err != ERR_NONE)
5853 return err;
5854 } else {
5855 NOT_IMPLEMENTED;
5857 break;
5861 *endbuf = buf;
5863 return ERR_NONE;
5866 static ErrorCode
5867 decode_value (MonoType *t, MonoDomain *domain, gpointer void_addr, gpointer void_buf, guint8 **endbuf, guint8 *limit, gboolean check_field_datatype)
5869 guint8 *addr = (guint8*)void_addr;
5870 guint8 *buf = (guint8*)void_buf;
5872 ERROR_DECL (error);
5873 ErrorCode err;
5874 int type = decode_byte (buf, &buf, limit);
5876 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) {
5877 MonoType *targ = t->data.generic_class->context.class_inst->type_argv [0];
5878 guint8 *nullable_buf;
5881 * First try decoding it as a Nullable`1
5883 err = decode_value_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype);
5884 if (err == ERR_NONE)
5885 return err;
5888 * Then try decoding as a primitive value or null.
5890 if (targ->type == type) {
5891 nullable_buf = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (targ)));
5892 err = decode_value_internal (targ, type, domain, nullable_buf, buf, endbuf, limit, check_field_datatype);
5893 if (err != ERR_NONE) {
5894 g_free (nullable_buf);
5895 return err;
5897 MonoObject *boxed = mono_value_box_checked (domain, mono_class_from_mono_type_internal (targ), nullable_buf, error);
5898 if (!is_ok (error)) {
5899 mono_error_cleanup (error);
5900 return ERR_INVALID_OBJECT;
5902 mono_nullable_init (addr, boxed, mono_class_from_mono_type_internal (t));
5903 g_free (nullable_buf);
5904 *endbuf = buf;
5905 return ERR_NONE;
5906 } else if (type == VALUE_TYPE_ID_NULL) {
5907 mono_nullable_init (addr, NULL, mono_class_from_mono_type_internal (t));
5908 *endbuf = buf;
5909 return ERR_NONE;
5913 return decode_value_internal (t, type, domain, addr, buf, endbuf, limit, check_field_datatype);
5916 static void
5917 add_var (Buffer *buf, MonoDebugMethodJitInfo *jit, MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, gboolean as_vtype)
5919 guint32 flags;
5920 int reg;
5921 guint8 *addr, *gaddr;
5922 host_mgreg_t reg_val;
5924 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5925 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5927 switch (flags) {
5928 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
5929 reg_val = mono_arch_context_get_int_reg (ctx, reg);
5931 buffer_add_value_full (buf, t, &reg_val, domain, as_vtype, NULL, 1);
5932 break;
5933 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
5934 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5935 addr += (gint32)var->offset;
5937 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
5939 buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL, 1);
5940 break;
5941 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
5942 NOT_IMPLEMENTED;
5943 break;
5944 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
5945 case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR:
5946 /* Same as regoffset, but with an indirection */
5947 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5948 addr += (gint32)var->offset;
5950 gaddr = (guint8 *)*(gpointer*)addr;
5951 g_assert (gaddr);
5952 buffer_add_value_full (buf, t, gaddr, domain, as_vtype, NULL, 1);
5953 break;
5954 case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: {
5955 MonoDebugVarInfo *info_var = jit->gsharedvt_info_var;
5956 MonoDebugVarInfo *locals_var = jit->gsharedvt_locals_var;
5957 MonoGSharedVtMethodRuntimeInfo *info;
5958 guint8 *locals;
5959 int idx;
5961 idx = reg;
5963 g_assert (info_var);
5964 g_assert (locals_var);
5966 flags = info_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5967 reg = info_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5968 if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
5969 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5970 addr += (gint32)info_var->offset;
5971 info = (MonoGSharedVtMethodRuntimeInfo *)*(gpointer*)addr;
5972 } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
5973 info = (MonoGSharedVtMethodRuntimeInfo *)mono_arch_context_get_int_reg (ctx, reg);
5974 } else {
5975 g_assert_not_reached ();
5977 g_assert (info);
5979 flags = locals_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5980 reg = locals_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
5981 if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET) {
5982 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5983 addr += (gint32)locals_var->offset;
5984 locals = (guint8 *)*(gpointer*)addr;
5985 } else if (flags == MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER) {
5986 locals = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
5987 } else {
5988 g_assert_not_reached ();
5990 g_assert (locals);
5992 addr = locals + GPOINTER_TO_INT (info->entries [idx]);
5994 buffer_add_value_full (buf, t, addr, domain, as_vtype, NULL, 1);
5995 break;
5998 default:
5999 g_assert_not_reached ();
6003 static void
6004 set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domain, guint8 *val, host_mgreg_t **reg_locations, MonoContext *restore_ctx)
6006 guint32 flags;
6007 int reg, size;
6008 guint8 *addr, *gaddr;
6010 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
6011 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
6013 if (MONO_TYPE_IS_REFERENCE (t))
6014 size = sizeof (gpointer);
6015 else
6016 size = mono_class_value_size (mono_class_from_mono_type_internal (t), NULL);
6018 switch (flags) {
6019 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER: {
6020 #ifdef MONO_ARCH_HAVE_CONTEXT_SET_INT_REG
6021 host_mgreg_t v;
6022 gboolean is_signed = FALSE;
6024 if (t->byref) {
6025 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
6027 if (addr) {
6028 // FIXME: Write barriers
6029 mono_gc_memmove_atomic (addr, val, size);
6031 break;
6034 if (!t->byref && (t->type == MONO_TYPE_I1 || t->type == MONO_TYPE_I2 || t->type == MONO_TYPE_I4 || t->type == MONO_TYPE_I8))
6035 is_signed = TRUE;
6037 switch (size) {
6038 case 1:
6039 v = is_signed ? *(gint8*)val : *(guint8*)val;
6040 break;
6041 case 2:
6042 v = is_signed ? *(gint16*)val : *(guint16*)val;
6043 break;
6044 case 4:
6045 v = is_signed ? *(gint32*)val : *(guint32*)val;
6046 break;
6047 case 8:
6048 v = is_signed ? *(gint64*)val : *(guint64*)val;
6049 break;
6050 default:
6051 g_assert_not_reached ();
6054 /* Set value on the stack or in the return ctx */
6055 if (reg_locations [reg]) {
6056 /* Saved on the stack */
6057 DEBUG_PRINTF (1, "[dbg] Setting stack location %p for reg %x to %p.\n", reg_locations [reg], reg, (gpointer)v);
6058 *(reg_locations [reg]) = v;
6059 } else {
6060 /* Not saved yet */
6061 DEBUG_PRINTF (1, "[dbg] Setting context location for reg %x to %p.\n", reg, (gpointer)v);
6062 mono_arch_context_set_int_reg (restore_ctx, reg, v);
6065 // FIXME: Move these to mono-context.h/c.
6066 mono_arch_context_set_int_reg (ctx, reg, v);
6067 #else
6068 // FIXME: Can't set registers, so we disable linears
6069 NOT_IMPLEMENTED;
6070 #endif
6071 break;
6073 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
6074 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
6075 addr += (gint32)var->offset;
6077 //printf ("[R%d+%d] = %p\n", reg, var->offset, addr);
6079 if (t->byref) {
6080 addr = *(guint8**)addr;
6082 if (!addr)
6083 break;
6086 // FIXME: Write barriers
6087 mono_gc_memmove_atomic (addr, val, size);
6088 break;
6089 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
6090 /* Same as regoffset, but with an indirection */
6091 addr = (guint8 *)mono_arch_context_get_int_reg (ctx, reg);
6092 addr += (gint32)var->offset;
6094 gaddr = (guint8 *)*(gpointer*)addr;
6095 g_assert (gaddr);
6096 // FIXME: Write barriers
6097 mono_gc_memmove_atomic (gaddr, val, size);
6098 break;
6099 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD:
6100 NOT_IMPLEMENTED;
6101 break;
6102 default:
6103 g_assert_not_reached ();
6107 static void
6108 set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf)
6110 int size;
6112 if (t->byref) {
6113 addr = *(gpointer*)addr;
6114 g_assert (addr);
6117 if (MONO_TYPE_IS_REFERENCE (t))
6118 size = sizeof (gpointer);
6119 else
6120 size = mono_class_value_size (mono_class_from_mono_type_internal (t), NULL);
6122 memcpy (addr, val_buf, size);
6125 static void
6126 clear_event_request (int req_id, int etype)
6128 int i;
6130 mono_loader_lock ();
6131 for (i = 0; i < event_requests->len; ++i) {
6132 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
6134 if (req->id == req_id && req->event_kind == etype) {
6135 if (req->event_kind == EVENT_KIND_BREAKPOINT)
6136 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
6137 if (req->event_kind == EVENT_KIND_STEP) {
6138 mono_de_cancel_ss ((SingleStepReq *)req->info);
6140 if (req->event_kind == EVENT_KIND_METHOD_ENTRY)
6141 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
6142 if (req->event_kind == EVENT_KIND_METHOD_EXIT)
6143 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
6144 g_ptr_array_remove_index_fast (event_requests, i);
6145 g_free (req);
6146 break;
6149 mono_loader_unlock ();
6152 static void
6153 clear_assembly_from_modifier (EventRequest *req, Modifier *m, MonoAssembly *assembly)
6155 int i;
6157 if (m->kind == MOD_KIND_EXCEPTION_ONLY && m->data.exc_class && m_class_get_image (m->data.exc_class)->assembly == assembly)
6158 m->kind = MOD_KIND_NONE;
6159 if (m->kind == MOD_KIND_ASSEMBLY_ONLY && m->data.assemblies) {
6160 int count = 0, match_count = 0, pos;
6161 MonoAssembly **newassemblies;
6163 for (i = 0; m->data.assemblies [i]; ++i) {
6164 count ++;
6165 if (m->data.assemblies [i] == assembly)
6166 match_count ++;
6169 if (match_count) {
6170 // +1 because we don't know length and we use last element to check for end
6171 newassemblies = g_new0 (MonoAssembly*, count - match_count + 1);
6173 pos = 0;
6174 for (i = 0; i < count; ++i)
6175 if (m->data.assemblies [i] != assembly)
6176 newassemblies [pos ++] = m->data.assemblies [i];
6177 g_assert (pos == count - match_count);
6178 g_free (m->data.assemblies);
6179 m->data.assemblies = newassemblies;
6184 static void
6185 clear_assembly_from_modifiers (EventRequest *req, MonoAssembly *assembly)
6187 int i;
6189 for (i = 0; i < req->nmodifiers; ++i) {
6190 Modifier *m = &req->modifiers [i];
6192 clear_assembly_from_modifier (req, m, assembly);
6197 * clear_event_requests_for_assembly:
6199 * Clear all events requests which reference ASSEMBLY.
6201 static void
6202 clear_event_requests_for_assembly (MonoAssembly *assembly)
6204 int i;
6205 gboolean found;
6207 mono_loader_lock ();
6208 found = TRUE;
6209 while (found) {
6210 found = FALSE;
6211 for (i = 0; i < event_requests->len; ++i) {
6212 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
6214 clear_assembly_from_modifiers (req, assembly);
6216 if (req->event_kind == EVENT_KIND_BREAKPOINT && breakpoint_matches_assembly ((MonoBreakpoint *)req->info, assembly)) {
6217 clear_event_request (req->id, req->event_kind);
6218 found = TRUE;
6219 break;
6222 if (req->event_kind == EVENT_KIND_STEP)
6223 ss_clear_for_assembly ((SingleStepReq *)req->info, assembly);
6226 mono_loader_unlock ();
6230 * type_comes_from_assembly:
6232 * GHRFunc that returns TRUE if klass comes from assembly
6234 static gboolean
6235 type_comes_from_assembly (gpointer klass, gpointer also_klass, gpointer assembly)
6237 return mono_type_in_image (m_class_get_byval_arg ((MonoClass*)klass), mono_assembly_get_image_internal ((MonoAssembly*)assembly));
6241 * clear_types_for_assembly:
6243 * Clears types from loaded_classes for a given assembly
6245 static void
6246 clear_types_for_assembly (MonoAssembly *assembly)
6248 MonoDomain *domain = mono_domain_get ();
6249 AgentDomainInfo *info = NULL;
6251 if (!domain || !domain_jit_info (domain))
6252 /* Can happen during shutdown */
6253 return;
6255 info = get_agent_domain_info (domain);
6257 mono_loader_lock ();
6258 g_hash_table_foreach_remove (info->loaded_classes, type_comes_from_assembly, assembly);
6259 mono_loader_unlock ();
6262 static void
6263 dispose_vm (void)
6265 /* Clear all event requests */
6266 mono_loader_lock ();
6267 while (event_requests->len > 0) {
6268 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, 0);
6270 clear_event_request (req->id, req->event_kind);
6272 mono_loader_unlock ();
6274 while (suspend_count > 0)
6275 resume_vm ();
6276 disconnected = TRUE;
6277 vm_start_event_sent = FALSE;
6280 static void
6281 count_thread_check_gc_finalizer (gpointer key, gpointer value, gpointer user_data)
6283 MonoThread *thread = (MonoThread *)value;
6284 gboolean *ret = (gboolean *)user_data;
6285 if (mono_gc_is_finalizer_internal_thread(thread->internal_thread)) {
6286 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread->internal_thread);
6287 if (!tls->gc_finalizing) { //GC Finalizer is not running some finalizer code, so ignore it
6288 *ret = TRUE;
6289 return;
6294 static void
6295 add_thread (gpointer key, gpointer value, gpointer user_data)
6297 MonoThread *thread = (MonoThread *)value;
6298 Buffer *buf = (Buffer *)user_data;
6299 if (mono_gc_is_finalizer_internal_thread(thread->internal_thread)) {
6300 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread->internal_thread);
6301 if (!tls->gc_finalizing) //GC Finalizer is not running some finalizer code, so ignore it
6302 return;
6304 buffer_add_objid (buf, (MonoObject*)thread);
6308 static ErrorCode
6309 do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 *p, guint8 **endp)
6311 ERROR_DECL (error);
6312 guint8 *end = invoke->endp;
6313 MonoMethod *m;
6314 int i, nargs;
6315 ErrorCode err;
6316 MonoMethodSignature *sig;
6317 guint8 **arg_buf;
6318 void **args;
6319 MonoObject *this_arg, *res, *exc = NULL;
6320 MonoDomain *domain;
6321 guint8 *this_buf;
6322 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6323 MonoLMFExt ext;
6324 #endif
6325 MonoStopwatch watch;
6327 if (invoke->method) {
6329 * Invoke this method directly, currently only Environment.Exit () is supported.
6331 this_arg = NULL;
6332 DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (invoke->method, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : "<null>");
6334 mono_runtime_try_invoke (invoke->method, NULL, invoke->args, &exc, error);
6335 mono_error_assert_ok (error);
6336 g_assert_not_reached ();
6339 m = decode_methodid (p, &p, end, &domain, &err);
6340 if (err != ERR_NONE)
6341 return err;
6342 sig = mono_method_signature_internal (m);
6344 if (m_class_is_valuetype (m->klass))
6345 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6346 else
6347 this_buf = (guint8 *)g_alloca (sizeof (MonoObject*));
6349 if (m->is_generic) {
6350 DEBUG_PRINTF (1, "[%p] Error: Attempting to invoke uninflated generic method %s.\n", (gpointer)(gsize)mono_native_thread_id_get (), mono_method_full_name (m, TRUE));
6351 return ERR_INVALID_ARGUMENT;
6352 } else if (m_class_is_valuetype (m->klass) && (m->flags & METHOD_ATTRIBUTE_STATIC)) {
6353 /* Should be null */
6354 int type = decode_byte (p, &p, end);
6355 if (type != VALUE_TYPE_ID_NULL) {
6356 DEBUG_PRINTF (1, "[%p] Error: Static vtype method invoked with this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6357 return ERR_INVALID_ARGUMENT;
6359 memset (this_buf, 0, mono_class_instance_size (m->klass));
6360 } else if (m_class_is_valuetype (m->klass) && !strcmp (m->name, ".ctor")) {
6361 /* Could be null */
6362 guint8 *tmp_p;
6364 int type = decode_byte (p, &tmp_p, end);
6365 if (type == VALUE_TYPE_ID_NULL) {
6366 memset (this_buf, 0, mono_class_instance_size (m->klass));
6367 p = tmp_p;
6368 } else {
6369 err = decode_value (m_class_get_byval_arg (m->klass), domain, this_buf, p, &p, end, FALSE);
6370 if (err != ERR_NONE)
6371 return err;
6373 } else {
6374 err = decode_value (m_class_get_byval_arg (m->klass), domain, this_buf, p, &p, end, FALSE);
6375 if (err != ERR_NONE)
6376 return err;
6379 if (!m_class_is_valuetype (m->klass))
6380 this_arg = *(MonoObject**)this_buf;
6381 else
6382 this_arg = NULL;
6384 if (MONO_CLASS_IS_INTERFACE_INTERNAL (m->klass)) {
6385 if (!this_arg) {
6386 DEBUG_PRINTF (1, "[%p] Error: Interface method invoked without this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6387 return ERR_INVALID_ARGUMENT;
6389 m = mono_object_get_virtual_method_internal (this_arg, m);
6390 /* Transform this to the format the rest of the code expects it to be */
6391 if (m_class_is_valuetype (m->klass)) {
6392 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6393 memcpy (this_buf, mono_object_unbox_internal (this_arg), mono_class_instance_size (m->klass));
6395 } else if ((m->flags & METHOD_ATTRIBUTE_VIRTUAL) && !m_class_is_valuetype (m->klass) && invoke->flags & INVOKE_FLAG_VIRTUAL) {
6396 if (!this_arg) {
6397 DEBUG_PRINTF (1, "[%p] Error: invoke with INVOKE_FLAG_VIRTUAL flag set without this argument.\n", (gpointer) (gsize) mono_native_thread_id_get ());
6398 return ERR_INVALID_ARGUMENT;
6400 m = mono_object_get_virtual_method_internal (this_arg, m);
6401 if (m_class_is_valuetype (m->klass)) {
6402 this_buf = (guint8 *)g_alloca (mono_class_instance_size (m->klass));
6403 memcpy (this_buf, mono_object_unbox_internal (this_arg), mono_class_instance_size (m->klass));
6407 DEBUG_PRINTF (1, "[%p] Invoking method '%s' on receiver '%s'.\n", (gpointer) (gsize) mono_native_thread_id_get (), mono_method_full_name (m, TRUE), this_arg ? m_class_get_name (this_arg->vtable->klass) : "<null>");
6409 if (this_arg && this_arg->vtable->domain != domain)
6410 NOT_IMPLEMENTED;
6412 if (!m_class_is_valuetype (m->klass) && !(m->flags & METHOD_ATTRIBUTE_STATIC) && !this_arg) {
6413 if (!strcmp (m->name, ".ctor")) {
6414 if (mono_class_is_abstract (m->klass))
6415 return ERR_INVALID_ARGUMENT;
6416 else {
6417 ERROR_DECL (error);
6418 this_arg = mono_object_new_checked (domain, m->klass, error);
6419 if (!is_ok (error)) {
6420 mono_error_cleanup (error);
6421 return ERR_INVALID_ARGUMENT;
6424 } else {
6425 return ERR_INVALID_ARGUMENT;
6429 if (this_arg && !obj_is_of_type (this_arg, m_class_get_byval_arg (m->klass)))
6430 return ERR_INVALID_ARGUMENT;
6432 nargs = decode_int (p, &p, end);
6433 if (nargs != sig->param_count)
6434 return ERR_INVALID_ARGUMENT;
6435 /* Use alloca to get gc tracking */
6436 arg_buf = (guint8 **)g_alloca (nargs * sizeof (gpointer));
6437 memset (arg_buf, 0, nargs * sizeof (gpointer));
6438 args = (gpointer *)g_alloca (nargs * sizeof (gpointer));
6439 for (i = 0; i < nargs; ++i) {
6440 if (MONO_TYPE_IS_REFERENCE (sig->params [i])) {
6441 err = decode_value (sig->params [i], domain, (guint8*)&args [i], p, &p, end, TRUE);
6442 if (err != ERR_NONE)
6443 break;
6444 if (args [i] && ((MonoObject*)args [i])->vtable->domain != domain)
6445 NOT_IMPLEMENTED;
6447 if (sig->params [i]->byref) {
6448 arg_buf [i] = g_newa (guint8, sizeof (gpointer));
6449 *(gpointer*)arg_buf [i] = args [i];
6450 args [i] = arg_buf [i];
6452 } else {
6453 MonoClass *arg_class = mono_class_from_mono_type_internal (sig->params [i]);
6454 arg_buf [i] = (guint8 *)g_alloca (mono_class_instance_size (arg_class));
6455 err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end, TRUE);
6456 if (err != ERR_NONE)
6457 break;
6458 if (mono_class_is_nullable (arg_class)) {
6459 args [i] = mono_nullable_box (arg_buf [i], arg_class, error);
6460 mono_error_assert_ok (error);
6461 } else {
6462 args [i] = arg_buf [i];
6467 if (i < nargs)
6468 return err;
6470 if (invoke->flags & INVOKE_FLAG_DISABLE_BREAKPOINTS)
6471 tls->disable_breakpoints = TRUE;
6472 else
6473 tls->disable_breakpoints = FALSE;
6476 * Add an LMF frame to link the stack frames on the invoke method with our caller.
6478 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6479 if (invoke->has_ctx) {
6480 /* Setup our lmf */
6481 memset (&ext, 0, sizeof (ext));
6482 ext.kind = MONO_LMFEXT_DEBUGGER_INVOKE;
6483 memcpy (&ext.ctx, &invoke->ctx, sizeof (MonoContext));
6485 mono_push_lmf (&ext);
6487 #endif
6489 mono_stopwatch_start (&watch);
6490 res = mono_runtime_try_invoke (m, m_class_is_valuetype (m->klass) ? (gpointer) this_buf : (gpointer) this_arg, args, &exc, error);
6491 if (!is_ok (error) && exc == NULL) {
6492 exc = (MonoObject*) mono_error_convert_to_exception (error);
6493 } else {
6494 mono_error_cleanup (error); /* FIXME report error */
6496 mono_stopwatch_stop (&watch);
6497 DEBUG_PRINTF (1, "[%p] Invoke result: %p, exc: %s, time: %ld ms.\n", (gpointer) (gsize) mono_native_thread_id_get (), res, exc ? m_class_get_name (exc->vtable->klass) : NULL, (long)mono_stopwatch_elapsed_ms (&watch));
6498 if (exc) {
6499 buffer_add_byte (buf, 0);
6500 buffer_add_value (buf, mono_get_object_type (), &exc, domain);
6501 } else {
6502 gboolean out_this = FALSE;
6503 gboolean out_args = FALSE;
6505 if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_THIS) && CHECK_PROTOCOL_VERSION (2, 35))
6506 out_this = TRUE;
6507 if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_ARGS) && CHECK_PROTOCOL_VERSION (2, 35))
6508 out_args = TRUE;
6509 buffer_add_byte (buf, 1 + (out_this ? 2 : 0) + (out_args ? 4 : 0));
6510 if (m->string_ctor) {
6511 buffer_add_value (buf, m_class_get_byval_arg (mono_get_string_class ()), &res, domain);
6512 } else if (sig->ret->type == MONO_TYPE_VOID && !m->string_ctor) {
6513 if (!strcmp (m->name, ".ctor")) {
6514 if (!m_class_is_valuetype (m->klass))
6515 buffer_add_value (buf, mono_get_object_type (), &this_arg, domain);
6516 else
6517 buffer_add_value (buf, m_class_get_byval_arg (m->klass), this_buf, domain);
6518 } else {
6519 buffer_add_value (buf, mono_get_void_type (), NULL, domain);
6521 } else if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
6522 if (sig->ret->byref) {
6523 MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret));
6524 buffer_add_value (buf, ret_byval, &res, domain);
6525 } else {
6526 buffer_add_value (buf, sig->ret, &res, domain);
6528 } else if (m_class_is_valuetype (mono_class_from_mono_type_internal (sig->ret)) || sig->ret->type == MONO_TYPE_PTR || sig->ret->type == MONO_TYPE_FNPTR) {
6529 if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig->ret))) {
6530 MonoClass *k = mono_class_from_mono_type_internal (sig->ret);
6531 guint8 *nullable_buf = (guint8 *)g_alloca (mono_class_value_size (k, NULL));
6533 g_assert (nullable_buf);
6534 mono_nullable_init (nullable_buf, res, k);
6535 buffer_add_value (buf, sig->ret, nullable_buf, domain);
6536 } else {
6537 g_assert (res);
6539 if (sig->ret->byref) {
6540 MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret));
6541 buffer_add_value (buf, ret_byval, mono_object_unbox_internal (res), domain);
6542 } else {
6543 buffer_add_value (buf, sig->ret, mono_object_unbox_internal (res), domain);
6546 } else {
6547 NOT_IMPLEMENTED;
6549 if (out_this)
6550 /* Return the new value of the receiver after the call */
6551 buffer_add_value (buf, m_class_get_byval_arg (m->klass), this_buf, domain);
6552 if (out_args) {
6553 buffer_add_int (buf, nargs);
6554 for (i = 0; i < nargs; ++i) {
6555 if (MONO_TYPE_IS_REFERENCE (sig->params [i]))
6556 buffer_add_value (buf, sig->params [i], &args [i], domain);
6557 else if (sig->params [i]->byref)
6558 /* add_value () does an indirection */
6559 buffer_add_value (buf, sig->params [i], &arg_buf [i], domain);
6560 else
6561 buffer_add_value (buf, sig->params [i], arg_buf [i], domain);
6566 tls->disable_breakpoints = FALSE;
6568 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6569 if (invoke->has_ctx)
6570 mono_pop_lmf ((MonoLMF*)&ext);
6571 #endif
6573 *endp = p;
6574 // FIXME: byref arguments
6575 // FIXME: varargs
6576 return ERR_NONE;
6580 * invoke_method:
6582 * Invoke the method given by tls->pending_invoke in the current thread.
6584 static void
6585 invoke_method (void)
6587 DebuggerTlsData *tls;
6588 InvokeData *invoke;
6589 int id;
6590 int i, mindex;
6591 ErrorCode err;
6592 Buffer buf;
6593 MonoContext restore_ctx;
6594 guint8 *p;
6596 tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id);
6597 g_assert (tls);
6600 * Store the `InvokeData *' in `tls->invoke' until we're done with
6601 * the invocation, so CMD_VM_ABORT_INVOKE can check it.
6604 mono_loader_lock ();
6606 invoke = tls->pending_invoke;
6607 g_assert (invoke);
6608 tls->pending_invoke = NULL;
6610 invoke->last_invoke = tls->invoke;
6611 tls->invoke = invoke;
6613 mono_loader_unlock ();
6615 tls->frames_up_to_date = FALSE;
6617 id = invoke->id;
6619 p = invoke->p;
6620 err = ERR_NONE;
6621 for (mindex = 0; mindex < invoke->nmethods; ++mindex) {
6622 buffer_init (&buf, 128);
6624 if (err) {
6625 /* Fail the other invokes as well */
6626 } else {
6627 err = do_invoke_method (tls, &buf, invoke, p, &p);
6630 if (tls->abort_requested) {
6631 if (CHECK_PROTOCOL_VERSION (2, 42))
6632 err = ERR_INVOKE_ABORTED;
6635 /* Start suspending before sending the reply */
6636 if (mindex == invoke->nmethods - 1) {
6637 if (!(invoke->flags & INVOKE_FLAG_SINGLE_THREADED)) {
6638 for (i = 0; i < invoke->suspend_count; ++i)
6639 suspend_vm ();
6643 send_reply_packet (id, err, &buf);
6645 buffer_free (&buf);
6648 memcpy (&restore_ctx, &invoke->ctx, sizeof (MonoContext));
6650 if (invoke->has_ctx)
6651 save_thread_context (&restore_ctx);
6653 if (invoke->flags & INVOKE_FLAG_SINGLE_THREADED) {
6654 g_assert (tls->resume_count);
6655 tls->resume_count -= invoke->suspend_count;
6658 DEBUG_PRINTF (1, "[%p] Invoke finished (%d), resume_count = %d.\n", (gpointer) (gsize) mono_native_thread_id_get (), err, tls->resume_count);
6661 * Take the loader lock to avoid race conditions with CMD_VM_ABORT_INVOKE:
6663 * It is possible that mono_thread_internal_abort () was called
6664 * after the mono_runtime_invoke_checked() already returned, but it doesn't matter
6665 * because we reset the abort here.
6668 mono_loader_lock ();
6670 if (tls->abort_requested)
6671 mono_thread_internal_reset_abort (tls->thread);
6673 tls->invoke = tls->invoke->last_invoke;
6674 tls->abort_requested = FALSE;
6676 mono_loader_unlock ();
6678 g_free (invoke->p);
6679 g_free (invoke);
6682 static gboolean
6683 is_really_suspended (gpointer key, gpointer value, gpointer user_data)
6685 MonoThread *thread = (MonoThread *)value;
6686 DebuggerTlsData *tls;
6687 gboolean res;
6689 mono_loader_lock ();
6690 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
6691 g_assert (tls);
6692 res = tls->really_suspended;
6693 mono_loader_unlock ();
6695 return res;
6698 static GPtrArray*
6699 get_source_files_for_type (MonoClass *klass)
6701 gpointer iter = NULL;
6702 MonoMethod *method;
6703 MonoDebugSourceInfo *sinfo;
6704 GPtrArray *files;
6705 int i, j;
6707 files = g_ptr_array_new ();
6709 while ((method = mono_class_get_methods (klass, &iter))) {
6710 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
6711 GPtrArray *source_file_list;
6713 if (minfo) {
6714 mono_debug_get_seq_points (minfo, NULL, &source_file_list, NULL, NULL, NULL);
6715 for (j = 0; j < source_file_list->len; ++j) {
6716 sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, j);
6717 for (i = 0; i < files->len; ++i)
6718 if (!strcmp ((const char*)g_ptr_array_index (files, i), (const char*)sinfo->source_file))
6719 break;
6720 if (i == files->len)
6721 g_ptr_array_add (files, g_strdup (sinfo->source_file));
6723 g_ptr_array_free (source_file_list, TRUE);
6727 return files;
6731 typedef struct {
6732 MonoTypeNameParse *info;
6733 gboolean ignore_case;
6734 GPtrArray *res_classes;
6735 GPtrArray *res_domains;
6736 } GetTypesArgs;
6738 static void
6739 get_types (gpointer key, gpointer value, gpointer user_data)
6741 MonoAssembly *ass;
6742 gboolean type_resolve;
6743 MonoType *t;
6744 GSList *tmp;
6745 MonoDomain *domain = (MonoDomain*)key;
6747 if (mono_domain_is_unloading (domain))
6748 return;
6750 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
6751 GetTypesArgs *ud = (GetTypesArgs*)user_data;
6753 mono_domain_assemblies_lock (domain);
6754 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
6755 ass = (MonoAssembly *)tmp->data;
6757 if (ass->image) {
6758 ERROR_DECL (probe_type_error);
6759 /* FIXME really okay to call while holding locks? */
6760 t = mono_reflection_get_type_checked (alc, ass->image, ass->image, ud->info, ud->ignore_case, TRUE, &type_resolve, probe_type_error);
6761 mono_error_cleanup (probe_type_error);
6762 if (t) {
6763 g_ptr_array_add (ud->res_classes, mono_type_get_class_internal (t));
6764 g_ptr_array_add (ud->res_domains, domain);
6768 mono_domain_assemblies_unlock (domain);
6771 typedef struct {
6772 gboolean ignore_case;
6773 char *basename;
6774 GPtrArray *res_classes;
6775 GPtrArray *res_domains;
6776 } GetTypesForSourceFileArgs;
6778 static void
6779 get_types_for_source_file (gpointer key, gpointer value, gpointer user_data)
6781 GHashTableIter iter;
6782 GSList *class_list = NULL;
6783 MonoClass *klass = NULL;
6784 GPtrArray *files = NULL;
6786 GetTypesForSourceFileArgs *ud = (GetTypesForSourceFileArgs*)user_data;
6787 MonoDomain *domain = (MonoDomain*)key;
6789 if (mono_domain_is_unloading (domain))
6790 return;
6792 AgentDomainInfo *info = (AgentDomainInfo *)domain_jit_info (domain)->agent_info;
6794 /* Update 'source_file_to_class' cache */
6795 g_hash_table_iter_init (&iter, info->loaded_classes);
6796 while (g_hash_table_iter_next (&iter, NULL, (void**)&klass)) {
6797 if (!g_hash_table_lookup (info->source_files, klass)) {
6798 files = get_source_files_for_type (klass);
6799 g_hash_table_insert (info->source_files, klass, files);
6801 for (int i = 0; i < files->len; ++i) {
6802 char *s = (char *)g_ptr_array_index (files, i);
6803 char *s2 = dbg_path_get_basename (s);
6804 char *s3;
6806 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class, s2);
6807 if (!class_list) {
6808 class_list = g_slist_prepend (class_list, klass);
6809 g_hash_table_insert (info->source_file_to_class, g_strdup (s2), class_list);
6810 } else {
6811 class_list = g_slist_prepend (class_list, klass);
6812 g_hash_table_insert (info->source_file_to_class, s2, class_list);
6815 /* The _ignorecase hash contains the lowercase path */
6816 s3 = strdup_tolower (s2);
6817 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class_ignorecase, s3);
6818 if (!class_list) {
6819 class_list = g_slist_prepend (class_list, klass);
6820 g_hash_table_insert (info->source_file_to_class_ignorecase, g_strdup (s3), class_list);
6821 } else {
6822 class_list = g_slist_prepend (class_list, klass);
6823 g_hash_table_insert (info->source_file_to_class_ignorecase, s3, class_list);
6826 g_free (s2);
6827 g_free (s3);
6832 if (ud->ignore_case) {
6833 char *s;
6835 s = strdup_tolower (ud->basename);
6836 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class_ignorecase, s);
6837 g_free (s);
6838 } else {
6839 class_list = (GSList *)g_hash_table_lookup (info->source_file_to_class, ud->basename);
6842 for (GSList *l = class_list; l; l = l->next) {
6843 klass = (MonoClass *)l->data;
6845 g_ptr_array_add (ud->res_classes, klass);
6846 g_ptr_array_add (ud->res_domains, domain);
6850 static void add_error_string (Buffer *buf, const char *str)
6852 if (CHECK_PROTOCOL_VERSION (2, 56))
6853 buffer_add_string (buf, str);
6856 static ErrorCode
6857 vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
6859 switch (command) {
6860 case CMD_VM_VERSION: {
6861 char *build_info, *version;
6863 build_info = mono_get_runtime_build_info ();
6864 version = g_strdup_printf ("mono %s", build_info);
6866 buffer_add_string (buf, version); /* vm version */
6867 buffer_add_int (buf, MAJOR_VERSION);
6868 buffer_add_int (buf, MINOR_VERSION);
6869 g_free (build_info);
6870 g_free (version);
6871 break;
6873 case CMD_VM_SET_PROTOCOL_VERSION: {
6874 major_version = decode_int (p, &p, end);
6875 minor_version = decode_int (p, &p, end);
6876 protocol_version_set = TRUE;
6877 DEBUG_PRINTF (1, "[dbg] Protocol version %d.%d, client protocol version %d.%d.\n", MAJOR_VERSION, MINOR_VERSION, major_version, minor_version);
6878 break;
6880 case CMD_VM_ALL_THREADS: {
6881 // FIXME: Domains
6882 gboolean remove_gc_finalizing = FALSE;
6883 mono_loader_lock ();
6884 int count = mono_g_hash_table_size (tid_to_thread_obj);
6885 mono_g_hash_table_foreach (tid_to_thread_obj, count_thread_check_gc_finalizer, &remove_gc_finalizing);
6886 if (remove_gc_finalizing)
6887 count--;
6888 buffer_add_int (buf, count);
6889 mono_g_hash_table_foreach (tid_to_thread_obj, add_thread, buf);
6891 mono_loader_unlock ();
6892 break;
6894 case CMD_VM_SUSPEND:
6895 suspend_vm ();
6896 wait_for_suspend ();
6897 break;
6898 case CMD_VM_RESUME:
6899 if (suspend_count == 0)
6900 return ERR_NOT_SUSPENDED;
6901 resume_vm ();
6902 clear_suspended_objs ();
6903 break;
6904 case CMD_VM_DISPOSE:
6905 dispose_vm ();
6906 break;
6907 case CMD_VM_EXIT: {
6908 MonoInternalThread *thread;
6909 DebuggerTlsData *tls;
6910 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6911 MonoClass *env_class;
6912 #endif
6913 MonoMethod *exit_method = NULL;
6914 gpointer *args;
6915 int exit_code;
6917 exit_code = decode_int (p, &p, end);
6919 // FIXME: What if there is a VM_DEATH event request with SUSPEND_ALL ?
6921 /* Have to send a reply before exiting */
6922 send_reply_packet (id, 0, buf);
6924 /* Clear all event requests */
6925 mono_loader_lock ();
6926 while (event_requests->len > 0) {
6927 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, 0);
6929 clear_event_request (req->id, req->event_kind);
6931 mono_loader_unlock ();
6934 * The JDWP documentation says that the shutdown is not orderly. It doesn't
6935 * specify whenever a VM_DEATH event is sent. We currently do an orderly
6936 * shutdown by hijacking a thread to execute Environment.Exit (). This is
6937 * better than doing the shutdown ourselves, since it avoids various races.
6940 suspend_vm ();
6941 wait_for_suspend ();
6943 #ifdef TRY_MANAGED_SYSTEM_ENVIRONMENT_EXIT
6944 env_class = mono_class_try_load_from_name (mono_defaults.corlib, "System", "Environment");
6945 if (env_class) {
6946 ERROR_DECL (error);
6947 exit_method = mono_class_get_method_from_name_checked (env_class, "Exit", 1, 0, error);
6948 mono_error_assert_ok (error);
6950 #endif
6952 mono_loader_lock ();
6953 thread = (MonoInternalThread *)mono_g_hash_table_find (tid_to_thread, is_really_suspended, NULL);
6954 mono_loader_unlock ();
6956 if (thread && exit_method) {
6957 mono_loader_lock ();
6958 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
6959 mono_loader_unlock ();
6961 args = g_new0 (gpointer, 1);
6962 args [0] = g_malloc (sizeof (int));
6963 *(int*)(args [0]) = exit_code;
6965 tls->pending_invoke = g_new0 (InvokeData, 1);
6966 tls->pending_invoke->method = exit_method;
6967 tls->pending_invoke->args = args;
6968 tls->pending_invoke->nmethods = 1;
6970 while (suspend_count > 0)
6971 resume_vm ();
6972 } else {
6974 * No thread found, do it ourselves.
6975 * FIXME: This can race with normal shutdown etc.
6977 while (suspend_count > 0)
6978 resume_vm ();
6980 if (!mono_runtime_try_shutdown ())
6981 break;
6983 mono_environment_exitcode_set (exit_code);
6985 /* Suspend all managed threads since the runtime is going away */
6986 #ifndef ENABLE_NETCORE
6987 DEBUG_PRINTF (1, "Suspending all threads...\n");
6988 mono_thread_suspend_all_other_threads ();
6989 #endif
6990 DEBUG_PRINTF (1, "Shutting down the runtime...\n");
6991 mono_runtime_quit_internal ();
6992 transport_close2 ();
6993 DEBUG_PRINTF (1, "Exiting...\n");
6995 exit (exit_code);
6997 break;
6999 case CMD_VM_INVOKE_METHOD:
7000 case CMD_VM_INVOKE_METHODS: {
7001 int objid = decode_objid (p, &p, end);
7002 MonoThread *thread;
7003 DebuggerTlsData *tls;
7004 int i, count, flags, nmethods;
7005 ErrorCode err;
7007 err = get_object (objid, (MonoObject**)&thread);
7008 if (err != ERR_NONE)
7009 return err;
7011 flags = decode_int (p, &p, end);
7013 if (command == CMD_VM_INVOKE_METHODS)
7014 nmethods = decode_int (p, &p, end);
7015 else
7016 nmethods = 1;
7018 // Wait for suspending if it already started
7019 if (suspend_count)
7020 wait_for_suspend ();
7021 if (!is_suspended ())
7022 return ERR_NOT_SUSPENDED;
7024 mono_loader_lock ();
7025 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL (thread));
7026 mono_loader_unlock ();
7027 g_assert (tls);
7029 if (!tls->really_suspended)
7030 /* The thread is still running native code, can't do invokes */
7031 return ERR_NOT_SUSPENDED;
7034 * Store the invoke data into tls, the thread will execute it after it is
7035 * resumed.
7037 if (tls->pending_invoke)
7038 return ERR_NOT_SUSPENDED;
7039 tls->pending_invoke = g_new0 (InvokeData, 1);
7040 tls->pending_invoke->id = id;
7041 tls->pending_invoke->flags = flags;
7042 tls->pending_invoke->p = (guint8 *)g_malloc (end - p);
7043 memcpy (tls->pending_invoke->p, p, end - p);
7044 tls->pending_invoke->endp = tls->pending_invoke->p + (end - p);
7045 tls->pending_invoke->suspend_count = suspend_count;
7046 tls->pending_invoke->nmethods = nmethods;
7048 if (flags & INVOKE_FLAG_SINGLE_THREADED) {
7049 resume_thread (THREAD_TO_INTERNAL (thread));
7051 else {
7052 count = suspend_count;
7053 for (i = 0; i < count; ++i)
7054 resume_vm ();
7056 break;
7058 case CMD_VM_ABORT_INVOKE: {
7059 int objid = decode_objid (p, &p, end);
7060 MonoThread *thread;
7061 DebuggerTlsData *tls;
7062 int invoke_id;
7063 ErrorCode err;
7065 err = get_object (objid, (MonoObject**)&thread);
7066 if (err != ERR_NONE)
7067 return err;
7069 invoke_id = decode_int (p, &p, end);
7071 mono_loader_lock ();
7072 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL (thread));
7073 g_assert (tls);
7075 if (tls->abort_requested) {
7076 DEBUG_PRINTF (1, "Abort already requested.\n");
7077 mono_loader_unlock ();
7078 break;
7082 * Check whether we're still inside the mono_runtime_invoke_checked() and that it's
7083 * actually the correct invocation.
7085 * Careful, we do not stop the thread that's doing the invocation, so we can't
7086 * inspect its stack. However, invoke_method() also acquires the loader lock
7087 * when it's done, so we're safe here.
7091 if (!tls->invoke || (tls->invoke->id != invoke_id)) {
7092 mono_loader_unlock ();
7093 return ERR_NO_INVOCATION;
7096 tls->abort_requested = TRUE;
7098 mono_thread_internal_abort (THREAD_TO_INTERNAL (thread), FALSE);
7099 mono_loader_unlock ();
7100 break;
7103 case CMD_VM_SET_KEEPALIVE: {
7104 int timeout = decode_int (p, &p, end);
7105 agent_config.keepalive = timeout;
7106 // FIXME:
7107 #ifndef DISABLE_SOCKET_TRANSPORT
7108 set_keepalive ();
7109 #else
7110 NOT_IMPLEMENTED;
7111 #endif
7112 break;
7114 case CMD_VM_GET_TYPES_FOR_SOURCE_FILE: {
7115 int i;
7116 char *fname, *basename;
7117 gboolean ignore_case;
7118 GPtrArray *res_classes, *res_domains;
7120 fname = decode_string (p, &p, end);
7121 ignore_case = decode_byte (p, &p, end);
7123 basename = dbg_path_get_basename (fname);
7125 res_classes = g_ptr_array_new ();
7126 res_domains = g_ptr_array_new ();
7128 mono_loader_lock ();
7129 GetTypesForSourceFileArgs args;
7130 memset (&args, 0, sizeof (args));
7131 args.ignore_case = ignore_case;
7132 args.basename = basename;
7133 args.res_classes = res_classes;
7134 args.res_domains = res_domains;
7135 mono_de_foreach_domain (get_types_for_source_file, &args);
7136 mono_loader_unlock ();
7138 g_free (fname);
7139 g_free (basename);
7141 buffer_add_int (buf, res_classes->len);
7142 for (i = 0; i < res_classes->len; ++i)
7143 buffer_add_typeid (buf, (MonoDomain *)g_ptr_array_index (res_domains, i), (MonoClass *)g_ptr_array_index (res_classes, i));
7144 g_ptr_array_free (res_classes, TRUE);
7145 g_ptr_array_free (res_domains, TRUE);
7146 break;
7148 case CMD_VM_GET_TYPES: {
7149 ERROR_DECL (error);
7150 int i;
7151 char *name;
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_checked (name, &info, error)) {
7160 add_error_string (buf, mono_error_get_message (error));
7161 mono_error_cleanup (error);
7162 g_free (name);
7163 mono_reflection_free_type_info (&info);
7164 return ERR_INVALID_ARGUMENT;
7167 res_classes = g_ptr_array_new ();
7168 res_domains = g_ptr_array_new ();
7170 mono_loader_lock ();
7172 GetTypesArgs args;
7173 memset (&args, 0, sizeof (args));
7174 args.info = &info;
7175 args.ignore_case = ignore_case;
7176 args.res_classes = res_classes;
7177 args.res_domains = res_domains;
7179 mono_de_foreach_domain (get_types, &args);
7181 mono_loader_unlock ();
7183 g_free (name);
7184 mono_reflection_free_type_info (&info);
7186 buffer_add_int (buf, res_classes->len);
7187 for (i = 0; i < res_classes->len; ++i)
7188 buffer_add_typeid (buf, (MonoDomain *)g_ptr_array_index (res_domains, i), (MonoClass *)g_ptr_array_index (res_classes, i));
7189 g_ptr_array_free (res_classes, TRUE);
7190 g_ptr_array_free (res_domains, TRUE);
7191 break;
7193 case CMD_VM_START_BUFFERING:
7194 case CMD_VM_STOP_BUFFERING:
7195 /* Handled in the main loop */
7196 break;
7197 default:
7198 return ERR_NOT_IMPLEMENTED;
7201 return ERR_NONE;
7204 static ErrorCode
7205 event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7207 ErrorCode err;
7208 ERROR_DECL (error);
7210 switch (command) {
7211 case CMD_EVENT_REQUEST_SET: {
7212 EventRequest *req;
7213 int i, event_kind, suspend_policy, nmodifiers;
7214 ModifierKind mod;
7215 MonoMethod *method;
7216 long location = 0;
7217 MonoThread *step_thread;
7218 int step_thread_id = 0;
7219 StepDepth depth = STEP_DEPTH_INTO;
7220 StepSize size = STEP_SIZE_MIN;
7221 StepFilter filter = STEP_FILTER_NONE;
7222 MonoDomain *domain;
7223 Modifier *modifier;
7225 event_kind = decode_byte (p, &p, end);
7226 suspend_policy = decode_byte (p, &p, end);
7227 nmodifiers = decode_byte (p, &p, end);
7229 req = (EventRequest *)g_malloc0 (sizeof (EventRequest) + (nmodifiers * sizeof (Modifier)));
7230 req->id = mono_atomic_inc_i32 (&event_request_id);
7231 req->event_kind = event_kind;
7232 req->suspend_policy = suspend_policy;
7233 req->nmodifiers = nmodifiers;
7235 method = NULL;
7236 for (i = 0; i < nmodifiers; ++i) {
7237 mod = (ModifierKind)decode_byte (p, &p, end);
7239 req->modifiers [i].kind = mod;
7240 if (mod == MOD_KIND_COUNT) {
7241 req->modifiers [i].data.count = decode_int (p, &p, end);
7242 } else if (mod == MOD_KIND_LOCATION_ONLY) {
7243 method = decode_methodid (p, &p, end, &domain, &err);
7244 if (err != ERR_NONE)
7245 return err;
7246 location = decode_long (p, &p, end);
7247 } else if (mod == MOD_KIND_STEP) {
7248 step_thread_id = decode_id (p, &p, end);
7249 size = (StepSize)decode_int (p, &p, end);
7250 depth = (StepDepth)decode_int (p, &p, end);
7251 if (CHECK_PROTOCOL_VERSION (2, 16))
7252 filter = (StepFilter)decode_int (p, &p, end);
7253 req->modifiers [i].data.filter = filter;
7254 if (!CHECK_PROTOCOL_VERSION (2, 26) && (req->modifiers [i].data.filter & STEP_FILTER_DEBUGGER_HIDDEN))
7255 /* Treat STEP_THOUGH the same as HIDDEN */
7256 req->modifiers [i].data.filter = (StepFilter)(req->modifiers [i].data.filter | STEP_FILTER_DEBUGGER_STEP_THROUGH);
7257 } else if (mod == MOD_KIND_THREAD_ONLY) {
7258 int id = decode_id (p, &p, end);
7260 err = get_object (id, (MonoObject**)&req->modifiers [i].data.thread);
7261 if (err != ERR_NONE) {
7262 g_free (req);
7263 return err;
7265 } else if (mod == MOD_KIND_EXCEPTION_ONLY) {
7266 MonoClass *exc_class = decode_typeid (p, &p, end, &domain, &err);
7268 if (err != ERR_NONE)
7269 return err;
7270 req->modifiers [i].caught = decode_byte (p, &p, end);
7271 req->modifiers [i].uncaught = decode_byte (p, &p, end);
7272 if (CHECK_PROTOCOL_VERSION (2, 25))
7273 req->modifiers [i].subclasses = decode_byte (p, &p, end);
7274 else
7275 req->modifiers [i].subclasses = TRUE;
7276 if (exc_class) {
7277 req->modifiers [i].data.exc_class = exc_class;
7279 if (!mono_class_is_assignable_from_internal (mono_defaults.exception_class, exc_class)) {
7280 g_free (req);
7281 return ERR_INVALID_ARGUMENT;
7284 if (CHECK_PROTOCOL_VERSION (2, 54)) {
7285 req->modifiers [i].not_filtered_feature = decode_byte (p, &p, end);
7286 req->modifiers [i].everything_else = decode_byte (p, &p, end);
7287 DEBUG_PRINTF (1, "[dbg] \tEXCEPTION_ONLY 2 filter (%s%s%s%s).\n", exc_class ? m_class_get_name (exc_class) : (req->modifiers [i].everything_else ? "everything else" : "all"), req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : "");
7288 } else {
7289 req->modifiers [i].not_filtered_feature = FALSE;
7290 req->modifiers [i].everything_else = FALSE;
7291 DEBUG_PRINTF (1, "[dbg] \tEXCEPTION_ONLY filter (%s%s%s%s).\n", exc_class ? m_class_get_name (exc_class) : "all", req->modifiers [i].caught ? ", caught" : "", req->modifiers [i].uncaught ? ", uncaught" : "", req->modifiers [i].subclasses ? ", include-subclasses" : "");
7294 } else if (mod == MOD_KIND_ASSEMBLY_ONLY) {
7295 int n = decode_int (p, &p, end);
7296 int j;
7298 // +1 because we don't know length and we use last element to check for end
7299 req->modifiers [i].data.assemblies = g_new0 (MonoAssembly*, n + 1);
7300 for (j = 0; j < n; ++j) {
7301 req->modifiers [i].data.assemblies [j] = decode_assemblyid (p, &p, end, &domain, &err);
7302 if (err != ERR_NONE) {
7303 g_free (req->modifiers [i].data.assemblies);
7304 return err;
7307 } else if (mod == MOD_KIND_SOURCE_FILE_ONLY) {
7308 int n = decode_int (p, &p, end);
7309 int j;
7311 modifier = &req->modifiers [i];
7312 modifier->data.source_files = g_hash_table_new (g_str_hash, g_str_equal);
7313 for (j = 0; j < n; ++j) {
7314 char *s = decode_string (p, &p, end);
7315 char *s2;
7317 if (s) {
7318 s2 = strdup_tolower (s);
7319 g_hash_table_insert (modifier->data.source_files, s2, s2);
7320 g_free (s);
7323 } else if (mod == MOD_KIND_TYPE_NAME_ONLY) {
7324 int n = decode_int (p, &p, end);
7325 int j;
7327 modifier = &req->modifiers [i];
7328 modifier->data.type_names = g_hash_table_new (g_str_hash, g_str_equal);
7329 for (j = 0; j < n; ++j) {
7330 char *s = decode_string (p, &p, end);
7332 if (s)
7333 g_hash_table_insert (modifier->data.type_names, s, s);
7335 } else {
7336 g_free (req);
7337 return ERR_NOT_IMPLEMENTED;
7341 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
7342 g_assert (method);
7344 req->info = mono_de_set_breakpoint (method, location, req, error);
7345 if (!is_ok (error)) {
7346 g_free (req);
7347 DEBUG_PRINTF (1, "[dbg] Failed to set breakpoint: %s\n", mono_error_get_message (error));
7348 mono_error_cleanup (error);
7349 return ERR_NO_SEQ_POINT_AT_IL_OFFSET;
7351 } else if (req->event_kind == EVENT_KIND_STEP) {
7352 g_assert (step_thread_id);
7354 err = get_object (step_thread_id, (MonoObject**)&step_thread);
7355 if (err != ERR_NONE) {
7356 g_free (req);
7357 return err;
7360 mono_loader_lock ();
7361 DebuggerTlsData *tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, THREAD_TO_INTERNAL(step_thread));
7362 mono_loader_unlock ();
7363 g_assert (tls);
7365 if (tls->terminated) {
7366 /* if the thread is already terminated ignore the single step */
7367 buffer_add_int (buf, req->id);
7368 return ERR_NONE;
7371 err = (ErrorCode)mono_de_ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, filter, req);
7372 if (err != ERR_NONE) {
7373 g_free (req);
7374 return err;
7376 } else if (req->event_kind == EVENT_KIND_METHOD_ENTRY) {
7377 req->info = mono_de_set_breakpoint (NULL, METHOD_ENTRY_IL_OFFSET, req, NULL);
7378 } else if (req->event_kind == EVENT_KIND_METHOD_EXIT) {
7379 req->info = mono_de_set_breakpoint (NULL, METHOD_EXIT_IL_OFFSET, req, NULL);
7380 } else if (req->event_kind == EVENT_KIND_EXCEPTION) {
7381 } else if (req->event_kind == EVENT_KIND_TYPE_LOAD) {
7382 } else {
7383 if (req->nmodifiers) {
7384 g_free (req);
7385 return ERR_NOT_IMPLEMENTED;
7389 mono_loader_lock ();
7390 g_ptr_array_add (event_requests, req);
7392 if (agent_config.defer) {
7393 /* Transmit cached data to the client on receipt of the event request */
7394 switch (req->event_kind) {
7395 case EVENT_KIND_APPDOMAIN_CREATE:
7396 /* Emit load events for currently loaded domains */
7397 mono_de_foreach_domain (emit_appdomain_load, NULL);
7398 break;
7399 case EVENT_KIND_ASSEMBLY_LOAD:
7400 /* Emit load events for currently loaded assemblies */
7401 mono_domain_foreach (send_assemblies_for_domain, NULL);
7402 break;
7403 case EVENT_KIND_THREAD_START:
7404 /* Emit start events for currently started threads */
7405 mono_g_hash_table_foreach (tid_to_thread, emit_thread_start, NULL);
7406 break;
7407 case EVENT_KIND_TYPE_LOAD:
7408 /* Emit type load events for currently loaded types */
7409 mono_domain_foreach (send_types_for_domain, NULL);
7410 break;
7411 default:
7412 break;
7415 mono_loader_unlock ();
7417 buffer_add_int (buf, req->id);
7418 break;
7420 case CMD_EVENT_REQUEST_CLEAR: {
7421 int etype = decode_byte (p, &p, end);
7422 int req_id = decode_int (p, &p, end);
7424 // FIXME: Make a faster mapping from req_id to request
7425 mono_loader_lock ();
7426 clear_event_request (req_id, etype);
7427 mono_loader_unlock ();
7428 break;
7430 case CMD_EVENT_REQUEST_CLEAR_ALL_BREAKPOINTS: {
7431 int i;
7433 mono_loader_lock ();
7434 i = 0;
7435 while (i < event_requests->len) {
7436 EventRequest *req = (EventRequest *)g_ptr_array_index (event_requests, i);
7438 if (req->event_kind == EVENT_KIND_BREAKPOINT) {
7439 mono_de_clear_breakpoint ((MonoBreakpoint *)req->info);
7441 g_ptr_array_remove_index_fast (event_requests, i);
7442 g_free (req);
7443 } else {
7444 i ++;
7447 mono_loader_unlock ();
7448 break;
7450 default:
7451 return ERR_NOT_IMPLEMENTED;
7454 return ERR_NONE;
7457 static ErrorCode
7458 domain_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7460 ErrorCode err;
7461 MonoDomain *domain;
7463 switch (command) {
7464 case CMD_APPDOMAIN_GET_ROOT_DOMAIN: {
7465 buffer_add_domainid (buf, mono_get_root_domain ());
7466 break;
7468 case CMD_APPDOMAIN_GET_FRIENDLY_NAME: {
7469 domain = decode_domainid (p, &p, end, NULL, &err);
7470 if (err != ERR_NONE)
7471 return err;
7472 buffer_add_string (buf, domain->friendly_name);
7473 break;
7475 case CMD_APPDOMAIN_GET_ASSEMBLIES: {
7476 GSList *tmp;
7477 MonoAssembly *ass;
7478 int count;
7480 domain = decode_domainid (p, &p, end, NULL, &err);
7481 if (err != ERR_NONE)
7482 return err;
7483 mono_domain_assemblies_lock (domain);
7484 count = 0;
7485 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
7486 count ++;
7488 buffer_add_int (buf, count);
7489 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
7490 ass = (MonoAssembly *)tmp->data;
7491 buffer_add_assemblyid (buf, domain, ass);
7493 mono_domain_assemblies_unlock (domain);
7494 break;
7496 case CMD_APPDOMAIN_GET_ENTRY_ASSEMBLY: {
7497 domain = decode_domainid (p, &p, end, NULL, &err);
7498 if (err != ERR_NONE)
7499 return err;
7501 buffer_add_assemblyid (buf, domain, domain->entry_assembly);
7502 break;
7504 case CMD_APPDOMAIN_GET_CORLIB: {
7505 domain = decode_domainid (p, &p, end, NULL, &err);
7506 if (err != ERR_NONE)
7507 return err;
7509 buffer_add_assemblyid (buf, domain, m_class_get_image (domain->domain->mbr.obj.vtable->klass)->assembly);
7510 break;
7512 case CMD_APPDOMAIN_CREATE_STRING: {
7513 char *s;
7514 MonoString *o;
7515 ERROR_DECL (error);
7517 domain = decode_domainid (p, &p, end, NULL, &err);
7518 if (err != ERR_NONE)
7519 return err;
7520 s = decode_string (p, &p, end);
7522 o = mono_string_new_checked (domain, s, error);
7523 if (!is_ok (error)) {
7524 DEBUG_PRINTF (1, "[dbg] Failed to allocate String object '%s': %s\n", s, mono_error_get_message (error));
7525 mono_error_cleanup (error);
7526 return ERR_INVALID_OBJECT;
7528 buffer_add_objid (buf, (MonoObject*)o);
7529 break;
7531 case CMD_APPDOMAIN_CREATE_BYTE_ARRAY: {
7532 ERROR_DECL (error);
7533 MonoArray *arr;
7534 gpointer elem;
7535 domain = decode_domainid (p, &p, end, NULL, &err);
7536 uintptr_t size = 0;
7537 int len = decode_int (p, &p, end);
7538 size = len;
7539 arr = mono_array_new_full_checked (mono_domain_get (), mono_class_create_array (mono_get_byte_class(), 1), &size, NULL, error);
7540 elem = mono_array_addr_internal (arr, guint8, 0);
7541 memcpy (elem, p, len);
7542 p += len;
7543 buffer_add_objid (buf, (MonoObject*) arr);
7544 break;
7546 case CMD_APPDOMAIN_CREATE_BOXED_VALUE: {
7547 ERROR_DECL (error);
7548 MonoClass *klass;
7549 MonoDomain *domain2;
7550 MonoObject *o;
7552 domain = decode_domainid (p, &p, end, NULL, &err);
7553 if (err != ERR_NONE)
7554 return err;
7555 klass = decode_typeid (p, &p, end, &domain2, &err);
7556 if (err != ERR_NONE)
7557 return err;
7559 // FIXME:
7560 g_assert (domain == domain2);
7562 o = mono_object_new_checked (domain, klass, error);
7563 mono_error_assert_ok (error);
7565 err = decode_value (m_class_get_byval_arg (klass), domain, (guint8 *)mono_object_unbox_internal (o), p, &p, end, TRUE);
7566 if (err != ERR_NONE)
7567 return err;
7569 buffer_add_objid (buf, o);
7570 break;
7572 default:
7573 return ERR_NOT_IMPLEMENTED;
7576 return ERR_NONE;
7579 static ErrorCode
7580 get_assembly_object_command (MonoDomain *domain, MonoAssembly *ass, Buffer *buf, MonoError *error)
7582 HANDLE_FUNCTION_ENTER();
7583 ErrorCode err = ERR_NONE;
7584 error_init (error);
7585 MonoReflectionAssemblyHandle o = mono_assembly_get_object_handle (domain, ass, error);
7586 if (MONO_HANDLE_IS_NULL (o)) {
7587 err = ERR_INVALID_OBJECT;
7588 goto leave;
7590 buffer_add_objid (buf, MONO_HANDLE_RAW (MONO_HANDLE_CAST (MonoObject, o)));
7591 leave:
7592 HANDLE_FUNCTION_RETURN_VAL (err);
7596 static ErrorCode
7597 assembly_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7599 ErrorCode err;
7600 MonoAssembly *ass;
7601 MonoDomain *domain;
7603 ass = decode_assemblyid (p, &p, end, &domain, &err);
7604 if (err != ERR_NONE)
7605 return err;
7607 switch (command) {
7608 case CMD_ASSEMBLY_GET_LOCATION: {
7609 buffer_add_string (buf, mono_image_get_filename (ass->image));
7610 break;
7612 case CMD_ASSEMBLY_GET_ENTRY_POINT: {
7613 guint32 token;
7614 MonoMethod *m;
7616 if (ass->image->dynamic) {
7617 buffer_add_id (buf, 0);
7618 } else {
7619 token = mono_image_get_entry_point (ass->image);
7620 if (token == 0) {
7621 buffer_add_id (buf, 0);
7622 } else {
7623 ERROR_DECL (error);
7624 m = mono_get_method_checked (ass->image, token, NULL, NULL, error);
7625 if (!m)
7626 mono_error_cleanup (error); /* FIXME don't swallow the error */
7627 buffer_add_methodid (buf, domain, m);
7630 break;
7632 case CMD_ASSEMBLY_GET_MANIFEST_MODULE: {
7633 buffer_add_moduleid (buf, domain, ass->image);
7634 break;
7636 case CMD_ASSEMBLY_GET_OBJECT: {
7637 ERROR_DECL (error);
7638 err = get_assembly_object_command (domain, ass, buf, error);
7639 mono_error_cleanup (error);
7640 return err;
7642 case CMD_ASSEMBLY_GET_DOMAIN: {
7643 buffer_add_domainid (buf, domain);
7644 break;
7646 case CMD_ASSEMBLY_GET_TYPE: {
7647 ERROR_DECL (error);
7648 char *s = decode_string (p, &p, end);
7649 char* original_s = g_strdup_printf ("\"%s\"", s);
7651 gboolean ignorecase = decode_byte (p, &p, end);
7652 MonoTypeNameParse info;
7653 MonoType *t;
7654 gboolean type_resolve, res;
7655 MonoDomain *d = mono_domain_get ();
7656 MonoAssemblyLoadContext *alc = mono_domain_default_alc (d);
7658 /* This is needed to be able to find referenced assemblies */
7659 res = mono_domain_set_fast (domain, FALSE);
7660 g_assert (res);
7662 if (!mono_reflection_parse_type_checked (s, &info, error)) {
7663 mono_error_cleanup (error);
7664 t = NULL;
7665 } else {
7666 if (info.assembly.name) {
7667 mono_reflection_free_type_info (&info);
7668 g_free (s);
7669 mono_domain_set_fast (d, TRUE);
7670 char* error_msg = g_strdup_printf ("Unexpected assembly-qualified type %s was provided", original_s);
7671 add_error_string (buf, error_msg);
7672 g_free (error_msg);
7673 g_free (original_s);
7674 return ERR_INVALID_ARGUMENT;
7676 t = mono_reflection_get_type_checked (alc, ass->image, ass->image, &info, ignorecase, TRUE, &type_resolve, error);
7677 if (!is_ok (error)) {
7678 mono_error_cleanup (error); /* FIXME don't swallow the error */
7679 mono_reflection_free_type_info (&info);
7680 g_free (s);
7681 mono_domain_set_fast (d, TRUE);
7682 char* error_msg = g_strdup_printf ("Invalid type name %s", original_s);
7683 add_error_string (buf, error_msg);
7684 g_free (error_msg);
7685 g_free (original_s);
7686 return ERR_INVALID_ARGUMENT;
7689 buffer_add_typeid (buf, domain, t ? mono_class_from_mono_type_internal (t) : NULL);
7690 mono_reflection_free_type_info (&info);
7691 g_free (s);
7692 g_free (original_s);
7693 mono_domain_set_fast (d, TRUE);
7695 break;
7697 case CMD_ASSEMBLY_GET_NAME: {
7698 gchar *name;
7699 MonoAssembly *mass = ass;
7701 name = g_strdup_printf (
7702 "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
7703 mass->aname.name,
7704 mass->aname.major, mass->aname.minor, mass->aname.build, mass->aname.revision,
7705 mass->aname.culture && *mass->aname.culture? mass->aname.culture: "neutral",
7706 mass->aname.public_key_token [0] ? (char *)mass->aname.public_key_token : "null",
7707 (mass->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
7709 buffer_add_string (buf, name);
7710 g_free (name);
7711 break;
7713 case CMD_ASSEMBLY_GET_METADATA_BLOB: {
7714 MonoImage* image = ass->image;
7715 if (ass->dynamic) {
7716 return ERR_NOT_IMPLEMENTED;
7718 buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
7719 break;
7721 case CMD_ASSEMBLY_GET_IS_DYNAMIC: {
7722 buffer_add_byte (buf, ass->dynamic);
7723 break;
7725 case CMD_ASSEMBLY_GET_PDB_BLOB: {
7726 MonoImage* image = ass->image;
7727 MonoDebugHandle* handle = mono_debug_get_handle (image);
7728 if (!handle) {
7729 return ERR_INVALID_ARGUMENT;
7731 MonoPPDBFile* ppdb = handle->ppdb;
7732 if (ppdb) {
7733 image = mono_ppdb_get_image (ppdb);
7734 buffer_add_byte_array (buf, (guint8*)image->raw_data, image->raw_data_len);
7735 } else {
7736 buffer_add_byte_array (buf, NULL, 0);
7738 break;
7740 case CMD_ASSEMBLY_GET_TYPE_FROM_TOKEN: {
7741 if (ass->dynamic) {
7742 return ERR_NOT_IMPLEMENTED;
7744 guint32 token = decode_int (p, &p, end);
7745 ERROR_DECL (error);
7746 error_init (error);
7747 MonoClass* mono_class = mono_class_get_checked (ass->image, token, error);
7748 if (!is_ok (error)) {
7749 add_error_string (buf, mono_error_get_message (error));
7750 mono_error_cleanup (error);
7751 return ERR_INVALID_ARGUMENT;
7753 buffer_add_typeid (buf, domain, mono_class);
7754 mono_error_cleanup (error);
7755 break;
7757 case CMD_ASSEMBLY_GET_METHOD_FROM_TOKEN: {
7758 if (ass->dynamic) {
7759 return ERR_NOT_IMPLEMENTED;
7761 guint32 token = decode_int (p, &p, end);
7762 ERROR_DECL (error);
7763 error_init (error);
7764 MonoMethod* mono_method = mono_get_method_checked (ass->image, token, NULL, NULL, error);
7765 if (!is_ok (error)) {
7766 add_error_string (buf, mono_error_get_message (error));
7767 mono_error_cleanup (error);
7768 return ERR_INVALID_ARGUMENT;
7770 buffer_add_methodid (buf, domain, mono_method);
7771 mono_error_cleanup (error);
7772 break;
7774 case CMD_ASSEMBLY_HAS_DEBUG_INFO: {
7775 buffer_add_byte (buf, !ass->dynamic && mono_debug_image_has_debug_info (ass->image));
7776 break;
7778 default:
7779 return ERR_NOT_IMPLEMENTED;
7782 return ERR_NONE;
7785 static ErrorCode
7786 module_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7788 ErrorCode err;
7789 MonoDomain *domain;
7791 switch (command) {
7792 case CMD_MODULE_GET_INFO: {
7793 MonoImage *image = decode_moduleid (p, &p, end, &domain, &err);
7794 char *basename, *sourcelink = NULL;
7796 if (CHECK_PROTOCOL_VERSION (2, 48))
7797 sourcelink = mono_debug_image_get_sourcelink (image);
7799 basename = g_path_get_basename (image->name);
7800 buffer_add_string (buf, basename); // name
7801 buffer_add_string (buf, image->module_name); // scopename
7802 buffer_add_string (buf, image->name); // fqname
7803 buffer_add_string (buf, mono_image_get_guid (image)); // guid
7804 buffer_add_assemblyid (buf, domain, image->assembly); // assembly
7805 if (CHECK_PROTOCOL_VERSION (2, 48))
7806 buffer_add_string (buf, sourcelink);
7807 g_free (basename);
7808 g_free (sourcelink);
7809 break;
7811 default:
7812 return ERR_NOT_IMPLEMENTED;
7815 return ERR_NONE;
7818 static ErrorCode
7819 field_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
7821 ErrorCode err;
7822 MonoDomain *domain;
7824 switch (command) {
7825 case CMD_FIELD_GET_INFO: {
7826 MonoClassField *f = decode_fieldid (p, &p, end, &domain, &err);
7828 buffer_add_string (buf, f->name);
7829 buffer_add_typeid (buf, domain, f->parent);
7830 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (f->type));
7831 buffer_add_int (buf, f->type->attrs);
7832 break;
7834 default:
7835 return ERR_NOT_IMPLEMENTED;
7838 return ERR_NONE;
7841 static void
7842 buffer_add_cattr_arg (Buffer *buf, MonoType *t, MonoDomain *domain, MonoObject *val)
7844 if (val && val->vtable->klass == mono_defaults.runtimetype_class) {
7845 /* Special case these so the client doesn't have to handle Type objects */
7847 buffer_add_byte (buf, VALUE_TYPE_ID_TYPE);
7848 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (((MonoReflectionType*)val)->type));
7849 } else if (MONO_TYPE_IS_REFERENCE (t))
7850 buffer_add_value (buf, t, &val, domain);
7851 else
7852 buffer_add_value (buf, t, mono_object_unbox_internal (val), domain);
7855 static ErrorCode
7856 buffer_add_cattrs (Buffer *buf, MonoDomain *domain, MonoImage *image, MonoClass *attr_klass, MonoCustomAttrInfo *cinfo)
7858 int i, j;
7859 int nattrs = 0;
7861 if (!cinfo) {
7862 buffer_add_int (buf, 0);
7863 return ERR_NONE;
7866 SETUP_ICALL_FUNCTION;
7868 for (i = 0; i < cinfo->num_attrs; ++i) {
7869 if (!attr_klass || mono_class_has_parent (cinfo->attrs [i].ctor->klass, attr_klass))
7870 nattrs ++;
7872 buffer_add_int (buf, nattrs);
7874 for (i = 0; i < cinfo->num_attrs; ++i) {
7875 MonoCustomAttrEntry *attr = &cinfo->attrs [i];
7876 if (!attr_klass || mono_class_has_parent (attr->ctor->klass, attr_klass)) {
7877 MonoArray *typed_args, *named_args;
7878 MonoArrayHandleOut typed_args_h, named_args_h;
7879 MonoObjectHandle val_h;
7880 MonoType *t;
7881 CattrNamedArg *arginfo = NULL;
7882 ERROR_DECL (error);
7884 SETUP_ICALL_FRAME;
7885 typed_args_h = MONO_HANDLE_NEW (MonoArray, NULL);
7886 named_args_h = MONO_HANDLE_NEW (MonoArray, NULL);
7887 val_h = MONO_HANDLE_NEW (MonoObject, NULL);
7889 mono_reflection_create_custom_attr_data_args (image, attr->ctor, attr->data, attr->data_size, typed_args_h, named_args_h, &arginfo, error);
7890 if (!is_ok (error)) {
7891 DEBUG_PRINTF (2, "[dbg] mono_reflection_create_custom_attr_data_args () failed with: '%s'\n", mono_error_get_message (error));
7892 mono_error_cleanup (error);
7893 CLEAR_ICALL_FRAME;
7894 return ERR_LOADER_ERROR;
7896 typed_args = MONO_HANDLE_RAW (typed_args_h);
7897 named_args = MONO_HANDLE_RAW (named_args_h);
7899 buffer_add_methodid (buf, domain, attr->ctor);
7901 /* Ctor args */
7902 if (typed_args) {
7903 buffer_add_int (buf, mono_array_length_internal (typed_args));
7904 for (j = 0; j < mono_array_length_internal (typed_args); ++j) {
7905 MonoObject *val = mono_array_get_internal (typed_args, MonoObject*, j);
7906 MONO_HANDLE_ASSIGN_RAW (val_h, val);
7908 t = mono_method_signature_internal (attr->ctor)->params [j];
7910 buffer_add_cattr_arg (buf, t, domain, val);
7912 } else {
7913 buffer_add_int (buf, 0);
7916 /* Named args */
7917 if (named_args) {
7918 buffer_add_int (buf, mono_array_length_internal (named_args));
7920 for (j = 0; j < mono_array_length_internal (named_args); ++j) {
7921 MonoObject *val = mono_array_get_internal (named_args, MonoObject*, j);
7922 MONO_HANDLE_ASSIGN_RAW (val_h, val);
7924 if (arginfo [j].prop) {
7925 buffer_add_byte (buf, 0x54);
7926 buffer_add_propertyid (buf, domain, arginfo [j].prop);
7927 } else if (arginfo [j].field) {
7928 buffer_add_byte (buf, 0x53);
7929 buffer_add_fieldid (buf, domain, arginfo [j].field);
7930 } else {
7931 g_assert_not_reached ();
7934 buffer_add_cattr_arg (buf, arginfo [j].type, domain, val);
7936 } else {
7937 buffer_add_int (buf, 0);
7939 g_free (arginfo);
7941 CLEAR_ICALL_FRAME;
7945 return ERR_NONE;
7948 /* FIXME: Code duplication with icall.c */
7949 static void
7950 collect_interfaces (MonoClass *klass, GHashTable *ifaces, MonoError *error)
7952 int i;
7953 MonoClass *ic;
7955 mono_class_setup_interfaces (klass, error);
7956 if (!is_ok (error))
7957 return;
7959 int klass_interface_count = m_class_get_interface_count (klass);
7960 MonoClass **klass_interfaces = m_class_get_interfaces (klass);
7961 for (i = 0; i < klass_interface_count; i++) {
7962 ic = klass_interfaces [i];
7963 g_hash_table_insert (ifaces, ic, ic);
7965 collect_interfaces (ic, ifaces, error);
7966 if (!is_ok (error))
7967 return;
7971 static ErrorCode
7972 type_commands_internal (int command, MonoClass *klass, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf)
7974 HANDLE_FUNCTION_ENTER ();
7976 ERROR_DECL (error);
7977 MonoClass *nested;
7978 MonoType *type;
7979 gpointer iter;
7980 guint8 b;
7981 int nnested;
7982 ErrorCode err;
7983 char *name;
7984 MonoStringHandle string_handle = MONO_HANDLE_NEW (MonoString, NULL); // FIXME? Not always needed.
7986 switch (command) {
7987 case CMD_TYPE_GET_INFO: {
7988 buffer_add_string (buf, m_class_get_name_space (klass));
7989 buffer_add_string (buf, m_class_get_name (klass));
7990 // FIXME: byref
7991 name = mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_FULL_NAME);
7992 buffer_add_string (buf, name);
7993 g_free (name);
7994 buffer_add_assemblyid (buf, domain, m_class_get_image (klass)->assembly);
7995 buffer_add_moduleid (buf, domain, m_class_get_image (klass));
7996 buffer_add_typeid (buf, domain, m_class_get_parent (klass));
7997 if (m_class_get_rank (klass) || m_class_get_byval_arg (klass)->type == MONO_TYPE_PTR)
7998 buffer_add_typeid (buf, domain, m_class_get_element_class (klass));
7999 else
8000 buffer_add_id (buf, 0);
8001 buffer_add_int (buf, m_class_get_type_token (klass));
8002 buffer_add_byte (buf, m_class_get_rank (klass));
8003 buffer_add_int (buf, mono_class_get_flags (klass));
8004 b = 0;
8005 type = m_class_get_byval_arg (klass);
8006 // FIXME: Can't decide whenever a class represents a byref type
8007 if (FALSE)
8008 b |= (1 << 0);
8009 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR)
8010 b |= (1 << 1);
8011 if (!type->byref && (((type->type >= MONO_TYPE_BOOLEAN) && (type->type <= MONO_TYPE_R8)) || (type->type == MONO_TYPE_I) || (type->type == MONO_TYPE_U)))
8012 b |= (1 << 2);
8013 if (type->type == MONO_TYPE_VALUETYPE)
8014 b |= (1 << 3);
8015 if (m_class_is_enumtype (klass))
8016 b |= (1 << 4);
8017 if (mono_class_is_gtd (klass))
8018 b |= (1 << 5);
8019 if (mono_class_is_gtd (klass) || mono_class_is_ginst (klass))
8020 b |= (1 << 6);
8021 buffer_add_byte (buf, b);
8022 nnested = 0;
8023 iter = NULL;
8024 while ((nested = mono_class_get_nested_types (klass, &iter)))
8025 nnested ++;
8026 buffer_add_int (buf, nnested);
8027 iter = NULL;
8028 while ((nested = mono_class_get_nested_types (klass, &iter)))
8029 buffer_add_typeid (buf, domain, nested);
8030 if (CHECK_PROTOCOL_VERSION (2, 12)) {
8031 if (mono_class_is_gtd (klass))
8032 buffer_add_typeid (buf, domain, klass);
8033 else if (mono_class_is_ginst (klass))
8034 buffer_add_typeid (buf, domain, mono_class_get_generic_class (klass)->container_class);
8035 else
8036 buffer_add_id (buf, 0);
8038 if (CHECK_PROTOCOL_VERSION (2, 15)) {
8039 int count, i;
8041 if (mono_class_is_ginst (klass)) {
8042 MonoGenericInst *inst = mono_class_get_generic_class (klass)->context.class_inst;
8044 count = inst->type_argc;
8045 buffer_add_int (buf, count);
8046 for (i = 0; i < count; i++)
8047 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (inst->type_argv [i]));
8048 } else if (mono_class_is_gtd (klass)) {
8049 MonoGenericContainer *container = mono_class_get_generic_container (klass);
8050 MonoClass *pklass;
8052 count = container->type_argc;
8053 buffer_add_int (buf, count);
8054 for (i = 0; i < count; i++) {
8055 pklass = mono_class_create_generic_parameter (mono_generic_container_get_param (container, i));
8056 buffer_add_typeid (buf, domain, pklass);
8058 } else {
8059 buffer_add_int (buf, 0);
8062 break;
8064 case CMD_TYPE_GET_METHODS: {
8065 int nmethods;
8066 int i = 0;
8067 gpointer iter = NULL;
8068 MonoMethod *m;
8070 mono_class_setup_methods (klass);
8072 nmethods = mono_class_num_methods (klass);
8074 buffer_add_int (buf, nmethods);
8076 while ((m = mono_class_get_methods (klass, &iter))) {
8077 buffer_add_methodid (buf, domain, m);
8078 i ++;
8080 g_assert (i == nmethods);
8081 break;
8083 case CMD_TYPE_GET_FIELDS: {
8084 int nfields;
8085 int i = 0;
8086 gpointer iter = NULL;
8087 MonoClassField *f;
8089 nfields = mono_class_num_fields (klass);
8091 buffer_add_int (buf, nfields);
8093 while ((f = mono_class_get_fields_internal (klass, &iter))) {
8094 buffer_add_fieldid (buf, domain, f);
8095 buffer_add_string (buf, f->name);
8096 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (f->type));
8097 buffer_add_int (buf, f->type->attrs);
8098 i ++;
8100 g_assert (i == nfields);
8101 break;
8103 case CMD_TYPE_GET_PROPERTIES: {
8104 int nprops;
8105 int i = 0;
8106 gpointer iter = NULL;
8107 MonoProperty *p;
8109 nprops = mono_class_num_properties (klass);
8111 buffer_add_int (buf, nprops);
8113 while ((p = mono_class_get_properties (klass, &iter))) {
8114 buffer_add_propertyid (buf, domain, p);
8115 buffer_add_string (buf, p->name);
8116 buffer_add_methodid (buf, domain, p->get);
8117 buffer_add_methodid (buf, domain, p->set);
8118 buffer_add_int (buf, p->attrs);
8119 i ++;
8121 g_assert (i == nprops);
8122 break;
8124 case CMD_TYPE_GET_CATTRS: {
8125 MonoClass *attr_klass;
8126 MonoCustomAttrInfo *cinfo;
8128 attr_klass = decode_typeid (p, &p, end, NULL, &err);
8129 /* attr_klass can be NULL */
8130 if (err != ERR_NONE)
8131 goto exit;
8133 cinfo = mono_custom_attrs_from_class_checked (klass, error);
8134 if (!is_ok (error)) {
8135 mono_error_cleanup (error); /* FIXME don't swallow the error message */
8136 goto loader_error;
8139 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
8140 if (err != ERR_NONE)
8141 goto exit;
8142 break;
8144 case CMD_TYPE_GET_FIELD_CATTRS: {
8145 MonoClass *attr_klass;
8146 MonoCustomAttrInfo *cinfo;
8147 MonoClassField *field;
8149 field = decode_fieldid (p, &p, end, NULL, &err);
8150 if (err != ERR_NONE)
8151 goto exit;
8152 attr_klass = decode_typeid (p, &p, end, NULL, &err);
8153 if (err != ERR_NONE)
8154 goto exit;
8156 cinfo = mono_custom_attrs_from_field_checked (klass, field, error);
8157 if (!is_ok (error)) {
8158 mono_error_cleanup (error); /* FIXME don't swallow the error message */
8159 goto loader_error;
8162 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
8163 if (err != ERR_NONE)
8164 goto exit;
8165 break;
8167 case CMD_TYPE_GET_PROPERTY_CATTRS: {
8168 MonoClass *attr_klass;
8169 MonoCustomAttrInfo *cinfo;
8170 MonoProperty *prop;
8172 prop = decode_propertyid (p, &p, end, NULL, &err);
8173 if (err != ERR_NONE)
8174 goto exit;
8175 attr_klass = decode_typeid (p, &p, end, NULL, &err);
8176 if (err != ERR_NONE)
8177 goto exit;
8179 cinfo = mono_custom_attrs_from_property_checked (klass, prop, error);
8180 if (!is_ok (error)) {
8181 mono_error_cleanup (error); /* FIXME don't swallow the error message */
8182 goto loader_error;
8185 err = buffer_add_cattrs (buf, domain, m_class_get_image (klass), attr_klass, cinfo);
8186 if (err != ERR_NONE)
8187 goto exit;
8188 break;
8190 case CMD_TYPE_GET_VALUES:
8191 case CMD_TYPE_GET_VALUES_2: {
8192 guint8 *val;
8193 MonoClassField *f;
8194 MonoVTable *vtable;
8195 MonoClass *k;
8196 int len, i;
8197 gboolean found;
8198 MonoThread *thread_obj;
8199 MonoInternalThread *thread = NULL;
8200 guint32 special_static_type;
8202 if (command == CMD_TYPE_GET_VALUES_2) {
8203 int objid = decode_objid (p, &p, end);
8205 err = get_object (objid, (MonoObject**)&thread_obj);
8206 if (err != ERR_NONE)
8207 goto exit;
8209 thread = THREAD_TO_INTERNAL (thread_obj);
8212 len = decode_int (p, &p, end);
8213 for (i = 0; i < len; ++i) {
8214 f = decode_fieldid (p, &p, end, NULL, &err);
8215 if (err != ERR_NONE)
8216 goto exit;
8218 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
8219 goto invalid_fieldid;
8221 special_static_type = mono_class_field_get_special_static_type (f);
8222 if (special_static_type != SPECIAL_STATIC_NONE) {
8223 if (!(thread && special_static_type == SPECIAL_STATIC_THREAD))
8224 goto invalid_fieldid;
8227 /* Check that the field belongs to the object */
8228 found = FALSE;
8229 for (k = klass; k; k = m_class_get_parent (k)) {
8230 if (k == f->parent) {
8231 found = TRUE;
8232 break;
8235 if (!found)
8236 goto invalid_fieldid;
8238 vtable = mono_class_vtable_checked (domain, f->parent, error);
8239 goto_if_nok (error, invalid_fieldid);
8241 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
8242 mono_field_static_get_value_for_thread (thread ? thread : mono_thread_internal_current (), vtable, f, val, string_handle, error);
8243 goto_if_nok (error, invalid_fieldid);
8245 buffer_add_value (buf, f->type, val, domain);
8246 g_free (val);
8248 break;
8250 case CMD_TYPE_SET_VALUES: {
8251 guint8 *val;
8252 MonoClassField *f;
8253 MonoVTable *vtable;
8254 MonoClass *k;
8255 int len, i;
8256 gboolean found;
8258 len = decode_int (p, &p, end);
8259 for (i = 0; i < len; ++i) {
8260 f = decode_fieldid (p, &p, end, NULL, &err);
8261 if (err != ERR_NONE)
8262 goto exit;
8264 if (!(f->type->attrs & FIELD_ATTRIBUTE_STATIC))
8265 goto invalid_fieldid;
8267 if (mono_class_field_is_special_static (f))
8268 goto invalid_fieldid;
8270 /* Check that the field belongs to the object */
8271 found = FALSE;
8272 for (k = klass; k; k = m_class_get_parent (k)) {
8273 if (k == f->parent) {
8274 found = TRUE;
8275 break;
8278 if (!found)
8279 goto invalid_fieldid;
8281 // FIXME: Check for literal/const
8283 vtable = mono_class_vtable_checked (domain, f->parent, error);
8284 goto_if_nok (error, invalid_fieldid);
8286 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
8287 err = decode_value (f->type, domain, val, p, &p, end, TRUE);
8288 if (err != ERR_NONE) {
8289 g_free (val);
8290 goto exit;
8292 if (MONO_TYPE_IS_REFERENCE (f->type))
8293 mono_field_static_set_value_internal (vtable, f, *(gpointer*)val);
8294 else
8295 mono_field_static_set_value_internal (vtable, f, val);
8296 g_free (val);
8298 break;
8300 case CMD_TYPE_GET_OBJECT: {
8301 MonoObject *o = (MonoObject*)mono_type_get_object_checked (domain, m_class_get_byval_arg (klass), error);
8302 if (!is_ok (error)) {
8303 mono_error_cleanup (error);
8304 goto invalid_object;
8306 buffer_add_objid (buf, o);
8307 break;
8309 case CMD_TYPE_GET_SOURCE_FILES:
8310 case CMD_TYPE_GET_SOURCE_FILES_2: {
8311 char *source_file, *base;
8312 GPtrArray *files;
8313 int i;
8315 files = get_source_files_for_type (klass);
8317 buffer_add_int (buf, files->len);
8318 for (i = 0; i < files->len; ++i) {
8319 source_file = (char *)g_ptr_array_index (files, i);
8320 if (command == CMD_TYPE_GET_SOURCE_FILES_2) {
8321 buffer_add_string (buf, source_file);
8322 } else {
8323 base = dbg_path_get_basename (source_file);
8324 buffer_add_string (buf, base);
8325 g_free (base);
8327 g_free (source_file);
8329 g_ptr_array_free (files, TRUE);
8330 break;
8332 case CMD_TYPE_IS_ASSIGNABLE_FROM: {
8333 MonoClass *oklass = decode_typeid (p, &p, end, NULL, &err);
8335 if (err != ERR_NONE)
8336 goto exit;
8337 if (mono_class_is_assignable_from_internal (klass, oklass))
8338 buffer_add_byte (buf, 1);
8339 else
8340 buffer_add_byte (buf, 0);
8341 break;
8343 case CMD_TYPE_GET_METHODS_BY_NAME_FLAGS: {
8344 char *name = decode_string (p, &p, end);
8345 int i, flags = decode_int (p, &p, end);
8346 int mlisttype;
8347 if (CHECK_PROTOCOL_VERSION (2, 48))
8348 mlisttype = decode_int (p, &p, end);
8349 else
8350 mlisttype = 0; // MLISTTYPE_All
8351 ERROR_DECL (error);
8352 GPtrArray *array;
8354 error_init (error);
8355 array = mono_class_get_methods_by_name (klass, name, flags & ~BINDING_FLAGS_IGNORE_CASE, mlisttype, TRUE, error);
8356 if (!is_ok (error)) {
8357 mono_error_cleanup (error);
8358 goto loader_error;
8360 buffer_add_int (buf, array->len);
8361 for (i = 0; i < array->len; ++i) {
8362 MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, i);
8363 buffer_add_methodid (buf, domain, method);
8366 g_ptr_array_free (array, TRUE);
8367 g_free (name);
8368 break;
8370 case CMD_TYPE_GET_INTERFACES: {
8371 MonoClass *parent;
8372 GHashTable *iface_hash = g_hash_table_new (NULL, NULL);
8373 MonoClass *tclass, *iface;
8374 GHashTableIter iter;
8376 tclass = klass;
8378 for (parent = tclass; parent; parent = m_class_get_parent (parent)) {
8379 mono_class_setup_interfaces (parent, error);
8380 goto_if_nok (error, loader_error);
8382 collect_interfaces (parent, iface_hash, error);
8383 goto_if_nok (error, loader_error);
8386 buffer_add_int (buf, g_hash_table_size (iface_hash));
8388 g_hash_table_iter_init (&iter, iface_hash);
8389 while (g_hash_table_iter_next (&iter, NULL, (void**)&iface))
8390 buffer_add_typeid (buf, domain, iface);
8391 g_hash_table_destroy (iface_hash);
8392 break;
8394 case CMD_TYPE_GET_INTERFACE_MAP: {
8395 int tindex, ioffset;
8396 gboolean variance_used;
8397 MonoClass *iclass;
8398 int len, nmethods, i;
8399 gpointer iter;
8400 MonoMethod *method;
8402 len = decode_int (p, &p, end);
8403 mono_class_setup_vtable (klass);
8405 for (tindex = 0; tindex < len; ++tindex) {
8406 iclass = decode_typeid (p, &p, end, NULL, &err);
8407 if (err != ERR_NONE)
8408 goto exit;
8410 ioffset = mono_class_interface_offset_with_variance (klass, iclass, &variance_used);
8411 if (ioffset == -1)
8412 goto invalid_argument;
8414 nmethods = mono_class_num_methods (iclass);
8415 buffer_add_int (buf, nmethods);
8417 iter = NULL;
8418 while ((method = mono_class_get_methods (iclass, &iter))) {
8419 buffer_add_methodid (buf, domain, method);
8421 MonoMethod **klass_vtable = m_class_get_vtable (klass);
8422 for (i = 0; i < nmethods; ++i)
8423 buffer_add_methodid (buf, domain, klass_vtable [i + ioffset]);
8425 break;
8427 case CMD_TYPE_IS_INITIALIZED: {
8428 MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error);
8429 goto_if_nok (error, loader_error);
8431 if (vtable)
8432 buffer_add_int (buf, (vtable->initialized || vtable->init_failed) ? 1 : 0);
8433 else
8434 buffer_add_int (buf, 0);
8435 break;
8437 case CMD_TYPE_CREATE_INSTANCE: {
8438 ERROR_DECL (error);
8439 MonoObject *obj;
8441 obj = mono_object_new_checked (domain, klass, error);
8442 mono_error_assert_ok (error);
8443 buffer_add_objid (buf, obj);
8444 break;
8446 case CMD_TYPE_GET_VALUE_SIZE: {
8447 int32_t value_size;
8449 value_size = mono_class_value_size (klass, NULL);
8450 buffer_add_int (buf, value_size);
8451 break;
8453 default:
8454 err = ERR_NOT_IMPLEMENTED;
8455 goto exit;
8458 err = ERR_NONE;
8459 goto exit;
8460 invalid_argument:
8461 err = ERR_INVALID_ARGUMENT;
8462 goto exit;
8463 invalid_fieldid:
8464 err = ERR_INVALID_FIELDID;
8465 goto exit;
8466 invalid_object:
8467 err = ERR_INVALID_OBJECT;
8468 goto exit;
8469 loader_error:
8470 err = ERR_LOADER_ERROR;
8471 goto exit;
8472 exit:
8473 HANDLE_FUNCTION_RETURN_VAL (err);
8476 static ErrorCode
8477 type_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8479 MonoClass *klass;
8480 MonoDomain *old_domain;
8481 MonoDomain *domain;
8482 ErrorCode err;
8484 klass = decode_typeid (p, &p, end, &domain, &err);
8485 if (err != ERR_NONE)
8486 return err;
8488 old_domain = mono_domain_get ();
8490 mono_domain_set_fast (domain, TRUE);
8492 err = type_commands_internal (command, klass, domain, p, end, buf);
8494 mono_domain_set_fast (old_domain, TRUE);
8496 return err;
8499 static ErrorCode
8500 method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, guint8 *p, guint8 *end, Buffer *buf)
8502 MonoMethodHeader *header;
8503 ErrorCode err;
8505 switch (command) {
8506 case CMD_METHOD_GET_NAME: {
8507 buffer_add_string (buf, method->name);
8508 break;
8510 case CMD_METHOD_GET_DECLARING_TYPE: {
8511 buffer_add_typeid (buf, domain, method->klass);
8512 break;
8514 case CMD_METHOD_GET_DEBUG_INFO: {
8515 ERROR_DECL (error);
8516 MonoDebugMethodInfo *minfo;
8517 char *source_file;
8518 int i, j, n_il_offsets;
8519 int *source_files;
8520 GPtrArray *source_file_list;
8521 MonoSymSeqPoint *sym_seq_points;
8523 header = mono_method_get_header_checked (method, error);
8524 if (!header) {
8525 mono_error_cleanup (error); /* FIXME don't swallow the error */
8526 buffer_add_int (buf, 0);
8527 buffer_add_string (buf, "");
8528 buffer_add_int (buf, 0);
8529 break;
8532 minfo = mono_debug_lookup_method (method);
8533 if (!minfo) {
8534 buffer_add_int (buf, header->code_size);
8535 buffer_add_string (buf, "");
8536 buffer_add_int (buf, 0);
8537 mono_metadata_free_mh (header);
8538 break;
8541 mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
8542 buffer_add_int (buf, header->code_size);
8543 if (CHECK_PROTOCOL_VERSION (2, 13)) {
8544 buffer_add_int (buf, source_file_list->len);
8545 for (i = 0; i < source_file_list->len; ++i) {
8546 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
8547 buffer_add_string (buf, sinfo->source_file);
8548 if (CHECK_PROTOCOL_VERSION (2, 14)) {
8549 for (j = 0; j < 16; ++j)
8550 buffer_add_byte (buf, sinfo->hash [j]);
8553 } else {
8554 buffer_add_string (buf, source_file);
8556 buffer_add_int (buf, n_il_offsets);
8557 DEBUG_PRINTF (10, "Line number table for method %s:\n", mono_method_full_name (method, TRUE));
8558 for (i = 0; i < n_il_offsets; ++i) {
8559 MonoSymSeqPoint *sp = &sym_seq_points [i];
8560 const char *srcfile = "";
8562 if (source_files [i] != -1) {
8563 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
8564 srcfile = sinfo->source_file;
8566 DEBUG_PRINTF (10, "IL%x -> %s:%d %d %d %d\n", sp->il_offset, srcfile, sp->line, sp->column, sp->end_line, sp->end_column);
8567 buffer_add_int (buf, sp->il_offset);
8568 buffer_add_int (buf, sp->line);
8569 if (CHECK_PROTOCOL_VERSION (2, 13))
8570 buffer_add_int (buf, source_files [i]);
8571 if (CHECK_PROTOCOL_VERSION (2, 19))
8572 buffer_add_int (buf, sp->column);
8573 if (CHECK_PROTOCOL_VERSION (2, 32)) {
8574 buffer_add_int (buf, sp->end_line);
8575 buffer_add_int (buf, sp->end_column);
8578 g_free (source_file);
8579 g_free (source_files);
8580 g_free (sym_seq_points);
8581 g_ptr_array_free (source_file_list, TRUE);
8582 mono_metadata_free_mh (header);
8583 break;
8585 case CMD_METHOD_GET_PARAM_INFO: {
8586 MonoMethodSignature *sig = mono_method_signature_internal (method);
8587 guint32 i;
8588 char **names;
8590 /* FIXME: mono_class_from_mono_type_internal () and byrefs */
8592 /* FIXME: Use a smaller encoding */
8593 buffer_add_int (buf, sig->call_convention);
8594 buffer_add_int (buf, sig->param_count);
8595 buffer_add_int (buf, sig->generic_param_count);
8596 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (sig->ret));
8597 for (i = 0; i < sig->param_count; ++i) {
8598 /* FIXME: vararg */
8599 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (sig->params [i]));
8602 /* Emit parameter names */
8603 names = g_new (char *, sig->param_count);
8604 mono_method_get_param_names (method, (const char **) names);
8605 for (i = 0; i < sig->param_count; ++i)
8606 buffer_add_string (buf, names [i]);
8607 g_free (names);
8609 break;
8611 case CMD_METHOD_GET_LOCALS_INFO: {
8612 ERROR_DECL (error);
8613 int i, num_locals;
8614 MonoDebugLocalsInfo *locals;
8615 int *locals_map = NULL;
8617 header = mono_method_get_header_checked (method, error);
8618 if (!header) {
8619 add_error_string (buf, mono_error_get_message (error));
8620 mono_error_cleanup (error); /* FIXME don't swallow the error */
8621 return ERR_INVALID_ARGUMENT;
8624 locals = mono_debug_lookup_locals (method);
8625 if (!locals) {
8626 if (CHECK_PROTOCOL_VERSION (2, 43)) {
8627 /* Scopes */
8628 buffer_add_int (buf, 1);
8629 buffer_add_int (buf, 0);
8630 buffer_add_int (buf, header->code_size);
8632 buffer_add_int (buf, header->num_locals);
8633 /* Types */
8634 for (i = 0; i < header->num_locals; ++i) {
8635 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (header->locals [i]));
8637 /* Names */
8638 for (i = 0; i < header->num_locals; ++i) {
8639 char lname [128];
8640 sprintf (lname, "V_%d", i);
8641 buffer_add_string (buf, lname);
8643 /* Scopes */
8644 for (i = 0; i < header->num_locals; ++i) {
8645 buffer_add_int (buf, 0);
8646 buffer_add_int (buf, header->code_size);
8648 } else {
8649 if (CHECK_PROTOCOL_VERSION (2, 43)) {
8650 /* Scopes */
8651 buffer_add_int (buf, locals->num_blocks);
8652 int last_start = 0;
8653 for (i = 0; i < locals->num_blocks; ++i) {
8654 buffer_add_int (buf, locals->code_blocks [i].start_offset - last_start);
8655 buffer_add_int (buf, locals->code_blocks [i].end_offset - locals->code_blocks [i].start_offset);
8656 last_start = locals->code_blocks [i].start_offset;
8660 num_locals = locals->num_locals;
8661 buffer_add_int (buf, num_locals);
8663 /* Types */
8664 for (i = 0; i < num_locals; ++i) {
8665 g_assert (locals->locals [i].index < header->num_locals);
8666 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (header->locals [locals->locals [i].index]));
8668 /* Names */
8669 for (i = 0; i < num_locals; ++i)
8670 buffer_add_string (buf, locals->locals [i].name);
8671 /* Scopes */
8672 for (i = 0; i < num_locals; ++i) {
8673 if (locals->locals [i].block) {
8674 buffer_add_int (buf, locals->locals [i].block->start_offset);
8675 buffer_add_int (buf, locals->locals [i].block->end_offset);
8676 } else {
8677 buffer_add_int (buf, 0);
8678 buffer_add_int (buf, header->code_size);
8682 mono_metadata_free_mh (header);
8684 if (locals)
8685 mono_debug_free_locals (locals);
8686 g_free (locals_map);
8688 break;
8690 case CMD_METHOD_GET_INFO:
8691 buffer_add_int (buf, method->flags);
8692 buffer_add_int (buf, method->iflags);
8693 buffer_add_int (buf, method->token);
8694 if (CHECK_PROTOCOL_VERSION (2, 12)) {
8695 guint8 attrs = 0;
8696 if (method->is_generic)
8697 attrs |= (1 << 0);
8698 if (mono_method_signature_internal (method)->generic_param_count)
8699 attrs |= (1 << 1);
8700 buffer_add_byte (buf, attrs);
8701 if (method->is_generic || method->is_inflated) {
8702 MonoMethod *result;
8704 if (method->is_generic) {
8705 result = method;
8706 } else {
8707 MonoMethodInflated *imethod = (MonoMethodInflated *)method;
8709 result = imethod->declaring;
8710 if (imethod->context.class_inst) {
8711 MonoClass *klass = ((MonoMethod *) imethod)->klass;
8712 /*Generic methods gets the context of the GTD.*/
8713 if (mono_class_get_context (klass)) {
8714 ERROR_DECL (error);
8715 result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error);
8716 if (!is_ok (error)) {
8717 add_error_string (buf, mono_error_get_message (error));
8718 mono_error_cleanup (error);
8719 return ERR_INVALID_ARGUMENT;
8725 buffer_add_methodid (buf, domain, result);
8726 } else {
8727 buffer_add_id (buf, 0);
8729 if (CHECK_PROTOCOL_VERSION (2, 15)) {
8730 if (mono_method_signature_internal (method)->generic_param_count) {
8731 int count, i;
8733 if (method->is_inflated) {
8734 MonoGenericInst *inst = mono_method_get_context (method)->method_inst;
8735 if (inst) {
8736 count = inst->type_argc;
8737 buffer_add_int (buf, count);
8739 for (i = 0; i < count; i++)
8740 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal (inst->type_argv [i]));
8741 } else {
8742 buffer_add_int (buf, 0);
8744 } else if (method->is_generic) {
8745 MonoGenericContainer *container = mono_method_get_generic_container (method);
8747 count = mono_method_signature_internal (method)->generic_param_count;
8748 buffer_add_int (buf, count);
8749 for (i = 0; i < count; i++) {
8750 MonoGenericParam *param = mono_generic_container_get_param (container, i);
8751 MonoClass *pklass = mono_class_create_generic_parameter (param);
8752 buffer_add_typeid (buf, domain, pklass);
8754 } else {
8755 buffer_add_int (buf, 0);
8757 } else {
8758 buffer_add_int (buf, 0);
8762 break;
8763 case CMD_METHOD_GET_BODY: {
8764 ERROR_DECL (error);
8765 int i;
8767 header = mono_method_get_header_checked (method, error);
8768 if (!header) {
8769 mono_error_cleanup (error); /* FIXME don't swallow the error */
8770 buffer_add_int (buf, 0);
8772 if (CHECK_PROTOCOL_VERSION (2, 18))
8773 buffer_add_int (buf, 0);
8774 } else {
8775 buffer_add_int (buf, header->code_size);
8776 for (i = 0; i < header->code_size; ++i)
8777 buffer_add_byte (buf, header->code [i]);
8779 if (CHECK_PROTOCOL_VERSION (2, 18)) {
8780 buffer_add_int (buf, header->num_clauses);
8781 for (i = 0; i < header->num_clauses; ++i) {
8782 MonoExceptionClause *clause = &header->clauses [i];
8784 buffer_add_int (buf, clause->flags);
8785 buffer_add_int (buf, clause->try_offset);
8786 buffer_add_int (buf, clause->try_len);
8787 buffer_add_int (buf, clause->handler_offset);
8788 buffer_add_int (buf, clause->handler_len);
8789 if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
8790 buffer_add_typeid (buf, domain, clause->data.catch_class);
8791 else if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
8792 buffer_add_int (buf, clause->data.filter_offset);
8796 mono_metadata_free_mh (header);
8799 break;
8801 case CMD_METHOD_RESOLVE_TOKEN: {
8802 guint32 token = decode_int (p, &p, end);
8804 // FIXME: Generics
8805 switch (mono_metadata_token_code (token)) {
8806 case MONO_TOKEN_STRING: {
8807 ERROR_DECL (error);
8808 MonoString *s;
8809 char *s2;
8811 s = mono_ldstr_checked (domain, m_class_get_image (method->klass), mono_metadata_token_index (token), error);
8812 mono_error_assert_ok (error); /* FIXME don't swallow the error */
8814 s2 = mono_string_to_utf8_checked_internal (s, error);
8815 mono_error_assert_ok (error);
8817 buffer_add_byte (buf, TOKEN_TYPE_STRING);
8818 buffer_add_string (buf, s2);
8819 g_free (s2);
8820 break;
8822 default: {
8823 ERROR_DECL (error);
8824 gpointer val;
8825 MonoClass *handle_class;
8827 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8828 val = mono_method_get_wrapper_data (method, token);
8829 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, token + 1);
8831 if (handle_class == NULL) {
8832 // Can't figure out the token type
8833 buffer_add_byte (buf, TOKEN_TYPE_UNKNOWN);
8834 break;
8836 } else {
8837 val = mono_ldtoken_checked (m_class_get_image (method->klass), token, &handle_class, NULL, error);
8838 if (!val)
8839 g_error ("Could not load token due to %s", mono_error_get_message (error));
8842 if (handle_class == mono_defaults.typehandle_class) {
8843 buffer_add_byte (buf, TOKEN_TYPE_TYPE);
8844 if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
8845 buffer_add_typeid (buf, domain, (MonoClass *) val);
8846 else
8847 buffer_add_typeid (buf, domain, mono_class_from_mono_type_internal ((MonoType*)val));
8848 } else if (handle_class == mono_defaults.fieldhandle_class) {
8849 buffer_add_byte (buf, TOKEN_TYPE_FIELD);
8850 buffer_add_fieldid (buf, domain, (MonoClassField *)val);
8851 } else if (handle_class == mono_defaults.methodhandle_class) {
8852 buffer_add_byte (buf, TOKEN_TYPE_METHOD);
8853 buffer_add_methodid (buf, domain, (MonoMethod *)val);
8854 } else if (handle_class == mono_defaults.string_class) {
8855 char *s;
8857 s = mono_string_to_utf8_checked_internal ((MonoString *)val, error);
8858 if (!is_ok (error)) {
8859 add_error_string (buf, mono_error_get_message (error));
8860 mono_error_cleanup (error);
8861 g_free (s);
8862 return ERR_INVALID_ARGUMENT;
8864 buffer_add_byte (buf, TOKEN_TYPE_STRING);
8865 buffer_add_string (buf, s);
8866 g_free (s);
8867 } else {
8868 g_assert_not_reached ();
8870 break;
8873 break;
8875 case CMD_METHOD_GET_CATTRS: {
8876 ERROR_DECL (error);
8877 MonoClass *attr_klass;
8878 MonoCustomAttrInfo *cinfo;
8880 attr_klass = decode_typeid (p, &p, end, NULL, &err);
8881 /* attr_klass can be NULL */
8882 if (err != ERR_NONE)
8883 return err;
8885 cinfo = mono_custom_attrs_from_method_checked (method, error);
8886 if (!is_ok (error)) {
8887 mono_error_cleanup (error); /* FIXME don't swallow the error message */
8888 return ERR_LOADER_ERROR;
8891 err = buffer_add_cattrs (buf, domain, m_class_get_image (method->klass), attr_klass, cinfo);
8892 if (err != ERR_NONE)
8893 return err;
8894 break;
8896 case CMD_METHOD_MAKE_GENERIC_METHOD: {
8897 ERROR_DECL (error);
8898 MonoType **type_argv;
8899 int i, type_argc;
8900 MonoDomain *d;
8901 MonoClass *klass;
8902 MonoGenericInst *ginst;
8903 MonoGenericContext tmp_context;
8904 MonoMethod *inflated;
8906 type_argc = decode_int (p, &p, end);
8907 type_argv = g_new0 (MonoType*, type_argc);
8908 for (i = 0; i < type_argc; ++i) {
8909 klass = decode_typeid (p, &p, end, &d, &err);
8910 if (err != ERR_NONE) {
8911 g_free (type_argv);
8912 return err;
8914 if (domain != d) {
8915 g_free (type_argv);
8916 return ERR_INVALID_ARGUMENT;
8918 type_argv [i] = m_class_get_byval_arg (klass);
8920 ginst = mono_metadata_get_generic_inst (type_argc, type_argv);
8921 g_free (type_argv);
8922 tmp_context.class_inst = mono_class_is_ginst (method->klass) ? mono_class_get_generic_class (method->klass)->context.class_inst : NULL;
8923 tmp_context.method_inst = ginst;
8925 inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error);
8926 if (!is_ok (error)) {
8927 add_error_string (buf, mono_error_get_message (error));
8928 mono_error_cleanup (error);
8929 return ERR_INVALID_ARGUMENT;
8931 if (!mono_verifier_is_method_valid_generic_instantiation (inflated))
8932 return ERR_INVALID_ARGUMENT;
8933 buffer_add_methodid (buf, domain, inflated);
8934 break;
8936 default:
8937 return ERR_NOT_IMPLEMENTED;
8940 return ERR_NONE;
8943 static ErrorCode
8944 method_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8946 ErrorCode err;
8947 MonoDomain *old_domain;
8948 MonoDomain *domain;
8949 MonoMethod *method;
8951 method = decode_methodid (p, &p, end, &domain, &err);
8952 if (err != ERR_NONE)
8953 return err;
8955 old_domain = mono_domain_get ();
8957 mono_domain_set_fast (domain, TRUE);
8959 err = method_commands_internal (command, method, domain, p, end, buf);
8961 mono_domain_set_fast (old_domain, TRUE);
8963 return err;
8966 static ErrorCode
8967 thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
8969 int objid = decode_objid (p, &p, end);
8970 ErrorCode err;
8971 MonoThread *thread_obj;
8972 MonoInternalThread *thread;
8974 err = get_object (objid, (MonoObject**)&thread_obj);
8975 if (err != ERR_NONE)
8976 return err;
8978 thread = THREAD_TO_INTERNAL (thread_obj);
8980 switch (command) {
8981 case CMD_THREAD_GET_NAME: {
8982 char *s = mono_thread_get_name_utf8 (thread_obj);
8984 if (!s) {
8985 buffer_add_int (buf, 0);
8986 } else {
8987 const size_t len = strlen (s);
8988 buffer_add_int (buf, len);
8989 buffer_add_data (buf, (guint8*)s, len);
8990 g_free (s);
8992 break;
8994 case CMD_THREAD_GET_FRAME_INFO: {
8995 DebuggerTlsData *tls;
8996 int i, start_frame, length;
8998 // Wait for suspending if it already started
8999 // FIXME: Races with suspend_count
9000 while (!is_suspended ()) {
9001 if (suspend_count)
9002 wait_for_suspend ();
9005 if (suspend_count)
9006 wait_for_suspend ();
9007 if (!is_suspended ())
9008 return ERR_NOT_SUSPENDED;
9011 start_frame = decode_int (p, &p, end);
9012 length = decode_int (p, &p, end);
9014 if (start_frame != 0 || length != -1)
9015 return ERR_NOT_IMPLEMENTED;
9017 mono_loader_lock ();
9018 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
9019 mono_loader_unlock ();
9020 if (tls == NULL)
9021 return ERR_UNLOADED;
9023 compute_frame_info (thread, tls, TRUE); //the last parameter is TRUE to force that the frame info that will be send is synchronised with the debugged thread
9025 buffer_add_int (buf, tls->frame_count);
9026 for (i = 0; i < tls->frame_count; ++i) {
9027 buffer_add_int (buf, tls->frames [i]->id);
9028 buffer_add_methodid (buf, tls->frames [i]->de.domain, tls->frames [i]->actual_method);
9029 buffer_add_int (buf, tls->frames [i]->il_offset);
9031 * Instead of passing the frame type directly to the client, we associate
9032 * it with the previous frame using a set of flags. This avoids lots of
9033 * conditional code in the client, since a frame whose type isn't
9034 * FRAME_TYPE_MANAGED has no method, location, etc.
9036 buffer_add_byte (buf, tls->frames [i]->flags);
9039 break;
9041 case CMD_THREAD_GET_STATE:
9042 buffer_add_int (buf, thread->state);
9043 break;
9044 case CMD_THREAD_GET_INFO:
9045 buffer_add_byte (buf, thread->threadpool_thread);
9046 break;
9047 case CMD_THREAD_GET_ID:
9048 buffer_add_long (buf, (guint64)(gsize)thread);
9049 break;
9050 case CMD_THREAD_GET_TID:
9051 buffer_add_long (buf, (guint64)thread->tid);
9052 break;
9053 case CMD_THREAD_SET_IP: {
9054 DebuggerTlsData *tls;
9055 MonoMethod *method;
9056 MonoDomain *domain;
9057 MonoSeqPointInfo *seq_points;
9058 SeqPoint sp;
9059 gboolean found_sp;
9060 gint64 il_offset;
9062 method = decode_methodid (p, &p, end, &domain, &err);
9063 if (err != ERR_NONE)
9064 return err;
9065 il_offset = decode_long (p, &p, end);
9067 while (!is_suspended ()) {
9068 if (suspend_count)
9069 wait_for_suspend ();
9072 mono_loader_lock ();
9073 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
9074 mono_loader_unlock ();
9075 g_assert (tls);
9077 compute_frame_info (thread, tls, FALSE);
9078 if (tls->frame_count == 0 || tls->frames [0]->actual_method != method)
9079 return ERR_INVALID_ARGUMENT;
9081 found_sp = mono_find_seq_point (domain, method, il_offset, &seq_points, &sp);
9083 g_assert (seq_points);
9085 if (!found_sp)
9086 return ERR_INVALID_ARGUMENT;
9088 // FIXME: Check that the ip change is safe
9090 DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset);
9092 if (tls->frames [0]->de.ji->is_interp) {
9093 MonoJitTlsData *jit_data = thread->thread_info->jit_data;
9094 mini_get_interp_callbacks ()->set_resume_state (jit_data, NULL, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->de.ji->code_start + sp.native_offset);
9095 } else {
9096 MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->de.ji->code_start + sp.native_offset);
9098 break;
9100 case CMD_THREAD_ELAPSED_TIME: {
9101 DebuggerTlsData *tls;
9102 mono_loader_lock ();
9103 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
9104 mono_loader_unlock ();
9105 g_assert (tls);
9106 buffer_add_long (buf, (long)mono_stopwatch_elapsed_ms (&tls->step_time));
9107 break;
9109 default:
9110 return ERR_NOT_IMPLEMENTED;
9113 return ERR_NONE;
9116 static ErrorCode
9117 frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9119 int objid;
9120 ErrorCode err;
9121 MonoThread *thread_obj;
9122 MonoInternalThread *thread;
9123 int pos, i, len, frame_idx;
9124 DebuggerTlsData *tls;
9125 StackFrame *frame;
9126 MonoDebugMethodJitInfo *jit;
9127 MonoMethodSignature *sig;
9128 gssize id;
9129 MonoMethodHeader *header;
9131 objid = decode_objid (p, &p, end);
9132 err = get_object (objid, (MonoObject**)&thread_obj);
9133 if (err != ERR_NONE)
9134 return err;
9136 thread = THREAD_TO_INTERNAL (thread_obj);
9138 id = decode_id (p, &p, end);
9140 mono_loader_lock ();
9141 tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread);
9142 mono_loader_unlock ();
9143 g_assert (tls);
9145 for (i = 0; i < tls->frame_count; ++i) {
9146 if (tls->frames [i]->id == id)
9147 break;
9149 if (i == tls->frame_count)
9150 return ERR_INVALID_FRAMEID;
9152 /* The thread is still running native code, can't get frame variables info */
9153 if (!tls->really_suspended && !tls->async_state.valid)
9154 return ERR_NOT_SUSPENDED;
9155 frame_idx = i;
9156 frame = tls->frames [frame_idx];
9158 /* This is supported for frames without has_ctx etc. set */
9159 if (command == CMD_STACK_FRAME_GET_DOMAIN) {
9160 if (CHECK_PROTOCOL_VERSION (2, 38))
9161 buffer_add_domainid (buf, frame->de.domain);
9162 return ERR_NONE;
9165 if (!frame->has_ctx)
9166 return ERR_ABSENT_INFORMATION;
9168 if (!ensure_jit ((DbgEngineStackFrame*)frame))
9169 return ERR_ABSENT_INFORMATION;
9171 jit = frame->jit;
9173 sig = mono_method_signature_internal (frame->actual_method);
9175 if (!(jit->has_var_info || frame->de.ji->is_interp) || !mono_get_seq_points (frame->de.domain, frame->actual_method))
9177 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
9179 return ERR_ABSENT_INFORMATION;
9181 switch (command) {
9182 case CMD_STACK_FRAME_GET_VALUES: {
9183 ERROR_DECL (error);
9184 len = decode_int (p, &p, end);
9185 header = mono_method_get_header_checked (frame->actual_method, error);
9186 mono_error_assert_ok (error); /* FIXME report error */
9188 for (i = 0; i < len; ++i) {
9189 pos = decode_int (p, &p, end);
9191 if (pos < 0) {
9192 pos = - pos - 1;
9194 DEBUG_PRINTF (4, "[dbg] send arg %d.\n", pos);
9196 if (frame->de.ji->is_interp) {
9197 guint8 *addr;
9199 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos);
9201 buffer_add_value_full (buf, sig->params [pos], addr, frame->de.domain, FALSE, NULL, 1);
9202 } else {
9203 g_assert (pos >= 0 && pos < jit->num_params);
9205 add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->de.domain, FALSE);
9207 } else {
9208 MonoDebugLocalsInfo *locals;
9210 locals = mono_debug_lookup_locals (frame->de.method);
9211 if (locals) {
9212 g_assert (pos < locals->num_locals);
9213 pos = locals->locals [pos].index;
9214 mono_debug_free_locals (locals);
9217 DEBUG_PRINTF (4, "[dbg] send local %d.\n", pos);
9219 if (frame->de.ji->is_interp) {
9220 guint8 *addr;
9222 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos);
9224 buffer_add_value_full (buf, header->locals [pos], addr, frame->de.domain, FALSE, NULL, 1);
9225 } else {
9226 g_assert (pos >= 0 && pos < jit->num_locals);
9228 add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->de.domain, FALSE);
9232 mono_metadata_free_mh (header);
9233 break;
9235 case CMD_STACK_FRAME_GET_THIS: {
9236 if (frame->de.method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
9237 return ERR_ABSENT_INFORMATION;
9238 if (m_class_is_valuetype (frame->api_method->klass)) {
9239 if (!sig->hasthis) {
9240 MonoObject *p = NULL;
9241 buffer_add_value (buf, mono_get_object_type (), &p, frame->de.domain);
9242 } else {
9243 if (frame->de.ji->is_interp) {
9244 guint8 *addr;
9246 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
9248 buffer_add_value_full (buf, m_class_get_this_arg (frame->actual_method->klass), addr, frame->de.domain, FALSE, NULL, 1);
9249 } else {
9250 add_var (buf, jit, m_class_get_this_arg (frame->actual_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
9253 } else {
9254 if (!sig->hasthis) {
9255 MonoObject *p = NULL;
9256 buffer_add_value (buf, m_class_get_byval_arg (frame->actual_method->klass), &p, frame->de.domain);
9257 } else {
9258 if (frame->de.ji->is_interp) {
9259 guint8 *addr;
9261 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
9263 buffer_add_value_full (buf, m_class_get_byval_arg (frame->api_method->klass), addr, frame->de.domain, FALSE, NULL, 1);
9264 } else {
9265 add_var (buf, jit, m_class_get_byval_arg (frame->api_method->klass), jit->this_var, &frame->ctx, frame->de.domain, TRUE);
9269 break;
9271 case CMD_STACK_FRAME_SET_VALUES: {
9272 ERROR_DECL (error);
9273 guint8 *val_buf;
9274 MonoType *t;
9275 MonoDebugVarInfo *var = NULL;
9276 gboolean is_arg = FALSE;
9278 len = decode_int (p, &p, end);
9279 header = mono_method_get_header_checked (frame->actual_method, error);
9280 mono_error_assert_ok (error); /* FIXME report error */
9282 for (i = 0; i < len; ++i) {
9283 pos = decode_int (p, &p, end);
9285 if (pos < 0) {
9286 pos = - pos - 1;
9288 g_assert (pos >= 0 && pos < jit->num_params);
9290 t = sig->params [pos];
9291 var = &jit->params [pos];
9292 is_arg = TRUE;
9293 } else {
9294 MonoDebugLocalsInfo *locals;
9296 locals = mono_debug_lookup_locals (frame->de.method);
9297 if (locals) {
9298 g_assert (pos < locals->num_locals);
9299 pos = locals->locals [pos].index;
9300 mono_debug_free_locals (locals);
9302 g_assert (pos >= 0 && pos < jit->num_locals);
9304 t = header->locals [pos];
9305 var = &jit->locals [pos];
9308 if (MONO_TYPE_IS_REFERENCE (t))
9309 val_buf = (guint8 *)g_alloca (sizeof (MonoObject*));
9310 else
9311 val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (t)));
9312 err = decode_value (t, frame->de.domain, val_buf, p, &p, end, TRUE);
9313 if (err != ERR_NONE)
9314 return err;
9316 if (frame->de.ji->is_interp) {
9317 guint8 *addr;
9319 if (is_arg)
9320 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_arg (frame->interp_frame, pos);
9321 else
9322 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_local (frame->interp_frame, pos);
9323 set_interp_var (t, addr, val_buf);
9324 } else {
9325 set_var (t, var, &frame->ctx, frame->de.domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
9328 mono_metadata_free_mh (header);
9329 break;
9331 case CMD_STACK_FRAME_GET_DOMAIN: {
9332 if (CHECK_PROTOCOL_VERSION (2, 38))
9333 buffer_add_domainid (buf, frame->de.domain);
9334 break;
9336 case CMD_STACK_FRAME_SET_THIS: {
9337 guint8 *val_buf;
9338 MonoType *t;
9339 MonoDebugVarInfo *var;
9341 t = m_class_get_byval_arg (frame->actual_method->klass);
9342 /* Checked by the sender */
9343 g_assert (MONO_TYPE_ISSTRUCT (t));
9345 val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type_internal (t)));
9346 err = decode_value (t, frame->de.domain, val_buf, p, &p, end, TRUE);
9347 if (err != ERR_NONE)
9348 return err;
9350 if (frame->de.ji->is_interp) {
9351 guint8 *addr;
9353 addr = (guint8*)mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);
9354 set_interp_var (m_class_get_this_arg (frame->actual_method->klass), addr, val_buf);
9355 } else {
9356 var = jit->this_var;
9357 if (!var) {
9358 add_error_string (buf, "Invalid this object");
9359 return ERR_INVALID_ARGUMENT;
9362 set_var (m_class_get_this_arg (frame->actual_method->klass), var, &frame->ctx, frame->de.domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
9364 break;
9366 default:
9367 return ERR_NOT_IMPLEMENTED;
9370 return ERR_NONE;
9373 static ErrorCode
9374 array_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9376 MonoArray *arr;
9377 int objid, index, len, i, esize;
9378 ErrorCode err;
9379 gpointer elem;
9381 objid = decode_objid (p, &p, end);
9382 err = get_object (objid, (MonoObject**)&arr);
9383 if (err != ERR_NONE)
9384 return err;
9386 switch (command) {
9387 case CMD_ARRAY_REF_GET_LENGTH:
9388 buffer_add_int (buf, m_class_get_rank (arr->obj.vtable->klass));
9389 if (!arr->bounds) {
9390 buffer_add_int (buf, arr->max_length);
9391 buffer_add_int (buf, 0);
9392 } else {
9393 for (i = 0; i < m_class_get_rank (arr->obj.vtable->klass); ++i) {
9394 buffer_add_int (buf, arr->bounds [i].length);
9395 buffer_add_int (buf, arr->bounds [i].lower_bound);
9398 break;
9399 case CMD_ARRAY_REF_GET_VALUES:
9400 index = decode_int (p, &p, end);
9401 len = decode_int (p, &p, end);
9403 if (index < 0 || len < 0)
9404 return ERR_INVALID_ARGUMENT;
9405 // Reordered to avoid integer overflow
9406 if (index > arr->max_length - len)
9407 return ERR_INVALID_ARGUMENT;
9409 esize = mono_array_element_size (arr->obj.vtable->klass);
9410 for (i = index; i < index + len; ++i) {
9411 elem = (gpointer*)((char*)arr->vector + (i * esize));
9412 buffer_add_value (buf, m_class_get_byval_arg (m_class_get_element_class (arr->obj.vtable->klass)), elem, arr->obj.vtable->domain);
9414 break;
9415 case CMD_ARRAY_REF_SET_VALUES:
9416 index = decode_int (p, &p, end);
9417 len = decode_int (p, &p, end);
9419 if (index < 0 || len < 0)
9420 return ERR_INVALID_ARGUMENT;
9421 // Reordered to avoid integer overflow
9422 if (index > arr->max_length - len)
9423 return ERR_INVALID_ARGUMENT;
9425 esize = mono_array_element_size (arr->obj.vtable->klass);
9426 for (i = index; i < index + len; ++i) {
9427 elem = (gpointer*)((char*)arr->vector + (i * esize));
9429 decode_value (m_class_get_byval_arg (m_class_get_element_class (arr->obj.vtable->klass)), arr->obj.vtable->domain, (guint8 *)elem, p, &p, end, TRUE);
9431 break;
9432 default:
9433 return ERR_NOT_IMPLEMENTED;
9436 return ERR_NONE;
9439 static ErrorCode
9440 string_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9442 int objid;
9443 ErrorCode err;
9444 MonoString *str;
9445 char *s;
9446 int i, index, length;
9447 gunichar2 *c;
9448 gboolean use_utf16 = FALSE;
9450 objid = decode_objid (p, &p, end);
9451 err = get_object (objid, (MonoObject**)&str);
9452 if (err != ERR_NONE)
9453 return err;
9455 switch (command) {
9456 case CMD_STRING_REF_GET_VALUE:
9457 if (CHECK_PROTOCOL_VERSION (2, 41)) {
9458 for (i = 0; i < mono_string_length_internal (str); ++i)
9459 if (mono_string_chars_internal (str)[i] == 0)
9460 use_utf16 = TRUE;
9461 buffer_add_byte (buf, use_utf16 ? 1 : 0);
9463 if (use_utf16) {
9464 buffer_add_int (buf, mono_string_length_internal (str) * 2);
9465 buffer_add_utf16 (buf, (guint8*)mono_string_chars_internal (str), mono_string_length_internal (str) * 2);
9466 } else {
9467 ERROR_DECL (error);
9468 s = mono_string_to_utf8_checked_internal (str, error);
9469 if (!is_ok (error)) {
9470 if (s)
9471 g_free (s);
9472 add_error_string (buf, mono_error_get_message (error));
9473 return ERR_INVALID_ARGUMENT;
9475 buffer_add_string (buf, s);
9476 g_free (s);
9478 break;
9479 case CMD_STRING_REF_GET_LENGTH:
9480 buffer_add_long (buf, mono_string_length_internal (str));
9481 break;
9482 case CMD_STRING_REF_GET_CHARS:
9483 index = decode_long (p, &p, end);
9484 length = decode_long (p, &p, end);
9485 if (index > mono_string_length_internal (str) - length)
9486 return ERR_INVALID_ARGUMENT;
9487 c = mono_string_chars_internal (str) + index;
9488 for (i = 0; i < length; ++i)
9489 buffer_add_short (buf, c [i]);
9490 break;
9491 default:
9492 return ERR_NOT_IMPLEMENTED;
9495 return ERR_NONE;
9498 static void
9499 create_file_to_check_memory_address (void)
9501 if (file_check_valid_memory != -1)
9502 return;
9503 char *file_name = g_strdup_printf ("debugger_check_valid_memory.%d", getpid());
9504 filename_check_valid_memory = g_build_filename (g_get_tmp_dir (), file_name, (const char*)NULL);
9505 file_check_valid_memory = open(filename_check_valid_memory, O_CREAT | O_WRONLY | O_APPEND, S_IWUSR);
9506 g_free (file_name);
9509 static gboolean
9510 valid_memory_address (gpointer addr, gint size)
9512 #ifndef _MSC_VER
9513 gboolean ret = TRUE;
9514 create_file_to_check_memory_address ();
9515 if(file_check_valid_memory < 0) {
9516 return TRUE;
9518 write (file_check_valid_memory, (gpointer)addr, 1);
9519 if (errno == EFAULT) {
9520 ret = FALSE;
9522 #else
9523 int i = 0;
9524 gboolean ret = FALSE;
9525 __try {
9526 for (i = 0; i < size; i++)
9527 *((volatile char*)addr+i);
9528 ret = TRUE;
9529 } __except(1) {
9530 return ret;
9532 #endif
9533 return ret;
9536 static ErrorCode
9537 pointer_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9539 ErrorCode err;
9540 gint64 addr;
9541 MonoClass* klass;
9542 MonoDomain* domain = NULL;
9543 MonoType *type = NULL;
9544 int align;
9545 int size = 0;
9547 switch (command) {
9548 case CMD_POINTER_GET_VALUE:
9549 addr = decode_long (p, &p, end);
9550 klass = decode_typeid (p, &p, end, &domain, &err);
9551 if (err != ERR_NONE)
9552 return err;
9554 if (m_class_get_byval_arg (klass)->type != MONO_TYPE_PTR)
9555 return ERR_INVALID_ARGUMENT;
9557 type = m_class_get_byval_arg (m_class_get_element_class (klass));
9558 size = mono_type_size (type, &align);
9560 if (!valid_memory_address((gpointer)addr, size))
9561 return ERR_INVALID_ARGUMENT;
9563 buffer_add_value (buf, type, (gpointer)addr, domain);
9565 break;
9566 default:
9567 return ERR_NOT_IMPLEMENTED;
9570 return ERR_NONE;
9573 static ErrorCode
9574 object_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
9576 HANDLE_FUNCTION_ENTER ();
9578 ERROR_DECL (error);
9579 int objid;
9580 ErrorCode err;
9581 MonoObject *obj;
9582 int len, i;
9583 MonoClassField *f;
9584 MonoClass *k;
9585 gboolean found;
9586 gboolean remote_obj = FALSE;
9587 MonoStringHandle string_handle = MONO_HANDLE_NEW (MonoString, NULL); // FIXME? Not always needed.
9589 if (command == CMD_OBJECT_REF_IS_COLLECTED) {
9590 objid = decode_objid (p, &p, end);
9591 err = get_object (objid, &obj);
9592 if (err != ERR_NONE)
9593 buffer_add_int (buf, 1);
9594 else
9595 buffer_add_int (buf, 0);
9596 err = ERR_NONE;
9597 goto exit;
9600 objid = decode_objid (p, &p, end);
9601 err = get_object (objid, &obj);
9602 if (err != ERR_NONE)
9603 goto exit;
9605 MonoClass *obj_type;
9607 obj_type = obj->vtable->klass;
9608 if (mono_class_is_transparent_proxy (obj_type)) {
9609 obj_type = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
9610 remote_obj = TRUE;
9613 g_assert (obj_type);
9615 switch (command) {
9616 case CMD_OBJECT_REF_GET_TYPE:
9617 /* This handles transparent proxies too */
9618 buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type_internal (((MonoReflectionType*)obj->vtable->type)->type));
9619 break;
9620 case CMD_OBJECT_REF_GET_VALUES:
9621 len = decode_int (p, &p, end);
9623 for (i = 0; i < len; ++i) {
9624 MonoClassField *f = decode_fieldid (p, &p, end, NULL, &err);
9625 if (err != ERR_NONE)
9626 goto exit;
9628 /* Check that the field belongs to the object */
9629 found = FALSE;
9630 for (k = obj_type; k; k = m_class_get_parent (k)) {
9631 if (k == f->parent) {
9632 found = TRUE;
9633 break;
9636 if (!found)
9637 goto invalid_fieldid;
9639 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9640 guint8 *val;
9641 MonoVTable *vtable;
9643 if (mono_class_field_is_special_static (f))
9644 goto invalid_fieldid;
9646 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
9647 vtable = mono_class_vtable_checked (obj->vtable->domain, f->parent, error);
9648 if (!is_ok (error)) {
9649 mono_error_cleanup (error);
9650 goto invalid_object;
9652 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
9653 mono_field_static_get_value_checked (vtable, f, val, string_handle, error);
9654 if (!is_ok (error)) {
9655 mono_error_cleanup (error); /* FIXME report the error */
9656 goto invalid_object;
9658 buffer_add_value (buf, f->type, val, obj->vtable->domain);
9659 g_free (val);
9660 } else {
9661 void *field_value = NULL;
9662 #ifndef DISABLE_REMOTING
9663 void *field_storage = NULL;
9664 #endif
9665 if (remote_obj) {
9666 #ifndef DISABLE_REMOTING
9667 field_value = mono_load_remote_field_checked(obj, obj_type, f, &field_storage, error);
9668 if (!is_ok (error)) {
9669 mono_error_cleanup (error); /* FIXME report the error */
9670 goto invalid_object;
9672 #else
9673 g_assert_not_reached ();
9674 #endif
9675 } else
9676 field_value = (guint8*)obj + f->offset;
9678 buffer_add_value (buf, f->type, field_value, obj->vtable->domain);
9681 break;
9682 case CMD_OBJECT_REF_SET_VALUES:
9683 len = decode_int (p, &p, end);
9685 for (i = 0; i < len; ++i) {
9686 f = decode_fieldid (p, &p, end, NULL, &err);
9687 if (err != ERR_NONE)
9688 goto exit;
9690 /* Check that the field belongs to the object */
9691 found = FALSE;
9692 for (k = obj_type; k; k = m_class_get_parent (k)) {
9693 if (k == f->parent) {
9694 found = TRUE;
9695 break;
9698 if (!found)
9699 goto invalid_fieldid;
9701 if (f->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9702 guint8 *val;
9703 MonoVTable *vtable;
9705 if (mono_class_field_is_special_static (f))
9706 goto invalid_fieldid;
9708 g_assert (f->type->attrs & FIELD_ATTRIBUTE_STATIC);
9709 vtable = mono_class_vtable_checked (obj->vtable->domain, f->parent, error);
9710 if (!is_ok (error)) {
9711 mono_error_cleanup (error);
9712 goto invalid_fieldid;
9715 val = (guint8 *)g_malloc (mono_class_instance_size (mono_class_from_mono_type_internal (f->type)));
9716 err = decode_value (f->type, obj->vtable->domain, val, p, &p, end, TRUE);
9717 if (err != ERR_NONE) {
9718 g_free (val);
9719 goto exit;
9721 mono_field_static_set_value_internal (vtable, f, val);
9722 g_free (val);
9723 } else {
9724 err = decode_value (f->type, obj->vtable->domain, (guint8*)obj + f->offset, p, &p, end, TRUE);
9725 if (err != ERR_NONE)
9726 goto exit;
9729 break;
9730 case CMD_OBJECT_REF_GET_ADDRESS:
9731 buffer_add_long (buf, (gssize)obj);
9732 break;
9733 case CMD_OBJECT_REF_GET_DOMAIN:
9734 buffer_add_domainid (buf, obj->vtable->domain);
9735 break;
9736 case CMD_OBJECT_REF_GET_INFO:
9737 buffer_add_typeid (buf, obj->vtable->domain, mono_class_from_mono_type_internal (((MonoReflectionType*)obj->vtable->type)->type));
9738 buffer_add_domainid (buf, obj->vtable->domain);
9739 break;
9740 default:
9741 err = ERR_NOT_IMPLEMENTED;
9742 goto exit;
9745 err = ERR_NONE;
9746 goto exit;
9747 invalid_fieldid:
9748 err = ERR_INVALID_FIELDID;
9749 goto exit;
9750 invalid_object:
9751 err = ERR_INVALID_OBJECT;
9752 goto exit;
9753 exit:
9754 HANDLE_FUNCTION_RETURN_VAL (err);
9757 static const char*
9758 command_set_to_string (CommandSet command_set)
9760 switch (command_set) {
9761 case CMD_SET_VM:
9762 return "VM";
9763 case CMD_SET_OBJECT_REF:
9764 return "OBJECT_REF";
9765 case CMD_SET_STRING_REF:
9766 return "STRING_REF";
9767 case CMD_SET_THREAD:
9768 return "THREAD";
9769 case CMD_SET_ARRAY_REF:
9770 return "ARRAY_REF";
9771 case CMD_SET_EVENT_REQUEST:
9772 return "EVENT_REQUEST";
9773 case CMD_SET_STACK_FRAME:
9774 return "STACK_FRAME";
9775 case CMD_SET_APPDOMAIN:
9776 return "APPDOMAIN";
9777 case CMD_SET_ASSEMBLY:
9778 return "ASSEMBLY";
9779 case CMD_SET_METHOD:
9780 return "METHOD";
9781 case CMD_SET_TYPE:
9782 return "TYPE";
9783 case CMD_SET_MODULE:
9784 return "MODULE";
9785 case CMD_SET_FIELD:
9786 return "FIELD";
9787 case CMD_SET_EVENT:
9788 return "EVENT";
9789 case CMD_SET_POINTER:
9790 return "POINTER";
9791 default:
9792 return "";
9796 static const char* vm_cmds_str [] = {
9797 "VERSION",
9798 "ALL_THREADS",
9799 "SUSPEND",
9800 "RESUME",
9801 "EXIT",
9802 "DISPOSE",
9803 "INVOKE_METHOD",
9804 "SET_PROTOCOL_VERSION",
9805 "ABORT_INVOKE",
9806 "SET_KEEPALIVE"
9807 "GET_TYPES_FOR_SOURCE_FILE",
9808 "GET_TYPES",
9809 "INVOKE_METHODS"
9812 static const char* thread_cmds_str[] = {
9813 "GET_FRAME_INFO",
9814 "GET_NAME",
9815 "GET_STATE",
9816 "GET_INFO",
9817 "GET_ID",
9818 "GET_TID",
9819 "SET_IP"
9822 static const char* event_cmds_str[] = {
9823 "REQUEST_SET",
9824 "REQUEST_CLEAR",
9825 "REQUEST_CLEAR_ALL_BREAKPOINTS"
9828 static const char* appdomain_cmds_str[] = {
9829 "GET_ROOT_DOMAIN",
9830 "GET_FRIENDLY_NAME",
9831 "GET_ASSEMBLIES",
9832 "GET_ENTRY_ASSEMBLY",
9833 "CREATE_STRING",
9834 "GET_CORLIB",
9835 "CREATE_BOXED_VALUE",
9836 "CREATE_BYTE_ARRAY",
9839 static const char* assembly_cmds_str[] = {
9840 "GET_LOCATION",
9841 "GET_ENTRY_POINT",
9842 "GET_MANIFEST_MODULE",
9843 "GET_OBJECT",
9844 "GET_TYPE",
9845 "GET_NAME",
9846 "GET_DOMAIN",
9847 "HAS_DEBUG_INFO"
9850 static const char* module_cmds_str[] = {
9851 "GET_INFO",
9854 static const char* field_cmds_str[] = {
9855 "GET_INFO",
9858 static const char* method_cmds_str[] = {
9859 "GET_NAME",
9860 "GET_DECLARING_TYPE",
9861 "GET_DEBUG_INFO",
9862 "GET_PARAM_INFO",
9863 "GET_LOCALS_INFO",
9864 "GET_INFO",
9865 "GET_BODY",
9866 "RESOLVE_TOKEN",
9867 "GET_CATTRS ",
9868 "MAKE_GENERIC_METHOD"
9871 static const char* type_cmds_str[] = {
9872 "GET_INFO",
9873 "GET_METHODS",
9874 "GET_FIELDS",
9875 "GET_VALUES",
9876 "GET_OBJECT",
9877 "GET_SOURCE_FILES",
9878 "SET_VALUES",
9879 "IS_ASSIGNABLE_FROM",
9880 "GET_PROPERTIES ",
9881 "GET_CATTRS",
9882 "GET_FIELD_CATTRS",
9883 "GET_PROPERTY_CATTRS",
9884 "GET_SOURCE_FILES_2",
9885 "GET_VALUES_2",
9886 "GET_METHODS_BY_NAME_FLAGS",
9887 "GET_INTERFACES",
9888 "GET_INTERFACE_MAP",
9889 "IS_INITIALIZED",
9890 "CREATE_INSTANCE",
9891 "GET_VALUE_SIZE"
9894 static const char* stack_frame_cmds_str[] = {
9895 "GET_VALUES",
9896 "GET_THIS",
9897 "SET_VALUES",
9898 "GET_DOMAIN",
9899 "SET_THIS"
9902 static const char* array_cmds_str[] = {
9903 "GET_LENGTH",
9904 "GET_VALUES",
9905 "SET_VALUES",
9908 static const char* string_cmds_str[] = {
9909 "GET_VALUE",
9910 "GET_LENGTH",
9911 "GET_CHARS"
9914 static const char* pointer_cmds_str[] = {
9915 "GET_VALUE"
9918 static const char* object_cmds_str[] = {
9919 "GET_TYPE",
9920 "GET_VALUES",
9921 "IS_COLLECTED",
9922 "GET_ADDRESS",
9923 "GET_DOMAIN",
9924 "SET_VALUES",
9925 "GET_INFO",
9928 static const char*
9929 cmd_to_string (CommandSet set, int command)
9931 const char **cmds;
9932 int cmds_len = 0;
9934 switch (set) {
9935 case CMD_SET_VM:
9936 cmds = vm_cmds_str;
9937 cmds_len = G_N_ELEMENTS (vm_cmds_str);
9938 break;
9939 case CMD_SET_OBJECT_REF:
9940 cmds = object_cmds_str;
9941 cmds_len = G_N_ELEMENTS (object_cmds_str);
9942 break;
9943 case CMD_SET_STRING_REF:
9944 cmds = string_cmds_str;
9945 cmds_len = G_N_ELEMENTS (string_cmds_str);
9946 break;
9947 case CMD_SET_THREAD:
9948 cmds = thread_cmds_str;
9949 cmds_len = G_N_ELEMENTS (thread_cmds_str);
9950 break;
9951 case CMD_SET_ARRAY_REF:
9952 cmds = array_cmds_str;
9953 cmds_len = G_N_ELEMENTS (array_cmds_str);
9954 break;
9955 case CMD_SET_EVENT_REQUEST:
9956 cmds = event_cmds_str;
9957 cmds_len = G_N_ELEMENTS (event_cmds_str);
9958 break;
9959 case CMD_SET_STACK_FRAME:
9960 cmds = stack_frame_cmds_str;
9961 cmds_len = G_N_ELEMENTS (stack_frame_cmds_str);
9962 break;
9963 case CMD_SET_APPDOMAIN:
9964 cmds = appdomain_cmds_str;
9965 cmds_len = G_N_ELEMENTS (appdomain_cmds_str);
9966 break;
9967 case CMD_SET_ASSEMBLY:
9968 cmds = assembly_cmds_str;
9969 cmds_len = G_N_ELEMENTS (assembly_cmds_str);
9970 break;
9971 case CMD_SET_METHOD:
9972 cmds = method_cmds_str;
9973 cmds_len = G_N_ELEMENTS (method_cmds_str);
9974 break;
9975 case CMD_SET_TYPE:
9976 cmds = type_cmds_str;
9977 cmds_len = G_N_ELEMENTS (type_cmds_str);
9978 break;
9979 case CMD_SET_MODULE:
9980 cmds = module_cmds_str;
9981 cmds_len = G_N_ELEMENTS (module_cmds_str);
9982 break;
9983 case CMD_SET_FIELD:
9984 cmds = field_cmds_str;
9985 cmds_len = G_N_ELEMENTS (field_cmds_str);
9986 break;
9987 case CMD_SET_EVENT:
9988 cmds = event_cmds_str;
9989 cmds_len = G_N_ELEMENTS (event_cmds_str);
9990 break;
9991 case CMD_SET_POINTER:
9992 cmds = pointer_cmds_str;
9993 cmds_len = G_N_ELEMENTS (pointer_cmds_str);
9994 break;
9995 default:
9996 return NULL;
9998 if (command > 0 && command <= cmds_len)
9999 return cmds [command - 1];
10000 else
10001 return NULL;
10004 static gboolean
10005 wait_for_attach (void)
10007 #ifndef DISABLE_SOCKET_TRANSPORT
10008 if (listen_fd == -1) {
10009 DEBUG_PRINTF (1, "[dbg] Invalid listening socket\n");
10010 return FALSE;
10013 /* Block and wait for client connection */
10014 conn_fd = socket_transport_accept (listen_fd);
10016 DEBUG_PRINTF (1, "Accepted connection on %d\n", conn_fd);
10017 if (conn_fd == -1) {
10018 DEBUG_PRINTF (1, "[dbg] Bad client connection\n");
10019 return FALSE;
10021 #else
10022 g_assert_not_reached ();
10023 #endif
10025 /* Handshake */
10026 disconnected = !transport_handshake ();
10027 if (disconnected) {
10028 DEBUG_PRINTF (1, "Transport handshake failed!\n");
10029 return FALSE;
10032 return TRUE;
10036 * debugger_thread:
10038 * This thread handles communication with the debugger client using a JDWP
10039 * like protocol.
10041 static gsize WINAPI
10042 debugger_thread (void *arg)
10044 int res, len, id, flags, command = 0;
10045 CommandSet command_set = (CommandSet)0;
10046 guint8 header [HEADER_LENGTH];
10047 guint8 *data, *p, *end;
10048 Buffer buf;
10049 ErrorCode err;
10050 gboolean no_reply;
10051 gboolean attach_failed = FALSE;
10053 DEBUG_PRINTF (1, "[dbg] Agent thread started, pid=%p\n", (gpointer) (gsize) mono_native_thread_id_get ());
10055 gboolean log_each_step = g_hasenv ("MONO_DEBUGGER_LOG_AFTER_COMMAND");
10057 debugger_thread_id = mono_native_thread_id_get ();
10059 MonoInternalThread *internal = mono_thread_internal_current ();
10060 mono_thread_set_name_constant_ignore_error (internal, "Debugger agent", MonoSetThreadNameFlag_Permanent);
10062 internal->state |= ThreadState_Background;
10063 internal->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
10065 if (agent_config.defer) {
10066 if (!wait_for_attach ()) {
10067 DEBUG_PRINTF (1, "[dbg] Can't attach, aborting debugger thread.\n");
10068 attach_failed = TRUE; // Don't abort process when we can't listen
10069 } else {
10070 mono_set_is_debugger_attached (TRUE);
10071 /* Send start event to client */
10072 process_profiler_event (EVENT_KIND_VM_START, mono_thread_get_main ());
10074 } else {
10075 mono_set_is_debugger_attached (TRUE);
10078 while (!attach_failed) {
10079 res = transport_recv (header, HEADER_LENGTH);
10081 /* This will break if the socket is closed during shutdown too */
10082 if (res != HEADER_LENGTH) {
10083 DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, HEADER_LENGTH);
10084 command_set = (CommandSet)0;
10085 command = 0;
10086 dispose_vm ();
10087 break;
10088 } else {
10089 p = header;
10090 end = header + HEADER_LENGTH;
10092 len = decode_int (p, &p, end);
10093 id = decode_int (p, &p, end);
10094 flags = decode_byte (p, &p, end);
10095 command_set = (CommandSet)decode_byte (p, &p, end);
10096 command = decode_byte (p, &p, end);
10099 g_assert (flags == 0);
10100 const char *cmd_str;
10101 char cmd_num [256];
10103 cmd_str = cmd_to_string (command_set, command);
10104 if (!cmd_str) {
10105 sprintf (cmd_num, "%d", command);
10106 cmd_str = cmd_num;
10109 if (log_level) {
10110 DEBUG_PRINTF (1, "[dbg] Command %s(%s) [%d][at=%lx].\n", command_set_to_string (command_set), cmd_str, id, (long)mono_100ns_ticks () / 10000);
10113 data = (guint8 *)g_malloc (len - HEADER_LENGTH);
10114 if (len - HEADER_LENGTH > 0)
10116 res = transport_recv (data, len - HEADER_LENGTH);
10117 if (res != len - HEADER_LENGTH) {
10118 DEBUG_PRINTF (1, "[dbg] transport_recv () returned %d, expected %d.\n", res, len - HEADER_LENGTH);
10119 break;
10123 p = data;
10124 end = data + (len - HEADER_LENGTH);
10126 buffer_init (&buf, 128);
10128 err = ERR_NONE;
10129 no_reply = FALSE;
10131 /* Process the request */
10132 switch (command_set) {
10133 case CMD_SET_VM:
10134 err = vm_commands (command, id, p, end, &buf);
10135 if (err == ERR_NONE && command == CMD_VM_INVOKE_METHOD)
10136 /* Sent after the invoke is complete */
10137 no_reply = TRUE;
10138 break;
10139 case CMD_SET_EVENT_REQUEST:
10140 err = event_commands (command, p, end, &buf);
10141 break;
10142 case CMD_SET_APPDOMAIN:
10143 err = domain_commands (command, p, end, &buf);
10144 break;
10145 case CMD_SET_ASSEMBLY:
10146 err = assembly_commands (command, p, end, &buf);
10147 break;
10148 case CMD_SET_MODULE:
10149 err = module_commands (command, p, end, &buf);
10150 break;
10151 case CMD_SET_FIELD:
10152 err = field_commands (command, p, end, &buf);
10153 break;
10154 case CMD_SET_TYPE:
10155 err = type_commands (command, p, end, &buf);
10156 break;
10157 case CMD_SET_METHOD:
10158 err = method_commands (command, p, end, &buf);
10159 break;
10160 case CMD_SET_THREAD:
10161 err = thread_commands (command, p, end, &buf);
10162 break;
10163 case CMD_SET_STACK_FRAME:
10164 err = frame_commands (command, p, end, &buf);
10165 break;
10166 case CMD_SET_ARRAY_REF:
10167 err = array_commands (command, p, end, &buf);
10168 break;
10169 case CMD_SET_STRING_REF:
10170 err = string_commands (command, p, end, &buf);
10171 break;
10172 case CMD_SET_POINTER:
10173 err = pointer_commands (command, p, end, &buf);
10174 break;
10175 case CMD_SET_OBJECT_REF:
10176 err = object_commands (command, p, end, &buf);
10177 break;
10178 default:
10179 err = ERR_NOT_IMPLEMENTED;
10182 if (command_set == CMD_SET_VM && command == CMD_VM_START_BUFFERING) {
10183 buffer_replies = TRUE;
10186 if (!no_reply) {
10187 if (buffer_replies) {
10188 buffer_reply_packet (id, err, &buf);
10189 } else {
10190 send_reply_packet (id, err, &buf);
10191 //DEBUG_PRINTF (1, "[dbg] Sent reply to %d [at=%lx].\n", id, (long)mono_100ns_ticks () / 10000);
10195 mono_debugger_log_command (command_set_to_string (command_set), cmd_str, buf.buf, buffer_len (&buf));
10197 if (err == ERR_NONE && command_set == CMD_SET_VM && command == CMD_VM_STOP_BUFFERING) {
10198 send_buffered_reply_packets ();
10199 buffer_replies = FALSE;
10202 g_free (data);
10203 buffer_free (&buf);
10205 if (log_each_step) {
10206 char *debugger_log = mono_debugger_state_str ();
10207 if (debugger_log) {
10208 fprintf (stderr, "Debugger state: %s\n", debugger_log);
10209 g_free (debugger_log);
10213 if (command_set == CMD_SET_VM && (command == CMD_VM_DISPOSE || command == CMD_VM_EXIT))
10214 break;
10217 mono_set_is_debugger_attached (FALSE);
10219 mono_coop_mutex_lock (&debugger_thread_exited_mutex);
10220 debugger_thread_exited = TRUE;
10221 mono_coop_cond_signal (&debugger_thread_exited_cond);
10222 mono_coop_mutex_unlock (&debugger_thread_exited_mutex);
10224 DEBUG_PRINTF (1, "[dbg] Debugger thread exited.\n");
10226 if (!attach_failed && command_set == CMD_SET_VM && command == CMD_VM_DISPOSE && !(vm_death_event_sent || mono_runtime_is_shutting_down ())) {
10227 DEBUG_PRINTF (2, "[dbg] Detached - restarting clean debugger thread.\n");
10228 ERROR_DECL (error);
10229 start_debugger_thread (error);
10230 mono_error_cleanup (error);
10233 return 0;
10236 void
10237 mono_debugger_agent_init (void)
10239 MonoDebuggerCallbacks cbs;
10241 memset (&cbs, 0, sizeof (cbs));
10242 cbs.version = MONO_DBG_CALLBACKS_VERSION;
10243 cbs.parse_options = debugger_agent_parse_options;
10244 cbs.init = debugger_agent_init;
10245 cbs.breakpoint_hit = debugger_agent_breakpoint_hit;
10246 cbs.single_step_event = debugger_agent_single_step_event;
10247 cbs.single_step_from_context = debugger_agent_single_step_from_context;
10248 cbs.breakpoint_from_context = debugger_agent_breakpoint_from_context;
10249 cbs.free_domain_info = debugger_agent_free_domain_info;
10250 cbs.unhandled_exception = debugger_agent_unhandled_exception;
10251 cbs.handle_exception = debugger_agent_handle_exception;
10252 cbs.begin_exception_filter = debugger_agent_begin_exception_filter;
10253 cbs.end_exception_filter = debugger_agent_end_exception_filter;
10254 cbs.user_break = debugger_agent_user_break;
10255 cbs.debug_log = debugger_agent_debug_log;
10256 cbs.debug_log_is_enabled = debugger_agent_debug_log_is_enabled;
10257 cbs.send_crash = mono_debugger_agent_send_crash;
10259 mini_install_dbg_callbacks (&cbs);
10262 void
10263 mono_debugger_agent_parse_options (char *options)
10265 sdb_options = options;
10268 #endif /* DISABLE_SDB */