| Previous | Contents | Index |
There are two different requests that end a remote debugger session:
Although there are explicit Ladebug commands that call up each of these requests, Ladebug normally kills processes that it has loaded and disconnects from processes to which it has connected. As such, a server that implements the Load Process function should at least implement the Kill Processes function and a server that implements the Connect to Process function should implement the Disconnect from Process function. The following are optional:
Two example Ladebug servers are available. The source code of these
example servers is available from Digital Equipment Corporation for
unrestricted reuse on Alpha based platforms (see the copyright notice
in the source code for details).
C.6.1 The Tru64 UNIX Server
The Tru64 UNIX server is designed to allow the debugging of user processes running on remote Tru64 UNIX systems. The version described in this section supports loading new processes using the Load Process request but does not support the Connect to Process or Connect to Process Insist requests.
The server consists of a server daemon and user servers:
The remote debugger daemon must be run as a root process. It would
normally be started at system start-up. The user server loads the
debuggee using Tru64 UNIX's fork() and
exec() functions and uses Tru64 UNIX's
ptrace() interface to implement the low
level debugger facilities required. The load server and daemon both use
Tru64 UNIX UDP sockets to communicate with the client.
C.6.2 Evaluation Board Server
The evaluation board server is included in the evaluation board debug monitor provided with the Alpha evaluation boards (EB64, EB64+, EB66, etc.). It is designed to provide source level debugging of operating system kernels being ported to these boards, and of programs running on these boards without an operating system. The complete monitor (including the remote debugger server) is designed to be easily ported to other Alpha based hardware.
The server only supports starting debugger sessions through the Connect to Process or Connect to Process Insist requests. This server does not support the Load Process request. Since the monitor is not a multiprocessing system, the server ignores the process ID in the Connect requests. It also ignores the login names in Connect requests.
The user is expected to load the test program using the monitor load facilities (LOAD, NETLOAD, etc.) before starting the debugger server. The server interprets all addresses it receives as physical addresses. The server then performs all debugger functions by directly reading and writing memory.
To set breakpoints, the debugger patches a PAL call into the code being debugged. To avoid conflict with the use of the breakpoint PAL call by operating system kernels, this is not the standard breakpoint PAL call (the BPT PAL call) but a special PAL call (DBGSTOP). DBGSTOP exhibits identical behaviour but has its own system entry address. It is implemented in the debugger version of evaluation boards' PAL code. When this PAL call is executed, it results in a call back to the monitor at which point the state of the debuggee is saved and the server is reentered.
The monitor's ethernet software allows server to register to receive packets addressed to particular UDP port and to send packets on any UDP port. The server depends on interrupts to receive packets while the debuggee is running. Upon receiving any interrupt, the monitor polls the ethernet driver for messages. The ethernet software passes any appropriate messages to the server.
A consequence of using interrupts to receive messages is that some care
is needed when debugging programs that do their own interrupt handling.
To allow such programs to be debugged, the Evaluation Board user
library contains a function that polls the ethernet. This function
would normally be called by the application every time it receives an
interrupt.
C.6.3 Structure of the Servers
Each server consists of:
The simplest way of creating a server for a new target is to base it upon one of the example servers. Normally, if you are developing the server to be part of a monitor program, you should base it upon the evaluation board server.
If, however, you are developing it as an operating system utility you
should probably base it upon the Tru64 UNIX server. You should try
to make as few changes as possible to the example servers, since you
are likely to have no satisfactory way of debugging software (and hence
the servers themselves) until you have successfully ported them to your
target system.
C.7 The Communicators
This section describes
The communicator contains the main function to the debugger server, to which the interface is target-dependent. It also contains some functions that the other components of the server can call. These functions are as follows:
The Tru64 UNIX communicator is implemented in the C source file server_main.c. This file contains the daemon's entry point (main()), the main function of the user servers (user_server_main() ), and the interface functions previously described.
When the daemon is started, main() creates a socket and binds it to the Ladebug remote debugger connect port. It then reads packets from this port ignoring any packets that are not load requests. When it receives a load request, it checks that the client user is allowed to run remote debugger sessions on this machine using the server user name he has requested. This it does by calling to the Tru64 UNIX function ruserok().
If the request is valid, the daemon creates a child process (by forking). The parent process then simply continues round the packet reading loop. The child process:
If, for any reason, the daemon is unable to start the user server, it then sends a load request response to the client containing an error code.
The user server function user_server_main() starts by creating a UDP socket for communicating with the client. It then:
One complication in the code of the communicator is that the daemon has to be able to handle the receipt of duplicate load messages. The client sends such duplicate load messages when the server's load response message is lost or does not reach the client within the client's time-out time.
To handle such duplicate load messages, a pipe is created between the
daemon and each user server. When the daemon receives a duplicate load
message, it uses this pipe to pass it on the appropriate user server.
The user server treats this message like any other duplicate message.
C.7.3 Evaluation Board Monitor
The evaluation boards' Ethernet driver software passes received frames to other parts of the monitor's software through call-back functions. A component of the monitor that wishes to receive frames on a UDP port calls a registration function provided by the Ethernet driver software.
The registration functions take as an argument the address of the call-back function to be called when such frames are received. When a component registers a call-back function, it can do either of the following:
If the ethernet hardware has received a packet for any registered UDP port then the driver will call the appropriate call-back function. The call-back function called may be in a completely different component of the monitor from that which called ethernet_process_one_packet() . Once any call-back function has completed its processing, ethernet_process_one_packet() will return with a result indicating whether any packets were processed.
All packets passed to the ethernet driver must be built in fixed sized buffers provided by the driver, so that the ethernet driver never has to copy any data. The ethernet driver allocates these buffers at addresses from which the ethernet devices can send data and to which they can receive data.
To avoid the need for complex allocation algorithms, and complex error handling if buffer allocation fails, any component of the monitor can allocate a number of buffers at start-up. To maintain this buffer count the ethernet send functions always return to the caller a buffer to replace the buffer containing the packet to be sent.
On completion, the call-back functions used to receive frames must always return an ethernet buffer to the ethernet drivers. This can be, but need not be, the buffer that contained the received frame.
The debugger server does not need its own pool of buffers, since it only sends a frame immediately following the receipt of a frame. As such it handles received frames in the following steps:
The server's communicator is largely implemented in C source file server_read_loop.c . This contains the following code:
The evaluation board library contains an assembler function called ladbx_poll() that calls app_poll() through the pointer at this address. Applications that do their own interrupt handline should call ladbx_poll() frequently (for example, every time they receive an interrupt) to ensure that the debugger server receives all debugger protocol packets without excessive delay. |
In addition, the file kutil.s contains
the source of the monitor's interrupt function. The monitor only
enables interrupts when an application is running. When the monitor
receives any interrupt, it saves the debuggee's state and polls the
Ethernet for received frames. Since the monitor will normally receive
regular 1ms timer interrupts this will ensure that it receives all the
client's debugger frames.
C.7.4 Porting the Communicators to Other Systems
It should be possible to port the Tru64 UNIX communicator to most other versions of Tru64 UNIX and Tru64 UNIX derivatives with few changes. For operating systems that are not derived from Tru64 UNIX, the mechanism for starting user servers may have to be significantly modified.
In particular, many operating systems have no exact equivalent of fork() and instead start a new process by running a new executable file. On such a system, the communicator will have to be split into two separate executable files (one for the daemon and the other for the server). Also in such systems the new process typically does not have access to data set up by its parent before it was created, so some other mechanism will have to be used to transfer the first packet, and other data, to the user process.
The mechanism for setting the user identifier of the user server will vary widely between operating systems. Be aware that although the term daemon is a Tru64 UNIX term almost all operating systems have some mechanism for installing and running privileged background processes.
The socket mechanism used to read data from the network is quite widely available. If this mechanism is not available, then any other mechanism that allows the communicator to wait for the receipt of UDP packets on particular ports can be used.
If the operating system does not provide any such mechanism (for example, a real time kernel that does not include networking support), then one option is to port part or all of the networking code in the Evaluation Board Monitor to this environment. In this case, it may be easier to base your communicator upon the that in the Evaluation Board Server rather than basing it upon that in the Tru64 UNIX Server.
For embedded servers, few (if any) changes should be needed to the
Evaluation Board's communicator. However, for many such systems you
will need to rewrite the network device drivers. These are contained in
the ethernet code of the Evaluation Board Monitor.
C.8 The Protocol Handler: Interface Functions and Implementation
The protocol handler's main interface function is ProcessPacket() . The only argument to this function is a pointer to the packet that it is to process. As a part of its processing of the packet ProcessPacket() converts the request packet passed to it into a response packet. The caller must ensure that the buffer pointed to by the argument is large enough to contain any possible response packet.
The function DumpPacket() can also be called by the communicator. This dumps the contents of packets passed to it, if the protocol handler is compiled with tracing enabled.
The code for the packet handler is identical for the two servers. It should not need to change for other server implementations. The source code is in the files packet-handling.c and packet-util.c ; packet-handling.c contains the function ProcessPackets(). When this function receives a packet, it:
packet-util.c contains utility functions
for reading and writing the fields of packets and for dumping the
contents of a packet. To avoid any possible alignment problems the
utility functions read and write packet fields a byte at a time.
C.9 The Debugger Kernels
This section describes:
The debugger kernels provide the following interface functions to the protocol handler:
| Previous | Next | Contents | Index |