Skip to content

Commit

Permalink
add additional CF info for CI env
Browse files Browse the repository at this point in the history
Introduce new RUBY_DEBUG option 'ci' to inform Ruby interpreter
that an interpreter is running on CI environment.

With this option, `rb_bug()` shows more information includes
method entry information, local variables information for each
control frame.
  • Loading branch information
ko1 committed Dec 5, 2019
1 parent c88afd5 commit edb80df
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 12 deletions.
2 changes: 2 additions & 0 deletions debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ extern int ruby_w32_rtc_error;
UINT ruby_w32_codepage[2];
#endif
extern int ruby_rgengc_debug;
extern int ruby_on_ci;

int
ruby_env_debug_option(const char *str, int len, void *arg)
Expand Down Expand Up @@ -192,6 +193,7 @@ ruby_env_debug_option(const char *str, int len, void *arg)

SET_WHEN("gc_stress", *ruby_initial_gc_stress_ptr, Qtrue);
SET_WHEN("core", ruby_enable_coredump, 1);
SET_WHEN("ci", ruby_on_ci, 1);
if (NAME_MATCH_VALUE("rgengc")) {
if (!len) ruby_rgengc_debug = 1;
else SET_UINT_LIST("rgengc", &ruby_rgengc_debug, 1);
Expand Down
8 changes: 4 additions & 4 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -11344,8 +11344,8 @@ obj_type_name(VALUE obj)
return type_name(TYPE(obj), obj);
}

static const char *
method_type_name(rb_method_type_t type)
const char *
rb_method_type_name(rb_method_type_t type)
{
switch (type) {
case VM_METHOD_TYPE_ISEQ: return "iseq";
Expand All @@ -11361,7 +11361,7 @@ method_type_name(rb_method_type_t type)
case VM_METHOD_TYPE_UNDEF: return "undef";
case VM_METHOD_TYPE_NOTIMPLEMENTED: return "notimplemented";
}
rb_bug("method_type_name: unreachable (type: %d)", type);
rb_bug("rb_method_type_name: unreachable (type: %d)", type);
}

/* from array.c */
Expand Down Expand Up @@ -11564,7 +11564,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
if (me->def) {
APPENDF((BUFF_ARGS, "(called_id: %s, type: %s, alias: %d, owner: %s, defined_class: %s)",
rb_id2name(me->called_id),
method_type_name(me->def->type),
rb_method_type_name(me->def->type),
me->def->alias_count,
obj_info(me->owner),
obj_info(me->defined_class)));
Expand Down
2 changes: 1 addition & 1 deletion test/ruby/test_rubyoptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ module SEGVTest
%r(
(?:--\s(?:.+\n)*\n)?
--\sControl\sframe\sinformation\s-+\n
(?:c:.*\n)*
(?:(?:c:.*\n)|(?:^\s+.+\n))*
\n
)x,
%r(
Expand Down
50 changes: 43 additions & 7 deletions vm_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include "addr2line.h"
#include "vm_core.h"
#include "iseq.h"
#include "gc.h"

#ifdef HAVE_UCONTEXT_H
#include <ucontext.h>
#endif
Expand All @@ -38,6 +40,9 @@
((rb_control_frame_t *)((ec)->vm_stack + (ec)->vm_stack_size) - \
(rb_control_frame_t *)(cfp))

const char *rb_method_type_name(rb_method_type_t type);
int ruby_on_ci;

static void
control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
{
Expand All @@ -46,11 +51,10 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
char ep_in_heap = ' ';
char posbuf[MAX_POSBUF+1];
int line = 0;

const char *magic, *iseq_name = "-", *selfstr = "-", *biseq_name = "-";
VALUE tmp;

const rb_callable_method_entry_t *me;
const rb_iseq_t *iseq = NULL;
const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);

if (ep < 0 || (size_t)ep > ec->vm_stack_size) {
ep = (ptrdiff_t)cfp->ep;
Expand Down Expand Up @@ -110,15 +114,16 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
line = -1;
}
else {
pc = cfp->pc - cfp->iseq->body->iseq_encoded;
iseq_name = RSTRING_PTR(cfp->iseq->body->location.label);
iseq = cfp->iseq;
pc = cfp->pc - iseq->body->iseq_encoded;
iseq_name = RSTRING_PTR(iseq->body->location.label);
line = rb_vm_get_sourceline(cfp);
if (line) {
snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(cfp->iseq)), line);
snprintf(posbuf, MAX_POSBUF, "%s:%d", RSTRING_PTR(rb_iseq_path(iseq)), line);
}
}
}
else if ((me = rb_vm_frame_method_entry(cfp)) != NULL) {
else if (me != NULL) {
iseq_name = rb_id2name(me->def->original_id);
snprintf(posbuf, MAX_POSBUF, ":%s", iseq_name);
line = -1;
Expand Down Expand Up @@ -148,6 +153,37 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c
fprintf(stderr, "%-1s ", biseq_name);
}
fprintf(stderr, "\n");

// additional information for CI machines
if (ruby_on_ci) {
char buff[0x100];

if (me) {
if (imemo_type_p((VALUE)me, imemo_ment)) {
fprintf(stderr, " me:\n");
fprintf(stderr, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type));
fprintf(stderr, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner));
if (me->owner != me->defined_class) {
fprintf(stderr, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class));
}
}
else {
fprintf(stderr, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me));
}
}

if (iseq) {
if (iseq->body->local_table_size > 0) {
fprintf(stderr, " lvars:\n");
for (unsigned int i=0; i<iseq->body->local_table_size; i++) {
const VALUE *argv = cfp->ep - cfp->iseq->body->local_table_size - VM_ENV_DATA_SIZE + 1;
fprintf(stderr, " %s: %s\n",
rb_id2name(iseq->body->local_table[i]),
rb_raw_obj_info(buff, 0x100, argv[i]));
}
}
}
}
}

void
Expand Down

0 comments on commit edb80df

Please sign in to comment.