Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 0 additions & 179 deletions src/mono/mono/mini/debugger-agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,35 +136,6 @@ typedef struct {
gboolean setpgid;
} AgentConfig;

typedef struct
{
//Must be the first field to ensure pointer equivalence
DbgEngineStackFrame de;
int id;
guint32 il_offset;
/*
* If method is gshared, this is the actual instance, otherwise this is equal to
* method.
*/
MonoMethod *actual_method;
/*
* This is the method which is visible to debugger clients. Same as method,
* except for native-to-managed wrappers.
*/
MonoMethod *api_method;
MonoContext ctx;
MonoDebugMethodJitInfo *jit;
MonoInterpFrameHandle interp_frame;
gpointer frame_addr;
int flags;
host_mgreg_t *reg_locations [MONO_MAX_IREGS];
/*
* Whenever ctx is set. This is FALSE for the last frame of running threads, since
* the frame can become invalid.
*/
gboolean has_ctx;
} StackFrame;

typedef struct _InvokeData InvokeData;

struct _InvokeData
Expand Down Expand Up @@ -740,8 +711,6 @@ static void ss_calculate_framecount (void *tls, MonoContext *ctx, gboolean force
static gboolean ensure_jit (DbgEngineStackFrame* the_frame);
static int ensure_runtime_is_suspended (void);
static int get_this_async_id (DbgEngineStackFrame *frame);
static gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame);
static MonoMethod* get_notify_debugger_of_wait_completion_method (void);
static void* create_breakpoint_events (GPtrArray *ss_reqs, GPtrArray *bp_reqs, MonoJitInfo *ji, EventKind kind);
static void process_breakpoint_events (void *_evts, MonoMethod *method, MonoContext *ctx, int il_offset);
static int ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args);
Expand Down Expand Up @@ -4551,114 +4520,6 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly;
}

static gpointer
get_this_addr (DbgEngineStackFrame *the_frame)
{
StackFrame *frame = (StackFrame *)the_frame;
if (frame->de.ji->is_interp)
return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);

MonoDebugVarInfo *var = frame->jit->this_var;
if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET)
return NULL;

guint8 *addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS);
addr += (gint32)var->offset;
return addr;
}

static MonoMethod*
get_set_notification_method (MonoClass* async_builder_class)
{
ERROR_DECL (error);
GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
if (array->len == 0) {
g_ptr_array_free (array, TRUE);
return NULL;
}
MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return set_notification_method;
}

static MonoMethod*
get_object_id_for_debugger_method (MonoClass* async_builder_class)
{
ERROR_DECL (error);
GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
if (array->len != 1) {
g_ptr_array_free (array, TRUE);
//if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug.
MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task");
if (!prop) {
DEBUG_PRINTF (1, "Impossible to debug async methods.\n");
return NULL;
}
return prop->get;
}
MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return method;
}

static MonoClass *
get_class_to_get_builder_field(DbgEngineStackFrame *frame)
{
ERROR_DECL (error);
gpointer this_addr = get_this_addr (frame);
MonoClass *original_class = frame->method->klass;
MonoClass *ret;
if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) {
MonoObject *this_obj = *(MonoObject**)this_addr;
MonoGenericContext context;
MonoType *inflated_type;

if (!this_obj)
return NULL;

context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable);
inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error);
mono_error_assert_ok (error); /* FIXME don't swallow the error */

ret = mono_class_from_mono_type_internal (inflated_type);
mono_metadata_free_type (inflated_type);
return ret;
}
return original_class;
}


/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */
static gpointer
get_async_method_builder (DbgEngineStackFrame *frame)
{
MonoObject *this_obj;
MonoClassField *builder_field;
gpointer builder;
gpointer this_addr;
MonoClass* klass = frame->method->klass;

klass = get_class_to_get_builder_field(frame);
builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL);
if (!builder_field)
return NULL;

this_addr = get_this_addr (frame);
if (!this_addr)
return NULL;

if (m_class_is_valuetype (klass)) {
builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field);
} else {
this_obj = *(MonoObject**)this_addr;
builder = (char*)this_obj + builder_field->offset;
}

return builder;
}

//This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
//since thread probably changed...
static int
Expand Down Expand Up @@ -4706,46 +4567,6 @@ get_this_async_id (DbgEngineStackFrame *frame)
return get_objid (obj);
}

// Returns true if TaskBuilder has NotifyDebuggerOfWaitCompletion method
// false if not(AsyncVoidBuilder)
static gboolean
set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
{
MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
if (!builder_field)
return FALSE;
gpointer builder = get_async_method_builder (frame);
if (!builder)
return FALSE;

MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type));
if (method == NULL)
return FALSE;
gboolean arg = TRUE;
ERROR_DECL (error);
void *args [ ] = { &arg };
mono_runtime_invoke_checked (method, builder, args, error);
mono_error_assert_ok (error);
return TRUE;
}

static MonoMethod* notify_debugger_of_wait_completion_method_cache;

static MonoMethod*
get_notify_debugger_of_wait_completion_method (void)
{
if (notify_debugger_of_wait_completion_method_cache != NULL)
return notify_debugger_of_wait_completion_method_cache;
ERROR_DECL (error);
MonoClass* task_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading.Tasks", "Task");
GPtrArray* array = mono_class_get_methods_by_name (task_class, "NotifyDebuggerOfWaitCompletion", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
g_assert (array->len == 1);
notify_debugger_of_wait_completion_method_cache = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return notify_debugger_of_wait_completion_method_cache;
}

static gboolean
begin_breakpoint_processing (void *the_tls, MonoContext *ctx, MonoJitInfo *ji, gboolean from_signal)
{
Expand Down
149 changes: 149 additions & 0 deletions src/mono/mono/mini/debugger-engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1606,4 +1606,153 @@ mono_debugger_free_objref (gpointer value)

g_free (o);
}

// Returns true if TaskBuilder has NotifyDebuggerOfWaitCompletion method
// false if not(AsyncVoidBuilder)
MonoClass *
get_class_to_get_builder_field(DbgEngineStackFrame *frame)
{
ERROR_DECL (error);
gpointer this_addr = get_this_addr (frame);
MonoClass *original_class = frame->method->klass;
MonoClass *ret;
if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) {
MonoObject *this_obj = *(MonoObject**)this_addr;
MonoGenericContext context;
MonoType *inflated_type;

if (!this_obj)
return NULL;

context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable);
inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error);
mono_error_assert_ok (error); /* FIXME don't swallow the error */

ret = mono_class_from_mono_type_internal (inflated_type);
mono_metadata_free_type (inflated_type);
return ret;
}
return original_class;
}

MonoMethod*
get_object_id_for_debugger_method (MonoClass* async_builder_class)
{
ERROR_DECL (error);
GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
if (array->len != 1) {
g_ptr_array_free (array, TRUE);
//if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug.
MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task");
if (!prop) {
DEBUG_PRINTF (1, "Impossible to debug async methods.\n");
return NULL;
}
return prop->get;
}
MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return method;
}

gboolean
set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
{
MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
if (!builder_field)
return FALSE;
gpointer builder = get_async_method_builder (frame);
if (!builder)
return FALSE;

MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type));
if (method == NULL)
return FALSE;
gboolean arg = TRUE;
ERROR_DECL (error);
void *args [ ] = { &arg };
mono_runtime_invoke_checked (method, builder, args, error);
mono_error_assert_ok (error);
return TRUE;
}

gpointer
get_this_addr (DbgEngineStackFrame *the_frame)
{
StackFrame *frame = (StackFrame *)the_frame;
if (frame->de.ji->is_interp)
return mini_get_interp_callbacks ()->frame_get_this (frame->interp_frame);

MonoDebugVarInfo *var = frame->jit->this_var;
if ((var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS) != MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET)
return NULL;

guint8 *addr = (guint8 *)mono_arch_context_get_int_reg (&frame->ctx, var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS);
addr += (gint32)var->offset;
return addr;
}

/* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */
gpointer
get_async_method_builder (DbgEngineStackFrame *frame)
{
MonoObject *this_obj;
MonoClassField *builder_field;
gpointer builder;
gpointer this_addr;
MonoClass* klass = frame->method->klass;

klass = get_class_to_get_builder_field(frame);
builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL);
if (!builder_field)
return NULL;

this_addr = get_this_addr (frame);
if (!this_addr)
return NULL;

if (m_class_is_valuetype (klass)) {
builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field);
} else {
this_obj = *(MonoObject**)this_addr;
builder = (char*)this_obj + builder_field->offset;
}

return builder;
}

MonoMethod*
get_set_notification_method (MonoClass* async_builder_class)
{
ERROR_DECL (error);
GPtrArray* array = mono_class_get_methods_by_name (async_builder_class, "SetNotificationForWaitCompletion", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
if (array->len == 0) {
g_ptr_array_free (array, TRUE);
return NULL;
}
MonoMethod* set_notification_method = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return set_notification_method;
}

static MonoMethod* notify_debugger_of_wait_completion_method_cache;

MonoMethod*
get_notify_debugger_of_wait_completion_method (void)
{
if (notify_debugger_of_wait_completion_method_cache != NULL)
return notify_debugger_of_wait_completion_method_cache;
ERROR_DECL (error);
MonoClass* task_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading.Tasks", "Task");
GPtrArray* array = mono_class_get_methods_by_name (task_class, "NotifyDebuggerOfWaitCompletion", 0x24, 1, FALSE, error);
mono_error_assert_ok (error);
g_assert (array->len == 1);
notify_debugger_of_wait_completion_method_cache = (MonoMethod *)g_ptr_array_index (array, 0);
g_ptr_array_free (array, TRUE);
return notify_debugger_of_wait_completion_method_cache;
}


#endif
Loading