Fix catch trace bug and inline cost bug
[hiphop-php.git] / hphp / doc / debugger.devdocs
blobc001af7629b25ffcc324709ceb2bd8eeac738849
1 This document is intended to help developers understand how HHVM
2 debugging is implemented. For user documentation, see
3 docs/debugger.start.
5 1. Overview
6 -----------
8 HHVM provides a rich set of debugging services as well as a
9 command-line debugger client. The client and server (VM) can be on the
10 same or different machines. The client and server may also be in the
11 same process when debugging a script instead of a web server.
13 For simplicity, much of this document will assume the client and
14 server are in different processes. The operation of the various
15 components below is mostly unchanged when they are in the same
16 process, though.
18 A HHVM server can be configured to allow remote debugging with option
19 Eval.Debugger.EnableDebuggerServer. This creates a new debug-only
20 endpoint to which debugger clients may connect on the port specified
21 by Eval.Debugger.DebuggerServerPort (default 8089). The class
22 DebuggerServer is responsible for setting up and listening for
23 connections on this endpoint.
26 1.1 The Proxy
27 -------------
29 When a debugger client connects to a VM, whether that VM is a remote
30 server or a local instance running a script, a "debugger proxy" is
31 created by the server. This proxy owns a connection, via a socket
32 wrapped within a Thrift buffer, to the client which is doing the
33 debugging. All interaction with the client is performed through this
34 proxy, and any time the VM does something the debugger might need to
35 know about it informs the proxy. The proxy is implemented in the
36 DebuggerProxy class.
38 The proxy has two important states: interrupted, or not
39 interrupted. When a proxy is interrupted it listens for commands from
40 the client and responds to them. When it is not interrupted, the proxy
41 does nothing and simply sits around waiting to be interrupted. A proxy
42 gets interrupted in one of two ways: interesting events from the VM,
43 or by a dedicated signal polling thread in response to a signal from
44 the client.
46 The proxy will listen for commands from the client, and create
47 instances of subclasses of DebuggerCommand to execute those
48 commands. A command may respond to the client with results, or it may
49 cause the proxy to allow the interrupted thread to run again.
52 1.2 The Client
53 --------------
55 Anyone can build a client so long as they speak the protocol described
56 below. HHVM provides a command line client, usually called
57 "hphpd". The client is invoked by passing "--mode debug" on the
58 command line. This causes HHVM to create a DebuggerClient object,
59 which creates a new thread which will run the command processing
60 loop. The client may attach to a server, or it may attach to the VM in
61 its own process and debug a script running on the main thread. If
62 there is no script to run, the main thread simply waits for the client
63 to finish.
65 Somewhat confusingly, the client also creates a proxy to represent the
66 VM in its own process. Thus, the proxy is not only a server-side
67 object. This proxy works just like the proxy on a server, and is
68 connected to in the same way. This proxy is created even if the client
69 is connecting to a server, though in that case it will not really be
70 used. If the user disconnects from their server this proxy will be
71 used to debug local scripts.
74 2.0 Communication Protocol
75 --------------------------
77 The communication protocol between the client and server is fairly
78 simple. It is based on Thrift, and the bulk of the implementation is
79 held in DebuggerCommand and its subclasses. All communication is based
80 on sending a Command, and in most cases receiving a response of the
81 same Command back, someitmes updated with more information. User
82 actions like print, where, and breakpoint translate into CmdPrint,
83 CmdWhere, and CmdBreak being sent to the server, and received back
84 with data like the result of the print or where operation, or status
85 about the breakpoints being set. Some commands cause the server to
86 resume execution of the program. User actions like continue, next, and
87 step translate into CmdContinue, CmdNext, and CmdStep being sent to
88 the server, which does not respond immediately but continues execution
89 until the program reaches, say, a breakpoint. The server then responds
90 with CmdInterrupt(BreakPointReached) to signal that it is now in the
91 "interrupted state" and is ready to receive more commands.
94 2.1 Initialization
95 ------------------
97 When a new connection is made to the debugger port a proxy is created
98 to own that connection. This proxy is held in a global map keyed by a
99 sandbox ID. The proxy starts a "dummy sandbox" so it can accept
100 commands when there is no active request, and it starts up a signal
101 thread to poll the client for "signals", i.e., Ctrl-C. The dummy
102 sandbox is always started, and should not be confused with a real
103 sandbox. It will never serve a request and is really just there to
104 provide a place to execute code and interact with the server when
105 there are no requests.
107 The proxy is now ready to use, and is not interrupted. The client,
108 after establishing the connection on the debugger port now waits for a
109 command from the proxy. Note that the proxy really doesn't have it's
110 own thread. From now on, it runs on whatever thread interrupts
111 it. That may be the dummy sandbox thread, or it may be a normal
112 request thread.
114 So long as the proxy is not interrupted, the signal thread will poll
115 the client once per second with CmdSignal. The client responds with
116 CmdSignal, updated with whether or not Ctrl-C was pressed. If it was,
117 the signal thread asks each thread registered with the proxy to
118 interrupt, then goes back to polling. If the proxy remains
119 un-interrupted on the next poll, the signal thread will ask the dummy
120 sandbox thread to interrupt.
122 The dummy sandbox creates a thread which first interrupts the proxy
123 with "session started", and then waits to see if it needs to respond
124 to a signal from the client. If there is a signal from the client, the
125 dummy sandbox thread simply loops and interrupts the proxy with
126 "session started" again, and waits again.
128 The proxy, having been interrupted with "session started" from the
129 dummy sandbox, sends a CmdInterrupt(SessionStarted) to the client. The
130 proxy is now interrupted, so it enters a loop listening for commands
131 from the client. It also blocks the signal thread from sending
132 CmdSignal to the client. The proxy will remain interrupted, processing
133 commands requested by the client, until one of those commands causes
134 the proxy to leave the interrupted state and let the thread which
135 interrupted it continue. In the case of SessionStarted, that lets the
136 dummy sandbox thread continue. In the case of more interesting
137 interrupts from the VM, on threads executing requests or other user
138 code, it lets those threads run.
140 When the client receives the SessionStarted interrupt after making the
141 initial connection, it sends CmdMachine to attach to the user's
142 sandbox. The proxy "attaches" to the sandbox by registering itself as
143 the proxy for that sandbox id in the global proxy map. It then signals
144 the dummy sandbox thread, responds with CmdMachine, and returns to the
145 un-interrupted state. The client again waits for a command from the
146 proxy. The dummy sandbox receives the signal, loops, and interrupts
147 the proxy again with "session started", which sends a second
148 CmdInterrupt with type SessionStarted to the client. At this point the
149 client has received CmdInterrupt(SessionStarted) and the proxy is
150 interrupted in the dummy sandbox. The initial connection is complete,
151 and the client can issue whatever commands it wishes.
153 Graphically, the initial connection protocol is:
155 Server threads:
156 DL  -- Debugger Server Listening Thread
157 SP  -- Signal Polling Thread
158 DS  -- Dummy Sandbox Thread
159 RTx -- Request Threads
161    Client                           Server
162 -------------   --------------------------------------------------
163                     DL            SP            DS           RTx
165    |            Listen for
166    |            connections
167    |                |
168 Connect on  ------> |
169 debugger port     Create Proxy
170    |              Create SP ----> |
171    |              Create DS ------------------> |
172    |                |             |             |
173    |                |             |             |
174    | <----------------------- CmdSignal         |
175 CmdSignal ----------------------> |             |
176    |                |             |             |
177    | <------------------------------------ CmdInterrupt(SS)
178 CmdMachine(attach) ---------------------------> |
179    |                |             |        Switch sandbox
180    |                |             |        Notify DS
181    | <------------------------------------ CmdMachine
182    |                |             |        Loop due to notify
183    | <------------------------------------ CmdInterrupt(SS)
184 Ready to go         |             |             |
185    |                |             |             |
186    v                v             v             v
189 2.2 Steady State
190 ----------------
192 Once the client and server are connected, the most common flow is that
193 the client waits for a CmdInterrupt from the proxy while the
194 application runs. When a request thread hits a breakpoint, throws an
195 exception, etc. it will interrupt the proxy. The proxy may decide to
196 ignore the interrupt (perhaps it is not configured to care about
197 thrown exceptions, for instance), in which case the request thread
198 will keep running and the client will never know about the event. If
199 the proxy does decide to take the interrupt it will send CmdInterrupt
200 to the client, then wait for commands from the client. The client will
201 send commands and get responses from the proxy until it sends a
202 command that causes the proxy to let the interrupted thread continue
203 execution.
205 Signal polling continues so long as the proxy is not interrupted.
207    Client                           Server
208 -------------   --------------------------------------------------
209                     DL            SP            DS           RTx
211 Listen for          |             |             |            |
212 commands            |             |             |       IP is at a
213    |                |             |             |       breakpoint.
214    | <----------------------------------------------- CmdInterrupt(BPR)
215 CmdWhere --------------------------------------------------> |
216    | <-------------------------------------------------- CmdWhere
217    |                |             |             |            |
218 CmdPrint --------------------------------------------------> |
219    | <-------------------------------------------------- CmdPrint
220    |                |             |             |            |
221 CmdContinue -----------------------------------------------> |
222    |                |             |             |       Continue request
223    | <----------------------- CmdSignal         |            |
224 CmdSignal ----------------------> |             |            |
225    |                |             |             |            |
226    v                v             v             v            v
229 2.3 Ctrl-C
230 ----------
232 When the client wants to interrupt the server while it is executing
233 code, it responds to CmdSignal with a flag indicating it wants to
234 stop. In the command line client, pressing Ctrl-C will cause the next
235 response to CmdSignal to set the flag. The proxy's signal polling
236 thread will then ask all current request threads to interrupt. When
237 one does, it will send a CmdInterrupt to the client.
239    Client                           Server
240 -------------   --------------------------------------------------
241                     DL            SP            DS           RTx
243    | <----------------------- CmdSignal         |            |
244 CmdSignal(stop) ----------------> |             |            |
245    |                |      Set flag on each     |            |
246    |                |      RTx thread to cause  |            |
247    |                |      it to interrupt      |            |
248    |                |             |             |    Interupt flag seen.
249    | <----------------------------------------------- CmdInterrupt(BPR)
250    |                |             |             |            |
251    v                v             v             v            v
254 2.4 Quitting
255 ------------
257 CmdQuit is just like any other command, except that after the proxy
258 responds it will remove itself from the global proxy map, close the
259 connection, turn off the signal polling and dummy sandbox threads, and
260 destroy itself. The same actions will occur if the connection with the
261 client is lost for any other reason, even if no CmdQuit was
262 received. An error reading from the socket, a closed socket, etc.
264 2.4.1 Cleaning the proxy
265 ------------------------
267 There are many cases where the proxy will notice that a client has
268 terminated the connection. The easiest one is when a quit command is
269 received, but the client may exit for any number of reasons, and in
270 any state. At a minimum, the proxy's signal polling thread will, after
271 one second, notice that the connection has been dropped and initiate
272 cleanup. However, neither the signal polling thread nor the dummy
273 sandbox thread can completely perform the cleanup because they are
274 owned by the proxy, and destroying the proxy would destroy those
275 threads before they have completed.
277 Thus, proxy cleanup may be initiated by any thread with Proxy::stop(),
278 but the final cleanup is performed by another thread doing
279 housekeeping work. The cleanup work waits for both the signal polling
280 and dummy sandbox threads to exit before completing. Server-side this
281 housekeeping work is done by the server thread, which is also
282 listening for new debugger connections. Note that this cleanup work
283 may complete while a request thread is still using the proxy. The last
284 reference to the proxy will finally destroy it, and the cleanup work
285 ensures that the proxy is still usable (and communicates that it is
286 stopped) by any outstanding request threads.
290 3.0 Client Implementation
291 -------------------------
293 The debugger client provided by HHVM is not a separate program, but a
294 special mode passed when executing HHVM. When "--mode debug" is
295 passed, a DebuggerClient object is created and a new thread is started
296 to execute DebuggerClient::run(). This "client thread" will execute
297 the main loop of the client, presenting a command prompt at times, and
298 running a communication loop with the server at other times.
300 A "local proxy" is also created, which is a normal DebuggerProxy for
301 the VM within the process. The client connects to this proxy normally,
302 with a socket and a thrift buffer. The proxy will create a signal
303 polling thread as usual, but it will not setup a dummy sandbox. The
304 lack of a dummy sandbox is really the only difference between a normal
305 proxy and this local proxy.
307 The main thread of the process will run a script specified on the
308 command line, just like HHVM normally would. The client will, by
309 default, attempt to debug that script. The main thread's execution is
310 slightly modified to allow the client to restart the script in
311 response to the 'run' command, and to give control back to the client
312 when the script is complete instead of exiting the process.
314 If the client is asked to connect to a remote server (either via "-h"
315 on the command line or via the 'machine connect' command) then it does
316 so as described above, and the main thread of the process will simply
317 idle and wait for the client to exit, at which time the process will
318 exit.
320 3.1 Console and communication loops
321 -----------------------------------
323 The debugger client has a top-level "event loop" which waits to
324 receive commands from the proxy to which it is attached. It responds
325 to CmdSignal, and when it receives a CmdInterrupt it enters a "console
326 loop" which presents a prompt to the user and processes user
327 commands. Each user command is recgonized and an instance of a
328 subclass of DebuggerCommand is created, then executed.
330 The client will remain in the top-level event loop until an interrupt
331 is received, and it will remain in the console loop until a command
332 causes execution on the server to continue. When such a command is
333 executed (e.g. 'continue'), it sends the request to the server and
334 then throws DebuggerConsoleExitException. This is the notification to
335 exit the console loop and return to the event loop. The use of an
336 exception for this is a bit odd, as it is typically simply the last
337 thing done from the commands's onClientImpl() method, which is called
338 directly from the console loop. The use of an exception here is
339 similar to the use of DebuggerClientExitException, discussed below,
340 but is now a vestige that will likely be removed soon.
342 Some commands can cause the client to exit, like 'quit'. The client
343 may also exit due to various error conditions, like loss of
344 communication with the server. In these cases a
345 DebuggerClientExitException is thrown. This causes execution to unwind
346 out of both the console and event loops, back to
347 DebuggerClient::run(), which eventually causes the client to exit. The
348 use of an exception here is more interesting as we will see below when
349 discussing nested event loops, as it allows the client to exit out of
350 multiple nested event loops with ease.
352 Somewhat confusingly, DebuggerClientExitException is also thrown by
353 the proxy when it detects the client is exiting. This signals the
354 termination of the request which was being debugged, which is
355 reasonable. But you'd imagine that a different exception could serve
356 that purpose. This is a subtle cheat in the system, and is more
357 meaningful when the proxy is local: it is a signal back to the
358 modified main thread that the debugger is quitting and the main thread
359 should now quit. In the local case, the main thread is much like a web
360 server request thread in that it calls into the proxy to interrupt it.
363 4.0 Nested execution
364 --------------------
366 Some commands allow a user to recursively execute more PHP code while
367 stopped at, say, a breakpoint. More breakpoints may be hit in the
368 newly executed function, and more code may be executed while stopped
369 at those breakpoints. The best example of this is CmdEval, which is
370 used to evaluate arbitrary functions and code (e.g., '@foo(42)').
372 Both the client and proxy are designed to handle this.
374 On the proxy, execution is paused waiting for a command from the
375 client. When an eval command is received, the proxy is put back into
376 the running state and the code is executed directly from the command
377 processing loop. If another interrupt is encountered, a new command
378 processing loop is entered and the interrupt is communicated to the
379 client just like normal. When then code completes, the response to the
380 eval command is sent and control is returned to the command processing
381 loop still on the stack. Thus we may recurse arbitrarily deep on the
382 server down multiple levels of proxy command loops, depending on how
383 deeply the user wishes to go. In practice this depth is quite shallow,
384 and most often involves no recursion.
386 On the client the story is much the same. When an eval command is
387 entered by the user, the client sends CmdEval to the proxy then enters
388 a nested event loop to wait for either the eval command to be sent
389 back, indication completion of the command, or for new CmdInterrupts
390 to be received, indicating breakpoints and other interesting events
391 while the code was being executed. Interrupts are handled normally,
392 and a new console loop is entered. Again, like the proxy these loops
393 may nest to arbitrary depths.
396 5.0 Control Flow
397 ----------------
399 This section will discuss how the control flow commands 'next',
400 'step', 'out', and 'continue' work in the proxy and the VM. Operation
401 of these commands on the client isn't very interesting and is covered
402 well enough elsewhere.
404 Flow control commands are treated specially by the proxy. A single
405 instance of a subclass of CmdFlowControl is held in the m_flow member
406 variable of DebuggerProxy so long as it remains active, and having an
407 active flow command typically means that the proxy will deliver all
408 interrupts to the flow command for processing first. The flow command
409 will have the opportunity to examine the interrupt and determine if
410 the proxy should really stop at the interrupt, or continue
411 execution. A flow command will mark itself as completed when it
412 decides it's time to stop execution, and the proxy will remove it.
414 The only thing that can get the proxy to stop at an interrupt when a
415 flow command has said not to is an active breakpoint.
417 When the proxy does finally have an interrupt to stop at and send to
418 the client it removes and deletes the flow command. The flow command
419 is either complete, in which case it doesn't need to remain active
420 anyway, or it has been trumped by a breakpoint, in which case the flow
421 command is essentially forced to be complete.
423 A flow command is set as active on the proxy when it is received from
424 the client. Execution continues at that time.
427 5.1 Continue
428 ------------
430 'continue' is the simplest control flow command. It simply marks
431 itself completed and returns. The proxy will remove the CmdContinue
432 and continue execution.
435 5.2 Step
436 --------
438 'step' is the next simplest flow command. It operates on the very
439 simple theory that to step to the next line executed you simply need
440 to interpret the program until the current source location
441 changes. This is, by definition, the next source line to be executed
442 no matter how execution flows in the program: function call,
443 exception, a simple add, etc.
445 First, CmdStep sets a "VM interrupt" flag which is eventually
446 installed on the VM's execution context for the current thread. The
447 interpreter's execution loop is instrumented, only when a debugger
448 client is actually attached to the VM, with a "hook" to the debugger
449 infrastructure called phpDebuggerOpcodeHook(). This hook is given the
450 PC of the opcode which is about to be executed. Setting the VM
451 interrupt flag ensures the VM will only interpret code, and thus call
452 the debugger opcode hook. This flag remains set only while the step
453 command is active; the VM will go back to executing translated code
454 once the command completes.
456 Next, CmdStep sets up a "location filter" for the current source
457 line. This is a very simple set which contains all PC's for bytecodes
458 implementing the current source line.  It first consults the location
459 filter to determine if this is a location which might be interesting
460 to a debugger. If it gets a hit in the location filter, it simply
461 returns to the interpreter and executes the opcode as usual. The
462 location filter, then, is a simple mechanism which flow commands can
463 use to avoid being interrupted when a set of bytecodes is executed.
465 By setting up a location filter for the current source line and
466 turning on interrupts the step command ensures it will be interrupted
467 as soon as a bytecode not belonging to the current source line is
468 encountered. When that occurs it marks itself completed, and the proxy
469 will remove the CmdStep and destroy it. When any flow command is
470 destroyed the location filter is cleared, and the VM interrupt flag is
471 turned off.
474 5.3 Out
475 -------
477 'out' works very differently from 'step'. It predicts the next
478 execution location and sets up an "internal breakpoint" at that
479 location. This internal breakpoint works just like a normal breakpoint
480 set by a user, but it is not visible to the user. The breakpoint will
481 be automatically removed when CmdOut is destroyed. CmdOut sets this
482 breakpoint, then continues execution like normal (no location filter,
483 no VM interrupt flag).
485 The breakpoint is placed at the return address of the current
486 function. When it is reached, there are two possibilities: we have
487 returned from the function in question, in which case the command is
488 marked as complete, or we have hit the breakpoint during a recursive
489 call before exiting the original function.
491 To determine which case it is, CmdOut remembers the original stack
492 depth when the command was activated, and checks it when the
493 breakpoint is hit. If the stack depth is the same or lower, execution
494 is continued. Otherwise, the command is complete.
497 5.3.1 Determining the location to step out to
498 ---------------------------------------------
500 Finding the location a function will return to is not straightforward
501 in all cases. For a function called from FCALL, the location is
502 obvious and unambiguous. But for functions called from, say, ITERNEXT
503 or a destructor called from a simple SETL the return offset stored in
504 the VM's activation record is not what we would expect. A complex
505 instruction may have multiple points at which execution could
506 continue. ITERNEXT, for instance, will branch to the top of the loop
507 if the iterator is not done, or fall thru if the iterator is
508 done. Thus the step out location could be multiple places.
510 Also, functions with no source information are ignored for a step out
511 operation, so the location could be multiple frames up, not just one.
513 All of this is accounted for in CmdFlowControl::setupStepOuts(). See
514 that function for the details.
517 5.4 Next
518 --------
520 'next' is the most complex of the flow control commands, and builds on
521 the primitives of the others. It starts just like 'step' by trying to
522 use the interpreter to get off the current source line. But the goal
523 is not to just get off the line, it is to get to the next line. If
524 execution ends up deeper on the stack, a call has been made. CmdNext
525 will re-use the step out facility needed for 'out' and, in essence,
526 internally execute a step out to get back to the original source line,
527 then continue try to interpret off of it. If execution ends up
528 shallower on the stack, then we have stepped over a return and are
529 done as well.
531 There is extra logic to support stepping within continuations, so that
532 a 'next' executed on a source line with a 'yield' on it will step over
533 the yield. Thus CmdNext looks at the opcodes it is stepping over, and
534 upon recognizing CONTEXIT or CONTRETC will setup its own internal
535 breakpoints at destinations indicated by those opcodes.
537 For the details, see CmdNext.
540 5.5 Exceptions
541 --------------
543 Exceptions are non-local control flow that throw a monkey wrench into
544 most flow control commands. The VM is further instrumented, again only
545 while a debugger is attached, to call a hook whenever it is about to
546 transfer control to a catch block. This gives all of the flow commands
547 a chance to determine if the new location satisfies the completion
548 criteria for their respective operations. In most cases, the flow
549 command will force the first opcode of the catch clause to be
550 interpreted and let it's normal logic run its course.
552 6. Breakpoints
553 --------------
555 Breakpoints are set via commands processed by the client, which keeps a list
556 of all breakpoints. This list is sent to the proxy whenever an element is added,
557 modified or deleted. The proxy keeps of a copy of the list and updates each
558 breakpoint with a flag that indicates if the breakpoint is bound. An unbound
559 breakpoint is either invalid because it refers to a non existent source line
560 or function, or it refers to a location that has not yet been loaded into the
561 VM. The flag distinguishes these cases.
563 6.1 Checking if breakpoints are hit.
565 When a breakpoint becomes bound, it is mapped to a range of program counters
566 (PCs) in an execution unit. Each of these PCs is then added to a set of
567 breakable PCs (called the Breakpoint Filter) kept in the VM's execution context
568 object. If a debugger is attached to the VM, the interpreter calls
569 phpDebuggerOpcodeHook before executing each operation. This routine checks if
570 the PC of the operation is a member of the Breakpoint Filter. If so, it calls
571 the Debugger::InterruptVMHook method, which among other things, checks the
572 proxy's list of breakpoints to see if any of them apply to the source location
573 of the current PC. This involves a check if the breakpoint is enabled by the
574 user, a check if the source location is the same, a check if the breakpoint is
575 not already active and a check if the breakpoint is conditional on the value
576 of an expression.
578 6.2 Active breakpoints
580 A breakpoint can be already active when InterruptVMHook is called because it
581 can be set on a source line that maps to several interpreter operations.
582 (InterruptVMHook will be called for each such operation). It is not safe to
583 simply disable the breakpoint until the last of these operations are completed,
584 since one or more of those operations may be function calls that recurse back
585 to the active breakpoint.
587 In order to deal with this, each breakpoint keeps track of the depth of the
588 execution stack where it was activated. When InterruptVM finds that a breakpoint
589 will be hit, it checks that the height of the execution stack is greater than
590 the height recorded in the breakpoint before it proceeds with the steps that
591 are taken when a breakpoint is first hit. When control leaves the site of a
592 breakpoint at the right stack depth, the breakpoint is updated its previous
593 active stack depth (it has a stack of stack depths and it pops the top entry).
595 This pop operation cannot happen before the last operation corresponding to a
596 breakpoint has completed. However, it is not convenient for this to happen on
597 the very next operation. Instead, InterruptVM hook will update any breakpoints
598 that do not correspond to the current operation to ensure they are active if a
599 subsequent call to InterruptVMHook matches their location at the current stack
600 level.