2 #include "mini-runtime.h"
3 #include <mono/metadata/mono-debug.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/seq-points-data.h>
7 #include <mono/mini/aot-runtime.h>
8 #include <mono/mini/seq-points.h>
9 #include <mono/mini/debugger-engine.h>
11 //XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle
12 #include <mono/mini/interp/interp-internals.h>
16 #include <emscripten.h>
19 static int log_level
= 1;
21 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (stdout, __VA_ARGS__); } } while (0)
23 //functions exported to be used by JS
26 EMSCRIPTEN_KEEPALIVE
int mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
);
27 EMSCRIPTEN_KEEPALIVE
int mono_wasm_remove_breakpoint (int bp_id
);
28 EMSCRIPTEN_KEEPALIVE
int mono_wasm_current_bp_id (void);
29 EMSCRIPTEN_KEEPALIVE
void mono_wasm_enum_frames (void);
30 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_var_info (int scope
, int* pos
, int len
);
31 EMSCRIPTEN_KEEPALIVE
void mono_wasm_clear_all_breakpoints (void);
32 EMSCRIPTEN_KEEPALIVE
void mono_wasm_setup_single_step (int kind
);
33 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_object_properties (int object_id
);
34 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_array_values (int object_id
);
36 //JS functions imported that we use
37 extern void mono_wasm_add_frame (int il_offset
, int method_token
, const char *assembly_name
);
38 extern void mono_wasm_fire_bp (void);
39 extern void mono_wasm_add_bool_var (gint8
);
40 extern void mono_wasm_add_number_var (double);
41 extern void mono_wasm_add_string_var (const char*);
42 extern void mono_wasm_add_obj_var (const char*, guint64
);
43 extern void mono_wasm_add_array_var (const char*, guint64
);
44 extern void mono_wasm_add_properties_var (const char*);
45 extern void mono_wasm_add_array_item (int);
49 //FIXME move all of those fields to the profiler object
50 static gboolean debugger_enabled
;
52 static int event_request_id
;
53 static GHashTable
*objrefs
;
54 static GHashTable
*obj_to_objref
;
55 static int objref_id
= 0;
57 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
60 inplace_tolower (char *c
)
63 for (i
= strlen (c
) - 1; i
>= 0; --i
)
64 c
[i
] = tolower (c
[i
]);
68 jit_done (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
70 mono_de_add_pending_breakpoints (method
, jinfo
);
74 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
)
76 mono_de_domain_add (domain
);
79 /* Frame state handling */
80 static GPtrArray
*frames
;
83 free_frame (DbgEngineStackFrame
*frame
)
89 collect_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
95 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
99 method
= jinfo_get_method (info
->ji
);
101 method
= info
->method
;
106 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
108 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
109 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
111 DbgEngineStackFrame
*frame
= g_new0 (DbgEngineStackFrame
, 1);
113 frame
->ji
= info
->ji
;
114 frame
->domain
= info
->domain
;
115 frame
->method
= method
;
116 frame
->native_offset
= info
->native_offset
;
118 g_ptr_array_add (frames
, frame
);
124 free_frame_state (void)
128 for (i
= 0; i
< frames
->len
; ++i
)
129 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
130 g_ptr_array_set_size (frames
, 0);
135 compute_frames (void) {
138 for (i
= 0; i
< frames
->len
; ++i
)
139 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
140 g_ptr_array_set_size (frames
, 0);
142 frames
= g_ptr_array_new ();
145 mono_walk_stack_with_ctx (collect_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
148 tls_get_restore_state (void *tls
)
154 try_process_suspend (void *tls
, MonoContext
*ctx
)
160 begin_breakpoint_processing (void *tls
, MonoContext
*ctx
, MonoJitInfo
*ji
, gboolean from_signal
)
166 begin_single_step_processing (MonoContext
*ctx
, gboolean from_signal
)
171 ss_discard_frame_context (void *the_tls
)
177 ss_calculate_framecount (void *tls
, MonoContext
*ctx
, gboolean force_use_ctx
, DbgEngineStackFrame
***out_frames
, int *nframes
)
181 *out_frames
= (DbgEngineStackFrame
**)frames
->pdata
;
183 *nframes
= frames
->len
;
187 ensure_jit (DbgEngineStackFrame
* the_frame
)
193 ensure_runtime_is_suspended (void)
199 get_this_async_id (DbgEngineStackFrame
*f
)
201 g_error ("get_this_async_id");
206 set_set_notification_for_wait_completion_flag (DbgEngineStackFrame
*f
)
208 g_error ("set_set_notification_for_wait_completion_flag");
213 get_notify_debugger_of_wait_completion_method (void)
215 g_error ("get_notify_debugger_of_wait_completion_method");
219 gboolean is_ss
; //do I need this?
223 create_breakpoint_events (GPtrArray
*ss_reqs
, GPtrArray
*bp_reqs
, MonoJitInfo
*ji
, EventKind kind
)
225 printf ("ss_reqs %d bp_reqs %d\n", ss_reqs
->len
, bp_reqs
->len
);
226 if ((ss_reqs
&& ss_reqs
->len
) || (bp_reqs
&& bp_reqs
->len
)) {
227 BpEvents
*evts
= g_new0 (BpEvents
, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events
228 evts
->is_ss
= (ss_reqs
&& ss_reqs
->len
);
235 process_breakpoint_events (void *_evts
, MonoMethod
*method
, MonoContext
*ctx
, int il_offsets
)
237 BpEvents
*evts
= (BpEvents
*)_evts
;
240 mono_de_cancel_ss ();
241 mono_wasm_fire_bp ();
247 no_seq_points_found (MonoMethod
*method
, int offset
)
250 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
252 printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method
, TRUE
), offset
);
255 #define DBG_NOT_SUSPENDED 1
258 ss_create_init_args (SingleStepReq
*ss_req
, SingleStepArgs
*ss_args
)
260 printf ("ss_create_init_args\n");
262 ss_req
->start_sp
= ss_req
->last_sp
= &dummy
;
264 memset (ss_args
, 0, sizeof (*ss_args
));
266 //BIG WTF, should not happen maybe should assert?
267 if (frames
->len
== 0) {
268 DEBUG_PRINTF (1, "SINGLE STEPPING FOUND NO FRAMES");
269 return DBG_NOT_SUSPENDED
;
272 DbgEngineStackFrame
*frame
= (DbgEngineStackFrame
*)g_ptr_array_index (frames
, 0);
273 ss_req
->start_method
= ss_args
->method
= frame
->method
;
274 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &ss_args
->info
, &ss_args
->sp
);
276 no_seq_points_found (frame
->method
, frame
->native_offset
);
279 ss_args
->frames
= (DbgEngineStackFrame
**)frames
->pdata
;
280 ss_args
->nframes
= frames
->len
;
287 ss_args_destroy (SingleStepArgs
*ss_args
)
293 mono_wasm_debugger_init (void)
295 if (!debugger_enabled
)
298 DebuggerEngineCallbacks cbs
= {
299 .tls_get_restore_state
= tls_get_restore_state
,
300 .try_process_suspend
= try_process_suspend
,
301 .begin_breakpoint_processing
= begin_breakpoint_processing
,
302 .begin_single_step_processing
= begin_single_step_processing
,
303 .ss_discard_frame_context
= ss_discard_frame_context
,
304 .ss_calculate_framecount
= ss_calculate_framecount
,
305 .ensure_jit
= ensure_jit
,
306 .ensure_runtime_is_suspended
= ensure_runtime_is_suspended
,
307 .get_this_async_id
= get_this_async_id
,
308 .set_set_notification_for_wait_completion_flag
= set_set_notification_for_wait_completion_flag
,
309 .get_notify_debugger_of_wait_completion_method
= get_notify_debugger_of_wait_completion_method
,
310 .create_breakpoint_events
= create_breakpoint_events
,
311 .process_breakpoint_events
= process_breakpoint_events
,
312 .ss_create_init_args
= ss_create_init_args
,
313 .ss_args_destroy
= ss_args_destroy
,
316 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
318 mono_de_set_log_level (1, stdout
);
320 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
321 mini_debug_options
.mdb_optimizations
= TRUE
;
322 mono_disable_optimizations (MONO_OPT_LINEARS
);
323 mini_debug_options
.load_aot_jit_info_eagerly
= TRUE
;
325 MonoProfilerHandle prof
= mono_profiler_create (NULL
);
326 mono_profiler_set_jit_done_callback (prof
, jit_done
);
327 //FIXME support multiple appdomains
328 mono_profiler_set_domain_loaded_callback (prof
, appdomain_load
);
330 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
331 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, mono_debugger_free_objref
);
335 mono_wasm_enable_debugging (void)
337 DEBUG_PRINTF (1, "DEBUGGING ENABLED\n");
338 debugger_enabled
= TRUE
;
341 EMSCRIPTEN_KEEPALIVE
void
342 mono_wasm_setup_single_step (int kind
)
346 printf (">>>> mono_wasm_setup_single_step %d\n", kind
);
347 EventRequest
*req
= (EventRequest
*)g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
348 req
->id
= ++event_request_id
;
349 req
->event_kind
= EVENT_KIND_STEP
;
350 // DE doesn't care about suspend_policy
351 // req->suspend_policy = SUSPEND_POLICY_ALL;
352 req
->nmodifiers
= nmodifiers
;
354 StepSize size
= STEP_SIZE_MIN
;
356 //FIXME I DON'T KNOW WHAT I'M DOING!!!!! filter all the things.
357 StepFilter filter
= (StepFilter
)(STEP_FILTER_STATIC_CTOR
| STEP_FILTER_DEBUGGER_HIDDEN
| STEP_FILTER_DEBUGGER_STEP_THROUGH
| STEP_FILTER_DEBUGGER_NON_USER_CODE
);
358 req
->modifiers
[0].data
.filter
= filter
;
363 depth
= STEP_DEPTH_INTO
;
366 depth
= STEP_DEPTH_OUT
;
369 depth
= STEP_DEPTH_OVER
;
372 g_error ("dunno step kind %d", kind
);
375 DbgEngineErrorCode err
= mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size
, depth
, filter
, req
);
376 if (err
!= DE_ERR_NONE
) {
377 DEBUG_PRINTF (1, "[dbg] Failed to setup single step request");
379 printf ("ss is in place, now ahat?\n");
382 EMSCRIPTEN_KEEPALIVE
void
383 mono_wasm_clear_all_breakpoints (void)
385 DEBUG_PRINTF (1, "CLEAR BREAKPOINTS\n");
386 mono_de_clear_all_breakpoints ();
389 EMSCRIPTEN_KEEPALIVE
int
390 mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
)
394 DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name
, method_token
, il_offset
);
397 //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot
398 char *lookup_name
= g_strdup (assembly_name
);
399 for (i
= strlen (lookup_name
) - 1; i
>= 0; --i
) {
400 if (lookup_name
[i
] == '.') {
406 //resolve the assembly
407 MonoImageOpenStatus status
;
408 MonoAssemblyName
* aname
= mono_assembly_name_new (lookup_name
);
409 MonoAssembly
*assembly
= mono_assembly_load (aname
, NULL
, &status
);
410 g_free (lookup_name
);
412 DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name
);
416 mono_assembly_name_free (aname
);
418 MonoMethod
*method
= mono_get_method_checked (assembly
->image
, MONO_TOKEN_METHOD_DEF
| method_token
, NULL
, NULL
, error
);
420 //FIXME don't swallow the error
421 DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error
));
422 mono_error_cleanup (error
);
426 //FIXME right now none of the EventRequest fields are used by debugger-engine
427 EventRequest
*req
= g_new0 (EventRequest
, 1);
428 req
->id
= ++event_request_id
;
429 req
->event_kind
= EVENT_KIND_BREAKPOINT
;
430 //DE doesn't care about suspend_policy
431 // req->suspend_policy = SUSPEND_POLICY_ALL;
432 req
->nmodifiers
= 0; //funny thing,
434 // BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset);
435 MonoBreakpoint
*bp
= mono_de_set_breakpoint (method
, il_offset
, req
, error
);
438 DEBUG_PRINTF (1, "Could not set breakpoint to %s\n", mono_error_get_message (error
));
439 mono_error_cleanup (error
);
443 DEBUG_PRINTF (1, "NEW BP %p has id %d\n", req
, req
->id
);
447 EMSCRIPTEN_KEEPALIVE
int
448 mono_wasm_remove_breakpoint (int bp_id
)
450 MonoBreakpoint
*bp
= mono_de_get_breakpoint_by_id (bp_id
);
454 mono_de_clear_breakpoint (bp
);
459 mono_wasm_single_step_hit (void)
461 mono_de_process_single_step (NULL
, FALSE
);
465 mono_wasm_breakpoint_hit (void)
467 mono_de_process_breakpoint (NULL
, FALSE
);
468 // mono_wasm_fire_bp ();
471 EMSCRIPTEN_KEEPALIVE
int
472 mono_wasm_current_bp_id (void)
474 DEBUG_PRINTF (1, "COMPUTING breapoint ID\n");
475 //FIXME handle compiled case
478 MonoLMF
*lmf
= mono_get_lmf ();
480 g_assert (((guint64
)lmf
->previous_lmf
) & 2);
481 MonoLMFExt
*ext
= (MonoLMFExt
*)lmf
;
483 g_assert (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
);
484 MonoInterpFrameHandle
*frame
= (MonoInterpFrameHandle
*)ext
->interp_exit_data
;
485 MonoJitInfo
*ji
= mini_get_interp_callbacks ()->frame_get_jit_info (frame
);
486 guint8
*ip
= (guint8
*)mini_get_interp_callbacks ()->frame_get_ip (frame
);
488 g_assert (ji
&& !ji
->is_trampoline
);
489 MonoMethod
*method
= jinfo_get_method (ji
);
491 /* Compute the native offset of the breakpoint from the ip */
492 guint32 native_offset
= ip
- (guint8
*)ji
->code_start
;
494 MonoSeqPointInfo
*info
= NULL
;
496 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
, &sp
);
498 DEBUG_PRINTF (1, "Could not find SP\n");
501 GPtrArray
*bp_reqs
= g_ptr_array_new ();
502 mono_de_collect_breakpoints_by_sp (&sp
, ji
, NULL
, bp_reqs
);
504 if (bp_reqs
->len
== 0) {
505 DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method
->name
, ji
, sp
.il_offset
);
509 if (bp_reqs
->len
> 1)
510 DEBUG_PRINTF (1, "Multiple breakpoints (%d) at the same location, returning the first one.", bp_reqs
->len
);
512 EventRequest
*evt
= (EventRequest
*)g_ptr_array_index (bp_reqs
, 0);
513 g_ptr_array_free (bp_reqs
, TRUE
);
515 DEBUG_PRINTF (1, "Found BP %p with id %d\n", evt
, evt
->id
);
519 static int get_object_id(MonoObject
*obj
)
521 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
524 ref
= g_new0 (ObjRef
, 1);
525 ref
->id
= mono_atomic_inc_i32 (&objref_id
);
526 ref
->handle
= mono_gchandle_new_weakref_internal (obj
, FALSE
);
527 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
528 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
533 list_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
539 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
544 method
= jinfo_get_method (info
->ji
);
546 method
= info
->method
;
551 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
553 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
554 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
556 while (method
->is_inflated
)
557 method
= ((MonoMethodInflated
*)method
)->declaring
;
559 char *assembly_name
= g_strdup (m_class_get_image (method
->klass
)->module_name
);
560 inplace_tolower (assembly_name
);
562 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
563 DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
564 mono_wasm_add_frame (sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
567 g_free (assembly_name
);
572 EMSCRIPTEN_KEEPALIVE
void
573 mono_wasm_enum_frames (void)
575 mono_walk_stack_with_ctx (list_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
584 static gboolean
describe_value(MonoType
* type
, gpointer addr
)
587 switch (type
->type
) {
588 case MONO_TYPE_BOOLEAN
:
589 mono_wasm_add_bool_var (*(gint8
*)addr
);
592 mono_wasm_add_number_var (*(gint8
*)addr
);
595 mono_wasm_add_number_var (*(guint8
*)addr
);
599 mono_wasm_add_number_var (*(guint16
*)addr
);
602 mono_wasm_add_number_var (*(gint16
*)addr
);
606 mono_wasm_add_number_var (*(gint32
*)addr
);
610 mono_wasm_add_number_var (*(guint32
*)addr
);
613 mono_wasm_add_number_var (*(gint64
*)addr
);
616 mono_wasm_add_number_var (*(guint64
*)addr
);
619 mono_wasm_add_number_var (*(float*)addr
);
622 mono_wasm_add_number_var (*(double*)addr
);
624 case MONO_TYPE_STRING
: {
625 MonoString
*str_obj
= *(MonoString
**)addr
;
627 mono_wasm_add_string_var (NULL
);
629 char *str
= mono_string_to_utf8_checked_internal (str_obj
, error
);
630 mono_error_assert_ok (error
); /* FIXME report error */
631 mono_wasm_add_string_var (str
);
636 case MONO_TYPE_GENERICINST
:
637 case MONO_TYPE_SZARRAY
:
638 case MONO_TYPE_ARRAY
:
639 case MONO_TYPE_OBJECT
:
640 case MONO_TYPE_CLASS
: {
641 MonoObject
*obj
= *(MonoObject
**)addr
;
643 mono_wasm_add_string_var (NULL
);
646 class_name
= g_string_new ("");
647 if (*(obj
->vtable
->klass
->name_space
)) {
648 g_string_append (class_name
, obj
->vtable
->klass
->name_space
);
649 g_string_append_c (class_name
, '.');
651 g_string_append (class_name
, obj
->vtable
->klass
->name
);
652 if (m_class_get_byval_arg (obj
->vtable
->klass
)->type
== MONO_TYPE_SZARRAY
|| m_class_get_byval_arg (obj
->vtable
->klass
)->type
== MONO_TYPE_ARRAY
)
653 mono_wasm_add_array_var (class_name
->str
, get_object_id(obj
));
655 mono_wasm_add_obj_var (class_name
->str
, get_object_id(obj
));
656 g_string_free(class_name
, FALSE
);
662 char *type_name
= mono_type_full_name (type
);
663 char *msg
= g_strdup_printf("can't handle type %s [%p, %x]", type_name
, type
, type
->type
);
664 mono_wasm_add_string_var (msg
);
673 describe_object_properties (guint64 objectId
, gboolean isAsyncLocalThis
)
679 MonoMethodSignature
*sig
;
680 gpointer iter
= NULL
;
682 DEBUG_PRINTF (2, "describe_object_properties %d\n", objectId
);
683 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
685 DEBUG_PRINTF (2, "describe_object_properties !ref\n");
689 MonoObject
*obj
= mono_gchandle_get_target_internal (ref
->handle
);
691 DEBUG_PRINTF (2, "describe_object_properties !obj\n");
695 while (obj
&& (f
= mono_class_get_fields_internal (obj
->vtable
->klass
, &iter
))) {
696 DEBUG_PRINTF (2, "mono_class_get_fields_internal - %s - %x\n", f
->name
, f
->type
->type
);
697 if (isAsyncLocalThis
&& (f
->name
[0] != '<' || (f
->name
[0] == '<' && f
->name
[1] == '>'))) {
700 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
702 if (mono_field_is_deleted (f
))
704 mono_wasm_add_properties_var(f
->name
);
705 gpointer field_value
= (guint8
*)obj
+ f
->offset
;
707 describe_value(f
->type
, field_value
);
711 while ((p
= mono_class_get_properties (obj
->vtable
->klass
, &iter
))) {
712 DEBUG_PRINTF (2, "mono_class_get_properties - %s - %s\n", p
->name
, p
->get
->name
);
713 if (p
->get
->name
) { //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug
714 if (isAsyncLocalThis
&& (p
->name
[0] != '<' || (p
->name
[0] == '<' && p
->name
[1] == '>'))) {
717 mono_wasm_add_properties_var(p
->name
);
718 sig
= mono_method_signature_internal (p
->get
);
719 res
= mono_runtime_try_invoke (p
->get
, obj
, NULL
, &exc
, error
);
720 if (!mono_error_ok (error
) && exc
== NULL
)
721 exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
723 describe_value (mono_get_object_type (), &exc
);
724 else if (!m_class_is_valuetype (mono_object_class (res
)))
725 describe_value(sig
->ret
, &res
);
727 describe_value(sig
->ret
, mono_object_unbox_internal (res
));
735 describe_array_values (guint64 objectId
)
739 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
743 MonoArray
*arr
= (MonoArray
*)mono_gchandle_get_target_internal (ref
->handle
);
744 MonoObject
*obj
= &arr
->obj
;
748 esize
= mono_array_element_size (obj
->vtable
->klass
);
749 for (int i
= 0; i
< arr
->max_length
; i
++) {
750 mono_wasm_add_array_item(i
);
751 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
752 describe_value(m_class_get_byval_arg (m_class_get_element_class (arr
->obj
.vtable
->klass
)), elem
);
758 describe_async_method_locals (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
760 //Async methods are special in the way that local variables can be lifted to generated class fields
761 FrameDescData
*data
= (FrameDescData
*)ud
;
764 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
768 if (data
->cur_frame
< data
->target_frame
) {
773 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
775 MonoMethod
*method
= frame
->imethod
->method
;
777 gpointer addr
= NULL
;
778 if (mono_debug_lookup_method_async_debug_info (method
)) {
779 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
780 MonoObject
*obj
= *(MonoObject
**)addr
;
781 describe_object_properties(get_object_id(obj
), TRUE
);
787 describe_this (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
789 //Async methods are special in the way that local variables can be lifted to generated class fields
790 FrameDescData
*data
= (FrameDescData
*)ud
;
793 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
797 if (data
->cur_frame
< data
->target_frame
) {
802 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
804 MonoMethod
*method
= frame
->imethod
->method
;
806 gpointer addr
= NULL
;
807 if (mono_method_signature_internal (method
)->hasthis
) {
808 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
809 MonoObject
*obj
= *(MonoObject
**)addr
;
810 mono_wasm_add_properties_var("this");
812 class_name
= g_string_new ("");
813 if (*(obj
->vtable
->klass
->name_space
)) {
814 g_string_append (class_name
, obj
->vtable
->klass
->name_space
);
815 g_string_append_c (class_name
, '.');
817 g_string_append (class_name
, obj
->vtable
->klass
->name
);
818 mono_wasm_add_obj_var (class_name
->str
, get_object_id(obj
));
819 g_string_free(class_name
, FALSE
);
826 describe_variable (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
829 MonoMethodHeader
*header
= NULL
;
831 FrameDescData
*data
= (FrameDescData
*)ud
;
834 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
838 if (data
->cur_frame
< data
->target_frame
) {
843 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
845 MonoMethod
*method
= frame
->imethod
->method
;
848 MonoType
*type
= NULL
;
849 gpointer addr
= NULL
;
850 int pos
= data
->variable
;
853 type
= mono_method_signature_internal (method
)->params
[pos
];
854 addr
= mini_get_interp_callbacks ()->frame_get_arg (frame
, pos
);
856 header
= mono_method_get_header_checked (method
, error
);
857 mono_error_assert_ok (error
); /* FIXME report error */
859 type
= header
->locals
[pos
];
860 addr
= mini_get_interp_callbacks ()->frame_get_local (frame
, pos
);
863 DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr
, type
, mono_type_full_name (type
));
865 describe_value(type
, addr
);
867 mono_metadata_free_mh (header
);
872 //FIXME this doesn't support getting the return value pseudo-var
873 EMSCRIPTEN_KEEPALIVE
void
874 mono_wasm_get_var_info (int scope
, int* pos
, int len
)
878 data
.target_frame
= scope
;
879 for (int i
= 0; i
< len
; i
++)
881 DEBUG_PRINTF (2, "getting var %d of scope %d - %d\n", pos
[i
], scope
, len
);
882 data
.variable
= pos
[i
];
883 mono_walk_stack_with_ctx (describe_variable
, NULL
, MONO_UNWIND_NONE
, &data
);
885 mono_walk_stack_with_ctx (describe_async_method_locals
, NULL
, MONO_UNWIND_NONE
, &data
);
886 mono_walk_stack_with_ctx (describe_this
, NULL
, MONO_UNWIND_NONE
, &data
);
889 EMSCRIPTEN_KEEPALIVE
void
890 mono_wasm_get_object_properties (int object_id
)
892 DEBUG_PRINTF (2, "getting properties of object %d\n", object_id
);
894 describe_object_properties(object_id
, FALSE
);
897 EMSCRIPTEN_KEEPALIVE
void
898 mono_wasm_get_array_values (int object_id
)
900 DEBUG_PRINTF (2, "getting array values %d\n", object_id
);
902 describe_array_values(object_id
);
905 // Functions required by debugger-state-machine.
907 mono_debugger_tls_thread_id (DebuggerTlsData
*debuggerTlsData
)
915 mono_wasm_single_step_hit (void)
920 mono_wasm_breakpoint_hit (void)
925 mono_wasm_debugger_init (void)