/** * 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; }
int rb_feature_provided(const char *feature, const char **loading) { const char *ext = strrchr(feature, '.'); volatile VALUE fullpath = 0; if (*feature == '.' && (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) { fullpath = rb_file_expand_path(rb_str_new2(feature), Qnil); feature = RSTRING_PTR(fullpath); } if (ext && !strchr(ext, '/')) { if (IS_RBEXT(ext)) { if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE; return FALSE; } else if (IS_SOEXT(ext) || IS_DLEXT(ext)) { if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE; return FALSE; } } if (rb_feature_p(feature, 0, TRUE, FALSE, loading)) return TRUE; return FALSE; }
static VALUE expand_include_path(VALUE path) { char *p = RSTRING_PTR(path); if (!p) return path; if (*p == '.' && p[1] == '/') return path; return rb_file_expand_path(path, Qnil); }
VALUE rb_get_load_path(void) { VALUE load_path = rb_vm_load_path(); VALUE ary = rb_ary_new(); for (long i = 0, count = RARRAY_LEN(load_path); i < count; i++) { rb_ary_push(ary, rb_file_expand_path(RARRAY_AT(load_path, i), Qnil)); } return ary; }
VALUE rb_get_expanded_load_path(void) { VALUE load_path = rb_get_load_path(); VALUE ary; long i; ary = rb_ary_new2(RARRAY_LEN(load_path)); for (i = 0; i < RARRAY_LEN(load_path); ++i) { VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil); rb_str_freeze(path); rb_ary_push(ary, path); } rb_obj_freeze(ary); return ary; }
/** * line_trace_callback * Callback function for thread line event tracing. It checks Tracer#breakpoints_cache * for any breakpoints trigger on current line called. Then trigger evaluation * procedure if found matching breakpoints. It also skip breakpoints that are * already marked completed. */ static void line_trace_callback(rb_event_flag_t event, VALUE data, VALUE obj, ID mid, VALUE klass) { VALUE self = data; VALUE trace_path; int c_trace_lineno; const char *c_trace_path; VALUE trace_binding; VALUE call_stack_bindings; ID callers_id; ID breakpoints_hit_id; VALUE matching_result; c_trace_path = rb_sourcefile(); // Ensure C_trace_path is absolute path trace_path = rb_str_new_cstr(c_trace_path); trace_path = rb_file_expand_path(trace_path, Qnil); if(!RTEST(trace_path)) { return; } c_trace_path = rb_string_value_cstr(&trace_path); c_trace_lineno = rb_sourceline(); matching_result = match_breakpoints(self, c_trace_path, c_trace_lineno); CONST_ID(callers_id, "callers"); CONST_ID(breakpoints_hit_id, "breakpoints_hit"); // If matching result isn't an array, it means we're in completely wrong file, // or not on the right line. Turn line tracing off if we're in wrong file. if (!RB_TYPE_P(matching_result, T_ARRAY)) { if (!RTEST(matching_result)) { disable_line_trace_for_thread(Qnil); } return; } trace_binding = rb_binding_new(); call_stack_bindings = rb_funcall(trace_binding, callers_id, 0); rb_funcall(self, breakpoints_hit_id, 2, matching_result, call_stack_bindings); return; }
int rb_feature_provided(const char *feature, const char **loading) { const char *ext = strrchr(feature, '.'); volatile VALUE fullpath = 0; if (*feature == '.' && (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) { fullpath = rb_file_expand_path(rb_str_new2(feature), Qnil); feature = RSTRING_PTR(fullpath); } if (ext && !strchr(ext, '/')) { int type = guess_ext_type(ext); if (type) { if (rb_feature_p(feature, ext, type, false, loading)) return true; return false; } } if (rb_feature_p(feature, 0, TYPE_GUESS, false, loading)) return true; return false; }
static bool search_required(VALUE name, VALUE *out, int *type) { const char *name_cstr = RSTRING_PTR(name); if (*name_cstr == '/' || *name_cstr == '.' || *name_cstr == '~') { // Given name is an absolute path. name = rb_file_expand_path(name, Qnil); return check_path(RSTRING_PTR(name), out, type); } // Given name is not an absolute path, we need to go through $:. VALUE load_path = rb_get_load_path(); for (long i = 0, count = RARRAY_LEN(load_path); i < count; i++) { const char *path = RSTRING_PTR(RARRAY_AT(load_path, i)); char buf[PATH_MAX]; snprintf(buf, sizeof buf, "%s/%s", path, name_cstr); if (check_path(buf, out, type)) { return true; } } return false; }
VALUE rb_get_expanded_load_path(void) { VALUE load_path = rb_get_load_path(); VALUE ary; long i; for (i = 0; i < RARRAY_LEN(load_path); ++i) { VALUE str = rb_check_string_type(RARRAY_PTR(load_path)[i]); if (NIL_P(str) || !rb_is_absolute_path(RSTRING_PTR(str))) goto relative_path_found; } return load_path; relative_path_found: ary = rb_ary_new2(RARRAY_LEN(load_path)); for (i = 0; i < RARRAY_LEN(load_path); ++i) { VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil); rb_str_freeze(path); rb_ary_push(ary, path); } rb_obj_freeze(ary); return ary; }