MOSA-0005: Kernel debugger architecture, interfaces and components
This RFC discusses the MOSA kernel debugging model. This model describes all components required to build kernel debugging support into a MOSA compliant kernel as well as the interaction with debuggers running on a client system.
The following table defines some terms used in this RFC. These definitions are specific to this RFC and may differ in their meaning from other uses.
A debugger is a client program used to interactively examine a (remotely) running program. In context to kernel debugging, a debugger allows the user to examine the flow of control in a running operating system and all of its processes.
A proxy encodes operations into a protocol, transmits the operation accross a physical connection to the
and awaits the response.
A stub is a component, which translates a debugging protocol into appropriate operations. In the context of this debugging model, the stub receives requests, decodes them and passes them on to a protocol independent debugging engine.
A protocol describes the communication between a client (the debugger) and a server (the debugger stub). The protocol consists of requests and responses.
The following image describes the debugging model defined by this RFC. It integrates various independent components in order to be able to debug a MOSA operating system. The model described is a kernel debugger model, which means that the remote system freezes
when it hits a breakpoint or is stopped by a debugger. Kernel debugging provides a very low-level facility to step through kernel code, debug drivers and applications remotely. Because the debugged operating system freezes, when breaking, it is not possible
to use this debugging facility to debug programs on the local machine. A seperate model is to be defined for that case.
The debugging model consists of a client debugger, which uses a proxy to communicate using a debugging protocol with a debugger stub running in the MOSA kernel. The debugger stub interacts with a protocol independent kernel debugging engine in order to realize
the requested commands. For example, if the user issues a break command in the debugger, the debugger passes it to its proxy. The proxy translates this command into the respective request in the protocol and transmits it through a physical connection to the
debugger stub running in the kernel. The debugger stub decodes the request, issues the appropriate calls into the debugging engine and responds with an appropriate response to the proxy. The proxy returns to the debugger.
The does not make any assumptions about the location of symbol information, which describe the executing code. This is specific to the debugger used and the capabilities of the communication protocol(s) involved. In case of JITted code this means that the JIT
has to emit debug information (in addition to the metadata available) and that the protocol must provide a transfer mechanism of these symbols to the debugger.
This model splits the kernel debugging interfaces into two parts: The debugging stub and the debug engine. The debugging stubs are protocol realizations, which use MOSA drivers to respond to requests made by a remote debugger. A stub translates the debugger
specific protocol into protocol independent calls to the debug engine described below. Debugger stubs are specific to the protocol and debugger to be used.
The MOSA kernel debug engine provides a set of commands to freeze the kernel, continue execution, set breakpoints, request memory dumps, write to memory, get call stacks and executing modules. TBD
Parts of the debug engine are architecture specific and use the native instruction set of the processor(s) in the system in order to achieve their functionality - for example breakpoints are set using the facilities provided by the processor. The debug engine
interface is shown in the following image:
The MOSA compiler framework provides facilities to generate symbols and to stream these symbols to the debugger, as the symbol files are stored via streams. The JIT in a process must be configurable in order to emit symbols for dynamically compiled code. The
supports a compiler switch (-g) in order to generate symbol files in addition to the native code emitted.