示例#1
0
void Debugger::Interrupt(int type, const char *program,
                         InterruptSite *site /* = NULL */,
                         const char *error /* = NULL */) {
  ASSERT(RuntimeOption::EnableDebugger);

  RequestInjectionData &rjdata = ThreadInfo::s_threadInfo->m_reqInjectionData;
  if (rjdata.debuggerIdle > 0 && type == BreakPointReached) {
    --rjdata.debuggerIdle;
    return;
  }

  DebuggerProxyPtr proxy = GetProxy();
  if (proxy) {
    if (proxy->needInterrupt() || type != BreakPointReached) {
      // Interrupts may execute some PHP code, causing another interruption.
      std::stack<void *> &interrupts = rjdata.interrupts;

      CmdInterrupt cmd((InterruptType)type, program, site, error);
      interrupts.push(&cmd);
      proxy->interrupt(cmd);
      interrupts.pop();
    }
    rjdata.debuggerIdle = proxy->needInterrupt() ? 0 : 1000;
  } else {
    // debugger clients are disconnected abnormally
    if (type == SessionStarted || type == SessionEnded) {
      // for command line programs, we need this exception to exit from
      // the infinite execution loop
      throw DebuggerClientExitException();
    }
  }
}
示例#2
0
void DebuggerProxy::checkStop() {
  TRACE(2, "DebuggerProxy::checkStop\n");
  if (m_stopped) {
    Debugger::RemoveProxy(shared_from_this());
    m_thrift.close();
    throw DebuggerClientExitException();
  }
}
示例#3
0
void DebuggerProxy::processInterrupt(CmdInterrupt &cmd) {
  TRACE(2, "DebuggerProxy::processInterrupt\n");
  // Do the server-side work for this cmd, which just notifies the client.
  if (!cmd.onServer(this)) {
    Debugger::RemoveProxy(shared_from_this()); // on socket error
    return;
  }

  // Wait for commands from the debugger client and process them. We'll stay
  // here until we get a command that should cause the thread to continue.
  while (true) {
    DebuggerCommandPtr res;
    while (!DebuggerCommand::Receive(m_thrift, res,
                                     "DebuggerProxy::processInterrupt()")) {
      // we will wait forever until DebuggerClient sends us something
      checkStop();
    }
    checkStop();
    if (res) {
      // Any control flow command gets installed here and we continue execution.
      m_flow = dynamic_pointer_cast<CmdFlowControl>(res);
      if (m_flow) {
        m_flow->onServer(this);
        processFlowControl(cmd);
        if (m_flow && m_threadMode == Normal) {
          switchThreadMode(Sticky);
        }
        return;
      }
      if (res->is(DebuggerCommand::KindOfQuit)) {
        Debugger::RemoveProxy(shared_from_this());
        throw DebuggerClientExitException();
      }
    }
    try {
      // Perform the server-side work for this command.
      if (!res || !res->onServer(this)) {
        Debugger::RemoveProxy(shared_from_this());
        return;
      }
    } catch (const DebuggerException &e) {
      throw;
    } catch (...) {
      Logger::Error("onServer() throws non DebuggerException: %d",
                    res->getType());
      Debugger::RemoveProxy(shared_from_this());
      return;
    }
    if (res->shouldExitInterrupt()) {
      return;
    }
  }
}
示例#4
0
// Primary entrypoint for the debugger from the VM. Called in response to a host
// of VM events that the debugger is interested in. The debugger will execute
// any logic needed to handle the event, and will block below this to wait for
// and process more commands from the debugger client. This function will only
// return when the debugger is letting the thread continue execution, e.g., for
// flow control command like continue, next, etc.
void Debugger::Interrupt(int type, const char *program,
                         InterruptSite *site /* = NULL */,
                         const char *error /* = NULL */) {
  assert(RuntimeOption::EnableDebugger);
  TRACE_RB(2, "Debugger::Interrupt type %d\n", type);

  DebuggerProxyPtr proxy = GetProxy();
  if (proxy) {
    TRACE(3, "proxy != null\n");
    RequestInjectionData &rjdata = ThreadInfo::s_threadInfo->m_reqInjectionData;
    // The proxy will only service an interrupt if we've previously setup some
    // form of flow control command (steps, breakpoints, etc.) or if it's
    // an interrupt related to something like the session or request.
    if (proxy->needInterrupt() || type != BreakPointReached) {
      // Interrupts may execute some PHP code, causing another interruption.
      std::stack<void *> &interrupts = rjdata.interrupts;

      CmdInterrupt cmd((InterruptType)type, program, site, error);
      interrupts.push(&cmd);
      proxy->interrupt(cmd);
      interrupts.pop();
    }
    // Some cmds require us to interpret all instructions until the cmd
    // completes. Setting this will ensure we stay out of JIT code and in the
    // interpreter so phpDebuggerOpcodeHook has a chance to work.
    rjdata.setDebuggerIntr(proxy->needVMInterrupts());
  } else {
    TRACE(3, "proxy == null\n");
    // Debugger clients are disconnected abnormally, or this sandbox is not
    // being debugged.
    if (type == SessionStarted || type == SessionEnded) {
      // For command line programs, we need this exception to exit from
      // the infinite execution loop.
      throw DebuggerClientExitException();
    }
  }
}
示例#5
0
void Debugger::Interrupt(int type, const char *program,
                         InterruptSite *site /* = NULL */,
                         const char *error /* = NULL */) {
  ASSERT(RuntimeOption::EnableDebugger);

  DebuggerProxyPtr proxy = GetProxy();
  if (proxy) {
    // Interrupts may execute some PHP code, causing another interruption.
    void *&tint = ThreadInfo::s_threadInfo->m_reqInjectionData.interrupt;
    if (!tint) {
      CmdInterrupt cmd((InterruptType)type, program, site, error);
      tint = &cmd;
      proxy->interrupt(cmd);
      tint = NULL;
    }
  } else {
    // debugger clients are disconnected abnormally
    if (type == SessionStarted || type == SessionEnded) {
      // for command line programs, we need this exception to exit from
      // the infinite execution loop
      throw DebuggerClientExitException();
    }
  }
}
示例#6
0
// Stop the proxy, and stop execution of the current request.
void DebuggerProxy::stopAndThrow() {
  stop();
  throw DebuggerClientExitException();
}