How to implement a stub or server using RDA =========================================== Andrew Cagney Fernando Nasser Frank Eigler Kevin Buettner Introduction ------------ RDA is a "Remote Debugger Agent" for GDB. It provides a library of commonly used routines which may be used to construct a "debugger stub" or "debug agent". The RDA package also includes several applications which use the RDA library. It is useful to examine these examples when creating a new RDA application. (One of the applications provides functionality similar to that of "gdbserver" found in the GDB sources.) The RDA library provides an implementation of the "server" end of the GDB remote protocol. An application which uses the RDA library will typically start up and then wait for GDB to connect to the the application via GDB's "target remote" command. Once communication between the RDA application and GDB has been established, the RDA application translates GDB's remote protocol requests into queries against the target environment. When results from these queries are known, the results are communicated back to GDB in a response packet. The RDA library has been designed so that a relatively small amount of target dependent code is required in order to create a new RDA application. GDB connects to the RDA application via either a TCP/IP connection or a connection on a serial port. When TCP/IP is used, the RDA application waits for a connection from GDB by listening on a non-restricted TCP port. A serial connection behaves in a similar fashion except that (obviously) no initial listen is needed. Note: Users of this software should take the usual precautions with regard to security of TCP/IP ports. Architecture ------------ The following diagram shows the components of an RDA application communicating with GDB: (GDB) <---"remote"---> CLIENT <--> SERVER <--> TARGET ------- ------------------------------ The client. The RDA application (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. Adding Target Dependent Code ---------------------------- An RDA application communicates with a debugger, such as GDB, using the GDB Remote Serial Protocol. The RDA library performs the high level I/O management for the debugger connections, watches for new connections, and looks for protocol requests from existing connections. The RDA library packages up suitable responses to protocol requests after invoking target specific callbacks which collect the necessary information. In short, the RDA library manages communication with the debugger. You are responsible for implementing target specific support. The "target" is a simulator, hardware device, board, program, or whatever you are interfacing to your stub/server. Starting up: The function gdbsocket_startup() is used to register a TCP/IP port number upon which to listen. It is called with the port number upon which to listen, a callback function to be invoked when a connection is made, and a pointer to target specific data which will be passed to the callback function. The callback will be referred to as the "attach callback", perhaps due to the fact that GDB is attaching to RDA. The function gdbsocket_startup() might be invoked as follows: gdbsocket_startup (portnum, my_attach_func, my_attach_data) The RDA library is capable of handling several connections (sessions) simultaneously. If listening on several ports is desired, it is permitted to make several calls to gdbsocket_startup() in order to register the various sockets upon which the RDA application should listen. (Note that it is still possible to have several connections at a time even without monitoring more than one port number.) Callback Registration: The library requires that you implement a set of callback routines for reading and writing memory, reading and writing registers, controlling the target, etc. These callbacks are made available by filling in members of a gdbserv_target struct. Registration of these callbacks is performed via the attach function passed as the second argument to gdbsocket_startup(). This function will be invoked when a new connection is detected upon the input port. When a new connection is received on one of the sockets registered by gdbsocket_startup(), the corresponding attach routine is invoked. The attach routine can reject the connection attempt by returning NULL. Otherwise, it is the responsibility of the attach function to allocate a gdbserv_target struct, fill in the various callback members, and perhaps perform some other initializations. If all of this successfully completes, the attach function should return a pointer to the gdbserv_target struct that's been initialized. A skeleton of my_attach_func() might look something like this: struct gdbserv_target * my_attach_func (struct gdbserv *serv, void *context) { struct gdbserv_target *my_target; if (!new_connection_okay ()) return NULL; my_target = malloc (sizeof (struct gdbserv_target)); if (!my_target) return NULL; memset (my_target, 0, sizeof (struct gdbserv_target)); my_target->get_reg = my_get_reg; my_target->set_reg = my_set_reg; ... perform_other_initializations (); return my_target; } Handling target events: The "gdbserv_fromtarget" prefixed routines are called by your target-specific code, however they must not be called from any of the gdbserv_target callback functions. (Use of a flag or flags for indicating a state change that is checked at some later time is recommended.) There are essentially only three of these routines that you need to be concerned with. They are: void gdbserv_fromtarget_reset (struct gdbserv *gdbserv, int sigval); void gdbserv_fromtarget_exit (struct gdbserv *gdbserv, int sigval); void gdbserv_fromtarget_break (struct gdbserv *gdbserv, int sigval); The first two (gdbserv_fromtarget_reset and gdbserv_fromtarget_exit) are used to indicate target reset and program exit. The latter, gdbserv_fromtarget_break, is used in all other situations to indicate that the target has stopped for some reason (indicated by sigval). If your target is a simulator, these "gdbserv_fromtarget" prefixed routines should be called when the corresponding condition arises in your simulated target. If your target is a board, these functions might be invoked from your interrupt service routines. If you target is a device that has to be polled to detect state changes, you'll call these routines from the polling code. The Event Loop: The RDA library uses an event driven model. The function gdbloop_poll() causes the library to: 1) Look for and handle new connection requests from a debugger. 2) Read remote protocol commands from a stream associated with an already connected debugger and invoke one or more of the callbacks that you have registered. A single argument is passed to gdbloop_poll() indicating the length of time to wait for an event to occur. A negative value will cause gdbloop_poll() to block as long as needed for something to happen. Otherwise, the integer passed to gdbloop_poll is the time in milliseconds to wait for an event to occur. If your RDA application is structured as a server, then gdbloop_poll() will be called repeatedly in the main loop. If the RDA application is part of a simulator, then a call to gdbloop_poll() should be added to the existing main loop. If a debugging stub for a board is being implemented, then gdbloop_poll() should be invoked periodically, perhaps in response to a timer interrupt. If your target has to be polled for state changes, you will have to alternate calls to gdbloop_poll() with polls of the target status. As noted earlier, one of the "gdbserv_fromtarget" prefixed functions is called to indicate a change of state (stop, exit, or reset). Callbacks: Recall that gdbsocket_startup() is given, as one of its arguments, the address of a function which is called to register a set of callbacks via a gdbserv_target struct. You will, of course, have to implement each these callbacks. Some knowledge of the GDB remote protocol will be required. Refer to the appendix of the GDB manual entitled "GDB Remote Serial Protocol" for these details. Here is a link (which may or may not work): http://sourceware.org/gdb/current/onlinedocs/gdb_33.html#SEC691 The layout of the gdbserv_target struct is defined in the RDA source tree in the header file include/gdbserv-target.h. (Most of the callbacks are discussed below.) Finally, it should prove useful to examine samples/demo-target.c, unix/thread-db.c, and unix/linux-target.c to see how these RDA applications implement the various callbacks. Register Related Callbacks -------------------------- The register related callbacks are probably the most confusing because there are many of them. Moreover, not all of them should be implemented. If your target has a concept of threads and you want GDB to be able to debug these threads, you should implement the threaded register processing callbacks. These are next_gg_reg, next_expedited_reg, reg_format, set_thread_reg and get_thread_reg. Even if your target is single-threaded, you should consider using these methods anyway. If you target does not use threads you may instead implement the following methods: input_reg, output_reg, gg_reg_nr, expedited_reg_nr, sizeof_reg, set_reg, and get_reg. Finally, there are an older set of register related callbacks that should be avoided. These are: process_set_reg, process_get_reg, process_set_regs, and process_get_regs. These older callbacks will not be discussed further. The thread aware register related callbacks are as follows: int (*next_gg_reg) (struct gdbserv *, struct gdbserv_thread *, int reg_nr); int (*next_expedited_reg) (struct gdbserv *, struct gdbserv_thread *, int reg_nr); int (*reg_format) (struct gdbserv *, struct gdbserv_thread *, int reg_nr, int *size, int *padding); int (*set_thread_reg) (struct gdbserv *, struct gdbserv_thread *, int regnr, const struct gdbserv_reg *reg); int (*get_thread_reg) (struct gdbserv *, struct gdbserv_thread *, int regnr, struct gdbserv_reg *reg); All of these thread aware register related callbacks are passed a pointer to a gdbserv object, as well as a pointer to a target defined thread object (struct gdbserv_thread *). (You will need to define the layout of struct gdbserv_thread.) The ``next_gg_reg'' callback is used by the RDA library to iterate over the registers in a 'G' or 'g' packet. (A 'g' packet is used to read general purpose registers. A 'G' packet is used to write them.) Thus, the ``next_gg_reg'' callback effectively defines the registers that are in a 'G' or 'g' packet and their order. This function is initially called with the reg_nr parameter set to -1. This callback should be implemented to return the register number of the first register when reg_nr is -1. After that, it is called successively with its previous return value in order to obtain successive register numbers. next_gg_reg() should return a negative value (such as -1) when the end of the list is reached. (Technically, the end of list is reached on the call prior to the one that returns -1.) The ``next_expedited_reg'' callback is optional. It is used to construct the list of values to include in a 'T' (stop reply) packet. The RDA library will initially call next_expedited_reg() with reg_nr set to -1 in order to obtain the first register (as the return value of the callback), and will, on successive calls, be called with the previous return value. A negative value should be returned when there are no more values to return. Although the ``next_expedited_reg'' callback is optional, it is strongly recommended that you implement it. Defining this method will permit the RDA library to send register values to GDB that it will almost certainly need. Examples of registers that should be included in the 'T' packet include the stack pointer and program counter. If this callback is not defined, RDA will not send any registers to GDB in the stop reply packet. GDB will then need to use a 'g' packet to retrieve all values (even if all values aren't required). The ``reg_format'' method describes format of the register given by reg_nr in the 'g' and 'G' packets. This method should set ``size'' to the width (in bytes) of the register given by ``reg_nr''. (Due to the representation of bytes in the remote protocol, 2*size bytes will actually be input or output.) If padding is required in the 'g' or 'G' packet, then ``padding'' should be set to the number of bytes of padding required. Again, 2*size bytes will be actually be output. A negative value of padding indicates that the padding should preceded the register value. A positive value places the padding after the register value. Note that the ``size'' and ``padding'' parameters are actually pointers, and that suitable pointer dereferencing is required when setting these as return values. The ``set_thread_reg'' method is used to change the value of the register specified by ``regnr'' to that of the value specified in ``reg'' parameter. (The new register value does not actually need to be set until the target is made to run again (in some fashion). Thus, it is permissible for your target specific code to accumulate the changes to be made to the registers and update them all at once if that is more efficient or convenient.) Return 0 if successful, or -1 if not. The ``get_thread_reg'' method is used to retrieve the value of the register specified by ``regnr''. The value should be placed in ``reg''. Return 0 if successful, or -1 if not. The non-threaded register related callbacks are as follows: int (*input_reg) (struct gdbserv *gdbserv, struct gdbserv_reg *reg, int len); void (*output_reg) (struct gdbserv *gdbserv, struct gdbserv_reg *reg, int len); int (*gg_reg_nr) (struct gdbserv *, int index); int (*expedited_reg_nr) (struct gdbserv *, int index); long (*sizeof_reg) (struct gdbserv *, int regnr); int (*set_reg) (struct gdbserv *, int regnr, struct gdbserv_reg *reg); int (*get_reg) (struct gdbserv *, int regnr, struct gdbserv_reg *reg); Each of these methods is passed passed a pointer to a gdbserv object. The ``input_reg'' method should be set to one of two predefined methods, either gdbserv_input_reg_beb(), for reading big endian data, or gdbserv_input_reg_leb(), for reading little endian data. It is unlikely that you'll need to define some custom method for reading or writing data. Likewise, the ``output_reg'' method should be set to one of two predefined methods, either gdbserv_output_reg_beb() or gdbserv_output_leb(). Again, it is unlikely that you'll need to define some custom method for reading or writing data. The ``gg_reg_nr'' method is used by the RDA library to obtain register numbers for 'G' or 'g' packets. (A 'g' packet is used to read general purpose registers. A 'G' packet is used to write them.) The library will initially invoke this method with index set to 0 and will successively increase the value passed as index by 1 until gg_reg_nr returns a negative value. This method should return the register number associated with the given index (in the 'g' or 'G' packet). It should do so even if there is a hole or undefined register in the packet, and only return -1 when there truly are no more registers. The ``expedited_reg_nr'' method works the same as ``gg_reg_nr'' except that it specifies the registers in a 'T' (stop reply) packet. See the discussion above for ``next_expedited_reg''. The ``sizeof_reg'' method is used to return the size in bytes of the register specified by ``regnr''. (The ``regnr'' value passed to sizeof_reg() is obtained from either gg_reg_nr() or expedited_reg_nr(). See above.) Due to the way that register values are transmitted using the GDB remote protocol, 2*size bytes are actually output. Finally, a negative size (return) value indicates a hole in the 'G' or 'g' packet, i.e. space is allocated in the packet, but there's no corresponding register in your target. The ``set_reg'' method is used to update the value specified by ``regnr'' in your target to that of the value specified by the ``reg'' parameter. Return 0 if successful, -1 if not. The ``get_reg'' method is used to fetch the value specified by ``regrn'' from your target. It should be placed in the gdbserv_reg struct specified by ``reg''. Return 0 if successful, -1 if not. Dealing with gdbserv_reg * values --------------------------------- Some of the callbacks have parameters of type `struct gdbserv_reg *'. This type is used to specify the value of registers, and is quite often used to specify addresses and other integral values as well. The RDA library provides several functions for converting to/from this type and an array of bytes. These functions which put an array of bytes into a gdbserv_reg struct are as follows: void gdbserv_be_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, int buflen, struct gdbserv_reg *reg, int reglen, int sign_extend); void gdbserv_le_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, int buflen, struct gdbserv_reg *reg, int reglen, int sign_extend); void gdbserv_host_bytes_to_reg (struct gdbserv *gdbserv, const void *buf, int buflen, struct gdbserv_reg *reg, int reglen, int sign_extend); In each case, `gdbserv' represents the gdbserv object, `buf' is the array of bytes to to convert, `buflen' is the number of bytes in the buffer `buf', `reg' is the gdbserv_reg struct into which the value should be placed, `reglen' is the size of the register, and `sign_extend' is non-zero iff the value should be sign-extended. (To the best of my knowledge, the only architecture which requires sign extension is MIPS.) Each of these methods handles a different byte order. The ``gdbserv_be_bytes_to_reg'' method converts a buffer of big-endian bytes to the gdbserv_reg format. Likewise, ``gdbserv_le_bytes_to_reg'' and ``gdbserv_host_bytes_to_reg'' convert little endian and host format bytes. The latter method is really a convenience function which just picks either the big endian or little endian formatter based on the endianess of the host that the RDA application is being built upon. For example, suppose you are interfacing the RDA library to a simulator which resides in the same process. If the variable ``regval'' has a register's value, this value may be put into the gdbserv_reg format as follows: unsigned long regval; struct gdbserv_reg regval_as_reg; regval = ... gdbserv_host_bytes_to_reg (serv, ®val, sizeof(regval), &addr_as_reg), sizeof(regval), 0); Conversely, these functions (below) convert the value found in a gdbserv_reg struct into an array of bytes: void gdbserv_be_bytes_from_reg (struct gdbserv *gdbserv, void *buf, int buflen, const struct gdbserv_reg *reg, int sign_extend); void gdbserv_le_bytes_from_reg (struct gdbserv *gdbserv, void *buf, int buflen, const struct gdbserv_reg *reg, int sign_extend); void gdbserv_host_bytes_from_reg (struct gdbserv *gdbserv, void *buf, int buflen, const struct gdbserv_reg *reg, int sign_extend); In each of these functions, ``gdbserv'' is a pointer o the gdbserv object, ``buf'' is a pointer to the array of bytes into which to place a value, ``buflen'' is the length of the buffer ``buf'', ``reg'' is a pointer to the gdbserv_reg struct to convert from, and ``sign_extend'' is non-zero iff sign-extension should be performed in the event that ``buf'' is bigger than the size of the register. Memory Related Callbacks ------------------------ Like the register related callbacks, the memory related callbacks come in two varieties, threaded and non-threaded. You only need to implement one set of these callbacks. The only difference between these callbacks is the fact that a thread object is passed to the threaded-version. Here are the thread aware versions of the memory callbacks: long (*get_thread_mem) (struct gdbserv *, struct gdbserv_thread *, struct gdbserv_reg *addr, void *data, long len); long (*set_thread_mem) (struct gdbserv *, struct gdbserv_thread *, struct gdbserv_reg *addr, void *data, long len); Both of these functions are passed both the gdbserv object and a thread object. The ``addr'' parameter represents the target memory address to either read or write. The ``data'' parameter is a pointer to the buffer to either deposit data into or from which data is written. The ``len'' parameter is the number of bytes that should be read or written. The ``get_thread_mem'' callback attempts to read the specified number of bytes from the target and place them into the buffer. It returns the number of bytes successfully read, or -1 if the memory read completely fails. The ``set_thread_mem'' callback attempts to write the specified number of bytes from the buffer provided to the target's memory. It returns the number of bytes successfully written, or -1 if the memory write completely fails. Here are the non-thread-aware memory callbacks: long (*get_mem) (struct gdbserv *, struct gdbserv_reg *addr, void *data, long len); long (*set_mem) (struct gdbserv *, struct gdbserv_reg *addr, void *data, long len); The gdbserv object is passed to these functions. The ``addr'' parameter represents the target memory address to either read or write. The ``data'' parameter is a pointer to the buffer to either deposit data into or from which data is written. The ``len'' parameter is the number of bytes that should be read or written. The ``get_mem'' callback attempts to read the specified number of bytes from the target and place them into the buffer. It returns the number of bytes successfully read, or -1 if the memory read completely fails. The ``set_mem'' callback attempts to write the specified number of bytes from the buffer provided to the target's memory. It returns the number of bytes successfully written, or -1 if the memory write completely fails. General Query Packets / General Set Packets ------------------------------------------- General query packets start with a 'q' prefix and general set packets begin with a 'Q' prefix. In recent years, nearly all new extensions to the remote protocol have added either a new 'q' or 'Q' packet, or both. There are a number of general query packets defined by the remote protocol. The RDA library currently recognizes the 'qRcmd', 'qCRC:', 'qC', 'qfThreadInfo', 'qsThreadInfo', and 'qThreadExtraInfo' packets. For all other 'q' and 'Q' packets, you will need to implement a callback which parses everything after the 'q' or 'Q', including the packet's parameters (if any), queries the target in an appropriate manner, and then formats and outputs the response. When a unrecognized 'q' packet is received from the client, the ``process_get_gen'' method is called. Here's the prototype: void (*process_get_gen) (struct gdbserv *); When any 'Q' packet is received from the client, the ``process_set_gen'' method is called. Here's the prototype: void (*process_set_gen) (struct gdbserv *); The 'qRcmd' packet is used to invoke arbitrary target specific commands. Results from these commands are usually directly printed out to GDB's console. Reciept of the qRcmd packet causes ``process_rcmd'' callback to be invoked. Here's the prototype: void (*process_rcmd) (struct gdbserv *, const char *cmd, int sizeof_cmd); Each of these callbacks is passed a pointer to a gdbserv object. The ``process_rcmd'' callback is passed two additional parameters, ``cmd'', a string representing the target specific command, and ``sizeof_cmd'' which represents the length of ``cmd''. (Do not assume that ``cmd'' will be null-terminated.) When implementing either the ``process_get_gen'' or ``process_set_gen'' callbacks, the following function is useful for parsing reset of the packet name (and delimiters associated with any arguments): int gdbserv_input_string_match (struct gdbserv *gdbserv, const char *string); gdbserv_input_string_match() will attempt to compare the next portion of the input packet against the characters in ``string''. If an exact match is found, the number of characters matched is returned and that number of characters is advanced in the input packet. If the characters in ``string'' are not matched exactly, and in their entirety, -1 is returned. Hex encoded numeric arguments may be parsed from the 'q' or 'Q' packet by invoking gdbserv_input_hex_long() or gdbserv_input_hex_ulong(): int gdbserv_input_hex_long (struct gdbserv *gdbserv, long *val); int gdbserv_input_hex_ulong (struct gdbserv *gdbserv, unsigned long *val); In both of these functions, the ``val'' parameter is a pointer to either a long or unsigned long into which to put the decoded integer. If no number could be matched, a -1 is returned. There are a number of functions which may be used to compose and output a reply. Here are several of the more useful ones: void gdbserv_output_string (struct gdbserv *gdbserv, const char *buf); void gdbserv_output_string_as_bytes (struct gdbserv *gdbserv, const char *buf); void gdbserv_output_bytes (struct gdbserv *gdbserv, const char *buf, unsigned sizeof_buf); gdbserv_output_string() outputs the string specified by ``buf'' verbatim. gdbserv_output_string_as_bytes() outputs a string, ``buf'', as a hex encoded value. Finally, gdbserv_output_bytes(), outputs an abitrary sequence of bytes given by ``buf'' with length ``sizeof_buf'' as a hex encoded value. There exist several other "gdbserv_input_" and "gdb_serv_output_" prefixed functions. Declarations for these may be found in include/gdbserv.h. Callback for Setting Program Arguments -------------------------------------- The 'A' packet is used to set program arguments. When the 'A' packet is recognized, the process_set_args() callback is invoked. It has the following prototype: void (*process_set_args) (struct gdbserv *); Notice that the library does not decode the arguments. Suitable calls to the various "gdbserv_input_" functions must be called to parse these arguments. Callback for setting the PC --------------------------- When a 'c' or 's' (continue or singlestep) packet is received with the address to continue from the ``process_set_pc'' callback is invoked. Its prototype is as follows: void (*process_set_pc) (struct gdbserv *, const struct gdbserv_reg *val); The ``val'' parameter species the PC value to set. Callback for Flushing the Instruction Cache ------------------------------------------- The ``flush_i_cache'' callback is invoked prior to continuing or singlestepping the program. This callback should do whatever operations are required in order to invalidate the instruction cache. Its prototype is: void (*flush_i_cache) (struct gdbserv *); Signal Related Callbacks ------------------------ Non-threaded targets should define the ``process_signal'' callback. This callback specifies the signal to deliver to the target when either a 'C' or 'S' packet is used. (The 'C' packet continues the program with a given signal; the 'S' packet singlesteps the program with the given signal.) The prototype for ``process_signal'' is: int (*process_signal) (struct gdbserv *, int sigval); The ``sigkill_program'' method is invoked if ``process_signal'' fails to deliver a signal. This method will not deliver the desired signal, but should instead kill the program. This method should not really be needed so long as the ``process_signal'' exists and works properly. Here's the prototype: void (*sigkill_program) (struct gdbserv *); There are two other signal related callbacks, ``compute_signal'' and ``get_trap_number''. Neither of these are called by the RDA library though. New RDA applications do not need to define these callbacks. Target State/Control Callbacks -------------------------------- The ``exit_program'' callback is invoked when a 'k' (kill) packet is received from the client. It's prototype is as follows: void (*exit_program) (struct gdbserv *); The ``break_program'' callback is invoked when a request to halt, suspend, or break the target is received from the client. This callback should do whatever is necessary to direct the target to stop. Later, when the target has actually stopped, the function gdbserv_fromtarget_break() should be called to indicate that it has indeed stopped. The ``break_program'' callback must NOT call gdbserv_fromtarget_break(). Here's the prototype: void (*break_program) (struct gdbserv *); The ``reset_program'' callback is invoked when an 'r' (reset system) packet is recieved from the client. The ``reset_program'' callback is invoked when an 'R' (reset program) packet is received. The prototypes for these methods are as follows: int (*reset_program) (struct gdbserv *); void (*restart_program) (struct gdbserv *); The ``singlestep_thread'' or ``singlestep_program'' callbacks are invoked for 's' (singlestep) or 'S' (singlestep with signal) packets. Only one of these methods needs to be implemented. If the ``singlestep_thread'' method is defined, it will be tried before the ``singlestep_program'' is invoked. The ``singlestep_thread'' method is passed a pointer to a gdbserv object, a pointer to a thread object, as well as the signal, ``siggnal'' to continue with. The ``singlestep_program'' method is only passed the gdbserv object. Care must be taken to also define ``process_signal'' when only ``singlestep_program'' is defined. Here are the prototypes: void (*singlestep_thread) (struct gdbserv *, struct gdbserv_thread *, const struct gdbserv_reg *signnal); void (*singlestep_program) (struct gdbserv *); The ``cyclestep_thread'' and ``cyclestep_program'' callbacks are invoked in response to an 'i' (cycle step) packet. Only one of these methods need to be define, and as before, the thread-specific method is tried first. The prototypes are as follows: void (*cyclestep_thread) (struct gdbserv *, struct gdbserv_thread *, const struct gdbserv_reg *signnal); void (*cyclestep_program) (struct gdbserv *); The ``continue_thread'' or ``continue_program'' callbacks are invoked in response to either a 'c' (continue) or 'C' (continue with signal) packet. As before, only one of these methods needs to be defined. The thread-specific method is tried first. The ``continue_thread'' method is passed the signal, ``signnal'', to continue with (in addition to the gdbserv object and the gdbserv_thread object). The ``continue_program'' method is not passed a signal, thus the ``process_signal'' must be defined in order for the signal to be delivered to the target. Here are the prototypes: void (*continue_thread) (struct gdbserv *, struct gdbserv_thread *, const struct gdbserv_reg *signnal); void (*continue_program) (struct gdbserv *); Breakpoint Callbacks -------------------- The ``set_breakpoint'' and ``remove_breakpoint'' callbacks are invoked in response to the 'z' (set breakpoint) and 'Z' (remove breakpoint) packets respectively. If these operations do are not defined here, that fact will be reported to GDB and GDB will attempt to set software breakpoints via reads and writes to memory. The prototypes for these callbacks are as follows: enum gdbserv_target_rc (*set_breakpoint) (struct gdbserv *, enum gdbserv_target_bp type, struct gdbserv_reg *addr, struct gdbserv_reg *len); enum gdbserv_target_rc (*remove_breakpoint) (struct gdbserv *, enum gdbserv_target_bp type, struct gdbserv_reg *addr, struct gdbserv_reg *len); The return status codes (of type enum gdbserv_target_rc) for these methods may be one of the following: GDBSERV_TARGET_RC_ERROR - Operation failed; reply with an 'Enn' error. (The breakpoint methods reply with 'E03'.) GDBSERV_TARGET_RC_OK - Operation succeeded; reply with 'OK'. GDBSERV_TARGET_RC_UNKNOWN - Operation not supported; send no reply. This null reply signals to GDB that the operation is not supported. For many operations, GDB will attempt to find an alternate mechanism to use, or will continue on as best as it can. The ``type'' parameter for these methods (of type enum gdbserv_target_bp) may be one of the following: GDBSERV_TARGET_BP_SOFTWARE - Software breakpoint. GDBSERV_TARGET_BP_HARDWARE - Hardware breakpoint. GDBSERV_TARGET_BP_WRITE - Write watchpoint. GDBSERV_TARGET_BP_READ - Read watchpoint. GDBSERV_TARGET_BP_ACCESS - Access (read or write) watchpoint. Note too that the address, ``addr'', at which to set the breakpoint or watchpoint is specified using a gdbserv_reg struct. The length, ``len'', is also specified using this type. See the section entitled "Dealing with gdbserv_reg * values" for a list of functions which may be used for accessing the values stored in these containers. Thread Related Callbacks ------------------------ The ``thread_info'' callback is called in response to the 'qThreadExtraInfo' packet. It allocates and returns a string containing printable information about the thread specified by the parameter ``thread''. This information is returned to GDB for use in its "info threads" command. Its prototype is as follows: char *(*thread_info) (struct gdbserv *, struct gdbserv_thread *thread); The ``thread_id'' callback is used to map the thread specified by ``thread'' to a unique identifier (an integer) shared between GDB and the RDA application. The integer needs to be placed into a gdbserv_reg container. Its prototype is as follows: char *(*thread_info) (struct gdbserv *, struct gdbserv_thread *thread); The ``thread_lookup_by_id'' callback is used to map a thread id, ``id'', to a thread, ``thread'', of type ``struct gdbserv_thread *''. It should return a positive integer if ``id'' uniquely identifies a thread. It should return 0 and select an arbitrary thread if the thread ID is zero. Otherwise, it should return -1 and select an arbitrary thread if the ID does not uniquely identify a thread or if the thread id is invalid. Here's the prototype: int (*thread_lookup_by_id) (struct gdbserv *, const struct gdbserv_reg *id, struct gdbserv_thread **thread); The ``thread_next'' callback is used to iterate over all threads known to the RDA application. The GDB library will start off by calling the ``thread_next'' callback with the ``thread_last'' parameter set to NULL and expect the first thread to be returned. (It doesn't really matter which thread is first, so long as all threads are eventually enumerated.) On successive calls, ``thread_next'' will be called with the previous thread returned as the value of ``thread_last'', with the expectation that the next (for some suitable meaning of "next") thread be returned. When there are no more threads, NULL is returned. Here's the prototype: struct gdbserv_thread *(*thread_next) (struct gdbserv *, struct gdbserv_thread *thread_last); Unknown Packet Callback ----------------------- The ``process_target_packet'' callback is invoked when a packet is seen that does not start with one of the letters used by the remote protocol. Here's the prototype: void (*process_target_packet) (struct gdbserv *); Note: This method is probably not all that useful given that the leading packet character is consumed by the the caller of the ``process_target_packet'' callback. Shutdown Callback ----------------- The ``detach'' callback is invoked when an end-of-file condition is sensed on the input stream. Note that the second parameter, ``target'' is a pointer to the data structure containing the list of callbacks originally allocated by the ``attach'' method. It is passed to the ``detach'' callback so that the callback struct can be deallocated. Here's the prototype: void (*detach) (struct gdbserv *, struct gdbserv_target *target);