www.riscos.com Technical Support: |
|
The debugger is a module that allows a program to be stopped at set places called breakpoints. Whenever the instruction that a breakpoint is set on is reached, a command line will be entered. From here, you can type debug commands and resume the program when you want.
Other commands may be called at any time to examine or change the values contained at particular addresses in memory and to list the contents of the registers. You can display memory as words or bytes.
There is also a facility to disassemble instructions. This means converting the instruction, stored as a word, into a string representation of its meaning. This allows you to examine the code anywhere in readable memory.
The debugger provides one SWI, Debugger_Disassemble (SWI &40380), which will disassemble one instruction. There are also the following * Commands:
Command | Description |
---|---|
*BreakClr | Remove breakpoint |
*BreakList | List currently set breakpoints |
*BreakSet | Set a breakpoint at a given address |
*Continue | Start execution from a breakpoint saved state |
*Debug | Enter the debugger |
*InitStore | Fill memory with given data |
*Memory | Display memory between two addresses/register |
*MemoryA | Display and alter memory |
*MemoryI | Disassemble ARM instructions |
*ShowRegs | Display registers caught by traps |
When an address is required, it should be given in hexadecimal. A preceding & is optional; that is, unlike most of the rest of the system, the debugger uses hexadecimal as a default base rather than decimal.
*Quit should be used to return from the debugger to the previous environment after a breakpoint - see *Quit.
Note that the breakpoints discussed here are separate from those caused by OS_BreakPt. See OS_BreakPt for details of this SWI.
When a breakpoint is set, the previous contents of the breakpoint address are replaced with a branch into the debugger code. This means that breakpoints may only be set in RAM. If you try to set a breakpoint in ROM, the error 'Bad breakpoint' will be given.
When a breakpoint instruction is reached, the debugger is entered, with the prompt
Debug*
from which you can type any * Command. An automatic register dump is also displayed.
From RISC OS 3 onwards this module supports ARM 3 instructions, and warns of certain unwise or invalid code sequences (see Appendix B: Warnings on the use of ARM assembler). Some of the output when disassembling has been changed for greater clarity than that provided by RISC OS 2.
R0 = instruction to disassemble
R1 = address to assume the instruction came from
R0 = preserved
R1 = address of buffer containing null-terminated text
R2 = length of disassembled line
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
Not defined
R0 contains the 32-bit instruction to disassemble. R1 contains the address from which to assume the instruction came, which is needed for instructions such as B, BL, LDR Rn, [PC...], and so on. On exit, R1 points to a buffer which contains a zero terminated string. This string consists of the instruction mnemonic, and any operands, in the format used by the *MemoryI instruction. The length in R2 excludes the zero-byte.
None
None
*BreakClr [addr|reg]
addr - hexadecimal address of breakpoint to clear
reg - register containing address of breakpoint to clear
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*BreakClr removes the breakpoint at the specified address or register value, putting the original contents back into that location. You can unset the last hit breakpoint with the command *BreakClr pc
If you give no parameter then you can remove all breakpoints - you will be prompted:
Clear all breakpoints [Y/N]?
*BreakClr 816C
*BreakSet, *BreakList
None
None
*BreakList
None
*BreakList lists all the breakpoints that are currently set with *BreakSet.
*BreakList Address Old Data 0000816C EF00141C
*BreakSet
None
None
*BreakSet addr|reg
addr - hexadecimal address of breakpoint to set
reg - register containing address of breakpoint to set
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*BreakSet sets a breakpoint at the specified address or register value, so that when the code is executed and the instruction at that address is reached, execution will be halted.
When a breakpoint is set, the previous contents of the breakpoint address are replaced with a branch into the debugger code. This means that you may only set breakpoints in RAM. If you try to set a breakpoint in ROM, the error 'Bad breakpoint' is generated.
*BreakSet 816C
*BreakClr, *BreakList, *Continue
None
None
*Continue
None
*Continue resumes execution after a breakpoint, using the saved state. If there is a breakpoint at the continuation position, then this prompt is given:
Continue from breakpoint set at &0000816C
Execute out of line? [Y/N]?
Reply 'Y' if it is permissible to execute the instruction at a different address (ie it does not refer to the PC).
If the instruction that was replaced by the breakpoint contains a PC-relative reference (such as LDR R0,label, a B or BL instruction, or an ADR directive), you should not execute it out of line. Instead you should clear the breakpoint, and then re-issue the *Continue command. The instruction will then be executed in line, avoiding the wrong address being referenced.
*BreakClr, *BreakList, *BreakSet
None
None
*Debug
None
*Debug enters the debugger. A prompt of Debug* appears. Use Escape to return to the caller, or *Quit to exit to the caller's parent.
*Quit is documented on *Quit.
*Quit
None
None
*InitStore [value|reg]
value - word with which to fill user memory
reg - register value with which to fill user memory
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*InitStore fills user memory with the specified value or register value, or with the value &E6000010 (which is an illegal instruction) if no parameter is given. If you give this command from within an application (eg BASIC) the machine will crash, and will have to be reset.
RISC OS 2 used the value &E1000090 instead. This is no longer an illegal instruction for all versions of the ARM processor.
*InitStore &381E6677
None
None
None
*Memory [B] addr1|reg1 *Memory [B] addr1|reg1 [+|-]addr2|reg2 *Memory [B] addr1|reg1 +|-addr2|reg2 +addr3|reg3
B - optionally display as bytes
addr1|reg1 - hexadecimal address, or register containing address for start of display
addr2|reg2 - hexadecimal offset, or register containing offset
addr3|reg3 - hexadecimal offset, or register containing offset
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*Memory displays the values in memory, in bytes if the optional B is given, or in words otherwise.
If only one address is given, 256 bytes are displayed starting from addr1. If two addresses are given, addr2 specifies the end of the range to be displayed (as an absolute address or, if '+' or '-' is present, as an offset from addr1). If three addresses are given, addr2 specifies an offset for the start from addr1, and addr3 specifies the end of the range to be displayed (as an offset from the combined address given by addr1 and addr2).
*Memory 1000 -200 +500 Display memory from &E00 to &12FF
*MemoryA, *MemoryI
None
None
*MemoryA [B] addr|reg1 [value|reg2]
B - optionally display as bytes
addr1|reg1 - hexadecimal address, or register containing address for start of display
value - value to write into the specified location
reg2 - register containing value to write into the specified location
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*MemoryA displays and alters memory in bytes, if the optional B is given, or in words otherwise.
If you give no further parameters, interactive mode is entered. At each line, something similar to the following is printed:
*MemoryA 8000 + 00008000 : x·.. : 00008F78 : ANDEQ R8,R0,R8,ROR PC Enter new value :
or, for byte mode:
*MemoryA B 8001 + 00008001 : · : 8F : Enter new value :
The first character shows the direction in which Return steps ('+' for forwards, '-' for backwards). Next is the address of the word/byte being altered, then the character(s) in that word/byte, then the current hexadecimal value of the word/byte, and finally (for words only) the instruction at that address.
You may type any of the following at the prompt:
Return | to go to the 'next' location |
- | to step backwards in memory |
+ | to step forwards in memory |
hex digits Return | to alter a location and proceed |
. | to exit. |
As an alternative to using this command interactively, you can give the new data value on the line after the address.
*MemoryA 87A0 12345678
*Memory, *MemoryI
None
*MemoryI addr1|reg1 *MemoryI addr1|reg1 [+|-]addr2|reg2 *MemoryI addr1|reg1 +|-addr2|reg2 +addr3|reg3
addr1|reg1 - hexadecimal address, or register containing address for start of display
addr2|reg2 - hexadecimal offset, or register containing offset
addr3|reg3 - hexadecimal offset, or register containing offset
Allowed register names are r0 - r15, sp (equivalent to r13), lr (r14 without the psr bits) and pc (r15 without the psr bits). These are taken from the current ExceptionDumpArea.
*MemoryI disassembles memory into ARM instructions.
If only one address is given, 24 instructions are disassembled starting from addr1. If two addresses are given, addr2 specifies the end of the range to be disassembled (as an absolute address or, if '+' or '-' is present, as an offset from addr1). If three addresses are given, addr2 specifies an offset for the start from addr1, and addr3 specifies the end of the range to be disassembled (as an offset from the combined address given by addr1 and addr2).
These options are particularly useful for disassembling modules, which contain offsets, not addresses.
*modules No. Position Workspace Name ... 22 0184D684 018016B4 Debugger Find address of Debugger ... *memoryi 184D684 +24 0184D684 : .... : 00000000 : ANDEQ R0,R0,R0 0184D688 : \... : 0000005C : ANDEQ R0,R0,R12,ASR R0 0184D68C : (... : 00000128 : ANDEQ R0,R0,R8,LSR #2 0184D690 : .... : 00000104 : ANDEQ R0,R0,R4,LSL #2 0184D694 : (... : 00000028 : ANDEQ R0,R0,R8,LSR #32 0184D698 : >... : 0000003E : ANDEQ R0,R0,R14,LSR R0 0184D69C : h... : 00000168 : ANDEQ R0,R0,R8,ROR #2 0184D6A0 : ... : 00040380 : ANDEQ R0,R4,R0,LSL #7 0184D6A4 : ü... : 000005FC : MULEQ R0,R12,R5 Offset of SWI handler is &5FC Disassemble SWI handler *memoryi 184D684 +5FC +20 0184DC80 : .B-é : E92D4200 : STMDB R13!,{R9,R14} 0184DC84 : .À|ä : E49CC000 : LDR R12,[R12],#0 0184DC88 : ..;ã : E33B0000 : TEQ R11,#0 0184DC8C : .... : 0A000005 : BEQ &0184DCA8 0184DC90 : ..·â : E28F0004 : ADR R0,&0184DC9C 0184DC94 : _..ë : EB00075F : BL &0184FA18 0184DC98 : . .è : E8BD8200 : LDMIA R13!,{R9,PC} 0184DC9C : .... : 0000010F : ANDEQ R0,R0,PC,LSL #2
*Memory, *MemoryA
*ShowRegs
None
*ShowRegs displays the register contents for the saved state, which may be caught on one of the five following traps:
It also prints the address in memory where the registers are stored, so you can alter them (for example after a breakpoint) by using *MemoryA on these locations, before using *Continue.
*ShowRegs Register dump (stored at &01804D2C) is: R0 = 0026D2CF R1 = 002483C1 R2 = 00000000 R3 = 00000000 R4 = 00000000 R5 = 52491ACE R6 = 42538FFD R7 = 263598DE R8 = B278A456 R9 = C2671D37 R10 = A72B34DC R11 = 82637D2F R12 = 00004000 R13 = 2538DAF0 R14 = 24368000 R15 = 7629D100 Mode USR flags set : nzcvif
None
None