Skip to content

Instantly share code, notes, and snippets.

@ujihisa
Created April 22, 2019 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ujihisa/da58a98a909a7a1be1db5e2050ec0552 to your computer and use it in GitHub Desktop.
Save ujihisa/da58a98a909a7a1be1db5e2050ec0552 to your computer and use it in GitHub Desktop.
$ d
diff --git a/vm_backtrace.c b/vm_backtrace.c
index bb01983a7c..de7b961174 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -47,6 +47,28 @@ calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
return rb_iseq_line_no(iseq, pos);
}
+inline static int
+calc_column(const rb_iseq_t *iseq, const VALUE *pc)
+{
+ size_t pos = (size_t)(pc - iseq->body->iseq_encoded);
+ if (LIKELY(pos)) {
+ /* use pos-1 because PC points next instruction at the beginning of instruction */
+ pos--;
+ }
+#if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
+ else {
+ /* SDR() is not possible; that causes infinite loop. */
+ rb_print_backtrace();
+ __builtin_trap();
+ }
+#endif
+ int beg_pos_lineno, beg_pos_column, end_pos_lineno, end_pos_column;
+ const rb_code_location_t *loc = &iseq->body->location.code_location;
+ printf("\n(%d, %d, %d, %d)\n", loc->beg_pos.lineno, loc->beg_pos.column, loc->end_pos.lineno, loc->end_pos.column);
+ rb_iseq_code_location(iseq, &beg_pos_lineno, &beg_pos_column, &end_pos_lineno, &end_pos_column);
+ return beg_pos_lineno;
+}
+
int
rb_vm_get_sourceline(const rb_control_frame_t *cfp)
{
@@ -80,6 +102,10 @@ typedef struct rb_backtrace_location_struct {
const VALUE *pc;
int lineno;
} lineno;
+ union {
+ const VALUE *pc;
+ int column;
+ } column;
} iseq;
struct {
ID mid;
@@ -156,6 +182,27 @@ location_lineno(rb_backtrace_location_t *loc)
}
}
+static int
+location_column(rb_backtrace_location_t *loc)
+{
+ switch (loc->type) {
+ case LOCATION_TYPE_ISEQ:
+ loc->type = LOCATION_TYPE_ISEQ_CALCED;
+ return (loc->body.iseq.column.column = calc_column(loc->body.iseq.iseq, loc->body.iseq.column.pc));
+ case LOCATION_TYPE_ISEQ_CALCED:
+ return loc->body.iseq.column.column;
+ case LOCATION_TYPE_CFUNC:
+ if (loc->body.cfunc.prev_loc) {
+ return location_column(loc->body.cfunc.prev_loc);
+ }
+ return 0;
+ default:
+ rb_bug("location_column: unreachable");
+ UNREACHABLE;
+ }
+}
+
+
/*
* Returns the line number of this frame.
*
@@ -170,6 +217,20 @@ location_lineno_m(VALUE self)
return INT2FIX(location_lineno(location_ptr(self)));
}
+/*
+ * Returns the column number of this frame.
+ *
+ * For example, using +caller_locations.rb+ from Thread::Backtrace::Location
+ *
+ * loc = c(0..1).first
+ * loc.column #=> 2
+ */
+static VALUE
+location_column_m(VALUE self)
+{
+ return INT2FIX(location_column(location_ptr(self)));
+}
+
static VALUE
location_label(rb_backtrace_location_t *loc)
{
@@ -517,6 +578,7 @@ bt_iter_iseq(void *ptr, const rb_control_frame_t *cfp)
loc->type = LOCATION_TYPE_ISEQ;
loc->body.iseq.iseq = iseq;
loc->body.iseq.lineno.pc = pc;
+ loc->body.iseq.column.pc = pc;
arg->prev_loc = loc;
}
@@ -1078,6 +1140,7 @@ Init_vm_backtrace(void)
rb_undef_alloc_func(rb_cBacktraceLocation);
rb_undef_method(CLASS_OF(rb_cBacktraceLocation), "new");
rb_define_method(rb_cBacktraceLocation, "lineno", location_lineno_m, 0);
+ rb_define_method(rb_cBacktraceLocation, "column", location_column_m, 0);
rb_define_method(rb_cBacktraceLocation, "label", location_label_m, 0);
rb_define_method(rb_cBacktraceLocation, "base_label", location_base_label_m, 0);
rb_define_method(rb_cBacktraceLocation, "path", location_path_m, 0);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment