Пример #1
0
// Helper which will look at every loaded file and attempt to see if any
// existing file:line breakpoints should be set.
void phpSetBreakPointsInAllFiles(Eval::DebuggerProxy* proxy) {
  for (EvaledFilesMap::const_iterator it =
       g_vmContext->m_evaledFiles.begin();
       it != g_vmContext->m_evaledFiles.end(); ++it) {
    addBreakPointsInFile(proxy, it->second);
  }

  std::vector<const StringData*> clsNames;
  proxy->getBreakClsMethods(clsNames);
  for (unsigned int i = 0; i < clsNames.size(); i++) {
    Class* cls = Unit::lookupClass(clsNames[i]);
    if (cls) {
      addBreakPointsClass(proxy, cls);
    }
  }

  std::vector<const StringData*> funcFullNames;
  proxy->getBreakFuncs(funcFullNames);
  for (unsigned int i = 0; i < funcFullNames.size(); i++) {
    // This list contains class method as well but they shouldn't hit anything
    Func* f = Unit::lookupFunc(funcFullNames[i]);
    if (f) {
      addBreakPointFuncEntry(f);
    }
  }
}
Пример #2
0
static void addBreakPointsClass(Eval::DebuggerProxy* proxy,
                                const Class* cls) {
  size_t numFuncs = cls->numMethods();
  Func* const* funcs = cls->methods();
  for (size_t i = 0; i < numFuncs; ++i) {
    if (proxy->couldBreakEnterFunc(funcs[i]->fullName())) {
      addBreakPointFuncEntry(funcs[i]);
    }
  }
}
Пример #3
0
// 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.
static void addBreakPointFuncEntry(Eval::DebuggerProxy* proxy, const Func* f) {
  std::vector<Eval::BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    if (bp->m_state == Eval::BreakPointInfo::Disabled) continue;
    if (!matchFunctionName(bp->getFuncName(), f)) continue;
    bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
    addBreakPointFuncEntry(f);
    return;
  }
}
Пример #4
0
// 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.
static void addBreakPointFuncEntry(Eval::DebuggerProxy* proxy, const Func* f) {
  Eval::BreakPointInfoPtrVec bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    if (bp->m_state == Eval::BreakPointInfo::Disabled) continue;
    if (bp->getFuncName() != f->fullName()->data()) continue;
    bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
    addBreakPointFuncEntry(f);
    return;
  }
}
Пример #5
0
// 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.
static void addBreakPointsClass(Eval::DebuggerProxy* proxy, const Class* cls) {
  size_t numFuncs = cls->numMethods();
  if (numFuncs == 0) return;
  auto clsName = cls->name();
  std::vector<Eval::BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    if (bp->m_state == Eval::BreakPointInfo::Disabled) continue;
    // TODO: check name space separately
    if (bp->getClass() != clsName->data()) continue;
    bp->m_bindState = Eval::BreakPointInfo::KnownToBeInvalid;
    for (size_t i = 0; i < numFuncs; ++i) {
      auto f = cls->getMethod(i);
      if (!matchFunctionName(bp->getFunction(), f)) continue;
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
      addBreakPointFuncEntry(f);
    }
  }
}
Пример #6
0
void phpDebuggerDefFuncHook(const Func* func) {
  Eval::DebuggerProxyPtr proxy = Eval::Debugger::GetProxy();
  if (proxy && proxy->couldBreakEnterFunc(func->fullName())) {
    addBreakPointFuncEntry(func);
  }
}
Пример #7
0
// Called by the proxy whenever its breakpoint list is updated.
// Since this intended to be called when user input is received, it is not
// performance critical. Also, in typical scenarios, the list is short.
void phpSetBreakPoints(Eval::DebuggerProxy* proxy) {
  std::vector<Eval::BreakPointInfoPtr> bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    bp->m_bindState = Eval::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 = Eval::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 = Eval::BreakPointInfo::KnownToBeValid;
        addBreakPointFuncEntry(f);
        break;
      }
      //TODO: what about superclass methods accessed via the derived class?
      //Task 2527229.
      continue;
    }
    auto funcName = bp->getFuncName();
    if (!funcName.empty()) {
      auto fName = makeStaticString(funcName);
      Func* f = Unit::lookupFunc(fName);
      if (f == nullptr) continue;
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
      addBreakPointFuncEntry(f);
      continue;
    }
    auto fileName = bp->m_file;
    if (!fileName.empty()) {
      for (auto it = g_context->m_evaledFiles.begin();
           it != g_context->m_evaledFiles.end();
           ++it) {
        auto efile = it->second;
        if (!Eval::BreakPointInfo::MatchFile(fileName, efile->getFileName())) {
          continue;
        }
        addBreakPointInUnit(bp, efile->unit());
        break;
      }
      continue;
    }
    auto exceptionClassName = bp->getExceptionClass();
    if (exceptionClassName == "@") {
      bp->m_bindState = Eval::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 = Eval::BreakPointInfo::KnownToBeValid;
          } else {
            bp->m_bindState = Eval::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 = Eval::BreakPointInfo::KnownToBeValid;
  }
}
Пример #8
0
// Called by the VM when a function definition is loaded.
void phpDebuggerDefFuncHook(const Func* func) {
  Eval::DebuggerProxyPtr proxy = Eval::Debugger::GetProxy();
  if (proxy == nullptr) return;
  addBreakPointFuncEntry(proxy.get(), func);
}
Пример #9
0
// Called by the proxy whenever its breakpoint list is updated.
// Since this intended to be called when user input is received, it is not
// performance critical. Also, in typical scenarios, the list is short.
void phpSetBreakPoints(Eval::DebuggerProxy* proxy) {
  Eval::BreakPointInfoPtrVec bps;
  proxy->getBreakPoints(bps);
  for (unsigned int i = 0; i < bps.size(); i++) {
    Eval::BreakPointInfoPtr bp = bps[i];
    bp->m_bindState = Eval::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 = Eval::BreakPointInfo::KnownToBeInvalid;
      size_t numFuncs = cls->numMethods();
      if (numFuncs == 0) continue;
      auto methodName = bp->getFunction();
      Func* const* funcs = cls->methods();
      for (size_t i = 0; i < numFuncs; ++i) {
        auto f = funcs[i];
        if (!matchFunctionName(methodName, f)) continue;
        bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
        addBreakPointFuncEntry(f);
        break;
      }
      //TODO: what about superclass methods accessed via the derived class?
      //Task 2527229.
      continue;
    }
    auto funcName = bp->getFuncName();
    if (!funcName.empty()) {
      auto fName = makeStaticString(funcName);
      Func* f = Unit::lookupFunc(fName);
      if (f == nullptr) continue;
      if (f->hasGeneratorAsBody() && !f->isAsync()) {
        // This function is a generator, and it's the original
        // function which has been turned into a stub which creates a
        // continuation. We want to set the breakpoint on the
        // continuation function instead.
        fName = makeStaticString(funcName + "$continuation");
        f = Unit::lookupFunc(fName);
        if (f == nullptr) continue;
      }
      bp->m_bindState = Eval::BreakPointInfo::KnownToBeValid;
      addBreakPointFuncEntry(f);
      continue;
    }
    auto fileName = bp->m_file;
    if (!fileName.empty()) {
      for (EvaledFilesMap::const_iterator it =
           g_vmContext->m_evaledFiles.begin();
           it != g_vmContext->m_evaledFiles.end(); ++it) {
        auto efile = it->second;
        if (!Eval::BreakPointInfo::MatchFile(fileName, efile->getFileName())) {
          continue;
        }
        addBreakPointInUnit(bp, efile->unit());
        break;
      }
      continue;
    }
    auto exceptionClassName = bp->getExceptionClass();
    if (exceptionClassName == "@") {
      bp->m_bindState = Eval::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 = Eval::BreakPointInfo::KnownToBeValid;
          } else {
            bp->m_bindState = Eval::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 = Eval::BreakPointInfo::KnownToBeValid;
  }
}