Skip to content

Commit caa6ba1

Browse files
committed
Make rb_debug_inspector_backtrace_locations return a raw backtrace
Previously, a user of the debug inspector API was supposed to use `rb_debug_inspector_backtrace_locations` to get an array of `Thread::Backtrace::Location`, and then used its index to get more information from `rb_debug_inspector _frame_binding_get(index)`, etc. However, `rb_debug_inspector_backtrace_locations` returned an array of backtraces excluding rescue/ensure frames. On the other hand, `rb_debug_inspector_frame_binding_get(index)` interprets index with rescue/ensure frames. This led to inconsistency of the index, and it was very difficult to correctly use the debug inspector API. This is a minimal fix for the issue by making `rb_debug_inspector_backtrace_locations` return a raw backtrace including rescue/ensure frames.
1 parent 8d14d6e commit caa6ba1

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

vm_backtrace.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,9 +1493,8 @@ RUBY_SYMBOL_EXPORT_END
14931493
struct rb_debug_inspector_struct {
14941494
rb_execution_context_t *ec;
14951495
rb_control_frame_t *cfp;
1496-
VALUE backtrace;
14971496
VALUE contexts; /* [[klass, binding, iseq, cfp], ...] */
1498-
long backtrace_size;
1497+
VALUE raw_backtrace;
14991498
};
15001499

15011500
enum {
@@ -1504,18 +1503,22 @@ enum {
15041503
CALLER_BINDING_BINDING,
15051504
CALLER_BINDING_ISEQ,
15061505
CALLER_BINDING_CFP,
1506+
CALLER_BINDING_LOC,
15071507
CALLER_BINDING_DEPTH,
15081508
};
15091509

15101510
struct collect_caller_bindings_data {
15111511
VALUE ary;
15121512
const rb_execution_context_t *ec;
1513+
VALUE btobj;
1514+
rb_backtrace_t *bt;
15131515
};
15141516

15151517
static void
1516-
collect_caller_bindings_init(void *arg, size_t size)
1518+
collect_caller_bindings_init(void *arg, size_t num_frames)
15171519
{
1518-
/* */
1520+
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1521+
data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
15191522
}
15201523

15211524
static VALUE
@@ -1553,6 +1556,14 @@ collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
15531556
rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
15541557
rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
15551558
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1559+
1560+
rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
1561+
RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1562+
RB_OBJ_WRITE(data->btobj, &loc->iseq, cfp->iseq);
1563+
loc->pc = cfp->pc;
1564+
VALUE vloc = location_create(loc, (void *)data->btobj);
1565+
rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1566+
15561567
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
15571568

15581569
rb_ary_push(data->ary, frame);
@@ -1569,6 +1580,14 @@ collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
15691580
rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
15701581
rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
15711582
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1583+
1584+
rb_backtrace_location_t *loc = &data->bt->backtrace[data->bt->backtrace_size++];
1585+
RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1586+
loc->iseq = NULL;
1587+
loc->pc = NULL;
1588+
VALUE vloc = location_create(loc, (void *)data->btobj);
1589+
rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1590+
15721591
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
15731592

15741593
rb_ary_push(data->ary, frame);
@@ -1617,15 +1636,19 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
16171636
rb_execution_context_t *ec = GET_EC();
16181637
enum ruby_tag_type state;
16191638
volatile VALUE MAYBE_UNUSED(result);
1639+
int i;
16201640

16211641
/* escape all env to heap */
16221642
rb_vm_stack_to_heap(ec);
16231643

16241644
dbg_context.ec = ec;
16251645
dbg_context.cfp = dbg_context.ec->cfp;
1626-
dbg_context.backtrace = rb_ec_backtrace_location_ary(ec, RUBY_BACKTRACE_START, RUBY_ALL_BACKTRACE_LINES, FALSE);
1627-
dbg_context.backtrace_size = RARRAY_LEN(dbg_context.backtrace);
16281646
dbg_context.contexts = collect_caller_bindings(ec);
1647+
dbg_context.raw_backtrace = rb_ary_new();
1648+
for (i=0; i<RARRAY_LEN(dbg_context.contexts); i++) {
1649+
VALUE frame = rb_ary_entry(dbg_context.contexts, i);
1650+
rb_ary_push(dbg_context.raw_backtrace, rb_ary_entry(frame, CALLER_BINDING_LOC));
1651+
}
16291652

16301653
EC_PUSH_TAG(ec);
16311654
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
@@ -1645,7 +1668,7 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
16451668
static VALUE
16461669
frame_get(const rb_debug_inspector_t *dc, long index)
16471670
{
1648-
if (index < 0 || index >= dc->backtrace_size) {
1671+
if (index < 0 || index >= RARRAY_LEN(dc->contexts)) {
16491672
rb_raise(rb_eArgError, "no such frame");
16501673
}
16511674
return rb_ary_entry(dc->contexts, index);
@@ -1698,7 +1721,7 @@ rb_debug_inspector_current_depth(void)
16981721
VALUE
16991722
rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
17001723
{
1701-
return dc->backtrace;
1724+
return dc->raw_backtrace;
17021725
}
17031726

17041727
static int

0 commit comments

Comments
 (0)