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
);
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_int_var (gint32
);
41 extern void mono_wasm_add_long_var (gint64
);
42 extern void mono_wasm_add_float_var (float);
43 extern void mono_wasm_add_double_var (double);
44 extern void mono_wasm_add_string_var (const char*);
45 extern void mono_wasm_add_obj_var (const char*, guint64
);
46 extern void mono_wasm_add_array_var (const char*, guint64
);
47 extern void mono_wasm_add_properties_var (const char*);
48 extern void mono_wasm_add_array_item (int);
52 //FIXME move all of those fields to the profiler object
53 static gboolean debugger_enabled
;
55 static int event_request_id
;
56 static GHashTable
*objrefs
;
57 static GHashTable
*obj_to_objref
;
58 static int objref_id
= 0;
60 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
63 inplace_tolower (char *c
)
66 for (i
= strlen (c
) - 1; i
>= 0; --i
)
67 c
[i
] = tolower (c
[i
]);
71 jit_done (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
73 mono_de_add_pending_breakpoints (method
, jinfo
);
77 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
)
79 mono_de_domain_add (domain
);
82 /* Frame state handling */
83 static GPtrArray
*frames
;
86 free_frame (DbgEngineStackFrame
*frame
)
92 collect_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
98 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
102 method
= jinfo_get_method (info
->ji
);
104 method
= info
->method
;
109 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
111 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
112 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
114 DbgEngineStackFrame
*frame
= g_new0 (DbgEngineStackFrame
, 1);
116 frame
->ji
= info
->ji
;
117 frame
->domain
= info
->domain
;
118 frame
->method
= method
;
119 frame
->native_offset
= info
->native_offset
;
121 g_ptr_array_add (frames
, frame
);
127 free_frame_state (void)
131 for (i
= 0; i
< frames
->len
; ++i
)
132 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
133 g_ptr_array_set_size (frames
, 0);
138 compute_frames (void) {
141 for (i
= 0; i
< frames
->len
; ++i
)
142 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
143 g_ptr_array_set_size (frames
, 0);
145 frames
= g_ptr_array_new ();
148 mono_walk_stack_with_ctx (collect_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
151 tls_get_restore_state (void *tls
)
157 try_process_suspend (void *tls
, MonoContext
*ctx
)
163 begin_breakpoint_processing (void *tls
, MonoContext
*ctx
, MonoJitInfo
*ji
, gboolean from_signal
)
169 begin_single_step_processing (MonoContext
*ctx
, gboolean from_signal
)
174 ss_discard_frame_context (void *the_tls
)
180 ss_calculate_framecount (void *tls
, MonoContext
*ctx
, gboolean force_use_ctx
, DbgEngineStackFrame
***out_frames
, int *nframes
)
184 *out_frames
= (DbgEngineStackFrame
**)frames
->pdata
;
186 *nframes
= frames
->len
;
190 ensure_jit (DbgEngineStackFrame
* the_frame
)
196 ensure_runtime_is_suspended (void)
202 get_this_async_id (DbgEngineStackFrame
*f
)
204 g_error ("get_this_async_id");
209 set_set_notification_for_wait_completion_flag (DbgEngineStackFrame
*f
)
211 g_error ("set_set_notification_for_wait_completion_flag");
216 get_notify_debugger_of_wait_completion_method (void)
218 g_error ("get_notify_debugger_of_wait_completion_method");
222 gboolean is_ss
; //do I need this?
226 create_breakpoint_events (GPtrArray
*ss_reqs
, GPtrArray
*bp_reqs
, MonoJitInfo
*ji
, EventKind kind
)
228 printf ("ss_reqs %d bp_reqs %d\n", ss_reqs
->len
, bp_reqs
->len
);
229 if ((ss_reqs
&& ss_reqs
->len
) || (bp_reqs
&& bp_reqs
->len
)) {
230 BpEvents
*evts
= g_new0 (BpEvents
, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events
231 evts
->is_ss
= (ss_reqs
&& ss_reqs
->len
);
238 process_breakpoint_events (void *_evts
, MonoMethod
*method
, MonoContext
*ctx
, int il_offsets
)
240 BpEvents
*evts
= (BpEvents
*)_evts
;
243 mono_de_cancel_ss ();
244 mono_wasm_fire_bp ();
250 no_seq_points_found (MonoMethod
*method
, int offset
)
253 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
255 printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method
, TRUE
), offset
);
258 #define DBG_NOT_SUSPENDED 1
261 ss_create_init_args (SingleStepReq
*ss_req
, SingleStepArgs
*ss_args
)
263 printf ("ss_create_init_args\n");
265 ss_req
->start_sp
= ss_req
->last_sp
= &dummy
;
267 memset (ss_args
, 0, sizeof (*ss_args
));
269 //BIG WTF, should not happen maybe should assert?
270 if (frames
->len
== 0) {
271 DEBUG_PRINTF (1, "SINGLE STEPPING FOUND NO FRAMES");
272 return DBG_NOT_SUSPENDED
;
275 DbgEngineStackFrame
*frame
= (DbgEngineStackFrame
*)g_ptr_array_index (frames
, 0);
276 ss_req
->start_method
= ss_args
->method
= frame
->method
;
277 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &ss_args
->info
, &ss_args
->sp
);
279 no_seq_points_found (frame
->method
, frame
->native_offset
);
282 ss_args
->frames
= (DbgEngineStackFrame
**)frames
->pdata
;
283 ss_args
->nframes
= frames
->len
;
290 ss_args_destroy (SingleStepArgs
*ss_args
)
296 mono_wasm_debugger_init (void)
298 if (!debugger_enabled
)
301 DebuggerEngineCallbacks cbs
= {
302 .tls_get_restore_state
= tls_get_restore_state
,
303 .try_process_suspend
= try_process_suspend
,
304 .begin_breakpoint_processing
= begin_breakpoint_processing
,
305 .begin_single_step_processing
= begin_single_step_processing
,
306 .ss_discard_frame_context
= ss_discard_frame_context
,
307 .ss_calculate_framecount
= ss_calculate_framecount
,
308 .ensure_jit
= ensure_jit
,
309 .ensure_runtime_is_suspended
= ensure_runtime_is_suspended
,
310 .get_this_async_id
= get_this_async_id
,
311 .set_set_notification_for_wait_completion_flag
= set_set_notification_for_wait_completion_flag
,
312 .get_notify_debugger_of_wait_completion_method
= get_notify_debugger_of_wait_completion_method
,
313 .create_breakpoint_events
= create_breakpoint_events
,
314 .process_breakpoint_events
= process_breakpoint_events
,
315 .ss_create_init_args
= ss_create_init_args
,
316 .ss_args_destroy
= ss_args_destroy
,
319 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
321 mono_de_set_log_level (1, stdout
);
323 mini_get_debug_options ()->gen_sdb_seq_points
= TRUE
;
324 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
325 mono_disable_optimizations (MONO_OPT_LINEARS
);
326 mini_get_debug_options ()->load_aot_jit_info_eagerly
= TRUE
;
328 MonoProfilerHandle prof
= mono_profiler_create (NULL
);
329 mono_profiler_set_jit_done_callback (prof
, jit_done
);
330 //FIXME support multiple appdomains
331 mono_profiler_set_domain_loaded_callback (prof
, appdomain_load
);
333 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
334 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, mono_debugger_free_objref
);
338 mono_wasm_enable_debugging (void)
340 DEBUG_PRINTF (1, "DEBUGGING ENABLED\n");
341 debugger_enabled
= TRUE
;
344 EMSCRIPTEN_KEEPALIVE
void
345 mono_wasm_setup_single_step (int kind
)
349 printf (">>>> mono_wasm_setup_single_step %d\n", kind
);
350 EventRequest
*req
= (EventRequest
*)g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
351 req
->id
= ++event_request_id
;
352 req
->event_kind
= EVENT_KIND_STEP
;
353 // DE doesn't care about suspend_policy
354 // req->suspend_policy = SUSPEND_POLICY_ALL;
355 req
->nmodifiers
= nmodifiers
;
357 StepSize size
= STEP_SIZE_MIN
;
359 //FIXME I DON'T KNOW WHAT I'M DOING!!!!! filter all the things.
360 StepFilter filter
= (StepFilter
)(STEP_FILTER_STATIC_CTOR
| STEP_FILTER_DEBUGGER_HIDDEN
| STEP_FILTER_DEBUGGER_STEP_THROUGH
| STEP_FILTER_DEBUGGER_NON_USER_CODE
);
361 req
->modifiers
[0].data
.filter
= filter
;
366 depth
= STEP_DEPTH_INTO
;
369 depth
= STEP_DEPTH_OUT
;
372 depth
= STEP_DEPTH_OVER
;
375 g_error ("dunno step kind %d", kind
);
378 DbgEngineErrorCode err
= mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size
, depth
, filter
, req
);
379 if (err
!= DE_ERR_NONE
) {
380 DEBUG_PRINTF (1, "[dbg] Failed to setup single step request");
382 printf ("ss is in place, now ahat?\n");
385 EMSCRIPTEN_KEEPALIVE
void
386 mono_wasm_clear_all_breakpoints (void)
388 DEBUG_PRINTF (1, "CLEAR BREAKPOINTS\n");
389 mono_de_clear_all_breakpoints ();
392 EMSCRIPTEN_KEEPALIVE
int
393 mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
)
397 DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name
, method_token
, il_offset
);
400 //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot
401 char *lookup_name
= g_strdup (assembly_name
);
402 for (i
= strlen (lookup_name
) - 1; i
>= 0; --i
) {
403 if (lookup_name
[i
] == '.') {
409 //resolve the assembly
410 MonoImageOpenStatus status
;
411 MonoAssemblyName
* aname
= mono_assembly_name_new (lookup_name
);
412 MonoAssembly
*assembly
= mono_assembly_load (aname
, NULL
, &status
);
413 g_free (lookup_name
);
415 DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name
);
419 mono_assembly_name_free (aname
);
421 MonoMethod
*method
= mono_get_method_checked (assembly
->image
, MONO_TOKEN_METHOD_DEF
| method_token
, NULL
, NULL
, error
);
423 //FIXME don't swallow the error
424 DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error
));
425 mono_error_cleanup (error
);
429 //FIXME right now none of the EventRequest fields are used by debugger-engine
430 EventRequest
*req
= g_new0 (EventRequest
, 1);
431 req
->id
= ++event_request_id
;
432 req
->event_kind
= EVENT_KIND_BREAKPOINT
;
433 //DE doesn't care about suspend_policy
434 // req->suspend_policy = SUSPEND_POLICY_ALL;
435 req
->nmodifiers
= 0; //funny thing,
437 // BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset);
438 MonoBreakpoint
*bp
= mono_de_set_breakpoint (method
, il_offset
, req
, error
);
441 DEBUG_PRINTF (1, "Could not set breakpoint to %s\n", mono_error_get_message (error
));
442 mono_error_cleanup (error
);
446 DEBUG_PRINTF (1, "NEW BP %p has id %d\n", req
, req
->id
);
450 EMSCRIPTEN_KEEPALIVE
int
451 mono_wasm_remove_breakpoint (int bp_id
)
453 MonoBreakpoint
*bp
= mono_de_get_breakpoint_by_id (bp_id
);
457 mono_de_clear_breakpoint (bp
);
462 mono_wasm_single_step_hit (void)
464 mono_de_process_single_step (NULL
, FALSE
);
468 mono_wasm_breakpoint_hit (void)
470 mono_de_process_breakpoint (NULL
, FALSE
);
471 // mono_wasm_fire_bp ();
474 EMSCRIPTEN_KEEPALIVE
int
475 mono_wasm_current_bp_id (void)
477 DEBUG_PRINTF (1, "COMPUTING breapoint ID\n");
478 //FIXME handle compiled case
481 MonoLMF
*lmf
= mono_get_lmf ();
483 g_assert (((guint64
)lmf
->previous_lmf
) & 2);
484 MonoLMFExt
*ext
= (MonoLMFExt
*)lmf
;
486 g_assert (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
);
487 MonoInterpFrameHandle
*frame
= (MonoInterpFrameHandle
*)ext
->interp_exit_data
;
488 MonoJitInfo
*ji
= mini_get_interp_callbacks ()->frame_get_jit_info (frame
);
489 guint8
*ip
= (guint8
*)mini_get_interp_callbacks ()->frame_get_ip (frame
);
491 g_assert (ji
&& !ji
->is_trampoline
);
492 MonoMethod
*method
= jinfo_get_method (ji
);
494 /* Compute the native offset of the breakpoint from the ip */
495 guint32 native_offset
= ip
- (guint8
*)ji
->code_start
;
497 MonoSeqPointInfo
*info
= NULL
;
499 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
, &sp
);
501 DEBUG_PRINTF (1, "Could not find SP\n");
504 GPtrArray
*bp_reqs
= g_ptr_array_new ();
505 mono_de_collect_breakpoints_by_sp (&sp
, ji
, NULL
, bp_reqs
);
507 if (bp_reqs
->len
== 0) {
508 DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method
->name
, ji
, sp
.il_offset
);
512 if (bp_reqs
->len
> 1)
513 DEBUG_PRINTF (1, "Multiple breakpoints (%d) at the same location, returning the first one.", bp_reqs
->len
);
515 EventRequest
*evt
= (EventRequest
*)g_ptr_array_index (bp_reqs
, 0);
516 g_ptr_array_free (bp_reqs
, TRUE
);
518 DEBUG_PRINTF (1, "Found BP %p with id %d\n", evt
, evt
->id
);
522 static int get_object_id(MonoObject
*obj
)
524 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
527 ref
= g_new0 (ObjRef
, 1);
528 ref
->id
= mono_atomic_inc_i32 (&objref_id
);
529 ref
->handle
= mono_gchandle_new_weakref_internal (obj
, FALSE
);
530 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
531 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
536 list_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
542 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
547 method
= jinfo_get_method (info
->ji
);
549 method
= info
->method
;
554 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
556 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
557 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
559 while (method
->is_inflated
)
560 method
= ((MonoMethodInflated
*)method
)->declaring
;
562 char *assembly_name
= g_strdup (m_class_get_image (method
->klass
)->module_name
);
563 inplace_tolower (assembly_name
);
565 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
566 DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
567 mono_wasm_add_frame (sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
570 g_free (assembly_name
);
575 EMSCRIPTEN_KEEPALIVE
void
576 mono_wasm_enum_frames (void)
578 mono_walk_stack_with_ctx (list_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
587 static gboolean
describe_value(MonoType
* type
, gpointer addr
)
590 switch (type
->type
) {
591 case MONO_TYPE_BOOLEAN
:
592 mono_wasm_add_bool_var (*(gint8
*)addr
);
596 mono_wasm_add_int_var (*(gint8
*)addr
);
601 mono_wasm_add_int_var (*(gint16
*)addr
);
607 mono_wasm_add_int_var (*(gint32
*)addr
);
611 mono_wasm_add_long_var (*(gint32
*)addr
);
614 mono_wasm_add_float_var (*(float*)addr
);
617 mono_wasm_add_float_var (*(double*)addr
);
619 case MONO_TYPE_STRING
: {
620 MonoString
*str_obj
= *(MonoString
**)addr
;
622 mono_wasm_add_string_var (NULL
);
624 char *str
= mono_string_to_utf8_checked_internal (str_obj
, error
);
625 mono_error_assert_ok (error
); /* FIXME report error */
626 mono_wasm_add_string_var (str
);
631 case MONO_TYPE_GENERICINST
:
632 case MONO_TYPE_SZARRAY
:
633 case MONO_TYPE_ARRAY
:
634 case MONO_TYPE_OBJECT
:
635 case MONO_TYPE_CLASS
: {
636 MonoObject
*obj
= *(MonoObject
**)addr
;
638 mono_wasm_add_string_var (NULL
);
641 class_name
= g_string_new ("");
642 if (*(obj
->vtable
->klass
->name_space
)) {
643 g_string_append (class_name
, obj
->vtable
->klass
->name_space
);
644 g_string_append_c (class_name
, '.');
646 g_string_append (class_name
, obj
->vtable
->klass
->name
);
647 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
)
648 mono_wasm_add_array_var (class_name
->str
, get_object_id(obj
));
650 mono_wasm_add_obj_var (class_name
->str
, get_object_id(obj
));
651 g_string_free(class_name
, FALSE
);
657 char *type_name
= mono_type_full_name (type
);
658 char *msg
= g_strdup_printf("can't handle type %s [%p, %x]", type_name
, type
, type
->type
);
659 mono_wasm_add_string_var (msg
);
668 describe_object_properties (guint64 objectId
)
674 MonoMethodSignature
*sig
;
675 gpointer iter
= NULL
;
677 DEBUG_PRINTF (2, "describe_object_properties %d\n", objectId
);
678 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
680 DEBUG_PRINTF (2, "describe_object_properties !ref\n");
684 MonoObject
*obj
= mono_gchandle_get_target_internal (ref
->handle
);
686 DEBUG_PRINTF (2, "describe_object_properties !obj\n");
690 while (obj
&& (f
= mono_class_get_fields_internal (obj
->vtable
->klass
, &iter
))) {
691 DEBUG_PRINTF (2, "mono_class_get_fields_internal - %s - %x\n", f
->name
, f
->type
->type
);
692 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
694 if (mono_field_is_deleted (f
))
696 mono_wasm_add_properties_var(f
->name
);
697 gpointer field_value
= (guint8
*)obj
+ f
->offset
;
699 describe_value(f
->type
, field_value
);
703 while ((p
= mono_class_get_properties (obj
->vtable
->klass
, &iter
))) {
704 DEBUG_PRINTF (2, "mono_class_get_properties - %s - %s\n", p
->name
, p
->get
->name
);
705 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
706 mono_wasm_add_properties_var(p
->name
);
707 sig
= mono_method_signature_internal (p
->get
);
708 res
= mono_runtime_try_invoke (p
->get
, obj
, NULL
, &exc
, error
);
709 if (!mono_error_ok (error
) && exc
== NULL
)
710 exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
712 describe_value (mono_get_object_type (), &exc
);
713 else if (!m_class_is_valuetype (mono_object_class (res
)))
714 describe_value(sig
->ret
, &res
);
716 describe_value(sig
->ret
, mono_object_unbox_internal (res
));
724 describe_array_values (guint64 objectId
)
728 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
732 MonoArray
*arr
= (MonoArray
*)mono_gchandle_get_target_internal (ref
->handle
);
733 MonoObject
*obj
= &arr
->obj
;
737 esize
= mono_array_element_size (obj
->vtable
->klass
);
738 for (int i
= 0; i
< arr
->max_length
; i
++) {
739 mono_wasm_add_array_item(i
);
740 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
741 describe_value(m_class_get_byval_arg (m_class_get_element_class (arr
->obj
.vtable
->klass
)), elem
);
747 describe_variable (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
750 MonoMethodHeader
*header
= NULL
;
752 FrameDescData
*data
= (FrameDescData
*)ud
;
755 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
759 if (data
->cur_frame
< data
->target_frame
) {
764 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
766 MonoMethod
*method
= frame
->imethod
->method
;
769 MonoType
*type
= NULL
;
770 gpointer addr
= NULL
;
771 int pos
= data
->variable
;
774 type
= mono_method_signature_internal (method
)->params
[pos
];
775 addr
= mini_get_interp_callbacks ()->frame_get_arg (frame
, pos
);
777 header
= mono_method_get_header_checked (method
, error
);
778 mono_error_assert_ok (error
); /* FIXME report error */
780 type
= header
->locals
[pos
];
781 addr
= mini_get_interp_callbacks ()->frame_get_local (frame
, pos
);
784 DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr
, type
, mono_type_full_name (type
));
786 describe_value(type
, addr
);
788 mono_metadata_free_mh (header
);
793 //FIXME this doesn't support getting the return value pseudo-var
794 EMSCRIPTEN_KEEPALIVE
void
795 mono_wasm_get_var_info (int scope
, int pos
)
797 DEBUG_PRINTF (2, "getting var %d of scope %d\n", pos
, scope
);
801 data
.target_frame
= scope
;
804 mono_walk_stack_with_ctx (describe_variable
, NULL
, MONO_UNWIND_NONE
, &data
);
807 EMSCRIPTEN_KEEPALIVE
void
808 mono_wasm_get_object_properties (int object_id
)
810 DEBUG_PRINTF (2, "getting properties of object %d\n", object_id
);
812 describe_object_properties(object_id
);
815 EMSCRIPTEN_KEEPALIVE
void
816 mono_wasm_get_array_values (int object_id
)
818 DEBUG_PRINTF (2, "getting array values %d\n", object_id
);
820 describe_array_values(object_id
);
823 // Functions required by debugger-state-machine.
825 mono_debugger_tls_thread_id (DebuggerTlsData
*debuggerTlsData
)
833 mono_wasm_single_step_hit (void)
838 mono_wasm_breakpoint_hit (void)
843 mono_wasm_debugger_init (void)