2 * debug-mini.c: Mini-specific debugging stuff.
5 * Martin Baulig (martin@ximian.com)
7 * (C) 2003 Ximian, Inc.
13 #include <mono/metadata/verify.h>
14 #include <mono/metadata/mono-config.h>
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/threads-types.h>
19 #define _IN_THE_MONO_DEBUGGER
20 #include <mono/metadata/mono-debug-debugger.h>
21 #include "debug-mini.h"
23 #ifdef HAVE_VALGRIND_H
24 #include <valgrind/valgrind.h>
27 #ifdef MONO_DEBUGGER_SUPPORTED
28 #include <libgc/include/libgc-mono-debugger.h>
34 } MiniDebugBreakpointInfo
;
38 MonoDebugMethodJitInfo
*jit
;
40 guint32 has_line_numbers
;
41 guint32 breakpoint_id
;
42 } MiniDebugMethodInfo
;
45 MonoObject
*last_exception
;
46 guint32 stopped_on_exception
: 1;
47 guint32 stopped_on_unhandled
: 1;
48 } MonoDebuggerExceptionState
;
51 MONO_DEBUGGER_THREAD_FLAGS_NONE
= 0,
52 MONO_DEBUGGER_THREAD_FLAGS_INTERNAL
= 1,
53 MONO_DEBUGGER_THREAD_FLAGS_THREADPOOL
= 2
54 } MonoDebuggerThreadFlags
;
56 struct _MonoDebuggerThreadInfo
{
61 guint64 extended_notifications
;
64 MonoDebuggerThreadInfo
*next
;
67 * The stack bounds are only used when reading a core file.
70 guint64 signal_stack_start
;
72 guint32 signal_stack_size
;
77 * The debugger doesn't access anything beyond this point.
79 MonoDebuggerExceptionState exception_state
;
81 MonoJitTlsData
*jit_tls
;
86 gpointer stack_pointer
;
87 MonoObject
*exception_obj
;
89 guint32 stop_unhandled
;
90 } MonoDebuggerExceptionInfo
;
92 MonoDebuggerThreadInfo
*mono_debugger_thread_table
= NULL
;
95 record_line_number (MiniDebugMethodInfo
*info
, guint32 address
, guint32 offset
)
97 MonoDebugLineNumberEntry lne
;
99 lne
.native_offset
= address
;
100 lne
.il_offset
= offset
;
102 g_array_append_val (info
->line_numbers
, lne
);
107 mono_debug_init_method (MonoCompile
*cfg
, MonoBasicBlock
*start_block
, guint32 breakpoint_id
)
109 MiniDebugMethodInfo
*info
;
111 if (mono_debug_format
== MONO_DEBUG_FORMAT_NONE
)
114 info
= g_new0 (MiniDebugMethodInfo
, 1);
115 info
->breakpoint_id
= breakpoint_id
;
117 cfg
->debug_info
= info
;
121 mono_debug_open_method (MonoCompile
*cfg
)
123 MiniDebugMethodInfo
*info
;
124 MonoDebugMethodJitInfo
*jit
;
125 MonoMethodHeader
*header
;
127 info
= (MiniDebugMethodInfo
*) cfg
->debug_info
;
131 mono_class_init (cfg
->method
->klass
);
133 header
= mono_method_get_header (cfg
->method
);
136 info
->jit
= jit
= g_new0 (MonoDebugMethodJitInfo
, 1);
137 info
->line_numbers
= g_array_new (FALSE
, TRUE
, sizeof (MonoDebugLineNumberEntry
));
138 jit
->num_locals
= header
->num_locals
;
139 jit
->locals
= g_new0 (MonoDebugVarInfo
, jit
->num_locals
);
143 write_variable (MonoInst
*inst
, MonoDebugVarInfo
*var
)
145 var
->type
= inst
->inst_vtype
;
147 if (inst
->opcode
== OP_REGVAR
)
148 var
->index
= inst
->dreg
| MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
;
149 else if (inst
->flags
& MONO_INST_IS_DEAD
)
150 var
->index
= MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
;
152 /* the debug interface needs fixing to allow 0(%base) address */
153 var
->index
= inst
->inst_basereg
| MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
;
154 var
->offset
= inst
->inst_offset
;
159 * mono_debug_add_vg_method:
161 * Register symbol information for the method with valgrind
164 mono_debug_add_vg_method (MonoMethod
*method
, MonoDebugMethodJitInfo
*jit
)
166 #ifdef VALGRIND_ADD_LINE_INFO
167 MonoMethodHeader
*header
;
168 MonoDebugMethodInfo
*minfo
;
170 char *filename
= NULL
;
171 guint32 address
, line_number
;
172 const char *full_name
;
176 if (!RUNNING_ON_VALGRIND
)
179 header
= mono_method_get_header (method
);
181 full_name
= mono_method_full_name (method
, TRUE
);
183 addresses
= g_new0 (guint32
, header
->code_size
+ 1);
184 lines
= g_new0 (guint32
, header
->code_size
+ 1);
187 * Very simple code to convert the addr->offset mappings that mono has
188 * into [addr-addr] ->line number mappings.
191 minfo
= mono_debug_lookup_method (method
);
193 /* Create offset->line number mapping */
194 for (i
= 0; i
< header
->code_size
; ++i
) {
195 MonoDebugSourceLocation
*location
;
197 location
= mono_debug_symfile_lookup_location (minfo
, i
);
201 lines
[i
] = location
.row
;
203 filename
= location
.source_file
;
205 mono_debug_free_source_location (location
);
209 /* Create address->offset mapping */
210 for (i
= 0; i
< jit
->num_line_numbers
; ++i
) {
211 MonoDebugLineNumberEntry
*lne
= jit
->line_numbers
[i
];
213 g_assert (lne
->offset
<= header
->code_size
);
215 if ((addresses
[lne
->offset
] == 0) || (lne
->address
< addresses
[lne
->offset
]))
216 addresses
[lne
->offset
] = lne
->address
;
218 /* Fill out missing addresses */
220 for (i
= 0; i
< header
->code_size
; ++i
) {
221 if (addresses
[i
] == 0)
222 addresses
[i
] = address
;
224 address
= addresses
[i
];
230 while (i
< header
->code_size
) {
231 if (lines
[i
] == line_number
)
234 if (line_number
> 0) {
235 //g_assert (addresses [i] - 1 >= address);
237 if (addresses
[i
] - 1 >= address
) {
238 VALGRIND_ADD_LINE_INFO (jit
->code_start
+ address
, jit
->code_start
+ addresses
[i
] - 1, filename
, line_number
);
239 //printf ("[%d-%d] -> %d.\n", address, addresses [i] - 1, line_number);
242 address
= addresses
[i
];
243 line_number
= lines
[i
];
247 if (line_number
> 0) {
248 VALGRIND_ADD_LINE_INFO (jit
->code_start
+ address
, jit
->code_start
+ jit
->code_size
- 1, filename
, line_number
);
249 //printf ("[%d-%d] -> %d.\n", address, jit->code_size - 1, line_number);
252 VALGRIND_ADD_SYMBOL (jit
->code_start
, jit
->code_size
, full_name
);
256 #endif /* VALGRIND_ADD_LINE_INFO */
260 mono_debug_close_method (MonoCompile
*cfg
)
262 MiniDebugMethodInfo
*info
;
263 MonoDebugMethodJitInfo
*jit
;
264 MonoMethodHeader
*header
;
265 MonoMethodSignature
*sig
;
266 MonoDebugMethodAddress
*debug_info
;
270 info
= (MiniDebugMethodInfo
*) cfg
->debug_info
;
271 if (!info
|| !info
->jit
) {
277 method
= cfg
->method
;
278 header
= mono_method_get_header (method
);
279 sig
= mono_method_signature (method
);
282 jit
->code_start
= cfg
->native_code
;
283 jit
->epilogue_begin
= cfg
->epilog_begin
;
284 jit
->code_size
= cfg
->code_len
;
286 if (jit
->epilogue_begin
)
287 record_line_number (info
, jit
->epilogue_begin
, header
->code_size
);
289 jit
->num_params
= sig
->param_count
;
290 jit
->params
= g_new0 (MonoDebugVarInfo
, jit
->num_params
);
292 for (i
= 0; i
< jit
->num_locals
; i
++)
293 write_variable (cfg
->locals
[i
], &jit
->locals
[i
]);
296 jit
->this_var
= g_new0 (MonoDebugVarInfo
, 1);
297 write_variable (cfg
->args
[0], jit
->this_var
);
300 for (i
= 0; i
< jit
->num_params
; i
++)
301 write_variable (cfg
->args
[i
+ sig
->hasthis
], &jit
->params
[i
]);
303 jit
->num_line_numbers
= info
->line_numbers
->len
;
304 jit
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, jit
->num_line_numbers
);
306 for (i
= 0; i
< jit
->num_line_numbers
; i
++)
307 jit
->line_numbers
[i
] = g_array_index (info
->line_numbers
, MonoDebugLineNumberEntry
, i
);
309 debug_info
= mono_debug_add_method (cfg
->method_to_register
, jit
, cfg
->domain
);
311 mono_debug_add_vg_method (method
, jit
);
313 mono_debugger_check_breakpoints (method
, debug_info
);
315 mono_debug_free_method_jit_info (jit
);
316 g_array_free (info
->line_numbers
, TRUE
);
321 mono_debug_record_line_number (MonoCompile
*cfg
, MonoInst
*ins
, guint32 address
)
323 MiniDebugMethodInfo
*info
;
324 MonoMethodHeader
*header
;
327 info
= (MiniDebugMethodInfo
*) cfg
->debug_info
;
328 if (!info
|| !info
->jit
|| !ins
->cil_code
)
331 header
= mono_method_get_header (cfg
->method
);
334 if ((ins
->cil_code
< header
->code
) ||
335 (ins
->cil_code
> header
->code
+ header
->code_size
))
338 offset
= ins
->cil_code
- header
->code
;
339 if (!info
->has_line_numbers
) {
340 info
->jit
->prologue_end
= address
;
341 info
->has_line_numbers
= TRUE
;
344 record_line_number (info
, address
, offset
);
348 mono_debug_open_block (MonoCompile
*cfg
, MonoBasicBlock
*bb
, guint32 address
)
350 MiniDebugMethodInfo
*info
;
351 MonoMethodHeader
*header
;
354 info
= (MiniDebugMethodInfo
*) cfg
->debug_info
;
355 if (!info
|| !info
->jit
|| !bb
->cil_code
)
358 header
= mono_method_get_header (cfg
->method
);
361 if ((bb
->cil_code
< header
->code
) ||
362 (bb
->cil_code
> header
->code
+ header
->code_size
))
365 offset
= bb
->cil_code
- header
->code
;
366 if (!info
->has_line_numbers
) {
367 info
->jit
->prologue_end
= address
;
368 info
->has_line_numbers
= TRUE
;
371 record_line_number (info
, address
, offset
);
375 encode_value (gint32 value
, guint8
*buf
, guint8
**endbuf
)
379 //printf ("ENCODE: %d 0x%x.\n", value, value);
382 * Same encoding as the one used in the metadata, extended to handle values
383 * greater than 0x1fffffff.
385 if ((value
>= 0) && (value
<= 127))
387 else if ((value
>= 0) && (value
<= 16383)) {
388 p
[0] = 0x80 | (value
>> 8);
389 p
[1] = value
& 0xff;
391 } else if ((value
>= 0) && (value
<= 0x1fffffff)) {
392 p
[0] = (value
>> 24) | 0xc0;
393 p
[1] = (value
>> 16) & 0xff;
394 p
[2] = (value
>> 8) & 0xff;
395 p
[3] = value
& 0xff;
400 p
[1] = (value
>> 24) & 0xff;
401 p
[2] = (value
>> 16) & 0xff;
402 p
[3] = (value
>> 8) & 0xff;
403 p
[4] = value
& 0xff;
411 decode_value (guint8
*ptr
, guint8
**rptr
)
416 if ((b
& 0x80) == 0){
419 } else if ((b
& 0x40) == 0){
420 len
= ((b
& 0x3f) << 8 | ptr
[1]);
422 } else if (b
!= 0xff) {
423 len
= ((b
& 0x1f) << 24) |
430 len
= (ptr
[1] << 24) | (ptr
[2] << 16) | (ptr
[3] << 8) | ptr
[4];
436 //printf ("DECODE: %d.\n", len);
441 serialize_variable (MonoDebugVarInfo
*var
, guint8
*p
, guint8
**endbuf
)
443 guint32 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
445 encode_value (var
->index
, p
, &p
);
448 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
450 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
451 encode_value (var
->offset
, p
, &p
);
453 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
456 g_assert_not_reached ();
462 mono_debug_serialize_debug_info (MonoCompile
*cfg
, guint8
**out_buf
, guint32
*buf_len
)
464 MonoDebugMethodJitInfo
*jit
;
465 guint32 size
, prev_offset
, prev_native_offset
;
469 /* Can't use cfg->debug_info as it is freed by close_method () */
470 jit
= mono_debug_find_method (cfg
->method
, mono_domain_get ());
476 size
= ((jit
->num_params
+ jit
->num_locals
+ 1) * 10) + (jit
->num_line_numbers
* 10) + 64;
477 p
= buf
= g_malloc (size
);
478 encode_value (jit
->epilogue_begin
, p
, &p
);
479 encode_value (jit
->prologue_end
, p
, &p
);
480 encode_value (jit
->code_size
, p
, &p
);
482 for (i
= 0; i
< jit
->num_params
; ++i
)
483 serialize_variable (&jit
->params
[i
], p
, &p
);
485 if (mono_method_signature (cfg
->method
)->hasthis
)
486 serialize_variable (jit
->this_var
, p
, &p
);
488 for (i
= 0; i
< jit
->num_locals
; i
++)
489 serialize_variable (&jit
->locals
[i
], p
, &p
);
491 encode_value (jit
->num_line_numbers
, p
, &p
);
494 prev_native_offset
= 0;
495 for (i
= 0; i
< jit
->num_line_numbers
; ++i
) {
496 /* Sometimes, the offset values are not in increasing order */
497 MonoDebugLineNumberEntry
*lne
= &jit
->line_numbers
[i
];
498 encode_value (lne
->il_offset
- prev_offset
, p
, &p
);
499 encode_value (lne
->native_offset
- prev_native_offset
, p
, &p
);
500 prev_offset
= lne
->il_offset
;
501 prev_native_offset
= lne
->native_offset
;
504 g_assert (p
- buf
< size
);
511 deserialize_variable (MonoDebugVarInfo
*var
, guint8
*p
, guint8
**endbuf
)
515 var
->index
= decode_value (p
, &p
);
517 flags
= var
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
;
520 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
522 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
523 var
->offset
= decode_value (p
, &p
);
525 case MONO_DEBUG_VAR_ADDRESS_MODE_DEAD
:
528 g_assert_not_reached ();
533 static MonoDebugMethodJitInfo
*
534 deserialize_debug_info (MonoMethod
*method
, guint8
*code_start
, guint8
*buf
, guint32 buf_len
)
536 MonoMethodHeader
*header
;
537 gint32 offset
, native_offset
, prev_offset
, prev_native_offset
;
538 MonoDebugMethodJitInfo
*jit
;
542 header
= mono_method_get_header (method
);
545 jit
= g_new0 (MonoDebugMethodJitInfo
, 1);
546 jit
->code_start
= code_start
;
547 jit
->num_locals
= header
->num_locals
;
548 jit
->locals
= g_new0 (MonoDebugVarInfo
, jit
->num_locals
);
549 jit
->num_params
= mono_method_signature (method
)->param_count
;
550 jit
->params
= g_new0 (MonoDebugVarInfo
, jit
->num_params
);
553 jit
->epilogue_begin
= decode_value (p
, &p
);
554 jit
->prologue_end
= decode_value (p
, &p
);
555 jit
->code_size
= decode_value (p
, &p
);
557 for (i
= 0; i
< jit
->num_params
; ++i
)
558 deserialize_variable (&jit
->params
[i
], p
, &p
);
560 if (mono_method_signature (method
)->hasthis
) {
561 jit
->this_var
= g_new0 (MonoDebugVarInfo
, 1);
562 deserialize_variable (jit
->this_var
, p
, &p
);
565 for (i
= 0; i
< jit
->num_locals
; i
++)
566 deserialize_variable (&jit
->locals
[i
], p
, &p
);
568 jit
->num_line_numbers
= decode_value (p
, &p
);
569 jit
->line_numbers
= g_new0 (MonoDebugLineNumberEntry
, jit
->num_line_numbers
);
572 prev_native_offset
= 0;
573 for (i
= 0; i
< jit
->num_line_numbers
; ++i
) {
574 MonoDebugLineNumberEntry
*lne
= &jit
->line_numbers
[i
];
576 offset
= prev_offset
+ decode_value (p
, &p
);
577 native_offset
= prev_native_offset
+ decode_value (p
, &p
);
579 lne
->native_offset
= native_offset
;
580 lne
->il_offset
= offset
;
582 prev_offset
= offset
;
583 prev_native_offset
= native_offset
;
590 mono_debug_add_aot_method (MonoDomain
*domain
, MonoMethod
*method
, guint8
*code_start
,
591 guint8
*debug_info
, guint32 debug_info_len
)
593 MonoDebugMethodJitInfo
*jit
;
595 if (mono_debug_format
== MONO_DEBUG_FORMAT_NONE
)
598 if ((method
->iflags
& METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
) ||
599 (method
->iflags
& METHOD_IMPL_ATTRIBUTE_RUNTIME
) ||
600 (method
->flags
& METHOD_ATTRIBUTE_PINVOKE_IMPL
) ||
601 (method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
) ||
602 (method
->wrapper_type
!= MONO_WRAPPER_NONE
))
605 if (debug_info_len
== 0)
608 jit
= deserialize_debug_info (method
, code_start
, debug_info
, debug_info_len
);
610 mono_debug_add_method (method
, jit
, domain
);
612 mono_debug_add_vg_method (method
, jit
);
614 mono_debug_free_method_jit_info (jit
);
618 mono_debug_add_icall_wrapper (MonoMethod
*method
, MonoJitICallInfo
* callinfo
)
620 if (mono_debug_format
== MONO_DEBUG_FORMAT_NONE
)
623 // mono_debug_add_wrapper (method, callinfo->wrapper, callinfo->func);
627 print_var_info (MonoDebugVarInfo
*info
, int idx
, const char *name
, const char *type
)
629 switch (info
->index
& MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
) {
630 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
631 g_print ("%s %s (%d) in register %s\n", type
, name
, idx
, mono_arch_regname (info
->index
& (~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
)));
633 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
634 g_print ("%s %s (%d) in memory: base register %s + %d\n", type
, name
, idx
, mono_arch_regname (info
->index
& (~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS
)), info
->offset
);
636 case MONO_DEBUG_VAR_ADDRESS_MODE_TWO_REGISTERS
:
638 g_assert_not_reached ();
643 * mono_debug_print_locals:
645 * Prints to stdout the information about the local variables in
646 * a method (if @only_arguments is false) or about the arguments.
647 * The information includes the storage info (where the variable
648 * lives, in a register or in memory).
649 * The method is found by looking up what method has been emitted at
650 * the instruction address @ip.
651 * This is for use inside a debugger.
654 mono_debug_print_vars (gpointer ip
, gboolean only_arguments
)
656 MonoDomain
*domain
= mono_domain_get ();
657 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, ip
);
658 MonoDebugMethodJitInfo
*jit
;
664 jit
= mono_debug_find_method (mono_jit_info_get_method (ji
), domain
);
668 if (only_arguments
) {
670 names
= g_new (char *, jit
->num_params
);
671 mono_method_get_param_names (mono_jit_info_get_method (ji
), (const char **) names
);
673 print_var_info (jit
->this_var
, 0, "this", "Arg");
674 for (i
= 0; i
< jit
->num_params
; ++i
) {
675 print_var_info (&jit
->params
[i
], i
, names
[i
]? names
[i
]: "unknown name", "Arg");
679 for (i
= 0; i
< jit
->num_locals
; ++i
) {
680 print_var_info (&jit
->locals
[i
], i
, "", "Local");
683 mono_debug_free_method_jit_info (jit
);
687 * The old Debugger breakpoint interface.
689 * This interface is used to insert breakpoints on methods which are not yet JITed.
690 * The debugging code keeps a list of all such breakpoints and automatically inserts the
691 * breakpoint when the method is JITed.
694 static GPtrArray
*breakpoints
= NULL
;
697 mono_debugger_insert_breakpoint_full (MonoMethodDesc
*desc
)
699 static int last_breakpoint_id
= 0;
700 MiniDebugBreakpointInfo
*info
;
702 info
= g_new0 (MiniDebugBreakpointInfo
, 1);
704 info
->index
= ++last_breakpoint_id
;
707 breakpoints
= g_ptr_array_new ();
709 g_ptr_array_add (breakpoints
, info
);
715 mono_debugger_remove_breakpoint (int breakpoint_id
)
722 for (i
= 0; i
< breakpoints
->len
; i
++) {
723 MiniDebugBreakpointInfo
*info
= g_ptr_array_index (breakpoints
, i
);
725 if (info
->index
!= breakpoint_id
)
728 mono_method_desc_free (info
->desc
);
729 g_ptr_array_remove (breakpoints
, info
);
738 mono_debugger_insert_breakpoint (const gchar
*method_name
, gboolean include_namespace
)
740 MonoMethodDesc
*desc
;
742 desc
= mono_method_desc_new (method_name
, include_namespace
);
746 return mono_debugger_insert_breakpoint_full (desc
);
750 mono_debugger_method_has_breakpoint (MonoMethod
*method
)
754 if (!breakpoints
|| ((method
->wrapper_type
!= MONO_WRAPPER_NONE
) &&
755 (method
->wrapper_type
!= MONO_WRAPPER_DYNAMIC_METHOD
)))
758 for (i
= 0; i
< breakpoints
->len
; i
++) {
759 MiniDebugBreakpointInfo
*info
= g_ptr_array_index (breakpoints
, i
);
761 if (!mono_method_desc_full_match (info
->desc
, method
))
771 mono_debugger_breakpoint_callback (MonoMethod
*method
, guint32 index
)
773 mono_debugger_event (MONO_DEBUGGER_EVENT_JIT_BREAKPOINT
, (guint64
) (gsize
) method
, index
);
777 mono_debugger_thread_created (gsize tid
, MonoThread
*thread
, MonoJitTlsData
*jit_tls
, gpointer func
)
779 #ifdef MONO_DEBUGGER_SUPPORTED
781 guint8
*staddr
= NULL
;
782 MonoDebuggerThreadInfo
*info
;
784 if (mono_debug_format
== MONO_DEBUG_FORMAT_NONE
)
787 mono_debugger_lock ();
789 mono_thread_get_stack_bounds (&staddr
, &stsize
);
791 info
= g_new0 (MonoDebuggerThreadInfo
, 1);
793 info
->thread
= thread
;
794 info
->stack_start
= (guint64
) (gsize
) staddr
;
795 info
->signal_stack_start
= (guint64
) (gsize
) jit_tls
->signal_stack
;
796 info
->stack_size
= stsize
;
797 info
->signal_stack_size
= jit_tls
->signal_stack_size
;
798 info
->end_stack
= (guint64
) (gsize
) GC_mono_debugger_get_stack_ptr ();
799 info
->lmf_addr
= (guint64
) (gsize
) mono_get_lmf_addr ();
800 info
->jit_tls
= jit_tls
;
803 info
->thread_flags
= MONO_DEBUGGER_THREAD_FLAGS_INTERNAL
;
804 if (thread
->internal_thread
->threadpool_thread
)
805 info
->thread_flags
|= MONO_DEBUGGER_THREAD_FLAGS_THREADPOOL
;
807 info
->next
= mono_debugger_thread_table
;
808 mono_debugger_thread_table
= info
;
810 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CREATED
,
811 tid
, (guint64
) (gsize
) info
);
813 mono_debugger_unlock ();
814 #endif /* MONO_DEBUGGER_SUPPORTED */
818 mono_debugger_thread_cleanup (MonoJitTlsData
*jit_tls
)
820 #ifdef MONO_DEBUGGER_SUPPORTED
821 MonoDebuggerThreadInfo
**ptr
;
823 if (mono_debug_format
== MONO_DEBUG_FORMAT_NONE
)
826 mono_debugger_lock ();
828 for (ptr
= &mono_debugger_thread_table
; *ptr
; ptr
= &(*ptr
)->next
) {
829 MonoDebuggerThreadInfo
*info
= *ptr
;
831 if (info
->jit_tls
!= jit_tls
)
834 mono_debugger_event (MONO_DEBUGGER_EVENT_THREAD_CLEANUP
,
835 info
->tid
, (guint64
) (gsize
) info
);
842 mono_debugger_unlock ();
847 mono_debugger_extended_notification (MonoDebuggerEvent event
, guint64 data
, guint64 arg
)
849 #ifdef MONO_DEBUGGER_SUPPORTED
850 MonoDebuggerThreadInfo
**ptr
;
851 MonoThread
*thread
= mono_thread_current ();
853 if (!mono_debug_using_mono_debugger ())
856 mono_debugger_lock ();
858 for (ptr
= &mono_debugger_thread_table
; *ptr
; ptr
= &(*ptr
)->next
) {
859 MonoDebuggerThreadInfo
*info
= *ptr
;
861 if (info
->thread
!= thread
)
864 if ((info
->extended_notifications
& (int) event
) == 0)
867 mono_debugger_event (event
, data
, arg
);
870 mono_debugger_unlock ();
875 mono_debugger_trampoline_compiled (const guint8
*trampoline
, MonoMethod
*method
, const guint8
*code
)
877 #ifdef MONO_DEBUGGER_SUPPORTED
879 const guint8
* trampoline
;
882 } info
= { trampoline
, method
, code
};
884 mono_debugger_extended_notification (MONO_DEBUGGER_EVENT_OLD_TRAMPOLINE
,
885 (guint64
) (gsize
) method
, (guint64
) (gsize
) code
);
886 mono_debugger_extended_notification (MONO_DEBUGGER_EVENT_TRAMPOLINE
,
887 (guint64
) (gsize
) &info
, 0);
891 #if MONO_DEBUGGER_SUPPORTED
892 static MonoDebuggerThreadInfo
*
893 find_debugger_thread_info (MonoThread
*thread
)
895 MonoDebuggerThreadInfo
**ptr
;
897 for (ptr
= &mono_debugger_thread_table
; *ptr
; ptr
= &(*ptr
)->next
) {
898 MonoDebuggerThreadInfo
*info
= *ptr
;
900 if (info
->thread
== thread
)
908 MonoDebuggerExceptionAction
909 _mono_debugger_throw_exception (gpointer addr
, gpointer stack
, MonoObject
*exc
)
911 #ifdef MONO_DEBUGGER_SUPPORTED
912 MonoDebuggerExceptionInfo exc_info
;
913 MonoDebuggerThreadInfo
*thread_info
;
915 if (!mono_debug_using_mono_debugger ())
916 return MONO_DEBUGGER_EXCEPTION_ACTION_NONE
;
918 mono_debugger_lock ();
920 thread_info
= find_debugger_thread_info (mono_thread_current ());
922 mono_debugger_unlock ();
923 return MONO_DEBUGGER_EXCEPTION_ACTION_NONE
;
926 if (thread_info
->exception_state
.stopped_on_exception
||
927 thread_info
->exception_state
.stopped_on_unhandled
) {
928 thread_info
->exception_state
.stopped_on_exception
= 0;
929 mono_debugger_unlock ();
930 return MONO_DEBUGGER_EXCEPTION_ACTION_NONE
;
933 /* Protect the exception object from being garbage collected. */
935 thread_info
->exception_state
.stopped_on_unhandled
= 0;
936 thread_info
->exception_state
.stopped_on_exception
= 1;
937 thread_info
->exception_state
.last_exception
= exc
;
940 * Backwards compatibility:
942 * Older debugger versions only know `exc_info.stop' and older runtime versions check
943 * `exc_info.stop != 0'.
945 * The debugger must check for `mono_debug_debugger_version >= 5' before accessing the
946 * `stop_unhandled' field.
949 exc_info
.stack_pointer
= stack
;
950 exc_info
.exception_obj
= exc
;
952 exc_info
.stop_unhandled
= 0;
954 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION
, (guint64
) (gsize
) &exc_info
,
955 (guint64
) (gsize
) addr
);
957 if (!exc_info
.stop
) {
958 thread_info
->exception_state
.stopped_on_exception
= 0;
959 thread_info
->exception_state
.last_exception
= NULL
;
962 mono_debugger_unlock ();
965 return MONO_DEBUGGER_EXCEPTION_ACTION_STOP
;
966 else if (exc_info
.stop_unhandled
)
967 return MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED
;
970 return MONO_DEBUGGER_EXCEPTION_ACTION_NONE
;
974 _mono_debugger_unhandled_exception (gpointer addr
, gpointer stack
, MonoObject
*exc
)
976 #ifdef MONO_DEBUGGER_SUPPORTED
977 MonoDebuggerThreadInfo
*thread_info
;
979 if (!mono_debug_using_mono_debugger ())
983 const gchar
*name
= mono_class_get_name (mono_object_get_class (exc
));
984 if (!strcmp (name
, "ThreadAbortException"))
988 mono_debugger_lock ();
990 thread_info
= find_debugger_thread_info (mono_thread_current ());
992 mono_debugger_unlock ();
996 if (thread_info
->exception_state
.stopped_on_unhandled
) {
997 thread_info
->exception_state
.stopped_on_unhandled
= 0;
998 mono_debugger_unlock ();
1002 thread_info
->exception_state
.stopped_on_unhandled
= 1;
1003 thread_info
->exception_state
.last_exception
= exc
;
1005 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION
,
1006 (guint64
) (gsize
) exc
, (guint64
) (gsize
) addr
);
1015 * mono_debugger_call_exception_handler:
1017 * Called from mono_handle_exception_internal() to tell the debugger that we're about
1018 * to invoke an exception handler.
1020 * The debugger may choose to set a breakpoint at @addr. This is used if the user is
1021 * single-stepping from a `try' into a `catch' block, for instance.
1025 mono_debugger_call_exception_handler (gpointer addr
, gpointer stack
, MonoObject
*exc
)
1027 #ifdef MONO_DEBUGGER_SUPPORTED
1028 MonoDebuggerThreadInfo
*thread_info
;
1029 MonoDebuggerExceptionInfo exc_info
;
1031 if (!mono_debug_using_mono_debugger ())
1034 mono_debugger_lock ();
1036 thread_info
= find_debugger_thread_info (mono_thread_current ());
1038 mono_debugger_unlock ();
1042 // Prevent the object from being finalized.
1043 thread_info
->exception_state
.last_exception
= exc
;
1045 exc_info
.stack_pointer
= stack
;
1046 exc_info
.exception_obj
= exc
;
1048 exc_info
.stop_unhandled
= 0;
1050 mono_debugger_event (MONO_DEBUGGER_EVENT_HANDLE_EXCEPTION
, (guint64
) (gsize
) &exc_info
,
1051 (guint64
) (gsize
) addr
);
1053 mono_debugger_unlock ();
1057 #ifdef MONO_DEBUGGER_SUPPORTED
1060 get_exception_message (MonoObject
*exc
)
1062 char *message
= NULL
;
1068 if (mono_object_isinst (exc
, mono_defaults
.exception_class
)) {
1069 klass
= exc
->vtable
->klass
;
1071 while (klass
&& method
== NULL
) {
1072 for (i
= 0; i
< klass
->method
.count
; ++i
) {
1073 method
= klass
->methods
[i
];
1074 if (!strcmp ("ToString", method
->name
) &&
1075 mono_method_signature (method
)->param_count
== 0 &&
1076 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1077 method
->flags
& METHOD_ATTRIBUTE_PUBLIC
) {
1084 klass
= klass
->parent
;
1089 str
= (MonoString
*) mono_runtime_invoke (method
, exc
, NULL
, NULL
);
1091 message
= mono_string_to_utf8 (str
);
1098 mono_debugger_runtime_invoke (MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
)
1100 MonoDebuggerThreadInfo
*thread_info
;
1101 MonoDebuggerExceptionState saved_exception_state
;
1105 mono_debugger_lock ();
1107 thread_info
= find_debugger_thread_info (mono_thread_current ());
1109 mono_debugger_unlock ();
1113 saved_exception_state
= thread_info
->exception_state
;
1115 thread_info
->exception_state
.last_exception
= NULL
;
1116 thread_info
->exception_state
.stopped_on_unhandled
= 0;
1117 thread_info
->exception_state
.stopped_on_exception
= 0;
1119 mono_debugger_unlock ();
1121 if (!strcmp (method
->name
, ".ctor")) {
1122 retval
= obj
= mono_object_new (mono_domain_get (), method
->klass
);
1124 mono_runtime_invoke (method
, obj
, params
, exc
);
1126 retval
= mono_runtime_invoke (method
, obj
, params
, exc
);
1128 mono_debugger_lock ();
1130 thread_info
= find_debugger_thread_info (mono_thread_current ());
1132 thread_info
->exception_state
= saved_exception_state
;
1134 mono_debugger_unlock ();
1136 if (!exc
|| (*exc
== NULL
))
1140 message
= get_exception_message (*exc
);
1142 *exc
= (MonoObject
*) mono_string_new_wrapper (message
);