Ejemplo n.º 1
0
// Handle a continue cmd, or setup stepping.
void DebuggerProxy::processFlowControl(CmdInterrupt &cmd) {
  TRACE(2, "DebuggerProxy::processFlowControl\n");
  switch (m_flow->getType()) {
    case DebuggerCommand::KindOfContinue:
      if (!m_flow->decCount()) {
        m_flow.reset();
      }
      break;
    case DebuggerCommand::KindOfStep:
      {
        // allows the breakpoint to be hit again when returns
        // from function call
        BreakPointInfoPtr bp = getBreakPointAtCmd(cmd);
        if (bp) {
          bp->setBreakable(getRealStackDepth());
        }
        break;
      }
    case DebuggerCommand::KindOfOut:
    case DebuggerCommand::KindOfNext:
      m_flow->setStackDepth(getStackDepth());
      m_flow->setVMDepth(g_vmContext->m_nesting);
      m_flow->setFileLine(cmd.getFileLine());
      break;
    default:
      assert(false);
      break;
  }
}
Ejemplo n.º 2
0
void CmdNext::onBeginInterrupt(DebuggerProxy &proxy, CmdInterrupt &interrupt) {
  TRACE(2, "CmdNext::onBeginInterrupt\n");
  assert(!m_complete); // Complete cmds should not be asked to do work.
  if (interrupt.getInterruptType() == ExceptionThrown) {
    // If an exception is thrown we turn interrupts on to ensure we stop when
    // control reaches the first catch clause.
    removeLocationFilter();
    m_needsVMInterrupt = true;
    return;
  }

  int currentVMDepth = g_vmContext->m_nesting;
  int currentStackDepth = proxy.getStackDepth();

  if ((currentVMDepth < m_vmDepth) ||
      ((currentVMDepth == m_vmDepth) && (currentStackDepth <= m_stackDepth))) {
    // We're at the same depth as when we started, or perhaps even shallower, so
    // there's no need for any step out breakpoint anymore.
    cleanupStepOut();

    if (m_loc != interrupt.getFileLine()) {
      TRACE(2, "CmdNext: same depth, off original line.\n");
      m_complete = (decCount() == 0);
    }
    if (!m_complete) {
      TRACE(2, "CmdNext: not complete, filter new line and keep stepping.\n");
      m_loc = interrupt.getFileLine();
      installLocationFilterForLine(interrupt.getSite());
      m_needsVMInterrupt = true;
    }
  } else {
    // Deeper, so let's setup a step out operation and turn interrupts off.
    if (!m_stepOutUnit) {
      // We can nuke the entire location filter here since we'll re-install it
      // when we get back to the old level. Keeping it installed may be more
      // efficient if we were on a large line, but there is a penalty for every
      // opcode executed while it's installed and that's bad if there's a lot of
      // code called from that line.
      removeLocationFilter();
      setupStepOut();
    }
    m_needsVMInterrupt = false;
  }
}
Ejemplo n.º 3
0
void CmdNext::onSetup(DebuggerProxy& proxy, CmdInterrupt& interrupt) {
  TRACE(2, "CmdNext::onSetup\n");
  assert(!m_complete); // Complete cmds should not be asked to do work.
  m_stackDepth = proxy.getStackDepth();
  m_vmDepth = g_vmContext->m_nesting;
  m_loc = interrupt.getFileLine();
  ActRec *fp = g_vmContext->getFP();
  assert(fp); // All interrupts which reach a flow cmd have an AR.
  PC pc = g_vmContext->getPC();
  stepCurrentLine(interrupt, fp, pc);
}
Ejemplo n.º 4
0
void CmdNext::onSetup(DebuggerProxy &proxy, CmdInterrupt &interrupt) {
  TRACE(2, "CmdNext::onSetup\n");
  assert(!m_complete); // Complete cmds should not be asked to do work.
  CmdFlowControl::onSetup(proxy, interrupt);
  m_stackDepth = proxy.getStackDepth();
  m_vmDepth = g_vmContext->m_nesting;
  m_loc = interrupt.getFileLine();

  // Start by single-stepping the current line.
  installLocationFilterForLine(interrupt.getSite());
  m_needsVMInterrupt = true;
}
Ejemplo n.º 5
0
void CmdNext::onSetup(DebuggerProxy& proxy, CmdInterrupt& interrupt) {
  TRACE(2, "CmdNext::onSetup\n");
  assertx(!m_complete); // Complete cmds should not be asked to do work.
  m_stackDepth = proxy.getStackDepth();
  m_vmDepth = g_context->m_nesting;
  m_loc = interrupt.getFileLine();
  ActRec *fp = vmfp();
  if (!fp) {
    // If we have no frame just wait for the next instruction to be interpreted.
    m_needsVMInterrupt = true;
    return;
  }
  PC pc = vmpc();
  stepCurrentLine(interrupt, fp, pc);
}
Ejemplo n.º 6
0
// Determine if an outstanding flow control cmd has run it's course and we
// should stop execution.
bool DebuggerProxy::breakByFlowControl(CmdInterrupt &cmd) {
  TRACE(2, "DebuggerProxy::breakByFlowControl\n");
  switch (m_flow->getType()) {
    case DebuggerCommand::KindOfStep: {
      if (!m_flow->decCount()) {
        // if the line changes and the stack depth is the same
        // pop the breakpoint depth stack
        m_flow.reset();
        return true;
      }
      break;
    }
    case DebuggerCommand::KindOfNext: {
      int currentVMDepth = g_vmContext->m_nesting;
      int currentStackDepth = getStackDepth();

      if (currentVMDepth <= m_flow->getVMDepth() &&
          currentStackDepth <= m_flow->getStackDepth() &&
          m_flow->getFileLine() != cmd.getFileLine()) {
            if (!m_flow->decCount()) {
              m_flow.reset();
              return true;
            }
      }

      break;
    }
    case DebuggerCommand::KindOfOut: {
      int currentVMDepth = g_vmContext->m_nesting;
      int currentStackDepth = getStackDepth();
      if (currentVMDepth < m_flow->getVMDepth()) {
        // Cut corner here, just break when cross VM boundary no matter how
        // many levels we want to go out of
        m_flow.reset();
        return true;
      } else if (m_flow->getStackDepth() - currentStackDepth >=
                 m_flow->getCount()) {
        m_flow.reset();
        return true;
      }
      break;
    }
    default:
      break;
  }
  return false;
}
Ejemplo n.º 7
0
void CmdNext::onBeginInterrupt(DebuggerProxy& proxy, CmdInterrupt& interrupt) {
  TRACE(2, "CmdNext::onBeginInterrupt\n");
  assertx(!m_complete); // Complete cmds should not be asked to do work.

  ActRec *fp = vmfp();
  if (!fp) {
    // If we have no frame just wait for the next instruction to be interpreted.
    m_needsVMInterrupt = true;
    return;
  }
  PC pc = vmpc();
  Unit* unit = fp->m_func->unit();
  Offset offset = unit->offsetOf(pc);
  TRACE(2, "CmdNext: pc %p, opcode %s at '%s' offset %d\n",
        pc,
        opcodeToName(peek_op(pc)),
        fp->m_func->fullName()->data(),
        offset);

  int currentVMDepth = g_context->m_nesting;
  int currentStackDepth = proxy.getStackDepth();

  TRACE(2, "CmdNext: original depth %d:%d, current depth %d:%d\n",
        m_vmDepth, m_stackDepth, currentVMDepth, currentStackDepth);

  // Where are we on the stack now vs. when we started? Breaking the answer down
  // into distinct variables helps the clarity of the algorithm below.
  bool deeper = false;
  bool originalDepth = false;
  if ((currentVMDepth == m_vmDepth) && (currentStackDepth == m_stackDepth)) {
    originalDepth = true;
  } else if ((currentVMDepth > m_vmDepth) ||
             ((currentVMDepth == m_vmDepth) &&
              (currentStackDepth > m_stackDepth))) {
    deeper = true;
  }

  m_needsVMInterrupt = false; // Will be set again below if still needed.

  // First consider if we've got internal breakpoints setup. These are used when
  // we can make an accurate prediction of where execution should flow,
  // eventually, and when we want to let the program run normally until we get
  // there.
  if (hasStepOuts() || hasStepResumable()) {
    TRACE(2, "CmdNext: checking internal breakpoint(s)\n");
    if (atStepOutOffset(unit, offset)) {
      if (deeper) return; // Recursion
      TRACE(2, "CmdNext: hit step-out\n");
    } else if (atStepResumableOffset(unit, offset)) {
      if (m_stepResumableId != getResumableId(fp)) return;
      TRACE(2, "CmdNext: hit step-cont\n");
      // We're in the resumable we expect. This may be at a
      // different stack depth, though, especially if we've moved from
      // the original function to the resumable. Update the depth
      // accordingly.
      if (!originalDepth) {
        m_vmDepth = currentVMDepth;
        m_stackDepth = currentStackDepth;
        deeper = false;
        originalDepth = true;
      }
    } else if (interrupt.getInterruptType() == ExceptionHandler) {
      // Entering an exception handler may take us someplace we weren't
      // expecting. Adjust internal breakpoints accordingly. First case is easy.
      if (deeper) {
        TRACE(2, "CmdNext: exception handler, deeper\n");
        return;
      }
      // For step-conts, we ignore handlers at the original level if we're not
      // in the original resumable. We don't care about exception handlers
      // in resumables being driven at the same level.
      if (hasStepResumable() && originalDepth &&
          (m_stepResumableId != getResumableId(fp))) {
        TRACE(2, "CmdNext: exception handler, original depth, wrong cont\n");
        return;
      }
      // Sometimes we have handlers in generated code, i.e., Continuation::next.
      // These just help propagate exceptions so ignore those.
      if (fp->m_func->line1() == 0) {
        TRACE(2, "CmdNext: exception handler, ignoring func with no source\n");
        return;
      }
      if (fp->m_func->isBuiltin()) {
        TRACE(2, "CmdNext: exception handler, ignoring builtin functions\n");
        return;
      }
      TRACE(2, "CmdNext: exception handler altering expected flow\n");
    } else {
      // We have internal breakpoints setup, but we haven't hit one yet. Keep
      // running until we reach one.
      TRACE(2, "CmdNext: waiting to hit internal breakpoint...\n");
      return;
    }
    // We've hit one internal breakpoint at a useful place, or decided we don't,
    // need them, so we can remove them all now.
    cleanupStepOuts();
    cleanupStepResumable();
  }

  if (interrupt.getInterruptType() == ExceptionHandler) {
    // If we're about to enter an exception handler we turn interrupts on to
    // ensure we stop when control reaches the handler. The normal logic below
    // will decide if we're done at that point or not.
    TRACE(2, "CmdNext: exception handler\n");
    removeLocationFilter();
    m_needsVMInterrupt = true;
    return;
  }

  if (m_skippingAwait) {
    m_skippingAwait = false;
    stepAfterAwait();
    return;
  }

  if (deeper) {
    TRACE(2, "CmdNext: deeper, setup step out to get back to original line\n");
    setupStepOuts();
    // We can nuke the entire location filter here since we'll re-install it
    // when we get back to the old level. Keeping it installed may be more
    // efficient if we were on a large line, but there is a penalty for every
    // opcode executed while it's installed and that's bad if there's a lot of
    // code called from that line.
    removeLocationFilter();
    return;
  }

  if (originalDepth && (m_loc == interrupt.getFileLine())) {
    TRACE(2, "CmdNext: not complete, still on same line\n");
    stepCurrentLine(interrupt, fp, pc);
    return;
  }

  TRACE(2, "CmdNext: operation complete.\n");
  m_complete = (decCount() == 0);
  if (!m_complete) {
    TRACE(2, "CmdNext: repeat count > 0, start fresh.\n");
    onSetup(proxy, interrupt);
  }
}