2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- 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/eval/debugger/cmd/cmd_interrupt.h"
18 #include "hphp/runtime/eval/debugger/cmd/cmd_break.h"
19 #include "hphp/runtime/eval/debugger/cmd/cmd_print.h"
21 namespace HPHP
{ namespace Eval
{
22 ///////////////////////////////////////////////////////////////////////////////
24 TRACE_SET_MOD(debugger
);
26 void CmdInterrupt::sendImpl(DebuggerThriftBuffer
&thrift
) {
27 DebuggerCommand::sendImpl(thrift
);
28 thrift
.write(m_interrupt
);
29 thrift
.write(m_program
);
30 thrift
.write(m_errorMsg
);
31 thrift
.write(m_threadId
);
32 // Used to be m_pendingJump, but that's been removed. Write false until
33 // we rev the protocol.
37 thrift
.write(m_site
->getFile());
38 thrift
.write(m_site
->getLine0());
39 thrift
.write(m_site
->getChar0());
40 thrift
.write(m_site
->getLine1());
41 thrift
.write(m_site
->getChar1());
42 thrift
.write(m_site
->getNamespace());
43 thrift
.write(m_site
->getClass());
44 thrift
.write(m_site
->getFunction());
45 Variant e
= m_site
->getException();
48 } else if (e
.isObject()) {
49 thrift
.write(e
.toObject()->o_getClassName());
51 String
ex(BreakPointInfo::ErrorClassName
);
54 thrift
.write(e
.toString());
58 BreakPointInfo::SendImpl(m_matched
, thrift
);
61 void CmdInterrupt::recvImpl(DebuggerThriftBuffer
&thrift
) {
62 DebuggerCommand::recvImpl(thrift
);
63 thrift
.read(m_interrupt
);
64 thrift
.read(m_program
);
65 thrift
.read(m_errorMsg
);
66 thrift
.read(m_threadId
);
67 // Used to be m_pendingJump, but that's been removed. Read a dummy bool until
68 // we rev the protocol.
71 m_bpi
= BreakPointInfoPtr(new BreakPointInfo());
72 bool site
; thrift
.read(site
);
74 thrift
.read(m_bpi
->m_file
);
75 thrift
.read(m_bpi
->m_line1
);
76 thrift
.read(m_bpi
->m_char1
);
77 thrift
.read(m_bpi
->m_line2
);
78 thrift
.read(m_bpi
->m_char2
);
79 DFunctionInfoPtr
func(new DFunctionInfo());
80 thrift
.read(func
->m_namespace
);
81 thrift
.read(func
->m_class
);
82 thrift
.read(func
->m_function
);
83 m_bpi
->m_funcs
.push_back(func
);
84 thrift
.read(m_bpi
->m_exceptionClass
);
85 thrift
.read(m_bpi
->m_exceptionObject
);
87 BreakPointInfo::RecvImpl(m_matched
, thrift
);
90 std::string
CmdInterrupt::desc() const {
91 switch (m_interrupt
) {
93 if (!m_program
.empty()) {
94 return m_program
+ " loaded.";
96 return "Program loaded.";
98 if (!m_program
.empty()) {
99 return m_program
+ " exited normally.";
101 return "Program exited normally.";
103 if (!m_program
.empty()) {
104 return m_program
+ " started.";
106 return "Web request started.";
108 if (!m_program
.empty()) {
109 return m_program
+ " ended.";
111 return "Web request ended.";
113 if (!m_program
.empty()) {
114 return "Post-Send Processing for " + m_program
+ " was ended.";
116 return "Post-Send Processing was ended.";
118 case BreakPointReached
:
119 case ExceptionThrown
: {
122 return m_site
->desc();
124 return "Breakpoint reached.";
132 bool CmdInterrupt::onClient(DebuggerClient
*client
) {
133 client
->setCurrentLocation(m_threadId
, m_bpi
);
134 if (!client
->getDebuggerSmallStep()) {
135 // Adjust line and char if it's not small stepping
136 if (m_bpi
->m_line1
== m_bpi
->m_line2
) {
138 m_bpi
->m_char2
= 100;
141 client
->setMatchedBreakPoints(m_matched
);
143 switch (m_interrupt
) {
145 if (!m_program
.empty()) {
146 client
->info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.",
148 m_bpi
->m_file
= m_program
;
152 if (!m_program
.empty()) {
153 client
->info("Program %s exited normally.", m_program
.c_str());
157 if (!m_program
.empty()) {
158 client
->info("Web request %s started.", m_program
.c_str());
162 if (!m_program
.empty()) {
163 client
->info("Web request %s ended.", m_program
.c_str());
167 if (!m_program
.empty()) {
168 client
->info("Post-Send Processing for %s was ended.",
173 case BreakPointReached
:
174 case ExceptionThrown
: {
176 bool toggled
= false;
177 BreakPointInfoPtrVec
*bps
= client
->getBreakPoints();
178 for (unsigned int i
= 0; i
< m_matched
.size(); i
++) {
179 BreakPointInfoPtr bpm
= m_matched
[i
];
180 BreakPointInfoPtr bp
;
182 for (; index
< (int)bps
->size(); index
++) {
183 if (bpm
->same((*bps
)[index
])) {
190 if (bp
->m_state
== BreakPointInfo::Once
) {
191 bp
->m_state
= BreakPointInfo::Disabled
;
194 if (m_interrupt
== BreakPointReached
||
195 m_interrupt
== HardBreakPoint
) {
196 client
->info("Breakpoint %d reached %s", bp
->index(),
197 m_bpi
->site().c_str());
198 client
->shortCode(m_bpi
);
200 if (m_bpi
->m_exceptionClass
== BreakPointInfo::ErrorClassName
) {
201 client
->info("Breakpoint %d reached: An error occurred %s",
202 bp
->index(), m_bpi
->site().c_str());
203 client
->shortCode(m_bpi
);
204 client
->error("Error Message: %s",
205 m_bpi
->m_exceptionObject
.c_str());
207 client
->info("Breakpoint %d reached: Throwing %s %s",
209 m_bpi
->m_exceptionClass
.c_str(),
210 m_bpi
->site().c_str());
211 client
->shortCode(m_bpi
);
212 client
->output(m_bpi
->m_exceptionObject
);
215 if (!bpm
->m_output
.empty()) {
216 client
->print(bpm
->m_output
);
221 CmdBreak::SendClientBreakpointListToServer(client
);
224 if (m_interrupt
== HardBreakPoint
) {
225 // for HardBreakPoint, default the frame to the caller
228 client
->info("Break %s", m_bpi
->site().c_str());
229 client
->shortCode(m_bpi
);
235 if (!m_errorMsg
.empty()) {
236 client
->error(m_errorMsg
);
240 switch (m_interrupt
) {
245 DebuggerClient::WatchPtrVec
&watches
= client
->getWatches();
246 for (int i
= 0; i
< (int)watches
.size(); i
++) {
247 if (i
> 0) client
->output("");
248 client
->info("Watch %d: %s =", i
+ 1, watches
[i
]->second
.c_str());
249 Variant v
= CmdPrint().processWatch(client
, watches
[i
]->first
,
251 client
->output(CmdPrint::FormatResult(watches
[i
]->first
, v
));
259 static const StaticString
s_format("format");
260 static const StaticString
s_php("php");
261 static const StaticString
s_value("value");
263 void CmdInterrupt::setClientOutput(DebuggerClient
*client
) {
264 client
->setOutputType(DebuggerClient::OTCodeLoc
);
265 client
->setOTFileLine(m_bpi
->m_file
, m_bpi
->m_line1
);
267 DebuggerClient::WatchPtrVec
&watches
= client
->getWatches();
268 for (int i
= 0; i
< (int)watches
.size(); i
++) {
270 watch
.set(s_format
, watches
[i
]->first
);
271 watch
.set(s_php
, watches
[i
]->second
);
272 Variant v
= CmdPrint().processWatch(client
, watches
[i
]->first
,
274 watch
.set(s_value
, CmdPrint::FormatResult(watches
[i
]->first
, v
));
275 values
.append(watch
.create());
277 client
->setOTValues(values
);
280 bool CmdInterrupt::onServer(DebuggerProxy
*proxy
) {
281 return proxy
->sendToClient(this);
284 bool CmdInterrupt::shouldBreak(const BreakPointInfoPtrVec
&bps
) {
286 switch (m_interrupt
) {
290 return true; // always break
294 case BreakPointReached
:
295 case ExceptionThrown
:
298 for (unsigned int i
= 0; i
< bps
.size(); i
++) {
299 if (bps
[i
]->m_state
!= BreakPointInfo::Disabled
&&
300 bps
[i
]->match(getInterruptType(), *getSite())) {
301 BreakPointInfoPtr
bp(new BreakPointInfo());
302 *bp
= *bps
[i
]; // make a copy
303 m_matched
.push_back(bp
);
307 return !m_matched
.empty();
313 std::string
CmdInterrupt::getFileLine() const {
316 if (m_site
->getFile()) {
317 ret
= m_site
->getFile();
319 ret
+= ":" + lexical_cast
<string
>(m_site
->getLine0());
324 ///////////////////////////////////////////////////////////////////////////////