How to implement a stub or server using RDA (Red Hat Debug Agent and library).
==================================================
Andrew Cagney <cagney@cygnus.com>
Fernando Nasser <fnasser@cygnus.com>
Frank Eigler <fche@cygnus.com>

Introduction
------------

This is the implementation of a server for the gdb remote protocol.
It is available as a host library that provides most of the common code
required.  By adding a relatively small amount of target dependent code,
one can build a server that allows gdb to connect to that target using
the gdb "target remote" command.

Gdb connects to this server through a TCP/IP connection.  The server
waits for a connection from GDB by listening to a non-restricted TCP port.
Anyone with GDB (or even telnet) network connectivity to the machine
running the server can initiate a connection to it.

Note: The user of this software is advised to ensure
that access to the TCP port being used is restricted to
secure siblings.  For instance, the user may need to take
action that ensures that `The Internet' is not able to access
the TCP port being used.

Architecture
------------

The following diagram shows the components of RDA.

	(GDB) <---"remote"---> CLIENT <--> SERVER <--> TARGET
       -------                 ------------------------------
     The client.                         The server.

Where:

	CLIENT  Provides the raw interface between
		GDB and the internal SERVER
		mechanism.

		The client passes on any data relevant
		to the server.  The SERVER presents
		CLIENT with raw output to be returned
		to GDB.

	SERVER  Implements the state-machine that
		is capable of decoding / processing
		various GDB remote protocol requests.

	TARGET  The embedded system proper.  SERVER
		passes decoded requests onto the TARGET
		while TARGET notifies the SERVER of any
		target state changes.


Looking at SERVER in more detail, that component consists of three sub
components INPUT, OUTPUT and STATE.  Visually:

          			     .------------ fromtarget_*
			            \|/
	fromclient_*   -> INPUT -> STATE (M/C) -> target->*
	                   /|\         |
                            |
	                   \|/         |
	client->write  <- OUTPUT <----'

Where:

	INPUT   Filters the raw input stream from the client
		breaking it up into complete packets and
		passing them onto STATE.

		This component co-operates with OUTPUT for
		the ACK/NAK of input packets.

	OUTPUT  Wraps up and then passes onto the client
		raw output packets ready for transmission
		on the output stream.

		This component  co-operates with INPUT for
		the ACK/NAK of output packets.

	STATE   The state machine proper.


The Appendix provides various scenarios showing in some detail how typical
operations are handled by these components.  It may be convenient to read the
next section first before turning to the Appendix.


Adding the target dependent code
--------------------------------

In the following discussion, assume your debugger (gdb) is using 
the remote protocol to communicate with the code you are building here.
The "target" is a simulator, hardware device, board, program or whatever you
are interfacing to with your stub/server.

The library provides gdbsocket_*() and gdbserv_fromtarget_*() routines that
must be called and requires you to set a series of callback routines.
You make these callbacks known/available to the library by filling the entries
of a "gdbserv_target" object.  You must also provide an extra function that
will be invoked when a new connection is detected on the input port (a socket).


Handling the connection:

The server is capable of handling several connections (named, sessions)
simultaneously.  This is possible because each session data is kept on
an instance of a GDBSERV object.  A routine called gdbserv_fromclient_attach()
is called when a connection request is received by the socket.
If the connection is accepted, a new instance of a GDBSERV object is returned,
otherwise NULL is returned indicating that it has been rejected (a EOF will be
sensed on the other end).

The server will, in turn, pass the request onto the target.  The target can
either reject the connection (returning NULL) or accept the connection
(returning a target object).  That is where you come in.

You must provide a routine like (please see the precise API in the header file
include/gdbserv-client.h):

typedef struct gdbserv_target *(gdbserv_target_attach) (struct gdbserv *gdbserv,                                                        void *attatch_data);

This will be called by the server to notify that the client has initiated a
connection.  You must return a GDBSERV_TARGET struct for the session or null
if your target has rejected the connection.

The recommended way to create your gdbserv_target object is:

struct gdbserv_target *gdbtarget = malloc (sizeof (struct gdbserv_target));
memset (gdbtarget, 0, sizeof (*gdbtarget));
gdbtarget->process_get_gen = process_get_gen;
(...)

If you initialize it like this, you will not have to change your code even if
new entries are added to this struct.


Handling target events:

The fromtarget_* routines may be called by your target.  Before you
despair, let me tell you that they are only three: reset, break and
exit.  They indicate that some interesting condition happened in your
target that requires debugger attention.  Reset and exit are quite
obvious and break is for everything else.  These routines must *not*
be called from within a gdbserv_target callback function, so it may be
necessary for your target to set some flags to signal state change
calls later.

If your target is a simulator, call those when the corresponding
condition arises in your simulated target.  If it is a board, it will
probably be called from your ISRs.  A special case occurs if your
target is a device that has to be polled in order to detect state
changes.  If this is the case, you will call these routines from the
polling code.


The main loop:

At some point you must get things going by:

1) looking for connection requests from gdb and 
2) causing remote protocol commands to be read from the input port (socket).

You must (repeatedly) call a function called gdbloop_poll().  This
will be in your main loop.  If it is a server it will be in your
main() function.  If it is a simulator that also accepts input from
other sources, it will have to be added to the existing main loop. If
it is a board, it will probably be called from the timer ISR.

Before doing that you must initialize your socket interface.  Look in
the main() routine of the sample program to see what to call.  When
calling gdbsocket_startup() you must give the address of the callback
that handles connection requests for your target.

If your target has to be polled for state changes, you will have to alternate 
calls to poll() and to check your target status.  As I mentioned before,
your status checking routine must call the appropriate fromtarget_* function.


The callbacks:

All that is left now is to implement your callbacks, which are, directly or
indirectly, called as a result of a remote protocol packet being received and
processed by some fromclient_* routine.  I will assume that the remote
protocol packets are known.  If not, please refer to the "Remote Protocol"
section of the gdb manual.  There you will find how your target should be
affected by each packet and what the response should be.  It is always
useful to look at what some other remote targets do as well.

The list of all callbacks with the situation in which they are invoked can be
found in the header file lib/gdbserv-target.h.

Have fun!



Appendix
--------

SCENARIOS


ATTACH: Creating a connection into the server/target.

Client receives a connect request from the remote GDB.  A socket
interface would see this as an attach.  For Cygmon this is the
``transfer'' command.

The client creates an output object (struct gdbserv_client) and passes
that and the target side attach function onto GDBSERV.  SERVER will
then initialize itself and call ``to_target_attach'' for final
approval of the request.

	struct gdbserv_client *client;
	...
	client->write = client_write_to_output_port;
	client->data = ... local state ...
	server = gdbserv_fromclient_attach (client, to_target_attach,
					    target_data);

The target_attach() function is expected to either create and return a
gdbserv_target object or return NULL.  The latter indicates that the
connection request is rejected.

Finally gdbserv_fromclient_attach() returns a SERVER state object that
should be passed to all client->server calls.


DATA-IN: Data being sent to the client from the remote GDB

The client passes the data vis:

	len = read (fd, buf, sizeof (buf));
	gdbserv_fromclient_data (server, buf, len);


BREAK-IN: Request to stop sent to the client from the remote GDB

The client passes the request to SERVER:

	server.c:

	volatile
	break_handler ()
	{
 	  gdbserv_fromclient_break (server);
	}

If the target is currently running, the server will in turn pass the
request onto the TARGET:

	->target->break_program (server);

and the target will record the break request and then return control
back to the SERVER.  The server returning control to the client.

Later, once the target has halted, the SERVER is notified of the state
change vis:

	target.c:

	  gdbserv_fromtarget_break (server);


NB: Often ``break'' is sent across the stream interface as a special
character sequence.

FIXME: gdbserv-input.c should be able to parse such character
sequences.


DATA-OUT: Data for the remote GDB from SERVER

The ``write'' function specified in the ``struct gdbserv_client''
object is called.


DETACH: Remote GDB disconnects from the SERVER

The CLIENT notifies SERVER via the gdbserv_fromclient_detach() call.


HARD-RESET:  A hard reset is performed on a serial board.

Assuming a standalone system, the client/target side sequences would
be performed:

	/* create the server */
	server = gdbserv_fromclient_attach (...);
	/* notify the server that the target was just reset */
	gdbserv_fromtarget_reset (server);


WRITE-MEMORY: GDB sends the server a write-memory packet.

Eventually SERVER passes the request onto the TARGET with the call:

	->target->process_set_mem (server, addr, len);

where ADDR and LEN contain the uninterpreted address/length of the
data to follow.  target_process_set_mem() might be implemented as:

	long long addr;
	long int;
	gdbserv_reg_to_ulonglong (server, reg_addr, &addr);
  	gdbserv_reg_to_ulong (server, reg_len, &len);
	/* just blat local memory */
	len = gdbserv_input_bytes (server, addr, len);
	

READ-MEMORY: GDB requests memory from the target.

Eventually target_process_get_mem() function is called.  An
implementation may look like:

	gdbserv_reg_to_ulonglong (gdbserv, reg_addr, &addr);
  	gdbserv_reg_to_ulong (gdbserv, reg_len, &len);
	/* assume we're reading raw memory from the local mc */
  	gdbserv_output_bytes (gdbserv, addr, len);


TARGET-RESUME: GDB requests that the target resume execution.

Eventually ->target->continue_program() is called.  That function
should record the request and then wait for SERVER to exit before
actually continuing the target.

--

