2 +----------------------------------------------------------------------+
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"
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.
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();
55 } else if (e
.isObject()) {
56 thrift
.write(e
.toObject()->getClassName());
58 String
ex(BreakPointInfo::ErrorClassName
);
61 thrift
.write(e
.toString());
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.
78 m_bpi
= std::make_shared
<BreakPointInfo
>();
79 bool site
; thrift
.read(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
) {
100 if (!m_program
.empty()) {
101 return m_program
+ " loaded.";
103 return "Program loaded.";
105 if (!m_program
.empty()) {
106 return m_program
+ " exited normally.";
108 return "Program exited normally.";
110 if (!m_program
.empty()) {
111 return m_program
+ " started.";
113 return "Web request started.";
115 if (!m_program
.empty()) {
116 return m_program
+ " ended.";
118 return "Web request ended.";
120 if (!m_program
.empty()) {
121 return "Post-Send Processing for " + m_program
+ " was ended.";
123 return "Post-Send Processing was ended.";
125 case BreakPointReached
:
126 case ExceptionThrown
: {
129 return m_site
->desc();
131 return "Breakpoint reached.";
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
) {
145 m_bpi
->m_char2
= 100;
148 client
.setMatchedBreakPoints(m_matched
);
150 switch (m_interrupt
) {
152 if (!m_program
.empty()) {
153 client
.info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.",
155 m_bpi
->m_file
= m_program
;
159 if (!m_program
.empty()) {
160 client
.info("Program %s exited normally.", m_program
.c_str());
164 if (!m_program
.empty()) {
165 client
.info("Web request %s started.", m_program
.c_str());
169 if (!m_program
.empty()) {
170 client
.info("Web request %s ended.", m_program
.c_str());
174 if (!m_program
.empty()) {
175 client
.info("Post-Send Processing for %s was ended.",
180 case BreakPointReached
:
181 case ExceptionThrown
: {
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
;
189 for (; index
< (int)bps
->size(); index
++) {
190 if (bpm
->same((*bps
)[index
])) {
197 if (bp
->m_state
== BreakPointInfo::Once
) {
198 bp
->m_state
= BreakPointInfo::Disabled
;
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
);
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());
214 client
.info("Breakpoint %d reached: Throwing %s %s",
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
);
230 CmdBreak::SendClientBreakpointListToServer(client
);
233 if (m_interrupt
== HardBreakPoint
) {
234 // for HardBreakPoint, default the frame to the caller
237 client
.info("Break %s", m_bpi
->site().c_str());
238 client
.shortCode(m_bpi
);
244 if (!m_errorMsg
.empty()) {
245 client
.error(m_errorMsg
);
249 switch (m_interrupt
) {
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
,
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
,
274 switch (m_interrupt
) {
278 return true; // always break
282 case BreakPointReached
:
283 case ExceptionThrown
:
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.
305 std::string
CmdInterrupt::getFileLine() const {
308 if (m_site
->getFile()) {
309 ret
= m_site
->getFile();
311 ret
+= ":" + folly::to
<std::string
>(m_site
->getLine0());
316 ///////////////////////////////////////////////////////////////////////////////