Skip to content

Commit 83cb352

Browse files
committed
Fix a design issue in the debug inspector API
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 change deprecates `rb_debug_inspector_backtrace_locations` and introduces instead `rb_debug_inspector_frame_loc_get(index)`, which returns a `Thread::Backtrace::Location` object for the frame specified by `index`. Also `rb_debug_inspector_frame_count` is introduced to get the length of the backtrace.
1 parent 553753c commit 83cb352

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

ext/-test-/debug/inspector.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
static VALUE
55
callback(const rb_debug_inspector_t *dbg_context, void *data)
66
{
7-
VALUE locs = rb_debug_inspector_backtrace_locations(dbg_context);
8-
long i, len = RARRAY_LEN(locs);
7+
long i, len = rb_debug_inspector_frame_count(dbg_context);
98
VALUE binds = rb_ary_new();
109
for (i = 0; i < len; ++i) {
1110
VALUE entry = rb_ary_new();
@@ -14,7 +13,7 @@ callback(const rb_debug_inspector_t *dbg_context, void *data)
1413
rb_ary_push(entry, rb_debug_inspector_frame_binding_get(dbg_context, i));
1514
rb_ary_push(entry, rb_debug_inspector_frame_class_get(dbg_context, i));
1615
rb_ary_push(entry, rb_debug_inspector_frame_iseq_get(dbg_context, i));
17-
rb_ary_push(entry, rb_ary_entry(locs, i));
16+
rb_ary_push(entry, rb_debug_inspector_frame_loc_get(dbg_context, i));
1817
}
1918
return binds;
2019
}

include/ruby/debug.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,22 @@ VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data);
233233
* @param[in] dc A debug context.
234234
* @return An array of `Thread::Backtrace::Location` which represents the
235235
* current point of execution at `dc`.
236+
* @deprecated This API returns a backtrace with makeup applied. (Specifically,
237+
* rescue and ensure frames are excluded.) Therefore, inconsistency
238+
* occurs between the index of this backtrace object and the index of
239+
* arguments such as rb_debug_inspector_frame_self_get.
236240
237241
*/
238242
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
239243

244+
/**
245+
* Returns the frame count of the context.
246+
*
247+
* @param[in] dc A debug context.
248+
* @return The count of the frames.
249+
*/
250+
VALUE rb_debug_inspector_frame_count(const rb_debug_inspector_t *dc);
251+
240252
/**
241253
* Queries the current receiver of the passed context's upper frame.
242254
*
@@ -280,6 +292,16 @@ VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long
280292
*/
281293
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index);
282294

295+
/**
296+
* Queries the backtrace location object of the passed context's upper frame.
297+
*
298+
* @param[in] dc A debug context.
299+
* @param[in] index Index of the frame from top to bottom.
300+
* @exception rb_eArgError `index` out of range.
301+
* @retval The backtrace location object at `index`-th frame in Integer.
302+
*/
303+
VALUE rb_debug_inspector_frame_loc_get(const rb_debug_inspector_t *dc, long index);
304+
283305
/**
284306
* Queries the depth of the passed context's upper frame.
285307
*

vm_backtrace.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,18 +1504,22 @@ enum {
15041504
CALLER_BINDING_BINDING,
15051505
CALLER_BINDING_ISEQ,
15061506
CALLER_BINDING_CFP,
1507+
CALLER_BINDING_LOC,
15071508
CALLER_BINDING_DEPTH,
15081509
};
15091510

15101511
struct collect_caller_bindings_data {
15111512
VALUE ary;
15121513
const rb_execution_context_t *ec;
1514+
VALUE btobj;
1515+
rb_backtrace_t *bt;
15131516
};
15141517

15151518
static void
1516-
collect_caller_bindings_init(void *arg, size_t size)
1519+
collect_caller_bindings_init(void *arg, size_t num_frames)
15171520
{
1518-
/* */
1521+
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1522+
data->btobj = backtrace_alloc_capa(num_frames, &data->bt);
15191523
}
15201524

15211525
static VALUE
@@ -1546,13 +1550,21 @@ static void
15461550
collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
15471551
{
15481552
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1549-
VALUE frame = rb_ary_new2(6);
1553+
VALUE frame = rb_ary_new2(7);
15501554

15511555
rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
15521556
rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
15531557
rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
15541558
rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? (VALUE)cfp->iseq : Qnil);
15551559
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1560+
1561+
rb_backtrace_location_t *loc = &data->bt->backtrace[RARRAY_LEN(data->ary)];
1562+
RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1563+
RB_OBJ_WRITE(data->btobj, &loc->iseq, cfp->iseq);
1564+
loc->pc = cfp->pc;
1565+
VALUE vloc = location_create(loc, (void *)data->btobj);
1566+
rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1567+
15561568
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
15571569

15581570
rb_ary_push(data->ary, frame);
@@ -1562,13 +1574,21 @@ static void
15621574
collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
15631575
{
15641576
struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
1565-
VALUE frame = rb_ary_new2(6);
1577+
VALUE frame = rb_ary_new2(7);
15661578

15671579
rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
15681580
rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
15691581
rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
15701582
rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
15711583
rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
1584+
1585+
rb_backtrace_location_t *loc = &data->bt->backtrace[RARRAY_LEN(data->ary)];
1586+
RB_OBJ_WRITE(data->btobj, &loc->cme, rb_vm_frame_method_entry(cfp));
1587+
loc->iseq = NULL;
1588+
loc->pc = NULL;
1589+
VALUE vloc = location_create(loc, (void *)data->btobj);
1590+
rb_ary_store(frame, CALLER_BINDING_LOC, vloc);
1591+
15721592
rb_ary_store(frame, CALLER_BINDING_DEPTH, INT2FIX(frame_depth(data->ec, cfp)));
15731593

15741594
rb_ary_push(data->ary, frame);
@@ -1645,12 +1665,18 @@ rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data)
16451665
static VALUE
16461666
frame_get(const rb_debug_inspector_t *dc, long index)
16471667
{
1648-
if (index < 0 || index >= dc->backtrace_size) {
1668+
if (index < 0 || index >= RARRAY_LEN(dc->contexts)) {
16491669
rb_raise(rb_eArgError, "no such frame");
16501670
}
16511671
return rb_ary_entry(dc->contexts, index);
16521672
}
16531673

1674+
VALUE
1675+
rb_debug_inspector_frame_count(const rb_debug_inspector_t *dc)
1676+
{
1677+
return RARRAY_LEN(dc->contexts);
1678+
}
1679+
16541680
VALUE
16551681
rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
16561682
{
@@ -1681,6 +1707,13 @@ rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
16811707
return RTEST(iseq) ? rb_iseqw_new((rb_iseq_t *)iseq) : Qnil;
16821708
}
16831709

1710+
VALUE
1711+
rb_debug_inspector_frame_loc_get(const rb_debug_inspector_t *dc, long index)
1712+
{
1713+
VALUE frame = frame_get(dc, index);
1714+
return rb_ary_entry(frame, CALLER_BINDING_LOC);
1715+
}
1716+
16841717
VALUE
16851718
rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
16861719
{

0 commit comments

Comments
 (0)