A real breakpoint makes entries in the breakpoint filter for all offsets at the given line. Various flow control commands will also use the breakpoint filter to add and remove temporary "internal breakpoints" required during the flow operation. Ensure that we never remove a breakpoint filter entry if there was already one there due to a breakpoint (or really any other reason).
When the proxy's signal polling thread gets a signal from the debugger client, it would normally wait one second for another thread to recognize and consume the signal. This is pretty reasonable, but with a debug build on a heavily loaded system it's very rarely possible for one second to not be long enough. Added a runtime option to extend this, and set it to 3s for the existing debugger server tests.
No emitted bytecode relies on Continuation being stored in local 0
anymore. Stop using local 0 for this purpose and compute offset
to the Continuation at JIT time. 16 bytes of memory freed.
At this point all locals of Continuation construction wrapper share the
same indices with their respective locals of Continuation body, which
should allow further optimizations.
The exit path for the debugger client has always been a little odd. We'd call a shutdown function which would destroy the client, then later call a stop function which would first make a new client, then stop it, then that one would get destroyed later. Made it so we stop and destroy just one client.
Flow control commands should not evaluate the conditions of conditional breakpoints when enabling and disabling breakpoints during stepping. Also, all breakpoints, rather than just the first matching breakpoint should be enabled/disabled.
There was a race in the debugger protocol tests which send bad commands to the proxy and expect it to disconnect. If the proxy thread was fast enough it would mark the client as stopped, and we'd skip trying to get a new message after sending the bad command. This means missing one line of output in very rare cases. I've put in a wait to ensure that the client settles in the stopped state before continuing, to remove the race.
A client couldn't break execution during eval. There used to be a lot of barriers to making that right, but I fixed most of them with a previous diff on unifying client-side event loops. Now the only barrier was that a server-side thread processing an interrupt was blocking the signal polling thread by holding a mutex while processing the interrupt. Changed to set a flag to disable polling when starting to process the interrupt (and unsetting it when done), while still synchronizing with the signal polling thread to ensure only one thread is sending the client messages at a time. Added logic to re-enable polling while executing PHP for eval, print, etc. Plumbed the proxy thru to the point where we check the clause on conditional breakpoints, too, since that's the third (and final) place we do this.
This is an incremental step towards moving it all the way
to hphp/server. This flattens base but doesn't untangle
the server files from lib_hphp_runtime
I broke the operation of CmdMachine when we attach with the force flag with https://phabricator.fb.com/D851880. I consolidated some error handling logic around broken connections, etc., and in particular pulled throwing of an exception into forceQuit(). I failed to realize there was a single call site of forceQuit() that did not in fact throw an exception afterwards… the logic underneath of force attach. Switching the forceQuit() call there to stop() replaces the logic that was there previously, and restores the behavior.
break start/end/psp currently always report themselves as unbound. If the client is connected to a sanbox, these should instead be treated as bound. Also, break clear all currently removes breakpoints without running their destructors in the right order, which causes the break point counter to not reset to 1.
Update the connect usage log message to include details of the client that is connecting to a proxy, or to state if it's a connection due to script debugging.
Added two simple functions to determine if a debugger is attached, and to provide info about where the debugger is connected from. Also fixed a minor bug in ext_socket where the name for an unbound AF_UNIX socket would come back from getsocketname()/getpeername() as garbage.
In HHVM (and HPHPc before it) we've been piggybacking resources on the
KindOfObject machinery. At the language level, resource is considered to
be a different type than object, and there are a number of differences
in behavior between objects and resources (ex. resources don't allow for
dynamic properties, resources don't work with the clone operator, the
"(object)" cast behaves differently for resources vs. objects, etc).
Piggybacking resources on the KindOfObject machinery has some downsides.
Code that deals with KindOfObject values often needs to check if the value
is a resource and go down a different code path. This makes things harder
to maintain and harder to keep parity with Zend. Also, these extra branches
hurt performance a little, and they make it harder for the JIT to do a good
job in some cases when its generating machine code that operates on objects.
This diff prepares the code base for a new KindOfResource type by adding a
new "Resource" smart pointer type (currently a typedef for the Object smart
pointer type) and it updates the C++ code and the idl files appropriately.
This diff is essentially a cosmetic change and should not impact run time
behavior. In the next diff (part 2) we'll actually add a new KindOfResource
type, detach ResourceData from the ObjectData inheritence hierarchy, and
provide a real implementation for the Resource smart pointer type (instead
of just aliasing the Object smart pointer type).
This abstracts the file format a bit, so that we can
dump to multiple formats. Currently, GraphViz and GML are
supported. GML was added at @edwinsmith's request (and it's much
nicer than GraphViz anyway...)
Adds an extension command to the debugger which provides
heap tracing functionality, and adds the framework needed to get
heap traces. The heaptrace command can dump the current heap to the
debugger session or it can save a GraphViz specification to a file.
I'm hoping to add a backend which can put the graph in GML format,
so it can be explored interactively. I also hope at some point to
see this integrated into FBIDE if we can do that.
The debugger relies on hooks into the interpreter to gain control of threads. If a thread is looping in translated code, though, it will never enter the interpreter. Take advantage of the existing surprise checks emitted on back-branches to pop out of translated code back to the interpreter when trying to interrupt threads due to a Ctrl-C from the client.
Also modified TestDebuggerJit to ensure that the thread executing the infinite loop has time to settle into looping in TC's. The signal to interrupt the server is historically fast enough to get there before one of the translations is made. Added a reasonable delay which caused the test to fail deterministically on my machine before the fix.
Added some test cases. Also now permit caller=>func() type of breakpoints. To make this work, I added a method, getCallingSite, to class InterruptSite and use this to walk the stack when checking if a site matches a break point that has more than one function name.
Updates continuations to allow yielding of a key-value
pair from a generator. Adds bytecode instructions (PackContK,
ContKey) for using the new feature, and adds IR instructions
(ContUpdateIdx, ContIncKey) to help get it down to the metal
(in particular, ContIncKey attempts to keep the current use-cases
as fast as possible).
Experimental attempt to make sure test output does not contain non ASCII characters is actually completely useless because it sanitizes an integer. Remove it.
It turns out that Tutorial=0 means "auto" and -1 means "off". With auto tutorials, the hphpd.hdf file got updated and test behavior got flaky. Even worse, the non ASCII characters in the tutorial output broke the test runner in a way that made it look like tests passed when you put up a differential, only to fail in contbuild.
PackCont opcode is always followed by ContExit so let's join them into ContSuspend. ContResume counterpart may come later (replacing ContNext/Send/Raise/Enter).
The [z]end command in hphpd runs the last manually entered snippet of php in "zend". If you typed 'z' before actually entering any php, it would segfault. Fixed a minor bug in Process::Exec, and present help if none entered. Also clarified that it will simply use your system's default php, and made it so you can override which exe to use with a hphpd config variable. The default is "php", since that is most commonly used.
When a test fails hphp/test/run runs a regular expression over the test output and returns it to the python scripts that is running the tests on the continuous build machine. These scripts crash if presented with output that is not printable ASCII, which makes it very difficult to figure out why the test is failing. This change modifies hphp/test/run to first encode the test output with quoted_printable_encode before returning it to the python scripts.
Add a bit more usage logging for the debugger, and ensure that there is a common field between clients and servers thats easy to search on, i.e., sandbox id.
Because stronger types are better types, and this will make
future refactoring easier. I considered trying to purge the Opcode
type from the codebase too but that would be a much bigger project.
C++11 cleanup (clean up easy enums)
This is for runtime/base/... and ended up touching a lot of files
because it turns out we have a lot of reasonably behaved enums.
People sometimes make mistakes and launch hphpd without connecting to a server, but expect to be in the server environment when evaluating expressions. Modified the –h option to not require a host specification, and default to localhost, so "hphpd –h" is a valid way to launch now. Provide a warning on launch when no args are specified at all warning the user that they're not connected, and giving suggestions for how to connect if necessary. There are reasonable use cases for launching hphpd with no args (so, no connection and no local script to debug) and I didn't want to take those away by automatically connecting to a server at localhost if launched with no args. I'm hoping the warning is sufficiently helpful.
Currently a breakpoint specified as relativefilepath:lineno will match only if the relative file path is a simple file name or if sandbox root + relative file path is an exact match. This is now generalized so that matching occurs if the relative file path is a suffix (path) of the absolute path of the execution location.
This was doing ref(foo), where foo is an Array. This will
create a temporary Variant, call the ref(CVarRef) overload, which
casts the temporary to a non-const RefResult, then a temporary
VRefParam is implicitly constructed from this, which creates a
KindOfRef and points the temporary variant at that. The sort will
operate on this temporary (leading to copy on write, and storing the
new ArrayData* there), so the m_constants field won't reflect the
changes.
The debugger client now accepts feedback from the the debugger server about whether a breakpoint can be hit, absent further loads of files, classes or functions.
There was a similar-but-different event loop used when receiving command results from the server which was close, but not quite right. Unified it with the main event loop to ensure that all error cases are handled properly when we put up a prompt at a nested interrupt, like when hitting a breakpoint during an eval. The event loop is now shared, with a few different "kinds" to control some of the special needs of the loop when executed from a command. Most commands don't cause the server to run more PHP, so they don't change the machine state or cause more interrupts. But some do (Eval and Print) and certainly the top-level loop does, too. Made sure to throw a protocol error if any command causes this to happen when we don't expect it.
Cleanup a lot of hangs with either the debugger client or server in a variety of error conditions, mostly related to communication errors or the client or server exiting unexpectedly. One of the biggest fixes is that all cases where the client was left in a state where Ctrl-C wouldn't work have been fixed.
Remove lots of little snippets of dead code. If you see a function (or small set of functions/fields) deleted then it was actually dead.
I debated whether to keep throwing DebuggerClientExitException on the server, and I decided to keep it. I think it's reasonable that if you've got the server stopped and you quit the debugger that the request gets terminated rather than continuing to run.
I also considered a big change to the way Ctrl-C works, but ended up staying with what was there with just a bit of cleanup. We need to guard against people banging on Ctrl-C, which is a reasonable behavior, and I think it feels pretty reasonable with the updated message.
Finally, added many comments about how this stuff works.
Instead of calling get_systemlib every time the debugger client needs to list source from systemlib.php, use a cached copy of the source string. Only do this if debugging is enabled.