/** * Create an Array with backtrace information. * * @param runtime * @param level * @param nativeException * @return an Array with the backtrace */ public static IRubyObject createBacktraceFromFrames( Ruby runtime, RubyStackTraceElement[] backtraceFrames, boolean cropAtEval) { RubyArray backtrace = runtime.newArray(); if (backtraceFrames == null || backtraceFrames.length <= 0) return backtrace; int traceSize = backtraceFrames.length; for (int i = 0; i < traceSize - 1; i++) { RubyStackTraceElement frame = backtraceFrames[i]; // We are in eval with binding break out early // FIXME: This is broken with the new backtrace stuff if (cropAtEval && frame.isBinding()) break; addBackTraceElement(runtime, backtrace, frame, backtraceFrames[i + 1]); } return backtrace; }
private static void addBackTraceElement( Ruby runtime, RubyArray backtrace, RubyStackTraceElement frame, RubyStackTraceElement previousFrame) { if (frame != previousFrame && // happens with native exceptions, should not filter those out frame.getLineNumber() == previousFrame.getLineNumber() && frame.getMethodName() != null && frame.getMethodName().equals(previousFrame.getMethodName()) && frame.getFileName() != null && frame.getFileName().equals(previousFrame.getFileName())) { return; } RubyString traceLine; String fileName = frame.getFileName(); if (fileName == null) fileName = ""; if (previousFrame.getMethodName() == UNKNOWN_NAME) { traceLine = RubyString.newString(runtime, fileName + ':' + (frame.getLineNumber())); } else { traceLine = RubyString.newString( runtime, fileName + ':' + (frame.getLineNumber()) + ":in `" + previousFrame.getMethodName() + '\''); } backtrace.append(traceLine); }
private static void addBackTraceElement( RubyArray backtrace, RubyStackTraceElement frame, RubyStackTraceElement previousFrame, FrameType frameType) { if (frame != previousFrame && // happens with native exceptions, should not filter those out frame.getMethodName() != null && frame.getMethodName().equals(previousFrame.getMethodName()) && frame.getFileName().equals(previousFrame.getFileName()) && frame.getLineNumber() == previousFrame.getLineNumber()) { return; } StringBuilder buf = new StringBuilder(60); buf.append(frame.getFileName()).append(':').append(frame.getLineNumber()); if (previousFrame.getMethodName() != null) { switch (frameType) { case METHOD: buf.append(":in `"); buf.append(previousFrame.getMethodName()); buf.append('\''); break; case BLOCK: buf.append(":in `"); buf.append("block in " + previousFrame.getMethodName()); buf.append('\''); break; case EVAL: buf.append(":in `"); buf.append("eval in " + previousFrame.getMethodName()); buf.append('\''); break; case CLASS: buf.append(":in `"); buf.append("class in " + previousFrame.getMethodName()); buf.append('\''); break; case ROOT: buf.append(":in `<toplevel>'"); break; } } backtrace.append(backtrace.getRuntime().newString(buf.toString())); }
public static IRubyObject createRubyHybridBacktrace( Ruby runtime, RubyStackTraceElement[] backtraceFrames, RubyStackTraceElement[] stackTrace, boolean debug) { RubyArray traceArray = RubyArray.newArray(runtime); ThreadContext context = runtime.getCurrentContext(); int rubyFrameIndex = backtraceFrames.length - 1; for (int i = 0; i < stackTrace.length; i++) { RubyStackTraceElement element = stackTrace[i]; // look for mangling markers for compiled Ruby in method name int index = element.getMethodName().indexOf("$RUBY$"); if (index >= 0) { String unmangledMethod = element.getMethodName().substring(index + 6); RubyString str = RubyString.newString( runtime, element.getFileName() + ":" + element.getLineNumber() + ":in `" + unmangledMethod + "'"); traceArray.append(str); // if it's not a rescue or ensure, there's a frame associated, so decrement if (!(element.getMethodName().contains("__rescue__") || element.getMethodName().contains("__ensure__"))) { rubyFrameIndex--; } continue; } // look for __file__ method name for compiled roots if (element.getMethodName().equals("__file__")) { RubyString str = RubyString.newString( runtime, element.getFileName() + ":" + element.getLineNumber() + ": `<toplevel>'"); traceArray.append(str); rubyFrameIndex--; continue; } // look for mangling markers for bound, unframed methods in class name index = element.getClassName().indexOf("$RUBYINVOKER$"); if (index >= 0) { // unframed invokers have no Ruby frames, so pull from class name // but use current frame as file and line String unmangledMethod = element.getClassName().substring(index + 13); Frame current = context.frameStack[rubyFrameIndex]; RubyString str = RubyString.newString( runtime, current.getFile() + ":" + (current.getLine() + 1) + ":in `" + unmangledMethod + "'"); traceArray.append(str); continue; } // look for mangling markers for bound, framed methods in class name index = element.getClassName().indexOf("$RUBYFRAMEDINVOKER$"); if (index >= 0) { // framed invokers will have Ruby frames associated with them addBackTraceElement( traceArray, backtraceFrames[rubyFrameIndex], backtraceFrames[rubyFrameIndex - 1], FrameType.METHOD); rubyFrameIndex--; continue; } // try to mine out a Ruby frame using our list of interpreter entry-point markers String classMethod = element.getClassName() + "." + element.getMethodName(); FrameType frameType = INTERPRETED_FRAMES.get(classMethod); if (frameType != null) { // Frame matches one of our markers for "interpreted" calls if (rubyFrameIndex == 0) { addBackTraceElement( traceArray, backtraceFrames[rubyFrameIndex], backtraceFrames[rubyFrameIndex], frameType); } else { addBackTraceElement( traceArray, backtraceFrames[rubyFrameIndex], backtraceFrames[rubyFrameIndex - 1], frameType); rubyFrameIndex--; } continue; } else { // Frame is extraneous runtime information, skip it unless debug if (debug) { RubyString str = RubyString.newString(runtime, createRubyBacktraceString(element.getElement())); traceArray.append(str); } continue; } } return traceArray; }