codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / debugger / cmd / cmd_interrupt.cpp
blobf05334ed2a792a20dccfc92cb0240789ed712030
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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/debugger/cmd/cmd_interrupt.h"
18 #include <vector>
20 #include <folly/Conv.h>
22 #include "hphp/runtime/base/array-init.h"
23 #include "hphp/runtime/debugger/debugger_client.h"
24 #include "hphp/runtime/debugger/cmd/cmd_break.h"
25 #include "hphp/runtime/debugger/cmd/cmd_print.h"
27 namespace HPHP { namespace Eval {
28 ///////////////////////////////////////////////////////////////////////////////
30 TRACE_SET_MOD(debugger);
32 void CmdInterrupt::sendImpl(DebuggerThriftBuffer &thrift) {
33 DebuggerCommand::sendImpl(thrift);
34 assert(m_interrupt != ExceptionHandler); // Server-side only.
35 thrift.write(m_interrupt);
36 thrift.write(m_program);
37 thrift.write(m_errorMsg);
38 thrift.write(m_threadId);
39 // Used to be m_pendingJump, but that's been removed. Write false until
40 // we rev the protocol.
41 thrift.write(false);
42 if (m_site) {
43 thrift.write(true);
44 thrift.write(m_site->getFile());
45 thrift.write(m_site->getLine0());
46 thrift.write(m_site->getChar0());
47 thrift.write(m_site->getLine1());
48 thrift.write(m_site->getChar1());
49 thrift.write(m_site->getNamespace());
50 thrift.write(m_site->getClass());
51 thrift.write(m_site->getFunction());
52 Variant e = m_site->getError();
53 if (e.isNull()) {
54 thrift.write("");
55 } else if (e.isObject()) {
56 thrift.write(e.toObject()->getClassName());
57 } else {
58 String ex(BreakPointInfo::ErrorClassName);
59 thrift.write(ex);
61 thrift.write(e.toString());
62 } else {
63 thrift.write(false);
65 BreakPointInfo::SendImpl(0, m_matched, thrift);
68 void CmdInterrupt::recvImpl(DebuggerThriftBuffer &thrift) {
69 DebuggerCommand::recvImpl(thrift);
70 thrift.read(m_interrupt);
71 thrift.read(m_program);
72 thrift.read(m_errorMsg);
73 thrift.read(m_threadId);
74 // Used to be m_pendingJump, but that's been removed. Read a dummy bool until
75 // we rev the protocol.
76 bool dummy;
77 thrift.read(dummy);
78 m_bpi = std::make_shared<BreakPointInfo>();
79 bool site; thrift.read(site);
80 if (site) {
81 thrift.read(m_bpi->m_file);
82 thrift.read(m_bpi->m_line1);
83 thrift.read(m_bpi->m_char1);
84 thrift.read(m_bpi->m_line2);
85 thrift.read(m_bpi->m_char2);
86 auto func = std::make_shared<DFunctionInfo>();
87 thrift.read(func->m_namespace);
88 thrift.read(func->m_class);
89 thrift.read(func->m_function);
90 m_bpi->m_funcs.push_back(func);
91 thrift.read(m_bpi->m_exceptionClass);
92 thrift.read(m_bpi->m_exceptionObject);
94 BreakPointInfo::RecvImpl(0, m_matched, thrift);
97 std::string CmdInterrupt::desc() const {
98 switch (m_interrupt) {
99 case SessionStarted:
100 if (!m_program.empty()) {
101 return m_program + " loaded.";
103 return "Program loaded.";
104 case SessionEnded:
105 if (!m_program.empty()) {
106 return m_program + " exited normally.";
108 return "Program exited normally.";
109 case RequestStarted:
110 if (!m_program.empty()) {
111 return m_program + " started.";
113 return "Web request started.";
114 case RequestEnded:
115 if (!m_program.empty()) {
116 return m_program + " ended.";
118 return "Web request ended.";
119 case PSPEnded:
120 if (!m_program.empty()) {
121 return "Post-Send Processing for " + m_program + " was ended.";
123 return "Post-Send Processing was ended.";
124 case HardBreakPoint:
125 case BreakPointReached:
126 case ExceptionThrown: {
127 assert(m_site);
128 if (m_site) {
129 return m_site->desc();
131 return "Breakpoint reached.";
135 assert(false);
136 return "";
139 void CmdInterrupt::onClient(DebuggerClient &client) {
140 client.setCurrentLocation(m_threadId, m_bpi);
141 if (!client.getDebuggerClientSmallStep()) {
142 // Adjust line and char if it's not small stepping
143 if (m_bpi->m_line1 == m_bpi->m_line2) {
144 m_bpi->m_char1 = 1;
145 m_bpi->m_char2 = 100;
148 client.setMatchedBreakPoints(m_matched);
150 switch (m_interrupt) {
151 case SessionStarted:
152 if (!m_program.empty()) {
153 client.info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.",
154 m_program.c_str());
155 m_bpi->m_file = m_program;
157 break;
158 case SessionEnded:
159 if (!m_program.empty()) {
160 client.info("Program %s exited normally.", m_program.c_str());
162 break;
163 case RequestStarted:
164 if (!m_program.empty()) {
165 client.info("Web request %s started.", m_program.c_str());
167 break;
168 case RequestEnded:
169 if (!m_program.empty()) {
170 client.info("Web request %s ended.", m_program.c_str());
172 break;
173 case PSPEnded:
174 if (!m_program.empty()) {
175 client.info("Post-Send Processing for %s was ended.",
176 m_program.c_str());
178 break;
179 case HardBreakPoint:
180 case BreakPointReached:
181 case ExceptionThrown: {
182 bool found = false;
183 bool toggled = false;
184 auto *bps = client.getBreakPoints();
185 for (unsigned int i = 0; i < m_matched.size(); i++) {
186 BreakPointInfoPtr bpm = m_matched[i];
187 BreakPointInfoPtr bp;
188 int index = 0;
189 for (; index < (int)bps->size(); index++) {
190 if (bpm->same((*bps)[index])) {
191 bp = (*bps)[index];
192 break;
195 if (bp) {
196 found = true;
197 if (bp->m_state == BreakPointInfo::Once) {
198 bp->m_state = BreakPointInfo::Disabled;
199 toggled = true;
201 if (m_interrupt == BreakPointReached ||
202 m_interrupt == HardBreakPoint) {
203 client.info("Breakpoint %d reached %s", bp->index(),
204 m_bpi->site().c_str());
205 client.shortCode(m_bpi);
206 } else {
207 if (m_bpi->m_exceptionClass == BreakPointInfo::ErrorClassName) {
208 client.info("Breakpoint %d reached: An error occurred %s",
209 bp->index(), m_bpi->site().c_str());
210 client.shortCode(m_bpi);
211 client.error("Error Message: %s",
212 m_bpi->m_exceptionObject.c_str());
213 } else {
214 client.info("Breakpoint %d reached: Throwing %s %s",
215 bp->index(),
216 m_bpi->m_exceptionClass.c_str(),
217 m_bpi->site().c_str());
218 client.shortCode(m_bpi);
219 if (client.getLogFileHandler()) {
220 client.output(m_bpi->m_exceptionObject);
224 if (!bpm->m_output.empty()) {
225 client.print(bpm->m_output);
229 if (toggled) {
230 CmdBreak::SendClientBreakpointListToServer(client);
232 if (!found) {
233 if (m_interrupt == HardBreakPoint) {
234 // for HardBreakPoint, default the frame to the caller
235 client.setFrame(1);
237 client.info("Break %s", m_bpi->site().c_str());
238 client.shortCode(m_bpi);
240 break;
244 if (!m_errorMsg.empty()) {
245 client.error(m_errorMsg);
248 // watches
249 switch (m_interrupt) {
250 case SessionStarted:
251 case RequestStarted:
252 break;
253 default: {
254 DebuggerClient::WatchPtrVec &watches = client.getWatches();
255 for (int i = 0; i < (int)watches.size(); i++) {
256 if (i > 0) client.output("%s", "");
257 client.info("Watch %d: %s =", i + 1, watches[i]->second.c_str());
258 Variant v = CmdPrint().processWatch(client, watches[i]->first,
259 watches[i]->second);
260 client.output(CmdPrint::FormatResult(watches[i]->first, v));
266 bool CmdInterrupt::onServer(DebuggerProxy &proxy) {
267 return proxy.sendToClient(this);
270 bool CmdInterrupt::shouldBreak(DebuggerProxy &proxy,
271 const std::vector<BreakPointInfoPtr> &bps,
272 int stackDepth) {
274 switch (m_interrupt) {
275 case SessionStarted:
276 case SessionEnded:
277 case HardBreakPoint:
278 return true; // always break
279 case RequestStarted:
280 case RequestEnded:
281 case PSPEnded:
282 case BreakPointReached:
283 case ExceptionThrown:
284 m_matched.clear();
285 if (m_site) {
286 auto offset = m_site->getCurOffset();
287 for (unsigned int i = 0; i < bps.size(); i++) {
288 if (bps[i]->m_state != BreakPointInfo::Disabled &&
289 bps[i]->breakable(stackDepth, offset) &&
290 bps[i]->cmatch(proxy, getInterruptType(), *m_site)) {
291 BreakPointInfoPtr bp(new BreakPointInfo());
292 *bp = *bps[i]; // make a copy
293 m_matched.push_back(bp);
297 return !m_matched.empty();
298 case ExceptionHandler:
299 return false; // For flow control only at this time.
301 assert(false);
302 return false;
305 std::string CmdInterrupt::getFileLine() const {
306 std::string ret;
307 if (m_site) {
308 if (m_site->getFile()) {
309 ret = m_site->getFile();
311 ret += ":" + folly::to<std::string>(m_site->getLine0());
313 return ret;
316 ///////////////////////////////////////////////////////////////////////////////