Revision: 4546 http://trac.macosforge.org/projects/ruby/changeset/4546 Author: lsansonetti@apple.com Date: 2010-09-27 22:47:47 -0700 (Mon, 27 Sep 2010) Log Message: ----------- add backtracing support for interpreted dispatch calls + cleanup useless code Modified Paths: -------------- MacRuby/trunk/dispatcher.cpp MacRuby/trunk/interpreter.cpp MacRuby/trunk/interpreter.h MacRuby/trunk/objc.h MacRuby/trunk/objc.m MacRuby/trunk/vm.cpp MacRuby/trunk/vm.h Modified: MacRuby/trunk/dispatcher.cpp =================================================================== --- MacRuby/trunk/dispatcher.cpp 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/dispatcher.cpp 2010-09-28 05:47:47 UTC (rev 4546) @@ -821,8 +821,8 @@ char *method_name = (char *)sel_getName(sel); char file[PATH_MAX]; unsigned long line = 0; - GET_CORE()->symbolize_backtrace_entry(1, NULL, file, sizeof file, - &line, NULL, 0); + GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line, + NULL, 0); MACRUBY_METHOD_ENTRY(class_name, method_name, file, line); } @@ -835,8 +835,8 @@ char *method_name = (char *)sel_getName(sel); char file[PATH_MAX]; unsigned long line = 0; - GET_CORE()->symbolize_backtrace_entry(1, NULL, file, sizeof file, - &line, NULL, 0); + GET_CORE()->symbolize_backtrace_entry(1, file, sizeof file, &line, + NULL, 0); MACRUBY_METHOD_RETURN(class_name, method_name, file, line); } Modified: MacRuby/trunk/interpreter.cpp =================================================================== --- MacRuby/trunk/interpreter.cpp 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/interpreter.cpp 2010-09-28 05:47:47 UTC (rev 4546) @@ -82,6 +82,35 @@ int argc = value_as(call_arg(call, 5), int); VALUE *argv = value_as(call_arg(call, 6), VALUE *); + MDNode *node = call->getMetadata(RoxorCompiler::shared->dbg_mdkind); + if (node != NULL) { + DILocation loc(node); + std::string path; + path.append(loc.getDirectory()); + path.append("/"); + path.append(loc.getFilename()); + + Frame frame; + frame.name = (const char *)sel; + frame.path = path; + frame.line = loc.getLineNumber(); + frames.push_back(frame); + } + + struct Finally { + RoxorInterpreter *ir; + bool pop; + Finally(RoxorInterpreter *_ir, bool _pop) { + ir = _ir; + pop = _pop; + } + ~Finally() { + if (pop) { + ir->frames.pop_back(); + } + } + } finalizer(this, node != NULL); + return vm_dispatch(top, self, sel, block, opt, argc, argv); } else if (called == RoxorCompiler::shared->singletonClassFunc) { @@ -93,6 +122,27 @@ oops("unrecognized call instruction:", call); } +bool +RoxorInterpreter::frame_at_index(unsigned int idx, void *addr, + std::string *name, std::string *path, unsigned int *line) +{ + if ((uintptr_t)addr < (uintptr_t)(void *)&vm_dispatch + || (uintptr_t)addr > (uintptr_t)(void *)&vm_dispatch + 5000) { + // Likely not an interpreted dispatch call. + return false; + } + if (idx >= frames.size()) { + // Not enough frames! + return false; + } + + Frame &frame = frames[idx]; + *name = frame.name; + *path = frame.path; + *line = frame.line; + return true; +} + #define return_if_cached(__insn) \ std::map<Instruction *, VALUE>::iterator __i = insns.find(__insn); \ if (__i != insns.end()) { \ Modified: MacRuby/trunk/interpreter.h =================================================================== --- MacRuby/trunk/interpreter.h 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/interpreter.h 2010-09-28 05:47:47 UTC (rev 4546) @@ -22,6 +22,9 @@ VALUE interpret(Function *func, VALUE self, SEL sel); + bool frame_at_index(unsigned int idx, void *addr, std::string *name, + std::string *path, unsigned int *line); + private: VALUE self_arg; SEL sel_arg; @@ -29,6 +32,13 @@ unsigned int stack_p; #define INTERPRETER_STACK_SIZE 1000 std::map<Instruction *, VALUE> insns; + class Frame { + public: + std::string name; + std::string path; + unsigned int line; + }; + std::vector<Frame> frames; VALUE interpret_basicblock(BasicBlock *bb); VALUE interpret_instruction(Instruction *insn); Modified: MacRuby/trunk/objc.h =================================================================== --- MacRuby/trunk/objc.h 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/objc.h 2010-09-28 05:47:47 UTC (rev 4546) @@ -73,9 +73,6 @@ return false; } -bool rb_objc_symbolize_address(void *addr, void **start, char *name, - size_t name_len); - id rb_rb2oc_exception(VALUE exc); VALUE rb_oc2rb_exception(id exc, bool *created); Modified: MacRuby/trunk/objc.m =================================================================== --- MacRuby/trunk/objc.m 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/objc.m 2010-09-28 05:47:47 UTC (rev 4546) @@ -109,26 +109,6 @@ return false; } -bool -rb_objc_symbolize_address(void *addr, void **start, char *name, - size_t name_len) -{ - Dl_info info; - if (dladdr(addr, &info) != 0) { - if (info.dli_saddr != NULL) { - if (start != NULL) { - *start = info.dli_saddr; - } - if (name != NULL) { - strncpy(name, info.dli_sname, name_len); - } - return true; - } - } - - return false; -} - VALUE rb_home_dir(VALUE user_name) { Modified: MacRuby/trunk/vm.cpp =================================================================== --- MacRuby/trunk/vm.cpp 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/vm.cpp 2010-09-28 05:47:47 UTC (rev 4546) @@ -651,14 +651,13 @@ void rb_symbolicate(void *addr) { - void *start = NULL; char path[1000]; char name[100]; unsigned long ln = 0; - if (GET_CORE()->symbolize_call_address(addr, &start, path, sizeof path, - &ln, name, sizeof name)) { - printf("addr %p start %p selector %s location %s:%ld\n", - addr, start, name, path, ln); + if (GET_CORE()->symbolize_call_address(addr, path, sizeof path, + &ln, name, sizeof name, NULL)) { + printf("addr %p selector %s location %s:%ld\n", + addr, name, path, ln); } else { printf("addr %p unknown\n", addr); @@ -666,8 +665,9 @@ } bool -RoxorCore::symbolize_call_address(void *addr, void **startp, char *path, - size_t path_len, unsigned long *ln, char *name, size_t name_len) +RoxorCore::symbolize_call_address(void *addr, char *path, size_t path_len, + unsigned long *ln, char *name, size_t name_len, + unsigned int *interpreter_frame_idx) { #if MACRUBY_STATIC return false; @@ -676,25 +676,34 @@ return false; } - void *start = NULL; RoxorFunction *f = jmm->find_function((unsigned char *)addr); if (f != NULL) { if (f->imp == NULL) { f->imp = ee->getPointerToFunctionOrStub(f->f); } - start = f->imp; } else { - if (!rb_objc_symbolize_address(addr, &start, NULL, 0)) { + std::string fr_name; + std::string fr_path; + unsigned int fr_line = 0; + if (interpreter_frame_idx == NULL + || !RoxorInterpreter::shared->frame_at_index(*interpreter_frame_idx, + addr, &fr_name, &fr_path, &fr_line)) { return false; } + (*interpreter_frame_idx)++; + if (name != NULL) { + strlcpy(name, fr_name.c_str(), name_len); + } + if (path != NULL) { + strlcpy(path, fr_path.c_str(), path_len); + } + if (ln != NULL) { + *ln = fr_line; + } + return true; } - assert(start != NULL); - if (startp != NULL) { - *startp = start; - } - if (f != NULL) { if (ln != NULL) { *ln = 0; @@ -711,7 +720,7 @@ } if (name != NULL) { std::map<IMP, rb_vm_method_node_t *>::iterator iter = - ruby_imps.find((IMP)start); + ruby_imps.find((IMP)f->imp); if (iter == ruby_imps.end()) { strncpy(name, "block", name_len); } @@ -737,8 +746,8 @@ } void -RoxorCore::symbolize_backtrace_entry(int index, void **startp, char *path, - size_t path_len, unsigned long *ln, char *name, size_t name_len) +RoxorCore::symbolize_backtrace_entry(int index, char *path, size_t path_len, + unsigned long *ln, char *name, size_t name_len) { void *callstack[10]; const int callstack_n = backtrace(callstack, 10); @@ -746,8 +755,8 @@ index++; // count us! if (callstack_n < index - || !GET_CORE()->symbolize_call_address(callstack[index], startp, - path, path_len, ln, name, name_len)) { + || !GET_CORE()->symbolize_call_address(callstack[index], path, + path_len, ln, name, name_len, NULL)) { if (path != NULL) { strncpy(path, "core", path_len); } @@ -3330,8 +3339,8 @@ char *classname = (char *)rb_class2name(CLASS_OF(rb_exc)); char file[PATH_MAX]; unsigned long line = 0; - GET_CORE()->symbolize_backtrace_entry(2, NULL, file, sizeof file, - &line, NULL, 0); + GET_CORE()->symbolize_backtrace_entry(2, file, sizeof file, &line, + NULL, 0); MACRUBY_RAISE(classname, file, line); } #if __LP64__ @@ -3583,6 +3592,8 @@ VALUE ary = rb_ary_new(); + unsigned int interpreter_frame_idx = 0; + for (int i = 0; i < callstack_n; i++) { char path[PATH_MAX]; char name[100]; @@ -3590,8 +3601,8 @@ path[0] = name[0] = '\0'; - if (GET_CORE()->symbolize_call_address(callstack[i], NULL, - path, sizeof path, &ln, name, sizeof name) + if (GET_CORE()->symbolize_call_address(callstack[i], path, sizeof path, + &ln, name, sizeof name, &interpreter_frame_idx) && name[0] != '\0' && path[0] != '\0') { char entry[PATH_MAX]; if (ln == 0) { Modified: MacRuby/trunk/vm.h =================================================================== --- MacRuby/trunk/vm.h 2010-09-27 23:05:30 UTC (rev 4545) +++ MacRuby/trunk/vm.h 2010-09-28 05:47:47 UTC (rev 4546) @@ -848,13 +848,12 @@ } #endif - bool symbolize_call_address(void *addr, void **startp, - char *path, size_t path_len, unsigned long *ln, - char *name, size_t name_len); + bool symbolize_call_address(void *addr, char *path, size_t path_len, + unsigned long *ln, char *name, size_t name_len, + unsigned int *interpreter_frame_idx); - void symbolize_backtrace_entry(int index, void **startp, - char *path, size_t path_len, unsigned long *ln, - char *name, size_t name_len); + void symbolize_backtrace_entry(int index, char *path, size_t path_len, + unsigned long *ln, char *name, size_t name_len); void invalidate_method_cache(SEL sel); rb_vm_method_node_t *method_node_get(IMP imp, bool create=false);