ARM Remote Debug Interface
==========================


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

The Remote Debug Interface (RDI) is a concrete procedural interface between a 
debugger, and a debuggee via a debug monitor or controlling debug agent. The 
interface can be 'pulled apart' to yield a pair of <stub> interfaces 
communicating via the Remote Debug Protocol (for details see "<ARM Remote Debug 
Protocol>"). 

The RDI gives the ARM symbolic debugger (<armsd>) core a uniform way to 
communicate with:

 *  a controlling debug agent or debug monitor linked with the debugger;

 *  a debug agent executing in a separate operating system process;

 *  a debug monitor running on ARM-based hardware accessed via a communication 
    link.

 *  a debug agent controlling an ARM processor via hardware debug support.

The first structure arises in the variant of <armsd> which is linked with ARM's 
standard ARM emulation environment (for the PC- and Sun-hosted 
cross-development variants of <armsd>), and in the self-hosted, single 
address-space variant of <armsd> (for Acorn's RISC OS operating system).

The second structure would arise in an ARM-Unix-hosted variant of <armsd>, if 
<armsd> and the ARM emulator (the <ARMulator>) were run in separate Unix 
processes (perhaps on separate machines). In this case, the <RDI> would consist 
of two stubs using Unix's remote procedure calls to effect the inter-process 
message passing. 

The third and fourth structures arise when <armsd> is used to control a 
debuggee, executing on ARM-based hardware (for instance on the <Platform 
Independent Evaluation (PIE)> card) connected to <armsd>'s host via a hardware 
debugging channel, (for instance via RS232 as used on the <PIE> card).


The RDI Specification
---------------------


Introduction
............

This document describes a C interface to the Remote Debug Protocol (RDP), 
designed to make using the RDP from a C program easier, and more efficient when 
the debugger and debug agent are linked as one program.

Every function returns an error status. Zero indicates no error, otherwise the 
value returned is the error number (see "<Error Codes>").

It is the caller's responsibility to ensure that memory pointers do indeed 
point to valid memory locations in the debugger's address space.

The RDI is not an entity fixed for all time.  As it evolves, new levels of 
specification are added and within any level of specification there are 
implementation options. This approach is taken so that a variety of minimal 
debug monitors and controlling debug agents can be accommodated without 
excessive overhead and so there can be good compatibility between debuggers and 
debug monitors released at different times. As a result, a debugger using the 
RDI must <negotiate> to establish its debuggee's capabilities and must not use 
capabilities its debuggee does not have. These issues are highlighted in the 
following sections.


RDI Functions
.............

    Purpose                         Function Name

    Open and/or Initialise Debuggee RDI_open(type,memorysize,bytesex)

    Close and Finalise Debuggee     RDI_close()

    Read Memory Address             RDI_read(source,dest,nbytes)

    Write Memory Address            RDI_write(source,dest,nbytes)

    Read CPU State                  RDI_CPUread(mode,mask,state)

    Write CPU State                 RDI_CPUwrite(mode,mask,state)

    Read Co-Processor State         RDI_CPread(CPnum,mask,state)

    Write Co-Processor State        RDI_CPwrite(CPnum,mask,state)

    Set Breakpoint                  RDI_setbreak(address,type,
                                          bound,point*)

    Clear Breakpoint                RDI_clearbreak(point)

    Set Watchpoint                  RDI_setwatch(address,type,
                                          datatype,bound,point*)

    Clear Watchpoint                RDI_clearwatch(point)

    Execute                         RDI_execute(point*)

    Multiple Step                   RDI_step(ninstr,point*)

    Break/watch inquiry             RDI_pointinquiry(address*,type,
                                          datatype,bound*)

    Miscellaneous Info              RDI_info(type,arg1,arg2)


Open and/or Initialise Debuggee
...............................

    int RDI_open(unsigned type, unsigned long memorysize, unsigned sex)

The <type> argument is used to distinguish between types of initialisation:

    Bit 0 = 0     cold start (execute bootstrap, initialise MMU etc.).

    Bit 0 = 1     warm start (terminate execution, reset processor state etc.).

    Bit 1 = 1     reset the communication link.

The <memorysize> argument is used to specify the minimum amount of memory the 
debuggee environment must have. A value of zero can be used if the debugger is 
not concerned with the memory size.

The <sex> argument indicates the byte order to be used by the debuggee. It 
takes one of three values:

 *  <RDISex_Little> or <RDISex_Big> force the debuggee to be that endianness, 
    and debuggees capable of switching endianness should assume the endianness 
    requested. Debuggees that cannot switch endianness should return 
    <RDIError_WrongByteSex>.

 *  The third value, <RDISex_DontCare> may be passed by the debugger, and the 
    debuggee should respond with its byte sex as an error code, either 
    <RDIError_LittleEndian> or <RDIError_BigEndian>. Note this does not signify 
    an error.


Close and Finalise Debuggee
...........................

    int RDI_close()

<RDI_close> is used to terminate the current debugging session. Only a call to 
<RDI_open> may follow this call.


Read Memory Address
...................

    int RDI_read(unsigned long source, void *dest, unsigned *nbytes)

<RDI_read> transfers data from the debuggee's memory to the debugger. Bytes are 
read from the debuggee at address <source>, and stored at location <dest> in 
the caller's address space. <nbytes> points to the number of bytes to transfer. 
On return, the location pointed to by <nbytes> contains the number of bytes 
that were successfully transferred. If an error occurs, the state of the memory 
at <dest> is undefined.


Write Memory Address
....................

    int RDI_write(void *source, unsigned long dest, unsigned *nbytes)

<RDI_write> transfers data from address <source> in the debugger to address 
<dest> in the debuggee. <nbytes> points to the number of bytes to transfer. On 
return, the location pointed to by <nbytes> contains the number of bytes that 
were successfully transferred. If an error occurs, the state of the memory at 
<dest> is undefined.


Read CPU State
..............

    int RDI_CPUread(unsigned mode, unsigned long mask, unsigned long state[])

<RDI_CPUread> allows the debugger to read the values of the debuggee's CPU 
registers.

The <mode> argument defines the ARM processor mode from which the transfer 
should be made. A value of <RDIMODE_Curr> indicates that the prevailing 
processor mode should be used.

The <mask> argument indicates which registers should be transferred. Bit 0 of 
this word corresponds to register 0; bit 14 corresponds to the link register; 
and bit 15 the Program Counter, (including the mode and flag bits in 26-bit 
modes).

Other values can be ORed into the mask to retrieve other registers:

 *  <RDIReg_PC> to get just the Program Counter value; 

 *  <RDIReg_CPSR> to get the value of the CPSR; 

 *  <RDIReg_SPSR> to get the value of the SPSR in non user modes.

Notice that the value of Program Counter that is returned (via either bit 15 or 
RDIReg_PC) has already had the effect of pipelining removed, thus it is 8 less 
than the actual value in the Program Counter. The <state> argument is a pointer 
to enough words of memory in which to save the CPU state (4 bytes per 
register). The requested registers are saved contiguously into this memory.


Write CPU State
...............

    int RDI_CPUwrite(unsigned mode, unsigned long mask, unsigned long state[])

RDI_CPUwrite allows the debugger to set the values of the debuggee's CPU 
registers. The arguments are as for RDI_CPUread, except that register values 
are read from <state> and written to the debuggee's register set.


Read Co-Processor State
.......................

    int RDI_CPread(unsigned CPnum, unsigned long mask, unsigned long state[])

RDI_CPread allows the debugger to read the debuggee's co-processor registers; 
(it has a similar function to RDI_CPUread, except that the register values are 
taken from the co-processor whose number is specified by the <CPnum> argument). 
The actual registers transferred, and their size is dependent on the 
co-processor specified. The transferred values are written to <state>.

By convention, the following co-processors are understood:

 *  Co-processor 1 (and 2 in the case of FPA) is a floating point unit. Bits 0 
    to 7 of <mask> request the transfer co-processor registers 0 to 7. Bit 8 
    designates the floating point status register (FPSR), and bit 9 the 
    floating point command register (FPCR).

 *  Co-processor 15 is a memory management unit (e.g. ARM3's or ARM600's). Bits 
    0 to 7 of <mask> request transfer of MMU registers 0 to 7.


Write Co-Processor State
........................

    int RDI_CPwrite(unsigned CPnum, unsigned long mask, unsigned long state[])

<RDI_CPwrite> allows the debugger to write the values of the debuggee's 
co-processor registers; (it has a similar function to <RDI_CPUwrite>, except 
that the register values are written to the co-processor whose number is given 
by <CPnum>). The actual registers transferred, and their size is dependent on 
the co-processor specified. The transferred values are read from <state>.

Currently the following co-processors are understood:

 *  Co-processor 1 (and 2 in the case of FPA) is a floating point unit. Bits 0 
    to 7 of <mask> request transfer of data to co-processor registers 0 to 7. 
    Bit 8 designates the floating point status register (FPSR), and bit 9 the 
    floating point command register (FPCR).

 *  Co-processor 15 is a memory management unit (e.g. ARM3's or ARM600's). Bits 
    0 to 7 of <mask> request transfer to MMU registers 0 to 7.


Set Breakpoint
..............

    int RDI_setbreak(unsigned long address, unsigned type,
          unsigned long bound, PointHandle *point)

<RDI_setbreak> requests the debuggee to set an execution breakpoint at <address>
. The <type> argument defines the sort of breakpoint to set:

    RDIPoint_EQ         halt execution if the pc is equal to <address>.

    RDIPoint_GT         halt execution if the pc is greater than <address>.

    RDIPoint_GE         halt execution if the pc is greater than or equal to
                        <address>.

    RDIPoint_LT         halt execution if the pc is less than <address>.

    RDIPoint_LE         halt execution if the pc is less than or equal to
                        <address>.

    RDIPoint_IN         halt execution if the pc is in the address range from
                        <address>. to <bound>, inclusive.

    RDIPoint_OUT        halt execution if the pc is not in the address range
                        <address> to <bound>, inclusive.

    RDIPoint_MASK       halt execution if (pc & <bound>) =  <address>.

In addition, bit 5 of <type> indicates whether the breakpoint should be 
<conditional>. If it is set, execution halts only when the breakpointed 
instruction is executed, not when the condition code causes it to be  skipped. 
Otherwise, Breakpoints are unconditional: execution halts when the breakpoint 
is reached, no matter what the condition field of the breakpointed instruction.

If the call succeeds, <*point> is set to a value which identifies the 
breakpoint. At RDI specification level 0, a breakpoint is identified by its 
address (the value of <address>); at levels 1 and above it is identified by a 
handle returned by the debuggee (see "<RDIInfo_Target>").

A special return value, <RDIError_NoMorePoints>, indicates that the call to 
<RDI_setbreak> was successful but that there are no more breakpoint resources 
of this type available.

The return value <RDIError_CantSetPoint> indicates that the call failed because 
the debugee currently has insufficient breakpoint resources available to honour 
this request.

If a breakpoint is set on a location which already has a breakpoint, the first 
breakpoint will be removed before the new breakpoint is set.


Clear Breakpoint
................

    int RDI_clearbreak(PointHandle point)

<RDI_clearbreak> clears the execution breakpoint identified by <point >which 
was set by a previous call to <RDI_setbreak>.


Set Watchpoint
..............

    int RDI_setwatch(unsigned long address, unsigned type, unsigned
          datatype, unsigned long bound, PointHandle *point)

<RDI_setwatch> sets a data access watchpoint at <address> in the debuggee. <type> 
defines the sort of watchpoint to set:

    RDIPoint_EQ         halt on a data access to the address equal to
                        <address>.

    RDIPoint_GT         halt on a data access to an address greater than
                        <address>.

    RDIPoint_GE         halt on a data access to an address greater than or
                        equal to <address>.

    RDIPoint_LT         halt on a data access to an address less than
                        <address>.

    RDIPoint_LE         halt on a data access to an address less than or
                        equal to <address>.

    RDIPoint_IN         halt on a data access to an address in the range from
                        <address> to <bound>, inclusive.

    RDIPoint_OUT        halt on a data access to an address not in the range
                        from <address> to <bound>, inclusive.

    RDIPoint_MASK       halt execution if (<data-access-address> & <bound>) =  
    <address>.

The <datatype> argument defines the sort of data access to watch for:

    RDIWatch_ByteRead         watch for byte reads;

    RDIWatch_HalfRead         watch for half-word reads;

    RDIWatch_WordRead         watch for word reads;

    RDIWatch_ByteWrite        watch for byte writes;

    RDIWatch_HalfWrite        watch for half-word writes;

    RDIWatch_WordWrite        watch for word writes.

Values may be summed or ORed together in order to halt on any of a set of sorts 
of memory access. For example:

    RDIWatch_ByteWrite + RDIWatch_HalfWrite + RDIWatch_WordWrite

to watch for any write access to the specified location(s).

If the call succeeds, <*point> is set to a value which identifies the 
watchpoint to the debugee. At RDI specification level 0, a watchpoint is 
identified by its address (the value of <address>); at levels 1 and above it is 
identified by a handle returned by the debuggee (see "<RDIInfo_Target>" 
starting on page80).

A special return value, <RDIError_NoMorePoints>, indicates that the call to 
<RDI_setwatch> was successful, but that there are no more watchpoint resources 
of this type available.

The return value <RDIError_CantSetPoint> indicates that the call failed because 
the debugee currently has insufficient watchpoint resources to honour this 
request.

If a watchpoint is set on a location which already has a watchpoint, the first 
watchpoint will be removed before the new watchpoint is set.


Clear Watchpoint
................

    int RDI_clearwatch(PointHandle point)

<RDI_clearwatch> clears the data access watchpoint identified by <point> which 
was set by a previous call to <RDI_setwatch>.


Execute
.......

    int RDI_execute(PointHandle *point)

<RDI_execute> initiates execution in the debuggee, at the address currently 
loaded into the CPU Program Counter.

If a breakpoint is reached, or a watched address is accessed, or an exception 
occurs, or the user presses Escape, then <RDI_execute> returns an error code 
(see "<Error Codes>").

If a breakpoint or watchpoint caused the return, <*point> will be set to the 
handle identifying  the break/watchpoint. At RDI specification level 0, a 
break/watch-point is identified by its address; at levels 1 and above it is 
identified by a handle returned by the debuggee when the -point was set.


Multiple Step
.............

    int RDI_step(unsigned ninstr, PointHandle *point)

<RDI_step> initiates execution in the debuggee at the address currently loaded 
into the CPU Program Counter, but only executes the number of instructions 
specified by <ninstr>.

If <ninstr> is zero, the debuggee executes instructions up to the next 
instruction that explicitly alters the program counter, (i.e. a branch or ALU 
operation with the program counter as destination).

If a breakpoint is reached, or a watched address is accessed, or an exception 
occurs, or the user presses Escape, or the end of the program is reached before 
<instr> instructions have been executed, then <RDI_step> returns an error code 
indicating why execution was suspended (see "<Error Codes>"
).

If a breakpoint or watchpoint caused the return, <*point> will be set to the 
handle identifying  the break/watchpoint. At RDI specification level 0, a 
break/watch-point is identified by its address; at levels 1 and above it is 
identified by a handle returned by the debuggee when the -point was set.


Break/Watch-Point Inquiry
.........................

    int RDI_pointinquiry(unsigned long *address, unsigned type,
          unsigned datatype, unsigned long *bound)

For inquiries about breakpoints, <datatype> must be 0. Otherwise, <type> and 
<datatype> are precisely as in corresponding calls to <setbreak> and <setwatch>
.

<RDI_pointinquiry> returns information about what will happen if a 
corresponding call is made to <setbreak> or <setwatch>. (for range and 
comparison point types, the debuggee is permitted to do its best to honour the 
request and is not required to use precisely the address and bound requested).

If the break/watch type is supported then <address> and, if applicable, <bound> 
are updated to the values that will be used if a break- or watch-point is set.

If it will be impossible to honour the corresponding break/watch-point request 
for for lack of break/watch-point resources, the value <RDIError_NoMorePoints> 
is returned.

Note that the <absence> of a return value of <RDIError_NoMorePoints> from 
<setbreak> or <setwatch> does <not> mean that the next request can be honoured, 
but merely that there is some value of <type> and <datatype> for which a 
following request can be honoured. To be sure that a request will be honoured, 
it is necessary to call <RDI_pointinquiry>.


Miscellaneous Info
..................

    int RDI_info(unsigned type, unsigned long *arg1, unsigned long *arg2)

This routine is used to transfer miscellaneous information between the debugger 
and the debuggee. Not all types make use of all three arguments.

The information transferred is dependent on the value of the first argument:

    RDIInfo_Target      Return information about the debuggee to the debugger 
                        memory locations addressed by <arg1> and <arg2>.

    RDIInfo_Points      Return information about the debuggee's 
                        breakpointing/watchpointing capabilities to the 
                        debugger memory location addressed by <arg1>, as 
                        described below.

    RDIInfo_Step        Return information about the debuggee's single-stepping 
                        capabilities to the debugger memory location addressed 
                        by <arg1>, as described below.

    RDIInfo_MMU         Return details of the memory manager used by the 
                        debuggee to the debugger memory location addressed by 
                        <arg1>, (the value returned is a unique identifier for 
                        the type of memory manager used by the debuggee).

    RDISignal_Stop      The debuggee should halt execution immediately, (if the 
                        debuggee is not currently executing, the signal has no 
                        effect).

    RDIVector_Catch     Tell the debuggee which hardware exceptions should be 
                        reported to the debugger. <arg1> describes the set of 
                        exceptions to be reported, as described below. when an 
                        exception is reported to the debugger, the state of the 
                        debuggee is rewound to the state which pertained just 
                        before execution of the faulting instruction.

    RDICycles           The debuggee returns, to the buffer addressed by <arg1>
                        , the number of instructions and the number of S, N, I, 
                        C, and F cycles executed since it was initialised.

    RDIErrorP           The debuggee returns, to the memory location addressed 
                        by arg1, the error pointer associated with the last 
                        return from <RDI_Execute> with status <RDIError_Error>.

    RDISet_Cmdline      Set the debuggee's command line arguments before 
                        commencing execution. <arg1> is a pointer to a 
                        NUL-terminated argument string, which must be no longer 
                        than 256 bytes (inclusive of the NUL).

    RDISet_RDILevel     Set the RDI/RDP protocol level to be used between the 
                        debugger and the debuggee. The level set must lie 
                        between the limits returned by <RDIInfo_Target>.

    RDISet_Thread       Set the thread context for thread-sensitive functions 
                        such as break- and watch-point setting.

    RDIInfo_Log         Return the RDI's and RDP's logging state in the integer 
                        variable addressed by <arg1>. Bit 0 is set when logging 
                        calls to RDI interfaces; bit 1 when logging RDP 
                        transactions

    RDIInfo_SetLog      Set the RDI's and RDP's logging state to the integer 
                        value addressed by <arg1>. Bit 0 is set to log calls to 
                        RDI interfaces; bit 1 to log RDP transactions

    RDIInfo_DescribeCoProDescribes the registers of a coprocessor. <arg1> is a 
                        pointer to an integer containing the coprocessor number 
                        <arg2> is a pointer to a structure describing the 
                        registers

A status value is returned to indicate success or failure of the call.


RDIInfo_Target

Following a call of type <RDIInfo_Target>, the value addressed by <arg1> should 
be interpreted as follows:

 *  bits 8,9,10: the minimum RDI specification level (0-7) required of the 
    debugger by the debugee; 

 *  bits 5,6,7: the maximum RDI specification level (0-7) implemented by the 
    debugee; 

 *  bit 4 = 0: debuggee is running under a software emulator; 

 *  bit 4 = 1: debuggee is running on ARM hardware; 

 *  bits 0:3: host speed as 10**(bits 0:3) instruction per second (IPS)    (0 
    => 1IPS, 1 => 10IPS, 2 => 100IPS, 3 = 1000IPS, ..., 6 => 1MIPS, ...).

The value addressed by <arg2> is a unique identifier, which identifiers the ARM 
processor or ARM emulator that the debuggee is running under.

Bits 5..10 allow a debugger to negotiate a suitable RDI specification level 
with a debuggee or to report gracefully that it is incompatible with the 
debuggee.


RDIInfo_Points

After a call of type <RDIInfo_Points>, the word addressed by <arg1> should be 
interpreted as a set of bits as follows:

    bit 0:  comparison break/watch-points are supported;

    bit 1:  range break/watch-points are supported;

    bit 2:  watchpoints for byte reads are supported;

    bit 3:  watchpoints for half-word reads are supported;

    bit 4:  watchpoints for word reads are supported;

    bit 5:  watchpoints for byte writes are supported;

    bit 6:  watchpoints for half-word writes are supported;

    bit 7:  watchpoints for word writes are supported;

    bit 8:  mask break/watch-points are supported;

    bit 9:  thread-specific breakpoints are supported;

    bit 10: thread-specific watchpoints are supported;

    bit 11: conditional breakpoints are supported.

If none of bits 2-7 are set then bits 0, 1, 8 apply only to breakpoints. 
Otherwise, bits 0, 1, 8 apply to both breakpoints and watchpoints

All debuggees support breakpoints of sort <RDIPoint_EQ>, (break at specified 
address), so there is no bit denoting this in the value returned by 
<RDIInfo_Points>.


RDIInfo_Step

After a call of type <RDIInfo_Step>, the location addressed by <arg1> should be 
interpreted as follows:

    bit 0:  single stepping of more than one instruction is supported;

    bit 1:  single stepping to the next direct PC alteration is supported;

    bit 2:  single stepping of a single instruction is supported.


RDI_Vector_Catch

A set bit in <arg1> indicates to the debuggee that the corresponding exception 
should be reported to the debugger, as follows:

    bit 0:  Branch through 0

    bit 1:  Undefined instruction

    bit 2:  Software interrupt (SWI)

    bit 3:  Prefetch abort

    bit 4:  Data abort 

    bit 5:  Address exception 

    bit 6:  Interrupt (IRQ) 

    bit 7:  Fast interrupt (FIQ)

    bit 8:  Error

Bits which are 0 indicate that the corresponding exception vector should be 
taken by the debuggee.


RDISet_RDILevel

Set the RDI level to the value of <arg1>. The level set must lie between the 
limits returned by <RDIInfo_Target>. 


RDISet_Thread

Set the thread context (for the interpretation of breakpoint and watchpoint 
requests) to the thread whose handle is given by arg1. The special value 
<RDINoHandle> resets the context to no thread, that is to the underlying 
hardware processor.


Error Codes
-----------

The symbolic values named here are defined in the file rdi.h. In each case, "
RDIError_" must be prepended to the name shown below. 

    Error Name                Possible cause

    NoError                   Everything worked

    Reset                     Debuggee reset

    UndefinedInstruction      Tried to execute an undefined instruction

    SoftwareInterrupt         A SWI happened

    PrefetchAbort             Execution ran into unmapped memory

    DataAbort                 No memory at the specified address

    AddressException          Accessed > 26 bit address in 26 bit mode

    IRQ                       An interrupt occurred

    FIQ                       A fast interrupt occurred

    Error                     A software error occurred

    BranchThrough0            Branch through location 0

    NoMorePoints              That's the last of the break/watchpoints

    CantSetPoint              Break/watch-point resources exhausted

    BreakpointReached         What RDI_execute and RDI_step can return ...

    WatchpointAccessed        ... or this

    ProgramFinishedInStep     End of the program reached while stepping

    UserInterrupt             User pressed Escape

The following errors indicate misuse of the RDI or similar problem: 

    Error Name                Possible cause

    NotInitialised            RDI_open must be the first call

    UnableToInitialise        The target world is broken

    WrongByteSex              The debuggee can't operate with the requested
                              byte sex.

    UnableToTerminate         Target world was smashed by the debuggee

    BadInstruction            It is illegal to execute this instruction

    IllegalInstruction        The effect of executing this is undefined 

    BadCPUStateSetting        Tried to set the SPSR of user mode

    UnknownCoPro              This co-processor is not connected

    UnknownCoProState         Don't know what to do with this co-pro request 

    BadCoProState             Recognisably broken co-pro request 

    BadPointType              Misuse of the RDI (user
    UnimplementedType         failed to read the 
    BadPointSize              documentation properly?)

    UnimplementedSize         Half words not yet implemented

    NoSuchPoint               Tried to clear a break/watch point that did not 
    exist

The following errors are not really errors, but are just a means of passing 
information. 

    Error Name                Possible cause

    LittleEndian              The debuggee is little endian 

    BigEndian                 The debuggee is big endian

The following errors indicate an internal fault or limitation:

    Error Name                Possible cause

    InsufficientPrivilege     Supervisor state was not accessible to this debug
                              monitor

    UnimplementedMessage      Debuggee can't honour this RDP request

    UndefinedMessage          Garbled RDP request 

    IncompatibleRDILevel      There is no common RDI level at which the 
    debugger
                               and debuggee can operate.

