Exemple #1
0
static void
line_event(VALUE trace_point, void *data)
{
  VALUE breakpoint, file, line, binding, self;
  int moved = 0;

  EVENT_SETUP

  breakpoint = Qnil;
  file    = rb_tracearg_path(trace_arg);
  line    = rb_tracearg_lineno(trace_arg);
  binding = rb_tracearg_binding(trace_arg);
  self    = rb_tracearg_self(trace_arg);

  EVENT_COMMON

  if (dc->calced_stack_size == 0) dc->calced_stack_size++;

  if (dc->last_line != rb_tracearg_lineno(trace_arg) ||
      dc->last_file != rb_tracearg_path(trace_arg))
  {
    moved = 1;
  }

  if (RTEST(tracing))
    call_at_tracing(context, dc, file, line);

  if (moved || !CTX_FL_TEST(dc, CTX_FL_FORCE_MOVE))
  {
    dc->steps = dc->steps <= 0 ? -1 : dc->steps - 1;
    if (dc->calced_stack_size <= dc->dest_frame)
    {
      dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1;
      if (dc->calced_stack_size < dc->dest_frame)
      {
        dc->dest_frame = dc->calced_stack_size;
        rb_funcall(mByebug, rb_intern("puts"), 1,
          rb_str_new2("Next went up a frame because previous frame finished\n"));
      }
    }
  }

  if (dc->steps == 0 || dc->lines == 0 ||
      (CTX_FL_TEST(dc, CTX_FL_ENABLE_BKPT) &&
      (!NIL_P(
       breakpoint = find_breakpoint_by_pos(bb_breakpoints(self), file, line, binding)))))
  {
    call_at_line_check(context, dc, breakpoint, file, line);
  }

  cleanup(dc);
}
Exemple #2
0
static void
call_event(VALUE trace_point, void *data)
{
  VALUE breakpoint, klass, mid, binding, self, file, line;

  EVENT_SETUP

  dc->calced_stack_size++;

  EVENT_COMMON

  breakpoint = Qnil;
  klass   = rb_tracearg_defined_class(trace_arg);
  mid     = SYM2ID(rb_tracearg_method_id(trace_arg));
  binding = rb_tracearg_binding(trace_arg);
  self    = rb_tracearg_self(trace_arg);
  file    = rb_tracearg_path(trace_arg);
  line    = rb_tracearg_lineno(trace_arg);

  breakpoint = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
  if (breakpoint != Qnil)
  {
    call_at_breakpoint(context, dc, breakpoint);
    call_at_line(context, dc, file, line);
  }

  cleanup(dc);
}
Exemple #3
0
static void
call_event(VALUE trace_point, void *data)
{
  VALUE breakpoint, klass, msym, mid, binding, self, file, line;

  EVENT_SETUP

  dc->calced_stack_size++;

  if (CTX_FL_TEST(dc, CTX_FL_STOP_ON_RET))
    dc->steps_out = dc->steps_out <= 0 ? -1 : dc->steps_out + 1;

  EVENT_COMMON

  breakpoint = Qnil;
  klass   = rb_tracearg_defined_class(trace_arg);
  msym    = rb_tracearg_method_id(trace_arg);
  mid     = NIL_P(msym) ? Qnil : SYM2ID(msym);
  binding = rb_tracearg_binding(trace_arg);
  self    = rb_tracearg_self(trace_arg);
  file    = rb_tracearg_path(trace_arg);
  line    = rb_tracearg_lineno(trace_arg);

  breakpoint = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);
  if (breakpoint != Qnil)
  {
    call_at_breakpoint(context, dc, breakpoint);
    call_at_line(context, dc, file, line);
  }

  cleanup(dc);
}
/**
 * file_tracepoint_callback
 * Callback function for Tracer#file_tracepoint. It gets called on
 * RUBY_EVENT_CLASS, RUBY_EVENT_CALL, and RUBY_EVENT_B_CALL
 * events. It check if any breakpoints matches current file the VM program counter
 * is in, and turn on line event tracing for that thread. Otherwise turn off
 * line tracing if in wrong file. The first time it turns on line event tracing,
 * it also turns on Tracer#return_tracepoint to maintain line tracing
 * consistency when file execution interleaves.
 */
static void
file_tracepoint_callback(VALUE tracepoint, void *data)
{
    VALUE self = (VALUE) data;
    rb_trace_arg_t *tracepoint_arg = rb_tracearg_from_tracepoint(tracepoint);
    VALUE tracepoint_path = rb_tracearg_path(tracepoint_arg);
    int match_found;

    if (!RB_TYPE_P(tracepoint_path, T_STRING))
        return;

    // Ensure tracepoint_path is absolute path
    tracepoint_path = rb_file_expand_path(tracepoint_path, Qnil);

    if (!RTEST(tracepoint_path)) {
        return;
    }

    match_found = match_breakpoints_files(self, tracepoint_path);

    if (match_found) {
        enable_line_trace_for_thread(self);
        enable_return_trace_for_thread(self);
    }
    else {
        disable_line_trace_for_thread(Qnil);
    }

    return;
}
Exemple #5
0
static VALUE
tracepoint_inspect(VALUE self)
{
    rb_tp_t *tp = tpptr(self);
    rb_trace_arg_t *trace_arg = GET_THREAD()->trace_arg;

    if (trace_arg) {
	switch (trace_arg->event) {
	  case RUBY_EVENT_LINE:
	  case RUBY_EVENT_SPECIFIED_LINE:
	    {
		VALUE sym = rb_tracearg_method_id(trace_arg);
		if (NIL_P(sym))
		  goto default_inspect;
		return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d in `%"PRIsVALUE"'>",
				  rb_tracearg_event(trace_arg),
				  rb_tracearg_path(trace_arg),
				  FIX2INT(rb_tracearg_lineno(trace_arg)),
				  sym);
	    }
	  case RUBY_EVENT_CALL:
	  case RUBY_EVENT_C_CALL:
	  case RUBY_EVENT_RETURN:
	  case RUBY_EVENT_C_RETURN:
	    return rb_sprintf("#<TracePoint:%"PRIsVALUE" `%"PRIsVALUE"'@%"PRIsVALUE":%d>",
			      rb_tracearg_event(trace_arg),
			      rb_tracearg_method_id(trace_arg),
			      rb_tracearg_path(trace_arg),
			      FIX2INT(rb_tracearg_lineno(trace_arg)));
	  case RUBY_EVENT_THREAD_BEGIN:
	  case RUBY_EVENT_THREAD_END:
	    return rb_sprintf("#<TracePoint:%"PRIsVALUE" %"PRIsVALUE">",
			      rb_tracearg_event(trace_arg),
			      rb_tracearg_self(trace_arg));
	  default:
	  default_inspect:
	    return rb_sprintf("#<TracePoint:%"PRIsVALUE"@%"PRIsVALUE":%d>",
			      rb_tracearg_event(trace_arg),
			      rb_tracearg_path(trace_arg),
			      FIX2INT(rb_tracearg_lineno(trace_arg)));
	}
    }
    else {
	return rb_sprintf("#<TracePoint:%s>", tp->tracing ? "enabled" : "disabled");
    }
}
Exemple #6
0
static void
raise_event(VALUE trace_point, void *data)
{
  VALUE expn_class, ancestors;
  VALUE path, lineno, binding, post_mortem_context;
  int i;
  debug_context_t *new_dc;

  EVENT_SETUP;

  path = rb_tracearg_path(trace_arg);
  lineno = rb_tracearg_lineno(trace_arg);
  binding = rb_tracearg_binding(trace_arg);
  raised_exception = rb_tracearg_raised_exception(trace_arg);

  if (post_mortem == Qtrue)
  {
    post_mortem_context = context_dup(dc);
    rb_ivar_set(raised_exception, rb_intern("@__bb_file"), path);
    rb_ivar_set(raised_exception, rb_intern("@__bb_line"), lineno);
    rb_ivar_set(raised_exception, rb_intern("@__bb_binding"), binding);
    rb_ivar_set(raised_exception, rb_intern("@__bb_context"),
                post_mortem_context);

    Data_Get_Struct(post_mortem_context, debug_context_t, new_dc);
    rb_debug_inspector_open(context_backtrace_set, (void *)new_dc);
  }

  if (catchpoints == Qnil || dc->calced_stack_size == 0
      || RHASH_TBL(catchpoints)->num_entries == 0)
  {
    EVENT_TEARDOWN;
    return;
  }

  expn_class = rb_obj_class(raised_exception);
  ancestors = rb_mod_ancestors(expn_class);
  for (i = 0; i < RARRAY_LENINT(ancestors); i++)
  {
    VALUE ancestor_class, module_name, hit_count;

    ancestor_class = rb_ary_entry(ancestors, i);
    module_name = rb_mod_name(ancestor_class);
    hit_count = rb_hash_aref(catchpoints, module_name);

    /* increment exception */
    if (hit_count != Qnil)
    {
      rb_hash_aset(catchpoints, module_name, INT2FIX(FIX2INT(hit_count) + 1));
      call_at_catchpoint(context, dc, raised_exception);
      call_at_line(context, dc, path, lineno);
      break;
    }
  }

  EVENT_TEARDOWN;
}
Exemple #7
0
static void
trace_print(rb_trace_arg_t * trace_arg, debug_context_t * dc,
            const char *file_filter, const char *debug_msg)
{
  char *fullpath = NULL;
  const char *basename;
  int filtered = 0;
  const char *event = rb_id2name(SYM2ID(rb_tracearg_event(trace_arg)));

  VALUE rb_path = rb_tracearg_path(trace_arg);
  const char *path = NIL_P(rb_path) ? "" : RSTRING_PTR(rb_path);

  int line = NUM2INT(rb_tracearg_lineno(trace_arg));

  VALUE rb_mid = rb_tracearg_method_id(trace_arg);
  const char *mid = NIL_P(rb_mid) ? "(top level)" : rb_id2name(SYM2ID(rb_mid));

  VALUE rb_cl = rb_tracearg_defined_class(trace_arg);
  VALUE rb_cl_name = NIL_P(rb_cl) ? rb_cl : rb_mod_name(rb_cl);
  const char *defined_class = NIL_P(rb_cl_name) ? "" : RSTRING_PTR(rb_cl_name);

  if (!trace_arg)
    return;

  if (file_filter)
  {
#ifndef _WIN32
    fullpath = realpath(path, NULL);
#endif
    basename = fullpath ? strrchr(fullpath, '/') : path;

    if (!basename || strncmp(basename + 1, file_filter, strlen(file_filter)))
      filtered = 1;

#ifndef _WIN32
    free(fullpath);
#endif
  }

  if (!filtered)
  {
    if (debug_msg)
      rb_funcall(mByebug, idPuts, 1,
                 rb_sprintf("[#%d] %s\n", dc->thnum, debug_msg));
    else
      rb_funcall(mByebug, idPuts, 1,
                 rb_sprintf("%*s [#%d] %s@%s:%d %s#%s\n", dc->calced_stack_size,
                            "", dc->thnum, event, path, line, defined_class,
                            mid));
  }
}
Exemple #8
0
static void
return_event(VALUE trace_point, void *data)
{
  VALUE brkpnt, file, line, binding;

  EVENT_SETUP;

  RETURN_EVENT_SETUP;

  if ((dc->steps_out == 0) && (CTX_FL_TEST(dc, CTX_FL_STOP_ON_RET)))
  {
    reset_stepping_stop_points(dc);

    call_at_return(context, dc, rb_tracearg_return_value(trace_arg));
  }
  else if (!NIL_P(breakpoints))
  {
    file = rb_tracearg_path(trace_arg);
    /*
     * @todo Sometimes the TracePoint API gives some return events without
     * file:line information, so we need to guard for nil until we know what's
     * going on. This happens, for example, with active_support core extensions:
     *
     * [#7] call@.../core_ext/numeric/conversions.rb:124 Fixnum#to_s
     *  [#7] b_call@.../core_ext/numeric/conversions.rb:124 BigDecimal#to_s
     *   [#7] line@.../core_ext/numeric/conversions.rb:125 BigDecimal#to_s
     *   [#7] c_call@.../core_ext/numeric/conversions.rb:125 Kernel#is_a?
     *    [#7] c_return@.../core_ext/numeric/conversions.rb:125 Kernel#is_a?
     *   [#7] line@.../core_ext/numeric/conversions.rb:131 BigDecimal#to_s
     *   [#7] c_call@.../core_ext/numeric/conversions.rb:131 Fixnum#to_default_s
     *    [#7] c_return@.../core_ext/numeric/conversions.rb:131 Fixnum#to_default_s
     *   [#7] b_return@/hort/core_ext/numeric/conversions.rb:133 BigDecimal#to_s
     *  [#7] return@:0 Fixnum#to_s # => This guy...
     */
    if (!NIL_P(file))
    {
      line = rb_tracearg_lineno(trace_arg);
      binding = rb_tracearg_binding(trace_arg);

      brkpnt = find_breakpoint_by_pos(breakpoints, file, line, binding);

      if (!NIL_P(brkpnt))
        call_at_return(context, dc, rb_tracearg_return_value(trace_arg));
    }
  }

  RETURN_EVENT_TEARDOWN;

  EVENT_TEARDOWN;
}
Exemple #9
0
static void
trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc)
{
  if (trace_arg)
  {
    const char *event = rb_id2name(SYM2ID(rb_tracearg_event(trace_arg)));
    char *path = RSTRING_PTR(rb_tracearg_path(trace_arg));
    int line = NUM2INT(rb_tracearg_lineno(trace_arg));
    VALUE v_mid_sym = rb_tracearg_method_id(trace_arg);
    VALUE v_mid_id = NIL_P(v_mid_sym) ? Qnil : SYM2ID(v_mid_sym);
    const char *mid = NIL_P(v_mid_id) ? "" : rb_id2name(v_mid_id);
    printf("%*s (%d)->[#%d] %s@%s:%d %s\n", dc->calced_stack_size, "",
           dc->calced_stack_size, dc->thnum, event, path, line, mid);
  }
}
Exemple #10
0
static void
trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc)
{
  if (trace_arg)
  {
    int i = 0;
    VALUE path  = rb_tracearg_path(trace_arg);
    VALUE line  = rb_tracearg_lineno(trace_arg);
    VALUE event = rb_tracearg_event(trace_arg);
    VALUE mid   = rb_tracearg_method_id(trace_arg);
    for (i=0; i<dc->calced_stack_size; i++) putc('|', stderr);
    fprintf(stderr, "[#%d] %s@%s:%d %s\n", dc->thnum,
      rb_id2name(SYM2ID(event)), RSTRING_PTR(path), NUM2INT(line),
      NIL_P(mid) ? "" : rb_id2name(SYM2ID(mid)));
  }
}
Exemple #11
0
static void
call_event(VALUE trace_point, void *data)
{
  VALUE brkpnt, klass, msym, mid, binding, self, file, line;

  EVENT_SETUP;

  if (dc->calced_stack_size <= dc->dest_frame)
    CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS);

  dc->calced_stack_size++;

  dc->steps_out = dc->steps_out <= 0 ? -1 : dc->steps_out + 1;

  /* nil method_id means we are at top level so there can't be a method
   * breakpoint here. Just leave then. */
  msym = rb_tracearg_method_id(trace_arg);
  if (NIL_P(msym))
  {
    EVENT_TEARDOWN;
    return;
  }

  mid = SYM2ID(msym);
  klass = rb_tracearg_defined_class(trace_arg);
  binding = rb_tracearg_binding(trace_arg);
  self = rb_tracearg_self(trace_arg);
  file = rb_tracearg_path(trace_arg);
  line = rb_tracearg_lineno(trace_arg);

  brkpnt = Qnil;

  if (!NIL_P(breakpoints))
    brkpnt = find_breakpoint_by_method(breakpoints, klass, mid, binding, self);

  if (!NIL_P(brkpnt))
  {
    call_at_breakpoint(context, dc, brkpnt);
    call_at_line(context, dc, file, line);
  }

  EVENT_TEARDOWN;
}
Exemple #12
0
static void
trace_print(rb_trace_arg_t *trace_arg, debug_context_t *dc)
{
  if (trace_arg)
  {
    const char *event = safe_sym_to_str(rb_tracearg_event(trace_arg));

    VALUE path_sym = rb_tracearg_path(trace_arg);
    const char *path = NIL_P(path_sym) ? "" : RSTRING_PTR(path_sym);

    int line = NUM2INT(rb_tracearg_lineno(trace_arg));

    const char *mid = safe_sym_to_str(rb_tracearg_method_id(trace_arg));

    rb_funcall(mByebug, rb_intern("puts"), 1,
      rb_sprintf("%*s (%d)->[#%d] %s@%s:%d %s\n", dc->calced_stack_size, "",
                 dc->calced_stack_size, dc->thnum, event, path, line, mid));
  }
}
Exemple #13
0
static void
line_event(VALUE trace_point, void *data)
{
  VALUE brkpnt, file, line, binding;

  EVENT_SETUP;

  file = rb_tracearg_path(trace_arg);
  line = rb_tracearg_lineno(trace_arg);
  binding = rb_tracearg_binding(trace_arg);

  if (RTEST(tracing))
    call_at_tracing(context, dc);

  if (!CTX_FL_TEST(dc, CTX_FL_IGNORE_STEPS))
    dc->steps = dc->steps <= 0 ? -1 : dc->steps - 1;

  if (dc->calced_stack_size <= dc->dest_frame)
  {
    dc->dest_frame = dc->calced_stack_size;
    CTX_FL_UNSET(dc, CTX_FL_IGNORE_STEPS);

    dc->lines = dc->lines <= 0 ? -1 : dc->lines - 1;
  }

  if (dc->steps == 0 || dc->lines == 0)
    call_at_line_check(context, dc, Qnil);
  else
  {
    brkpnt = Qnil;

    if (!NIL_P(breakpoints))
      brkpnt = find_breakpoint_by_pos(breakpoints, file, line, binding);

    if (!NIL_P(brkpnt))
      call_at_line_check(context, dc, brkpnt);
  }

  EVENT_TEARDOWN;
}
Exemple #14
0
static void
return_event(VALUE trace_point, void *data)
{
  EVENT_SETUP;

  dc->calced_stack_size--;

  if (dc->steps_out == 1)
    dc->steps = 1;
  else if ((dc->steps_out == 0) && (CTX_FL_TEST(dc, CTX_FL_STOP_ON_RET)))
  {
    VALUE file, line;

    reset_stepping_stop_points(dc);
    file = rb_tracearg_path(trace_arg);
    line = rb_tracearg_lineno(trace_arg);
    call_at_return(context, dc, file, line);
  }

  dc->steps_out = dc->steps_out <= 0 ? -1 : dc->steps_out - 1;

  EVENT_TEARDOWN;
}
Exemple #15
0
static int
trace_common(rb_trace_arg_t *trace_arg, debug_context_t *dc)
{
  /* return if thread marked as 'ignored', like byebug's control thread */
  if (CTX_FL_TEST(dc, CTX_FL_IGNORE))
  {
    cleanup(dc);
    return 0;
  }

  halt_while_other_thread_is_active(dc);

  /* Get the lock! */
  locker = rb_thread_current();

  /* Many events per line, but only *one* breakpoint */
  if (dc->last_line != rb_tracearg_lineno(trace_arg) ||
      dc->last_file != rb_tracearg_path(trace_arg))
  {
    CTX_FL_SET(dc, CTX_FL_ENABLE_BKPT);
  }

  return 1;
}
Exemple #16
0
/*
 * Path of the file being run
 */
static VALUE
tracepoint_attr_path(VALUE tpval)
{
    return rb_tracearg_path(get_trace_arg());
}
Exemple #17
0
static void
return_event(VALUE trace_point, void *data)
{
  EVENT_SETUP

  if (dc->calced_stack_size > 0) dc->calced_stack_size--;

  EVENT_COMMON

  if (dc->calced_stack_size + 1 == dc->before_frame)
  {
    VALUE file, line;

    reset_stepping_stop_points(dc);
    file = rb_tracearg_path(trace_arg);
    line = rb_tracearg_lineno(trace_arg);
    call_at_return(context, dc, file, line);
  }

  if (dc->calced_stack_size + 1 == dc->after_frame)
  {
    reset_stepping_stop_points(dc);
    dc->steps = 1;
  }

  cleanup(dc);
}

static void
c_call_event(VALUE trace_point, void *data)