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>
10 //XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle
11 #include <mono/mini/interp/interp-internals.h>
13 #include <emscripten.h>
16 static int log_level
= 1;
18 #define DEBUG_PRINTF(level, ...) do { if (G_UNLIKELY ((level) <= log_level)) { fprintf (stdout, __VA_ARGS__); } } while (0)
20 //functions exported to be used by JS
21 EMSCRIPTEN_KEEPALIVE
int mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
);
22 EMSCRIPTEN_KEEPALIVE
void mono_set_timeout_exec (int id
);
23 EMSCRIPTEN_KEEPALIVE
int mono_wasm_current_bp_id (void);
24 EMSCRIPTEN_KEEPALIVE
void mono_wasm_enum_frames (void);
25 EMSCRIPTEN_KEEPALIVE
void mono_wasm_get_var_info (int scope
, int pos
);
27 //JS functions imported that we use
28 extern void mono_wasm_add_frame (int il_offset
, int method_token
, const char *assembly_name
);
29 extern void mono_wasm_fire_bp (void);
30 extern void mono_set_timeout (int t
, int d
);
31 extern void mono_wasm_add_bool_var (gint8
);
32 extern void mono_wasm_add_int_var (gint32
);
33 extern void mono_wasm_add_long_var (gint64
);
34 extern void mono_wasm_add_float_var (float);
35 extern void mono_wasm_add_double_var (double);
36 extern void mono_wasm_add_string_var (const char*);
40 mono_arch_get_this_arg_from_call (mgreg_t
*regs
, guint8
*code
)
42 g_error ("mono_arch_get_this_arg_from_call");
46 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature
*sig
, MonoMethod
*method
, int offset
, gboolean load_imt_reg
)
48 g_error ("mono_arch_get_delegate_virtual_invoke_impl");
53 mono_arch_cpu_init (void)
55 // printf ("mono_arch_cpu_init\n");
59 mono_arch_finish_init (void)
61 // printf ("mono_arch_finish_init\n");
67 // printf ("mono_arch_init\n");
71 mono_arch_cleanup (void)
76 mono_arch_register_lowlevel_calls (void)
81 mono_arch_flush_register_windows (void)
86 mono_arch_free_jit_tls_data (MonoJitTlsData
*tls
)
92 mono_arch_find_imt_method (mgreg_t
*regs
, guint8
*code
)
94 g_error ("mono_arch_find_static_call_vtable");
95 return (MonoMethod
*) regs
[MONO_ARCH_IMT_REG
];
99 mono_arch_find_static_call_vtable (mgreg_t
*regs
, guint8
*code
)
101 g_error ("mono_arch_find_static_call_vtable");
102 return (MonoVTable
*) regs
[MONO_ARCH_RGCTX_REG
];
106 mono_arch_build_imt_trampoline (MonoVTable
*vtable
, MonoDomain
*domain
, MonoIMTCheckItem
**imt_entries
, int count
, gpointer fail_tramp
)
108 g_error ("mono_arch_build_imt_trampoline");
112 mono_arch_cpu_enumerate_simd_versions (void)
118 mono_arch_cpu_optimizations (guint32
*exclude_mask
)
124 mono_arch_get_delegate_invoke_impls (void)
126 g_error ("mono_arch_get_delegate_invoke_impls");
131 mono_arch_get_delegate_invoke_impl (MonoMethodSignature
*sig
, gboolean has_target
)
133 g_error ("mono_arch_get_delegate_invoke_impl");
138 mono_arch_context_get_int_reg (MonoContext
*ctx
, int reg
)
140 g_error ("mono_arch_context_get_int_reg");
145 mono_arch_get_argument_info (MonoMethodSignature
*csig
, int param_count
, MonoJitArgumentInfo
*arg_info
)
147 g_error ("mono_arch_get_argument_info");
153 mono_runtime_setup_stat_profiler (void)
155 g_error ("mono_runtime_setup_stat_profiler");
160 mono_runtime_shutdown_stat_profiler (void)
162 g_error ("mono_runtime_shutdown_stat_profiler");
167 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal
)
169 g_error ("mono_chain_signal");
175 mono_runtime_install_handlers (void)
180 mono_runtime_cleanup_handlers (void)
185 mono_thread_state_init_from_handle (MonoThreadUnwindState
*tctx
, MonoThreadInfo
*info
, void *sigctx
)
187 g_error ("WASM systems don't support mono_thread_state_init_from_handle");
192 EMSCRIPTEN_KEEPALIVE
void
193 mono_set_timeout_exec (int id
)
196 MonoClass
*klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Threading", "WasmRuntime");
199 MonoMethod
*method
= mono_class_get_method_from_name (klass
, "TimeoutCallback", -1);
202 gpointer params
[1] = { &id
};
203 MonoObject
*exc
= NULL
;
205 mono_runtime_try_invoke (method
, NULL
, params
, &exc
, error
);
207 //YES we swallow exceptions cuz there's nothing much we can do from here.
208 //FIXME Maybe call the unhandled exception function?
209 if (!is_ok (error
)) {
210 printf ("timeout callback failed due to %s\n", mono_error_get_message (error
));
211 mono_error_cleanup (error
);
215 char *type_name
= mono_type_get_full_name (mono_object_get_class (exc
));
216 printf ("timeout callback threw a %s\n", type_name
);
222 mono_wasm_set_timeout (int timeout
, int id
)
224 mono_set_timeout (timeout
, id
);
228 mono_arch_register_icall (void)
230 mono_add_internal_call ("System.Threading.WasmRuntime::SetTimeout", mono_wasm_set_timeout
);
234 mono_arch_patch_code_new (MonoCompile
*cfg
, MonoDomain
*domain
, guint8
*code
, MonoJumpInfo
*ji
, gpointer target
)
236 g_error ("mono_arch_patch_code_new");
240 The following functions don't belong here, but are due to laziness.
242 gboolean
mono_w32file_get_volume_information (const gunichar2
*path
, gunichar2
*volumename
, gint volumesize
, gint
*outserial
, gint
*maxcomp
, gint
*fsflags
, gunichar2
*fsbuffer
, gint fsbuffersize
);
243 void * getgrnam (const char *name
);
244 void * getgrgid (gid_t gid
);
245 int inotify_init (void);
246 int inotify_rm_watch (int fd
, int wd
);
247 int inotify_add_watch (int fd
, const char *pathname
, uint32_t mask
);
248 int sem_timedwait (sem_t
*sem
, const struct timespec
*abs_timeout
);
253 mono_w32file_get_volume_information (const gunichar2
*path
, gunichar2
*volumename
, gint volumesize
, gint
*outserial
, gint
*maxcomp
, gint
*fsflags
, gunichar2
*fsbuffer
, gint fsbuffersize
)
256 gboolean status
= FALSE
;
258 gunichar2
*ret
= g_utf8_to_utf16 ("memfs", -1, NULL
, &len
, NULL
);
259 if (ret
!= NULL
&& len
< fsbuffersize
) {
260 memcpy (fsbuffer
, ret
, len
* sizeof (gunichar2
));
271 //llvm builtin's that we should not have used in the first place
274 //libc / libpthread missing bits from musl or shit we didn't detect :facepalm:
275 int pthread_getschedparam (pthread_t thread
, int *policy
, struct sched_param
*param
)
277 g_error ("pthread_getschedparam");
282 pthread_setschedparam(pthread_t thread
, int policy
, const struct sched_param
*param
)
289 pthread_attr_getstacksize (const pthread_attr_t
*restrict attr
, size_t *restrict stacksize
)
291 return 65536; //wasm page size
295 pthread_sigmask (int how
, const sigset_t
* restrict set
, sigset_t
* restrict oset
)
302 sigsuspend(const sigset_t
*sigmask
)
304 g_error ("sigsuspend");
311 return 256; //random constant that is the fd limit
315 getgrnam (const char *name
)
329 g_error ("inotify_init");
333 inotify_rm_watch (int fd
, int wd
)
335 g_error ("inotify_rm_watch");
340 inotify_add_watch (int fd
, const char *pathname
, uint32_t mask
)
342 g_error ("inotify_add_watch");
347 sem_timedwait (sem_t
*sem
, const struct timespec
*abs_timeout
)
349 g_error ("sem_timedwait");
357 MonoAssembly
*assembly
;
369 long il_offset
, native_offset
;
373 } BreakpointInstance
;
376 //FIXME move all of those fields to the profiler object
377 static gboolean debugger_enabled
;
378 static int bp_id_count
;
379 static GHashTable
*bp_locs
;
380 static GPtrArray
*active_breakpoints
;
383 breakpoint_request_free (BreakPointRequest
*bp
)
389 inplace_tolower (char *c
)
392 for (i
= strlen (c
) - 1; i
>= 0; --i
)
393 c
[i
] = tolower (c
[i
]);
396 static BreakPointRequest
*
397 breakpoint_request_new (MonoAssembly
*assembly
, MonoMethod
*method
, int il_offset
)
400 BreakPointRequest
*req
= g_new0(BreakPointRequest
, 1);
401 req
->assembly
= assembly
;
402 req
->method
= method
;
403 req
->il_offset
= il_offset
;
409 breakpoint_matches (BreakPointRequest
*bp
, MonoMethod
*method
)
413 if (method
== bp
->method
)
415 if (method
->is_inflated
&& ((MonoMethodInflated
*)method
)->declaring
== bp
->method
)
417 //XXX we don't support setting a breakpoint on a specif ginst, so whatever
421 //LOCKING: loader lock must be held
423 find_applicable_methods (BreakPointRequest
*bp
, GPtrArray
*methods
, GPtrArray
*method_seq_points
)
427 MonoSeqPointInfo
*seq_points
;
429 mono_domain_lock (mono_get_root_domain ());
430 g_hash_table_iter_init (&iter
, domain_jit_info (mono_get_root_domain ())->seq_points
);
431 while (g_hash_table_iter_next (&iter
, (void**)&method
, (void**)&seq_points
)) {
432 if (breakpoint_matches (bp
, method
)) {
433 g_ptr_array_add (methods
, method
);
434 g_ptr_array_add (method_seq_points
, seq_points
);
437 mono_domain_unlock (mono_get_root_domain ());
441 insert_breakpoint (MonoSeqPointInfo
*seq_points
, MonoDomain
*domain
, MonoJitInfo
*ji
, BreakPointRequest
*bp
, MonoError
*error
)
445 gboolean it_has_sp
= FALSE
;
449 DEBUG_PRINTF (1, "insert_breakpoint: JI [%p] method %s at %d SP %p\n", ji
, jinfo_get_method (ji
)->name
, bp
->il_offset
, seq_points
);
451 mono_seq_point_iterator_init (&it
, seq_points
);
452 while (mono_seq_point_iterator_next (&it
)) {
453 if (it
.seq_point
.il_offset
== bp
->il_offset
) {
461 * The set of IL offsets with seq points doesn't completely match the
462 * info returned by CMD_METHOD_GET_DEBUG_INFO (#407).
464 mono_seq_point_iterator_init (&it
, seq_points
);
465 while (mono_seq_point_iterator_next (&it
)) {
466 if (it
.seq_point
.il_offset
!= METHOD_ENTRY_IL_OFFSET
&&
467 it
.seq_point
.il_offset
!= METHOD_EXIT_IL_OFFSET
&&
468 it
.seq_point
.il_offset
+ 1 == bp
->il_offset
) {
476 DEBUG_PRINTF (1, "Unable to insert breakpoint at %s:%d. SeqPoint data:", mono_method_full_name (jinfo_get_method (ji
), TRUE
), bp
->il_offset
);
478 mono_seq_point_iterator_init (&it
, seq_points
);
479 while (mono_seq_point_iterator_next (&it
))
480 DEBUG_PRINTF (1, "\t%d\n", it
.seq_point
.il_offset
);
482 DEBUG_PRINTF (1, "End of data\n");
483 mono_error_set_error (error
, MONO_ERROR_GENERIC
, "Failed to find the SP for the given il offset");
487 BreakpointInstance
*inst
= g_new0 (BreakpointInstance
, 1);
488 inst
->il_offset
= it
.seq_point
.il_offset
;
489 inst
->native_offset
= it
.seq_point
.native_offset
;
490 inst
->ip
= (guint8
*)ji
->code_start
+ it
.seq_point
.native_offset
;
492 inst
->domain
= mono_get_root_domain ();
497 bp
->children
= g_ptr_array_new ();
498 g_ptr_array_add (bp
->children
, inst
);
500 mono_loader_unlock ();
503 count
= GPOINTER_TO_INT (g_hash_table_lookup (bp_locs
, inst
->ip
));
504 g_hash_table_insert (bp_locs
, inst
->ip
, GINT_TO_POINTER (count
+ 1));
507 if (it
.seq_point
.native_offset
== SEQ_POINT_NATIVE_OFFSET_DEAD_CODE
) {
508 DEBUG_PRINTF (1, "Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp
->il_offset
);
509 } else if (count
== 0) {
510 DEBUG_PRINTF (1, "ACTIVATING BREAKPOINT in %s\n", jinfo_get_method (ji
)->name
);
512 mini_get_interp_callbacks ()->set_breakpoint (ji
, inst
->ip
);
514 g_error ("no idea how to deal with compiled code");
515 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
516 mono_arch_set_breakpoint (ji
, inst
->ip
);
527 set_breakpoint (MonoMethod
*method
, MonoSeqPointInfo
*seq_points
, BreakPointRequest
*bp
, MonoError
*error
)
529 MonoJitInfo
*ji
= NULL
;
533 MonoDomain
*domain
= mono_get_root_domain ();
534 gpointer code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
536 /* Might be AOTed code */
537 mono_class_init (method
->klass
);
538 code
= mono_aot_get_method (domain
, method
, error
);
540 mono_error_assert_ok (error
);
541 ji
= mono_jit_info_table_find (domain
, code
);
543 /* Might be interpreted */
544 ji
= mini_get_interp_callbacks ()->find_jit_info (domain
, method
);
549 return insert_breakpoint (seq_points
, domain
, ji
, bp
, error
);
553 add_breakpoint (BreakPointRequest
*bp
)
557 bp
->bp_id
= ++bp_id_count
;
561 GPtrArray
*methods
= g_ptr_array_new ();
562 GPtrArray
*method_seq_points
= g_ptr_array_new ();
566 find_applicable_methods (bp
, methods
, method_seq_points
);
568 for (i
= 0; i
< methods
->len
; ++i
) {
569 MonoMethod
*method
= (MonoMethod
*)g_ptr_array_index (methods
, i
);
570 MonoSeqPointInfo
*seq_points
= (MonoSeqPointInfo
*)g_ptr_array_index (method_seq_points
, i
);
572 if (!set_breakpoint (method
, seq_points
, bp
, error
)) {
573 //FIXME don't swallow the error
574 DEBUG_PRINTF (1, "Error setting breaking due to %s\n", mono_error_get_message (error
));
575 mono_error_cleanup (error
);
580 g_ptr_array_add (active_breakpoints
, bp
);
582 mono_loader_unlock ();
584 g_ptr_array_free (methods
, TRUE
);
585 g_ptr_array_free (method_seq_points
, TRUE
);
589 add_pending_breakpoints (MonoMethod
*method
, MonoJitInfo
*ji
)
592 MonoSeqPointInfo
*seq_points
;
596 if (!active_breakpoints
)
599 domain
= mono_domain_get ();
603 for (i
= 0; i
< active_breakpoints
->len
; ++i
) {
604 BreakPointRequest
*bp
= (BreakPointRequest
*)g_ptr_array_index (active_breakpoints
, i
);
605 gboolean found
= FALSE
;
607 if (!breakpoint_matches (bp
, method
))
610 for (j
= 0; j
< bp
->children
->len
; ++j
) {
611 BreakpointInstance
*inst
= (BreakpointInstance
*)g_ptr_array_index (bp
->children
, j
);
619 MonoMethod
*declaring
= NULL
;
621 jmethod
= jinfo_get_method (ji
);
622 if (jmethod
->is_inflated
)
623 declaring
= mono_method_get_declaring_generic_method (jmethod
);
625 mono_domain_lock (domain
);
626 seq_points
= (MonoSeqPointInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, jmethod
);
627 if (!seq_points
&& declaring
)
628 seq_points
= (MonoSeqPointInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->seq_points
, declaring
);
629 mono_domain_unlock (domain
);
631 /* Could be AOT code */
634 g_assert (seq_points
);
636 if (!insert_breakpoint (seq_points
, domain
, ji
, bp
, error
)) {
637 DEBUG_PRINTF (1, "Failed to resolve pending BP due to %s\n", mono_error_get_message (error
));
638 mono_error_cleanup (error
);
643 mono_loader_unlock ();
647 jit_done (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
649 add_pending_breakpoints (method
, jinfo
);
653 mono_wasm_debugger_init (void)
655 if (!debugger_enabled
)
658 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
659 mini_get_debug_options ()->gen_sdb_seq_points
= TRUE
;
660 mini_get_debug_options ()->mdb_optimizations
= TRUE
;
661 mono_disable_optimizations (MONO_OPT_LINEARS
);
662 mini_get_debug_options ()->load_aot_jit_info_eagerly
= TRUE
;
664 MonoProfilerHandle prof
= mono_profiler_create (NULL
);
665 mono_profiler_set_jit_done_callback (prof
, jit_done
);
667 bp_locs
= g_hash_table_new (NULL
, NULL
);
668 active_breakpoints
= g_ptr_array_new ();
672 mono_wasm_enable_debugging (void)
674 DEBUG_PRINTF (1, "DEBUGGING ENABLED");
675 debugger_enabled
= TRUE
;
679 EMSCRIPTEN_KEEPALIVE
int
680 mono_wasm_set_breakpoint (const char *assembly_name
, int method_token
, int il_offset
)
684 DEBUG_PRINTF (1, "SET BREAKPOINT: assembly %s method %x offset %x\n", assembly_name
, method_token
, il_offset
);
687 //we get 'foo.dll' but mono_assembly_load expects 'foo' so we strip the last dot
688 char *lookup_name
= g_strdup (assembly_name
);
689 for (i
= strlen (lookup_name
) - 1; i
>= 0; --i
) {
690 if (lookup_name
[i
] == '.') {
696 //resolve the assembly
697 MonoImageOpenStatus status
;
698 MonoAssemblyName
* aname
= mono_assembly_name_new (lookup_name
);
699 MonoAssembly
*assembly
= mono_assembly_load (aname
, NULL
, &status
);
700 g_free (lookup_name
);
702 DEBUG_PRINTF (1, "Could not resolve assembly %s\n", assembly_name
);
706 mono_assembly_name_free (aname
);
708 MonoMethod
*method
= mono_get_method_checked (assembly
->image
, MONO_TOKEN_METHOD_DEF
| method_token
, NULL
, NULL
, error
);
710 //FIXME don't swallow the error
711 DEBUG_PRINTF (1, "Could not find method due to %s\n", mono_error_get_message (error
));
712 mono_error_cleanup (error
);
716 BreakPointRequest
*req
= breakpoint_request_new (assembly
, method
, il_offset
);
718 add_breakpoint (req
);
725 mono_sdb_single_step_trampoline (void)
727 g_error ("mono_sdb_single_step_trampoline");
731 mono_wasm_breakpoint_hit (void)
733 mono_wasm_fire_bp ();
736 EMSCRIPTEN_KEEPALIVE
int
737 mono_wasm_current_bp_id (void)
741 DEBUG_PRINTF (1, "COMPUTING breapoint ID\n");
742 //FIXME handle compiled case
745 MonoLMF
*lmf
= mono_get_lmf ();
747 g_assert (((guint64
)lmf
->previous_lmf
) & 2);
748 MonoLMFExt
*ext
= (MonoLMFExt
*)lmf
;
750 g_assert (ext
->interp_exit
);
751 MonoInterpFrameHandle
*frame
= ext
->interp_exit_data
;
752 MonoJitInfo
*ji
= mini_get_interp_callbacks ()->frame_get_jit_info (frame
);
753 guint8
*ip
= mini_get_interp_callbacks ()->frame_get_ip (frame
);
755 g_assert (ji
&& !ji
->is_trampoline
);
756 MonoMethod
*method
= jinfo_get_method (ji
);
758 /* Compute the native offset of the breakpoint from the ip */
759 guint32 native_offset
= ip
- (guint8
*)ji
->code_start
;
761 MonoSeqPointInfo
*info
= NULL
;
763 gboolean found_sp
= mono_find_prev_seq_point_for_native_offset (mono_domain_get (), method
, native_offset
, &info
, &sp
);
765 DEBUG_PRINTF (1, "Could not find SP\n");
767 for (i
= 0; i
< active_breakpoints
->len
; ++i
) {
768 BreakPointRequest
*bp
= (BreakPointRequest
*)g_ptr_array_index (active_breakpoints
, i
);
773 for (j
= 0; j
< bp
->children
->len
; ++j
) {
774 BreakpointInstance
*inst
= (BreakpointInstance
*)g_ptr_array_index (bp
->children
, j
);
775 if (inst
->ji
== ji
&& inst
->il_offset
== sp
.il_offset
&& inst
->native_offset
== sp
.native_offset
) {
776 DEBUG_PRINTF (1, "FOUND BREAKPOINT idx %d ID %d\n", i
, bp
->bp_id
);
781 DEBUG_PRINTF (1, "BP NOT FOUND for method %s JI %p il_offset %d\n", method
->name
, ji
, sp
.il_offset
);
787 list_frames (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer data
)
793 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
)
798 method
= jinfo_get_method (info
->ji
);
800 method
= info
->method
;
805 DEBUG_PRINTF (2, "Reporting method %s native_offset %d\n", method
->name
, info
->native_offset
);
807 if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method
, info
->native_offset
, NULL
, &sp
))
808 DEBUG_PRINTF (1, "Failed to lookup sequence point\n");
810 while (method
->is_inflated
)
811 method
= ((MonoMethodInflated
*)method
)->declaring
;
813 char *assembly_name
= g_strdup (m_class_get_image (method
->klass
)->module_name
);
814 inplace_tolower (assembly_name
);
816 if (method
->wrapper_type
== MONO_WRAPPER_NONE
) {
817 DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
818 mono_wasm_add_frame (sp
.il_offset
, mono_metadata_token_index (method
->token
), assembly_name
);
821 g_free (assembly_name
);
826 EMSCRIPTEN_KEEPALIVE
void
827 mono_wasm_enum_frames (void)
829 mono_walk_stack_with_ctx (list_frames
, NULL
, MONO_UNWIND_NONE
, NULL
);
839 describe_variable (MonoStackFrameInfo
*info
, MonoContext
*ctx
, gpointer ud
)
842 MonoMethodHeader
*header
= NULL
;
844 FrameDescData
*data
= ud
;
847 if (info
->type
!= FRAME_TYPE_MANAGED
&& info
->type
!= FRAME_TYPE_INTERP
) {
851 if (data
->cur_frame
< data
->target_frame
) {
856 InterpFrame
*frame
= info
->interp_frame
;
858 MonoMethod
*method
= frame
->imethod
->method
;
861 MonoType
*type
= NULL
;
862 gpointer addr
= NULL
;
863 int pos
= data
->variable
;
866 type
= mono_method_signature (method
)->params
[pos
];
867 addr
= mini_get_interp_callbacks ()->frame_get_arg (frame
, pos
);
869 header
= mono_method_get_header_checked (method
, error
);
870 mono_error_assert_ok (error
); /* FIXME report error */
872 type
= header
->locals
[pos
];
873 addr
= mini_get_interp_callbacks ()->frame_get_local (frame
, pos
);
876 DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr
, type
, mono_type_full_name (type
));
878 switch (type
->type
) {
879 case MONO_TYPE_BOOLEAN
:
880 mono_wasm_add_bool_var (*(gint8
*)addr
);
884 mono_wasm_add_int_var (*(gint8
*)addr
);
889 mono_wasm_add_int_var (*(gint16
*)addr
);
895 mono_wasm_add_int_var (*(gint32
*)addr
);
899 mono_wasm_add_long_var (*(gint32
*)addr
);
902 mono_wasm_add_float_var (*(float*)addr
);
905 mono_wasm_add_float_var (*(double*)addr
);
907 case MONO_TYPE_STRING
: {
908 MonoString
*str_obj
= *(MonoString
**)addr
;
910 mono_wasm_add_string_var (NULL
);
911 char *str
= mono_string_to_utf8_checked (str_obj
, error
);
912 mono_error_assert_ok (error
); /* FIXME report error */
914 mono_wasm_add_string_var (str
);
919 char *type_name
= mono_type_full_name (type
);
920 char *msg
= g_strdup_printf("can't handle type %s [%p, %x]", type_name
, type
, type
->type
);
921 mono_wasm_add_string_var (msg
);
927 mono_metadata_free_mh (header
);
932 //FIXME this doesn't support getting the return value pseudo-var
933 EMSCRIPTEN_KEEPALIVE
void
934 mono_wasm_get_var_info (int scope
, int pos
)
936 DEBUG_PRINTF (2, "getting var %d of scope %d\n", pos
, scope
);
940 data
.target_frame
= scope
;
943 mono_walk_stack_with_ctx (describe_variable
, NULL
, MONO_UNWIND_NONE
, &data
);