Example #1
0
void HphpdHook::onDefClass(const Class* cls) {
  // Make sure we have a proxy
  DebuggerProxy* proxy = Debugger::GetProxy().get();
  if (proxy == nullptr) return;

  // If the proxy has enabled breakpoints that match entry into methods of
  // the given class, arrange for the VM to stop execution and notify the
  // debugger whenever execution enters one of these matched method.
  // This function is called once, when a class is first loaded, so it is not
  // performance critical.
  size_t numFuncs = cls->numMethods();
  if (numFuncs == 0) return;
  auto clsName = cls->name();
  std::vector<BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    BreakPointInfoPtr bp = bps[i];
    if (bp->m_state == BreakPointInfo::Disabled) continue;
    // TODO: check name space separately
    if (bp->getClass() != clsName->data()) continue;
    bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
    for (size_t i = 0; i < numFuncs; ++i) {
      auto f = cls->getMethod(i);
      if (!matchFunctionName(bp->getFunction(), f)) continue;
      bp->m_bindState = BreakPointInfo::KnownToBeValid;
      phpAddBreakPointFuncEntry(f);
    }
  }
}
Example #2
0
bool CmdBreak::validate(DebuggerClient *client, BreakPointInfoPtr bpi,
                        int index) {
  ++index;
  if (client->arg(index, "if")) {
    bpi->setClause(client->lineRest(++index), true);
  } else if (client->arg(index, "&&")) {
    bpi->setClause(client->lineRest(++index), false);
  }

  if (bpi->valid()) {
    m_breakpoints = client->getBreakPoints();
    for (int i = 0; i < (int)m_breakpoints->size(); i++) {
      if ((*m_breakpoints)[i]->same(bpi)) {
        client->error("Breakpoint was already set previously.");
        return true;
      }
    }
    m_breakpoints->push_back(bpi);
    updateImpl(client);
    client->info("Breakpoint %d set %s", bpi->index(), bpi->desc().c_str());
    return true;
  }

  if (!bpi->m_url.empty()) {
    client->error("@{url} cannot be specified alone.");
  } else {
    client->error("Breakpoint was not set in right format.");
  }
  return false;
}
Example #3
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;
  }
}
Example #4
0
// Hold the entire set of breakpoints, and sift breakpoints by function and
// class name into separate containers for later.
void DebuggerProxy::setBreakPoints(BreakPointInfoPtrVec &breakpoints) {
  TRACE(2, "DebuggerProxy::setBreakPoints\n");
  // Hold the break mutex while we update the proxy's state. There's no need
  // to hold it over the longer operation to set breakpoints in each file later.
  {
    WriteLock lock(m_breakMutex);
    m_breakpoints = breakpoints;
    m_hasBreakPoints = !m_breakpoints.empty();
    m_breaksEnterFunc.clear();
    m_breaksEnterClsMethod.clear();
    for (unsigned int i = 0; i < m_breakpoints.size(); i++) {
      BreakPointInfoPtr bp = m_breakpoints[i];
      std::string funcFullName = bp->getFuncName();
      if (funcFullName.empty()) {
        continue;
      }
      {
        StringDataMap::accessor acc;
        const StringData* sd = StringData::GetStaticString(funcFullName);
        m_breaksEnterFunc.insert(acc, sd);
      }
      std::string clsName = bp->getClass();
      if (!clsName.empty()) {
        StringDataMap::accessor acc;
        const StringData* sd = StringData::GetStaticString(clsName);
        m_breaksEnterClsMethod.insert(acc, sd);
      }
    }
  }
  VM::phpSetBreakPointsInAllFiles(this); // Apply breakpoints to the code.
}
Example #5
0
void DebuggerProxy::changeBreakPointDepth(CmdInterrupt& cmd) {
  TRACE(2, "DebuggerProxy::changeBreakPointDepth\n");
  for (unsigned int i = 0; i < m_breakpoints.size(); ++i) {
    // if the site changes, then update the breakpoint depth
    BreakPointInfoPtr bp = m_breakpoints[i];
    if (bp->m_state != BreakPointInfo::Disabled &&
        !bp->match(cmd.getInterruptType(), *cmd.getSite())) {
      m_breakpoints[i]->changeBreakPointDepth(getRealStackDepth());
    }
  }
}
Example #6
0
// There could be multiple breakpoints at one place but we can manage this
// with only one breakpoint.
BreakPointInfoPtr DebuggerProxy::getBreakPointAtCmd(CmdInterrupt& cmd) {
  TRACE(2, "DebuggerProxy::getBreakPointAtCmd\n");
  for (unsigned int i = 0; i < m_breakpoints.size(); ++i) {
    BreakPointInfoPtr bp = m_breakpoints[i];
    if (bp->m_state != BreakPointInfo::Disabled &&
        bp->match(cmd.getInterruptType(), *cmd.getSite())) {
      return bp;
    }
  }
  return BreakPointInfoPtr();
}
// Do not allow further breaks on the site of cmd, except during
// calls made from the current site.
void DebuggerProxy::unsetBreakableForBreakpointsMatching(CmdInterrupt& cmd) {
  TRACE(2, "DebuggerProxy::unsetBreakableForBreakpointsMatching\n");
  auto stackDepth = getRealStackDepth();
  for (unsigned int i = 0; i < m_breakpoints.size(); ++i) {
    BreakPointInfoPtr bp = m_breakpoints[i];
    if (bp != nullptr && bp->m_state != BreakPointInfo::Disabled &&
        bp->match(*this, cmd.getInterruptType(), *cmd.getSite())) {
      bp->unsetBreakable(stackDepth);
    }
  }
}
Example #8
0
void CmdStep::onSetup(DebuggerProxy *proxy, CmdInterrupt &interrupt) {
  assert(!m_complete); // Complete cmds should not be asked to do work.
  CmdFlowControl::onSetup(proxy, interrupt);
  // Allows a breakpoint on this same line to be hit again when control returns
  // from function call.
  BreakPointInfoPtr bp = proxy->getBreakPointAtCmd(interrupt);
  if (bp) {
    bp->setBreakable(proxy->getRealStackDepth());
  }
  installLocationFilterForLine(interrupt.getSite());
  m_needsVMInterrupt = true;
}
Variant c_DebuggerClientCmdUser::t_getcurrentlocation() {
  TRACE(5, "c_DebuggerClientCmdUser::t_getcurrentlocation\n");
  BreakPointInfoPtr bpi = m_client->getCurrentLocation();
  if (!bpi) return Array::Create();
  ArrayInit ret(6);
  ret.set(s_file,      String(bpi->m_file));
  ret.set(s_line,      (int64_t)bpi->m_line1);
  ret.set(s_namespace, String(bpi->getNamespace()));
  ret.set(s_class,     String(bpi->getClass()));
  ret.set(s_function,  String(bpi->getFunction()));
  ret.set(s_text,      String(bpi->site()));
  return ret.create();
}
Example #10
0
void CmdBreak::setClientOutput(DebuggerClient *client) {
  // Output an array of current breakpoints including exceptions
  client->setOutputType(DebuggerClient::OTValues);
  Array values;
  m_breakpoints = client->getBreakPoints();
  for (int i = 0; i < (int)m_breakpoints->size(); i++) {
    BreakPointInfoPtr bpi = m_breakpoints->at(i);
    Array breakpoint;
    breakpoint.set(s_id, bpi->index());
    breakpoint.set(s_state, bpi->state(false));
    if (bpi->m_interrupt == ExceptionThrown) {
      breakpoint.set(s_is_exception, true);
      breakpoint.set(s_exception_class, bpi->getExceptionClass());
    } else {
      breakpoint.set(s_is_exception, false);
      breakpoint.set(s_file, bpi->m_file);
      breakpoint.set(s_line1, bpi->m_line1);
      breakpoint.set(s_line2, bpi->m_line2);
      breakpoint.set(s_namespace, bpi->getNamespace());
      breakpoint.set(s_func, bpi->getFunction());
      breakpoint.set(s_class, bpi->getClass());
    }
    breakpoint.set(s_url, bpi->m_url);
    breakpoint.set(s_use_regex, bpi->m_regex);
    breakpoint.set(s_clause_type, bpi->m_check ? s_if : s_ampamp);
    breakpoint.set(s_clause, bpi->m_clause);
    breakpoint.set(s_desc, bpi->desc());
    values.append(breakpoint);
  }
  client->setOTValues(values);
}
Example #11
0
Variant c_DebuggerClientCmdUser::t_getcurrentlocation() {
  INSTANCE_METHOD_INJECTION_BUILTIN(DebuggerClientCmdUser, DebuggerClientCmdUser::getcurrentlocation);
  BreakPointInfoPtr bpi = m_client->getCurrentLocation();
  Array ret(Array::Create());
  if (bpi) {
    ret.set("file",      String(bpi->m_file));
    ret.set("line",      (int64)bpi->m_line1);
    ret.set("namespace", String(bpi->getNamespace()));
    ret.set("class",     String(bpi->getClass()));
    ret.set("function",  String(bpi->getFunction()));
    ret.set("text",      String(bpi->site()));
  }
  return ret;
}
Example #12
0
void HphpdHook::onDefFunc(const Func* f) {
  // Make sure we have a proxy
  DebuggerProxyPtr proxy = Debugger::GetProxy();
  if (proxy == nullptr) return;

  // If the proxy has an enabled breakpoint that matches entry into the given
  // function, arrange for the VM to stop execution and notify the debugger
  // whenever execution enters the given function.
  std::vector<BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    BreakPointInfoPtr bp = bps[i];
    if (bp->m_state == BreakPointInfo::Disabled) continue;
    if (!matchFunctionName(bp->getFuncName(), f)) continue;
    bp->m_bindState = BreakPointInfo::KnownToBeValid;
    phpAddBreakPointFuncEntry(f);
    return;
  }
}
Example #13
0
bool CmdBreak::processList(DebuggerClient *client) {
  m_breakpoints = client->getBreakPoints();
  for (int i = 0; i < (int)m_breakpoints->size(); i++) {
    BreakPointInfoPtr bpi = m_breakpoints->at(i);
    client->print("  %d\t%s  %s", bpi->index(), bpi->state(true).c_str(),
                  bpi->desc().c_str());
  }
  if (m_breakpoints->empty()) {
    client->tutorial(
      "Use '[b]reak ?|[h]elp' to read how to set breakpoints. "
    );
  } else {
    client->tutorial(
      "Use '[b]reak [c]lear {index}|[a]ll' to remove breakpoint(s). "
      "Use '[b]reak [t]oggle {index}|[a]ll' to change their states."
    );
  }
  return true;
}
Example #14
0
void DebuggerProxy::setBreakPoints(
  std::vector<BreakPointInfoPtr>& breakpoints
) {
  TRACE(2, "DebuggerProxy::setBreakPoints\n");
  // Hold the break mutex while we update the proxy's state. There's no need to
  // hold it over the longer operation to set breakpoints in each file later.
  {
    WriteLock lock(m_breakMutex);
    // breakpoints holds a list of fresh new BreakPointInfo objects that
    // have been deserialized from the client's list of breakpoints.
    // The existing BreakPointInfo objects may include non empty values
    // for m_stack. If these get thrown away, breakpoints that are temporarily
    // disabled will suddenly fire again, which is not what we want to
    // happen if we create a new breakpoint or just even list breakpoints.
    auto it = m_breakpoints.begin();
    for (auto it1 = breakpoints.begin(); it1 != breakpoints.end(); ++it1)  {
      BreakPointInfoPtr newBreakPoint = *it1;
      do {
        for (auto it2 = it; it2 != m_breakpoints.end(); ) {
          BreakPointInfoPtr oldBreakPoint = *it2++;
          if (oldBreakPoint->same(newBreakPoint)) {
            newBreakPoint->transferStack(oldBreakPoint);
            it = it2;
            goto next_breakpoint;
          }
        }
        if (it == m_breakpoints.begin()) goto next_breakpoint;
        // Only searched a part of m_breakpoints. Reset it and try again.
        it = m_breakpoints.begin();
      } while (true);
      next_breakpoint: continue;
    }
    m_breakpoints = breakpoints;
    m_hasBreakPoints = !m_breakpoints.empty();
  }
  proxySetBreakPoints(this);
}
Example #15
0
void proxySetBreakPoints(DebuggerProxy* proxy) {
  std::vector<BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    BreakPointInfoPtr bp = bps[i];
    bp->m_bindState = BreakPointInfo::Unknown;
    auto className = bp->getClass();
    if (!className.empty()) {
      auto clsName = makeStaticString(className);
      auto cls = Unit::lookupClass(clsName);
      if (cls == nullptr) continue;
      bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
      size_t numFuncs = cls->numMethods();
      if (numFuncs == 0) continue;
      auto methodName = bp->getFunction();
      for (size_t i = 0; i < numFuncs; ++i) {
        auto f = cls->getMethod(i);
        if (!matchFunctionName(methodName, f)) continue;
        bp->m_bindState = BreakPointInfo::KnownToBeValid;
        phpAddBreakPointFuncEntry(f);
        break;
      }
      // TODO(#2527229): what about superclass methods accessed via the derived
      // class?
      continue;
    }
    auto funcName = bp->getFuncName();
    if (!funcName.empty()) {
      auto fName = makeStaticString(funcName);
      Func* f = Unit::lookupFunc(fName);
      if (f == nullptr) continue;
      bp->m_bindState = BreakPointInfo::KnownToBeValid;
      phpAddBreakPointFuncEntry(f);
      continue;
    }
    auto fileName = bp->m_file;
    if (!fileName.empty()) {
      for (auto& kv : g_context->m_evaledFiles) {
        auto const unit = kv.second;
        if (!BreakPointInfo::MatchFile(fileName,
                            unit->filepath()->toCppString())) {
          continue;
        }
        addBreakPointInUnit(bp, unit);
        break;
      }
      continue;
    }
    auto exceptionClassName = bp->getExceptionClass();
    if (exceptionClassName == "@") {
      bp->m_bindState = BreakPointInfo::KnownToBeValid;
      continue;
    } else if (!exceptionClassName.empty()) {
      auto expClsName = makeStaticString(exceptionClassName);
      auto cls = Unit::lookupClass(expClsName);
      if (cls != nullptr) {
        auto baseClsName = makeStaticString("Exception");
        auto baseCls = Unit::lookupClass(baseClsName);
        if (baseCls != nullptr) {
          if (cls->classof(baseCls)) {
            bp->m_bindState = BreakPointInfo::KnownToBeValid;
          } else {
            bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
          }
        }
      }
      continue;
    } else {
      continue;
    }
    // If we get here, the break point is of a type that does
    // not need to be explicitly enabled in the VM. For example
    // a break point that get's triggered when the server starts
    // to process a page request.
    bp->m_bindState = BreakPointInfo::KnownToBeValid;
  }
}
Example #16
0
bool CmdInterrupt::onClient(DebuggerClient *client) {
  client->setCurrentLocation(m_threadId, m_bpi);
  client->setMatchedBreakPoints(m_matched);

  switch (m_interrupt) {
    case SessionEnded:
    case RequestEnded:
    case PSPEnded:
      if (m_pendingJump) {
        client->error("Your jump point cannot be reached. You may only jump "
                      "to certain parallel or outer execution points.");
      }
      break;
  }

  switch (m_interrupt) {
    case SessionStarted:
      if (!m_program.empty()) {
        client->info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.",
                     m_program.c_str());
        m_bpi->m_file = m_program;
      }
      break;
    case SessionEnded:
      if (!m_program.empty()) {
        client->info("Program %s exited normally.", m_program.c_str());
      }
      break;
    case RequestStarted:
      if (!m_program.empty()) {
        client->info("Web request %s started.", m_program.c_str());
      }
      break;
    case RequestEnded:
      if (!m_program.empty()) {
        client->info("Web request %s ended.", m_program.c_str());
      }
      break;
    case PSPEnded:
      if (!m_program.empty()) {
        client->info("Post-Send Processing for %s was ended.",
                     m_program.c_str());
      }
      break;
    case BreakPointReached:
    case ExceptionThrown: {
      bool found = false;
      bool toggled = false;
      BreakPointInfoPtrVec *bps = client->getBreakPoints();
      for (unsigned int i = 0; i < m_matched.size(); i++) {
        BreakPointInfoPtr bpm = m_matched[i];
        BreakPointInfoPtr bp;
        int index = 0;
        for (; index < (int)bps->size(); index++) {
          if (bpm->same((*bps)[index])) {
            bp = (*bps)[index];
            break;
          }
        }
        if (bp) {
          found = true;
          if (bp->m_state == BreakPointInfo::Once) {
            bp->m_state = BreakPointInfo::Disabled;
            toggled = true;
          }
          if (m_interrupt == BreakPointReached) {
            client->info("Breakpoint %d reached %s", index + 1,
                         m_bpi->site().c_str());
          } else {
            client->info("Breakpoint %d reached: Throwing %s %s", index + 1,
                         m_bpi->m_exceptionClass.c_str(),
                         m_bpi->site().c_str());
            client->output(m_bpi->m_exceptionObject);
          }
          if (!bpm->m_output.empty()) {
            client->print(bpm->m_output);
          }
        }
      }
      if (toggled) {
        CmdBreak().update(client);
      }
      if (!found) {
        client->info("Break %s", m_bpi->site().c_str());
      }
      break;
    }
  }

  if (!m_errorMsg.empty()) {
    client->error(m_errorMsg);
  }

  // watches
  switch (m_interrupt) {
    case SessionStarted:
    case RequestStarted:
      break;
    default: {
      DebuggerClient::WatchPtrVec &watches = client->getWatches();
      for (int i = 0; i < (int)watches.size(); i++) {
        if (i > 0) client->output("");
        client->info("Watch %d: %s =", i + 1, watches[i]->second.c_str());
        CmdPrint().processWatch(client, watches[i]->first, watches[i]->second);
      }
    }
  }

  return true;
}
Example #17
0
bool CmdBreak::processUpdate(DebuggerClient *client) {
  m_breakpoints = client->getBreakPoints();
  if (m_breakpoints->empty()) {
    client->error("There is no breakpoint to clear or toggle.");
    client->tutorial(
      "Use '[b]reak ?|[h]elp' to read how to set breakpoints. "
    );
    return true;
  }

  if (client->argCount() == 1) {
    BreakPointInfoPtrVec *matched = client->getMatchedBreakPoints();
    BreakPointInfoPtrVec *bps = client->getBreakPoints();
    bool found = false;
    for (unsigned int i = 0; i < matched->size(); i++) {
      BreakPointInfoPtr bpm = (*matched)[i];
      BreakPointInfoPtr bp;
      int index = 0;
      for (; index < (int)bps->size(); index++) {
        if (bpm->same((*bps)[index])) {
          bp = (*bps)[index];
          break;
        }
      }
      if (bp) {
        const char *action;
        if (hasClearArg(client)) {
          action = "cleared";
          bps->erase(bps->begin() + index);
        } else if (hasEnableArg(client)) {
          action = "updated";
          bp->setState(BreakPointInfo::Always);
        } else if (hasDisableArg(client)) {
          action = "updated";
          bp->setState(BreakPointInfo::Disabled);
        } else {
          assert(hasToggleArg(client));
          action = "updated";
          bp->toggle();
        }
        client->info("Breakpoint %d is %s %s", bp->index(),
                     action, bp->site().c_str());
        found = true;
      }
    }
    if (found) {
      updateImpl(client);
      return true;
    }

    client->error("There is no current breakpoint to clear or toggle.");
    return true;
  }

  if (client->arg(2, "all")) {
    if (hasClearArg(client)) {
      m_breakpoints->clear();
      updateImpl(client);
      client->info("All breakpoints are cleared.");
      return true;
    }

    for (unsigned int i = 0; i < m_breakpoints->size(); i++) {
      BreakPointInfoPtr bpi = (*m_breakpoints)[i];
      if (hasEnableArg(client)) {
        bpi->setState(BreakPointInfo::Always);
      }
      else if (hasDisableArg(client)) {
        bpi->setState(BreakPointInfo::Disabled);
      }
      else {
        assert(hasToggleArg(client));
        bpi->toggle();
      }
    }

    updateImpl(client);
    return processList(client);
  }

  string snum = client->argValue(2);
  if (!DebuggerClient::IsValidNumber(snum)) {
    client->error("'[b]reak [c]lear|[t]oggle' needs an {index} argument.");
    client->tutorial(
      "You will have to run '[b]reak [l]ist' first to see a list of valid "
      "numbers or indices to specify."
    );
    return true;
  }

  int index = -1;
  int num = atoi(snum.c_str());
  for (unsigned int i = 0; i < m_breakpoints->size(); i++) {
    if (m_breakpoints->at(i)->index() == num) {
      index = i;
      break;
    }
  }
  if (index < 0) {
    client->error("\"%s\" is not a valid breakpoint index. Choose one from "
                  "this list:", snum.c_str());
    processList(client);
    return true;
  }

  BreakPointInfoPtr bpi = (*m_breakpoints)[index];
  if (hasClearArg(client)) {
    m_breakpoints->erase(m_breakpoints->begin() + index);
    updateImpl(client);
    client->info("Breakpoint %d cleared %s", bpi->index(),
                 bpi->desc().c_str());
  } else if (hasEnableArg(client)) {
    bpi->setState(BreakPointInfo::Always);
    updateImpl(client);
    client->info("Breakpoint %d's state is changed to %s.", bpi->index(),
                 bpi->state(false).c_str());
  } else if (hasDisableArg(client)) {
    bpi->setState(BreakPointInfo::Disabled);
    updateImpl(client);
    client->info("Breakpoint %d's state is changed to %s.", bpi->index(),
                 bpi->state(false).c_str());
  } else {
    assert(hasToggleArg(client));
    bpi->toggle();
    updateImpl(client);
    client->info("Breakpoint %d's state is changed to %s.", bpi->index(),
                 bpi->state(false).c_str());
  }

  return true;
}
Example #18
0
void CmdInterrupt::onClient(DebuggerClient &client) {
  client.setCurrentLocation(m_threadId, m_bpi);
  if (!client.getDebuggerClientSmallStep()) {
    // Adjust line and char if it's not small stepping
    if (m_bpi->m_line1 == m_bpi->m_line2) {
      m_bpi->m_char1 = 1;
      m_bpi->m_char2 = 100;
    }
  }
  client.setMatchedBreakPoints(m_matched);

  switch (m_interrupt) {
    case SessionStarted:
      if (!m_program.empty()) {
        client.info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.",
                     m_program.c_str());
        m_bpi->m_file = m_program;
      }
      break;
    case SessionEnded:
      if (!m_program.empty()) {
        client.info("Program %s exited normally.", m_program.c_str());
      }
      break;
    case RequestStarted:
      if (!m_program.empty()) {
        client.info("Web request %s started.", m_program.c_str());
      }
      break;
    case RequestEnded:
      if (!m_program.empty()) {
        client.info("Web request %s ended.", m_program.c_str());
      }
      break;
    case PSPEnded:
      if (!m_program.empty()) {
        client.info("Post-Send Processing for %s was ended.",
                     m_program.c_str());
      }
      break;
    case HardBreakPoint:
    case BreakPointReached:
    case ExceptionThrown: {
      bool found = false;
      bool toggled = false;
      auto *bps = client.getBreakPoints();
      for (unsigned int i = 0; i < m_matched.size(); i++) {
        BreakPointInfoPtr bpm = m_matched[i];
        BreakPointInfoPtr bp;
        int index = 0;
        for (; index < (int)bps->size(); index++) {
          if (bpm->same((*bps)[index])) {
            bp = (*bps)[index];
            break;
          }
        }
        if (bp) {
          found = true;
          if (bp->m_state == BreakPointInfo::Once) {
            bp->m_state = BreakPointInfo::Disabled;
            toggled = true;
          }
          if (m_interrupt == BreakPointReached ||
              m_interrupt == HardBreakPoint) {
            client.info("Breakpoint %d reached %s", bp->index(),
                         m_bpi->site().c_str());
            client.shortCode(m_bpi);
          } else {
            if (m_bpi->m_exceptionClass == BreakPointInfo::ErrorClassName) {
              client.info("Breakpoint %d reached: An error occurred %s",
                           bp->index(), m_bpi->site().c_str());
              client.shortCode(m_bpi);
              client.error("Error Message: %s",
                            m_bpi->m_exceptionObject.c_str());
            } else {
              client.info("Breakpoint %d reached: Throwing %s %s",
                           bp->index(),
                           m_bpi->m_exceptionClass.c_str(),
                           m_bpi->site().c_str());
              client.shortCode(m_bpi);
              if (client.getLogFileHandler()) {
                client.output(m_bpi->m_exceptionObject);
              }
            }
          }
          if (!bpm->m_output.empty()) {
            client.print(bpm->m_output);
          }
        }
      }
      if (toggled) {
        CmdBreak::SendClientBreakpointListToServer(client);
      }
      if (!found) {
        if (m_interrupt == HardBreakPoint) {
          // for HardBreakPoint, default the frame to the caller
          client.setFrame(1);
        }
        client.info("Break %s", m_bpi->site().c_str());
        client.shortCode(m_bpi);
      }
      break;
    }
  }

  if (!m_errorMsg.empty()) {
    client.error(m_errorMsg);
  }

  // watches
  switch (m_interrupt) {
    case SessionStarted:
    case RequestStarted:
      break;
    default: {
      DebuggerClient::WatchPtrVec &watches = client.getWatches();
      for (int i = 0; i < (int)watches.size(); i++) {
        if (i > 0) client.output("%s", "");
        client.info("Watch %d: %s =", i + 1, watches[i]->second.c_str());
        Variant v = CmdPrint().processWatch(client, watches[i]->first,
                                            watches[i]->second);
        client.output(CmdPrint::FormatResult(watches[i]->first, v));
      }
    }
  }
}
Example #19
0
// Handle an interrupt from the VM.
void DebuggerProxy::interrupt(CmdInterrupt &cmd) {
  TRACE(2, "DebuggerProxy::interrupt\n");
  changeBreakPointDepth(cmd);

  if (cmd.getInterruptType() == BreakPointReached) {
    if (!needInterrupt()) return;

    // NB: stepping is represented as a BreakPointReached interrupt.

    // Modify m_lastLocFilter to save current location. This will short-circuit
    // the work done up in phpDebuggerOpcodeHook() and ensure we don't break on
    // this line until we're completely off of it.
    InterruptSite *site = cmd.getSite();
    if (g_vmContext->m_lastLocFilter) {
      g_vmContext->m_lastLocFilter->clear();
    } else {
      g_vmContext->m_lastLocFilter = new VM::PCFilter();
    }
    if (debug && Trace::moduleEnabled(Trace::bcinterp, 5)) {
      Trace::trace("prepare source loc filter\n");
      const VM::OffsetRangeVec& offsets = site->getCurOffsetRange();
      for (VM::OffsetRangeVec::const_iterator it = offsets.begin();
           it != offsets.end(); ++it) {
        Trace::trace("block source loc in %s:%d: unit %p offset [%d, %d)\n",
                     site->getFile(), site->getLine0(),
                     site->getUnit(), it->m_base, it->m_past);
      }
    }
    g_vmContext->m_lastLocFilter->addRanges(site->getUnit(),
                                            site->getCurOffsetRange());
    // If the breakpoint is not to be processed, we should continue execution.
    BreakPointInfoPtr bp = getBreakPointAtCmd(cmd);
    if (bp) {
      if (!bp->breakable(getRealStackDepth())) {
        return;
      } else {
        bp->unsetBreakable(getRealStackDepth());
      }
    }
  }

  // Wait until this thread is the thread this proxy wants to debug.
  // NB: breakpoints and control flow checks happen here, too, and return false
  // if we're not done with the flow, or not at a breakpoint, etc.
  if (!blockUntilOwn(cmd, true)) {
    return;
  }
  if (processFlowBreak(cmd)) {
    while (true) {
      try {
        Lock lock(m_signalMutex);
        m_signum = CmdSignal::SignalNone;
        processInterrupt(cmd);
      } catch (const DebuggerException &e) {
        switchThreadMode(Normal);
        throw;
      } catch (...) {
        assert(false); // no other exceptions should be seen here
        switchThreadMode(Normal);
        throw;
      }
      if (cmd.getInterruptType() == PSPEnded) {
        switchThreadMode(Normal);
        return; // we are done with this thread
      }
      if (!m_newThread) {
        break; // we're not switching threads
      }

      switchThreadMode(Normal, m_newThread->m_id);
      blockUntilOwn(cmd, false);
    }
  }

  if (m_threadMode == Normal) {
    Lock lock(this);
    m_thread = 0;
    notify();
  } else if (cmd.getInterruptType() == PSPEnded) {
    switchThreadMode(Normal); // we are done with this thread
  }
}