Beispiel #1
0
  /**
   * 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;
  }
Beispiel #2
0
  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);
  }
Beispiel #3
0
  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()));
  }
Beispiel #4
0
  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;
  }