Add dissasembly to Excdump
André Timmermans (100) 655 posts |
It would be nice to have (when possible) the dissasembly of the current instruction in the generated excdump. I am debugging some BASIC program which contains some assembler code and having the instruction that fails would seriously help infere which part of the assembler code to check. |
Peter Everett (9846) 59 posts |
You could use Zap. Create a data file, word mode, type in the instruction, say. |
André Timmermans (100) 655 posts |
The problem is that the dump doesn’t provide that instruction. |
Charles Ferguson (8243) 427 posts |
Extending the exception dump information isn’t really practical, as it’s a pretty defined interface – if you extended it, then any client that changed the address would find that additional data would need to also be present. OS_ChangeEnvironment 13 is defined to be 17 words long (16 on 26bit OSs – yes it changed before, but since the same code wouldn’t necessarily work on 32bit systems, this was a suitable time to change it). The information could be defined in another interface – q.v. OS_ReadSysInfo 7 (http://www.riscos.com/support/developers/riscos6)/core/osreadsysyinfo.html which would allow this to be retrieved. I asked some time back how RISC OS 5 reported the IFSR and DFSR, as these are other useful indications of what went wrong (whether the fault was external, or the type of permission fault that’s been reported). I believe the reply was that nothing had been done with those registers – it’s possible that situation has changed since then. A new interface could be added, for example, to store memory leading up to the exception in a new ChangeEnvironment area. This could then be interrogated by Debugger to report what the memory was leading up to the failure, without relying on the memory having stayed the same. Similar to how BTS records the privileged stacks at the time of failure so that BTSDump can report on the failures, or how MiniDump captures the stack and relevant memory areas when an exception occurs. Updating Debugger to handle that report would be relatively trivial. However, existing RISC OS versions already report this information in a useful manner for developers… Here’s RISC OS Pyromaniac reporting a fault from a piece of BASIC assembler: charles@phonewave ~/projects/RO/pyromaniac (systeminfo-experiment)> ./pyro.py --load-internal-modules --load-module modules/BASIC,ffa --command BASIC --config input.readline_native=true --debug trace 2> trace.txt BASIC V version 1.36 © RISCOS Ltd Starting with 1044732 bytes free >P%=&9000:[ OPT 0: MOV r0, #-20:LDR r0,[r0] >CALL &9000 Exception: Data abort r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0700a9c8, pc = &00009004 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Internal error: Abort on data transfer at &00009004 (DA 'Application Space') (read at &ffffffec, DA 'Exception vectors', unmapped) As you can see, the actual exception report also reports the registers at the time of the abort, as well as what address was being read, and the DA that it belongs to. Then you can use >*showregs r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0700a9c8, pc = &00009004 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Locations: lr: DA 'Module area', module 'BASIC' (area offset &8d1c) pc: DA 'Application Space' (area offset &1004) Disassembly before pc: &00008fb4 : &00000000 : ANDEQ r0, r0, r0 &00008fb8 : &00000000 : ANDEQ r0, r0, r0 &00008fbc : &00000000 : ANDEQ r0, r0, r0 &00008fc0 : &00000000 : ANDEQ r0, r0, r0 &00008fc4 : &00000000 : ANDEQ r0, r0, r0 &00008fc8 : &00000000 : ANDEQ r0, r0, r0 &00008fcc : &00000000 : ANDEQ r0, r0, r0 &00008fd0 : &00000000 : ANDEQ r0, r0, r0 &00008fd4 : &00000000 : ANDEQ r0, r0, r0 &00008fd8 : &00000000 : ANDEQ r0, r0, r0 &00008fdc : &00000000 : ANDEQ r0, r0, r0 &00008fe0 : &00000000 : ANDEQ r0, r0, r0 &00008fe4 : &00000000 : ANDEQ r0, r0, r0 &00008fe8 : &00000000 : ANDEQ r0, r0, r0 &00008fec : &00000000 : ANDEQ r0, r0, r0 &00008ff0 : &00000000 : ANDEQ r0, r0, r0 &00008ff4 : &00000000 : ANDEQ r0, r0, r0 &00008ff8 : &00000000 : ANDEQ r0, r0, r0 &00008ffc : &00000000 : ANDEQ r0, r0, r0 &00009000 : &e3e00013 : MVN r0, #&13 ; #&ffffffec = -20 &00009004 : &e5900000 > LDR r0, [r0] Last abort: Fault: &ffffffec (DA 'Exception vectors', unmapped) DFSR: &00000006 (Read, MMU access second level) > As you can see, the report includes the disassembled code. However, this code was also executed with As well as the full execution of the BASIC program (which I’ve not included here) there’s a report of each instruction leading up to the exception, and then an exception report. ... 700a97c: PUSH {r4, r5, r8, r10, r11, r12, lr} 700a980: MOV r10, r5 ; R5 = &00000000 700a984: SUB r11, r8, #&600 ; R8 = &00008700, #1536 700a988: SUBS r0, r8, #&fc ; R8 = &00008700, #252 700a98c: LDMIA r0, {r0, r1, r2, r3, r4, r5, r6, r7} ; R0 = &00008604 700a990: ADR lr, &0700a9c8 ; -> [&eafffff8, &fffffa00, &ffffff6c, &ffffff70] 700a994: LDMIA sp!, {pc} ; R13 = &00107fbc 9000: MVN r0, #&13 ; #&ffffffec = -20 9004: LDR r0, [r0] ; R0 = &ffffffec ==== Begin exception report ==== Exception triggered: Exception 'Data Abort' Fault address: &ffffffec inside: DA 'Exception vectors', unmapped Fault status: Read, MMU access second level r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0700a9c8, pc = &0000900c CPSR= &20000010 : USR-32 ARM fi ae qvCzn Locations: r8 -> [&00008640, &00000001, &00000000, &00000004] in DA 'Application Space' r9 -> [&00000000, &e5900000, &00000004, &00009008] in DA 'Application Space' r11 -> "CALL &9000" in DA 'Application Space' r12 -> "\xff[ OPT 0: MOV r0, #-20:LDR r0,[r0]" in DA 'Application Space' pc is DA 'Application Space' lr is DA 'Module area', module 'BASIC' ==== End exception report ==== If, instead of using charles@phonewave ~/projects/RO/pyromaniac (systeminfo-experiment)> ./pyro.py --load-internal-modules --load-module modules/BASIC,ffa --command BASIC --config input.readline_native=true --debug traceblock BASIC V version 1.36 © RISCOS Ltd Starting with 1044732 bytes free >P%=&9000:[ OPT 0: MOV r0, #-20:LDR r0,[r0] >CALL &9000 ==== Begin exception report ==== Exception triggered: Exception 'Data Abort' Fault address: &ffffffec inside: DA 'Exception vectors', unmapped Fault status: Read, MMU access second level r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0700a9c8, pc = &00009008 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Locations: r8 -> [&00008640, &00000001, &00000000, &00000004] in DA 'Application Space' r9 -> [&00000000, &e5900000, &00000004, &00009008] in DA 'Application Space' r11 -> "CALL &9000" in DA 'Application Space' r12 -> "\xff[ OPT 0: MOV r0, #-20:LDR r0,[r0]" in DA 'Application Space' pc is DA 'Application Space' lr is DA 'Module area', module 'BASIC' Recently executed code: ---- Block &0700d66c, 2 instructions ---- 700d66c: {DA 'Module area', module 'BASIC'} 700d66c: CMP r10, #&20 ; #32 = ' ' = bit 5 700d670: BEQ &0700d668 ---- Block &0700d674, 3 instructions ---- 700d674: CMP r10, #&3a ; #58 = ':' 700d678: CMPNE r10, #&d ; #13 700d67c: MOVEQ pc, lr ---- Block &0700a924, 2 instructions ---- 700a924: MOV r9, r0 700a928: BL &0700aa74 ---- Block &0700aa74, 3 instructions ---- 700aa74: MOV r7, r9, LSR #8 700aa78: TEQ r7, #&ff ; #255 700aa7c: BNE &0700ac18 ---- Block &0700ac18, 2 instructions ---- 700ac18: MOVS r0, #0 700ac1c: MOV pc, lr ---- Block &0700a92c, 1 instructions ---- 700a92c: BNE &070027e4 ---- Block &0700a930, 3 instructions ---- 700a930: MOV r4, r9 700a934: MOV r5, #0 700a938: B &0700a970 ---- Block &0700a970, 1 instructions ---- 700a970: BL &0700a978 ---- Block &0700a978, 8 instructions ---- 700a978: MOV r9, sp 700a97c: PUSH {r4, r5, r8, r10, r11, r12, lr} 700a980: MOV r10, r5 700a984: SUB r11, r8, #&600 ; #1536 700a988: SUBS r0, r8, #&fc ; #252 700a98c: LDMIA r0, {r0, r1, r2, r3, r4, r5, r6, r7} 700a990: ADR lr, &0700a9c8 ; -> [&eafffff8, &fffffa00, &ffffff6c, &ffffff70] 700a994: LDMIA sp!, {pc} ---- Block &00009000, 0 instructions ---- 9000: {DA 'Application Space'} Code preceding PC (not in last block): 8fcc: ANDEQ r0, r0, r0 8fd0: ANDEQ r0, r0, r0 8fd4: ANDEQ r0, r0, r0 8fd8: ANDEQ r0, r0, r0 8fdc: ANDEQ r0, r0, r0 8fe0: ANDEQ r0, r0, r0 8fe4: ANDEQ r0, r0, r0 8fe8: ANDEQ r0, r0, r0 8fec: ANDEQ r0, r0, r0 8ff0: ANDEQ r0, r0, r0 8ff4: ANDEQ r0, r0, r0 8ff8: ANDEQ r0, r0, r0 8ffc: ANDEQ r0, r0, r0 9000: MVN r0, #&13 ; #&ffffffec = -20 9004: LDR r0, [r0] 9008: ANDEQ r0, r0, r0 ==== End exception report ==== Exception: Data abort r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0700a9c8, pc = &00009000 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Internal error: Abort on data transfer at &00009000 (DA 'Application Space') (read at &ffffffec, DA 'Exception vectors', unmapped) > So without even using RISC OS Pyromaniac is designed to provide developers with as much information as possible to allow them to be able to debug problems. More information can be found in the documentation on tracing, here: https://pyromaniac.riscos.online/pyromaniac/TRACE.html |
Charles Ferguson (8243) 427 posts |
I’ve spent an hour or so knocking up a simple prototype this evening (admittedly whilst half asleep), which uses a new environment (34: ExceptionDumpRegion) to store the information about the data leading up to the instruction, with a buffer like this: +0 pc of fault +4 base address of dump +8 size of dump +12 ... memory from the base address up to the size of the dump and an update to Debugger which reports this information if the PC in the block matches the PC in the exception dump area. The results look exactly like the Not sure whether it’s a generally useful feature for RISC OS Classic, though. Here’s what it looks like: charles@phonewave ~/projects/RO/pyromaniac (memory-region-environment-buffer↑)> pyrodev --common --basic --boot-debug trace 2> trace.txt BASIC V version 1.36 © RISCOS Ltd Starting with 1044732 bytes free >P%=&9000:[ OPT 0: MOV r0, #-20:LDR r0,[r0] >CALL &9000 Exception: Data abort r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0384c920, pc = &00009004 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Internal error: Abort on data transfer at &00009004 (DA 'Application Space') (read at &ffffffec, DA 'Exception vectors', unmapped) >*showregs r0 = &ffffffec, r1 = &00000000, r2 = &00000000, r3 = &00000000 r4 = &00000000, r5 = &00000000, r6 = &00000000, r7 = &00000000 r8 = &00008700, r9 = &00107fd8, r10 = &00000000, r11 = &00008100 r12 = &00008208, sp = &00107fc0, lr = &0384c920, pc = &00009004 CPSR= &20000010 : USR-32 ARM fi ae qvCzn Locations: lr: DA 'ROM', module 'BASIC' (area offset &8d1c) pc: DA 'Application Space' (area offset &1004) Disassembly before pc (from time of exception): &00008fbc : &00000000 : ANDEQ r0, r0, r0 &00008fc0 : &00000000 : ANDEQ r0, r0, r0 &00008fc4 : &00000000 : ANDEQ r0, r0, r0 &00008fc8 : &00000000 : ANDEQ r0, r0, r0 &00008fcc : &00000000 : ANDEQ r0, r0, r0 &00008fd0 : &00000000 : ANDEQ r0, r0, r0 &00008fd4 : &00000000 : ANDEQ r0, r0, r0 &00008fd8 : &00000000 : ANDEQ r0, r0, r0 &00008fdc : &00000000 : ANDEQ r0, r0, r0 &00008fe0 : &00000000 : ANDEQ r0, r0, r0 &00008fe4 : &00000000 : ANDEQ r0, r0, r0 &00008fe8 : &00000000 : ANDEQ r0, r0, r0 &00008fec : &00000000 : ANDEQ r0, r0, r0 &00008ff0 : &00000000 : ANDEQ r0, r0, r0 &00008ff4 : &00000000 : ANDEQ r0, r0, r0 &00008ff8 : &00000000 : ANDEQ r0, r0, r0 &00008ffc : &00000000 : ANDEQ r0, r0, r0 &00009000 : &e3e00013 : MVN r0, #&13 ; #&ffffffec = -20 &00009004 : &e5900000 > LDR r0, [r0] &00009008 : &00000000 : ANDEQ r0, r0, r0 &0000900c : &00000000 : ANDEQ r0, r0, r0 &00009010 : &00000000 : ANDEQ r0, r0, r0 Last abort: Fault: &ffffffec (DA 'Exception vectors', unmapped) DFSR: &00000006 (Read, MMU access second level) |
Jon Abbott (1421) 2641 posts |
Exception handling via SeriousErrorV can provide exactly what André has requested. Currently you’d have to write your own custom report handler though. Debugging assembler Aborts in BASIC is particularily frustrating because BASIC doesn’t necessarily report the line that called the aborting code. The JIT in ADFFS for example hooks into SeriousErrorV and outputs a dissasembly, registers, IRQ/FIQ state, processor mode and a list of all claimed vectors…so it is possible. ZeroPain also uses it to output detailed exception reports for PZ accesses. If the source for ZeroPain is available, it might be a simple tweak to get it to cover all aborts but ultimately I agree with André, extending the inbuilt OS exception report would be useful – even if it required a *command to enable it. |
Charles Ferguson (8243) 427 posts |
As mentioned, this interface is implemented in the RISC OS Pyromaniac Debugger. I’d already added the display of these details to my Debugger module source in C, so in the recent live coding last Sunday, I lifted the code into the new Debugger module. So this module now implements the information from the environment, if it is present. The interface is documented within the Pyromaniac PRM documentation: https://pyromaniac.riscos.online/pyromaniac/prm/kernel/progenv-supplement.html#subsection_handler_34-_exception_dump_region |