PikeDebugger

[ Start > PikeDevel > PikeDebugger ] [ Edit this Page | Show Page Versions | Show Raw Source ]


Work on permitting pike code to be debugged interactively is underway, and currently exists as a rough proof of concept in branch bill/debugger-concept. The debugger requires pike to be compiled with --with-debug and can be enabled using --debugger option to pike, with enables a hilfe server on port 3333

Current features of the POC

  • Multiple breakpoints may be set and cleared independently.
  • Hilfe interface
  • Backtrace viewing
  • Frame stack browsing (as part of backtrace frames)
  • View locals with variable names (thanks, Grubba!)
  • Modify locals
  • Single stepping
  • Continue

    Things that need to be done

  • Pass current thread to debugger engine
  • Allow the debug session to stop execution without waiting for a breakpoint - probably just a matter of setting the stepping mode on the desired thread.
  • A programmatic interface to the debugger (in process - Mateusz)
  • Step-over, in, return, etc. These require understanding of code structure
  • Do we need to evaluate a possible debugger halt for every opcode, or just some?
  • Do we need some more methods on the Thread object for getting state (running/paused) or to set a thread name for clarity?
  • Watchpoints?
  • Efficiency improvements?
  • Work to not require RTL debug
  • Make ports configurable

    Example of a debugging session:

    Start up a pike program with the debugger enabled. Pike will wait a few seconds for a debugger to connect, then continue on if one has not.

$ pike --debugger /path/to/file.pike

In another terminal, connect to the debugger port.

$ telnet localhost 3333
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Welcome to the Pike Debugger.
> object bp = Debug.Debugger.add_breakpoint("/path/to/file.pike", 22);
> object bp1 = Debug.Debugger.add_breakpoint("/path/to/file.pike", "/path/to/included_file.h", 2);
> bp->enable();
> bp1->enable();
> go
Breakpoint on /path/to/file.pike:22
> backtrace;
(1) Result: ({ /* 4 elements */
                backtrace_frame(/Users/hww3/pike2/build/darwin-16.7.0-x86_64/master.pike:4148, _main(), Args: 1),
                backtrace_frame(-:1, `()(), Args: 1),
                backtrace_frame(/path/to/file.pike:14, doit(), No args),
                backtrace_frame(/path/to/included_file.h:2, whee(), Args: 1)
            })
> backtrace[-1]->locals();
(4) Result: ({ /* 3 elements */
                "rad",
                0,
                0
            })
> backtrace[-1]->set_local(1, "bar");
(5) Result: 0
> backtrace[-1]->locals();
(6) Result: ({ /* 3 elements */
                "rad",
                "bar",
                0
            })
> step
Stepping.
Breakpoint on /path/to/included_file.h:2
> go

Some thoughts about an API

The programmatic API would probably need to be at least partially asynchronous, as events may occur at any point, and not necessarily in response to a request from the debugging client. An example would be one or more breakpoints being reached.

Perhaps something websocket-y like socket.io? Would performance be good enough?

It seems as though it will be necessary for certain aspects of the api that deal with evaluation, variable assignment and such, to operate in a "semi-hilfe" mode, where expressions are passed over the link and evaluated in the debugger. Otherwise reference-type values would always be new literals, and it would not be possible to, for example, replace a value with a mapping that was defined elsewhere in the context being debugged.

Some notes about optimization

Pike is very clever, and will attempt to do whatever you ask in the most efficient way possible. This can create confusion when debugging, though, as code may not be evaluated quite the way you expect.

For example, if you have a breakpoint in a method that has no side-effects and the answer returned would be considered constant (either because it takes no input variables, or those inputs are constant in the context of the call), Pike may opt to evaluate the method once, possibly at compile time, and then simply skip over it during evaluation. If you were to put a breakpoint on a line in this method, you may hit it at an unexpected time, and then never again when the code around it executes.

Needs research: It may be possible to disable certain optimizations to prevent this unexpected behavior, though that could have side effects of its own.


Powered by PikeWiki2

 
gotpike.org | Copyright © 2004 - 2009 | Pike is a trademark of Department of Computer and Information Science, Linköping University