New flag and error message for class to memo key conversion
[hiphop-php.git] / hphp / runtime / debugger / debugger_hook_handler.cpp
blob1163bd7759542e35b9788ce83f5677d3c2d59a68
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/debugger/debugger_hook_handler.h"
19 namespace HPHP::Eval {
21 //////////////////////////////////////////////////////////////////////////
23 TRACE_SET_MOD(debuggerflow);
25 // See if the given name matches the function's name.
26 static bool matchFunctionName(std::string name, const Func* f) {
27 return name == f->name()->data();
30 static void addBreakPointInUnit(BreakPointInfoPtr bp, Unit* unit) {
31 OffsetFuncRangeVec offsets;
32 if (!unit->getOffsetRanges(bp->m_line1, offsets) || offsets.size() == 0) {
33 bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
34 return;
36 bp->m_bindState = BreakPointInfo::KnownToBeValid;
37 TRACE(3, "Add to breakpoint filter for %s:%d, unit %p:\n",
38 unit->filepath()->data(), bp->m_line1, unit);
40 assertx(offsets.size() > 0);
41 assertx(offsets[0].second.size() > 0);
42 auto func = offsets[0].first;
43 auto bpOffset = offsets[0].second[0].base;
44 phpAddBreakPoint(func, bpOffset);
47 void proxySetBreakPoints(DebuggerProxy* proxy) {
48 std::vector<BreakPointInfoPtr> bps;
49 proxy->getBreakPoints(bps);
50 for (unsigned int i = 0; i < bps.size(); i++) {
51 BreakPointInfoPtr bp = bps[i];
52 bp->m_bindState = BreakPointInfo::Unknown;
53 auto className = bp->getClass();
54 if (!className.empty()) {
55 auto clsName = makeStaticString(className);
56 auto cls = Class::lookup(clsName);
57 if (cls == nullptr) continue;
58 bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
59 size_t numFuncs = cls->numMethods();
60 if (numFuncs == 0) continue;
61 auto methodName = bp->getFunction();
62 for (size_t i2 = 0; i2 < numFuncs; ++i2) {
63 auto f = cls->getMethod(i2);
64 if (!matchFunctionName(methodName, f)) continue;
65 bp->m_bindState = BreakPointInfo::KnownToBeValid;
66 phpAddBreakPointFuncEntry(f);
67 break;
69 continue;
71 auto funcName = bp->getFuncName();
72 if (!funcName.empty()) {
73 auto fName = makeStaticString(funcName);
74 Func* f = Func::lookup(fName);
75 if (f == nullptr) continue;
76 bp->m_bindState = BreakPointInfo::KnownToBeValid;
77 phpAddBreakPointFuncEntry(f);
78 continue;
80 auto fileName = bp->m_file;
81 if (!fileName.empty()) {
82 for (auto& kv : g_context->m_evaledFiles) {
83 auto const unit = kv.second.unit;
84 if (!BreakPointInfo::MatchFile(fileName,
85 unit->filepath()->toCppString())) {
86 continue;
88 addBreakPointInUnit(bp, unit);
89 break;
91 continue;
93 auto exceptionClassName = bp->getExceptionClass();
94 if (exceptionClassName == "@") {
95 bp->m_bindState = BreakPointInfo::KnownToBeValid;
96 continue;
97 } else if (!exceptionClassName.empty()) {
98 auto expClsName = makeStaticString(exceptionClassName);
99 auto cls = Class::lookup(expClsName);
100 if (cls != nullptr) {
101 static auto baseClsName = makeStaticString("Exception");
102 auto baseCls = Class::lookup(baseClsName);
103 if (baseCls != nullptr) {
104 if (cls->classof(baseCls)) {
105 bp->m_bindState = BreakPointInfo::KnownToBeValid;
106 } else {
107 bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
111 continue;
112 } else {
113 continue;
115 // If we get here, the break point is of a type that does
116 // not need to be explicitly enabled in the VM. For example
117 // a break point that get's triggered when the server starts
118 // to process a page request.
119 bp->m_bindState = BreakPointInfo::KnownToBeValid;
123 DebuggerHook* HphpdHook::GetInstance() {
124 static DebuggerHook* instance = new HphpdHook();
125 return instance;
128 void HphpdHook::onFileLoad(Unit* unit) {
129 DebuggerProxy* proxy = Debugger::GetProxy().get();
130 if (proxy == nullptr) return;
132 // Look up the proxy's breakpoints and add needed breakpoints to the passed
133 // unit
134 std::vector<BreakPointInfoPtr> bps;
135 proxy->getBreakPoints(bps);
136 for (unsigned int i = 0; i < bps.size(); i++) {
137 BreakPointInfoPtr bp = bps[i];
138 if (BreakPointInfo::MatchFile(bp->m_file,
139 unit->filepath()->toCppString())) {
140 addBreakPointInUnit(bp, unit);
145 void HphpdHook::onDefClass(const Class* cls) {
146 // Make sure we have a proxy
147 DebuggerProxy* proxy = Debugger::GetProxy().get();
148 if (proxy == nullptr) return;
150 // If the proxy has enabled breakpoints that match entry into methods of
151 // the given class, arrange for the VM to stop execution and notify the
152 // debugger whenever execution enters one of these matched method.
153 // This function is called once, when a class is first loaded, so it is not
154 // performance critical.
155 size_t numFuncs = cls->numMethods();
156 if (numFuncs == 0) return;
157 auto clsName = cls->name();
158 std::vector<BreakPointInfoPtr> bps;
159 proxy->getBreakPoints(bps);
160 for (unsigned int i = 0; i < bps.size(); i++) {
161 BreakPointInfoPtr bp = bps[i];
162 if (bp->m_state == BreakPointInfo::Disabled) continue;
163 // TODO: check name space separately
164 if (bp->getClass() != clsName->data()) continue;
165 bp->m_bindState = BreakPointInfo::KnownToBeInvalid;
166 for (size_t i2 = 0; i2 < numFuncs; ++i2) {
167 auto f = cls->getMethod(i2);
168 if (!matchFunctionName(bp->getFunction(), f)) continue;
169 bp->m_bindState = BreakPointInfo::KnownToBeValid;
170 phpAddBreakPointFuncEntry(f);
175 void HphpdHook::onDefFunc(const Func* f) {
176 // Make sure we have a proxy
177 DebuggerProxyPtr proxy = Debugger::GetProxy();
178 if (proxy == nullptr) return;
180 // If the proxy has an enabled breakpoint that matches entry into the given
181 // function, arrange for the VM to stop execution and notify the debugger
182 // whenever execution enters the given function.
183 std::vector<BreakPointInfoPtr> bps;
184 proxy->getBreakPoints(bps);
185 for (unsigned int i = 0; i < bps.size(); i++) {
186 BreakPointInfoPtr bp = bps[i];
187 if (bp->m_state == BreakPointInfo::Disabled) continue;
188 if (!matchFunctionName(bp->getFuncName(), f)) continue;
189 bp->m_bindState = BreakPointInfo::KnownToBeValid;
190 phpAddBreakPointFuncEntry(f);
191 return;
195 //////////////////////////////////////////////////////////////////////////