2 #include "mini-runtime.h"
3 #include <mono/metadata/mono-debug.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/assembly-internals.h>
6 #include <mono/metadata/metadata.h>
7 #include <mono/metadata/metadata-internals.h>
8 #include <mono/metadata/mono-endian.h>
9 #include <mono/metadata/seq-points-data.h>
10 #include <mono/mini/aot-runtime.h>
11 #include <mono/mini/seq-points.h>
12 #include <mono/mini/debugger-engine.h>
14 //XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle
15 #include <mono/mini/interp/interp-internals.h>
19 #include <emscripten.h>
21 #include "mono/metadata/assembly-internals.h"
22 #include "mono/metadata/debug-mono-ppdb.h"
24 static int log_level
= 1;
26 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (stdout, __VA_ARGS__); } } while (0)
30 EXCEPTION_MODE_UNCAUGHT
,
34 // Flags for get_*_properties
35 #define GPFLAG_NONE 0x0000
36 #define GPFLAG_OWN_PROPERTIES 0x0001
37 #define GPFLAG_ACCESSORS_ONLY 0x0002
38 #define GPFLAG_EXPAND_VALUETYPES 0x0004
40 //functions exported to be used by JS
43 EMSCRIPTEN_KEEPALIVE
int mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
);
44 EMSCRIPTEN_KEEPALIVE
int mono_wasm_remove_breakpoint (int bp_id
);
45 EMSCRIPTEN_KEEPALIVE
int mono_wasm_current_bp_id (void);
46 EMSCRIPTEN_KEEPALIVE
void mono_wasm_enum_frames (void);
47 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_get_local_vars (int scope
, int* pos
, int len
);
48 EMSCRIPTEN_KEEPALIVE
void mono_wasm_clear_all_breakpoints (void);
49 EMSCRIPTEN_KEEPALIVE
int mono_wasm_setup_single_step (int kind
);
50 EMSCRIPTEN_KEEPALIVE
int mono_wasm_pause_on_exceptions (int state
);
51 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_get_object_properties (int object_id
, int gpflags
);
52 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_get_array_values (int object_id
, int start_idx
, int count
, int gpflags
);
53 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_invoke_getter_on_object (int object_id
, const char* name
);
54 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_invoke_getter_on_value (void *value
, MonoClass
*klass
, const char *name
);
55 EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_get_deref_ptr_value (void *value_addr
, MonoClass
*klass
);
57 //JS functions imported that we use
58 extern void mono_wasm_add_frame (int il_offset
, int method_token
, int frame_id
, const char *assembly_name
, const char *method_name
);
59 extern void mono_wasm_fire_bp (void);
60 extern void mono_wasm_fire_exception (int exception_obj_id
, const char* message
, const char* class_name
, gboolean uncaught
);
61 extern void mono_wasm_add_obj_var (const char*, const char*, guint64
);
62 extern void mono_wasm_add_enum_var (const char*, const char*, guint64
);
63 extern void mono_wasm_add_func_var (const char*, const char*, guint64
);
64 extern void mono_wasm_add_properties_var (const char*, gint32
);
65 extern void mono_wasm_add_array_item (int);
66 extern void mono_wasm_set_is_async_method (guint64
);
67 extern void mono_wasm_add_typed_value (const char *type
, const char *str_value
, double value
);
68 extern void mono_wasm_asm_loaded (const char *asm_name
, const char *assembly_data
, guint32 assembly_len
, const char *pdb_data
, guint32 pdb_len
);
72 static void describe_object_properties_for_klass (void *obj
, MonoClass
*klass
, gboolean isAsyncLocalThis
, int gpflags
);
73 static void handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
, MonoContext
*catch_ctx
, StackFrameInfo
*catch_frame
);
74 static void assembly_loaded (MonoProfiler
*prof
, MonoAssembly
*assembly
);
76 //FIXME move all of those fields to the profiler object
77 static gboolean debugger_enabled
;
79 static int event_request_id
;
80 static GHashTable
*objrefs
;
81 static GHashTable
*obj_to_objref
;
82 static int objref_id
= 0;
83 static int pause_on_exc
= EXCEPTION_MODE_NONE
;
86 all_getters_allowed_class_names
[] = {
88 "System.DateTimeOffset",
93 to_string_as_descr_names
[] = {
95 "System.DateTimeOffset",
100 #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread
103 inplace_tolower (char *c
)
106 for (i
= strlen (c
) - 1; i
>= 0; --i
)
107 c
[i
] = tolower (c
[i
]);
111 jit_done (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
113 mono_de_add_pending_breakpoints (method
, jinfo
);
117 appdomain_load (MonoProfiler
*prof
, MonoDomain
*domain
)
119 mono_de_domain_add (domain
);
122 /* Frame state handling */
123 static GPtrArray
*frames
;
126 free_frame (DbgEngineStackFrame
*frame
)
132 collect_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
138 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
142 method
= jinfo_get_method (info
->ji
);
144 method
= info
->method
;
149 DEBUG_PRINTF (2, "collect_frames: Reporting method %s native_offset %d, wrapper_type: %d\n", method
->name
, info
->native_offset
, method
->wrapper_type
);
151 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
152 DEBUG_PRINTF (2, "collect_frames: Failed to lookup sequence point. method: %s, native_offset: %d \n", method
->name
, info
->native_offset
);
155 StackFrame
*frame
= g_new0 (StackFrame
, 1);
156 frame
->de
.ji
= info
->ji
;
157 frame
->de
.domain
= info
->domain
;
158 frame
->de
.method
= method
;
159 frame
->de
.native_offset
= info
->native_offset
;
161 frame
->il_offset
= info
->il_offset
;
162 frame
->interp_frame
= info
->interp_frame
;
163 frame
->frame_addr
= info
->frame_addr
;
165 g_ptr_array_add (frames
, frame
);
171 free_frame_state (void)
175 for (i
= 0; i
< frames
->len
; ++i
)
176 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
177 g_ptr_array_set_size (frames
, 0);
182 compute_frames (void) {
185 for (i
= 0; i
< frames
->len
; ++i
)
186 free_frame ((DbgEngineStackFrame
*)g_ptr_array_index (frames
, i
));
187 g_ptr_array_set_size (frames
, 0);
189 frames
= g_ptr_array_new ();
192 mono_walk_stack_with_ctx (collect_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
195 tls_get_restore_state (void *tls
)
201 try_process_suspend (void *tls
, MonoContext
*ctx
, gboolean from_breakpoint
)
207 begin_breakpoint_processing (void *tls
, MonoContext
*ctx
, MonoJitInfo
*ji
, gboolean from_signal
)
213 begin_single_step_processing (MonoContext
*ctx
, gboolean from_signal
)
218 ss_discard_frame_context (void *the_tls
)
224 ss_calculate_framecount (void *tls
, MonoContext
*ctx
, gboolean force_use_ctx
, DbgEngineStackFrame
***out_frames
, int *nframes
)
228 *out_frames
= (DbgEngineStackFrame
**)frames
->pdata
;
230 *nframes
= frames
->len
;
234 ensure_jit (DbgEngineStackFrame
* the_frame
)
240 ensure_runtime_is_suspended (void)
246 get_object_id (MonoObject
*obj
)
252 ref
= (ObjRef
*)g_hash_table_lookup (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)));
255 ref
= g_new0 (ObjRef
, 1);
256 ref
->id
= mono_atomic_inc_i32 (&objref_id
);
257 ref
->handle
= mono_gchandle_new_weakref_internal (obj
, FALSE
);
258 g_hash_table_insert (objrefs
, GINT_TO_POINTER (ref
->id
), ref
);
259 g_hash_table_insert (obj_to_objref
, GINT_TO_POINTER (~((gsize
)obj
)), ref
);
265 get_this_async_id (DbgEngineStackFrame
*frame
)
267 MonoClassField
*builder_field
;
275 * FRAME points to a method in a state machine class/struct.
276 * Call the ObjectIdForDebugger method of the associated method builder type.
278 builder
= get_async_method_builder (frame
);
282 builder_field
= mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame
), "<>t__builder", NULL
);
286 method
= get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field
->type
));
291 obj
= mono_runtime_try_invoke (method
, builder
, NULL
, &ex
, error
);
292 mono_error_assert_ok (error
);
294 return get_object_id (obj
);
298 gboolean is_ss
; //do I need this?
302 create_breakpoint_events (GPtrArray
*ss_reqs
, GPtrArray
*bp_reqs
, MonoJitInfo
*ji
, EventKind kind
)
304 DEBUG_PRINTF (1, "ss_reqs %d bp_reqs %d\n", ss_reqs
->len
, bp_reqs
->len
);
305 if ((ss_reqs
&& ss_reqs
->len
) || (bp_reqs
&& bp_reqs
->len
)) {
306 BpEvents
*evts
= g_new0 (BpEvents
, 1); //just a non-null value to make sure we can raise it on process_breakpoint_events
307 evts
->is_ss
= (ss_reqs
&& ss_reqs
->len
);
314 process_breakpoint_events (void *_evts
, MonoMethod
*method
, MonoContext
*ctx
, int il_offsets
)
316 BpEvents
*evts
= (BpEvents
*)_evts
;
319 mono_de_cancel_all_ss ();
320 mono_wasm_fire_bp ();
326 no_seq_points_found (MonoMethod
*method
, int offset
)
329 * This can happen in full-aot mode with assemblies AOTed without the 'soft-debug' option to save space.
331 DEBUG_PRINTF (1, "Unable to find seq points for method '%s', offset 0x%x.\n", mono_method_full_name (method
, TRUE
), offset
);
334 #define DBG_NOT_SUSPENDED 1
337 ss_create_init_args (SingleStepReq
*ss_req
, SingleStepArgs
*ss_args
)
339 DEBUG_PRINTF (1, "ss_create_init_args\n");
341 ss_req
->start_sp
= ss_req
->last_sp
= &dummy
;
343 memset (ss_args
, 0, sizeof (*ss_args
));
345 // This shouldn't happen - maybe should assert here ?
346 if (frames
->len
== 0) {
347 DEBUG_PRINTF (1, "SINGLE STEPPING FOUND NO FRAMES");
348 return DBG_NOT_SUSPENDED
;
351 DbgEngineStackFrame
*frame
= (DbgEngineStackFrame
*)g_ptr_array_index (frames
, 0);
352 ss_req
->start_method
= ss_args
->method
= frame
->method
;
353 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (frame
->domain
, frame
->method
, frame
->native_offset
, &ss_args
->info
, &ss_args
->sp
);
355 no_seq_points_found (frame
->method
, frame
->native_offset
);
358 ss_args
->frames
= (DbgEngineStackFrame
**)frames
->pdata
;
359 ss_args
->nframes
= frames
->len
;
366 ss_args_destroy (SingleStepArgs
*ss_args
)
372 handle_multiple_ss_requests (void) {
373 mono_de_cancel_all_ss ();
378 mono_wasm_debugger_init (void)
380 if (!debugger_enabled
)
383 DebuggerEngineCallbacks cbs
= {
384 .tls_get_restore_state
= tls_get_restore_state
,
385 .try_process_suspend
= try_process_suspend
,
386 .begin_breakpoint_processing
= begin_breakpoint_processing
,
387 .begin_single_step_processing
= begin_single_step_processing
,
388 .ss_discard_frame_context
= ss_discard_frame_context
,
389 .ss_calculate_framecount
= ss_calculate_framecount
,
390 .ensure_jit
= ensure_jit
,
391 .ensure_runtime_is_suspended
= ensure_runtime_is_suspended
,
392 .get_this_async_id
= get_this_async_id
,
393 .set_set_notification_for_wait_completion_flag
= set_set_notification_for_wait_completion_flag
,
394 .get_notify_debugger_of_wait_completion_method
= get_notify_debugger_of_wait_completion_method
,
395 .create_breakpoint_events
= create_breakpoint_events
,
396 .process_breakpoint_events
= process_breakpoint_events
,
397 .ss_create_init_args
= ss_create_init_args
,
398 .ss_args_destroy
= ss_args_destroy
,
399 .handle_multiple_ss_requests
= handle_multiple_ss_requests
,
402 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
404 mono_de_set_log_level (log_level
, stdout
);
406 mini_debug_options
.gen_sdb_seq_points
= TRUE
;
407 mini_debug_options
.mdb_optimizations
= TRUE
;
408 mono_disable_optimizations (MONO_OPT_LINEARS
);
409 mini_debug_options
.load_aot_jit_info_eagerly
= TRUE
;
411 MonoProfilerHandle prof
= mono_profiler_create (NULL
);
412 mono_profiler_set_jit_done_callback (prof
, jit_done
);
413 //FIXME support multiple appdomains
414 mono_profiler_set_domain_loaded_callback (prof
, appdomain_load
);
415 mono_profiler_set_assembly_loaded_callback (prof
, assembly_loaded
);
417 obj_to_objref
= g_hash_table_new (NULL
, NULL
);
418 objrefs
= g_hash_table_new_full (NULL
, NULL
, NULL
, mono_debugger_free_objref
);
420 mini_get_dbg_callbacks ()->handle_exception
= handle_exception
;
424 mono_wasm_enable_debugging (int debug_level
)
426 DEBUG_PRINTF (1, "DEBUGGING ENABLED\n");
427 debugger_enabled
= TRUE
;
428 log_level
= debug_level
;
431 EMSCRIPTEN_KEEPALIVE
int
432 mono_wasm_pause_on_exceptions (int state
)
434 pause_on_exc
= state
;
435 DEBUG_PRINTF (1, "setting pause on exception: %d\n", pause_on_exc
);
439 EMSCRIPTEN_KEEPALIVE
int
440 mono_wasm_setup_single_step (int kind
)
444 DEBUG_PRINTF (2, ">>>> mono_wasm_setup_single_step %d\n", kind
);
445 EventRequest
*req
= (EventRequest
*)g_malloc0 (sizeof (EventRequest
) + (nmodifiers
* sizeof (Modifier
)));
446 req
->id
= ++event_request_id
;
447 req
->event_kind
= EVENT_KIND_STEP
;
448 // DE doesn't care about suspend_policy
449 // req->suspend_policy = SUSPEND_POLICY_ALL;
450 req
->nmodifiers
= nmodifiers
;
452 StepSize size
= STEP_SIZE_MIN
;
454 //FIXME I DON'T KNOW WHAT I'M DOING!!!!! filter all the things.
455 StepFilter filter
= (StepFilter
)(STEP_FILTER_STATIC_CTOR
| STEP_FILTER_DEBUGGER_HIDDEN
| STEP_FILTER_DEBUGGER_STEP_THROUGH
| STEP_FILTER_DEBUGGER_NON_USER_CODE
);
456 req
->modifiers
[0].data
.filter
= filter
;
461 depth
= STEP_DEPTH_INTO
;
464 depth
= STEP_DEPTH_OUT
;
467 depth
= STEP_DEPTH_OVER
;
470 g_error ("[dbg] unknown step kind %d", kind
);
473 DbgEngineErrorCode err
= mono_de_ss_create (THREAD_TO_INTERNAL (mono_thread_current ()), size
, depth
, filter
, req
);
474 if (err
!= DE_ERR_NONE
) {
475 DEBUG_PRINTF (1, "[dbg] Failed to setup single step request");
477 DEBUG_PRINTF (1, "[dbg] single step is in place, now what?\n");
478 SingleStepReq
*ss_req
= req
->info
;
479 int isBPOnNativeCode
= 0;
480 if (ss_req
&& ss_req
->bps
) {
483 for (l
= ss_req
->bps
; l
; l
= l
->next
) {
484 if (((MonoBreakpoint
*)l
->data
)->method
->wrapper_type
!= MONO_WRAPPER_RUNTIME_INVOKE
)
485 isBPOnNativeCode
= 1;
488 if (!isBPOnNativeCode
) {
489 mono_de_cancel_all_ss ();
491 return isBPOnNativeCode
;
495 assembly_loaded (MonoProfiler
*prof
, MonoAssembly
*assembly
)
497 DEBUG_PRINTF (2, "assembly_loaded callback called for %s\n", assembly
->aname
.name
);
498 MonoImage
*assembly_image
= assembly
->image
;
499 MonoImage
*pdb_image
= NULL
;
500 if (mono_has_pdb_checksum ((char *) assembly_image
->raw_data
, assembly_image
->raw_data_len
)) { //if it's a release assembly we don't need to send to DebuggerProxy
501 MonoDebugHandle
*handle
= mono_debug_get_handle (assembly_image
);
503 MonoPPDBFile
*ppdb
= handle
->ppdb
;
504 if (!mono_ppdb_is_embedded (ppdb
)) { //if it's an embedded pdb we don't need to send pdb extrated to DebuggerProxy.
505 pdb_image
= mono_ppdb_get_image (ppdb
);
506 mono_wasm_asm_loaded (assembly_image
->assembly_name
, assembly_image
->raw_data
, assembly_image
->raw_data_len
, pdb_image
->raw_data
, pdb_image
->raw_data_len
);
510 mono_wasm_asm_loaded (assembly_image
->assembly_name
, assembly_image
->raw_data
, assembly_image
->raw_data_len
, NULL
, 0);
515 handle_exception (MonoException
*exc
, MonoContext
*throw_ctx
, MonoContext
*catch_ctx
, StackFrameInfo
*catch_frame
)
518 DEBUG_PRINTF (1, "handle exception - %d - %p - %p - %p\n", pause_on_exc
, exc
, throw_ctx
, catch_ctx
);
520 if (pause_on_exc
== EXCEPTION_MODE_NONE
)
522 if (pause_on_exc
== EXCEPTION_MODE_UNCAUGHT
&& catch_ctx
!= NULL
)
525 int obj_id
= get_object_id ((MonoObject
*)exc
);
526 const char *error_message
= mono_string_to_utf8_checked_internal (exc
->message
, error
);
529 error_message
= "Failed to get exception message.";
531 const char *class_name
= mono_class_full_name (mono_object_class (exc
));
532 DEBUG_PRINTF (2, "handle exception - calling mono_wasm_fire_exc(): %d - message - %s, class_name: %s\n", obj_id
, error_message
, class_name
);
534 mono_wasm_fire_exception (obj_id
, error_message
, class_name
, !catch_ctx
);
536 DEBUG_PRINTF (2, "handle exception - done\n");
540 EMSCRIPTEN_KEEPALIVE
void
541 mono_wasm_clear_all_breakpoints (void)
543 DEBUG_PRINTF (1, "CLEAR BREAKPOINTS\n");
544 mono_de_clear_all_breakpoints ();
547 EMSCRIPTEN_KEEPALIVE
int
548 mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
)
552 DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name
, method_token
, il_offset
);
555 //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot
556 char *lookup_name
= g_strdup (assembly_name
);
557 for (i
= strlen (lookup_name
) - 1; i
>= 0; --i
) {
558 if (lookup_name
[i
] == '.') {
564 //resolve the assembly
565 MonoImageOpenStatus status
;
566 MonoAssemblyName
* aname
= mono_assembly_name_new (lookup_name
);
567 MonoAssemblyByNameRequest byname_req
;
568 mono_assembly_request_prepare_byname (&byname_req
, MONO_ASMCTX_DEFAULT
, mono_domain_default_alc (mono_get_root_domain ()));
569 MonoAssembly
*assembly
= mono_assembly_request_byname (aname
, &byname_req
, &status
);
570 g_free (lookup_name
);
572 DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name
);
576 mono_assembly_name_free_internal (aname
);
578 MonoMethod
*method
= mono_get_method_checked (assembly
->image
, MONO_TOKEN_METHOD_DEF
| method_token
, NULL
, NULL
, error
);
580 //FIXME don't swallow the error
581 DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error
));
582 mono_error_cleanup (error
);
586 //FIXME right now none of the EventRequest fields are used by debugger-engine
587 EventRequest
*req
= g_new0 (EventRequest
, 1);
588 req
->id
= ++event_request_id
;
589 req
->event_kind
= EVENT_KIND_BREAKPOINT
;
590 //DE doesn't care about suspend_policy
591 // req->suspend_policy = SUSPEND_POLICY_ALL;
592 req
->nmodifiers
= 0; //funny thing,
594 // BreakPointRequest *req = breakpoint_request_new (assembly, method, il_offset);
595 MonoBreakpoint
*bp
= mono_de_set_breakpoint (method
, il_offset
, req
, error
);
598 DEBUG_PRINTF (1, "Could not set breakpoint to %s\n", mono_error_get_message (error
));
599 mono_error_cleanup (error
);
603 DEBUG_PRINTF (1, "NEW BP %p has id %d\n", req
, req
->id
);
607 EMSCRIPTEN_KEEPALIVE
int
608 mono_wasm_remove_breakpoint (int bp_id
)
610 MonoBreakpoint
*bp
= mono_de_get_breakpoint_by_id (bp_id
);
614 mono_de_clear_breakpoint (bp
);
619 mono_wasm_single_step_hit (void)
621 mono_de_process_single_step (NULL
, FALSE
);
625 mono_wasm_breakpoint_hit (void)
627 mono_de_process_breakpoint (NULL
, FALSE
);
628 // mono_wasm_fire_bp ();
631 EMSCRIPTEN_KEEPALIVE
int
632 mono_wasm_current_bp_id (void)
634 DEBUG_PRINTF (2, "COMPUTING breakpoint ID\n");
635 //FIXME handle compiled case
638 MonoLMF
*lmf
= mono_get_lmf ();
640 g_assert (((guint64
)lmf
->previous_lmf
) & 2);
641 MonoLMFExt
*ext
= (MonoLMFExt
*)lmf
;
643 g_assert (ext
->kind
== MONO_LMFEXT_INTERP_EXIT
|| ext
->kind
== MONO_LMFEXT_INTERP_EXIT_WITH_CTX
);
644 MonoInterpFrameHandle
*frame
= (MonoInterpFrameHandle
*)ext
->interp_exit_data
;
645 MonoJitInfo
*ji
= mini_get_interp_callbacks ()->frame_get_jit_info (frame
);
646 guint8
*ip
= (guint8
*)mini_get_interp_callbacks ()->frame_get_ip (frame
);
648 g_assert (ji
&& !ji
->is_trampoline
);
649 MonoMethod
*method
= jinfo_get_method (ji
);
651 /* Compute the native offset of the breakpoint from the ip */
652 guint32 native_offset
= ip
- (guint8
*)ji
->code_start
;
654 MonoSeqPointInfo
*info
= NULL
;
656 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
, &sp
);
658 DEBUG_PRINTF (1, "Could not find SP\n");
661 GPtrArray
*bp_reqs
= g_ptr_array_new ();
662 mono_de_collect_breakpoints_by_sp (&sp
, ji
, NULL
, bp_reqs
);
664 if (bp_reqs
->len
== 0) {
665 DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method
->name
, ji
, sp
.il_offset
);
669 if (bp_reqs
->len
> 1)
670 DEBUG_PRINTF (1, "Multiple breakpoints (%d) at the same location, returning the first one.", bp_reqs
->len
);
672 EventRequest
*evt
= (EventRequest
*)g_ptr_array_index (bp_reqs
, 0);
673 g_ptr_array_free (bp_reqs
, TRUE
);
675 DEBUG_PRINTF (1, "Found BP %p with id %d\n", evt
, evt
->id
);
680 get_object_from_id (int objectId
)
682 ObjRef
*ref
= (ObjRef
*)g_hash_table_lookup (objrefs
, GINT_TO_POINTER (objectId
));
684 DEBUG_PRINTF (2, "get_object_from_id !ref: %d\n", objectId
);
688 MonoObject
*obj
= mono_gchandle_get_target_internal (ref
->handle
);
690 DEBUG_PRINTF (2, "get_object_from_id !obj: %d\n", objectId
);
696 list_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
700 char *method_full_name
;
702 int* frame_id_p
= (int*)data
;
706 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
710 method
= jinfo_get_method (info
->ji
);
712 method
= info
->method
;
714 if (!method
|| method
->wrapper_type
!= MONO_WRAPPER_NONE
)
717 DEBUG_PRINTF (2, "list_frames: Reporting method %s native_offset %d, wrapper_type: %d\n", method
->name
, info
->native_offset
, method
->wrapper_type
);
719 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
720 DEBUG_PRINTF (2, "list_frames: Failed to lookup sequence point. method: %s, native_offset: %d\n", method
->name
, info
->native_offset
);
722 method_full_name
= mono_method_full_name (method
, FALSE
);
723 while (method
->is_inflated
)
724 method
= ((MonoMethodInflated
*)method
)->declaring
;
726 char *assembly_name
= g_strdup (m_class_get_image (method
->klass
)->module_name
);
727 inplace_tolower (assembly_name
);
729 DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
730 mono_wasm_add_frame (sp
.il_offset
, mono_metadata_token_index (method
->token
), *frame_id_p
, assembly_name
, method_full_name
);
732 g_free (assembly_name
);
737 EMSCRIPTEN_KEEPALIVE
void
738 mono_wasm_enum_frames (void)
741 mono_walk_stack_with_ctx (list_frames
, NULL
, MONO_UNWIND_NONE
, &frame_id
);
745 invoke_to_string (const char *class_name
, MonoClass
*klass
, gpointer addr
)
753 // TODO: this is for a specific use case right now,
754 // (invoke ToString() get a preview/description for *some* types)
755 // and we don't want to report errors for that.
756 if (m_class_is_valuetype (klass
)) {
759 MONO_STATIC_POINTER_INIT (MonoMethod
, to_string
)
760 to_string
= mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL
| METHOD_ATTRIBUTE_PUBLIC
, error
);
761 mono_error_assert_ok (error
);
762 MONO_STATIC_POINTER_INIT_END (MonoMethod
, to_string
)
764 method
= mono_class_get_virtual_method (klass
, to_string
, FALSE
, error
);
768 MonoString
*mstr
= (MonoString
*) mono_runtime_try_invoke (method
, addr
, NULL
, &exc
, error
);
769 if (exc
|| !is_ok (error
)) {
770 DEBUG_PRINTF (1, "Failed to invoke ToString for %s\n", class_name
);
774 return mono_string_to_utf8_checked_internal (mstr
, error
);
777 obj
= *(MonoObject
**)addr
;
781 mstr
= mono_object_try_to_string (obj
, &exc
, error
);
782 if (exc
|| !is_ok (error
))
785 ret_str
= mono_string_to_utf8_checked_internal (mstr
, error
);
793 get_to_string_description (const char* class_name
, MonoClass
*klass
, gpointer addr
)
795 if (!class_name
|| !klass
|| !addr
)
798 if (strcmp (class_name
, "System.Guid") == 0)
799 return mono_guid_to_string (addr
);
801 for (int i
= 0; i
< G_N_ELEMENTS (to_string_as_descr_names
); i
++) {
802 if (strcmp (to_string_as_descr_names
[i
], class_name
) == 0) {
803 return invoke_to_string (class_name
, klass
, addr
);
819 * this returns a string formatted like
821 * <ret_type>:[<comma separated list of arg types>]:<method name>
823 * .. which is consumed by `mono_wasm_add_func_var`. It is used for
824 * generating this for the delegate, and it's target.
827 mono_method_to_desc_for_js (MonoMethod
*method
, gboolean include_namespace
)
829 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
830 char *ret_desc
= mono_type_full_name (sig
->ret
);
831 char *args_desc
= mono_signature_get_desc (sig
, include_namespace
);
833 char *sig_desc
= g_strdup_printf ("%s:%s:%s", ret_desc
, args_desc
, method
->name
);
841 read_enum_value (const char *mem
, int type
)
844 case MONO_TYPE_BOOLEAN
:
846 return *(guint8
*)mem
;
853 return (gint16
) read16 (mem
);
858 return (gint32
) read32 (mem
);
865 #if SIZEOF_REGISTER == 8
871 g_assert_not_reached ();
877 nullable_try_get_value (guint8
*nullable
, MonoClass
*klass
, gpointer
* out_value
)
879 mono_class_setup_fields (klass
);
880 g_assert (m_class_is_fields_inited (klass
));
883 MonoClassField
*klass_fields
= m_class_get_fields (klass
);
884 gpointer addr_for_has_value
= mono_vtype_get_field_addr (nullable
, &klass_fields
[0]);
885 if (0 == *(guint8
*)addr_for_has_value
)
888 *out_value
= mono_vtype_get_field_addr (nullable
, &klass_fields
[1]);
893 describe_value(MonoType
* type
, gpointer addr
, int gpflags
)
896 switch (type
->type
) {
897 case MONO_TYPE_BOOLEAN
:
898 mono_wasm_add_typed_value ("bool", NULL
, *(gint8
*)addr
);
901 mono_wasm_add_typed_value ("number", NULL
, *(gint8
*)addr
);
904 mono_wasm_add_typed_value ("number", NULL
, *(guint8
*)addr
);
907 mono_wasm_add_typed_value ("char", NULL
, *(guint16
*)addr
);
910 mono_wasm_add_typed_value ("number", NULL
, *(guint16
*)addr
);
913 mono_wasm_add_typed_value ("number", NULL
, *(gint16
*)addr
);
917 mono_wasm_add_typed_value ("number", NULL
, *(gint32
*)addr
);
921 mono_wasm_add_typed_value ("number", NULL
, *(guint32
*)addr
);
924 mono_wasm_add_typed_value ("number", NULL
, *(gint64
*)addr
);
927 mono_wasm_add_typed_value ("number", NULL
, *(guint64
*)addr
);
930 mono_wasm_add_typed_value ("number", NULL
, *(float*)addr
);
933 mono_wasm_add_typed_value ("number", NULL
, *(double*)addr
);
936 case MONO_TYPE_FNPTR
: {
937 char *class_name
= mono_type_full_name (type
);
938 const void *val
= *(const void **)addr
;
939 char *descr
= g_strdup_printf ("(%s) %p", class_name
, val
);
942 MONO
.mono_wasm_add_typed_value ('pointer', $
0, { ptr_addr
: $
1, klass_addr
: $
2 });
943 }, descr
, val
? addr
: 0, val
? mono_class_from_mono_type_internal (type
) : 0);
950 case MONO_TYPE_STRING
: {
951 MonoString
*str_obj
= *(MonoString
**)addr
;
953 mono_wasm_add_typed_value ("string", NULL
, 0);
955 char *str
= mono_string_to_utf8_checked_internal (str_obj
, error
);
956 mono_error_assert_ok (error
); /* FIXME report error */
957 mono_wasm_add_typed_value ("string", str
, 0);
963 case MONO_TYPE_OBJECT
: {
964 MonoObject
*obj
= *(MonoObject
**)addr
;
965 MonoClass
*klass
= obj
->vtable
->klass
;
968 mono_wasm_add_obj_var ("object", NULL
, 0);
972 type
= m_class_get_byval_arg (klass
);
973 if (type
->type
== MONO_TYPE_OBJECT
) {
974 mono_wasm_add_obj_var ("object", "object", get_object_id (obj
));
979 if (m_class_is_valuetype (klass
))
980 addr
= mono_object_unbox_internal (obj
);
982 return describe_value (type
, addr
, gpflags
);
985 case MONO_TYPE_GENERICINST
: {
986 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
987 if (mono_class_is_nullable (klass
)) {
988 MonoType
*targ
= type
->data
.generic_class
->context
.class_inst
->type_argv
[0];
990 gpointer nullable_value
= NULL
;
991 if (nullable_try_get_value (addr
, klass
, &nullable_value
)) {
992 return describe_value (targ
, nullable_value
, gpflags
);
994 char* class_name
= mono_type_full_name (type
);
995 mono_wasm_add_obj_var (class_name
, NULL
, 0);
1001 if (mono_type_generic_inst_is_valuetype (type
))
1008 case MONO_TYPE_SZARRAY
:
1009 case MONO_TYPE_ARRAY
:
1010 case MONO_TYPE_CLASS
: {
1011 MonoObject
*obj
= *(MonoObject
**)addr
;
1012 MonoClass
*klass
= type
->data
.klass
;
1014 if (m_class_is_valuetype (mono_object_class (obj
))) {
1015 addr
= mono_object_unbox_internal (obj
);
1016 type
= m_class_get_byval_arg (mono_object_class (obj
));
1020 char *class_name
= mono_type_full_name (type
);
1021 int obj_id
= get_object_id (obj
);
1023 if (type
-> type
== MONO_TYPE_ARRAY
|| type
->type
== MONO_TYPE_SZARRAY
) {
1024 MonoArray
*array
= (MonoArray
*)obj
;
1026 MONO
.mono_wasm_add_typed_value ('array', $
0, { objectId
: $
1, length
: $
2 });
1027 }, class_name
, obj_id
, mono_array_length_internal (array
));
1028 } else if (m_class_is_delegate (klass
) || (type
->type
== MONO_TYPE_GENERICINST
&& m_class_is_delegate (type
->data
.generic_class
->container_class
))) {
1031 if (type
->type
== MONO_TYPE_GENERICINST
)
1032 klass
= type
->data
.generic_class
->container_class
;
1034 method
= mono_get_delegate_invoke_internal (klass
);
1036 mono_wasm_add_func_var (class_name
, NULL
, -1);
1038 MonoMethod
*tm
= ((MonoDelegate
*)obj
)->method
;
1039 char *tm_desc
= NULL
;
1041 tm_desc
= mono_method_to_desc_for_js (tm
, FALSE
);
1043 mono_wasm_add_func_var (class_name
, tm_desc
, obj_id
);
1047 char *to_string_val
= get_to_string_description (class_name
, klass
, addr
);
1048 mono_wasm_add_obj_var (class_name
, to_string_val
, obj_id
);
1049 g_free (to_string_val
);
1051 g_free (class_name
);
1056 case MONO_TYPE_VALUETYPE
: {
1058 MonoClass
*klass
= mono_class_from_mono_type_internal (type
);
1059 char *class_name
= mono_type_full_name (type
);
1061 if (m_class_is_enumtype (klass
)) {
1062 MonoClassField
*field
;
1063 gpointer iter
= NULL
;
1065 MonoTypeEnum def_type
;
1066 guint64 field_value
;
1067 guint64 value__
= 0xDEAD;
1068 GString
*enum_members
= g_string_new ("");
1069 int base_type
= mono_class_enum_basetype_internal (klass
)->type
;
1071 while ((field
= mono_class_get_fields_internal (klass
, &iter
))) {
1072 if (strcmp ("value__", mono_field_get_name (field
)) == 0) {
1073 value__
= read_enum_value (mono_vtype_get_field_addr (addr
, field
), base_type
);
1077 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
1079 if (mono_field_is_deleted (field
))
1082 p
= mono_class_get_field_default_value (field
, &def_type
);
1083 /* this is to correctly increment `p` in the blob */
1084 /* len = */ mono_metadata_decode_blob_size (p
, &p
);
1086 field_value
= read_enum_value (p
, base_type
);
1088 g_string_append_printf (enum_members
, ",%s:%llu", mono_field_get_name (field
), field_value
);
1091 mono_wasm_add_enum_var (class_name
, enum_members
->str
, value__
);
1092 g_string_free (enum_members
, TRUE
);
1094 char *to_string_val
= get_to_string_description (class_name
, klass
, addr
);
1096 if (gpflags
& GPFLAG_EXPAND_VALUETYPES
) {
1097 int32_t size
= mono_class_value_size (klass
, NULL
);
1098 void *value_buf
= g_malloc0 (size
);
1099 mono_value_copy_internal (value_buf
, addr
, klass
);
1102 MONO
.mono_wasm_add_typed_value ($
0, $
1, { toString
: $
2, value_addr
: $
3, value_size
: $
4, klass
: $
5 });
1103 }, "begin_vt", class_name
, to_string_val
, value_buf
, size
, klass
);
1107 // FIXME: isAsyncLocalThis
1108 describe_object_properties_for_klass (addr
, klass
, FALSE
, gpflags
);
1109 mono_wasm_add_typed_value ("end_vt", NULL
, 0);
1112 MONO
.mono_wasm_add_typed_value ($
0, $
1, { toString
: $
2 });
1113 }, "unexpanded_vt", class_name
, to_string_val
);
1115 g_free (to_string_val
);
1117 g_free (class_name
);
1121 char *type_name
= mono_type_full_name (type
);
1122 char *msg
= g_strdup_printf("can't handle type %s [%p, %x]", type_name
, type
, type
->type
);
1123 mono_wasm_add_typed_value ("string", msg
, 0);
1132 are_getters_allowed (const char *class_name
)
1134 for (int i
= 0; i
< G_N_ELEMENTS (all_getters_allowed_class_names
); i
++) {
1135 if (strcmp (class_name
, all_getters_allowed_class_names
[i
]) == 0)
1143 invoke_and_describe_getter_value (MonoObject
*obj
, MonoProperty
*p
)
1149 MonoMethodSignature
*sig
= mono_method_signature_internal (p
->get
);
1151 res
= mono_runtime_try_invoke (p
->get
, obj
, NULL
, &exc
, error
);
1152 if (!is_ok (error
) && exc
== NULL
)
1153 exc
= (MonoObject
*) mono_error_convert_to_exception (error
);
1155 return describe_value (mono_get_object_type (), &exc
, GPFLAG_EXPAND_VALUETYPES
);
1156 else if (!res
|| !m_class_is_valuetype (mono_object_class (res
)))
1157 return describe_value (sig
->ret
, &res
, GPFLAG_EXPAND_VALUETYPES
);
1159 return describe_value (sig
->ret
, mono_object_unbox_internal (res
), GPFLAG_EXPAND_VALUETYPES
);
1163 describe_object_properties_for_klass (void *obj
, MonoClass
*klass
, gboolean isAsyncLocalThis
, int gpflags
)
1167 MonoMethodSignature
*sig
;
1168 gboolean is_valuetype
;
1171 gboolean auto_invoke_getters
;
1173 gboolean only_backing_fields
;
1176 MonoClass
*start_klass
= klass
;
1178 only_backing_fields
= gpflags
& GPFLAG_ACCESSORS_ONLY
;
1179 is_valuetype
= m_class_is_valuetype(klass
);
1181 gpflags
|= GPFLAG_EXPAND_VALUETYPES
;
1184 is_own
= (start_klass
== klass
);
1185 klass_name
= mono_class_full_name (klass
);
1186 gpointer iter
= NULL
;
1187 while (obj
&& (f
= mono_class_get_fields_internal (klass
, &iter
))) {
1188 if (isAsyncLocalThis
&& f
->name
[0] == '<' && f
->name
[1] == '>') {
1189 if (g_str_has_suffix (f
->name
, "__this")) {
1190 mono_wasm_add_properties_var ("this", f
->offset
);
1191 gpointer field_value
= (guint8
*)obj
+ f
->offset
;
1193 describe_value (f
->type
, field_value
, gpflags
);
1198 if (f
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
1200 if (mono_field_is_deleted (f
))
1203 if (only_backing_fields
&& !g_str_has_suffix(f
->name
, "k__BackingField"))
1207 MONO
.mono_wasm_add_properties_var ($
0, { field_offset
: $
1, is_own
: $
2, attr
: $
3, owner_class
: $
4 });
1208 }, f
->name
, f
->offset
, is_own
, f
->type
->attrs
, klass_name
);
1210 gpointer field_addr
;
1212 field_addr
= mono_vtype_get_field_addr (obj
, f
);
1214 field_addr
= (guint8
*)obj
+ f
->offset
;
1216 describe_value (f
->type
, field_addr
, gpflags
);
1219 auto_invoke_getters
= are_getters_allowed (klass_name
);
1222 while ((p
= mono_class_get_properties (klass
, &iter
))) {
1223 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
1224 if (isAsyncLocalThis
&& (p
->name
[0] != '<' || (p
->name
[0] == '<' && p
->name
[1] == '>')))
1227 sig
= mono_method_signature_internal (p
->get
);
1228 if (sig
->param_count
!= 0) {
1229 // getters with params are not shown
1234 MONO
.mono_wasm_add_properties_var ($
0, { field_offset
: $
1, is_own
: $
2, attr
: $
3, owner_class
: $
4 });
1235 }, p
->name
, pnum
, is_own
, p
->attrs
, klass_name
);
1237 gboolean vt_self_type_getter
= is_valuetype
&& mono_class_from_mono_type_internal (sig
->ret
) == klass
;
1238 if (auto_invoke_getters
&& !vt_self_type_getter
) {
1239 invoke_and_describe_getter_value (obj
, p
);
1241 // not allowed to call the getter here
1242 char *ret_class_name
= mono_class_full_name (mono_class_from_mono_type_internal (sig
->ret
));
1244 mono_wasm_add_typed_value ("getter", ret_class_name
, -1);
1246 g_free (ret_class_name
);
1253 g_free (klass_name
);
1256 // Note: ownProperties should mean that we return members of the klass itself,
1257 // but we are going to ignore that here, because otherwise vscode/chrome don't
1258 // seem to ask for inherited fields at all.
1259 // if (!is_valuetype && !(gpflags & GPFLAG_OWN_PROPERTIES) && (klass = m_class_get_parent (klass)))
1260 if (!is_valuetype
&& (klass
= m_class_get_parent (klass
)))
1265 * We return a `Target` property only for now.
1266 * In future, we could add a `MethodInfo` too.
1269 describe_delegate_properties (MonoObject
*obj
)
1271 MonoClass
*klass
= mono_object_class(obj
);
1272 if (!m_class_is_delegate (klass
))
1275 // Target, like in VS - what is this field supposed to be, anyway??
1276 MonoMethod
*tm
= ((MonoDelegate
*)obj
)->method
;
1277 char * sig_desc
= mono_method_to_desc_for_js (tm
, FALSE
);
1279 mono_wasm_add_properties_var ("Target", -1);
1280 mono_wasm_add_func_var (NULL
, sig_desc
, -1);
1287 describe_object_properties (guint64 objectId
, gboolean isAsyncLocalThis
, int gpflags
)
1289 DEBUG_PRINTF (2, "describe_object_properties %llu, gpflags: %d\n", objectId
, gpflags
);
1291 MonoObject
*obj
= get_object_from_id (objectId
);
1295 if (m_class_is_delegate (mono_object_class (obj
))) {
1296 // delegates get the same id format as regular objects
1297 describe_delegate_properties (obj
);
1299 describe_object_properties_for_klass (obj
, obj
->vtable
->klass
, isAsyncLocalThis
, gpflags
);
1306 invoke_getter (void *obj_or_value
, MonoClass
*klass
, const char *name
)
1308 if (!obj_or_value
|| !klass
|| !name
) {
1309 DEBUG_PRINTF (2, "invoke_getter: none of the arguments can be null");
1317 while ((p
= mono_class_get_properties (klass
, &iter
))) {
1318 //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
1319 if (!p
->get
->name
|| strcasecmp (p
->name
, name
) != 0)
1322 invoke_and_describe_getter_value (obj_or_value
, p
);
1326 if ((klass
= m_class_get_parent(klass
)))
1333 describe_array_values (guint64 objectId
, int startIdx
, int count
, int gpflags
)
1340 MonoArray
*arr
= (MonoArray
*) get_object_from_id (objectId
);
1344 MonoClass
*klass
= mono_object_class (arr
);
1345 MonoTypeEnum type
= m_class_get_byval_arg (klass
)->type
;
1346 if (type
!= MONO_TYPE_SZARRAY
&& type
!= MONO_TYPE_ARRAY
) {
1347 DEBUG_PRINTF (1, "describe_array_values: object is not an array. type: 0x%x\n", type
);
1351 int len
= arr
->max_length
;
1352 if (len
== 0 && startIdx
== 0 && count
<= 0) {
1357 if (startIdx
< 0 || (len
> 0 && startIdx
>= len
)) {
1358 DEBUG_PRINTF (1, "describe_array_values: invalid startIdx (%d) for array of length %d\n", startIdx
, len
);
1362 if (count
> 0 && (startIdx
+ count
) > len
) {
1363 DEBUG_PRINTF (1, "describe_array_values: invalid count (%d) for startIdx: %d, and array of length %d\n", count
, startIdx
, len
);
1367 esize
= mono_array_element_size (klass
);
1368 int endIdx
= count
< 0 ? len
: startIdx
+ count
;
1370 for (int i
= startIdx
; i
< endIdx
; i
++) {
1371 mono_wasm_add_array_item(i
);
1372 elem
= (gpointer
*)((char*)arr
->vector
+ (i
* esize
));
1373 describe_value (m_class_get_byval_arg (m_class_get_element_class (klass
)), elem
, gpflags
);
1379 describe_async_method_locals (InterpFrame
*frame
, MonoMethod
*method
)
1381 //Async methods are special in the way that local variables can be lifted to generated class fields
1382 gpointer addr
= NULL
;
1383 if (mono_debug_lookup_method_async_debug_info (method
)) {
1384 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
1385 MonoObject
*obj
= *(MonoObject
**)addr
;
1386 int objId
= get_object_id (obj
);
1387 mono_wasm_set_is_async_method (objId
);
1388 describe_object_properties (objId
, TRUE
, GPFLAG_NONE
);
1393 describe_non_async_this (InterpFrame
*frame
, MonoMethod
*method
)
1395 gpointer addr
= NULL
;
1396 if (mono_debug_lookup_method_async_debug_info (method
))
1399 if (mono_method_signature_internal (method
)->hasthis
) {
1400 addr
= mini_get_interp_callbacks ()->frame_get_this (frame
);
1401 MonoObject
*obj
= *(MonoObject
**)addr
;
1402 MonoClass
*klass
= method
->klass
;
1403 MonoType
*type
= m_class_get_byval_arg (method
->klass
);
1405 mono_wasm_add_properties_var ("this", -1);
1407 if (m_class_is_valuetype (klass
)) {
1408 describe_value (type
, obj
, GPFLAG_EXPAND_VALUETYPES
);
1410 // this is an object, and we can retrieve the valuetypes in it later
1411 // through the object id
1412 describe_value (type
, addr
, GPFLAG_NONE
);
1418 describe_variable (InterpFrame
*frame
, MonoMethod
*method
, MonoMethodHeader
*header
, int pos
, int gpflags
)
1420 MonoType
*type
= NULL
;
1421 gpointer addr
= NULL
;
1423 MonoMethodSignature
*sig
= mono_method_signature_internal (method
);
1426 if (pos
>= sig
->param_count
) {
1427 DEBUG_PRINTF(1, "BUG: describe_variable, trying to access param indexed %d, but the method (%s) has only %d params\n", pos
, method
->name
, sig
->param_count
);
1431 type
= sig
->params
[pos
];
1432 addr
= mini_get_interp_callbacks ()->frame_get_arg (frame
, pos
);
1434 if (pos
>= header
->num_locals
) {
1435 DEBUG_PRINTF(1, "BUG: describe_variable, trying to access local indexed %d, but the method (%s) has only %d locals\n", pos
, method
->name
, header
->num_locals
);
1439 type
= header
->locals
[pos
];
1440 addr
= mini_get_interp_callbacks ()->frame_get_local (frame
, pos
);
1443 DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr
, type
, mono_type_full_name (type
));
1445 return describe_value(type
, addr
, gpflags
);
1449 describe_variables_on_frame (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
1452 FrameDescData
*data
= (FrameDescData
*)ud
;
1457 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
1461 if (data
->cur_frame
!= data
->target_frame
)
1466 InterpFrame
*frame
= (InterpFrame
*)info
->interp_frame
;
1468 MonoMethod
*method
= frame
->imethod
->method
;
1471 MonoMethodHeader
*header
= mono_method_get_header_checked (method
, error
);
1472 mono_error_assert_ok (error
); /* FIXME report error */
1474 for (int i
= 0; i
< data
->len
; i
++)
1476 if (!describe_variable (frame
, method
, header
, data
->pos
[i
], GPFLAG_EXPAND_VALUETYPES
))
1477 mono_wasm_add_typed_value("symbol", "<unreadable value>", 0);
1480 describe_async_method_locals (frame
, method
);
1481 describe_non_async_this (frame
, method
);
1483 mono_metadata_free_mh (header
);
1487 EMSCRIPTEN_KEEPALIVE gboolean
1488 mono_wasm_get_deref_ptr_value (void *value_addr
, MonoClass
*klass
)
1490 MonoType
*type
= m_class_get_byval_arg (klass
);
1491 if (type
->type
!= MONO_TYPE_PTR
&& type
->type
!= MONO_TYPE_FNPTR
) {
1492 DEBUG_PRINTF (2, "BUG: mono_wasm_get_deref_ptr_value: Expected to get a ptr type, but got 0x%x\n", type
->type
);
1496 mono_wasm_add_properties_var ("deref", -1);
1497 return describe_value (type
->data
.type
, value_addr
, GPFLAG_EXPAND_VALUETYPES
);
1500 //FIXME this doesn't support getting the return value pseudo-var
1501 EMSCRIPTEN_KEEPALIVE gboolean
1502 mono_wasm_get_local_vars (int scope
, int* pos
, int len
)
1508 data
.target_frame
= scope
;
1509 data
.cur_frame
= -1;
1514 mono_walk_stack_with_ctx (describe_variables_on_frame
, NULL
, MONO_UNWIND_NONE
, &data
);
1519 EMSCRIPTEN_KEEPALIVE gboolean
1520 mono_wasm_get_object_properties (int object_id
, int gpflags
)
1522 DEBUG_PRINTF (2, "getting properties of object %d, gpflags: %d\n", object_id
, gpflags
);
1524 return describe_object_properties (object_id
, FALSE
, gpflags
);
1527 EMSCRIPTEN_KEEPALIVE gboolean
1528 mono_wasm_get_array_values (int object_id
, int start_idx
, int count
, int gpflags
)
1530 DEBUG_PRINTF (2, "getting array values %d, startIdx: %d, count: %d, gpflags: 0x%x\n", object_id
, start_idx
, count
, gpflags
);
1532 return describe_array_values (object_id
, start_idx
, count
, gpflags
);
1535 EMSCRIPTEN_KEEPALIVE gboolean
1536 mono_wasm_invoke_getter_on_object (int object_id
, const char* name
)
1538 MonoObject
*obj
= get_object_from_id (object_id
);
1542 return invoke_getter (obj
, mono_object_class (obj
), name
);
1545 EMSCRIPTEN_KEEPALIVE gboolean
1546 mono_wasm_invoke_getter_on_value (void *value
, MonoClass
*klass
, const char *name
)
1548 DEBUG_PRINTF (2, "mono_wasm_invoke_getter_on_value: v: %p klass: %p, name: %s\n", value
, klass
, name
);
1549 if (!klass
|| !value
)
1552 if (!m_class_is_valuetype (klass
)) {
1553 DEBUG_PRINTF (2, "mono_wasm_invoke_getter_on_value: klass is not a valuetype. name: %s\n", mono_class_full_name (klass
));
1557 return invoke_getter (value
, klass
, name
);
1560 // Functions required by debugger-state-machine.
1562 mono_debugger_tls_thread_id (DebuggerTlsData
*debuggerTlsData
)
1570 mono_wasm_single_step_hit (void)
1575 mono_wasm_breakpoint_hit (void)
1580 mono_wasm_debugger_init (void)