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>
18 #include "mono/metadata/assembly-internals.h"
20 static int log_level
= 1;
22 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (stdout, __VA_ARGS__); } } while (0)
24 //functions exported to be used by JS
27 EMSCRIPTEN_KEEPALIVE
int mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
);
28 EMSCRIPTEN_KEEPALIVE
int mono_wasm_remove_breakpoint (int bp_id
);
29 EMSCRIPTEN_KEEPALIVE
int mono_wasm_current_bp_id (void);
30 EMSCRIPTEN_KEEPALIVE
void mono_wasm_enum_frames (void);
31 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_var_info (int scope
, int* pos
, int len
);
32 EMSCRIPTEN_KEEPALIVE
void mono_wasm_clear_all_breakpoints (void);
33 EMSCRIPTEN_KEEPALIVE
void mono_wasm_setup_single_step (int kind
);
34 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_object_properties (int object_id
);
35 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_array_values (int object_id
);
37 //JS functions imported that we use
38 extern void mono_wasm_add_frame (int il_offset
, int method_token
, const char *assembly_name
);
39 extern void mono_wasm_fire_bp (void);
40 extern void mono_wasm_add_bool_var (gint8
);
41 extern void mono_wasm_add_number_var (double);
42 extern void mono_wasm_add_string_var (const char*);
43 extern void mono_wasm_add_obj_var (const char*, guint64
);
44 extern void mono_wasm_add_array_var (const char*, guint64
);
45 extern void mono_wasm_add_properties_var (const char*);
46 extern void mono_wasm_add_array_item (int);
50 //FIXME move all of those fields to the profiler object
51 static gboolean debugger_enabled
;
53 static int event_request_id
;
54 static GHashTable
*objrefs
;
55 static GHashTable
*obj_to_objref
;
56 static int objref_id
= 0;
58 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
61 inplace_tolower (char *c
)
64 for (i
= strlen (c
) - 1; i
>= 0; --i
)
65 c
[i
] = tolower (c
[i
]);
69 jit_done (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
71 mono_de_add_pending_breakpoints (method
, jinfo
);
75 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
)
77 mono_de_domain_add (domain
);
80 /* Frame state handling */
81 static GPtrArray
*frames
;
84 free_frame (DbgEngineStackFrame
*frame
)
90 collect_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
96 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
100 method
= jinfo_get_method (info
->ji
);
102 method
= info
->method
;
107 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
109 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
110 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
112 DbgEngineStackFrame
*frame
= g_new0 (DbgEngineStackFrame
, 1);
114 frame
->ji
= info
->ji
;
115 frame
->domain
= info
->domain
;
116 frame
->method
= method
;
117 frame
->native_offset
= info
->native_offset
;
119 g_ptr_array_add (frames
, frame
);
125 free_frame_state (void)
129 for (i
= 0; i
< frames
->len
; ++i
)
130 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
131 g_ptr_array_set_size (frames
, 0);
136 compute_frames (void) {
139 for (i
= 0; i
< frames
->len
; ++i
)
140 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
141 g_ptr_array_set_size (frames
, 0);
143 frames
= g_ptr_array_new ();
146 mono_walk_stack_with_ctx (collect_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
149 tls_get_restore_state (void *tls
)
155 try_process_suspend (void *tls
, MonoContext
*ctx
)
161 begin_breakpoint_processing (void *tls
, MonoContext
*ctx
, MonoJitInfo
*ji
, gboolean from_signal
)
167 begin_single_step_processing (MonoContext
*ctx
, gboolean from_signal
)
172 ss_discard_frame_context (void *the_tls
)
178 ss_calculate_framecount (void *tls
, MonoContext
*ctx
, gboolean force_use_ctx
, DbgEngineStackFrame
***out_frames
, int *nframes
)
182 *out_frames
= (DbgEngineStackFrame
**)frames
->pdata
;
184 *nframes
= frames
->len
;
188 ensure_jit (DbgEngineStackFrame
* the_frame
)
194 ensure_runtime_is_suspended (void)
200 get_this_async_id (DbgEngineStackFrame
*f
)
202 g_error ("get_this_async_id");
207 set_set_notification_for_wait_completion_flag (DbgEngineStackFrame
*f
)
209 g_error ("set_set_notification_for_wait_completion_flag");
214 get_notify_debugger_of_wait_completion_method (void)
216 g_error ("get_notify_debugger_of_wait_completion_method");
220 gboolean is_ss
; //do I need this?
224 create_breakpoint_events (GPtrArray
*ss_reqs
, GPtrArray
*bp_reqs
, MonoJitInfo
*ji
, EventKind kind
)
226 printf ("ss_reqs %d bp_reqs %d\n", ss_reqs
->len
, bp_reqs
->len
);
227 if ((ss_reqs
&& ss_reqs
->len
) || (bp_reqs
&& bp_reqs
->len
)) {
228 BpEvents
*evts
= g_new0 (BpEvents
, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events
229 evts
->is_ss
= (ss_reqs
&& ss_reqs
->len
);
236 process_breakpoint_events (void *_evts
, MonoMethod
*method
, MonoContext
*ctx
, int il_offsets
)
238 BpEvents
*evts
= (BpEvents
*)_evts
;
241 mono_de_cancel_ss ();
242 mono_wasm_fire_bp ();
248 no_seq_points_found (MonoMethod
*method
, int offset
)
251 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
253 printf ("Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method
, TRUE
), offset
);
256 #define DBG_NOT_SUSPENDED 1
259 ss_create_init_args (SingleStepReq
*ss_req
, SingleStepArgs
*ss_args
)
261 printf ("ss_create_init_args\n");
263 ss_req
->start_sp
= ss_req
->last_sp
= &dummy
;
265 memset (ss_args
, 0, sizeof (*ss_args
));
267 //BIG WTF, should not happen maybe should assert?
268 if (frames
->len
== 0) {
269 DEBUG_PRINTF (1, "SINGLE STEPPING FOUND NO FRAMES");
270 return DBG_NOT_SUSPENDED
;
273 DbgEngineStackFrame
*frame
= (DbgEngineStackFrame
*)g_ptr_array_index (frames
, 0);
274 ss_req
->start_method
= ss_args
->method
= frame
->method
;
275 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &ss_args
->info
, &ss_args
->sp
);
277 no_seq_points_found (frame
->method
, frame
->native_offset
);
280 ss_args
->frames
= (DbgEngineStackFrame
**)frames
->pdata
;
281 ss_args
->nframes
= frames
->len
;
288 ss_args_destroy (SingleStepArgs
*ss_args
)
294 mono_wasm_debugger_init (void)
296 if (!debugger_enabled
)
299 DebuggerEngineCallbacks cbs
= {
300 .tls_get_restore_state
= tls_get_restore_state
,
301 .try_process_suspend
= try_process_suspend
,
302 .begin_breakpoint_processing
= begin_breakpoint_processing
,
303 .begin_single_step_processing
= begin_single_step_processing
,
304 .ss_discard_frame_context
= ss_discard_frame_context
,
305 .ss_calculate_framecount
= ss_calculate_framecount
,
306 .ensure_jit
= ensure_jit
,
307 .ensure_runtime_is_suspended
= ensure_runtime_is_suspended
,
308 .get_this_async_id
= get_this_async_id
,
309 .set_set_notification_for_wait_completion_flag
= set_set_notification_for_wait_completion_flag
,
310 .get_notify_debugger_of_wait_completion_method
= get_notify_debugger_of_wait_completion_method
,
311 .create_breakpoint_events
= create_breakpoint_events
,
312 .process_breakpoint_events
= process_breakpoint_events
,
313 .ss_create_init_args
= ss_create_init_args
,
314 .ss_args_destroy
= ss_args_destroy
,
317 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
319 mono_de_set_log_level (1, stdout
);
321 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
322 mini_debug_options
.mdb_optimizations
= TRUE
;
323 mono_disable_optimizations (MONO_OPT_LINEARS
);
324 mini_debug_options
.load_aot_jit_info_eagerly
= TRUE
;
326 MonoProfilerHandle prof
= mono_profiler_create (NULL
);
327 mono_profiler_set_jit_done_callback (prof
, jit_done
);
328 //FIXME support multiple appdomains
329 mono_profiler_set_domain_loaded_callback (prof
, appdomain_load
);
331 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
332 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, mono_debugger_free_objref
);
336 mono_wasm_enable_debugging (void)
338 DEBUG_PRINTF (1, "DEBUGGING ENABLED\n");
339 debugger_enabled
= TRUE
;
342 EMSCRIPTEN_KEEPALIVE
void
343 mono_wasm_setup_single_step (int kind
)
347 printf (">>>> mono_wasm_setup_single_step %d\n", kind
);
348 EventRequest
*req
= (EventRequest
*)g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
349 req
->id
= ++event_request_id
;
350 req
->event_kind
= EVENT_KIND_STEP
;
351 // DE doesn't care about suspend_policy
352 // req->suspend_policy = SUSPEND_POLICY_ALL;
353 req
->nmodifiers
= nmodifiers
;
355 StepSize size
= STEP_SIZE_MIN
;
357 //FIXME I DON'T KNOW WHAT I'M DOING!!!!! filter all the things.
358 StepFilter filter
= (StepFilter
)(STEP_FILTER_STATIC_CTOR
| STEP_FILTER_DEBUGGER_HIDDEN
| STEP_FILTER_DEBUGGER_STEP_THROUGH
| STEP_FILTER_DEBUGGER_NON_USER_CODE
);
359 req
->modifiers
[0].data
.filter
= filter
;
364 depth
= STEP_DEPTH_INTO
;
367 depth
= STEP_DEPTH_OUT
;
370 depth
= STEP_DEPTH_OVER
;
373 g_error ("dunno step kind %d", kind
);
376 DbgEngineErrorCode err
= mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size
, depth
, filter
, req
);
377 if (err
!= DE_ERR_NONE
) {
378 DEBUG_PRINTF (1, "[dbg] Failed to setup single step request");
380 printf ("ss is in place, now ahat?\n");
383 EMSCRIPTEN_KEEPALIVE
void
384 mono_wasm_clear_all_breakpoints (void)
386 DEBUG_PRINTF (1, "CLEAR BREAKPOINTS\n");
387 mono_de_clear_all_breakpoints ();
390 EMSCRIPTEN_KEEPALIVE
int
391 mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
)
395 DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name
, method_token
, il_offset
);
398 //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot
399 char *lookup_name
= g_strdup (assembly_name
);
400 for (i
= strlen (lookup_name
) - 1; i
>= 0; --i
) {
401 if (lookup_name
[i
] == '.') {
407 //resolve the assembly
408 MonoImageOpenStatus status
;
409 MonoAssemblyName
* aname
= mono_assembly_name_new (lookup_name
);
410 MonoAssembly
*assembly
= mono_assembly_load (aname
, NULL
, &status
);
411 g_free (lookup_name
);
413 DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name
);
417 mono_assembly_name_free_internal (aname
);
419 MonoMethod
*method
= mono_get_method_checked (assembly
->image
, MONO_TOKEN_METHOD_DEF
| method_token
, NULL
, NULL
, error
);
421 //FIXME don't swallow the error
422 DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error
));
423 mono_error_cleanup (error
);
427 //FIXME right now none of the EventRequest fields are used by debugger-engine
428 EventRequest
*req
= g_new0 (EventRequest
, 1);
429 req
->id
= ++event_request_id
;
430 req
->event_kind
= EVENT_KIND_BREAKPOINT
;
431 //DE doesn't care about suspend_policy
432 // req->suspend_policy = SUSPEND_POLICY_ALL;
433 req
->nmodifiers
= 0; //funny thing,
435 // BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset);
436 MonoBreakpoint
*bp
= mono_de_set_breakpoint (method
, il_offset
, req
, error
);
439 DEBUG_PRINTF (1, "Could not set breakpoint to %s\n", mono_error_get_message (error
));
440 mono_error_cleanup (error
);
444 DEBUG_PRINTF (1, "NEW BP %p has id %d\n", req
, req
->id
);
448 EMSCRIPTEN_KEEPALIVE
int
449 mono_wasm_remove_breakpoint (int bp_id
)
451 MonoBreakpoint
*bp
= mono_de_get_breakpoint_by_id (bp_id
);
455 mono_de_clear_breakpoint (bp
);
460 mono_wasm_single_step_hit (void)
462 mono_de_process_single_step (NULL
, FALSE
);
466 mono_wasm_breakpoint_hit (void)
468 mono_de_process_breakpoint (NULL
, FALSE
);
469 // mono_wasm_fire_bp ();
472 EMSCRIPTEN_KEEPALIVE
int
473 mono_wasm_current_bp_id (void)
475 DEBUG_PRINTF (1, "COMPUTING breapoint ID\n");
476 //FIXME handle compiled case
479 MonoLMF
*lmf
= mono_get_lmf ();
481 g_assert (((guint64
)lmf
->previous_lmf
) & 2);
482 MonoLMFExt
*ext
= (MonoLMFExt
*)lmf
;
484 g_assert (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
);
485 MonoInterpFrameHandle
*frame
= (MonoInterpFrameHandle
*)ext
->interp_exit_data
;
486 MonoJitInfo
*ji
= mini_get_interp_callbacks ()->frame_get_jit_info (frame
);
487 guint8
*ip
= (guint8
*)mini_get_interp_callbacks ()->frame_get_ip (frame
);
489 g_assert (ji
&& !ji
->is_trampoline
);
490 MonoMethod
*method
= jinfo_get_method (ji
);
492 /* Compute the native offset of the breakpoint from the ip */
493 guint32 native_offset
= ip
- (guint8
*)ji
->code_start
;
495 MonoSeqPointInfo
*info
= NULL
;
497 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
, &sp
);
499 DEBUG_PRINTF (1, "Could not find SP\n");
502 GPtrArray
*bp_reqs
= g_ptr_array_new ();
503 mono_de_collect_breakpoints_by_sp (&sp
, ji
, NULL
, bp_reqs
);
505 if (bp_reqs
->len
== 0) {
506 DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method
->name
, ji
, sp
.il_offset
);
510 if (bp_reqs
->len
> 1)
511 DEBUG_PRINTF (1, "Multiple breakpoints (%d) at the same location, returning the first one.", bp_reqs
->len
);
513 EventRequest
*evt
= (EventRequest
*)g_ptr_array_index (bp_reqs
, 0);
514 g_ptr_array_free (bp_reqs
, TRUE
);
516 DEBUG_PRINTF (1, "Found BP %p with id %d\n", evt
, evt
->id
);
520 static int get_object_id(MonoObject
*obj
)
522 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
525 ref
= g_new0 (ObjRef
, 1);
526 ref
->id
= mono_atomic_inc_i32 (&objref_id
);
527 ref
->handle
= mono_gchandle_new_weakref_internal (obj
, FALSE
);
528 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
529 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
534 list_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
540 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
545 method
= jinfo_get_method (info
->ji
);
547 method
= info
->method
;
552 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
554 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
555 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
557 while (method
->is_inflated
)
558 method
= ((MonoMethodInflated
*)method
)->declaring
;
560 char *assembly_name
= g_strdup (m_class_get_image (method
->klass
)->module_name
);
561 inplace_tolower (assembly_name
);
563 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
564 DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
565 mono_wasm_add_frame (sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
568 g_free (assembly_name
);
573 EMSCRIPTEN_KEEPALIVE
void
574 mono_wasm_enum_frames (void)
576 mono_walk_stack_with_ctx (list_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
585 static gboolean
describe_value(MonoType
* type
, gpointer addr
)
588 switch (type
->type
) {
589 case MONO_TYPE_BOOLEAN
:
590 mono_wasm_add_bool_var (*(gint8
*)addr
);
593 mono_wasm_add_number_var (*(gint8
*)addr
);
596 mono_wasm_add_number_var (*(guint8
*)addr
);
600 mono_wasm_add_number_var (*(guint16
*)addr
);
603 mono_wasm_add_number_var (*(gint16
*)addr
);
607 mono_wasm_add_number_var (*(gint32
*)addr
);
611 mono_wasm_add_number_var (*(guint32
*)addr
);
614 mono_wasm_add_number_var (*(gint64
*)addr
);
617 mono_wasm_add_number_var (*(guint64
*)addr
);
620 mono_wasm_add_number_var (*(float*)addr
);
623 mono_wasm_add_number_var (*(double*)addr
);
625 case MONO_TYPE_STRING
: {
626 MonoString
*str_obj
= *(MonoString
**)addr
;
628 mono_wasm_add_string_var (NULL
);
630 char *str
= mono_string_to_utf8_checked_internal (str_obj
, error
);
631 mono_error_assert_ok (error
); /* FIXME report error */
632 mono_wasm_add_string_var (str
);
637 case MONO_TYPE_GENERICINST
:
638 case MONO_TYPE_SZARRAY
:
639 case MONO_TYPE_ARRAY
:
640 case MONO_TYPE_OBJECT
:
641 case MONO_TYPE_CLASS
: {
642 MonoObject
*obj
= *(MonoObject
**)addr
;
644 mono_wasm_add_string_var (NULL
);
647 class_name
= g_string_new ("");
648 if (*(obj
->vtable
->klass
->name_space
)) {
649 g_string_append (class_name
, obj
->vtable
->klass
->name_space
);
650 g_string_append_c (class_name
, '.');
652 g_string_append (class_name
, obj
->vtable
->klass
->name
);
653 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
)
654 mono_wasm_add_array_var (class_name
->str
, get_object_id(obj
));
656 mono_wasm_add_obj_var (class_name
->str
, get_object_id(obj
));
657 g_string_free(class_name
, FALSE
);
663 char *type_name
= mono_type_full_name (type
);
664 char *msg
= g_strdup_printf("can't handle type %s [%p, %x]", type_name
, type
, type
->type
);
665 mono_wasm_add_string_var (msg
);
674 describe_object_properties (guint64 objectId
, gboolean isAsyncLocalThis
)
680 MonoMethodSignature
*sig
;
681 gpointer iter
= NULL
;
683 DEBUG_PRINTF (2, "describe_object_properties %d\n", objectId
);
684 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
686 DEBUG_PRINTF (2, "describe_object_properties !ref\n");
690 MonoObject
*obj
= mono_gchandle_get_target_internal (ref
->handle
);
692 DEBUG_PRINTF (2, "describe_object_properties !obj\n");
696 while (obj
&& (f
= mono_class_get_fields_internal (obj
->vtable
->klass
, &iter
))) {
697 DEBUG_PRINTF (2, "mono_class_get_fields_internal - %s - %x\n", f
->name
, f
->type
->type
);
698 if (isAsyncLocalThis
&& (f
->name
[0] != '<' || (f
->name
[0] == '<' && f
->name
[1] == '>'))) {
701 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
703 if (mono_field_is_deleted (f
))
705 mono_wasm_add_properties_var(f
->name
);
706 gpointer field_value
= (guint8
*)obj
+ f
->offset
;
708 describe_value(f
->type
, field_value
);
712 while ((p
= mono_class_get_properties (obj
->vtable
->klass
, &iter
))) {
713 DEBUG_PRINTF (2, "mono_class_get_properties - %s - %s\n", p
->name
, p
->get
->name
);
714 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
715 if (isAsyncLocalThis
&& (p
->name
[0] != '<' || (p
->name
[0] == '<' && p
->name
[1] == '>'))) {
718 mono_wasm_add_properties_var(p
->name
);
719 sig
= mono_method_signature_internal (p
->get
);
720 res
= mono_runtime_try_invoke (p
->get
, obj
, NULL
, &exc
, error
);
721 if (!is_ok (error
) && exc
== NULL
)
722 exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
724 describe_value (mono_get_object_type (), &exc
);
725 else if (!m_class_is_valuetype (mono_object_class (res
)))
726 describe_value(sig
->ret
, &res
);
728 describe_value(sig
->ret
, mono_object_unbox_internal (res
));
736 describe_array_values (guint64 objectId
)
740 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
744 MonoArray
*arr
= (MonoArray
*)mono_gchandle_get_target_internal (ref
->handle
);
745 MonoObject
*obj
= &arr
->obj
;
749 esize
= mono_array_element_size (obj
->vtable
->klass
);
750 for (int i
= 0; i
< arr
->max_length
; i
++) {
751 mono_wasm_add_array_item(i
);
752 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
753 describe_value(m_class_get_byval_arg (m_class_get_element_class (arr
->obj
.vtable
->klass
)), elem
);
759 describe_async_method_locals (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
761 //Async methods are special in the way that local variables can be lifted to generated class fields
762 FrameDescData
*data
= (FrameDescData
*)ud
;
765 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
769 if (data
->cur_frame
< data
->target_frame
) {
774 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
776 MonoMethod
*method
= frame
->imethod
->method
;
778 gpointer addr
= NULL
;
779 if (mono_debug_lookup_method_async_debug_info (method
)) {
780 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
781 MonoObject
*obj
= *(MonoObject
**)addr
;
782 describe_object_properties(get_object_id(obj
), TRUE
);
788 describe_this (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
790 //Async methods are special in the way that local variables can be lifted to generated class fields
791 FrameDescData
*data
= (FrameDescData
*)ud
;
794 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
798 if (data
->cur_frame
< data
->target_frame
) {
803 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
805 MonoMethod
*method
= frame
->imethod
->method
;
807 gpointer addr
= NULL
;
808 if (mono_method_signature_internal (method
)->hasthis
) {
809 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
810 MonoObject
*obj
= *(MonoObject
**)addr
;
811 mono_wasm_add_properties_var("this");
813 class_name
= g_string_new ("");
814 if (*(obj
->vtable
->klass
->name_space
)) {
815 g_string_append (class_name
, obj
->vtable
->klass
->name_space
);
816 g_string_append_c (class_name
, '.');
818 g_string_append (class_name
, obj
->vtable
->klass
->name
);
819 mono_wasm_add_obj_var (class_name
->str
, get_object_id(obj
));
820 g_string_free(class_name
, FALSE
);
827 describe_variable (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
830 MonoMethodHeader
*header
= NULL
;
832 FrameDescData
*data
= (FrameDescData
*)ud
;
835 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
839 if (data
->cur_frame
< data
->target_frame
) {
844 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
846 MonoMethod
*method
= frame
->imethod
->method
;
849 MonoType
*type
= NULL
;
850 gpointer addr
= NULL
;
851 int pos
= data
->variable
;
854 type
= mono_method_signature_internal (method
)->params
[pos
];
855 addr
= mini_get_interp_callbacks ()->frame_get_arg (frame
, pos
);
857 header
= mono_method_get_header_checked (method
, error
);
858 mono_error_assert_ok (error
); /* FIXME report error */
860 type
= header
->locals
[pos
];
861 addr
= mini_get_interp_callbacks ()->frame_get_local (frame
, pos
);
864 DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr
, type
, mono_type_full_name (type
));
866 describe_value(type
, addr
);
868 mono_metadata_free_mh (header
);
873 //FIXME this doesn't support getting the return value pseudo-var
874 EMSCRIPTEN_KEEPALIVE
void
875 mono_wasm_get_var_info (int scope
, int* pos
, int len
)
879 data
.target_frame
= scope
;
880 for (int i
= 0; i
< len
; i
++)
882 DEBUG_PRINTF (2, "getting var %d of scope %d - %d\n", pos
[i
], scope
, len
);
883 data
.variable
= pos
[i
];
884 mono_walk_stack_with_ctx (describe_variable
, NULL
, MONO_UNWIND_NONE
, &data
);
886 mono_walk_stack_with_ctx (describe_async_method_locals
, NULL
, MONO_UNWIND_NONE
, &data
);
887 mono_walk_stack_with_ctx (describe_this
, NULL
, MONO_UNWIND_NONE
, &data
);
890 EMSCRIPTEN_KEEPALIVE
void
891 mono_wasm_get_object_properties (int object_id
)
893 DEBUG_PRINTF (2, "getting properties of object %d\n", object_id
);
895 describe_object_properties(object_id
, FALSE
);
898 EMSCRIPTEN_KEEPALIVE
void
899 mono_wasm_get_array_values (int object_id
)
901 DEBUG_PRINTF (2, "getting array values %d\n", object_id
);
903 describe_array_values(object_id
);
906 // Functions required by debugger-state-machine.
908 mono_debugger_tls_thread_id (DebuggerTlsData
*debuggerTlsData
)
916 mono_wasm_single_step_hit (void)
921 mono_wasm_breakpoint_hit (void)
926 mono_wasm_debugger_init (void)