From 37f536b128cec0e4d25cb827bb90ae20368795c6 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 22 Jun 2011 10:54:18 +0800 Subject: power down brick when kill command received Instead of rebooting, power down the brick when kill command received, to be consistent with NXT firmware behavior --- Debugger/debug_runlooptasks.S | 4 ++++ Debugger/debug_runlooptasks.h | 35 ++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index 75c477c..91e0fa9 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -113,7 +113,11 @@ dbg__runloopTasks: * ****************************************************************************/ dbg__reboot: +#ifdef REBOOT_POWERDOWN + b nx_core_halt /* Shutdown Brick, won't return */ +#else b nx_core_reset /* Reboot Brick, won't return */ +#endif #else /**************************************************************************** diff --git a/Debugger/debug_runlooptasks.h b/Debugger/debug_runlooptasks.h index 360e0d1..6eb0461 100644 --- a/Debugger/debug_runlooptasks.h +++ b/Debugger/debug_runlooptasks.h @@ -34,26 +34,27 @@ .extern nx_usb_read .extern nx_usb_data_read .extern nx_core_reset + .extern nx_core_halt #else /* NXT Firmware */ - .extern cCommInit - .extern cCommCtrl - .extern cCommExit - .extern dUsbWrite - .extern dUsbRead - .extern dUsbIsConfigured - .extern dBtSendMsg - .equ nxt_UBYTE_TRUE, 1 - .equ nxt_UBYTE_FALSE, 0 - .equ USB_CMD_READY, 0x01 /* From c_comm.iom */ - .equ BT_CMD_READY, 0x02 /* From c_comm.iom */ - - .extern dIOCtrlSetPower - .extern dIOCtrlSetPwm - .extern dIOCtrlTransfer - .equ BOOT, 0xA55A /* from c_ioctrl.iom */ - .equ POWERDOWN, 0x5A00 /* from c_ioctrl.iom */ + .extern cCommInit + .extern cCommCtrl + .extern cCommExit + .extern dUsbWrite + .extern dUsbRead + .extern dUsbIsConfigured + .extern dBtSendMsg + .equ nxt_UBYTE_TRUE, 1 + .equ nxt_UBYTE_FALSE, 0 + .equ USB_CMD_READY, 0x01 /* From c_comm.iom */ + .equ BT_CMD_READY, 0x02 /* From c_comm.iom */ + + .extern dIOCtrlSetPower + .extern dIOCtrlSetPwm + .extern dIOCtrlTransfer + .equ BOOT, 0xA55A /* from c_ioctrl.iom */ + .equ POWERDOWN, 0x5A00 /* from c_ioctrl.iom */ #endif -- cgit v1.2.3 From 7d044b402b282ab55657e1e1b07535aef8ad7edd Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 29 Jun 2011 09:39:44 +0800 Subject: added 1 ms delay to run loop --- Debugger/debug_runlooptasks.S | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index 91e0fa9..91c130e 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -88,9 +88,13 @@ * NxOS Run Loop * ****************************************************************************/ + .extern nx_systick_wait_ms dbg__runloopTasks: /* Currently, there's nothing that needs to be done in the NxOS Run Loop */ - bx lr + push {lr} + mov r0, #1 /* 1 ms delay */ + bl nx_systick_wait_ms + pop {pc} #else /**************************************************************************** -- cgit v1.2.3 From 5ad59e0fa53a9e57e4d06a408ab6051c3d6af701 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 29 Jun 2011 11:39:05 +0800 Subject: fix bug in dbg__sendcommmsg where it did not set the return value correctly Implemented delay in dbg__sendCommMsg to improve reliability--- Debugger/debug_runlooptasks.S | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index 91c130e..d2557d5 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -172,6 +172,7 @@ _dbg__reboot_wait: #ifdef __NXOS__ .extern debug_OutCommBuf + .extern nx_systick_wait_ms /**************************************************************************** * * NxOS Communications Driver Interface Routine @@ -182,7 +183,8 @@ _dbg__reboot_wait: * On entry: * R0: Total Message Buffer length * On exit: - R0: Tx Status (TRUE if data sent) + * R0: Tx Status (TRUE if data sent) + * R1-R3: Destroyed */ dbg__sendCommMsg: stmfd sp!, {r4, lr} @@ -199,12 +201,17 @@ dbg__sendCommMsg: mov r1, r4 /* Comm buffer length */ bl nx_usb_write -1: bl nx_usb_data_written /* R0 = True if data has been sent */ +1: mov r0, #1 /* 1 ms delay */ + bl nx_systick_wait_ms + bl nx_usb_data_written /* R0 = True if data has been sent */ teq r0, #0 /* FALSE == #0; We can't check for True condition since values used by C-Compiler & ARMDEBUG are different */ /* FIXME: implement timeout */ beq 1b /* Busy Wait Loop */ + + mov r0, #TRUE + b exit_dbg__sendCommMsg dbg__sendCommMsgFailed: mov r0, #FALSE -- cgit v1.2.3 From f68750cddf5754e527278f56e472757671fc6869 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 29 Jun 2011 12:03:14 +0800 Subject: remove wait delay in comm transmit dbg__sendCommMsg does not need 1 ms delay. Removed. dbg__runloopTasks needs the 1 ms delay, otherwise Armdebug doess not reliably detect incoming messages in comm buffer. This probably masks synchronization issues related to the USB Receive Buffer checking and handling, and should be fixed (eventually). --- Debugger/debug_runlooptasks.S | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index d2557d5..8eed3ad 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -172,7 +172,6 @@ _dbg__reboot_wait: #ifdef __NXOS__ .extern debug_OutCommBuf - .extern nx_systick_wait_ms /**************************************************************************** * * NxOS Communications Driver Interface Routine @@ -201,9 +200,7 @@ dbg__sendCommMsg: mov r1, r4 /* Comm buffer length */ bl nx_usb_write -1: mov r0, #1 /* 1 ms delay */ - bl nx_systick_wait_ms - bl nx_usb_data_written /* R0 = True if data has been sent */ +1: bl nx_usb_data_written /* R0 = True if data has been sent */ teq r0, #0 /* FALSE == #0; We can't check for True condition since values used by C-Compiler & ARMDEBUG are different */ -- cgit v1.2.3 From 80a5686b41b09b05219fe87def8fc74beecec774 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 1 Jul 2011 12:09:21 +0800 Subject: simple code optimization Reduced the number of instructions needed to access User Stack Registers by defining more compact macros for immediate access needs.--- Debugger/debug_macros.h | 28 +++++++++++++++++++++++ Debugger/debug_stub.S | 61 +++++++++++++++---------------------------------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index 75d6299..7932d97 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -281,6 +281,34 @@ str \contentsreg, [\addressreg, \indexreg, lsl #2] .endm +/* _getdbgregister + * Retrieve register contents from debugger stack given immediate index value + * + * On entry: + * indexval contains debugger stack index value (0-max index) + * On exit: + * contentsreg: Register Contents for given index + */ + .macro _getdbgregister indexval, contentsreg + ldr \contentsreg, =__debugger_stack_bottom__ + ldr \contentsreg, [\contentsreg, #(\indexval << 2)] + .endm + +/* _setdbgregister + * Store register contents to debugger stack given immediate index value + * + * On entry: + * indexval contains debugger stack index value (0-max index) + * contentsreg: Register Contents for given index + * addressreg: Scratch register for address pointer + * On exit: + * contentsreg: Register Contents for given index + * addressreg: Destroyed + */ + .macro _setdbgregister indexval, contentsreg, addressreg + ldr \addressreg, =__debugger_stack_bottom__ + str \contentsreg, [\addressreg, #(\indexval << 2)] + .endm /* _index2bkptindex_addr * Convert Breakpoint index to breakpoing entry address diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index e32c2dc..15d2548 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1256,10 +1256,8 @@ _dbg__cont_is_normal_breakpoint: This breaks normal breakpoints which need to determine the next instruction to execute (for placing the autobreakpoint) prior to returning. */ - mov r2, #DBGSTACK_USERPC_INDEX /* Retrieve Aborted Instruction PC from the Debug Stack */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R0 */ - mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */ - _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */ + _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ + _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ @@ -1314,22 +1312,19 @@ _dbg__step_is_normal_breakpoint: This breaks normal breakpoints which need to determine the next instruction to execute (for placing the autobreakpoint) prior to returning. */ - mov r2, #DBGSTACK_USERPC_INDEX /* Retrieve Aborted Instruction PC from the Debug Stack */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R0 */ - mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */ - _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */ + _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ + _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume usinh contents in R0, and scratch register R1 */ b _dbg__step_is_manual_bkpt_or_address_specified _dbg__step_is_manual_bkpt: - mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R1 */ + _getdbgregister DBGSTACK_NEXTINSTR_INDEX, r0 /* Retrieve Next Instruction Pointer for Resume into R1 */ /* b _dbg__step_is_manual_bkpt_or_address_specified */ _dbg__step_is_manual_bkpt_or_address_specified: - bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ - bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ + bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ + bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ bl dbg__activate_singlestep - bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ + bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ b _dbg__switch2undefmode /* _dbg__cmd_Kill @@ -1929,8 +1924,7 @@ _dbg_following_instruction_addr: * i.e., the Debugger does not leave stray Single Step / Auto / Normal breakpoints in memory */ mov r6, r0 /* Keep instruction address in R6 */ - mov r2, #DBGSTACK_USERCPSR_INDEX /* Retrieve User CPSR */ - _getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */ + _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve User CPSR into R1 */ and r4, r1, #CPSR_THUMB /* store Thumb Mode status in R4 */ mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */ @@ -2219,7 +2213,7 @@ _arm_calc_shifted_rm_val: * R1: Shift/Rotate Amount * On exit: * R0: RmShifted result - * R1, R2: destroyed + * R1: destroyed * */ _reg_lsl: @@ -2239,12 +2233,11 @@ _reg_ror: bx lr _reg_rrx: - moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ - _getdbgregisterfromindex r2, r1 /* Retrieve CPSR contents from Index (R2) into R1 */ - ands r1, r1, #CPSR_CFLAG /* Keep C Flag */ - movne r1, #0x80000000 /* Set B31 if C Flag set */ - lsr r0, r0, #1 /* Rm >> 1 */ - orr r0, r0, r1 /* Put C flag into B31 */ + _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve CPSR contents into R1 */ + ands r1, r1, #CPSR_CFLAG /* Keep C Flag */ + movne r1, #0x80000000 /* Set B31 if C Flag set */ + lsr r0, r0, #1 /* Rm >> 1 */ + orr r0, r0, r1 /* Put C flag into B31 */ bx lr @@ -2341,36 +2334,21 @@ _opcode_add: _opcode_adc: /* Op1 + Op2 + C */ -#if 0 - moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ - _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */ - ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */ -#endif - tst r5, #0x02 /* R5[3:0] is shifted CPSR value */ + tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ add r0, r0, r1 addne r0, r0, #1 /* Add C if set */ bx lr _opcode_sbc: /* Op1 - Op2 + C - 1 */ -#if 0 - moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ - _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */ - ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */ -#endif - tst r5, #0x02 /* R5[3:0] is shifted CPSR value */ + tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ sub r0, r0, r1 subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ bx lr _opcode_rsc: /* Op2 - Op1 + C - 1 */ -#if 0 - moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ - _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */ - ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */ -#endif - tst r5, #0x02 /* R5[3:0] is shifted CPSR value */ + tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ rsb r0, r0, r1 subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ bx lr @@ -2597,8 +2575,7 @@ _thumb_poppc_handler: stmfd sp!, {lr} _thumb_get_SP_val: - mov r2, #DBGSTACK_USERSP_INDEX /* Set Register Index (R2) to SP Index */ - _getdbgregisterfromindex r2, r1 /* Retrieve SP contents from Index (R2) into R1 */ + _getdbgregister DBGSTACK_USERSP_INDEX, r1 /* Retrieve SP contents into R1 */ _thumb_get_regcount: mov r2, #0 /* Initialize reg_count (R2) to 0 */ -- cgit v1.2.3 From 8e3722fe1290616f129ede031c9fd6cb947d61c2 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 1 Jul 2011 18:03:07 +0800 Subject: work in progress to fix bugs in arm opcode parser Fixing bugs in ARM Opcode Parser. Lots of logical errors. --- Debugger/debug_stub.S | 78 ++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 15d2548..a58908e 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -408,7 +408,7 @@ debug_armCondCodeTable: * Condition Code stored in the following order: * b7 b6 b5 b4 b3 b2 b1 b0 * - - - ANDOR - Z set AND N==V (bit set = 1) - * - - - ANDOR - Z clr OR N!=V (bit clr = 0) + * - - - - - Z clr OR N!=V (bit clr = 0) * * GE: N == V * LT: N != V @@ -430,7 +430,7 @@ debug_armCondCodeTable: debug_armComplexCCTable: /* GE, LT, GT, LE */ - .byte 0x01, 0x00, 0x15, 0x12 + .byte 0x01, 0x00, 0x13, 0x14 .code 32 .text @@ -1925,34 +1925,34 @@ _dbg_following_instruction_addr: */ mov r6, r0 /* Keep instruction address in R6 */ _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve User CPSR into R1 */ - and r4, r1, #CPSR_THUMB /* store Thumb Mode status in R4 */ + and r0, r1, #CPSR_THUMB /* store Thumb Mode status in R0 */ mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */ _dbg_get_aborted_instr: -1: teq r4, #0 /* Check if it is ARM or Thumb instruction */ - ldrneh r0, [r6] /* Load Thumb instruction opcode using Addr in R6 into R0 */ +1: teq r0, #0 /* Check if it is ARM or Thumb instruction */ + ldrneh r4, [r6] /* Load Thumb instruction opcode using Addr in R6 into R4 */ ldrne r2, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ - ldreq r0, [r6] /* Load ARM instruction opcode using Addr in R6 into R0 */ + ldreq r4, [r6] /* Load ARM instruction opcode using Addr in R6 into R4 */ ldreq r2, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ - teq r0, r2 /* Is instruction opcode (R0) == Manual Breakpoint opcode (R2)? */ + teq r4, r2 /* Is instruction opcode (R4) == Manual Breakpoint opcode (R2)? */ bne 2f /* Not Manual breakpoint */ - teq r4, #0 /* Check if it is ARM or Thumb Manual Breakpoint */ + teq r0, #0 /* Check if it is ARM or Thumb Manual Breakpoint */ addne r6, r6, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ addeq r6, r6, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ -/* Here, R0 contains the instruction opcode which will be (re)executed when program resumes. +/* Here, R4 contains the instruction opcode which will be (re)executed when program resumes. * We need to dissect it to see if it is a branch instruction. * For ARM instructions, we also need to evaluate the current (breakpointed) instruction to see if it'll execute. - * If not, then the following instruction is at the address following the address of the opcode in R0 (Default Following Instruction Address). + * If not, then the following instruction is at the address following the address of the opcode in R4 (Default Following Instruction Address in R6). */ 2: - teq r4, #0 /* Check if it is ARM or Thumb instruction */ + teq r0, #0 /* Check if it is ARM or Thumb instruction */ beq _following_instr_is_arm _following_instr_is_thumb: - add r6, r6, #2 /* Store following Thumb instruction address to R1 */ + add r6, r6, #2 /* Store default following Thumb instruction address to R6 */ orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */ - /* R0: Candidate Instruction Opcode + /* R4: Candidate Instruction Opcode * R5[3:0]: CPSR condition codes * R6: Default Following Instruction Address (PC+2) */ @@ -1961,8 +1961,8 @@ _following_instr_is_thumb: b _exit_dbg_following_instruction_addr _following_instr_is_arm: - add r6, r6, #4 /* Store following ARM instruction address to R1 */ - /* R0: Candidate Instruction Opcode + add r6, r6, #4 /* Store default following ARM instruction address to R6 */ + /* R4: Candidate Instruction Opcode * R5[3:0]: CPSR condition codes * R6: Default Following Instruction Address (PC+4) */ @@ -1976,7 +1976,7 @@ _exit_dbg_following_instruction_addr: /* _eval_arm_instruction * Evaluate ARM instruction to determine following instruction address * On entry: - * R0: instruction to be executed + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes * R6: Default Following Instruction Address (PC+4) * On exit: @@ -1985,7 +1985,6 @@ _exit_dbg_following_instruction_addr: */ _eval_arm_instruction: stmfd sp!, {lr} - mov r4, r0 /* Keep Instruction Opcode in R4 */ bl _dbg_check_arm_condcode teq r0, #FALSE moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ @@ -2015,7 +2014,7 @@ _exit_eval_arm_instruction: /* _eval_thumb_instruction * Evaluate Thumb instruction to determine following instruction address * On entry: - * R0: instruction to be executed + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes * R6: Default Following Instruction Address (PC+2) * On exit: @@ -2025,7 +2024,6 @@ _exit_eval_arm_instruction: _eval_thumb_instruction: stmfd sp!, {lr} #if 0 - mov r4, r0 /* Keep Instruction Opcode in R4 */ /* Only B instructions are conditionally executed, deal with it in that Code Handler */ bl _dbg_check_thumb_condcode teq r0, #FALSE @@ -2065,7 +2063,7 @@ _exit_eval_thumb_instruction: /* _dbg_check_arm_condcode * Check ARM conditional execution code * On entry: - * R0: instruction to be executed + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes * On exit: * R0: will_execute (boolean) @@ -2073,11 +2071,11 @@ _exit_eval_thumb_instruction: */ _dbg_check_arm_condcode: - stmfd sp!, {r6,lr} /* Use R6 as temporary will_execute variable */ - mov r6, #TRUE - mov r0, r0, lsr #28 /* convert condition code to index (0-F) */ + stmfd sp!, {lr} /* Use R6 as temporary will_execute variable */ + mov r0, #TRUE + mov r3, r4, lsr #28 /* convert condition code to index (0-F) */ ldr r2, =debug_armCondCodeTable - ldrb r1, [r2, r0] /* Get condition code mask */ + ldrb r1, [r2, r3] /* Get condition code mask */ /* * The following check is unnecessary as it is covered by the set/clear checking algorithm teq r1, #0 @@ -2097,16 +2095,17 @@ _dbg_check_arm_condcode: * will_execute = (N != V) * * If (ANDOR bit) set - * z_cond = ((Z XOR Z set) == 0) + * z_cond = (Z XOR Z set) * If (AND bit set) * will_execute = will_execute && z_cond * else * will_execute = will_execute || z_cond */ _dbg_cond_complex_check: - sub r1, r0, #COMPLEX_CONDCODE_START /* Convert complex condition code to new index (0-3) */ +/* TODO: Need to verify logic below */ + sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */ ldr r2, =debug_armComplexCCTable - ldrb r1, [r2, r1] /* Get complex condition code bitmap */ + ldrb r1, [r2, r3] /* Get complex condition code bitmap */ /* Use r2 to store N, r3 to store V */ tst r5, #COMPLEX_CONDCODE_NFLAG @@ -2143,30 +2142,25 @@ _dbg_cond_complex_check: * If (SetBitMask is Non-Zero) * will_execute = ((cond_code & SetBitMask) == SetBitMask) * If will_execute && (ClearBitMask is Non-Zero) - * will_execute = will_execute && ((cond_code | ~ClearBitMask) == ~ClearBitMask) + * will_execute = will_execute && ((cond_code & ClearBitMask) == 0) */ _dbg_check_bits_set: - movs r0, r1, lsr #4 /* R0: bits set */ - beq _dbg_check_bits_clear - and r2, r5, r0 /* Check bits set IF bitmask non-zero */ - teq r2, r0 /* ((cond_code & SetBitMask) == SetBitMask)? */ - movne r6, #FALSE /* No, so will_execute = FALSE */ - bne _dbg_check_arm_condcode_exit + movs r2, r1, lsr #4 /* R2: bits set */ + beq _dbg_check_bits_clear /* No bits set mask enabled, skip check */ + and r3, r5, r2 /* Check bits set IF bitmask non-zero */ + teq r2, r3 /* ((cond_code & SetBitMask) == SetBitMask)? */ + movne r0, #FALSE /* No, so will_execute = FALSE */ + bne _dbg_check_arm_condcode_exit /* Check failed (need to be TRUE to check bits clear), return */ _dbg_check_bits_clear: ands r1, r1, #NIBBLE0 /* R1: bits clear */ beq _dbg_check_arm_condcode_exit - mvn r1, r1 /* Invert Bitmask */ - orr r2, r5, r1 /* Check bits clear IF bitmask non-zero */ - teq r2, r1 /* ((cond_code | ~ClearBitMask) == ~ClearBitMask)? */ - movne r6, #FALSE /* No, so will_execute = FALSE */ - bne _dbg_check_arm_condcode_exit - + ands r3, r5, r1 /* Check bits clear IF bitmask non-zero */ + movne r0, #FALSE /* (cond_code & ClearBitMask) != 0, so will_execute = FALSE */ _dbg_check_arm_condcode_exit: - mov r0, r6 /* Update return value */ - ldmfd sp!, {r6, pc} + ldmfd sp!, {pc} /* R0: will_execute (boolean) */ /* _arm_rmshifted_val -- cgit v1.2.3 From cd19bc0f96fb7b2923b8aefe3295e7047f690c30 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 1 Jul 2011 22:09:27 +0800 Subject: work in progress, clean up _dbg_check_arm_condcode Rewrite _dbg_check_arm_condcode to fix logical errors --- Debugger/debug_stub.S | 60 +++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index a58908e..2e2ff8a 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2095,45 +2095,49 @@ _dbg_check_arm_condcode: * will_execute = (N != V) * * If (ANDOR bit) set - * z_cond = (Z XOR Z set) + * z_match = ~(Z XOR Z set) * If (AND bit set) - * will_execute = will_execute && z_cond + * will_execute = will_execute && z_match * else - * will_execute = will_execute || z_cond + * will_execute = will_execute || z_match */ _dbg_cond_complex_check: -/* TODO: Need to verify logic below */ sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */ ldr r2, =debug_armComplexCCTable - ldrb r1, [r2, r3] /* Get complex condition code bitmap */ - - /* Use r2 to store N, r3 to store V */ - tst r5, #COMPLEX_CONDCODE_NFLAG - moveq r2, #FALSE - movne r2, #TRUE /* r2 = N flag */ - tst r5, #COMPLEX_CONDCODE_VFLAG - moveq r3, #FALSE - movne r3, #TRUE /* r3 = V flag */ - eor r2, r2, r3 /* r2 = (N xor V): 0 if equal, 0xFF if not equal */ - tst r1, #COMPLEX_CONDCODE_NEQV_MASK - mvnne r6, r1 /* If (N == V) bit set, will_execute (r6) = TRUE if (N == V) [r2 == 0] -> invert r2 */ - moveq r6, r1 /* else (N == V) bit clr, will_execute (r6) = TRUE if (N != V) [r2 == 0xFF] */ - + ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */ + + /* Use R3 to store N+V Mask, R2 to store results */ + mov r3, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Mask N+V from CPSR */ + ands r2, r3, r5 /* Is (N == V == 0)? */ + teqne r2, r3 /* No, Is (N == V == 1)? */ + bne _cond_nnev /* No, so (N != V) */ + + /* EQ: Either (N == V == 0) or (N == V == 1) */ +_cond_neqv: + tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ + moveq r0, #FALSE /* No, so will_execute = FALSE (for now) */ + b _cond_check_andor + + /* Else, N != V */ +_cond_nnev: + tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ + movne r0, #FALSE /* Yes, so will_execute = FALSE (for now) */ + +_cond_check_andor: tst r1, #COMPLEX_CONDCODE_ANDOR_MASK beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */ - /* Use r2 to store Z, r3 to store Z set */ + /* Use R2 to store Z Flag, R3 to store Z set Mask */ and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */ and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = Z set */ - eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if not matched */ - moveq r2, #TRUE - movne r2, #FALSE /* r2 (z_cond): TRUE if matched, FALSE if not matched */ - - tst r1, #COMPLEX_CONDCODE_AND_MASK - andne r6, r6, r2 /* If AND bit set, will_execute = will_execute && z_cond */ - orreq r6, r6, r2 /* else, will_execute = will_execute || z_cond */ - b _dbg_check_arm_condcode_exit - + eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if failed match */ + moveq r3, #TRUE /* Zero, so z flag matched */ + movne r3, #FALSE /* Non-zero, so z flag failed match */ + + tst r1, #COMPLEX_CONDCODE_AND_MASK /* Is AND mask set? */ + andne r0, r0, r3 /* Yes, so AND with will_execute */ + orreq r0, r0, r3 /* No, so OR with will_execute */ + b _dbg_check_arm_condcode_exit /* Return will_execute (R0) */ /* * Simple Checks: -- cgit v1.2.3 From bc3a3acc1924b3abae24344b51669a316980f5d8 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 1 Jul 2011 22:24:52 +0800 Subject: fix invalid table name in _dbg_armDecodeEntry macro, improved comments in arm processing routines Misc cleanups, fix error in _dbg_armDecodeEntry macro. --- Debugger/debug_macros.h | 2 +- Debugger/debug_stub.S | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index 7932d97..e3208b4 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -67,7 +67,7 @@ */ .macro _dbg_armDecodeEntry instrreg, instrmask, codehandler, indexreg - ldr \instrmask, =debug_thumbDecodeTable /* Temporary register */ + ldr \instrmask, =debug_armDecodeTable /* Temporary register */ add \instrmask, \instrmask, \indexreg, lsl #3 add \instrmask, \instrmask, \indexreg, lsl #2 /* 12 byte entries */ ldm \instrmask, {\instrreg, \instrmask, \codehandler} diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 2e2ff8a..0b0040c 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1985,10 +1985,10 @@ _exit_dbg_following_instruction_addr: */ _eval_arm_instruction: stmfd sp!, {lr} - bl _dbg_check_arm_condcode + bl _dbg_check_arm_condcode /* Returns R0: will_execute (boolean) */ teq r0, #FALSE - moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ - bne _exit_eval_arm_instruction + moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */ + beq _exit_eval_arm_instruction /* and Return to caller */ _will_execute_arm_instr: mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */ @@ -2025,10 +2025,10 @@ _eval_thumb_instruction: stmfd sp!, {lr} #if 0 /* Only B instructions are conditionally executed, deal with it in that Code Handler */ - bl _dbg_check_thumb_condcode + bl _dbg_check_thumb_condcode /* Returns R0: will_execute (boolean) */ teq r0, #FALSE - moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ - bne _exit_eval_thumb_instruction + moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */ + beq _exit_eval_thumb_instruction /* and Return to caller */ _will_execute_thumb_instr: mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */ @@ -2071,7 +2071,6 @@ _exit_eval_thumb_instruction: */ _dbg_check_arm_condcode: - stmfd sp!, {lr} /* Use R6 as temporary will_execute variable */ mov r0, #TRUE mov r3, r4, lsr #28 /* convert condition code to index (0-F) */ ldr r2, =debug_armCondCodeTable @@ -2164,8 +2163,7 @@ _dbg_check_bits_clear: movne r0, #FALSE /* (cond_code & ClearBitMask) != 0, so will_execute = FALSE */ _dbg_check_arm_condcode_exit: - ldmfd sp!, {pc} /* R0: will_execute (boolean) */ - + bx lr /* Return to caller */ /* _arm_rmshifted_val * Calculate value of Shifted Rm (operand) -- cgit v1.2.3 From a046173911b8598d524b53c75dd82d6e1d7e529f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 1 Jul 2011 22:49:09 +0800 Subject: work in progress, cleaning up code handler api Change code handler register usage to reduce parameter copying. --- Debugger/debug_stub.S | 80 +++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 0b0040c..6c90a40 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1991,22 +1991,20 @@ _eval_arm_instruction: beq _exit_eval_arm_instruction /* and Return to caller */ _will_execute_arm_instr: - mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */ - mov r1, #0 /* initialize ARM Decode Entry Table index register */ + mov r0, #0 /* initialize ARM Decode Entry Table index register */ 1: - _dbg_armDecodeEntry r2, r3, r4, r1 /* instrreg (R2), instrmask (R3), codehandler (R4), indexreg (R1) */ - teq r2, #0 /* Check for Null Entry (End of Table marker) */ + _dbg_armDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ + teq r1, #0 /* Check for Null Entry (End of Table marker) */ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ beq _exit_eval_arm_instruction - and r7, r0, r3 /* Use R7 to check masked instruction opcode (from R0) to see if it matches template (in R2) */ - teq r7, r2 - addne r1, r1, #1 /* No match, so keep looking */ + and r7, r4, r2 /* Use R7 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ + teq r7, r1 + addne r0, r0, #1 /* No match, so keep looking */ bne 1b _call_arm_code_handler: - mov r1, r6 /* Copy Default Following Instruction Address to R1 as Code Handler Parameter */ mov lr, pc - bx r4 /* Call Code Handler with R0: Instruction Opcode, R1: Default Following Instruction Address */ + bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ _exit_eval_arm_instruction: /* Returned Following Address Instruction in R0 (B0 set to indicate Thumb mode) */ ldmfd sp!, {pc} @@ -2031,24 +2029,22 @@ _eval_thumb_instruction: beq _exit_eval_thumb_instruction /* and Return to caller */ _will_execute_thumb_instr: - mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */ #endif - mov r1, #0 /* initialize Thumb Decode Entry Table index register */ + mov r0, #0 /* initialize Thumb Decode Entry Table index register */ 1: - _dbg_thumbDecodeEntry r2, r3, r4, r1 /* instrreg (R2), instrmask (R3), codehandler (R4), indexreg (R1) */ - teq r2, #0 /* Check for Null Entry (End of Table marker) */ + _dbg_thumbDecodeEntry r1, r2, r3, r10 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ + teq r1, #0 /* Check for Null Entry (End of Table marker) */ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ beq _exit_eval_thumb_instruction - and r7, r0, r3 /* Use R5 to check masked instruction opcode (from R0) to see if it matches template (in R2) */ - teq r7, r2 - addne r1, r1, #1 /* No match, so keep looking */ + and r7, r4, r2 /* Use R5 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ + teq r7, r1 + addne r0, r0, #1 /* No match, so keep looking */ bne 1b _call_thumb_code_handler: - mov r1, r6 /* Copy Default Following Instruction Address to R1 as Code Handler Parameter */ mov lr, pc - bx r4 /* Call Code Handler with R0: Instruction Opcode, R1: Default Following Instruction Address */ + bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ _exit_eval_thumb_instruction: /* Returned Following Address Instruction in R0 */ ldmfd sp!, {pc} @@ -2165,6 +2161,8 @@ _dbg_check_bits_clear: _dbg_check_arm_condcode_exit: bx lr /* Return to caller */ +@@@@ TODO: Code Audit Needed + /* _arm_rmshifted_val * Calculate value of Shifted Rm (operand) * On entry: @@ -2240,9 +2238,9 @@ _reg_rrx: /* _arm_data_instr_handler * ARM Data Processing Instruction with Rd == R15 * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address * R1-R7: Destroyed @@ -2376,9 +2374,9 @@ _opcode_mvn: /* _arm_bx_blx_handler * BX or BLX Rm Handler. Note v4t does not have BLX instr * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1, R2: destroyed @@ -2397,9 +2395,9 @@ _arm_bx_blx_handler: /* _arm_ldr_pc_handler * LDR with Rd = PC * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address * R1, R2, R3, R4, R5: destroyed @@ -2438,9 +2436,9 @@ _exit_arm_ldr_pc_handler: /* _arm_ldm_pc_handler * LDM {pc} * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address * R1, R2, R3: destroyed @@ -2478,9 +2476,9 @@ _arm_check_updown_offset: /* _arm_b_bl_blx_handler * B, BL or BLX . Note v4t does not have BLX instr * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address * R1, R2, R3: destroyed @@ -2516,9 +2514,9 @@ _exit_arm_b_bl_blx_handler: /* _arm_coproc_swi_handler * SVC (SWI) or Coprocessor instruction * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+4) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address * R1, R2: destroyed @@ -2541,9 +2539,9 @@ _exit_arm_coproc_swi_handler: /* _thumb_bx_blx_handler * BX or BLX Handler. Note: b7 (H1) is not matched in the mask (should be 0); armv4t does not support BLX. * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+2) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1: destroyed @@ -2560,9 +2558,9 @@ _thumb_bx_blx_handler: /* _thumb_poppc_handler * PUSH/POP, specifically POP {Rlist,PC} * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+2) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1: destroyed @@ -2592,9 +2590,9 @@ _thumb_get_regcount: /* _thumb_bcond_swi_handler * B or SWI (SVC) * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+2) - * R5[3:0]: CPSR condition codes + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1-R6: destroyed @@ -2632,9 +2630,9 @@ _exit_thumb_bcond_swi_handler: /* _thumb_b_handler * B * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+2) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1: destroyed @@ -2653,9 +2651,9 @@ _thumb_b_handler: /* _thumb_long_bl_blx_handler * Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr; armv4t does not support BLX. * On entry: - * R0: instruction to be executed - * R1: Default Following Instruction Address (PC+2) + * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1, R2, R3: destroyed -- cgit v1.2.3 From 9f24b7909c3e747da9fd724262e6522236b3057f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 2 Jul 2011 07:34:38 +0800 Subject: optimization, removed one instruction from _dbg_cond_complex_check --- Debugger/debug_stub.S | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 6c90a40..99be1df 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2101,10 +2101,8 @@ _dbg_cond_complex_check: ldr r2, =debug_armComplexCCTable ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */ - /* Use R3 to store N+V Mask, R2 to store results */ - mov r3, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Mask N+V from CPSR */ - ands r2, r3, r5 /* Is (N == V == 0)? */ - teqne r2, r3 /* No, Is (N == V == 1)? */ + ands r2, r5, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Is (N == V == 0)? */ + teqne r2, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* No, Is (N == V == 1)? */ bne _cond_nnev /* No, so (N != V) */ /* EQ: Either (N == V == 0) or (N == V == 1) */ -- cgit v1.2.3 From 4464045ea9322934d885d771f5b5128e0759c749 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 2 Jul 2011 09:26:36 +0800 Subject: work in progress: fix thumb instruction evaluation, update arm data instruction handler More fixes: Thumb Instruction Evaluator ARM Data Instruction handler --- Debugger/debug_stub.S | 62 +++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 99be1df..e9ea490 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2021,18 +2021,10 @@ _exit_eval_arm_instruction: */ _eval_thumb_instruction: stmfd sp!, {lr} -#if 0 /* Only B instructions are conditionally executed, deal with it in that Code Handler */ - bl _dbg_check_thumb_condcode /* Returns R0: will_execute (boolean) */ - teq r0, #FALSE - moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */ - beq _exit_eval_thumb_instruction /* and Return to caller */ - -_will_execute_thumb_instr: -#endif mov r0, #0 /* initialize Thumb Decode Entry Table index register */ 1: - _dbg_thumbDecodeEntry r1, r2, r3, r10 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ + _dbg_thumbDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ teq r1, #0 /* Check for Null Entry (End of Table marker) */ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ beq _exit_eval_thumb_instruction @@ -2159,8 +2151,6 @@ _dbg_check_bits_clear: _dbg_check_arm_condcode_exit: bx lr /* Return to caller */ -@@@@ TODO: Code Audit Needed - /* _arm_rmshifted_val * Calculate value of Shifted Rm (operand) * On entry: @@ -2233,6 +2223,9 @@ _reg_rrx: bx lr +#define ARM_DATA_INSTR_MASK 0x0FBF0000 +#define ARM_DATA_INSTR_MSRMRS 0x010F0000 +#define ARM_DATA_INSTR_NORMAL 0x01E00000 /* _arm_data_instr_handler * ARM Data Processing Instruction with Rd == R15 * On entry: @@ -2245,50 +2238,46 @@ _reg_rrx: */ _arm_data_instr_handler: stmfd sp!, {lr} - mov r6, r1 /* save Following Instruction Address in R6 */ - ldr r1, =0x0FBF0000 - and r4, r0, r1 /* Keep instruction Opcode in R4 */ - ldr r1, =0x010F0000 - cmp r4, r1 /* Check for MSR / MRS instruction */ + ldr r1, =ARM_DATA_INSTR_MASK + and r3, r4, r1 /* Keep base instruction Opcode in R3 */ + ldr r1, =ARM_DATA_INSTR_MSRMRS + teq r3, r1 /* Check for MSR / MRS instruction */ _arm_is_msr_mrs_instr: moveq r0, r6 /* Copy default next instruciton address to R0 */ beq _exit_arm_data_instr_handler /* Return default next instruction address */ /* Not MSR / MRS, so process normally */ -_arm_normal_data_instr: - and r4, r0, #0x01E00000 /* Mask Instruction Opcode into R4[24:21] */ - lsr r4, r4, #21 /* Shift Data Processing Opcode into R4[3:0] */ - and r7, r0, #0x000F0000 /* Store Rn (Operand 1) Register Enum into R7[19:16] */ - lsr r7, r7, #16 /* Shift into R7[3:0] */ - _arm_check_operand2_type: - tst r0, #0x02000000 /* Check for Immediate (1) or Register (0) Operand 2 */ + tst r4, #0x02000000 /* Check for Immediate (1) or Register (0) Operand 2 */ beq _arm_op2_is_reg _arm_op2_is_imm: - and r1, r0, #BYTE0 /* 8 bit unsigned constant in R1 */ - and r2, r0, #NIBBLE2 /* (rotate count / 2) in R2[11:8] */ + and r1, r4, #BYTE0 /* 8 bit unsigned constant in R1 */ + and r2, r4, #NIBBLE2 /* (rotate count / 2) in R2[11:8] */ lsr r2, r2, #7 /* actual rotate count in R2[4:0] */ ror r1, r1, r2 /* Rotated constant in R1 */ b _arm_get_operand1_val _arm_op2_is_reg: ldr r1, =(NIBBLE2|BYTE0) - and r0, r0, r1 /* 12 bit register operand in R1 */ + and r0, r4, r1 /* 12 bit register operand in R1 */ bl _arm_rmshifted_val /* R0 contains the Rm shifted val */ - mov r1, r0 /* move to R1 for later processing */ + mov r1, r0 /* R1: Operand2 val */ _arm_get_operand1_val: - _regenum2index r7, r1 /* Convert Enum into Index in R1 */ - _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R4 */ - teq r7, #REG_PC /* Check if it is PC relative */ - addeq r0, r0, #8 /* adjust for PC relative (+8) */ + and r3, r4, #0x000F0000 /* Store Rn (Operand1) Register Enum into R3[19:16] */ + lsr r3, r3, #16 /* Shift into R3[3:0] */ + _regenum2index r3, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ + teq r3, #REG_PC /* Check if it is PC relative */ + addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ _arm_calc_data_instr_val: - mov r2, r6 /* Retrieve Following Instruction Address in R6 to R2 */ - /* Calculate data instruction value from R0: Rn Register (Op1) val, R1: Operand 2 val, R2: Default Next Instr Addr */ - _dbg_jumpTableHandler debug_dataInstrJumpTable, r6, r4 /* Next Instruction Address in R0 */ + and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */ + lsr r3, r3, #21 /* Shift Data Processing Opcode into R3[3:0] */ + /* Calculate data instruction value from R0: Register Rn (Operand1) val, R1: Operand2 val, R5[3:0]: CPSR, R6: Default Next Instr Addr */ + _dbg_jumpTableHandler debug_dataInstrJumpTable, r2, r3 /* Next Instruction Address in R0 */ _exit_arm_data_instr_handler: ldmfd sp!, {pc} @@ -2297,8 +2286,8 @@ _exit_arm_data_instr_handler: * On entry: * R0: Register Rn (Operand 1) value * R1: Operand 2 value - * R2: Default Next Instruction Address (PC+4) * R5[3:0]: CPSR condition codes + * R6: Default Next Instruction Address (PC+4) * On exit: * R0: Calculated result * R1, R2, R3: Destroyed @@ -2349,7 +2338,7 @@ _opcode_tst: _opcode_teq: _opcode_cmp: _opcode_cmn: - mov r0, r2 /* Next Instruction Address is not modified */ + mov r0, r6 /* Next Instruction Address is not modified */ bx lr _opcode_orr: @@ -2368,6 +2357,7 @@ _opcode_mvn: mvn r0, r1 /* Operand 1 is ignored */ bx lr +@@@ TODO: Code Audit Needed /* _arm_bx_blx_handler * BX or BLX Rm Handler. Note v4t does not have BLX instr -- cgit v1.2.3 From 3b91630a70ca6a3cd5635c806ed6154eb63b019e Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 4 Jul 2011 07:20:46 +0800 Subject: work in progress, further cleanups More code audits and cleanups. --- Debugger/debug_stub.S | 98 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index e9ea490..1cc4340 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2266,12 +2266,15 @@ _arm_op2_is_reg: mov r1, r0 /* R1: Operand2 val */ _arm_get_operand1_val: - and r3, r4, #0x000F0000 /* Store Rn (Operand1) Register Enum into R3[19:16] */ + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ +#if 0 + and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */ lsr r3, r3, #16 /* Shift into R3[3:0] */ _regenum2index r3, r2 /* Convert Enum into Index in R2 */ _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ teq r3, #REG_PC /* Check if it is PC relative */ addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ +#endif _arm_calc_data_instr_val: and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */ @@ -2281,6 +2284,25 @@ _arm_calc_data_instr_val: _exit_arm_data_instr_handler: ldmfd sp!, {pc} +/* _dbg_data_instr_retrieve_op1val + * Retrieve Data Instruction Operand 1 value + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Next Instruction Address (PC+4) + * On exit: + * R0: Register Rn (Operand 1) value + * R2, R3: Destroyed + * + */ +_dbg_data_instr_retrieve_op1val: + and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */ + lsr r3, r3, #16 /* Shift into R3[3:0] */ + _regenum2index r3, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ + teq r3, #REG_PC /* Check if it is PC relative */ + addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ + bx lr /* Data Processing Instruction Jump Table Routines * On entry: @@ -2357,8 +2379,6 @@ _opcode_mvn: mvn r0, r1 /* Operand 1 is ignored */ bx lr -@@@ TODO: Code Audit Needed - /* _arm_bx_blx_handler * BX or BLX Rm Handler. Note v4t does not have BLX instr * On entry: @@ -2367,11 +2387,11 @@ _opcode_mvn: * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) - * R1, R2: destroyed + * R1: destroyed */ _arm_bx_blx_handler: stmfd sp!, {lr} - and r0, r0, #NIBBLE0 /* Register Rn Enum in R0 */ + and r0, r4, #NIBBLE0 /* Register Rn Enum in R0 */ _regenum2index r0, r1 /* Convert Enum into Index in R1 */ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ /* Here, the register value would have B0 set to indicate switch to Thumb mode */ @@ -2380,6 +2400,8 @@ _arm_bx_blx_handler: #endif ldmfd sp!, {pc} +@@@ TODO: Code Audit Needed + /* _arm_ldr_pc_handler * LDR with Rd = PC * On entry: @@ -2393,33 +2415,65 @@ _arm_bx_blx_handler: _arm_ldr_pc_handler: stmfd sp!, {lr} - mov r5, r0 /* Keep a copy of the instruction in R5 */ - and r0, r0, #NIBBLE4 /* Register Rn Enum in R0[19:16] */ - lsr r0, r0, #16 /* Move Rn Enum to R0[3:0] */ - _regenum2index r0, r1 /* Convert Enum into Index in R1 */ - _getdbgregisterfromindex r1, r4 /* Retrieve Register contents from Index (R1) into R4 */ - teq r0, #REG_PC /* Check if it is PC relative */ - addeq r4, r4, #8 /* adjust for PC relative (+8) */ - tst r5, #0x01000000 /* Pre (1) or Post (0) Indexed */ - beq _exit_arm_ldr_pc_handler /* If Post-Indexed, just return value of Rn */ + + mov r1, #0 /* R1: Post-Indexed Offset (cleared) */ + tst r4, #0x01000000 /* Pre (1) or Post (0) Indexed */ + beq _get_rn_val /* If Post-Indexed, just return value of Rn */ + /* Pre-Indexed */ ldr r0, =(NIBBLE2|BYTE0) - and r0, r5, r0 /* 12 bit Immediate value or Shifted Reg operand */ - tst r5, #0x02000000 /* Immediate (0) or Register (1) */ + and r0, r4, r0 /* R0: 12 bit Immediate value or Shifted Reg operand */ + tst r4, #0x02000000 /* Immediate (0) or Register (1) */ beq _calc_ldr_pc_offset /* Immediate value is already in R0 */ _get_shiftedreg_val: - bl _arm_rmshifted_val /* Convert Rm shifted operand into value in R0 */ + bl _arm_rmshifted_val /* Convert Rm shifted operand in R0 into value in R0 */ _calc_ldr_pc_offset: - tst r5, #0x00800000 /* Add (1) or Subtract (0) */ - addne r4, r4, r0 /* If Add, R2 = Rn + value */ - subeq r4, r4, r0 /* If Sub, R2 = Rn - value */ + mov r1, r0 /* Keep Offset in R1 */ +_get_rn_val: + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ +_calc_op1val_with_offset: + tst r4, #0x00800000 /* Add (1) or Subtract (0) */ + addne r0, r0, r1 /* If Add, R0 = Rn + Offset */ + subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */ _exit_arm_ldr_pc_handler: - mov r0, r4 /* Return next instruction address in R0 */ ldmfd sp!, {pc} +#if 0 +/* Obsolete code */ + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ +#if 0 + and r3, r4, #NIBBLE4 /* Register Rn Enum in R3[19:16] */ + lsr r3, r3, #16 /* Move Rn Enum to R3[3:0] */ + _regenum2index r3, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R1) into R0 */ + teq r3, #REG_PC /* Check if it is PC relative */ + addeq r0, r0, #8 /* adjust for PC relative (+8) */ +#endif + tst r4, #0x01000000 /* Pre (1) or Post (0) Indexed */ + beq _exit_arm_ldr_pc_handler /* If Post-Indexed, just return value of Rn */ + /* Pre-Indexed */ + ldr r2, =(NIBBLE2|BYTE0) + and r2, r4, r2 /* R2: 12 bit Immediate value or Shifted Reg operand */ + tst r4, #0x02000000 /* Immediate (0) or Register (1) */ + beq _calc_ldr_pc_offset /* Immediate value is already in R2 */ + +_get_shiftedreg_val: +@@@ Fixme: R2 destroyed by _arm_rmshifted_val + + mov r2, r0 /* Keep Rn in R2 for now */ + bl _arm_rmshifted_val /* Convert Rm shifted operand into value in R0 */ + +_calc_ldr_pc_offset: + tst r4, #0x00800000 /* Add (1) or Subtract (0) */ + addne r0, r0, r2 /* If Add, R0 = Rn + value */ + subeq r0, r0, r2 /* If Sub, R0 = Rn - value */ + +_exit_arm_ldr_pc_handler: + ldmfd sp!, {pc} +#endif /* _arm_ldm_pc_handler * LDM {pc} @@ -2435,7 +2489,7 @@ _exit_arm_ldr_pc_handler: */ _arm_ldm_pc_handler: stmfd sp!, {lr} - and r3, r0, #0x000F0000 /* Store Rn (Operand 1) Register Enum into R3[19:16] */ + and r3, r0, #NIBBLE4 /* Store Rn (Operand 1) Register Enum into R3[19:16] */ lsr r3, r3, #16 /* Shift into R3[3:0] */ _arm_get_Rn_val: -- cgit v1.2.3 From eb3d7ebd9fc75e73cc6dd808b638c211e483eb08 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 4 Jul 2011 10:23:14 +0800 Subject: work in progress, done prelim audit of arm opcode parsing Preliminary ARM Opcode Parsing complete --- Debugger/debug_stub.S | 98 ++++++++++++++------------------------------------- 1 file changed, 27 insertions(+), 71 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 1cc4340..40d717e 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2400,8 +2400,6 @@ _arm_bx_blx_handler: #endif ldmfd sp!, {pc} -@@@ TODO: Code Audit Needed - /* _arm_ldr_pc_handler * LDR with Rd = PC * On entry: @@ -2418,7 +2416,7 @@ _arm_ldr_pc_handler: mov r1, #0 /* R1: Post-Indexed Offset (cleared) */ tst r4, #0x01000000 /* Pre (1) or Post (0) Indexed */ - beq _get_rn_val /* If Post-Indexed, just return value of Rn */ + beq _get_rn_val /* If Post-Indexed, just use Rn directly */ /* Pre-Indexed */ ldr r0, =(NIBBLE2|BYTE0) @@ -2438,43 +2436,10 @@ _calc_op1val_with_offset: addne r0, r0, r1 /* If Add, R0 = Rn + Offset */ subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */ -_exit_arm_ldr_pc_handler: +_get_ldr_pc_val_from_mem: + ldr r0, [r0] /* Retrieve value from Memory at address given in R0 */ ldmfd sp!, {pc} -#if 0 -/* Obsolete code */ - bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ -#if 0 - and r3, r4, #NIBBLE4 /* Register Rn Enum in R3[19:16] */ - lsr r3, r3, #16 /* Move Rn Enum to R3[3:0] */ - _regenum2index r3, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R1) into R0 */ - teq r3, #REG_PC /* Check if it is PC relative */ - addeq r0, r0, #8 /* adjust for PC relative (+8) */ -#endif - tst r4, #0x01000000 /* Pre (1) or Post (0) Indexed */ - beq _exit_arm_ldr_pc_handler /* If Post-Indexed, just return value of Rn */ - /* Pre-Indexed */ - ldr r2, =(NIBBLE2|BYTE0) - and r2, r4, r2 /* R2: 12 bit Immediate value or Shifted Reg operand */ - tst r4, #0x02000000 /* Immediate (0) or Register (1) */ - beq _calc_ldr_pc_offset /* Immediate value is already in R2 */ - -_get_shiftedreg_val: -@@@ Fixme: R2 destroyed by _arm_rmshifted_val - - mov r2, r0 /* Keep Rn in R2 for now */ - bl _arm_rmshifted_val /* Convert Rm shifted operand into value in R0 */ - -_calc_ldr_pc_offset: - tst r4, #0x00800000 /* Add (1) or Subtract (0) */ - addne r0, r0, r2 /* If Add, R0 = Rn + value */ - subeq r0, r0, r2 /* If Sub, R0 = Rn - value */ - -_exit_arm_ldr_pc_handler: - ldmfd sp!, {pc} -#endif - /* _arm_ldm_pc_handler * LDM {pc} * On entry: @@ -2483,37 +2448,32 @@ _exit_arm_ldr_pc_handler: * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address - * R1, R2, R3: destroyed + * R2, R3: destroyed * * FIXME: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit. */ _arm_ldm_pc_handler: stmfd sp!, {lr} - and r3, r0, #NIBBLE4 /* Store Rn (Operand 1) Register Enum into R3[19:16] */ - lsr r3, r3, #16 /* Shift into R3[3:0] */ - -_arm_get_Rn_val: - _regenum2index r3, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r1 /* Retrieve Register contents from Index (R2) into R1 */ - teq r3, #REG_PC /* Check if it is PC relative */ - addeq r1, r1, #8 /* adjust Rn (R1) for PC relative (+8) */ + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ _arm_get_regcount: mov r2, #0 /* Initialize reg_count (R2) to 0 */ - mov r3, r0, lsl #16 /* Keep HLFWORD0 containing vector bits in R3[31:16] */ + mov r3, r4, lsl #16 /* Keep HLFWORD0 containing vector bits in R3[31:16] */ /* This shortens the checking to a max of 16 iterations, since the PC bit should be set */ 1: movs r3, r3, lsl #1 /* count number of '1' bits */ addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ bne 1b /* continue until vector is empty */ _arm_check_updown_offset: - tst r0, #0x00800000 /* Check Up (1) or Down (0) */ - addne r1, r1, r2, lsl #2 /* Ascending: Rn (R1) += reg_count (R2) x 4 */ - subeq r1, r1, #4 /* Descending: Rn (R1) -= 4 */ - ldr r0, [r1] /* Retrieve stack content for new PC value */ + tst r4, #0x00800000 /* Check Up (1) or Down (0) */ + addne r0, r0, r2, lsl #2 /* Ascending: Rn (R0) += reg_count (R2) x 4 */ + subeq r0, r0, #4 /* Descending: Rn (R0) -= 4 */ + ldr r0, [r0] /* Retrieve stack content for new PC value */ ldmfd sp!, {pc} +#define ARM_B_L_X_INSTR_OPCODE_MASK 0xFE000000 +#define ARM_BLX_INSTR_OPCODE_VAL 0xFA000000 /* _arm_b_bl_blx_handler * B, BL or BLX . Note v4t does not have BLX instr @@ -2523,29 +2483,25 @@ _arm_check_updown_offset: * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address - * R1, R2, R3: destroyed + * R1: destroyed */ _arm_b_bl_blx_handler: stmfd sp!, {lr} -#ifndef __ARM6OR7__ - /* armv5t or later, has BLX support */ - mov r3, r0 /* Copy instruction to R3 */ -#endif _arm_b_bl_blx_get_offset: - and r0, r0, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R0[23:0] */ + and r0, r4, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R4[23:0] */ lsl r0, r0, #(32-24) /* Shift to R0[31:8] */ asr r0, r0, #(32-25) /* Actual Signed offset = Encode Offset x 2 in R0[25:0] */ - add r1, r1, #4 /* R1: (PC+4) + 4 */ + add r1, r6, #4 /* R1: (PC+4) + 4 */ add r0, r0, r1 /* Calculate Branch Target Address R0: (PC+8) + signed offset */ #ifndef __ARM6OR7__ /* armv5t or later, has BLX support */ - and r2, r3, #0xFE000000 /* Mask out Condition Code and Opcode */ - teq r2, #0xFA000000 /* Look for BLX */ + and r1, r4, #ARM_B_L_X_INSTR_OPCODE_MASK /* Mask out Condition Code and Opcode */ + teq r1, #ARM_BLX_INSTR_OPCODE_VAL /* Look for BLX */ bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */ - tst r3, #0x01000000 /* H bit for Thumb Halfword Address */ + tst r4, #0x01000000 /* H bit for Thumb Halfword Address */ orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */ orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ #endif @@ -2553,6 +2509,9 @@ _arm_b_bl_blx_get_offset: _exit_arm_b_bl_blx_handler: ldmfd sp!, {pc} +#define ARM_SWI_INSTR_MASK 0x0F000000 +#define ARM_SWI_INSTR_VAL 0x0F000000 + /* _arm_coproc_swi_handler * SVC (SWI) or Coprocessor instruction * On entry: @@ -2561,22 +2520,19 @@ _exit_arm_b_bl_blx_handler: * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address - * R1, R2: destroyed */ _arm_coproc_swi_handler: - and r2, r0, #0x0F000000 - teq r2, #0x0F000000 /* SVC (SWI) instruction */ + and r0, r4, #ARM_SWI_INSTR_MASK + teq r0, #ARM_SWI_INSTR_VAL /* SVC (SWI) instruction */ -_arm_swi_instr: - ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */ - beq _exit_arm_coproc_swi_handler - -_arm_coproc_instr: - mov r0, r1 /* Use default Following Instruction Address */ + ldreq r0, =SVC_VECTOR /* SWI: Return SVC Vector Address */ + movne r0, r6 /* CoProc: Use default Following Instruction Address */ _exit_arm_coproc_swi_handler: bx lr +@@@ TODO: Code Audit Needed + /* _thumb_bx_blx_handler * BX or BLX Handler. Note: b7 (H1) is not matched in the mask (should be 0); armv4t does not support BLX. -- cgit v1.2.3 From e99de21c49589cd177540cf27ad9220142b4542d Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 4 Jul 2011 11:07:48 +0800 Subject: update arm opcode parser for ldm instruction Code Audit. Fix LDM parsing for Pre-Post Indexing modes. --- Debugger/debug_stub.S | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 40d717e..f48d986 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2267,14 +2267,6 @@ _arm_op2_is_reg: _arm_get_operand1_val: bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ -#if 0 - and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */ - lsr r3, r3, #16 /* Shift into R3[3:0] */ - _regenum2index r3, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ - teq r3, #REG_PC /* Check if it is PC relative */ - addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ -#endif _arm_calc_data_instr_val: and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */ @@ -2464,10 +2456,28 @@ _arm_get_regcount: addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ bne 1b /* continue until vector is empty */ + /* Pre-Incr: Rn += reg_count x 4 + * Post-Incr: Rn += (reg_count - 1) x 4 + * Pre-Decr: Rn -= 4 + * Post-Decr: Rn + */ + _arm_check_updown_offset: tst r4, #0x00800000 /* Check Up (1) or Down (0) */ - addne r0, r0, r2, lsl #2 /* Ascending: Rn (R0) += reg_count (R2) x 4 */ - subeq r0, r0, #4 /* Descending: Rn (R0) -= 4 */ + beq _arm_check_prepost_decr + +_arm_check_prepost_incr: + tst r4, #0x01000000 /* Check Pre (1) or Post (0) */ + subeq r2, r2, #1 /* Post-Incr: Decrement reg_count in R2 */ + add r0, r0, r2, lsl #2 /* Increment Offset: Rn (R0) += reg_count (R2) x 4 */ + b _get_ldm_pc_val_from_mem + +_arm_check_prepost_decr: + tst r4, #0x01000000 /* Check Pre (1) or Post (0) */ + /* Post-Decr: Rn unchanged */ + subne r0, r0, #4 /* Pre-Decr: Rn (R0) -= 4 */ + +_get_ldm_pc_val_from_mem: ldr r0, [r0] /* Retrieve stack content for new PC value */ ldmfd sp!, {pc} -- cgit v1.2.3 From 9985ae796b3f4806fe7087b685b5067e6c7469cd Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 4 Jul 2011 11:25:25 +0800 Subject: code cleanup, moved constant defines to debug_internals.h --- Debugger/debug_internals.h | 12 ++++++++++++ Debugger/debug_stub.S | 18 +++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index c7f5d16..d82563e 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -230,6 +230,18 @@ #define CPSR_CFLAG 0x20000000 #define CPSR_VFLAG 0x10000000 + +/* + * ARM Opcode Masks (for Parser) + */ +#define ARM_DATA_INSTR_MASK 0x0FBF0000 +#define ARM_DATA_INSTR_MSRMRS 0x010F0000 +#define ARM_DATA_INSTR_NORMAL 0x01E00000 +#define ARM_B_L_X_INSTR_OPCODE_MASK 0xFE000000 +#define ARM_BLX_INSTR_OPCODE_VAL 0xFA000000 +#define ARM_SWI_INSTR_MASK 0x0F000000 +#define ARM_SWI_INSTR_VAL 0x0F000000 + /*@}*/ /** Debugger State Enums diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index f48d986..6142588 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -2223,9 +2223,6 @@ _reg_rrx: bx lr -#define ARM_DATA_INSTR_MASK 0x0FBF0000 -#define ARM_DATA_INSTR_MSRMRS 0x010F0000 -#define ARM_DATA_INSTR_NORMAL 0x01E00000 /* _arm_data_instr_handler * ARM Data Processing Instruction with Rd == R15 * On entry: @@ -2329,21 +2326,21 @@ _opcode_add: _opcode_adc: /* Op1 + Op2 + C */ - tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ add r0, r0, r1 addne r0, r0, #1 /* Add C if set */ bx lr _opcode_sbc: /* Op1 - Op2 + C - 1 */ - tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ sub r0, r0, r1 subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ bx lr _opcode_rsc: /* Op2 - Op1 + C - 1 */ - tst r5, #0x02 /* R5[3:0] is shifted CPSR value: Test C Flag */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ rsb r0, r0, r1 subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ bx lr @@ -2442,7 +2439,8 @@ _get_ldr_pc_val_from_mem: * R0: following instruction address * R2, R3: destroyed * - * FIXME: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit. + * Note: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit. + * The algorithm here loads different content using LDM based on the value of the P bit. */ _arm_ldm_pc_handler: stmfd sp!, {lr} @@ -2482,9 +2480,6 @@ _get_ldm_pc_val_from_mem: ldmfd sp!, {pc} -#define ARM_B_L_X_INSTR_OPCODE_MASK 0xFE000000 -#define ARM_BLX_INSTR_OPCODE_VAL 0xFA000000 - /* _arm_b_bl_blx_handler * B, BL or BLX . Note v4t does not have BLX instr * On entry: @@ -2519,9 +2514,6 @@ _arm_b_bl_blx_get_offset: _exit_arm_b_bl_blx_handler: ldmfd sp!, {pc} -#define ARM_SWI_INSTR_MASK 0x0F000000 -#define ARM_SWI_INSTR_VAL 0x0F000000 - /* _arm_coproc_swi_handler * SVC (SWI) or Coprocessor instruction * On entry: -- cgit v1.2.3 From f83c5c09674b2d2dbdfe7cdd9cd2d776df229b43 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 4 Jul 2011 16:20:17 +0800 Subject: thumb instruction parser cleanups Cleanup Thumb Instruction Parser. --- Debugger/debug_internals.h | 40 +++++++++++++++--- Debugger/debug_stub.S | 103 +++++++++++++++++++++++---------------------- 2 files changed, 85 insertions(+), 58 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index d82563e..adb5497 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -234,13 +234,39 @@ /* * ARM Opcode Masks (for Parser) */ -#define ARM_DATA_INSTR_MASK 0x0FBF0000 -#define ARM_DATA_INSTR_MSRMRS 0x010F0000 -#define ARM_DATA_INSTR_NORMAL 0x01E00000 -#define ARM_B_L_X_INSTR_OPCODE_MASK 0xFE000000 -#define ARM_BLX_INSTR_OPCODE_VAL 0xFA000000 -#define ARM_SWI_INSTR_MASK 0x0F000000 -#define ARM_SWI_INSTR_VAL 0x0F000000 +#define ARM_DATA_INSTR_MASK 0x0FBF0000 +#define ARM_DATA_INSTR_MSRMRS 0x010F0000 +#define ARM_DATA_INSTR_NORMAL 0x01E00000 +#define ARM_DATA_INSTR_IMMREG 0x02000000 + +#define ARM_LDR_INSTR_REGIMM 0x02000000 +#define ARM_LDR_INSTR_PREPOST 0x01000000 +#define ARM_LDR_INSTR_UPDOWN 0x00800000 + +#define ARM_LDM_INSTR_PREPOST 0x01000000 +#define ARM_LDM_INSTR_UPDOWN 0x00800000 + +#define ARM_BLX_INSTR_MASK 0xFE000000 +#define ARM_BLX_INSTR_BLX 0xFA000000 +#define ARM_BLX_INSTR_HBIT 0x01000000 + +#define ARM_SWI_INSTR_MASK 0x0F000000 +#define ARM_SWI_INSTR_VAL 0x0F000000 + + +/* + * Thumb Opcode Masks (for Parser) + */ +#define THUMB_BLX_INSTR_REG_RNMASK 0x0078 + +#define THUMB_BCOND_SWI_INSTR_CONDMASK 0x0F00 +#define THUMB_BCOND_SWI_COND_UNUSED 0x0E00 +#define THUMB_BCOND_SWI_INSTR_SWI 0x0F00 + +#define THUMB_BLX_INSTR_IMM_HBIT 0x0800 +#define THUMB_BLX_INSTR_IMM_MASK 0xF000 +#define THUMB_BLX_INSTR_IMM_BL 0xF000 +#define THUMB_BLX_INSTR_IMM_BLX 0xE000 /*@}*/ diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 6142588..40bd322 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -361,7 +361,7 @@ debug_armDecodeTable: debug_thumbDecodeTable: .hword 0x4700, 0xff07 - .word _thumb_bx_blx_handler /* BX or BLX. Note: b7 (H1) is not matched in the mask */ + .word _thumb_bx_blx_handler /* BX or BLX. Note: Link (L:b7) is not checked in the mask */ .hword 0xbd00, 0xff00 .word _thumb_poppc_handler /* PUSH/POP, specifically POP {Rlist,PC} */ .hword 0xd000, 0xf000 @@ -2246,7 +2246,7 @@ _arm_is_msr_mrs_instr: /* Not MSR / MRS, so process normally */ _arm_check_operand2_type: - tst r4, #0x02000000 /* Check for Immediate (1) or Register (0) Operand 2 */ + tst r4, #ARM_DATA_INSTR_IMMREG /* Check for Immediate (1) or Register (0) Operand 2 */ beq _arm_op2_is_reg _arm_op2_is_imm: @@ -2404,13 +2404,13 @@ _arm_ldr_pc_handler: stmfd sp!, {lr} mov r1, #0 /* R1: Post-Indexed Offset (cleared) */ - tst r4, #0x01000000 /* Pre (1) or Post (0) Indexed */ + tst r4, #ARM_LDR_INSTR_PREPOST /* Pre (1) or Post (0) Indexed */ beq _get_rn_val /* If Post-Indexed, just use Rn directly */ /* Pre-Indexed */ ldr r0, =(NIBBLE2|BYTE0) and r0, r4, r0 /* R0: 12 bit Immediate value or Shifted Reg operand */ - tst r4, #0x02000000 /* Immediate (0) or Register (1) */ + tst r4, #ARM_LDR_INSTR_REGIMM /* Register (1) or Immediate (0) */ beq _calc_ldr_pc_offset /* Immediate value is already in R0 */ _get_shiftedreg_val: @@ -2421,7 +2421,7 @@ _calc_ldr_pc_offset: _get_rn_val: bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ _calc_op1val_with_offset: - tst r4, #0x00800000 /* Add (1) or Subtract (0) */ + tst r4, #ARM_LDR_INSTR_UPDOWN /* Add (1) or Subtract (0) */ addne r0, r0, r1 /* If Add, R0 = Rn + Offset */ subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */ @@ -2461,17 +2461,17 @@ _arm_get_regcount: */ _arm_check_updown_offset: - tst r4, #0x00800000 /* Check Up (1) or Down (0) */ + tst r4, #ARM_LDM_INSTR_UPDOWN /* Check Up (1) or Down (0) */ beq _arm_check_prepost_decr _arm_check_prepost_incr: - tst r4, #0x01000000 /* Check Pre (1) or Post (0) */ + tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ subeq r2, r2, #1 /* Post-Incr: Decrement reg_count in R2 */ add r0, r0, r2, lsl #2 /* Increment Offset: Rn (R0) += reg_count (R2) x 4 */ b _get_ldm_pc_val_from_mem _arm_check_prepost_decr: - tst r4, #0x01000000 /* Check Pre (1) or Post (0) */ + tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ /* Post-Decr: Rn unchanged */ subne r0, r0, #4 /* Pre-Decr: Rn (R0) -= 4 */ @@ -2503,12 +2503,12 @@ _arm_b_bl_blx_get_offset: #ifndef __ARM6OR7__ /* armv5t or later, has BLX support */ - and r1, r4, #ARM_B_L_X_INSTR_OPCODE_MASK /* Mask out Condition Code and Opcode */ - teq r1, #ARM_BLX_INSTR_OPCODE_VAL /* Look for BLX */ + and r1, r4, #ARM_BLX_INSTR_MASK /* Mask out Condition Code and Opcode */ + teq r1, #ARM_BLX_INSTR_BLX /* Look for BLX */ bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */ - tst r4, #0x01000000 /* H bit for Thumb Halfword Address */ + tst r4, #ARM_BLX_INSTR_HBIT /* H bit for Thumb Halfword Address */ orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */ - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + orr r0, r0, #0x01 /* Set R0[0] since BLX instr used to switch to Thumb mode */ #endif _exit_arm_b_bl_blx_handler: @@ -2533,11 +2533,8 @@ _arm_coproc_swi_handler: _exit_arm_coproc_swi_handler: bx lr -@@@ TODO: Code Audit Needed - - /* _thumb_bx_blx_handler - * BX or BLX Handler. Note: b7 (H1) is not matched in the mask (should be 0); armv4t does not support BLX. + * BX or BLX Handler. Note: Link (L:b7) is not checked in the mask; armv4t does not support BLX. * On entry: * R4: Opcode of instruction to be executed * R5[3:0]: CPSR condition codes @@ -2548,7 +2545,7 @@ _exit_arm_coproc_swi_handler: */ _thumb_bx_blx_handler: stmfd sp!, {lr} - and r0, r0, #0x78 /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */ + and r0, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */ mov r0, r0, lsr #3 /* Shift Rn Enum to R0[3:0] */ _regenum2index r0, r1 /* Convert Enum into Index in R1 */ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ @@ -2563,7 +2560,7 @@ _thumb_bx_blx_handler: * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed + * R1-R3: destroyed */ _thumb_poppc_handler: stmfd sp!, {lr} @@ -2573,7 +2570,7 @@ _thumb_get_SP_val: _thumb_get_regcount: mov r2, #0 /* Initialize reg_count (R2) to 0 */ - mov r3, r0, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */ + mov r3, r4, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */ /* This shortens the checking to a max of 8 iterations */ 1: movs r3, r3, lsl #1 /* count number of '1' bits */ addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ @@ -2586,7 +2583,6 @@ _thumb_get_regcount: #endif ldmfd sp!, {pc} - /* _thumb_bcond_swi_handler * B or SWI (SVC) * On entry: @@ -2595,24 +2591,25 @@ _thumb_get_regcount: * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) - * R1-R6: destroyed + * R1-R3: destroyed */ _thumb_bcond_swi_handler: - mov r4, r0 /* Keep instruction in R4 */ - and r2, r0, #0x0F00 /* Keep Condition Code R2[11:8] */ - teq r2, #0x0F00 /* SVC (SWI) instruction */ + stmfd sp!, {lr} + and r2, r4, #THUMB_BCOND_SWI_INSTR_CONDMASK /* Keep Condition Code R2[11:8] */ + teq r2, #THUMB_BCOND_SWI_INSTR_SWI /* SVC (SWI) instruction */ _thumb_swi_instr: ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */ beq _exit_thumb_bcond_swi_handler /* Switch to ARM mode for SVC */ _thum_bcond_unused_instr: - teq r2, #0x0E00 + teq r2, #THUMB_BCOND_SWI_COND_UNUSED moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ beq _exit_thumb_bcond_instr _thumb_bcond_instr: - mov r6, r1 /* Store Default Following Instruction Address in R6 */ - lsl r0, r2, #(32-12) /* Shift condition code in R2[11:8] to R0[31:28] to match ARM cond-code format */ + stmfd sp!, {r4} /* Preserve Opcode in R4 */ + lsl r4, r2, #(32-12) /* Shift condition code in R2[11:8] to R0[31:28] to match ARM cond-code format */ bl _dbg_check_arm_condcode /* Use ARM condition code checking routine to test (R4, R6 unchanged) */ + ldmfd sp!, {r4} /* Restore Opcode in R4 */ teq r0, #FALSE moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ beq _exit_thumb_bcond_instr @@ -2625,7 +2622,7 @@ _thumb_calc_bcond_offset: _exit_thumb_bcond_instr: orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ _exit_thumb_bcond_swi_handler: - bx lr + ldmfd sp!, {pc} /* _thumb_b_handler * B @@ -2640,14 +2637,13 @@ _exit_thumb_bcond_swi_handler: */ _thumb_b_handler: stmfd sp!, {lr} - lsl r0, r0, #(32-11) /* Shift 11-bit offset in R0[10:0] to R0[31:21] */ + lsl r0, r4, #(32-11) /* Shift 11-bit offset in R4[10:0] to R0[31:21] */ asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */ - add r0, r1, r0 /* PC+2 + signed offset */ + add r0, r6, r0 /* PC+2 + signed offset */ add r0, r0, #2 /* PC+4 + signed offset */ orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ ldmfd sp!, {pc} - /* _thumb_long_bl_blx_handler * Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr; armv4t does not support BLX. * On entry: @@ -2657,6 +2653,7 @@ _thumb_b_handler: * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) * R1, R2, R3: destroyed + * R6: Subseqent Instruction Address (PC+4) if first instruction is valid, else unchanged (PC+2) * Note: The BL instruction (0xFxxx) should be in pairs (Dual 16-bit instructions). * The first instruction should have (H=0) to indicate the upper 11 bits of the encoded offset * The second instruction should have (H=1) to indicate the lower 11 bits of the encoded offset @@ -2668,38 +2665,42 @@ _thumb_b_handler: */ _thumb_long_bl_blx_handler: stmfd sp!, {lr} - tst r0, #0x0800 /* Check H bit */ +_thumb_check_1st_bl_blx_instruction: + tst r4, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ bne _return_default_thumb_following_instr /* H=1 as first instruction shouldn't happen */ - -_thumb_is_1st_bl_blx_instruction: - lsl r0, r0, #(32-11) /* Shift 11-bit offset in R0[10:0] to R0[31:21] */ +_thumb_check_2nd_bl_blx_instruction: + ldrh r3, [r6] /* Get second instruction in pair at PC+2 into R3 */ + add r6, r6, #2 /* Skip to Subsequent Instruction (PC+4) */ + tst r3, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ + beq _return_default_thumb_following_instr /* H=0 as second instruction shouldn't happen */ + +_thumb_concat_branch_offset: + lsl r0, r4, #(32-11) /* Shift first instruction 11-bit offset in R4[10:0] to R0[31:21] */ asr r0, r0, #(32-23) /* Convert into 12-bit signed offset in R0[22:12] */ - ldrh r3, [r1] /* Get second instruction in pair into R3 */ - tst r3, #0x0800 /* Check H bit */ - beq _exit_thumb_long_bl_blx_handler /* H=0 as second instruction shouldn't happen */ - - lsl r2, r3, #(32-11) /* Shift 11-bit offset in R3[10:0] to R2[31:21] */ + lsl r2, r3, #(32-11) /* Shift second instruction 11-bit offset in R3[10:0] to R2[31:21] */ lsr r2, r2, #(32-12) /* Convert into 12-bit unsigned offset in R2[11:0] */ orr r0, r0, r2 /* Combine offsets */ - add r0, r1, r0 /* PC+2 + signed offset */ - add r0, r0, #2 /* PC+4 + signed offset */ + add r0, r6, r0 /* PC+4 + signed offset */ -_thumb_is_2nd_bl_blx_instruction: - and r3, r3, #0x0F000 /* Keep instruction opcode in R3 */ - - cmp r3, #0x0F000 /* Look for BL */ - orreq r0, r0, #0x01 /* Match, set R0[0] since it is used to indicates Thumb mode */ - beq _exit_thumb_long_bl_blx_handler +_thumb_check_bl_blx_pair: + and r3, r3, #THUMB_BLX_INSTR_IMM_MASK /* Keep second instruction opcode in R3 */ + teq r3, #THUMB_BLX_INSTR_IMM_BL /* Look for BL */ + beq _flag_thumb_instr_addr /* Return BL target address in R0 */ #ifndef __ARM6OR7__ /* v5t or higher architecture */ - cmp r3, #0x0E000 /* Look for BLX */ - biceq r0, r0, #0x03 /* Match, Force ARM address */ + teq r3, #THUMB_BLX_INSTR_IMM_BLX /* Look for BLX */ + biceq r0, r0, #0x03 /* Match, Force ARM address */ beq _exit_thumb_long_bl_blx_handler #endif _return_default_thumb_following_instr: - mov r0, r1 /* Return default Following Instruction Address */ + /* FIXME: This assumes that once the 4-byte sequence check fails, it will return PC+4, + * regardless of whether the second instruction is a valid BL/BLX instruction or not. + */ + mov r0, r6 /* Return default Following/Subsequent Instruction Address */ +_flag_thumb_instr_addr: + orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ _exit_thumb_long_bl_blx_handler: ldmfd sp!, {pc} -- cgit v1.2.3 From 96911760b63c228774b2f947c29481cbc7b071e9 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 5 Jul 2011 09:19:41 +0800 Subject: fix step command response Remove ACK response from Step command, let the next breakpoint trigger the Signal response --- Debugger/debug_stub.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 40bd322..e03896c 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1324,7 +1324,10 @@ _dbg__step_is_manual_bkpt_or_address_specified: bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ bl dbg__activate_singlestep +#if 0 + /* Disable ACK transmit, let the next Breakpoint generate the Signal Response */ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ +#endif b _dbg__switch2undefmode /* _dbg__cmd_Kill -- cgit v1.2.3 From f8c74550cf2a06f62499e4abbcd1c82afb9a3d42 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 5 Jul 2011 09:37:12 +0800 Subject: refactoring, moved opcode parsing logic to separate file --- Debugger/debug_opcodes.S | 1443 ++++++++++++++++++++++++++++++++++++++++++++++ Debugger/debug_stub.S | 1438 +-------------------------------------------- 2 files changed, 1449 insertions(+), 1432 deletions(-) create mode 100644 Debugger/debug_opcodes.S diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S new file mode 100644 index 0000000..e460e83 --- /dev/null +++ b/Debugger/debug_opcodes.S @@ -0,0 +1,1443 @@ +/** @file debug_opcodes.S + * @brief ARM Debugger Opcode Parsing Routines + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ +/**************************************************************************** +// Selected Routines from the eCos arm_stub.c related to next instruction address +// determination in ARM processors. + +//======================================================================== +// +// arm_stub.c +// +// Helper functions for stub, generic to all ARM processors +// +//======================================================================== +// ####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later +// version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License +// along with eCos; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// As a special exception, if other files instantiate templates or use +// macros or inline functions from this file, or you compile this file +// and link it with other works to produce a work based on this file, +// this file does not by itself cause the resulting work to be covered by +// the GNU General Public License. However the source code for this file +// must still be made available in accordance with section (3) of the GNU +// General Public License v2. +// +// This exception does not invalidate any other reasons why a work based +// on this file might be covered by the GNU General Public License. +// ------------------------------------------- +// ####ECOSGPLCOPYRIGHTEND#### +//======================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Red Hat, gthomas +// Contributors: Red Hat, gthomas, jskov +// Date: 1998-11-26 +// Purpose: +// Description: Helper functions for stub, generic to all ARM processors +// Usage: +// +//####DESCRIPTIONEND#### +// +//======================================================================== + + +static int +ins_will_execute(unsigned long ins) +{ + unsigned long psr = get_register(PS); // condition codes + int res = 0; + switch ((ins & 0xF0000000) >> 28) { + case 0x0: // EQ + res = (psr & PS_Z) != 0; + break; + case 0x1: // NE + res = (psr & PS_Z) == 0; + break; + case 0x2: // CS + res = (psr & PS_C) != 0; + break; + case 0x3: // CC + res = (psr & PS_C) == 0; + break; + case 0x4: // MI + res = (psr & PS_N) != 0; + break; + case 0x5: // PL + res = (psr & PS_N) == 0; + break; + case 0x6: // VS + res = (psr & PS_V) != 0; + break; + case 0x7: // VC + res = (psr & PS_V) == 0; + break; + case 0x8: // HI + res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0); + break; + case 0x9: // LS + res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0); + break; + case 0xA: // GE + res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || + ((psr & (PS_N|PS_V)) == 0); + break; + case 0xB: // LT + res = ((psr & (PS_N|PS_V)) == PS_N) || + ((psr & (PS_N|PS_V)) == PS_V); + break; + case 0xC: // GT + res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || + ((psr & (PS_N|PS_V)) == 0); + res = ((psr & PS_Z) == 0) && res; + break; + case 0xD: // LE + res = ((psr & (PS_N|PS_V)) == PS_N) || + ((psr & (PS_N|PS_V)) == PS_V); + res = ((psr & PS_Z) == PS_Z) || res; + break; + case 0xE: // AL + res = TRUE; + break; + case 0xF: // NV + if (((ins & 0x0E000000) >> 24) == 0xA) + res = TRUE; + else + res = FALSE; + break; + } + return res; +} + +static unsigned long +RmShifted(int shift) +{ + unsigned long Rm = get_register(shift & 0x00F); + int shift_count; + if ((shift & 0x010) == 0) { + shift_count = (shift & 0xF80) >> 7; + } else { + shift_count = get_register((shift & 0xF00) >> 8); + } + switch ((shift & 0x060) >> 5) { + case 0x0: // Logical left + Rm <<= shift_count; + break; + case 0x1: // Logical right + Rm >>= shift_count; + break; + case 0x2: // Arithmetic right + Rm = (unsigned long)((long)Rm >> shift_count); + break; + case 0x3: // Rotate right + if (shift_count == 0) { + // Special case, RORx + Rm >>= 1; + if (get_register(PS) & PS_C) Rm |= 0x80000000; + } else { + Rm = (Rm >> shift_count) | (Rm << (32-shift_count)); + } + break; + } + return Rm; +} + +// Decide the next instruction to be executed for a given instruction +static unsigned long * +target_ins(unsigned long *pc, unsigned long ins) +{ + unsigned long new_pc, offset, op2; + unsigned long Rn; + int i, reg_count, c; + + switch ((ins & 0x0C000000) >> 26) { + case 0x0: + // BX or BLX + if ((ins & 0x0FFFFFD0) == 0x012FFF10) { + new_pc = (unsigned long)get_register(ins & 0x0000000F); + return ((unsigned long *)new_pc); + } + // Data processing + new_pc = (unsigned long)(pc+1); + if ((ins & 0x0000F000) == 0x0000F000) { + // Destination register is PC + if ((ins & 0x0FBF0000) != 0x010F0000) { + Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + if ((ins & 0x02000000) == 0) { + op2 = RmShifted(ins & 0x00000FFF); + } else { + op2 = ins & 0x000000FF; + i = (ins & 0x00000F00) >> 8; // Rotate count + op2 = (op2 >> (i*2)) | (op2 << (32-(i*2))); + } + switch ((ins & 0x01E00000) >> 21) { + case 0x0: // AND + new_pc = Rn & op2; + break; + case 0x1: // EOR + new_pc = Rn ^ op2; + break; + case 0x2: // SUB + new_pc = Rn - op2; + break; + case 0x3: // RSB + new_pc = op2 - Rn; + break; + case 0x4: // ADD + new_pc = Rn + op2; + break; + case 0x5: // ADC + c = (get_register(PS) & PS_C) != 0; + new_pc = Rn + op2 + c; + break; + case 0x6: // SBC + c = (get_register(PS) & PS_C) != 0; + new_pc = Rn - op2 + c - 1; + break; + case 0x7: // RSC + c = (get_register(PS) & PS_C) != 0; + new_pc = op2 - Rn +c - 1; + break; + case 0x8: // TST + case 0x9: // TEQ + case 0xA: // CMP + case 0xB: // CMN + break; // PC doesn't change + case 0xC: // ORR + new_pc = Rn | op2; + break; + case 0xD: // MOV + new_pc = op2; + break; + case 0xE: // BIC + new_pc = Rn & ~op2; + break; + case 0xF: // MVN + new_pc = ~op2; + break; + } + } + } + return ((unsigned long *)new_pc); + case 0x1: + if ((ins & 0x02000010) == 0x02000010) { + // Undefined! + return (pc+1); + } else { + if ((ins & 0x00100000) == 0) { + // STR + return (pc+1); + } else { + // LDR + if ((ins & 0x0000F000) != 0x0000F000) { + // Rd not PC + return (pc+1); + } else { + Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + if (ins & 0x01000000) { + // Add/subtract offset before + if ((ins & 0x02000000) == 0) { + // Immediate offset + if (ins & 0x00800000) { + // Add offset + Rn += (ins & 0x00000FFF); + } else { + // Subtract offset + Rn -= (ins & 0x00000FFF); + } + } else { + // Offset is in a register + if (ins & 0x00800000) { + // Add offset + Rn += RmShifted(ins & 0x00000FFF); + } else { + // Subtract offset + Rn -= RmShifted(ins & 0x00000FFF); + } + } + } + return ((unsigned long *)*(unsigned long *)Rn); + } + } + } + return (pc+1); + case 0x2: // Branch, LDM/STM + if ((ins & 0x02000000) == 0) { + // LDM/STM + if ((ins & 0x00100000) == 0) { + // STM + return (pc+1); + } else { + // LDM + if ((ins & 0x00008000) == 0) { + // PC not in list + return (pc+1); + } else { + Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); + if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! + offset = ins & 0x0000FFFF; + reg_count = 0; + for (i = 0; i < 15; i++) { + if (offset & (1<> 12) { + case 0x4: + // Check for BX or BLX + if ((ins & 0xff07) == 0x4700) + new_pc = (unsigned long)get_register((ins & 0x00078) >> 3); + break; + case 0xb: + // push/pop + // Look for "pop {...,pc}" + if ((ins & 0xf00) == 0xd00) { + // find PC + sp = (unsigned long)get_register(SP); + + for (offset = i = 0; i < 8; i++) + if (ins & (1 << i)) + offset += 4; + + new_pc = *(cyg_uint32 *)(sp + offset); + + if (!v5T_semantics()) + new_pc = MAKE_THUMB_ADDR(new_pc); + } + break; + case 0xd: + // Bcc | SWI + // Use ARM function to check condition + arm_ins = ((unsigned long)(ins & 0x0f00)) << 20; + if ((arm_ins & 0xF0000000) == 0xF0000000) { + // SWI + new_pc = CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4; + } else if (ins_will_execute(arm_ins)) { + offset = (ins & 0x00FF) << 1; + if (ins & 0x0080) offset |= 0xFFFFFE00; // sign extend + new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); + } + break; + case 0xe: + // check for B + if ((ins & 0x0800) == 0) { + offset = (ins & 0x07FF) << 1; + if (ins & 0x0400) offset |= 0xFFFFF800; // sign extend + new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); + } + break; + case 0xf: + // BL/BLX (4byte instruction!) + // First instruction (bit 11 == 0) holds top-part of offset + if ((ins & 0x0800) == 0) { + offset = (ins & 0x07FF) << 12; + if (ins & 0x0400) offset |= 0xFF800000; // sign extend + // Get second instruction + // Second instruction (bit 11 == 1) holds bottom-part of offset + ins = *(unsigned short*)(pc+2); + // Check for BL/BLX + if ((ins & 0xE800) == 0xE800) { + offset |= (ins & 0x07ff) << 1; + new_pc = (unsigned long)(pc+4) + offset; + // If its BLX, force a full word alignment + // Otherwise, its a thumb address. + if (!(ins & 0x1000)) + new_pc &= ~3; + else + new_pc = MAKE_THUMB_ADDR(new_pc); + } + } + break; + } + + return new_pc; +} + +void __single_step (void) +{ + unsigned long pc = get_register(PC); + unsigned long cpsr = get_register(PS); + + // Calculate address of next instruction to be executed + if (cpsr & CPSR_THUMB_ENABLE) { + // thumb + ss_saved_pc = target_thumb_ins(pc, *(unsigned short*)pc); + } else { + // ARM + unsigned long curins = *(unsigned long*)pc; + if (ins_will_execute(curins)) { + // Decode instruction to decide what the next PC will be + ss_saved_pc = (unsigned long) target_ins((unsigned long*)pc, + curins); + } else { + // The current instruction will not execute (the conditions + // don't hold) + ss_saved_pc = pc+4; + } + } + + // Set breakpoint according to type + if (IS_THUMB_ADDR(ss_saved_pc)) { + // Thumb instruction + unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc); + ss_saved_thumb_instr = *(unsigned short*)t_pc; + *(unsigned short*)t_pc = HAL_BREAKINST_THUMB; + } else { + // ARM instruction + ss_saved_instr = *(unsigned long*)ss_saved_pc; + *(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM; + } +} + + ****************************************************************************/ + +#define __ASSEMBLY__ +#include "debug_stub.h" +#include "debug_internals.h" +#include "debug_macros.h" + +.data +.align 4 +/* Rm Shifted Shift Type Jump Table + * On entry: + * R0: Register Rm + * R1: Shift/Rotate Amount + * On exit: + * R0: RmShifted result + * + */ +debug_regShiftJumpTable: + .word _reg_lsl /* 00 */ + .word _reg_lsr /* 01 */ + .word _reg_asr /* 02 */ + .word _reg_ror /* 03 */ + .word _reg_rrx /* 04 */ + +/* Data Processing Instruction Jump Table + * On entry: + * R0: Register Rn (Operand 1) value + * R1: Operand 2 value + * R2: Default Next Instruction Address + * R5[3:0]: CPSR condition codes + * On exit: + * R0: Calculated result + * R1, R2, R3: Destroyed + * + */ +debug_dataInstrJumpTable: + .word _opcode_and /* 00 */ + .word _opcode_eor /* 01 */ + .word _opcode_sub /* 02 */ + .word _opcode_rsb /* 03 */ + .word _opcode_add /* 04 */ + .word _opcode_adc /* 05 */ + .word _opcode_sbc /* 06 */ + .word _opcode_rsc /* 07 */ + .word _opcode_tst /* 08 */ + .word _opcode_teq /* 09 */ + .word _opcode_cmp /* 0A */ + .word _opcode_cmn /* 0B */ + .word _opcode_orr /* 0C */ + .word _opcode_mov /* 0D */ + .word _opcode_bic /* 0E */ + .word _opcode_mvn /* 0F */ + + +/* + * To determine the next instruction to execute, we need to check current (breakpointed) instruction + * and determine whether it will be executed or not. This necessitates a mini instruction decoder + * that can check the type of instruction, as well as if it'll affect the PC. + * The instruction decoder used here is table based. Each entry in the table consists of: + * Instruction Identifier (IID), Instruction Bitmask (IBM), Instruction Handler Address (IHA) + * Null entries are placed at the end of the table. + * + * This allows for a flexible approach to handling instructions that we're interested in, at the expense + * of memory usage. + * + * For ARM, the IID & IBM are both 4 bytes, whereas the Thumb IID & IBM are 2 bytes. + * The IHA is always 4 bytes. + */ + +/* ARM Instruction Decode Table + * .word IID, IBM, IHA (12 bytes) + */ + +debug_armDecodeTable: + .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* Data Processing instr with Rd = R15 */ + .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* BX or BLX. Note v4t does not have BLX instr */ + .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* LDR with Rd = PC */ +/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */ + .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* LDM {pc} */ + .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* B, BL or BLX. Note v4t does not have BLX instr */ + .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* Coprocessor instr or SWI */ + .word 0x0,0x0,0x0 /* Null Entry */ + +/* Thumb Instruction Decode Table + * .hword IID, IBM + * .word IHA (8 bytes) + */ + +debug_thumbDecodeTable: + .hword 0x4700, 0xff07 + .word _thumb_bx_blx_handler /* BX or BLX. Note: Link (L:b7) is not checked in the mask */ + .hword 0xbd00, 0xff00 + .word _thumb_poppc_handler /* PUSH/POP, specifically POP {Rlist,PC} */ + .hword 0xd000, 0xf000 + .word _thumb_bcond_swi_handler /* B or SWI */ + .hword 0xe000, 0xf800 + .word _thumb_b_handler /* B */ + .hword 0xf000, 0xf000 + .word _thumb_long_bl_blx_handler /* Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr */ + .hword 0x0,0x0 + .word 0x0 /* Null Entry */ + +/* ARM Condition Code Mapping Table + * Converts Instruction encoding to SPSR Flags. + * b31 b30 b29 b28 + * N Z C V + * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet) + * Condition Code stored in MSN(set), LSN(clr) order + * Note1: 0x00 = AL. NV is deprecated, treat as AL + * Note2: 0xFF indicates that the condition checks needs to be handled separately (complex checks) + * + * EQ: Z set + * NE: Z clr + * HS/CS: C set + * LO/CC: C clr + * MI: N set + * PL: N clr + * VS: V set + * VC: V clr + * HI: C set AND Z clr + * LS: C clr AND Z set + */ + + +debug_armCondCodeTable: + /* EQ, NE, HS/CS, LO/CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV */ + .byte 0x40, 0x04, 0x20, 0x02, 0x80, 0x08, 0x10, 0x01, 0x24, 0x42, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 + +/* ARM Complex Condition Code Mapping Table + * Converts Instruction encoding to SPSR Flags. + * b31 b30 b29 b28 + * N Z C V + * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet) + * for GE, LT, GT and LE instructions only + * Condition Code stored in the following order: + * b7 b6 b5 b4 b3 b2 b1 b0 + * - - - ANDOR - Z set AND N==V (bit set = 1) + * - - - - - Z clr OR N!=V (bit clr = 0) + * + * GE: N == V + * LT: N != V + * GT: Z clr AND (N == V) + * LE: Z set OR (N != V) + */ + +#define COMPLEX_CONDCODE_START 0x0A +#define COMPLEX_CONDCODE_NEQV_MASK 0x01 +#define COMPLEX_CONDCODE_AND_MASK 0x02 +#define COMPLEX_CONDCODE_ZSET_MASK 0x04 +#define COMPLEX_CONDCODE_ANDOR_MASK 0x10 + +#define COMPLEX_CONDCODE_NFLAG 0x08 +#define COMPLEX_CONDCODE_ZFLAG 0x04 +#define COMPLEX_CONDCODE_CFLAG 0x02 +#define COMPLEX_CONDCODE_VFLAG 0x01 + + +debug_armComplexCCTable: + /* GE, LT, GT, LE */ + .byte 0x01, 0x00, 0x13, 0x14 + +.code 32 +.text +.align 4 + +/* dbg_following_instruction_addr + * Determine the address of the following instruction to execute. + * On entry: + * R0: Address of the instruction to be (re)executed + * On exit: + * R0: Destroyed + * R1: Following Instruction Address (31 bits, b0 = THUMB flag) + * R2-R7: Destroyed + * + * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted + * when we resume the program. + * + * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction + * address to skip the current aborted instruction and resume execution at the next instruction address, + * and the next instruction address to be returned to the calling routine is the following instruction + * address instead. + * + * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine + * the next instruction address (for inserting a Breakpoint). + */ + .global dbg_following_instruction_addr +dbg_following_instruction_addr: + stmfd sp!, {lr} +/* We assume that any BKPT instructions in the code will be Manual Breakpoints, + * i.e., the Debugger does not leave stray Single Step / Auto / Normal breakpoints in memory + */ + mov r6, r0 /* Keep instruction address in R6 */ + _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve User CPSR into R1 */ + and r0, r1, #CPSR_THUMB /* store Thumb Mode status in R0 */ + mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */ + +_dbg_get_aborted_instr: +1: teq r0, #0 /* Check if it is ARM or Thumb instruction */ + ldrneh r4, [r6] /* Load Thumb instruction opcode using Addr in R6 into R4 */ + ldrne r2, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ + ldreq r4, [r6] /* Load ARM instruction opcode using Addr in R6 into R4 */ + ldreq r2, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ + teq r4, r2 /* Is instruction opcode (R4) == Manual Breakpoint opcode (R2)? */ + bne 2f /* Not Manual breakpoint */ + teq r0, #0 /* Check if it is ARM or Thumb Manual Breakpoint */ + addne r6, r6, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ + addeq r6, r6, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ + b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ + +/* Here, R4 contains the instruction opcode which will be (re)executed when program resumes. + * We need to dissect it to see if it is a branch instruction. + * For ARM instructions, we also need to evaluate the current (breakpointed) instruction to see if it'll execute. + * If not, then the following instruction is at the address following the address of the opcode in R4 (Default Following Instruction Address in R6). + */ +2: + teq r0, #0 /* Check if it is ARM or Thumb instruction */ + beq _following_instr_is_arm +_following_instr_is_thumb: + add r6, r6, #2 /* Store default following Thumb instruction address to R6 */ + orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */ + /* R4: Candidate Instruction Opcode + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + */ + bl _eval_thumb_instruction /* following address is either ARM or Thumb */ + /* We must set this the Thumb bit only within the instruction handler since BX would switch modes */ + b _exit_dbg_following_instruction_addr + +_following_instr_is_arm: + add r6, r6, #4 /* Store default following ARM instruction address to R6 */ + /* R4: Candidate Instruction Opcode + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + */ + bl _eval_arm_instruction + +_exit_dbg_following_instruction_addr: + mov r1, r0 /* Return Actual Following Instruction Address in R1 (B0 set to indicate Thumb mode) */ + ldmfd sp!, {pc} + + +/* _eval_arm_instruction + * Evaluate ARM instruction to determine following instruction address + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1-R7: destroyed + */ +_eval_arm_instruction: + stmfd sp!, {lr} + bl _dbg_check_arm_condcode /* Returns R0: will_execute (boolean) */ + teq r0, #FALSE + moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */ + beq _exit_eval_arm_instruction /* and Return to caller */ + +_will_execute_arm_instr: + mov r0, #0 /* initialize ARM Decode Entry Table index register */ +1: + _dbg_armDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ + teq r1, #0 /* Check for Null Entry (End of Table marker) */ + moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ + beq _exit_eval_arm_instruction + and r7, r4, r2 /* Use R7 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ + teq r7, r1 + addne r0, r0, #1 /* No match, so keep looking */ + bne 1b + +_call_arm_code_handler: + mov lr, pc + bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ +_exit_eval_arm_instruction: + /* Returned Following Address Instruction in R0 (B0 set to indicate Thumb mode) */ + ldmfd sp!, {pc} + +/* _eval_thumb_instruction + * Evaluate Thumb instruction to determine following instruction address + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1-R7: destroyed + */ +_eval_thumb_instruction: + stmfd sp!, {lr} + /* Only B instructions are conditionally executed, deal with it in that Code Handler */ + mov r0, #0 /* initialize Thumb Decode Entry Table index register */ +1: + _dbg_thumbDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ + teq r1, #0 /* Check for Null Entry (End of Table marker) */ + moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ + beq _exit_eval_thumb_instruction + + and r7, r4, r2 /* Use R5 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ + teq r7, r1 + addne r0, r0, #1 /* No match, so keep looking */ + bne 1b + +_call_thumb_code_handler: + mov lr, pc + bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ +_exit_eval_thumb_instruction: + /* Returned Following Address Instruction in R0 */ + ldmfd sp!, {pc} + + +/**************************************************************************** + * + * Instruction Decode Routines + * + ****************************************************************************/ + +/* _dbg_check_arm_condcode + * Check ARM conditional execution code + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * On exit: + * R0: will_execute (boolean) + * R1-R3: Destroyed + */ + +_dbg_check_arm_condcode: + mov r0, #TRUE + mov r3, r4, lsr #28 /* convert condition code to index (0-F) */ + ldr r2, =debug_armCondCodeTable + ldrb r1, [r2, r3] /* Get condition code mask */ +/* + * The following check is unnecessary as it is covered by the set/clear checking algorithm + teq r1, #0 + beq _dbg_check_arm_condcode_exit +*/ + teq r1, #0xFF + bne _dbg_check_bits_set + + +/* + * Complex Checks: + * + * will_execute = TRUE [default condition] + * If (N == V) bit set + * will_execute = (N == V) + * else + * will_execute = (N != V) + * + * If (ANDOR bit) set + * z_match = ~(Z XOR Z set) + * If (AND bit set) + * will_execute = will_execute && z_match + * else + * will_execute = will_execute || z_match + */ +_dbg_cond_complex_check: + sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */ + ldr r2, =debug_armComplexCCTable + ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */ + + ands r2, r5, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Is (N == V == 0)? */ + teqne r2, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* No, Is (N == V == 1)? */ + bne _cond_nnev /* No, so (N != V) */ + + /* EQ: Either (N == V == 0) or (N == V == 1) */ +_cond_neqv: + tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ + moveq r0, #FALSE /* No, so will_execute = FALSE (for now) */ + b _cond_check_andor + + /* Else, N != V */ +_cond_nnev: + tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ + movne r0, #FALSE /* Yes, so will_execute = FALSE (for now) */ + +_cond_check_andor: + tst r1, #COMPLEX_CONDCODE_ANDOR_MASK + beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */ + + /* Use R2 to store Z Flag, R3 to store Z set Mask */ + and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */ + and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = Z set */ + eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if failed match */ + moveq r3, #TRUE /* Zero, so z flag matched */ + movne r3, #FALSE /* Non-zero, so z flag failed match */ + + tst r1, #COMPLEX_CONDCODE_AND_MASK /* Is AND mask set? */ + andne r0, r0, r3 /* Yes, so AND with will_execute */ + orreq r0, r0, r3 /* No, so OR with will_execute */ + b _dbg_check_arm_condcode_exit /* Return will_execute (R0) */ + +/* + * Simple Checks: + * + * will_execute = TRUE [default condition, equivalent to 0x00 (AL) ] + * If (SetBitMask is Non-Zero) + * will_execute = ((cond_code & SetBitMask) == SetBitMask) + * If will_execute && (ClearBitMask is Non-Zero) + * will_execute = will_execute && ((cond_code & ClearBitMask) == 0) + */ + +_dbg_check_bits_set: + movs r2, r1, lsr #4 /* R2: bits set */ + beq _dbg_check_bits_clear /* No bits set mask enabled, skip check */ + and r3, r5, r2 /* Check bits set IF bitmask non-zero */ + teq r2, r3 /* ((cond_code & SetBitMask) == SetBitMask)? */ + movne r0, #FALSE /* No, so will_execute = FALSE */ + bne _dbg_check_arm_condcode_exit /* Check failed (need to be TRUE to check bits clear), return */ + +_dbg_check_bits_clear: + ands r1, r1, #NIBBLE0 /* R1: bits clear */ + beq _dbg_check_arm_condcode_exit + ands r3, r5, r1 /* Check bits clear IF bitmask non-zero */ + movne r0, #FALSE /* (cond_code & ClearBitMask) != 0, so will_execute = FALSE */ + +_dbg_check_arm_condcode_exit: + bx lr /* Return to caller */ + +/* _arm_rmshifted_val + * Calculate value of Shifted Rm (operand) + * On entry: + * R0[11:0]: Shifted Rm operand + * On exit: + * R0: value of Shifted Rm + * R1, R2, R3: destroyed + */ +_arm_rmshifted_val: + stmfd sp!, {lr} + ldr r3, =(NIBBLE2|BYTE0) + and r3, r0, r3 /* 12 bit Shifted Register operand, copied to R3 */ + and r2, r3, #NIBBLE0 /* Register Rn Enum in R2 */ + _regenum2index r2, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r0 /* Retrieve Register Rn contents from Index (R2) into R0 */ + + tst r3, #0x10 /* B4: Immediate (0) or Register (1) shift count */ + /* check bitshift op */ + and r3, r3, #0x60 /* shift type */ + mov r3, r3, lsr #5 /* convert into shift type jumptable index */ + bne _arm_get_reg_shift /* Flags set previously via TST r3 (B4) */ +_arm_calc_const_shift: + movs r1, r3, lsr #7 /* Immediate shift count, 5 bit unsigned value in R1 */ + bne _arm_calc_shifted_rm_val /* Non-zero shift count, process normally */ + /* Must check for RRX == ROR #0 */ + teq r3, #0x3 /* ROR == 0x3 */ + addeq r3, r3, #1 + b _arm_calc_shifted_rm_val + +_arm_get_reg_shift: + mov r2, r3, lsr #8 /* Register-based shift count, 4 bit register enum in R2 */ + _regenum2index r2, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r1 /* Retrieve Register value (shift count) from Index (R2) into R1 */ + +_arm_calc_shifted_rm_val: + _dbg_jumpTableHandler debug_regShiftJumpTable, r2, r3 /* Calculate RmShifted value from R0: Rn Register val, R1: Shift/Rotate val */ + ldmfd sp!, {pc} + +/* Rm Shifted Shift Type Jump Table Routines + * On entry: + * R0: Register Rm + * R1: Shift/Rotate Amount + * On exit: + * R0: RmShifted result + * R1: destroyed + * + */ +_reg_lsl: + lsl r0, r0, r1 + bx lr + +_reg_lsr: + lsr r0, r0, r1 + bx lr + +_reg_asr: + asr r0, r0, r1 + bx lr + +_reg_ror: + ror r0, r0, r1 + bx lr + +_reg_rrx: + _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve CPSR contents into R1 */ + ands r1, r1, #CPSR_CFLAG /* Keep C Flag */ + movne r1, #0x80000000 /* Set B31 if C Flag set */ + lsr r0, r0, #1 /* Rm >> 1 */ + orr r0, r0, r1 /* Put C flag into B31 */ + bx lr + + +/* _arm_data_instr_handler + * ARM Data Processing Instruction with Rd == R15 + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address + * R1-R7: Destroyed + */ +_arm_data_instr_handler: + stmfd sp!, {lr} + ldr r1, =ARM_DATA_INSTR_MASK + and r3, r4, r1 /* Keep base instruction Opcode in R3 */ + ldr r1, =ARM_DATA_INSTR_MSRMRS + teq r3, r1 /* Check for MSR / MRS instruction */ + +_arm_is_msr_mrs_instr: + moveq r0, r6 /* Copy default next instruciton address to R0 */ + beq _exit_arm_data_instr_handler /* Return default next instruction address */ + + /* Not MSR / MRS, so process normally */ +_arm_check_operand2_type: + tst r4, #ARM_DATA_INSTR_IMMREG /* Check for Immediate (1) or Register (0) Operand 2 */ + beq _arm_op2_is_reg + +_arm_op2_is_imm: + and r1, r4, #BYTE0 /* 8 bit unsigned constant in R1 */ + and r2, r4, #NIBBLE2 /* (rotate count / 2) in R2[11:8] */ + lsr r2, r2, #7 /* actual rotate count in R2[4:0] */ + ror r1, r1, r2 /* Rotated constant in R1 */ + b _arm_get_operand1_val + +_arm_op2_is_reg: + ldr r1, =(NIBBLE2|BYTE0) + and r0, r4, r1 /* 12 bit register operand in R1 */ + bl _arm_rmshifted_val /* R0 contains the Rm shifted val */ + mov r1, r0 /* R1: Operand2 val */ + +_arm_get_operand1_val: + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ + +_arm_calc_data_instr_val: + and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */ + lsr r3, r3, #21 /* Shift Data Processing Opcode into R3[3:0] */ + /* Calculate data instruction value from R0: Register Rn (Operand1) val, R1: Operand2 val, R5[3:0]: CPSR, R6: Default Next Instr Addr */ + _dbg_jumpTableHandler debug_dataInstrJumpTable, r2, r3 /* Next Instruction Address in R0 */ +_exit_arm_data_instr_handler: + ldmfd sp!, {pc} + +/* _dbg_data_instr_retrieve_op1val + * Retrieve Data Instruction Operand 1 value + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Next Instruction Address (PC+4) + * On exit: + * R0: Register Rn (Operand 1) value + * R2, R3: Destroyed + * + */ +_dbg_data_instr_retrieve_op1val: + and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */ + lsr r3, r3, #16 /* Shift into R3[3:0] */ + _regenum2index r3, r2 /* Convert Enum into Index in R2 */ + _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ + teq r3, #REG_PC /* Check if it is PC relative */ + addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ + bx lr + +/* Data Processing Instruction Jump Table Routines + * On entry: + * R0: Register Rn (Operand 1) value + * R1: Operand 2 value + * R5[3:0]: CPSR condition codes + * R6: Default Next Instruction Address (PC+4) + * On exit: + * R0: Calculated result + * R1, R2, R3: Destroyed + * + */ +_opcode_and: + and r0, r0, r1 + bx lr + +_opcode_eor: + eor r0, r0, r1 + bx lr + +_opcode_sub: + sub r0, r0, r1 + bx lr + +_opcode_rsb: + rsb r0, r0, r1 + bx lr + +_opcode_add: + add r0, r0, r1 + bx lr + +_opcode_adc: + /* Op1 + Op2 + C */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ + add r0, r0, r1 + addne r0, r0, #1 /* Add C if set */ + bx lr + +_opcode_sbc: + /* Op1 - Op2 + C - 1 */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ + sub r0, r0, r1 + subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ + bx lr + +_opcode_rsc: + /* Op2 - Op1 + C - 1 */ + tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ + rsb r0, r0, r1 + subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ + bx lr + +_opcode_tst: +_opcode_teq: +_opcode_cmp: +_opcode_cmn: + mov r0, r6 /* Next Instruction Address is not modified */ + bx lr + +_opcode_orr: + orr r0, r0, r1 + bx lr + +_opcode_mov: + mov r0, r1 /* Operand 1 is ignored */ + bx lr + +_opcode_bic: + bic r0, r0, r1 + bx lr + +_opcode_mvn: + mvn r0, r1 /* Operand 1 is ignored */ + bx lr + +/* _arm_bx_blx_handler + * BX or BLX Rm Handler. Note v4t does not have BLX instr + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1: destroyed + */ +_arm_bx_blx_handler: + stmfd sp!, {lr} + and r0, r4, #NIBBLE0 /* Register Rn Enum in R0 */ + _regenum2index r0, r1 /* Convert Enum into Index in R1 */ + _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ + /* Here, the register value would have B0 set to indicate switch to Thumb mode */ +#if 0 + bic r0, #0x01 /* Clear R0[0] since it is used to indicates Thumb mode */ +#endif + ldmfd sp!, {pc} + +/* _arm_ldr_pc_handler + * LDR with Rd = PC + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address + * R1, R2, R3, R4, R5: destroyed + */ + +_arm_ldr_pc_handler: + stmfd sp!, {lr} + + mov r1, #0 /* R1: Post-Indexed Offset (cleared) */ + tst r4, #ARM_LDR_INSTR_PREPOST /* Pre (1) or Post (0) Indexed */ + beq _get_rn_val /* If Post-Indexed, just use Rn directly */ + + /* Pre-Indexed */ + ldr r0, =(NIBBLE2|BYTE0) + and r0, r4, r0 /* R0: 12 bit Immediate value or Shifted Reg operand */ + tst r4, #ARM_LDR_INSTR_REGIMM /* Register (1) or Immediate (0) */ + beq _calc_ldr_pc_offset /* Immediate value is already in R0 */ + +_get_shiftedreg_val: + bl _arm_rmshifted_val /* Convert Rm shifted operand in R0 into value in R0 */ + +_calc_ldr_pc_offset: + mov r1, r0 /* Keep Offset in R1 */ +_get_rn_val: + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ +_calc_op1val_with_offset: + tst r4, #ARM_LDR_INSTR_UPDOWN /* Add (1) or Subtract (0) */ + addne r0, r0, r1 /* If Add, R0 = Rn + Offset */ + subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */ + +_get_ldr_pc_val_from_mem: + ldr r0, [r0] /* Retrieve value from Memory at address given in R0 */ + ldmfd sp!, {pc} + +/* _arm_ldm_pc_handler + * LDM {pc} + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address + * R2, R3: destroyed + * + * Note: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit. + * The algorithm here loads different content using LDM based on the value of the P bit. + */ +_arm_ldm_pc_handler: + stmfd sp!, {lr} + bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ + +_arm_get_regcount: + mov r2, #0 /* Initialize reg_count (R2) to 0 */ + mov r3, r4, lsl #16 /* Keep HLFWORD0 containing vector bits in R3[31:16] */ + /* This shortens the checking to a max of 16 iterations, since the PC bit should be set */ +1: movs r3, r3, lsl #1 /* count number of '1' bits */ + addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ + bne 1b /* continue until vector is empty */ + + /* Pre-Incr: Rn += reg_count x 4 + * Post-Incr: Rn += (reg_count - 1) x 4 + * Pre-Decr: Rn -= 4 + * Post-Decr: Rn + */ + +_arm_check_updown_offset: + tst r4, #ARM_LDM_INSTR_UPDOWN /* Check Up (1) or Down (0) */ + beq _arm_check_prepost_decr + +_arm_check_prepost_incr: + tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ + subeq r2, r2, #1 /* Post-Incr: Decrement reg_count in R2 */ + add r0, r0, r2, lsl #2 /* Increment Offset: Rn (R0) += reg_count (R2) x 4 */ + b _get_ldm_pc_val_from_mem + +_arm_check_prepost_decr: + tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ + /* Post-Decr: Rn unchanged */ + subne r0, r0, #4 /* Pre-Decr: Rn (R0) -= 4 */ + +_get_ldm_pc_val_from_mem: + ldr r0, [r0] /* Retrieve stack content for new PC value */ + ldmfd sp!, {pc} + + +/* _arm_b_bl_blx_handler + * B, BL or BLX . Note v4t does not have BLX instr + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address + * R1: destroyed + */ + +_arm_b_bl_blx_handler: + stmfd sp!, {lr} + +_arm_b_bl_blx_get_offset: + and r0, r4, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R4[23:0] */ + lsl r0, r0, #(32-24) /* Shift to R0[31:8] */ + asr r0, r0, #(32-25) /* Actual Signed offset = Encode Offset x 2 in R0[25:0] */ + add r1, r6, #4 /* R1: (PC+4) + 4 */ + add r0, r0, r1 /* Calculate Branch Target Address R0: (PC+8) + signed offset */ + +#ifndef __ARM6OR7__ + /* armv5t or later, has BLX support */ + and r1, r4, #ARM_BLX_INSTR_MASK /* Mask out Condition Code and Opcode */ + teq r1, #ARM_BLX_INSTR_BLX /* Look for BLX */ + bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */ + tst r4, #ARM_BLX_INSTR_HBIT /* H bit for Thumb Halfword Address */ + orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */ + orr r0, r0, #0x01 /* Set R0[0] since BLX instr used to switch to Thumb mode */ +#endif + +_exit_arm_b_bl_blx_handler: + ldmfd sp!, {pc} + +/* _arm_coproc_swi_handler + * SVC (SWI) or Coprocessor instruction + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+4) + * On exit: + * R0: following instruction address + */ + +_arm_coproc_swi_handler: + and r0, r4, #ARM_SWI_INSTR_MASK + teq r0, #ARM_SWI_INSTR_VAL /* SVC (SWI) instruction */ + + ldreq r0, =SVC_VECTOR /* SWI: Return SVC Vector Address */ + movne r0, r6 /* CoProc: Use default Following Instruction Address */ +_exit_arm_coproc_swi_handler: + bx lr + +/* _thumb_bx_blx_handler + * BX or BLX Handler. Note: Link (L:b7) is not checked in the mask; armv4t does not support BLX. + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1: destroyed + */ +_thumb_bx_blx_handler: + stmfd sp!, {lr} + and r0, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */ + mov r0, r0, lsr #3 /* Shift Rn Enum to R0[3:0] */ + _regenum2index r0, r1 /* Convert Enum into Index in R1 */ + _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ + /* Here, the register value would have R0[0] set to indicate switch to Thumb mode */ + ldmfd sp!, {pc} + +/* _thumb_poppc_handler + * PUSH/POP, specifically POP {Rlist,PC} + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1-R3: destroyed + */ +_thumb_poppc_handler: + stmfd sp!, {lr} + +_thumb_get_SP_val: + _getdbgregister DBGSTACK_USERSP_INDEX, r1 /* Retrieve SP contents into R1 */ + +_thumb_get_regcount: + mov r2, #0 /* Initialize reg_count (R2) to 0 */ + mov r3, r4, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */ + /* This shortens the checking to a max of 8 iterations */ +1: movs r3, r3, lsl #1 /* count number of '1' bits */ + addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ + add r1, r1, #4 /* Walk the stack to locate the PUSHed LR (POP PC) value */ + bne 1b /* continue until vector is empty */ + ldr r0, [r1] /* Retrieve new PC value */ +#if 0 + /* PC Value should have B0 set */ + orr r0, r0, #0x01 /* Force R0[0] since it is used to indicates Thumb mode */ +#endif + ldmfd sp!, {pc} + +/* _thumb_bcond_swi_handler + * B or SWI (SVC) + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1-R3: destroyed + */ +_thumb_bcond_swi_handler: + stmfd sp!, {lr} + and r2, r4, #THUMB_BCOND_SWI_INSTR_CONDMASK /* Keep Condition Code R2[11:8] */ + teq r2, #THUMB_BCOND_SWI_INSTR_SWI /* SVC (SWI) instruction */ +_thumb_swi_instr: + ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */ + beq _exit_thumb_bcond_swi_handler /* Switch to ARM mode for SVC */ +_thum_bcond_unused_instr: + teq r2, #THUMB_BCOND_SWI_COND_UNUSED + moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ + beq _exit_thumb_bcond_instr + +_thumb_bcond_instr: + stmfd sp!, {r4} /* Preserve Opcode in R4 */ + lsl r4, r2, #(32-12) /* Shift condition code in R2[11:8] to R0[31:28] to match ARM cond-code format */ + bl _dbg_check_arm_condcode /* Use ARM condition code checking routine to test (R4, R6 unchanged) */ + ldmfd sp!, {r4} /* Restore Opcode in R4 */ + teq r0, #FALSE + moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ + beq _exit_thumb_bcond_instr + +_thumb_calc_bcond_offset: + lsl r0, r4, #(32-8) /* Shift 8-bit offset in R4[7:0] to R0[31:24] */ + asr r0, r0, #(32-9) /* Convert into 9-bit signed offset in R0[8:0] */ + add r0, r6, r0 /* PC+2 + signed offset */ + add r0, r0, #2 /* PC+4 + signed offset */ +_exit_thumb_bcond_instr: + orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ +_exit_thumb_bcond_swi_handler: + ldmfd sp!, {pc} + +/* _thumb_b_handler + * B + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1: destroyed + * Note: The signed offset is 12-bits (encoded value x 2) + */ +_thumb_b_handler: + stmfd sp!, {lr} + lsl r0, r4, #(32-11) /* Shift 11-bit offset in R4[10:0] to R0[31:21] */ + asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */ + add r0, r6, r0 /* PC+2 + signed offset */ + add r0, r0, #2 /* PC+4 + signed offset */ + orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + ldmfd sp!, {pc} + +/* _thumb_long_bl_blx_handler + * Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr; armv4t does not support BLX. + * On entry: + * R4: Opcode of instruction to be executed + * R5[3:0]: CPSR condition codes + * R6: Default Following Instruction Address (PC+2) + * On exit: + * R0: following instruction address (B0 set to indicate Thumb mode) + * R1, R2, R3: destroyed + * R6: Subseqent Instruction Address (PC+4) if first instruction is valid, else unchanged (PC+2) + * Note: The BL instruction (0xFxxx) should be in pairs (Dual 16-bit instructions). + * The first instruction should have (H=0) to indicate the upper 11 bits of the encoded offset + * The second instruction should have (H=1) to indicate the lower 11 bits of the encoded offset + * The signed offset is 23 bits (encoded value x 2) + * + * Note2: The BLX instruction (0xExxx) encodes the first instruciton using BL (0xFxxx) with H=0, + * while the second instruction has a different opcode value (0xExxx), with H=1. + * BLX is only used to switch to an ARM target. + */ +_thumb_long_bl_blx_handler: + stmfd sp!, {lr} +_thumb_check_1st_bl_blx_instruction: + tst r4, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ + bne _return_default_thumb_following_instr /* H=1 as first instruction shouldn't happen */ +_thumb_check_2nd_bl_blx_instruction: + ldrh r3, [r6] /* Get second instruction in pair at PC+2 into R3 */ + add r6, r6, #2 /* Skip to Subsequent Instruction (PC+4) */ + tst r3, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ + beq _return_default_thumb_following_instr /* H=0 as second instruction shouldn't happen */ + +_thumb_concat_branch_offset: + lsl r0, r4, #(32-11) /* Shift first instruction 11-bit offset in R4[10:0] to R0[31:21] */ + asr r0, r0, #(32-23) /* Convert into 12-bit signed offset in R0[22:12] */ + lsl r2, r3, #(32-11) /* Shift second instruction 11-bit offset in R3[10:0] to R2[31:21] */ + lsr r2, r2, #(32-12) /* Convert into 12-bit unsigned offset in R2[11:0] */ + orr r0, r0, r2 /* Combine offsets */ + add r0, r6, r0 /* PC+4 + signed offset */ + +_thumb_check_bl_blx_pair: + and r3, r3, #THUMB_BLX_INSTR_IMM_MASK /* Keep second instruction opcode in R3 */ + teq r3, #THUMB_BLX_INSTR_IMM_BL /* Look for BL */ + beq _flag_thumb_instr_addr /* Return BL target address in R0 */ + +#ifndef __ARM6OR7__ + /* v5t or higher architecture */ + teq r3, #THUMB_BLX_INSTR_IMM_BLX /* Look for BLX */ + biceq r0, r0, #0x03 /* Match, Force ARM address */ + beq _exit_thumb_long_bl_blx_handler +#endif + +_return_default_thumb_following_instr: + /* FIXME: This assumes that once the 4-byte sequence check fails, it will return PC+4, + * regardless of whether the second instruction is a valid BL/BLX instruction or not. + */ + mov r0, r6 /* Return default Following/Subsequent Instruction Address */ +_flag_thumb_instr_addr: + orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + +_exit_thumb_long_bl_blx_handler: + ldmfd sp!, {pc} + diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index e03896c..a0797c6 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -144,6 +144,9 @@ #include "debug_internals.h" #include "debug_macros.h" + /* Opcode Parser function reference */ + .extern dbg_following_instruction_addr + /* Hexutils function references */ .extern hex2char .extern char2hex @@ -280,158 +283,6 @@ debug_cmdJumpTable: .word _dbg__nop /* 'Q' */ .word 0 -/* Rm Shifted Shift Type Jump Table - * On entry: - * R0: Register Rm - * R1: Shift/Rotate Amount - * On exit: - * R0: RmShifted result - * - */ -debug_regShiftJumpTable: - .word _reg_lsl /* 00 */ - .word _reg_lsr /* 01 */ - .word _reg_asr /* 02 */ - .word _reg_ror /* 03 */ - .word _reg_rrx /* 04 */ - -/* Data Processing Instruction Jump Table - * On entry: - * R0: Register Rn (Operand 1) value - * R1: Operand 2 value - * R2: Default Next Instruction Address - * R5[3:0]: CPSR condition codes - * On exit: - * R0: Calculated result - * R1, R2, R3: Destroyed - * - */ -debug_dataInstrJumpTable: - .word _opcode_and /* 00 */ - .word _opcode_eor /* 01 */ - .word _opcode_sub /* 02 */ - .word _opcode_rsb /* 03 */ - .word _opcode_add /* 04 */ - .word _opcode_adc /* 05 */ - .word _opcode_sbc /* 06 */ - .word _opcode_rsc /* 07 */ - .word _opcode_tst /* 08 */ - .word _opcode_teq /* 09 */ - .word _opcode_cmp /* 0A */ - .word _opcode_cmn /* 0B */ - .word _opcode_orr /* 0C */ - .word _opcode_mov /* 0D */ - .word _opcode_bic /* 0E */ - .word _opcode_mvn /* 0F */ - - -/* - * To determine the next instruction to execute, we need to check current (breakpointed) instruction - * and determine whether it will be executed or not. This necessitates a mini instruction decoder - * that can check the type of instruction, as well as if it'll affect the PC. - * The instruction decoder used here is table based. Each entry in the table consists of: - * Instruction Identifier (IID), Instruction Bitmask (IBM), Instruction Handler Address (IHA) - * Null entries are placed at the end of the table. - * - * This allows for a flexible approach to handling instructions that we're interested in, at the expense - * of memory usage. - * - * For ARM, the IID & IBM are both 4 bytes, whereas the Thumb IID & IBM are 2 bytes. - * The IHA is always 4 bytes. - */ - -/* ARM Instruction Decode Table - * .word IID, IBM, IHA (12 bytes) - */ - -debug_armDecodeTable: - .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* Data Processing instr with Rd = R15 */ - .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* BX or BLX. Note v4t does not have BLX instr */ - .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* LDR with Rd = PC */ -/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */ - .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* LDM {pc} */ - .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* B, BL or BLX. Note v4t does not have BLX instr */ - .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* Coprocessor instr or SWI */ - .word 0x0,0x0,0x0 /* Null Entry */ - -/* Thumb Instruction Decode Table - * .hword IID, IBM - * .word IHA (8 bytes) - */ - -debug_thumbDecodeTable: - .hword 0x4700, 0xff07 - .word _thumb_bx_blx_handler /* BX or BLX. Note: Link (L:b7) is not checked in the mask */ - .hword 0xbd00, 0xff00 - .word _thumb_poppc_handler /* PUSH/POP, specifically POP {Rlist,PC} */ - .hword 0xd000, 0xf000 - .word _thumb_bcond_swi_handler /* B or SWI */ - .hword 0xe000, 0xf800 - .word _thumb_b_handler /* B */ - .hword 0xf000, 0xf000 - .word _thumb_long_bl_blx_handler /* Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr */ - .hword 0x0,0x0 - .word 0x0 /* Null Entry */ - -/* ARM Condition Code Mapping Table - * Converts Instruction encoding to SPSR Flags. - * b31 b30 b29 b28 - * N Z C V - * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet) - * Condition Code stored in MSN(set), LSN(clr) order - * Note1: 0x00 = AL. NV is deprecated, treat as AL - * Note2: 0xFF indicates that the condition checks needs to be handled separately (complex checks) - * - * EQ: Z set - * NE: Z clr - * HS/CS: C set - * LO/CC: C clr - * MI: N set - * PL: N clr - * VS: V set - * VC: V clr - * HI: C set AND Z clr - * LS: C clr AND Z set - */ - - -debug_armCondCodeTable: - /* EQ, NE, HS/CS, LO/CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV */ - .byte 0x40, 0x04, 0x20, 0x02, 0x80, 0x08, 0x10, 0x01, 0x24, 0x42, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 - -/* ARM Complex Condition Code Mapping Table - * Converts Instruction encoding to SPSR Flags. - * b31 b30 b29 b28 - * N Z C V - * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet) - * for GE, LT, GT and LE instructions only - * Condition Code stored in the following order: - * b7 b6 b5 b4 b3 b2 b1 b0 - * - - - ANDOR - Z set AND N==V (bit set = 1) - * - - - - - Z clr OR N!=V (bit clr = 0) - * - * GE: N == V - * LT: N != V - * GT: Z clr AND (N == V) - * LE: Z set OR (N != V) - */ - -#define COMPLEX_CONDCODE_START 0x0A -#define COMPLEX_CONDCODE_NEQV_MASK 0x01 -#define COMPLEX_CONDCODE_AND_MASK 0x02 -#define COMPLEX_CONDCODE_ZSET_MASK 0x04 -#define COMPLEX_CONDCODE_ANDOR_MASK 0x10 - -#define COMPLEX_CONDCODE_NFLAG 0x08 -#define COMPLEX_CONDCODE_ZFLAG 0x04 -#define COMPLEX_CONDCODE_CFLAG 0x02 -#define COMPLEX_CONDCODE_VFLAG 0x01 - - -debug_armComplexCCTable: - /* GE, LT, GT, LE */ - .byte 0x01, 0x00, 0x13, 0x14 - .code 32 .text .align 4 @@ -1252,14 +1103,10 @@ _dbg__cont_check_breakpoint_type: beq _dbg__cont_is_manual_bkpt_or_address_specified _dbg__cont_is_normal_breakpoint: -/* FIXME: _dbg_following_instruction_addr doesn't actually work currently. - This breaks normal breakpoints which need to determine the next instruction to execute - (for placing the autobreakpoint) prior to returning. -*/ _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ - bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ - bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ + bl dbg_following_instruction_addr /* following instruction address returned in r1 */ + bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ b _dbg__switch2undefmode @@ -1308,10 +1155,6 @@ _dbg__step_check_breakpoint_type: beq _dbg__step_is_manual_bkpt _dbg__step_is_normal_breakpoint: -/* FIXME: _dbg_following_instruction_addr doesn't actually work currently. - This breaks normal breakpoints which need to determine the next instruction to execute - (for placing the autobreakpoint) prior to returning. -*/ _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume usinh contents in R0, and scratch register R1 */ b _dbg__step_is_manual_bkpt_or_address_specified @@ -1321,7 +1164,7 @@ _dbg__step_is_manual_bkpt: /* b _dbg__step_is_manual_bkpt_or_address_specified */ _dbg__step_is_manual_bkpt_or_address_specified: - bl _dbg_following_instruction_addr /* following instruction address returned in r1 */ + bl dbg_following_instruction_addr /* following instruction address returned in r1 */ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ bl dbg__activate_singlestep #if 0 @@ -1440,1275 +1283,6 @@ _dbg__cmd_RemoveBreakpoint: bl _dbg__clear_one_breakpoint /* R0: address of breakpoint to clear */ b __dbg__procCmdOk - - - -/**************************************************************************** -// Selected Routines from the eCos arm_stub.c related to next instruction address -// determination in ARM processors. - -//======================================================================== -// -// arm_stub.c -// -// Helper functions for stub, generic to all ARM processors -// -//======================================================================== -// ####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later -// version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License -// along with eCos; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// As a special exception, if other files instantiate templates or use -// macros or inline functions from this file, or you compile this file -// and link it with other works to produce a work based on this file, -// this file does not by itself cause the resulting work to be covered by -// the GNU General Public License. However the source code for this file -// must still be made available in accordance with section (3) of the GNU -// General Public License v2. -// -// This exception does not invalidate any other reasons why a work based -// on this file might be covered by the GNU General Public License. -// ------------------------------------------- -// ####ECOSGPLCOPYRIGHTEND#### -//======================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Red Hat, gthomas -// Contributors: Red Hat, gthomas, jskov -// Date: 1998-11-26 -// Purpose: -// Description: Helper functions for stub, generic to all ARM processors -// Usage: -// -//####DESCRIPTIONEND#### -// -//======================================================================== - - -static int -ins_will_execute(unsigned long ins) -{ - unsigned long psr = get_register(PS); // condition codes - int res = 0; - switch ((ins & 0xF0000000) >> 28) { - case 0x0: // EQ - res = (psr & PS_Z) != 0; - break; - case 0x1: // NE - res = (psr & PS_Z) == 0; - break; - case 0x2: // CS - res = (psr & PS_C) != 0; - break; - case 0x3: // CC - res = (psr & PS_C) == 0; - break; - case 0x4: // MI - res = (psr & PS_N) != 0; - break; - case 0x5: // PL - res = (psr & PS_N) == 0; - break; - case 0x6: // VS - res = (psr & PS_V) != 0; - break; - case 0x7: // VC - res = (psr & PS_V) == 0; - break; - case 0x8: // HI - res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0); - break; - case 0x9: // LS - res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0); - break; - case 0xA: // GE - res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || - ((psr & (PS_N|PS_V)) == 0); - break; - case 0xB: // LT - res = ((psr & (PS_N|PS_V)) == PS_N) || - ((psr & (PS_N|PS_V)) == PS_V); - break; - case 0xC: // GT - res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || - ((psr & (PS_N|PS_V)) == 0); - res = ((psr & PS_Z) == 0) && res; - break; - case 0xD: // LE - res = ((psr & (PS_N|PS_V)) == PS_N) || - ((psr & (PS_N|PS_V)) == PS_V); - res = ((psr & PS_Z) == PS_Z) || res; - break; - case 0xE: // AL - res = TRUE; - break; - case 0xF: // NV - if (((ins & 0x0E000000) >> 24) == 0xA) - res = TRUE; - else - res = FALSE; - break; - } - return res; -} - -static unsigned long -RmShifted(int shift) -{ - unsigned long Rm = get_register(shift & 0x00F); - int shift_count; - if ((shift & 0x010) == 0) { - shift_count = (shift & 0xF80) >> 7; - } else { - shift_count = get_register((shift & 0xF00) >> 8); - } - switch ((shift & 0x060) >> 5) { - case 0x0: // Logical left - Rm <<= shift_count; - break; - case 0x1: // Logical right - Rm >>= shift_count; - break; - case 0x2: // Arithmetic right - Rm = (unsigned long)((long)Rm >> shift_count); - break; - case 0x3: // Rotate right - if (shift_count == 0) { - // Special case, RORx - Rm >>= 1; - if (get_register(PS) & PS_C) Rm |= 0x80000000; - } else { - Rm = (Rm >> shift_count) | (Rm << (32-shift_count)); - } - break; - } - return Rm; -} - -// Decide the next instruction to be executed for a given instruction -static unsigned long * -target_ins(unsigned long *pc, unsigned long ins) -{ - unsigned long new_pc, offset, op2; - unsigned long Rn; - int i, reg_count, c; - - switch ((ins & 0x0C000000) >> 26) { - case 0x0: - // BX or BLX - if ((ins & 0x0FFFFFD0) == 0x012FFF10) { - new_pc = (unsigned long)get_register(ins & 0x0000000F); - return ((unsigned long *)new_pc); - } - // Data processing - new_pc = (unsigned long)(pc+1); - if ((ins & 0x0000F000) == 0x0000F000) { - // Destination register is PC - if ((ins & 0x0FBF0000) != 0x010F0000) { - Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); - if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! - if ((ins & 0x02000000) == 0) { - op2 = RmShifted(ins & 0x00000FFF); - } else { - op2 = ins & 0x000000FF; - i = (ins & 0x00000F00) >> 8; // Rotate count - op2 = (op2 >> (i*2)) | (op2 << (32-(i*2))); - } - switch ((ins & 0x01E00000) >> 21) { - case 0x0: // AND - new_pc = Rn & op2; - break; - case 0x1: // EOR - new_pc = Rn ^ op2; - break; - case 0x2: // SUB - new_pc = Rn - op2; - break; - case 0x3: // RSB - new_pc = op2 - Rn; - break; - case 0x4: // ADD - new_pc = Rn + op2; - break; - case 0x5: // ADC - c = (get_register(PS) & PS_C) != 0; - new_pc = Rn + op2 + c; - break; - case 0x6: // SBC - c = (get_register(PS) & PS_C) != 0; - new_pc = Rn - op2 + c - 1; - break; - case 0x7: // RSC - c = (get_register(PS) & PS_C) != 0; - new_pc = op2 - Rn +c - 1; - break; - case 0x8: // TST - case 0x9: // TEQ - case 0xA: // CMP - case 0xB: // CMN - break; // PC doesn't change - case 0xC: // ORR - new_pc = Rn | op2; - break; - case 0xD: // MOV - new_pc = op2; - break; - case 0xE: // BIC - new_pc = Rn & ~op2; - break; - case 0xF: // MVN - new_pc = ~op2; - break; - } - } - } - return ((unsigned long *)new_pc); - case 0x1: - if ((ins & 0x02000010) == 0x02000010) { - // Undefined! - return (pc+1); - } else { - if ((ins & 0x00100000) == 0) { - // STR - return (pc+1); - } else { - // LDR - if ((ins & 0x0000F000) != 0x0000F000) { - // Rd not PC - return (pc+1); - } else { - Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); - if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! - if (ins & 0x01000000) { - // Add/subtract offset before - if ((ins & 0x02000000) == 0) { - // Immediate offset - if (ins & 0x00800000) { - // Add offset - Rn += (ins & 0x00000FFF); - } else { - // Subtract offset - Rn -= (ins & 0x00000FFF); - } - } else { - // Offset is in a register - if (ins & 0x00800000) { - // Add offset - Rn += RmShifted(ins & 0x00000FFF); - } else { - // Subtract offset - Rn -= RmShifted(ins & 0x00000FFF); - } - } - } - return ((unsigned long *)*(unsigned long *)Rn); - } - } - } - return (pc+1); - case 0x2: // Branch, LDM/STM - if ((ins & 0x02000000) == 0) { - // LDM/STM - if ((ins & 0x00100000) == 0) { - // STM - return (pc+1); - } else { - // LDM - if ((ins & 0x00008000) == 0) { - // PC not in list - return (pc+1); - } else { - Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); - if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! - offset = ins & 0x0000FFFF; - reg_count = 0; - for (i = 0; i < 15; i++) { - if (offset & (1<> 12) { - case 0x4: - // Check for BX or BLX - if ((ins & 0xff07) == 0x4700) - new_pc = (unsigned long)get_register((ins & 0x00078) >> 3); - break; - case 0xb: - // push/pop - // Look for "pop {...,pc}" - if ((ins & 0xf00) == 0xd00) { - // find PC - sp = (unsigned long)get_register(SP); - - for (offset = i = 0; i < 8; i++) - if (ins & (1 << i)) - offset += 4; - - new_pc = *(cyg_uint32 *)(sp + offset); - - if (!v5T_semantics()) - new_pc = MAKE_THUMB_ADDR(new_pc); - } - break; - case 0xd: - // Bcc | SWI - // Use ARM function to check condition - arm_ins = ((unsigned long)(ins & 0x0f00)) << 20; - if ((arm_ins & 0xF0000000) == 0xF0000000) { - // SWI - new_pc = CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4; - } else if (ins_will_execute(arm_ins)) { - offset = (ins & 0x00FF) << 1; - if (ins & 0x0080) offset |= 0xFFFFFE00; // sign extend - new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); - } - break; - case 0xe: - // check for B - if ((ins & 0x0800) == 0) { - offset = (ins & 0x07FF) << 1; - if (ins & 0x0400) offset |= 0xFFFFF800; // sign extend - new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); - } - break; - case 0xf: - // BL/BLX (4byte instruction!) - // First instruction (bit 11 == 0) holds top-part of offset - if ((ins & 0x0800) == 0) { - offset = (ins & 0x07FF) << 12; - if (ins & 0x0400) offset |= 0xFF800000; // sign extend - // Get second instruction - // Second instruction (bit 11 == 1) holds bottom-part of offset - ins = *(unsigned short*)(pc+2); - // Check for BL/BLX - if ((ins & 0xE800) == 0xE800) { - offset |= (ins & 0x07ff) << 1; - new_pc = (unsigned long)(pc+4) + offset; - // If its BLX, force a full word alignment - // Otherwise, its a thumb address. - if (!(ins & 0x1000)) - new_pc &= ~3; - else - new_pc = MAKE_THUMB_ADDR(new_pc); - } - } - break; - } - - return new_pc; -} - -void __single_step (void) -{ - unsigned long pc = get_register(PC); - unsigned long cpsr = get_register(PS); - - // Calculate address of next instruction to be executed - if (cpsr & CPSR_THUMB_ENABLE) { - // thumb - ss_saved_pc = target_thumb_ins(pc, *(unsigned short*)pc); - } else { - // ARM - unsigned long curins = *(unsigned long*)pc; - if (ins_will_execute(curins)) { - // Decode instruction to decide what the next PC will be - ss_saved_pc = (unsigned long) target_ins((unsigned long*)pc, - curins); - } else { - // The current instruction will not execute (the conditions - // don't hold) - ss_saved_pc = pc+4; - } - } - - // Set breakpoint according to type - if (IS_THUMB_ADDR(ss_saved_pc)) { - // Thumb instruction - unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc); - ss_saved_thumb_instr = *(unsigned short*)t_pc; - *(unsigned short*)t_pc = HAL_BREAKINST_THUMB; - } else { - // ARM instruction - ss_saved_instr = *(unsigned long*)ss_saved_pc; - *(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM; - } -} - - ****************************************************************************/ - -/* _dbg_following_instruction_addr - * Determine the address of the following instruction to execute. - * On entry: - * R0: Address of the instruction to be (re)executed - * On exit: - * R0: Destroyed - * R1: Following Instruction Address (31 bits, b0 = THUMB flag) - * R2-R7: Destroyed - * - * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted - * when we resume the program. - * - * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction - * address to skip the current aborted instruction and resume execution at the next instruction address, - * and the next instruction address to be returned to the calling routine is the following instruction - * address instead. - * - * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine - * the next instruction address (for inserting a Breakpoint). - */ -_dbg_following_instruction_addr: - stmfd sp!, {lr} -/* We assume that any BKPT instructions in the code will be Manual Breakpoints, - * i.e., the Debugger does not leave stray Single Step / Auto / Normal breakpoints in memory - */ - mov r6, r0 /* Keep instruction address in R6 */ - _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve User CPSR into R1 */ - and r0, r1, #CPSR_THUMB /* store Thumb Mode status in R0 */ - mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */ - -_dbg_get_aborted_instr: -1: teq r0, #0 /* Check if it is ARM or Thumb instruction */ - ldrneh r4, [r6] /* Load Thumb instruction opcode using Addr in R6 into R4 */ - ldrne r2, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ - ldreq r4, [r6] /* Load ARM instruction opcode using Addr in R6 into R4 */ - ldreq r2, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ - teq r4, r2 /* Is instruction opcode (R4) == Manual Breakpoint opcode (R2)? */ - bne 2f /* Not Manual breakpoint */ - teq r0, #0 /* Check if it is ARM or Thumb Manual Breakpoint */ - addne r6, r6, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ - addeq r6, r6, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ - b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ - -/* Here, R4 contains the instruction opcode which will be (re)executed when program resumes. - * We need to dissect it to see if it is a branch instruction. - * For ARM instructions, we also need to evaluate the current (breakpointed) instruction to see if it'll execute. - * If not, then the following instruction is at the address following the address of the opcode in R4 (Default Following Instruction Address in R6). - */ -2: - teq r0, #0 /* Check if it is ARM or Thumb instruction */ - beq _following_instr_is_arm -_following_instr_is_thumb: - add r6, r6, #2 /* Store default following Thumb instruction address to R6 */ - orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */ - /* R4: Candidate Instruction Opcode - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - */ - bl _eval_thumb_instruction /* following address is either ARM or Thumb */ - /* We must set this the Thumb bit only within the instruction handler since BX would switch modes */ - b _exit_dbg_following_instruction_addr - -_following_instr_is_arm: - add r6, r6, #4 /* Store default following ARM instruction address to R6 */ - /* R4: Candidate Instruction Opcode - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - */ - bl _eval_arm_instruction - -_exit_dbg_following_instruction_addr: - mov r1, r0 /* Return Actual Following Instruction Address in R1 (B0 set to indicate Thumb mode) */ - ldmfd sp!, {pc} - - -/* _eval_arm_instruction - * Evaluate ARM instruction to determine following instruction address - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1-R7: destroyed - */ -_eval_arm_instruction: - stmfd sp!, {lr} - bl _dbg_check_arm_condcode /* Returns R0: will_execute (boolean) */ - teq r0, #FALSE - moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */ - beq _exit_eval_arm_instruction /* and Return to caller */ - -_will_execute_arm_instr: - mov r0, #0 /* initialize ARM Decode Entry Table index register */ -1: - _dbg_armDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ - teq r1, #0 /* Check for Null Entry (End of Table marker) */ - moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ - beq _exit_eval_arm_instruction - and r7, r4, r2 /* Use R7 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ - teq r7, r1 - addne r0, r0, #1 /* No match, so keep looking */ - bne 1b - -_call_arm_code_handler: - mov lr, pc - bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ -_exit_eval_arm_instruction: - /* Returned Following Address Instruction in R0 (B0 set to indicate Thumb mode) */ - ldmfd sp!, {pc} - -/* _eval_thumb_instruction - * Evaluate Thumb instruction to determine following instruction address - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1-R7: destroyed - */ -_eval_thumb_instruction: - stmfd sp!, {lr} - /* Only B instructions are conditionally executed, deal with it in that Code Handler */ - mov r0, #0 /* initialize Thumb Decode Entry Table index register */ -1: - _dbg_thumbDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ - teq r1, #0 /* Check for Null Entry (End of Table marker) */ - moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ - beq _exit_eval_thumb_instruction - - and r7, r4, r2 /* Use R5 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ - teq r7, r1 - addne r0, r0, #1 /* No match, so keep looking */ - bne 1b - -_call_thumb_code_handler: - mov lr, pc - bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: Default Following Instruction Address */ -_exit_eval_thumb_instruction: - /* Returned Following Address Instruction in R0 */ - ldmfd sp!, {pc} - - -/**************************************************************************** - * - * Instruction Decode Routines - * - ****************************************************************************/ - -/* _dbg_check_arm_condcode - * Check ARM conditional execution code - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * On exit: - * R0: will_execute (boolean) - * R1-R3: Destroyed - */ - -_dbg_check_arm_condcode: - mov r0, #TRUE - mov r3, r4, lsr #28 /* convert condition code to index (0-F) */ - ldr r2, =debug_armCondCodeTable - ldrb r1, [r2, r3] /* Get condition code mask */ -/* - * The following check is unnecessary as it is covered by the set/clear checking algorithm - teq r1, #0 - beq _dbg_check_arm_condcode_exit -*/ - teq r1, #0xFF - bne _dbg_check_bits_set - - -/* - * Complex Checks: - * - * will_execute = TRUE [default condition] - * If (N == V) bit set - * will_execute = (N == V) - * else - * will_execute = (N != V) - * - * If (ANDOR bit) set - * z_match = ~(Z XOR Z set) - * If (AND bit set) - * will_execute = will_execute && z_match - * else - * will_execute = will_execute || z_match - */ -_dbg_cond_complex_check: - sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */ - ldr r2, =debug_armComplexCCTable - ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */ - - ands r2, r5, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Is (N == V == 0)? */ - teqne r2, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* No, Is (N == V == 1)? */ - bne _cond_nnev /* No, so (N != V) */ - - /* EQ: Either (N == V == 0) or (N == V == 1) */ -_cond_neqv: - tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ - moveq r0, #FALSE /* No, so will_execute = FALSE (for now) */ - b _cond_check_andor - - /* Else, N != V */ -_cond_nnev: - tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ - movne r0, #FALSE /* Yes, so will_execute = FALSE (for now) */ - -_cond_check_andor: - tst r1, #COMPLEX_CONDCODE_ANDOR_MASK - beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */ - - /* Use R2 to store Z Flag, R3 to store Z set Mask */ - and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */ - and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = Z set */ - eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if failed match */ - moveq r3, #TRUE /* Zero, so z flag matched */ - movne r3, #FALSE /* Non-zero, so z flag failed match */ - - tst r1, #COMPLEX_CONDCODE_AND_MASK /* Is AND mask set? */ - andne r0, r0, r3 /* Yes, so AND with will_execute */ - orreq r0, r0, r3 /* No, so OR with will_execute */ - b _dbg_check_arm_condcode_exit /* Return will_execute (R0) */ - -/* - * Simple Checks: - * - * will_execute = TRUE [default condition, equivalent to 0x00 (AL) ] - * If (SetBitMask is Non-Zero) - * will_execute = ((cond_code & SetBitMask) == SetBitMask) - * If will_execute && (ClearBitMask is Non-Zero) - * will_execute = will_execute && ((cond_code & ClearBitMask) == 0) - */ - -_dbg_check_bits_set: - movs r2, r1, lsr #4 /* R2: bits set */ - beq _dbg_check_bits_clear /* No bits set mask enabled, skip check */ - and r3, r5, r2 /* Check bits set IF bitmask non-zero */ - teq r2, r3 /* ((cond_code & SetBitMask) == SetBitMask)? */ - movne r0, #FALSE /* No, so will_execute = FALSE */ - bne _dbg_check_arm_condcode_exit /* Check failed (need to be TRUE to check bits clear), return */ - -_dbg_check_bits_clear: - ands r1, r1, #NIBBLE0 /* R1: bits clear */ - beq _dbg_check_arm_condcode_exit - ands r3, r5, r1 /* Check bits clear IF bitmask non-zero */ - movne r0, #FALSE /* (cond_code & ClearBitMask) != 0, so will_execute = FALSE */ - -_dbg_check_arm_condcode_exit: - bx lr /* Return to caller */ - -/* _arm_rmshifted_val - * Calculate value of Shifted Rm (operand) - * On entry: - * R0[11:0]: Shifted Rm operand - * On exit: - * R0: value of Shifted Rm - * R1, R2, R3: destroyed - */ -_arm_rmshifted_val: - stmfd sp!, {lr} - ldr r3, =(NIBBLE2|BYTE0) - and r3, r0, r3 /* 12 bit Shifted Register operand, copied to R3 */ - and r2, r3, #NIBBLE0 /* Register Rn Enum in R2 */ - _regenum2index r2, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register Rn contents from Index (R2) into R0 */ - - tst r3, #0x10 /* B4: Immediate (0) or Register (1) shift count */ - /* check bitshift op */ - and r3, r3, #0x60 /* shift type */ - mov r3, r3, lsr #5 /* convert into shift type jumptable index */ - bne _arm_get_reg_shift /* Flags set previously via TST r3 (B4) */ -_arm_calc_const_shift: - movs r1, r3, lsr #7 /* Immediate shift count, 5 bit unsigned value in R1 */ - bne _arm_calc_shifted_rm_val /* Non-zero shift count, process normally */ - /* Must check for RRX == ROR #0 */ - teq r3, #0x3 /* ROR == 0x3 */ - addeq r3, r3, #1 - b _arm_calc_shifted_rm_val - -_arm_get_reg_shift: - mov r2, r3, lsr #8 /* Register-based shift count, 4 bit register enum in R2 */ - _regenum2index r2, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r1 /* Retrieve Register value (shift count) from Index (R2) into R1 */ - -_arm_calc_shifted_rm_val: - _dbg_jumpTableHandler debug_regShiftJumpTable, r2, r3 /* Calculate RmShifted value from R0: Rn Register val, R1: Shift/Rotate val */ - ldmfd sp!, {pc} - -/* Rm Shifted Shift Type Jump Table Routines - * On entry: - * R0: Register Rm - * R1: Shift/Rotate Amount - * On exit: - * R0: RmShifted result - * R1: destroyed - * - */ -_reg_lsl: - lsl r0, r0, r1 - bx lr - -_reg_lsr: - lsr r0, r0, r1 - bx lr - -_reg_asr: - asr r0, r0, r1 - bx lr - -_reg_ror: - ror r0, r0, r1 - bx lr - -_reg_rrx: - _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve CPSR contents into R1 */ - ands r1, r1, #CPSR_CFLAG /* Keep C Flag */ - movne r1, #0x80000000 /* Set B31 if C Flag set */ - lsr r0, r0, #1 /* Rm >> 1 */ - orr r0, r0, r1 /* Put C flag into B31 */ - bx lr - - -/* _arm_data_instr_handler - * ARM Data Processing Instruction with Rd == R15 - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address - * R1-R7: Destroyed - */ -_arm_data_instr_handler: - stmfd sp!, {lr} - ldr r1, =ARM_DATA_INSTR_MASK - and r3, r4, r1 /* Keep base instruction Opcode in R3 */ - ldr r1, =ARM_DATA_INSTR_MSRMRS - teq r3, r1 /* Check for MSR / MRS instruction */ - -_arm_is_msr_mrs_instr: - moveq r0, r6 /* Copy default next instruciton address to R0 */ - beq _exit_arm_data_instr_handler /* Return default next instruction address */ - - /* Not MSR / MRS, so process normally */ -_arm_check_operand2_type: - tst r4, #ARM_DATA_INSTR_IMMREG /* Check for Immediate (1) or Register (0) Operand 2 */ - beq _arm_op2_is_reg - -_arm_op2_is_imm: - and r1, r4, #BYTE0 /* 8 bit unsigned constant in R1 */ - and r2, r4, #NIBBLE2 /* (rotate count / 2) in R2[11:8] */ - lsr r2, r2, #7 /* actual rotate count in R2[4:0] */ - ror r1, r1, r2 /* Rotated constant in R1 */ - b _arm_get_operand1_val - -_arm_op2_is_reg: - ldr r1, =(NIBBLE2|BYTE0) - and r0, r4, r1 /* 12 bit register operand in R1 */ - bl _arm_rmshifted_val /* R0 contains the Rm shifted val */ - mov r1, r0 /* R1: Operand2 val */ - -_arm_get_operand1_val: - bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ - -_arm_calc_data_instr_val: - and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */ - lsr r3, r3, #21 /* Shift Data Processing Opcode into R3[3:0] */ - /* Calculate data instruction value from R0: Register Rn (Operand1) val, R1: Operand2 val, R5[3:0]: CPSR, R6: Default Next Instr Addr */ - _dbg_jumpTableHandler debug_dataInstrJumpTable, r2, r3 /* Next Instruction Address in R0 */ -_exit_arm_data_instr_handler: - ldmfd sp!, {pc} - -/* _dbg_data_instr_retrieve_op1val - * Retrieve Data Instruction Operand 1 value - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Next Instruction Address (PC+4) - * On exit: - * R0: Register Rn (Operand 1) value - * R2, R3: Destroyed - * - */ -_dbg_data_instr_retrieve_op1val: - and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */ - lsr r3, r3, #16 /* Shift into R3[3:0] */ - _regenum2index r3, r2 /* Convert Enum into Index in R2 */ - _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */ - teq r3, #REG_PC /* Check if it is PC relative */ - addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */ - bx lr - -/* Data Processing Instruction Jump Table Routines - * On entry: - * R0: Register Rn (Operand 1) value - * R1: Operand 2 value - * R5[3:0]: CPSR condition codes - * R6: Default Next Instruction Address (PC+4) - * On exit: - * R0: Calculated result - * R1, R2, R3: Destroyed - * - */ -_opcode_and: - and r0, r0, r1 - bx lr - -_opcode_eor: - eor r0, r0, r1 - bx lr - -_opcode_sub: - sub r0, r0, r1 - bx lr - -_opcode_rsb: - rsb r0, r0, r1 - bx lr - -_opcode_add: - add r0, r0, r1 - bx lr - -_opcode_adc: - /* Op1 + Op2 + C */ - tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ - add r0, r0, r1 - addne r0, r0, #1 /* Add C if set */ - bx lr - -_opcode_sbc: - /* Op1 - Op2 + C - 1 */ - tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ - sub r0, r0, r1 - subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ - bx lr - -_opcode_rsc: - /* Op2 - Op1 + C - 1 */ - tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */ - rsb r0, r0, r1 - subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */ - bx lr - -_opcode_tst: -_opcode_teq: -_opcode_cmp: -_opcode_cmn: - mov r0, r6 /* Next Instruction Address is not modified */ - bx lr - -_opcode_orr: - orr r0, r0, r1 - bx lr - -_opcode_mov: - mov r0, r1 /* Operand 1 is ignored */ - bx lr - -_opcode_bic: - bic r0, r0, r1 - bx lr - -_opcode_mvn: - mvn r0, r1 /* Operand 1 is ignored */ - bx lr - -/* _arm_bx_blx_handler - * BX or BLX Rm Handler. Note v4t does not have BLX instr - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed - */ -_arm_bx_blx_handler: - stmfd sp!, {lr} - and r0, r4, #NIBBLE0 /* Register Rn Enum in R0 */ - _regenum2index r0, r1 /* Convert Enum into Index in R1 */ - _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ - /* Here, the register value would have B0 set to indicate switch to Thumb mode */ -#if 0 - bic r0, #0x01 /* Clear R0[0] since it is used to indicates Thumb mode */ -#endif - ldmfd sp!, {pc} - -/* _arm_ldr_pc_handler - * LDR with Rd = PC - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address - * R1, R2, R3, R4, R5: destroyed - */ - -_arm_ldr_pc_handler: - stmfd sp!, {lr} - - mov r1, #0 /* R1: Post-Indexed Offset (cleared) */ - tst r4, #ARM_LDR_INSTR_PREPOST /* Pre (1) or Post (0) Indexed */ - beq _get_rn_val /* If Post-Indexed, just use Rn directly */ - - /* Pre-Indexed */ - ldr r0, =(NIBBLE2|BYTE0) - and r0, r4, r0 /* R0: 12 bit Immediate value or Shifted Reg operand */ - tst r4, #ARM_LDR_INSTR_REGIMM /* Register (1) or Immediate (0) */ - beq _calc_ldr_pc_offset /* Immediate value is already in R0 */ - -_get_shiftedreg_val: - bl _arm_rmshifted_val /* Convert Rm shifted operand in R0 into value in R0 */ - -_calc_ldr_pc_offset: - mov r1, r0 /* Keep Offset in R1 */ -_get_rn_val: - bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ -_calc_op1val_with_offset: - tst r4, #ARM_LDR_INSTR_UPDOWN /* Add (1) or Subtract (0) */ - addne r0, r0, r1 /* If Add, R0 = Rn + Offset */ - subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */ - -_get_ldr_pc_val_from_mem: - ldr r0, [r0] /* Retrieve value from Memory at address given in R0 */ - ldmfd sp!, {pc} - -/* _arm_ldm_pc_handler - * LDM {pc} - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address - * R2, R3: destroyed - * - * Note: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit. - * The algorithm here loads different content using LDM based on the value of the P bit. - */ -_arm_ldm_pc_handler: - stmfd sp!, {lr} - bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */ - -_arm_get_regcount: - mov r2, #0 /* Initialize reg_count (R2) to 0 */ - mov r3, r4, lsl #16 /* Keep HLFWORD0 containing vector bits in R3[31:16] */ - /* This shortens the checking to a max of 16 iterations, since the PC bit should be set */ -1: movs r3, r3, lsl #1 /* count number of '1' bits */ - addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ - bne 1b /* continue until vector is empty */ - - /* Pre-Incr: Rn += reg_count x 4 - * Post-Incr: Rn += (reg_count - 1) x 4 - * Pre-Decr: Rn -= 4 - * Post-Decr: Rn - */ - -_arm_check_updown_offset: - tst r4, #ARM_LDM_INSTR_UPDOWN /* Check Up (1) or Down (0) */ - beq _arm_check_prepost_decr - -_arm_check_prepost_incr: - tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ - subeq r2, r2, #1 /* Post-Incr: Decrement reg_count in R2 */ - add r0, r0, r2, lsl #2 /* Increment Offset: Rn (R0) += reg_count (R2) x 4 */ - b _get_ldm_pc_val_from_mem - -_arm_check_prepost_decr: - tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */ - /* Post-Decr: Rn unchanged */ - subne r0, r0, #4 /* Pre-Decr: Rn (R0) -= 4 */ - -_get_ldm_pc_val_from_mem: - ldr r0, [r0] /* Retrieve stack content for new PC value */ - ldmfd sp!, {pc} - - -/* _arm_b_bl_blx_handler - * B, BL or BLX . Note v4t does not have BLX instr - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address - * R1: destroyed - */ - -_arm_b_bl_blx_handler: - stmfd sp!, {lr} - -_arm_b_bl_blx_get_offset: - and r0, r4, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R4[23:0] */ - lsl r0, r0, #(32-24) /* Shift to R0[31:8] */ - asr r0, r0, #(32-25) /* Actual Signed offset = Encode Offset x 2 in R0[25:0] */ - add r1, r6, #4 /* R1: (PC+4) + 4 */ - add r0, r0, r1 /* Calculate Branch Target Address R0: (PC+8) + signed offset */ - -#ifndef __ARM6OR7__ - /* armv5t or later, has BLX support */ - and r1, r4, #ARM_BLX_INSTR_MASK /* Mask out Condition Code and Opcode */ - teq r1, #ARM_BLX_INSTR_BLX /* Look for BLX */ - bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */ - tst r4, #ARM_BLX_INSTR_HBIT /* H bit for Thumb Halfword Address */ - orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */ - orr r0, r0, #0x01 /* Set R0[0] since BLX instr used to switch to Thumb mode */ -#endif - -_exit_arm_b_bl_blx_handler: - ldmfd sp!, {pc} - -/* _arm_coproc_swi_handler - * SVC (SWI) or Coprocessor instruction - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+4) - * On exit: - * R0: following instruction address - */ - -_arm_coproc_swi_handler: - and r0, r4, #ARM_SWI_INSTR_MASK - teq r0, #ARM_SWI_INSTR_VAL /* SVC (SWI) instruction */ - - ldreq r0, =SVC_VECTOR /* SWI: Return SVC Vector Address */ - movne r0, r6 /* CoProc: Use default Following Instruction Address */ -_exit_arm_coproc_swi_handler: - bx lr - -/* _thumb_bx_blx_handler - * BX or BLX Handler. Note: Link (L:b7) is not checked in the mask; armv4t does not support BLX. - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed - */ -_thumb_bx_blx_handler: - stmfd sp!, {lr} - and r0, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */ - mov r0, r0, lsr #3 /* Shift Rn Enum to R0[3:0] */ - _regenum2index r0, r1 /* Convert Enum into Index in R1 */ - _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ - /* Here, the register value would have R0[0] set to indicate switch to Thumb mode */ - ldmfd sp!, {pc} - -/* _thumb_poppc_handler - * PUSH/POP, specifically POP {Rlist,PC} - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1-R3: destroyed - */ -_thumb_poppc_handler: - stmfd sp!, {lr} - -_thumb_get_SP_val: - _getdbgregister DBGSTACK_USERSP_INDEX, r1 /* Retrieve SP contents into R1 */ - -_thumb_get_regcount: - mov r2, #0 /* Initialize reg_count (R2) to 0 */ - mov r3, r4, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */ - /* This shortens the checking to a max of 8 iterations */ -1: movs r3, r3, lsl #1 /* count number of '1' bits */ - addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ - add r1, r1, #4 /* Walk the stack to locate the PUSHed LR (POP PC) value */ - bne 1b /* continue until vector is empty */ - ldr r0, [r1] /* Retrieve new PC value */ -#if 0 - /* PC Value should have B0 set */ - orr r0, r0, #0x01 /* Force R0[0] since it is used to indicates Thumb mode */ -#endif - ldmfd sp!, {pc} - -/* _thumb_bcond_swi_handler - * B or SWI (SVC) - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1-R3: destroyed - */ -_thumb_bcond_swi_handler: - stmfd sp!, {lr} - and r2, r4, #THUMB_BCOND_SWI_INSTR_CONDMASK /* Keep Condition Code R2[11:8] */ - teq r2, #THUMB_BCOND_SWI_INSTR_SWI /* SVC (SWI) instruction */ -_thumb_swi_instr: - ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */ - beq _exit_thumb_bcond_swi_handler /* Switch to ARM mode for SVC */ -_thum_bcond_unused_instr: - teq r2, #THUMB_BCOND_SWI_COND_UNUSED - moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ - beq _exit_thumb_bcond_instr - -_thumb_bcond_instr: - stmfd sp!, {r4} /* Preserve Opcode in R4 */ - lsl r4, r2, #(32-12) /* Shift condition code in R2[11:8] to R0[31:28] to match ARM cond-code format */ - bl _dbg_check_arm_condcode /* Use ARM condition code checking routine to test (R4, R6 unchanged) */ - ldmfd sp!, {r4} /* Restore Opcode in R4 */ - teq r0, #FALSE - moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */ - beq _exit_thumb_bcond_instr - -_thumb_calc_bcond_offset: - lsl r0, r4, #(32-8) /* Shift 8-bit offset in R4[7:0] to R0[31:24] */ - asr r0, r0, #(32-9) /* Convert into 9-bit signed offset in R0[8:0] */ - add r0, r6, r0 /* PC+2 + signed offset */ - add r0, r0, #2 /* PC+4 + signed offset */ -_exit_thumb_bcond_instr: - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ -_exit_thumb_bcond_swi_handler: - ldmfd sp!, {pc} - -/* _thumb_b_handler - * B - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed - * Note: The signed offset is 12-bits (encoded value x 2) - */ -_thumb_b_handler: - stmfd sp!, {lr} - lsl r0, r4, #(32-11) /* Shift 11-bit offset in R4[10:0] to R0[31:21] */ - asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */ - add r0, r6, r0 /* PC+2 + signed offset */ - add r0, r0, #2 /* PC+4 + signed offset */ - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ - ldmfd sp!, {pc} - -/* _thumb_long_bl_blx_handler - * Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr; armv4t does not support BLX. - * On entry: - * R4: Opcode of instruction to be executed - * R5[3:0]: CPSR condition codes - * R6: Default Following Instruction Address (PC+2) - * On exit: - * R0: following instruction address (B0 set to indicate Thumb mode) - * R1, R2, R3: destroyed - * R6: Subseqent Instruction Address (PC+4) if first instruction is valid, else unchanged (PC+2) - * Note: The BL instruction (0xFxxx) should be in pairs (Dual 16-bit instructions). - * The first instruction should have (H=0) to indicate the upper 11 bits of the encoded offset - * The second instruction should have (H=1) to indicate the lower 11 bits of the encoded offset - * The signed offset is 23 bits (encoded value x 2) - * - * Note2: The BLX instruction (0xExxx) encodes the first instruciton using BL (0xFxxx) with H=0, - * while the second instruction has a different opcode value (0xExxx), with H=1. - * BLX is only used to switch to an ARM target. - */ -_thumb_long_bl_blx_handler: - stmfd sp!, {lr} -_thumb_check_1st_bl_blx_instruction: - tst r4, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ - bne _return_default_thumb_following_instr /* H=1 as first instruction shouldn't happen */ -_thumb_check_2nd_bl_blx_instruction: - ldrh r3, [r6] /* Get second instruction in pair at PC+2 into R3 */ - add r6, r6, #2 /* Skip to Subsequent Instruction (PC+4) */ - tst r3, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */ - beq _return_default_thumb_following_instr /* H=0 as second instruction shouldn't happen */ - -_thumb_concat_branch_offset: - lsl r0, r4, #(32-11) /* Shift first instruction 11-bit offset in R4[10:0] to R0[31:21] */ - asr r0, r0, #(32-23) /* Convert into 12-bit signed offset in R0[22:12] */ - lsl r2, r3, #(32-11) /* Shift second instruction 11-bit offset in R3[10:0] to R2[31:21] */ - lsr r2, r2, #(32-12) /* Convert into 12-bit unsigned offset in R2[11:0] */ - orr r0, r0, r2 /* Combine offsets */ - add r0, r6, r0 /* PC+4 + signed offset */ - -_thumb_check_bl_blx_pair: - and r3, r3, #THUMB_BLX_INSTR_IMM_MASK /* Keep second instruction opcode in R3 */ - teq r3, #THUMB_BLX_INSTR_IMM_BL /* Look for BL */ - beq _flag_thumb_instr_addr /* Return BL target address in R0 */ - -#ifndef __ARM6OR7__ - /* v5t or higher architecture */ - teq r3, #THUMB_BLX_INSTR_IMM_BLX /* Look for BLX */ - biceq r0, r0, #0x03 /* Match, Force ARM address */ - beq _exit_thumb_long_bl_blx_handler -#endif - -_return_default_thumb_following_instr: - /* FIXME: This assumes that once the 4-byte sequence check fails, it will return PC+4, - * regardless of whether the second instruction is a valid BL/BLX instruction or not. - */ - mov r0, r6 /* Return default Following/Subsequent Instruction Address */ -_flag_thumb_instr_addr: - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ - -_exit_thumb_long_bl_blx_handler: - ldmfd sp!, {pc} - - /**************************************************************************** * * Breakpoint Manipulation Routines -- cgit v1.2.3 From 0a17d7ae48b32cce9e9c7e7de80610ae429c7e26 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 5 Jul 2011 11:23:30 +0800 Subject: added gdb step command execution example routine --- Debugger/debug_test.S | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ Debugger/debug_test.h | 3 +++ 2 files changed, 66 insertions(+) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 91e19d2..ed4ae14 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -29,6 +29,58 @@ dbg__test_arm_bkpt: dbg__bkpt_arm /* Trigger ARM Manual Breakpoint */ ldmfd sp!,{pc} + +/********************************************** + * dbg__test_arm_instrstep Test Routine + * Used to test GDB Stepping command + * This routine exercises the mov, add, ldr, ldm, b, bl, + * and bx instructions which modify the PC (R15) + * In addition, conditional instructions are also evaluated. + * + */ + .global dbg__test_arm_instrstep +dbg__test_arm_instrstep: + stmfd sp!, {lr} + bl dbg__test_arm_instr_sub1 + ldr r1, =test_arm_2 /* R1: pointer to test_arm_2 */ + ldr r2, =test_arm_2 /* R2: pointer to test_arm_2 (should not be triggered) */ + mov pc, r1 + +test_arm_1: + subs r0, r0, #1 + addne pc, r1, #4 /* If R0 > 0, keep branching to a new location */ + /* else R0 == 0 */ + b exit_dbg__test_arm_instrstep + +test_arm_2: + sub r0, r0, #1 + cmp r0, #8 + bls test_arm_1 + bhi test_arm_3 + beq test_arm_2 + ldr pc, =test_arm_1 + +test_arm_3: + /* case for r0 == 9 */ + sub r0, r0, #1 + teq r0, #5 + ldreq r2, =test_arm_1 + ldrne r2, =test_arm_3 + bx r2 + +exit_dbg__test_arm_instrstep: + bl dbg__test_arm_instr_sub2 + ldmfd sp!, {pc} + +dbg__test_arm_instr_sub1: + mov r0, #10 + bx lr + +dbg__test_arm_instr_sub2: + stmfd sp!, {r4, lr} + mov r0, #TRUE + ldmfd sp!, {r4, pc} + /********************************************** * dbg__test_thumb_bkpt Test Routine * @@ -50,4 +102,15 @@ _thumb_entry: dbg__bkpt_thumb bx lr + +/********************************************** + * dbg__test_thumb_instrstep Test Routine + * Used to test GDB Stepping command + * + */ + .global dbg__test_thumb_instrstep +dbg__test_thumb_instrstep: + bx lr + + .end diff --git a/Debugger/debug_test.h b/Debugger/debug_test.h index 6680f58..1c004e7 100644 --- a/Debugger/debug_test.h +++ b/Debugger/debug_test.h @@ -27,6 +27,9 @@ FUNCDEF void dbg__test_arm_bkpt(void); FUNCDEF void dbg__test_thumb_bkpt(void); +FUNCDEF void dbg__test_arm_instrstep(void); +FUNCDEF void dbg__test_thumb_instrstep(void); + /*@}*/ #endif -- cgit v1.2.3 From b2f8982f8293ed6b875f2251b4a01011d1786428 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 08:25:06 +0800 Subject: fix bug in b and bl offset calculation, code cleanup. B/BL Instruction Parsing routine was not calculating the correct offset. Cleanup debugger stack frame access logic --- Debugger/debug_opcodes.S | 10 +++++----- Debugger/debug_stub.S | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index e460e83..6f203fd 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -683,9 +683,9 @@ _dbg_get_aborted_instr: * If not, then the following instruction is at the address following the address of the opcode in R4 (Default Following Instruction Address in R6). */ 2: - teq r0, #0 /* Check if it is ARM or Thumb instruction */ - beq _following_instr_is_arm -_following_instr_is_thumb: + teq r0, #0 /* Check if current instruction is ARM or Thumb instruction */ + beq _following_instr_addr_for_arm +_following_instr_addr_for_thumb: add r6, r6, #2 /* Store default following Thumb instruction address to R6 */ orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */ /* R4: Candidate Instruction Opcode @@ -696,7 +696,7 @@ _following_instr_is_thumb: /* We must set this the Thumb bit only within the instruction handler since BX would switch modes */ b _exit_dbg_following_instruction_addr -_following_instr_is_arm: +_following_instr_addr_for_arm: add r6, r6, #4 /* Store default following ARM instruction address to R6 */ /* R4: Candidate Instruction Opcode * R5[3:0]: CPSR condition codes @@ -1233,7 +1233,7 @@ _arm_b_bl_blx_handler: _arm_b_bl_blx_get_offset: and r0, r4, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R4[23:0] */ lsl r0, r0, #(32-24) /* Shift to R0[31:8] */ - asr r0, r0, #(32-25) /* Actual Signed offset = Encode Offset x 2 in R0[25:0] */ + asr r0, r0, #(32-26) /* Actual Signed offset = Encode Offset x 4 in R0[25:0] */ add r1, r6, #4 /* R1: (PC+4) + 4 */ add r0, r0, r1 /* Calculate Branch Target Address R0: (PC+8) + signed offset */ diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index a0797c6..2152f7f 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1090,8 +1090,7 @@ _dbg__cmd_Continue: _dbg__cont_fromAddr: bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ /* Continue from Specified Address */ - mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */ - _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */ + _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ b _dbg__cont_is_manual_bkpt_or_address_specified @@ -1102,6 +1101,7 @@ _dbg__cont_check_breakpoint_type: teq r0, #DBG_MANUAL_BKPT_THUMB beq _dbg__cont_is_manual_bkpt_or_address_specified +@ FIXME: Need to validate the following code _dbg__cont_is_normal_breakpoint: _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ @@ -1143,8 +1143,7 @@ _dbg__cmd_Step: _dbg__step_fromAddr: bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ /* Step from Specified Address */ - mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */ - _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */ + _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ b _dbg__step_is_manual_bkpt_or_address_specified _dbg__step_check_breakpoint_type: -- cgit v1.2.3 From 5adc436b9b0f10dc8461570d75bf9d0d4aeb3850 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 09:05:33 +0800 Subject: reorder arm opcode decode table entries to check for more specific instr first ARM BX/BLX instruction share similar opcode prefix with ARM Data instructions. We must check for the BX/BLX instruction first, otherwise the decoder will assume that it is a Data instruction. --- Debugger/debug_opcodes.S | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index 6f203fd..a2693b4 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -541,14 +541,18 @@ debug_dataInstrJumpTable: * .word IID, IBM, IHA (12 bytes) */ +/* WARNING: The sequence of matching instructions is important! + * Always check from more specific to more general IBMs + * for instructions sharing common opcode prefix bits. + */ debug_armDecodeTable: - .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* Data Processing instr with Rd = R15 */ - .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* BX or BLX. Note v4t does not have BLX instr */ - .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* LDR with Rd = PC */ -/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */ - .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* LDM {pc} */ - .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* B, BL or BLX. Note v4t does not have BLX instr */ - .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* Coprocessor instr or SWI */ + .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* [Prefix:00] BX or BLX. Note v4t does not have BLX instr */ + .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* [Prefix:00] Data Processing instr with Rd = R15 */ +/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* [Prefix:01] Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */ + .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* [Prefix:01] LDR with Rd = PC */ + .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* [Prefix:10] LDM {pc} */ + .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* [Prefix:10] B, BL or BLX. Note v4t does not have BLX instr */ + .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* [Prefix:11] Coprocessor instr or SWI */ .word 0x0,0x0,0x0 /* Null Entry */ /* Thumb Instruction Decode Table @@ -556,17 +560,21 @@ debug_armDecodeTable: * .word IHA (8 bytes) */ +/* WARNING: The sequence of matching instructions is important! + * Always check from more specific to more general IBMs + * for instructions sharing common opcode prefix bits. + */ debug_thumbDecodeTable: .hword 0x4700, 0xff07 - .word _thumb_bx_blx_handler /* BX or BLX. Note: Link (L:b7) is not checked in the mask */ + .word _thumb_bx_blx_handler /* [Prefix:01] BX or BLX. Note: Link (L:b7) is not checked in the mask */ .hword 0xbd00, 0xff00 - .word _thumb_poppc_handler /* PUSH/POP, specifically POP {Rlist,PC} */ + .word _thumb_poppc_handler /* [Prefix:10] PUSH/POP, specifically POP {Rlist,PC} */ .hword 0xd000, 0xf000 - .word _thumb_bcond_swi_handler /* B or SWI */ + .word _thumb_bcond_swi_handler /* [Prefix:11] B or SWI */ .hword 0xe000, 0xf800 - .word _thumb_b_handler /* B */ + .word _thumb_b_handler /* [Prefix:11] B */ .hword 0xf000, 0xf000 - .word _thumb_long_bl_blx_handler /* Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr */ + .word _thumb_long_bl_blx_handler /* [Prefix:11] Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr */ .hword 0x0,0x0 .word 0x0 /* Null Entry */ -- cgit v1.2.3 From e04b88b669338243a7228a86eff3c0c62aff8f9c Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 09:38:56 +0800 Subject: attempt to fix gdb nak retransmit endless loop When GDB sends a NAK (-) but does not receive what it expects, it will keep trying to get a valid response. We just try to retransmit the last message in this case, hopefully GDB will be satisfied. --- Debugger/debug_comm.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Debugger/debug_comm.S b/Debugger/debug_comm.S index e237999..7bb150f 100644 --- a/Debugger/debug_comm.S +++ b/Debugger/debug_comm.S @@ -398,7 +398,11 @@ _hasMsg2Copy: beq exit_dbg__getDebugMsg /* Valid length, return */ exit_dbg__getMsgError: + bl dbg__putDebugMsg /* Retransmit message */ + mov r0, #0 /* Flag no message received */ +#if 0 mov r0, #MSGBUF_MSGERROR +#endif exit_dbg__getDebugMsg: mov r1, r5 /* Return GDB Message Buffer Pointer in R1 */ ldmfd sp!, {r4,r5,pc} -- cgit v1.2.3 From 654c39440b698559ff3c7e5f345ad3b4c98d071f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 10:20:20 +0800 Subject: send nak '-' immediately upon receipt Implement GDB message retransmission from NXT to Host --- Host/nxt-gdb-server.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index 7de81b7..7606d75 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -80,6 +80,13 @@ class NXTGDBServer: assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" segs.append (self.pack (msg, 0)) end = self.in_buf.find (CTRLC) + + end = self.in_buf.find ('-') + if end >= 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + assert len (msg) <= self.pack_size, "NAK Packet too long!" + segs.append (self.pack (msg, 0)) + end = self.in_buf.find ('-') end = self.in_buf.find ('#') # Is # found and enough place for the checkum? @@ -87,8 +94,8 @@ class NXTGDBServer: msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] i = 0 gdbprefix = msg[i] - while gdbprefix in ['+', '-']: - # Ignore any '+' or '-' + while gdbprefix in ['+']: + # Ignore any '+' i += 1 gdbprefix = msg[i] if DEBUG2: -- cgit v1.2.3 From c579d271287bd850ed6d546d94b2f1151919a8ce Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 10:21:10 +0800 Subject: the previous transmitted message checksum must be cleared before retransmitting The previous transmitted message contained a checksum suffix. It must be cleared before retransmission in order to use dbg__putDebugMsg() to retransmit. --- Debugger/debug_comm.S | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Debugger/debug_comm.S b/Debugger/debug_comm.S index 7bb150f..70499e1 100644 --- a/Debugger/debug_comm.S +++ b/Debugger/debug_comm.S @@ -398,6 +398,17 @@ _hasMsg2Copy: beq exit_dbg__getDebugMsg /* Valid length, return */ exit_dbg__getMsgError: + /* We must first clear the existing message checksum */ + ldr r1, =debug_msgTxBufPtr /* R5: data structure base pointer */ + ldr r1, [r1] /* Tx buffer Start Address */ + +1: ldrb r0, [r1], #1 + teq r0, #MSGBUF_CHKSUMCHAR + bne 1b + + mov r0, #0 /* ASCIIZ */ + strb r0, [r1, #-1] /* Pointer R1 is now one past the MSGBUF_CHKSUMCHAR */ + bl dbg__putDebugMsg /* Retransmit message */ mov r0, #0 /* Flag no message received */ #if 0 -- cgit v1.2.3 From 48c5777e564acd22e1237fd63437f2413da9c541 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 12:00:36 +0800 Subject: made nak processing more robust --- Host/nxt-gdb-server.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index 7606d75..d66b12e 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -24,6 +24,8 @@ import pyfantom import struct CTRLC = chr(3) +NAKCHAR = '-' +ACKCHAR = '+' STATUS_QUERY = "$?#3F" DEFAULT_PORT = 2828 SELECT_TIMEOUT = 0.1 @@ -70,9 +72,25 @@ class NXTGDBServer: return body, segment_no def segment (self, data): - """Split datas in GDB commands and make segments with each command.""" + """Split messages in GDB commands and make segments with each command.""" segs = [ ] self.in_buf += data + + # Find ACK '+' + end = self.in_buf.find (ACKCHAR) + while end == 0: + self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR + if DEBUG2: + print "stripped ACK, remain: ", self.in_buf + end = self.in_buf.find (ACKCHAR) + + # Find NAK '-' + end = self.in_buf.find (NAKCHAR) + if end == 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (NAKCHAR) + # Find Ctrl-C (assumed to be by itself and not following a normal command) end = self.in_buf.find (CTRLC) if end >= 0: @@ -80,13 +98,6 @@ class NXTGDBServer: assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" segs.append (self.pack (msg, 0)) end = self.in_buf.find (CTRLC) - - end = self.in_buf.find ('-') - if end >= 0: - msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] - assert len (msg) <= self.pack_size, "NAK Packet too long!" - segs.append (self.pack (msg, 0)) - end = self.in_buf.find ('-') end = self.in_buf.find ('#') # Is # found and enough place for the checkum? @@ -94,7 +105,7 @@ class NXTGDBServer: msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] i = 0 gdbprefix = msg[i] - while gdbprefix in ['+']: + while gdbprefix in [ACKCHAR]: # Ignore any '+' i += 1 gdbprefix = msg[i] -- cgit v1.2.3 From 6351b5a7bf1fc79882767012510b34ff48f902f4 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 12:35:06 +0800 Subject: update comment on nak message processing --- Debugger/debug_comm.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_comm.S b/Debugger/debug_comm.S index 70499e1..4c23912 100644 --- a/Debugger/debug_comm.S +++ b/Debugger/debug_comm.S @@ -360,7 +360,7 @@ _hasMsg2Copy: moveq r0, r4 /* If found, set R0 to current message length */ beq exit_dbg__getDebugMsg /* and return */ teq r0, #MSGBUF_NAKCHAR /* Look for '-' */ - beq exit_dbg__getMsgError /* FIXME: We can't handle retransmission, flag message error */ + beq exit_dbg__getMsgError /* Error from Host, Retransmit previous message */ teq r0, #MSGBUF_ACKCHAR /* Look for '+' */ addeq r5, r5, #1 /* Adjust Buffer Start Pointer (excl '+') */ subeq r4, r4, #1 /* Adjust Message Length */ @@ -411,9 +411,11 @@ exit_dbg__getMsgError: bl dbg__putDebugMsg /* Retransmit message */ mov r0, #0 /* Flag no message received */ + #if 0 mov r0, #MSGBUF_MSGERROR #endif + exit_dbg__getDebugMsg: mov r1, r5 /* Return GDB Message Buffer Pointer in R1 */ ldmfd sp!, {r4,r5,pc} -- cgit v1.2.3 From 4a7632650397fa87a5a962bb9e2a02f26099229e Mon Sep 17 00:00:00 2001 From: TC Wan Date: Wed, 6 Jul 2011 15:24:11 +0800 Subject: updated arm condtion code check algorithm The previous ARM Condition Code checking algorithm was incorrect due to an error in the LS condition requirements. Revised algorithm with some code optimization --- Debugger/debug_opcodes.S | 131 +++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index a2693b4..d43991d 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -595,37 +595,40 @@ debug_thumbDecodeTable: * PL: N clr * VS: V set * VC: V clr - * HI: C set AND Z clr - * LS: C clr AND Z set */ debug_armCondCodeTable: /* EQ, NE, HS/CS, LO/CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV */ - .byte 0x40, 0x04, 0x20, 0x02, 0x80, 0x08, 0x10, 0x01, 0x24, 0x42, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 + .byte 0x40, 0x04, 0x20, 0x02, 0x80, 0x08, 0x10, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00 /* ARM Complex Condition Code Mapping Table * Converts Instruction encoding to SPSR Flags. * b31 b30 b29 b28 * N Z C V * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet) - * for GE, LT, GT and LE instructions only + * for HI, LS, GE, LT, GT and LE instructions only * Condition Code stored in the following order: - * b7 b6 b5 b4 b3 b2 b1 b0 - * - - - ANDOR - Z set AND N==V (bit set = 1) - * - - - - - Z clr OR N!=V (bit clr = 0) + * b7 b6 b5 b4 b3 b2 b1 b0 + * AND CHKZ CHKC CHKNV - Z set C set N==V (bit set = 1) + * OR - - - - Z clr C clr N!=V (bit clr = 0) * + * HI: C set AND Z clr + * LS: C clr OR Z set * GE: N == V * LT: N != V * GT: Z clr AND (N == V) * LE: Z set OR (N != V) */ -#define COMPLEX_CONDCODE_START 0x0A -#define COMPLEX_CONDCODE_NEQV_MASK 0x01 -#define COMPLEX_CONDCODE_AND_MASK 0x02 -#define COMPLEX_CONDCODE_ZSET_MASK 0x04 -#define COMPLEX_CONDCODE_ANDOR_MASK 0x10 +#define COMPLEX_CONDCODE_START 0x08 +#define COMPLEX_CONDCODE_NEQV_MASK 0x01 +#define COMPLEX_CONDCODE_CSET_MASK 0x02 +#define COMPLEX_CONDCODE_ZSET_MASK 0x04 +#define COMPLEX_CONDCODE_CHKNV_MASK 0x10 +#define COMPLEX_CONDCODE_CHKC_MASK 0x20 +#define COMPLEX_CONDCODE_CHKZ_MASK 0x40 +#define COMPLEX_CONDCODE_ANDOR_MASK 0x80 #define COMPLEX_CONDCODE_NFLAG 0x08 #define COMPLEX_CONDCODE_ZFLAG 0x04 @@ -634,8 +637,8 @@ debug_armCondCodeTable: debug_armComplexCCTable: - /* GE, LT, GT, LE */ - .byte 0x01, 0x00, 0x13, 0x14 + /* HI, LS, GE, LT, GT, LE */ + .byte 0xE2, 0x64, 0x11, 0x10, 0xD1, 0x54 .code 32 .text @@ -803,94 +806,122 @@ _exit_eval_thumb_instruction: */ _dbg_check_arm_condcode: - mov r0, #TRUE - mov r3, r4, lsr #28 /* convert condition code to index (0-F) */ + mov r0, #TRUE /* Default will_execute value */ + mov r3, r4, lsr #28 /* convert opcode's condition code to index (0-F) */ ldr r2, =debug_armCondCodeTable ldrb r1, [r2, r3] /* Get condition code mask */ /* - * The following check is unnecessary as it is covered by the set/clear checking algorithm + * The following check is unnecessary as it is covered by the _dbg_cond_simple_checks checking algorithm teq r1, #0 beq _dbg_check_arm_condcode_exit */ teq r1, #0xFF - bne _dbg_check_bits_set + bne _dbg_cond_simple_checks /* * Complex Checks: + * We assume that CHKNV and CHKC are mutually exclusive. + * In addition, it is possible for CHKNV, CHKC and CHKZ to + * be cleared, in which case it'll return True (default) + * * * will_execute = TRUE [default condition] - * If (N == V) bit set - * will_execute = (N == V) - * else - * will_execute = (N != V) + * If (CHKNV) set + * // Only N/V, and Z flags are involved + * NEQV_Flag = (N == V) + * will_execute = (NEQV_Flag == NEQV_Mask) + * + * If (CHKC) set + * // Only C and Z flags are involved + * will_execute = (C_Flag == CSet_Mask) * - * If (ANDOR bit) set - * z_match = ~(Z XOR Z set) + * If (CHKZ) set + * z_match = (Z_Flag == ZSet_Mask) * If (AND bit set) * will_execute = will_execute && z_match * else * will_execute = will_execute || z_match + * */ -_dbg_cond_complex_check: +_dbg_cond_complex_checks: sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */ ldr r2, =debug_armComplexCCTable ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */ +_cond_check_nv: + tst r1, #COMPLEX_CONDCODE_CHKNV_MASK + beq _cond_check_c /* CHECKNV not set, so skip */ ands r2, r5, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Is (N == V == 0)? */ teqne r2, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* No, Is (N == V == 1)? */ + + moveq r2, #COMPLEX_CONDCODE_NEQV_MASK /* EQ: Either (N == V == 0) or (N == V == 1), set R2: COMPLEX_CONDCODE_NEQV_MASK */ + movne r2, #0 /* NE: N != V, clear R2 */ + and r3, r1, #COMPLEX_CONDCODE_NEQV_MASK /* R3: Extract NEQV Mask Value */ + teq r2, r3 /* Does N/V Condition match NEQV Mask value? */ + movne r0, #FALSE /* No, so will_execute = FALSE (for now) */ + b _cond_check_z + +#if 0 bne _cond_nnev /* No, so (N != V) */ /* EQ: Either (N == V == 0) or (N == V == 1) */ _cond_neqv: tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ moveq r0, #FALSE /* No, so will_execute = FALSE (for now) */ - b _cond_check_andor + b _cond_check_z /* Else, N != V */ _cond_nnev: tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */ movne r0, #FALSE /* Yes, so will_execute = FALSE (for now) */ + b _cond_check_z +#endif + +_cond_check_c: + tst r1, #COMPLEX_CONDCODE_CHKC_MASK + beq _cond_check_z /* CHECKC not set, so skip */ -_cond_check_andor: - tst r1, #COMPLEX_CONDCODE_ANDOR_MASK + /* Use R2 to store C Flag, R3 to store CSet Mask */ + and r2, r5, #COMPLEX_CONDCODE_CFLAG /* r2 = C flag */ + and r3, r1, #COMPLEX_CONDCODE_CSET_MASK /* r3 = CSet mask */ + teq r2, r3 /* Does C flag == CSet mask */ + movne r0, #FALSE /* No, so C flag failed match */ + +_cond_check_z: + tst r1, #COMPLEX_CONDCODE_CHKZ_MASK beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */ - /* Use R2 to store Z Flag, R3 to store Z set Mask */ + /* Use R2 to store Z Flag, R3 to store ZSet Mask */ and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */ - and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = Z set */ - eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if failed match */ + and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = ZSet mask */ + teq r2, r3 /* Does Z flag == ZSet mask */ moveq r3, #TRUE /* Zero, so z flag matched */ movne r3, #FALSE /* Non-zero, so z flag failed match */ - tst r1, #COMPLEX_CONDCODE_AND_MASK /* Is AND mask set? */ +_cond_andor: + tst r1, #COMPLEX_CONDCODE_ANDOR_MASK /* Is ANDOR mask set? */ andne r0, r0, r3 /* Yes, so AND with will_execute */ orreq r0, r0, r3 /* No, so OR with will_execute */ b _dbg_check_arm_condcode_exit /* Return will_execute (R0) */ /* * Simple Checks: + * We take advantage of the fact that only 1 bit would be set + * in the bitmask, by generating the corresponding actual + * CondSet[7:4], CondClr[3:0] value for comparison. * * will_execute = TRUE [default condition, equivalent to 0x00 (AL) ] - * If (SetBitMask is Non-Zero) - * will_execute = ((cond_code & SetBitMask) == SetBitMask) - * If will_execute && (ClearBitMask is Non-Zero) - * will_execute = will_execute && ((cond_code & ClearBitMask) == 0) + * Generate CondSetClr[7:0] from CPSR[3:0] + * will_execute = ((CondSetClr & BitMask) == BitMask) + * */ - -_dbg_check_bits_set: - movs r2, r1, lsr #4 /* R2: bits set */ - beq _dbg_check_bits_clear /* No bits set mask enabled, skip check */ - and r3, r5, r2 /* Check bits set IF bitmask non-zero */ - teq r2, r3 /* ((cond_code & SetBitMask) == SetBitMask)? */ - movne r0, #FALSE /* No, so will_execute = FALSE */ - bne _dbg_check_arm_condcode_exit /* Check failed (need to be TRUE to check bits clear), return */ - -_dbg_check_bits_clear: - ands r1, r1, #NIBBLE0 /* R1: bits clear */ - beq _dbg_check_arm_condcode_exit - ands r3, r5, r1 /* Check bits clear IF bitmask non-zero */ - movne r0, #FALSE /* (cond_code & ClearBitMask) != 0, so will_execute = FALSE */ +_dbg_cond_simple_checks: + xor r2, r5, #NIBBLE0 /* R2: CondClr[3:0] = Invert CPSR[3:0] */ + orr r2, r2, r5 lsl #4 /* R2: CondSet[7:4] | CondClr[3:0] */ + and r2, r2, r1 /* R2: CondSetClr[7:0] & Bitmask */ + teq r2, r1 /* ((cond_code & SetBitMask) == SetBitMask)? */ + movne r0, #FALSE /* Not equal, check failed */ _dbg_check_arm_condcode_exit: bx lr /* Return to caller */ -- cgit v1.2.3 From b544c4b06db299df82275e20bed9b313cbd61e01 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 6 Jul 2011 15:32:01 +0800 Subject: fix syntax errors --- Debugger/debug_opcodes.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index d43991d..fbdd7db 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -917,8 +917,8 @@ _cond_andor: * */ _dbg_cond_simple_checks: - xor r2, r5, #NIBBLE0 /* R2: CondClr[3:0] = Invert CPSR[3:0] */ - orr r2, r2, r5 lsl #4 /* R2: CondSet[7:4] | CondClr[3:0] */ + eor r2, r5, #NIBBLE0 /* R2: CondClr[3:0] = Invert CPSR[3:0] */ + orr r2, r2, r5, lsl #4 /* R2: CondSet[7:4] | CondClr[3:0] */ and r2, r2, r1 /* R2: CondSetClr[7:0] & Bitmask */ teq r2, r1 /* ((cond_code & SetBitMask) == SetBitMask)? */ movne r0, #FALSE /* Not equal, check failed */ -- cgit v1.2.3 From 37faf49dcde68185b86c9d2ab3239428b461c5b7 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 8 Jul 2011 10:43:36 +0800 Subject: display ctrl-c explicitly in debug information --- Host/nxt-gdb-server.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index d66b12e..9ef8ff1 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -180,7 +180,10 @@ class NXTGDBServer: # print "CTRL-C Received!" # data = STATUS_QUERY if DEBUG: - print "[GDB->NXT] %s" % data + if data[0] == CTRLC: + print "[GDB->NXT] " + else: + print "[GDB->NXT] %s" % data segments = self.segment (data) data = '' for seg in segments: -- cgit v1.2.3 From 08c4d9c38bebc5689d0677431ef59cf45c4b5714 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 8 Jul 2011 16:08:47 +0800 Subject: code cleanup, fix breakpoint handling logic on entry to debugger When any Breakpoint is triggered, we must restore all active breakpoints. Otherwise, in the case where Normal Breakpoints are active and we encounter a Manual Breakpoint, the Normal Breakpoint will be left dangling (and eventually the breakpoint will be cleared by GDB, destroying the original instruction opcode). --- Debugger/debug_macros.h | 15 ++++-- Debugger/debug_stub.S | 141 ++++++++++++++++++++++++++---------------------- 2 files changed, 90 insertions(+), 66 deletions(-) diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index e3208b4..3a60677 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -377,18 +377,27 @@ .endm /* _dbg_set_bkpt_type + * Set Breakpoint Type using value in reg + * On exit: + * reg: destroyed + * r1: destroyed + */ + .macro _dbg_set_bkpt_type reg + ldr r1, =debug_bkpt_type + strb \reg, [r1] + .endm + +/* _dbg_set_bkpt_type_val * Set Breakpoint Type to given value * On exit: * r0, r1: destroyed */ - .macro _dbg_set_bkpt_type bkpt_type + .macro _dbg_set_bkpt_type_val bkpt_type mov r0, #\bkpt_type ldr r1, =debug_bkpt_type strb r0, [r1] .endm - - /* _dbg_getcurrbkpt_index * Get current breakpoint index * On exit: diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 2152f7f..ccd411d 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -355,10 +355,14 @@ debug_cmdJumpTable: ****************************************************************************/ .code 32 .align 4 - .global dbg__bkpt_init /* dbg__bkpt_init - * GDB set_debug_traps() routine + * GDB set_debug_traps() routine + * On entry: + * None + * On exit: + * r0-r3: destroyed */ + .global dbg__bkpt_init dbg__bkpt_init: push {lr} bl _dbg__clear_breakpoints @@ -383,74 +387,78 @@ dbg__bkpt_init: * Defined by GDB Stub, but not needed for ARMv4T architecture */ _dbg__flush_icache: - /* nop */ - bx lr + /* nop */ + bx lr - .global dbg__thumb_bkpt_handler /* dbg__thumb_bkpt_handler - * GDB handle_exception() routine (Thumb Mode) + * GDB handle_exception() routine (Thumb Mode) + * On entry: + * r0: Breakpoint index value + * On exit: + * routine does not 'exit' in the normal sense */ + .global dbg__thumb_bkpt_handler dbg__thumb_bkpt_handler: -/* On entry, r0 contains breakpoint index value */ - /* mov r4, #BKPT16_AUTO_BKPT Redundant?! */ - and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ - _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ - ldr r1, =BKPT16_MANUAL_BKPT - teq r0, r1 - beq _process_manual_breakpoint_thumb - ldr r1, =__breakpoints_num__ - cmp r0, r1 /* Sanity check that index is in range */ - bhs dbg__bkpt_offset_outofrange -/* Valid index value found */ - teq r4, #0 /* Check if AUTO flag set */ - bne _process_auto_breakpoint -/* else */ - _dbg_set_bkpt_type DBG_NORMAL_BKPT_THUMB - b _process_normal_breakpoint + and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT16_MANUAL_BKPT + teq r0, r1 + moveq r0, #DBG_MANUAL_BKPT_THUMB /* Manual Thumb Breakpoint, process it */ + beq _restore_normal_breakpoints + +_process_normal_or_auto_breakpoint_thumb: + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */ + +_check_auto_breakpoint_thumb: + teq r4, #0 /* Check if AUTO flag set */ + moveq r0, #DBG_NORMAL_BKPT_THUMB /* No, it is a normal breakpoint */ + beq _restore_normal_breakpoints + b _process_auto_breakpoint - .global dbg__arm_bkpt_handler /* dbg__arm_bkpt_handler - * GDB handle_exception() routine (ARM Mode) + * GDB handle_exception() routine (ARM Mode) + * On entry: + * r0: breakpoint index value + * On exit: + * routine does not 'exit' in the normal sense */ + .global dbg__arm_bkpt_handler dbg__arm_bkpt_handler: -/* On entry, r0 contains breakpoint index value */ - /* mov r4, #BKPT32_AUTO_BKPT Redundant?! */ - and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ - _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ - ldr r1, =BKPT32_MANUAL_BKPT - teq r0, r1 - beq _process_manual_breakpoint_arm - ldr r1, =__breakpoints_num__ - cmp r0, r1 /* Sanity check that index is in range */ - bhs dbg__bkpt_offset_outofrange -/* Valid index value found */ - teq r4, #0 /* Check if AUTO flag set */ - bne _process_auto_breakpoint -/* else */ - _dbg_set_bkpt_type DBG_NORMAL_BKPT_ARM -/* b _process_normal_breakpoint */ - -_process_normal_breakpoint: - bl _dbg__restore_breakpoints /* includes restoring single step */ -/* bl _dbg__restore_singlestep */ - bl _dbg__clear_singlestep - bl _dbg__flush_icache - b dbg__bkpt_waitCMD + /* On entry, r0 contains breakpoint index value */ + and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT32_MANUAL_BKPT + teq r0, r1 + moveq r0, #DBG_MANUAL_BKPT_ARM /* Manual ARM Breakpoint, process it */ + beq _restore_normal_breakpoints + +_process_normal_or_auto_breakpoint_arm: + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */ + +_check_auto_breakpoint_arm: + teq r4, #0 /* Check if AUTO flag set */ + moveq r0, #DBG_NORMAL_BKPT_ARM /* No, it is a normal breakpoint */ + beq _restore_normal_breakpoints +/* b _process_auto_breakpoint */ _process_auto_breakpoint: -/* Load Auto BKPT for Breakpoint index given in r0 */ - _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ - ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 /* Check that Breakpoint is active */ - beq dbg__bkpt_inactive - bl _dbg__activate_one_breakpoint - bl _dbg__restore_singlestep - bl _dbg__clear_singlestep - _dbg_set_bkpt_type DBG_AUTO_BKPT - b _dbg__switch2undefmode + /* Load Auto BKPT for Breakpoint index given in r0 */ + _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Check that Breakpoint is active */ + beq dbg__bkpt_inactive + bl _dbg__activate_one_breakpoint + bl _dbg__restore_singlestep + bl _dbg__clear_singlestep + _dbg_set_bkpt_type_val DBG_AUTO_BKPT +/* b _dbg__switch2undefmode */ /* _dbg__switch2undefmode * Common internal routine to return execution to user program @@ -463,11 +471,18 @@ _dbg__switch2undefmode: mov pc, lr /* Exit via UNDEF mode */ _process_manual_breakpoint_thumb: - _dbg_set_bkpt_type DBG_MANUAL_BKPT_THUMB - b dbg__bkpt_waitCMD + mov r0, #DBG_MANUAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ + b _restore_normal_breakpoints + +_process_normal_breakpoint_thumb: + mov r0, #DBG_NORMAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ + b _restore_normal_breakpoints -_process_manual_breakpoint_arm: - _dbg_set_bkpt_type DBG_MANUAL_BKPT_ARM +_restore_normal_breakpoints: + _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */ + bl _dbg__restore_breakpoints /* includes restoring single step */ + bl _dbg__clear_singlestep + bl _dbg__flush_icache /* b dbg__bkpt_waitCMD */ dbg__bkpt_inactive: -- cgit v1.2.3 From a20e9463fba4b7fb3ae93d100a505a0818a4b4d6 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:40:26 +0800 Subject: thumb mode tests, modified arm mode test for signed compares Thumb mode test routine using Unsigned compares Implement Signed Compares for ARM Mode --- Debugger/debug_test.S | 53 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index ed4ae14..db260ff 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -55,8 +55,8 @@ test_arm_1: test_arm_2: sub r0, r0, #1 cmp r0, #8 - bls test_arm_1 - bhi test_arm_3 + ble test_arm_1 + bgt test_arm_3 beq test_arm_2 ldr pc, =test_arm_1 @@ -69,7 +69,7 @@ test_arm_3: bx r2 exit_dbg__test_arm_instrstep: - bl dbg__test_arm_instr_sub2 + bl dbg__test_thumb_instr_sub1 ldmfd sp!, {pc} dbg__test_arm_instr_sub1: @@ -109,8 +109,53 @@ _thumb_entry: * */ .global dbg__test_thumb_instrstep +.thumb_func dbg__test_thumb_instrstep: - bx lr + push {lr} + bl dbg__test_thumb_instr_sub1 + bl dbg__test_thumb_instr_sub2 + +test_thumb_1: + sub r0, #1 + bne test_thumb_2 + /* else R0 == 0 */ + b exit_dbg__test_thumb_instrstep + +test_thumb_2: + sub r0, #1 + cmp r0, #8 + bls test_thumb_1 + bhi test_thumb_3 + beq test_thumb_2 + b test_thumb_1 + +test_thumb_3: + /* case for r0 == 9 */ + sub r0, #1 + cmp r0, #5 + beq load_test_thumb_1 + ldr r2, =test_thumb_3 + b exit_test_thumb_3 +load_test_thumb_1: + ldr r2, =test_thumb_1 +exit_test_thumb_3: + bx r2 + +exit_dbg__test_thumb_instrstep: + bl dbg__test_arm_instr_sub1 + pop {r1} + bx r1 + +.thumb_func +dbg__test_thumb_instr_sub1: + mov r0, #0x0F + bx lr + +.thumb_func +dbg__test_thumb_instr_sub2: + push {lr} + mov r0, #FALSE + pop {pc} .end -- cgit v1.2.3 From 1485242af0a92d0c17e99973ee28364b7adedce6 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:41:41 +0800 Subject: comments and code alignment cleanups --- Debugger/undef_handler.S | 62 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Debugger/undef_handler.S b/Debugger/undef_handler.S index 11d3cbc..412fd18 100644 --- a/Debugger/undef_handler.S +++ b/Debugger/undef_handler.S @@ -29,20 +29,18 @@ undef_handler: * On triggering, lr (R14) contains the previous mode's pc (R15). * Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" * Chapter 11, Example 11.1. - * Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.) */ - /* We assume that the UNDEF stack holds only one stack frame and we will overwrite it. + /* We assume that the DEBUG stack holds only one stack frame and we will overwrite it. * On entry, LR_undef points to one instruction past the UNDEF instruction. * * For the purpose of Debugging, the stack frame should present the PC (R15) as the address * of the instruction that triggered the Breakpoint. Hence we need to adjust R15 * to point to the address of the UNDEF instruction. This is what the JTAG debugger - * does. (In the ARM hardware, the PC would point to UNDEF+2 instruction address - * since it has a three stage pipeline). + * does. * * We will also store UNDEF LR (next instruction pointer) and UNDEF SPSR to the stack. * - * For the handler, once the user registers have been stored in the debug stack, the + * For the handler, once the user registers have been stored in the DEBUG stack, the * registers will be used as follows: * * R0: UNDEF LR, then UNDEF instruction address, finally UNDEF instruction word / BKPT index @@ -71,37 +69,39 @@ undef_handler: _store_prev_mode_banked_regs: /* FIXME: We don't handle FIQ properly! */ - orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ - msr cpsr_c, r2 /* Switch to previous mode */ - stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */ - msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */ + orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ + msr cpsr_c, r2 /* Switch to previous mode */ + stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */ + msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */ _skip_banked_registers: - tst r1, #CPSR_THUMB /* Check for Thumb Mode */ - beq _is_arm /* Clear, so it's ARM mode */ + tst r1, #CPSR_THUMB /* Check for Thumb Mode */ + beq _is_arm /* Clear, so it's ARM mode */ _is_thumb: - ldrh r0, [r0] /* load UNDEF instruction into r0 */ - ldr r1, =BKPT16_ENUM_MASK /* Thumb BKPT enum mask */ - bic r2, r0, r1 /* leave only opcode */ - ldr r1, =BKPT16_INSTR /* check for Thumb Breakpoint Instruction */ - teq r2, r1 - bne default_undef_handler - ldr r1, =BKPT16_ENUM_MASK /* get Thumb BKPT Enum Mask */ - ldr r2, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ - b _exit_undef_handler + ldrh r0, [r0] /* load UNDEF instruction into r0 */ + ldr r1, =BKPT16_ENUM_MASK /* Thumb BKPT enum mask */ + bic r2, r0, r1 /* leave only opcode */ + ldr r1, =BKPT16_INSTR /* check for Thumb Breakpoint Instruction */ + teq r2, r1 + bne default_undef_handler + ldr r1, =BKPT16_ENUM_MASK /* get Thumb BKPT Enum Mask */ + ldr r2, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ + b _exit_undef_handler _is_arm: - ldr r0, [r0] /* load UNDEF instruction into r0 */ - ldr r1, =BKPT32_ENUM_MASK /* ARM BKPT enum mask */ - bic r2, r0, r1 /* leave only opcode */ - ldr r1, =BKPT32_INSTR /* check for ARM Breakpoint Instruction */ - teq r2, r1 - bne default_undef_handler - ldr r1, =BKPT32_ENUM_MASK /* get ARM BKPT Enum Mask */ - ldr r2, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ + ldr r0, [r0] /* load UNDEF instruction into r0 */ + ldr r1, =BKPT32_ENUM_MASK /* ARM BKPT enum mask */ + bic r2, r0, r1 /* leave only opcode */ + ldr r1, =BKPT32_INSTR /* check for ARM Breakpoint Instruction */ + teq r2, r1 + bne default_undef_handler + ldr r1, =BKPT32_ENUM_MASK /* get ARM BKPT Enum Mask */ + ldr r2, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ _exit_undef_handler: - and r0, r1, r0 /* Keep index value */ - msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Switch to Abort Mode, Disable Interrupts */ - mov pc, r2 /* Invoke Debugger */ + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Switch to Abort Mode, Disable Interrupts */ + ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time a Breakpoint happens */ + bic sp, sp, #7 + mov pc, r2 /* Invoke Debugger */ .global resume_execution -- cgit v1.2.3 From d59b9a5172b31b3ab3fb60e7f6bf7af6cf7caf91 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:42:28 +0800 Subject: added preliminary abort exception support --- Debugger/debug_internals.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index adb5497..91a55cb 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -292,6 +292,8 @@ ENUM_VAL(DBG_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */ ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */ ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */ +ENUM_VAL(DBG_ABORT_PREFETCH) /**< Prefetch Abort. */ +ENUM_VAL(DBG_ABORT_DATA) /**< Data Abort. */ ENUM_END(bkpt_type_t) /** Debugger Message Error Enums @@ -337,5 +339,17 @@ ENUM_VAL(REG_CPSR) /**< Previous Mode CPSR */ ENUM_END(register_enum_t) +/** Abort Type Enums + * + * Abort Type used for interfacing with LCD Display routine. + * The enums must be consecutive, starting from 0 + * Note: The values must align with those defined in NxOS's _abort.h + */ +ENUM_BEGIN +ENUM_VALASSIGN(ABORT_PREFETCH,0) /**< Prefetch Abort. */ +ENUM_VAL(ABORT_DATA) /**< Data Abort. */ +ENUM_VAL(ABORT_SPURIOUS) /**< Spurious IRQ. */ +ENUM_VAL(ABORT_ILLEGAL) /**< Illegal Instruction. */ +ENUM_END(abort_type_t) #endif /* __DEBUG_INTERNALS_H__ */ -- cgit v1.2.3 From e3521e37c5ac486c10c67e738eca50abebc0ed62 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:42:56 +0800 Subject: added preliminary abort mode support Interface to platform specific LCD Display routines --- Debugger/debug_runlooptasks.S | 30 +++++++++++++++++++++++++++++- Debugger/debug_runlooptasks.h | 12 +++++++----- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index 8eed3ad..dcca3b1 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -88,7 +88,6 @@ * NxOS Run Loop * ****************************************************************************/ - .extern nx_systick_wait_ms dbg__runloopTasks: /* Currently, there's nothing that needs to be done in the NxOS Run Loop */ push {lr} @@ -169,6 +168,35 @@ _dbg__reboot_wait: b _dbg__reboot_wait /* Wait for AVR... */ #endif +#ifdef __NXOS__ +/**************************************************************************** + * + * NxOS Abort Info LCD Display Routine + * + ****************************************************************************/ +/* On entry: + * r0: abort type + * On exit: + * r0-r3: destroyed + */ +dbg__display_abort_info: + push {lr} + _getdbgregister DBGSTACK_USERPC_INDEX, r1 /* Retrieve User PC into R2 */ + _getdbgregister DBGSTACK_USERCPSR_INDEX, r2 /* Retrieve User CPSR into R2 */ + bl nx__abort_info /* void nx__abort_info(U32 data, U32 pc, U32 cpsr); */ + pop {pc} + +#else +/**************************************************************************** + * + * NXT Firmware Abort Info LCD Display Routine + * + ****************************************************************************/ +dbg__display_abort_info: +/* FIXME: Inteface with NXT Firmware LCD Display routines */ + push {lr} + pop {pc} +#endif #ifdef __NXOS__ .extern debug_OutCommBuf diff --git a/Debugger/debug_runlooptasks.h b/Debugger/debug_runlooptasks.h index 6eb0461..f55311e 100644 --- a/Debugger/debug_runlooptasks.h +++ b/Debugger/debug_runlooptasks.h @@ -26,8 +26,10 @@ */ #ifdef __NXOS__ + .extern nx__abort_info + .extern nx_systick_wait_ms - .extern nx_usb_is_connected + .extern nx_usb_is_connected .extern nx_usb_can_write .extern nx_usb_write .extern nx_usb_data_written @@ -45,10 +47,10 @@ .extern dUsbRead .extern dUsbIsConfigured .extern dBtSendMsg - .equ nxt_UBYTE_TRUE, 1 - .equ nxt_UBYTE_FALSE, 0 - .equ USB_CMD_READY, 0x01 /* From c_comm.iom */ - .equ BT_CMD_READY, 0x02 /* From c_comm.iom */ + .equ nxt_UBYTE_TRUE, 1 + .equ nxt_UBYTE_FALSE, 0 + .equ USB_CMD_READY, 0x01 /* From c_comm.iom */ + .equ BT_CMD_READY, 0x02 /* From c_comm.iom */ .extern dIOCtrlSetPower .extern dIOCtrlSetPwm -- cgit v1.2.3 From 7d70ae2da93e8fe92e0eb471ed4278a59cab0cf8 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 07:43:30 +0800 Subject: preliminary abort exception handler --- Debugger/abort_handler.S | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Debugger/abort_handler.S diff --git a/Debugger/abort_handler.S b/Debugger/abort_handler.S new file mode 100644 index 0000000..a968374 --- /dev/null +++ b/Debugger/abort_handler.S @@ -0,0 +1,106 @@ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * Redistribution of this file is permitted under + * the terms of the GNU Public License (GPL) version 2. + */ +#define __ASSEMBLY__ +#include "debug_stub.h" +#include "debug_internals.h" + +#define PREFETCH_OFFSET 4 +#define DATA_OFFSET 8 + +/* Trap Abort Exceptions. + * On triggering, lr (R14) contains the previous mode's pc (R15). + * Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" + * Chapter 11, Example 11.1. + */ +/* + * NOTE: This routine closely mirrors the undef_handler routine, since we will store + * the ABORT stack frame in the UNDEF stack. + * In addition, since ARMDEBUG uses Abort mode, if the ABORT occurs while the + * debugger is running, the value of SP_abort is not valid. This should not happen + * in any case (it is a BUG if ARMDEBUG triggers an ABORT). + * + * We assume that the DEBUG stack holds only one stack frame and we will overwrite it. + * On entry, LR_undef contains the PC+4 for Prefetch Abort, and PC+8 for Data Abort. + * + * For the purpose of Debugging, the stack frame should present the PC (R15) as the address + * of the instruction that triggered the Abort. Hence we need to adjust R15 + * to point to the address of the ABORTed instruction. + * + * We will also store ABORT LR (next instruction pointer) and ABORT SPSR to the stack. + * + * For the handler, once the user registers have been stored in the DEBUG stack, the + * registers will be used as follows: + * + * R0: ABORT LR, then ABORT instruction address + * R1: SPSR + * R2: PC Offset, then Mode + * R3: DEBUG Stack Pointer (for Banked R13-R14 update) + * R4: Abort Type Enum + */ + +.text +.code 32 +.align 0 + + .extern dbg__display_abort_info + .extern dbg__bkpt_waitCMD + .extern default_prefetch_abort_handler + .extern default_data_abort_handler + + .global prefetch_abort_handler + .global data_abort_handler + +prefetch_abort_handler: + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ + mov r2, #PREFETCH_OFFSET + mov r4, #ABORT_PREFETCH + b _common_abort_handler + +data_abort_handler: + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ + mov r2, #DATA_OFFSET + mov r4, #ABORT_DATA + +_common_abort_handler: + sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */ + str r0, [sp, #-4] /* Save PC to stack (R15 slot) */ + + mov r3, sp /* Use R3 to write Banked R13-R14 of ABORT instruction */ + + mrs r1, spsr /* Copy SPSR to r1 */ + tst r1, #CPSR_THUMB /* Check for Thumb Mode */ + addne r0, r0, #2 /* Is Thumb instruction, adjust PC for ABORT next instruction address */ + addeq r0, r0, #4 /* Is ARM instruction, adjust PC for ABORT next instruction address */ + sub sp, sp, #(4*16) /* Need to manually update SP(abort) */ + stmfd sp!, {r0,r1} /* Save ABORTed Next Instr Pointer (in R0) and previous mode's CPSR to stack */ + + and r2, r1, #CPSR_MODE /* Get previous mode */ + teq r2, #MODE_USR + beq _exit_abort_handler /* Can't switch back if we're in User mode! */ + +_store_prev_mode_banked_regs: + /* FIXME: We don't handle FIQ properly! */ + + orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ + msr cpsr_c, r2 /* Switch to previous mode */ + stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */ + msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Revert to ABORT Mode */ + +_exit_abort_handler: + ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time an Abort happens */ + bic sp, sp, #7 + mov r0, r4 /* Copy Abort Type Enum to R0 */ + bl dbg__display_abort_info /* Display Abort Type to LCD */ + b dbg__bkpt_waitCMD /* Invoke Debugger */ + + -- cgit v1.2.3 From a250b0f75e58053ee3e7428b8499baa9ddec3e88 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Sat, 9 Jul 2011 08:04:31 +0800 Subject: cleanup abort handler to armdebug interface --- Debugger/abort_handler.S | 13 ++++++++----- Debugger/debug_internals.h | 8 ++++---- Debugger/debug_stub.S | 11 +++++++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Debugger/abort_handler.S b/Debugger/abort_handler.S index a968374..7d2e158 100644 --- a/Debugger/abort_handler.S +++ b/Debugger/abort_handler.S @@ -51,7 +51,7 @@ .align 0 .extern dbg__display_abort_info - .extern dbg__bkpt_waitCMD + .extern dbg__abort_exception_handler .extern default_prefetch_abort_handler .extern default_data_abort_handler @@ -62,14 +62,16 @@ prefetch_abort_handler: ldr sp, =__debugger_stack__ stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ mov r2, #PREFETCH_OFFSET - mov r4, #ABORT_PREFETCH + mov r4, #DISP_ABORT_PREFETCH /* Display Abort Info Type */ + mov r5, #DBG_ABORT_PREFETCH /* Debugger Abort Type */ b _common_abort_handler data_abort_handler: ldr sp, =__debugger_stack__ stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ mov r2, #DATA_OFFSET - mov r4, #ABORT_DATA + mov r4, #DISP_ABORT_DATA /* Display Abort Info Type */ + mov r5, #DBG_ABORT_DATA /* Debugger Abort Type */ _common_abort_handler: sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */ @@ -99,8 +101,9 @@ _store_prev_mode_banked_regs: _exit_abort_handler: ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time an Abort happens */ bic sp, sp, #7 - mov r0, r4 /* Copy Abort Type Enum to R0 */ + mov r0, r4 /* Copy Display Abort Type Enum to R0 */ bl dbg__display_abort_info /* Display Abort Type to LCD */ - b dbg__bkpt_waitCMD /* Invoke Debugger */ + mov r0, r5 /* Copy Debugger Abort Type Enum to R0 */ + b dbg__abort_exception_handler /* Invoke Debugger */ diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index 91a55cb..56cf26a 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -346,10 +346,10 @@ ENUM_END(register_enum_t) * Note: The values must align with those defined in NxOS's _abort.h */ ENUM_BEGIN -ENUM_VALASSIGN(ABORT_PREFETCH,0) /**< Prefetch Abort. */ -ENUM_VAL(ABORT_DATA) /**< Data Abort. */ -ENUM_VAL(ABORT_SPURIOUS) /**< Spurious IRQ. */ -ENUM_VAL(ABORT_ILLEGAL) /**< Illegal Instruction. */ +ENUM_VALASSIGN(DISP_ABORT_PREFETCH,0) /**< Prefetch Abort. */ +ENUM_VAL(DISP_ABORT_DATA) /**< Data Abort. */ +ENUM_VAL(DISP_ABORT_SPURIOUS) /**< Spurious IRQ. */ +ENUM_VAL(DISP_ABORT_ILLEGAL) /**< Illegal Instruction. */ ENUM_END(abort_type_t) #endif /* __DEBUG_INTERNALS_H__ */ diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index ccd411d..193705e 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -390,6 +390,17 @@ _dbg__flush_icache: /* nop */ bx lr +/* dbg__abort_exception_handler + * Handle Abort Exceptions + * On entry: + * r0: Abort Type Enum + * On exit: + * routine does not 'exit' in the normal sense + */ + .global dbg__abort_exception_handler +dbg__abort_exception_handler: + _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */ + b dbg__bkpt_waitCMD /* dbg__thumb_bkpt_handler * GDB handle_exception() routine (Thumb Mode) -- cgit v1.2.3 From 1cb68509578f3a7e1112b1daed83714e6430f8f0 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 07:19:54 +0800 Subject: export dbg__display_abort_info symbol --- Debugger/debug_runlooptasks.S | 1 + 1 file changed, 1 insertion(+) diff --git a/Debugger/debug_runlooptasks.S b/Debugger/debug_runlooptasks.S index dcca3b1..3bcf35a 100644 --- a/Debugger/debug_runlooptasks.S +++ b/Debugger/debug_runlooptasks.S @@ -80,6 +80,7 @@ .align 4 .global dbg__runloopTasks .global dbg__reboot + .global dbg__display_abort_info .global dbg__sendCommMsg #ifdef __NXOS__ -- cgit v1.2.3 From 4bb47785205304ad894021864d6bb8ea5afe34bb Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 07:42:07 +0800 Subject: test pc relative loads to pc --- Debugger/debug_test.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index db260ff..e0f3cf0 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -55,7 +55,7 @@ test_arm_1: test_arm_2: sub r0, r0, #1 cmp r0, #8 - ble test_arm_1 + ldrle pc, =test_arm_1 bgt test_arm_3 beq test_arm_2 ldr pc, =test_arm_1 -- cgit v1.2.3 From 7d8f3895e29f9659d2974dfa285bb594aeef1fa0 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 07:58:58 +0800 Subject: handle proper brick socket open and close sequence Allow for multiple GDB sessions from gdb client by opening the brick socket after client connection, and closing the brick socket after client disconnection. --- Host/nxt-gdb-server.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index 9ef8ff1..c1cf083 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -156,14 +156,17 @@ class NXTGDBServer: s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind (('', self.port)) s.listen (1) - # Open connection to the NXT brick. - brick = nxt.locator.find_one_brick (method=nxt.Method(usb=False, bluetooth=False, fantomusb=True, fantombt=False)) - brick.sock.debug = DEBUG + ## Open connection to the NXT brick. + #brick = nxt.locator.find_one_brick () + #brick.sock.debug = DEBUG print "Waiting for GDB connection on port %s..." % self.port while True: # Wait for a connection. client, addr = s.accept () print "Client from", addr + # Open connection to the NXT brick. + brick = nxt.locator.find_one_brick () + brick.sock.debug = DEBUG # Work loop, wait for a message from client socket or NXT brick. while client is not None: data = '' @@ -212,6 +215,7 @@ class NXTGDBServer: if client: client.send (data) data = '' + brick.sock.close() print "Connection closed, waiting for GDB connection on port %s..." % self.port if __name__ == '__main__': -- cgit v1.2.3 From 811650695764fd5da07fc950f6071be84f27c32f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 08:00:59 +0800 Subject: remove commented out code --- Host/nxt-gdb-server.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index c1cf083..fea3d9e 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -156,9 +156,6 @@ class NXTGDBServer: s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind (('', self.port)) s.listen (1) - ## Open connection to the NXT brick. - #brick = nxt.locator.find_one_brick () - #brick.sock.debug = DEBUG print "Waiting for GDB connection on port %s..." % self.port while True: # Wait for a connection. -- cgit v1.2.3 From b9bb70c16dba4c945b75f1a4b929e2ec304d2874 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 08:25:40 +0800 Subject: fix incorrect stack pointer offset for debug stack save of abort state SP was not updated after storing Aborted instruction PC to debug stack --- Debugger/abort_handler.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Debugger/abort_handler.S b/Debugger/abort_handler.S index 7d2e158..882156a 100644 --- a/Debugger/abort_handler.S +++ b/Debugger/abort_handler.S @@ -75,7 +75,7 @@ data_abort_handler: _common_abort_handler: sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */ - str r0, [sp, #-4] /* Save PC to stack (R15 slot) */ + stmfd sp!, {r0} /* Save ABORTed Instruction PC to stack (R15 slot) */ mov r3, sp /* Use R3 to write Banked R13-R14 of ABORT instruction */ -- cgit v1.2.3 From 1da4bbcbb476f5133e9d2c7f8ede8382d9e2bfe2 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 08:57:08 +0800 Subject: revert b9bb70c16dba4c945b75f1a4b929e2ec304d2874, revise fix We need to adjust SP to store SPSR and Aborted Next Instruction Address Revised fix to not update SP for storing Aborted PC to R15 slot, but to copy the adjusted SP value for the R14 slot to R3 instead. --- Debugger/abort_handler.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Debugger/abort_handler.S b/Debugger/abort_handler.S index 882156a..f4d1bd0 100644 --- a/Debugger/abort_handler.S +++ b/Debugger/abort_handler.S @@ -75,9 +75,8 @@ data_abort_handler: _common_abort_handler: sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */ - stmfd sp!, {r0} /* Save ABORTed Instruction PC to stack (R15 slot) */ - - mov r3, sp /* Use R3 to write Banked R13-R14 of ABORT instruction */ + str r0, [sp, #-4] /* Save ABORTed Instruction PC to stack (R15 slot) */ + sub r3, sp, #4 /* Use R3 to write Banked R13-R14 of ABORT instruction, update R3 to point to R14 slot */ mrs r1, spsr /* Copy SPSR to r1 */ tst r1, #CPSR_THUMB /* Check for Thumb Mode */ -- cgit v1.2.3 From e1309e3eb381cc375f661c21ec9d668f4b746d59 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 09:38:34 +0800 Subject: update signal output to handle prefetch and data aborts Implement Prefetch and Data Abort Signal enum output --- Debugger/debug_internals.h | 12 ++++++++++++ Debugger/debug_macros.h | 41 ++++++++++++++++++++++++++++++++++------- Debugger/debug_stub.S | 20 +++++++++++++++++--- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index 56cf26a..8292854 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -296,6 +296,18 @@ ENUM_VAL(DBG_ABORT_PREFETCH) /**< Prefetch Abort. */ ENUM_VAL(DBG_ABORT_DATA) /**< Data Abort. */ ENUM_END(bkpt_type_t) +/** Debugger Message Signal Enums + * + * Debugger Signal Message Enums. + * The enums must be consecutive, starting from 0 + */ +/* FIXME: Need to validate against the ecos-generic-stub.c Error enums */ +ENUM_BEGIN +ENUM_VALASSIGN(MSG_SIG_DEFAULT, 0) /**< Normal Signal Response. */ +ENUM_VALASSIGN(MSG_SIG_PREFETCH, 0) /**< Prefetch Abort Signal Response. */ +ENUM_VALASSIGN(MSG_SIG_DATA, 0) /**< Data Abort Signal Response. */ +ENUM_END(dbg_msg_signo) + /** Debugger Message Error Enums * * Debugger Error Message Enums. diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index 3a60677..fcf6ca6 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -198,7 +198,7 @@ /* _dbg_outputMsgStatusErr * Return Message with Error ('+$ENN') status * On entry: - * R0: error code + * R1: error code * On exit: * R0: Pointer to Output Buffer ASCIIZ location * R1: destroyed @@ -206,7 +206,6 @@ * R3: destroyed */ .macro _dbg_outputMsgStatusErr - mov r1, r0 __dbg_outputErrMsg .endm @@ -222,22 +221,50 @@ __dbg_outputErrMsg .endm -/* _dbg_outputMsgStatusSig +/* __dbg_outputSigMsg + * Internal Routine called to generate Signal messages * Return Message with Signal ('+$SNN') status + * On entry: + * R1: signal code * On exit: * R0: Pointer to Output Buffer ASCIIZ location * R1: destroyed * R2: destroyed + * R3: destroyed */ - .macro _dbg_outputMsgStatusSig statuscode + .macro __dbg_outputSigMsg ldr r0, =debug_OutMsgBuf - ldr r1, =debug_SignalResponsePrefix - _dbg_stpcpy r0, r1, r2 - mov r1, #\statuscode + ldr r2, =debug_SignalResponsePrefix + _dbg_stpcpy r0, r2, r3 bl byte2ascii /* R0 points to buffer position after byte value */ _asciiz r0, r1 .endm +/* _dbg_outputMsgStatusSig + * Return Message with Signal ('+$SNN') status + * On entry: + * R1: signal code + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R1: destroyed + * R2: destroyed + */ + .macro _dbg_outputMsgStatusSig + __dbg_outputSigMsg + .endm + +/* _dbg_outputMsgStatusSigCode + * Return Message with Signal ('+$SNN') status + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R1: destroyed + * R2: destroyed + */ + .macro _dbg_outputMsgStatusSigCode statuscode + mov r1, #\statuscode + __dbg_outputSigMsg + .endm + /* _regenum2index * Convert register enum to debugger stack index * diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 193705e..e462c6b 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -546,7 +546,7 @@ _proc_command: _dbg_check_gdb_command: teq r0, #MSGBUF_STARTCHAR - movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */ + movne r1, #MSG_ERRFORMAT /* Message Format invalid (not '$') */ bne _dbg__cmdError /* Shouldn't happen */ ldrb r0, [r4], #1 /* Look for command char */ bl _dbg__cmdChar2Index /* Index in R0 */ @@ -558,7 +558,7 @@ _dbg_unknown_command: b dbg__bkpt_waitCMD_cont #if 0 - moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ + moveq r1, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ beq _dbg__cmdError /* Send response to GDB server */ #endif @@ -740,8 +740,22 @@ __dbg__sendDebugMsgExit: * r0, r1, r2, r3: destroyed */ _dbg__cmd_Status: + /* FIXME: The Signal numbers do not correspond to any GDB defined signals */ stmfd sp!, {lr} - _dbg_outputMsgStatusSig 0x0 /* FIXME: Dummy Signal number */ + _dbg_get_bkpt_type r0 +_check_data_abort_exception: + teq r0, #DBG_ABORT_DATA + moveq r1, #MSG_SIG_DATA + beq _exit_dmg__cmd_Status +_check_prefetch_abort_exception: + teq r0, #DBG_ABORT_PREFETCH + moveq r1, #MSG_SIG_PREFETCH + beq _exit_dmg__cmd_Status +_default_breakpoint_exception: + mov r1, #MSG_SIG_DEFAULT /* FIXME: Dummy Signal number */ + +_exit_dmg__cmd_Status: + _dbg_outputMsgStatusSig b __dbg__sendDebugMsgExit /* _dbg__cmd_Query -- cgit v1.2.3 From 9719b8e5bdb202dc07320141cb1b642e563b8b97 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 10:05:53 +0800 Subject: fix invalid values for abort signals Use correct enum defintion macros to define abort signal values --- Debugger/debug_internals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index 8292854..f7ab7d5 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -304,8 +304,8 @@ ENUM_END(bkpt_type_t) /* FIXME: Need to validate against the ecos-generic-stub.c Error enums */ ENUM_BEGIN ENUM_VALASSIGN(MSG_SIG_DEFAULT, 0) /**< Normal Signal Response. */ -ENUM_VALASSIGN(MSG_SIG_PREFETCH, 0) /**< Prefetch Abort Signal Response. */ -ENUM_VALASSIGN(MSG_SIG_DATA, 0) /**< Data Abort Signal Response. */ +ENUM_VAL(MSG_SIG_PREFETCH) /**< Prefetch Abort Signal Response. */ +ENUM_VAL(MSG_SIG_DATA) /**< Data Abort Signal Response. */ ENUM_END(dbg_msg_signo) /** Debugger Message Error Enums -- cgit v1.2.3 From 7af6f3e1ef6d172311038390b156e6c65c72afb1 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 10:24:21 +0800 Subject: updated gdb signal numbers based on ecos header Use actual ECoS header signal definitions --- Debugger/debug_internals.h | 21 +++++++++++++++++---- Debugger/debug_stub.S | 7 +++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index f7ab7d5..74a695c 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -301,11 +301,24 @@ ENUM_END(bkpt_type_t) * Debugger Signal Message Enums. * The enums must be consecutive, starting from 0 */ -/* FIXME: Need to validate against the ecos-generic-stub.c Error enums */ +/* Need to sync with the Signal enums in ecos-common-hal_stub.c */ ENUM_BEGIN -ENUM_VALASSIGN(MSG_SIG_DEFAULT, 0) /**< Normal Signal Response. */ -ENUM_VAL(MSG_SIG_PREFETCH) /**< Prefetch Abort Signal Response. */ -ENUM_VAL(MSG_SIG_DATA) /**< Data Abort Signal Response. */ +ENUM_VALASSIGN(MSG_SIG_DEFAULT, 0) /**< Default Signal Response. */ +ENUM_VAL(MSG_SIG_HUP) /**< Hangup Signal Response. */ +ENUM_VAL(MSG_SIG_INT) /**< Interrupt Signal Response. */ +ENUM_VAL(MSG_SIG_QUIT) /**< Quit Signal Response. */ +ENUM_VAL(MSG_SIG_ILL) /**< Illegal Instruction Signal Response (not reset when caught). */ +ENUM_VAL(MSG_SIG_TRAP) /**< Trace Trap Signal Response (not reset when caught). */ +ENUM_VAL(MSG_SIG_ABRT) /**< Abort Signal Response (replace SIGIOT). */ +ENUM_VAL(MSG_SIG_EMT) /**< EMT Instruciton Signal Response. */ +ENUM_VAL(MSG_SIG_FPE) /**< Floating Point Exception Signal Response. */ +ENUM_VAL(MSG_SIG_KILL) /**< Kill Signal Response (cannot be caught or ignored). */ +ENUM_VAL(MSG_SIG_BUS) /**< Bus Error Signal Response. */ +ENUM_VAL(MSG_SIG_SEGV) /**< Segmentation Violation Signal Response. */ +ENUM_VAL(MSG_SIG_SYS) /**< Bad Argument to System Call Signal Response. */ +ENUM_VAL(MSG_SIG_PIPE) /**< Write on a Pipe with No Reader Signal Response. */ +ENUM_VAL(MSG_SIG_ALRM) /**< Alarm Clock Signal Response. */ +ENUM_VAL(MSG_SIG_TERM) /**< Software Termination Signal from Kill Signal Response. */ ENUM_END(dbg_msg_signo) /** Debugger Message Error Enums diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index e462c6b..19645a5 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -740,19 +740,18 @@ __dbg__sendDebugMsgExit: * r0, r1, r2, r3: destroyed */ _dbg__cmd_Status: - /* FIXME: The Signal numbers do not correspond to any GDB defined signals */ stmfd sp!, {lr} _dbg_get_bkpt_type r0 _check_data_abort_exception: teq r0, #DBG_ABORT_DATA - moveq r1, #MSG_SIG_DATA + moveq r1, #MSG_SIG_BUS /* Bus Error */ beq _exit_dmg__cmd_Status _check_prefetch_abort_exception: teq r0, #DBG_ABORT_PREFETCH - moveq r1, #MSG_SIG_PREFETCH + moveq r1, #MSG_SIG_ABRT /* FIMXE: Look for a better Signal number */ beq _exit_dmg__cmd_Status _default_breakpoint_exception: - mov r1, #MSG_SIG_DEFAULT /* FIXME: Dummy Signal number */ + mov r1, #MSG_SIG_DEFAULT /* Dummy Signal number */ _exit_dmg__cmd_Status: _dbg_outputMsgStatusSig -- cgit v1.2.3 From 3500d60eaa090c048fae181cde26492f38a2b65f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 10:52:07 +0800 Subject: fix data abort error due to thumb bit set in instruction address Need to clear thumb flag in _dbg__install_one_breakpoint before accessing memory location, otherwise a Data Abort will be triggered for thumb instructions --- Debugger/debug_stub.S | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 19645a5..6dfb333 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1412,8 +1412,9 @@ _dbg__install_one_breakpoint: /* Check for Thumb bit */ tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ /* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ - ldreq r2, [r1] /* if 0: load ARM instruction from address location */ - ldrneh r2, [r1] /* else load Thumb instruction */ + bic r2, r1, #BKPT_STATE_THUMB_FLAG /* R2: Instruction Address; clear Thumb Flag for accessing to Memory */ + ldreq r2, [r2] /* if 0: load ARM instruction from address location */ + ldrneh r2, [r2] /* else load Thumb instruction */ _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */ stm r3, {r1, r2} bx lr -- cgit v1.2.3 From b5d953af250eb97ee1f41940edab873d547f2579 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 17:01:31 +0800 Subject: fix comment text --- Debugger/debug_stub.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 6dfb333..c75f297 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1412,7 +1412,7 @@ _dbg__install_one_breakpoint: /* Check for Thumb bit */ tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ /* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ - bic r2, r1, #BKPT_STATE_THUMB_FLAG /* R2: Instruction Address; clear Thumb Flag for accessing to Memory */ + bic r2, r1, #BKPT_STATE_THUMB_FLAG /* R2: Instruction Address; clear Thumb Flag for accessing Memory */ ldreq r2, [r2] /* if 0: load ARM instruction from address location */ ldrneh r2, [r2] /* else load Thumb instruction */ _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */ -- cgit v1.2.3 From 2830257afe20ee94de071990250868ed1290cd7f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 17:02:35 +0800 Subject: do not set thumb flag before calling thumb instruction handler routines Pass valid (even) addresses to thumb instruction handler routines. Set Thumb bit (b0) only on return from the handlers. --- Debugger/debug_opcodes.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index fbdd7db..d7811d7 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -698,7 +698,10 @@ _dbg_get_aborted_instr: beq _following_instr_addr_for_arm _following_instr_addr_for_thumb: add r6, r6, #2 /* Store default following Thumb instruction address to R6 */ +#if 0 + /* Flag Thumb instruction only within the instruction handler */ orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */ +#endif /* R4: Candidate Instruction Opcode * R5[3:0]: CPSR condition codes * R6: Default Following Instruction Address (PC+2) @@ -1159,9 +1162,6 @@ _arm_bx_blx_handler: _regenum2index r0, r1 /* Convert Enum into Index in R1 */ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ /* Here, the register value would have B0 set to indicate switch to Thumb mode */ -#if 0 - bic r0, #0x01 /* Clear R0[0] since it is used to indicates Thumb mode */ -#endif ldmfd sp!, {pc} /* _arm_ldr_pc_handler @@ -1354,7 +1354,7 @@ _thumb_get_regcount: ldr r0, [r1] /* Retrieve new PC value */ #if 0 /* PC Value should have B0 set */ - orr r0, r0, #0x01 /* Force R0[0] since it is used to indicates Thumb mode */ + orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Force R0[0] since it is used to indicates Thumb mode */ #endif ldmfd sp!, {pc} @@ -1395,7 +1395,7 @@ _thumb_calc_bcond_offset: add r0, r6, r0 /* PC+2 + signed offset */ add r0, r0, #2 /* PC+4 + signed offset */ _exit_thumb_bcond_instr: - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since it is used to indicates Thumb mode */ _exit_thumb_bcond_swi_handler: ldmfd sp!, {pc} @@ -1416,7 +1416,7 @@ _thumb_b_handler: asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */ add r0, r6, r0 /* PC+2 + signed offset */ add r0, r0, #2 /* PC+4 + signed offset */ - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since it is used to indicates Thumb mode */ ldmfd sp!, {pc} /* _thumb_long_bl_blx_handler @@ -1475,7 +1475,7 @@ _return_default_thumb_following_instr: */ mov r0, r6 /* Return default Following/Subsequent Instruction Address */ _flag_thumb_instr_addr: - orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */ + orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since it is used to indicates Thumb mode */ _exit_thumb_long_bl_blx_handler: ldmfd sp!, {pc} -- cgit v1.2.3 From 42dffd151ed52ebc4a918e9217cf376e34ebec6f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 17:21:36 +0800 Subject: most set thumb flag for non-matching thumb instruction decode case Thumb bit was not set if there was no matching Thumb instruction found --- Debugger/debug_opcodes.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index d7811d7..ee516ab 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -777,6 +777,7 @@ _eval_thumb_instruction: _dbg_thumbDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */ teq r1, #0 /* Check for Null Entry (End of Table marker) */ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */ + orreq r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] to flag Thumb mode */ beq _exit_eval_thumb_instruction and r7, r4, r2 /* Use R5 to check masked instruction opcode (from R4) to see if it matches template (in R1) */ @@ -1283,7 +1284,7 @@ _arm_b_bl_blx_get_offset: bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */ tst r4, #ARM_BLX_INSTR_HBIT /* H bit for Thumb Halfword Address */ orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */ - orr r0, r0, #0x01 /* Set R0[0] since BLX instr used to switch to Thumb mode */ + orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since BLX instr used to switch to Thumb mode */ #endif _exit_arm_b_bl_blx_handler: -- cgit v1.2.3 From 1306993ca037f6a51dbf0aeab9e162e5878486c7 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 11 Jul 2011 20:09:10 +0800 Subject: fix thumb instruction parser for pop pc SP was not incremented correctly for the Thumb instruction POP PC opcode. --- Debugger/debug_opcodes.S | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index ee516ab..d0b4226 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -1345,12 +1345,13 @@ _thumb_get_SP_val: _getdbgregister DBGSTACK_USERSP_INDEX, r1 /* Retrieve SP contents into R1 */ _thumb_get_regcount: - mov r2, #0 /* Initialize reg_count (R2) to 0 */ mov r3, r4, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */ - /* This shortens the checking to a max of 8 iterations */ + /* POP is equivalent to LDMFD. Load PC is encoded in b8, + * the 8-bit vector is for Lo registers. + * This shortens the checking to a max of 8 iterations + */ 1: movs r3, r3, lsl #1 /* count number of '1' bits */ - addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */ - add r1, r1, #4 /* Walk the stack to locate the PUSHed LR (POP PC) value */ + addcs r1, r1, #4 /* Walk the stack to locate the PUSHed LR (POP PC) value */ bne 1b /* continue until vector is empty */ ldr r0, [r1] /* Retrieve new PC value */ #if 0 -- cgit v1.2.3 From c7d4fd94a369b757bebe3ee57512bd535dba3a36 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:20:14 +0800 Subject: modified debug test case for shorter loops to enable single stepping --- Debugger/debug_test.S | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index e0f3cf0..104e327 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -54,17 +54,16 @@ test_arm_1: test_arm_2: sub r0, r0, #1 - cmp r0, #8 - ldrle pc, =test_arm_1 - bgt test_arm_3 - beq test_arm_2 + cmp r0, #5 + bgt test_arm_1 + ldrle pc, =test_arm_2 ldr pc, =test_arm_1 test_arm_3: /* case for r0 == 9 */ sub r0, r0, #1 - teq r0, #5 - ldreq r2, =test_arm_1 + teq r0, #8 + beq test_arm_1 ldrne r2, =test_arm_3 bx r2 @@ -154,7 +153,7 @@ dbg__test_thumb_instr_sub1: .thumb_func dbg__test_thumb_instr_sub2: push {lr} - mov r0, #FALSE + mov r1, #FALSE pop {pc} -- cgit v1.2.3 From 3d7f61034a2e2421b97aa00c3cd2c9211f789919 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:29:08 +0800 Subject: fix thumb target address missing thumb flag for bx instruction --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 104e327..10600ec 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -133,10 +133,10 @@ test_thumb_3: sub r0, #1 cmp r0, #5 beq load_test_thumb_1 - ldr r2, =test_thumb_3 + ldr r2, =test_thumb_3+1 /* Need to set Thumb bit */ b exit_test_thumb_3 load_test_thumb_1: - ldr r2, =test_thumb_1 + ldr r2, =test_thumb_1+1 /* Need to set Thumb bit */ exit_test_thumb_3: bx r2 -- cgit v1.2.3 From 96ef68af99df49cce5ea2c52e7916e375f610df9 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:36:12 +0800 Subject: updated thumb test case compare limits to shorten single stepping duration --- Debugger/debug_test.S | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 10600ec..7f74b17 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -60,7 +60,6 @@ test_arm_2: ldr pc, =test_arm_1 test_arm_3: - /* case for r0 == 9 */ sub r0, r0, #1 teq r0, #8 beq test_arm_1 @@ -129,10 +128,9 @@ test_thumb_2: b test_thumb_1 test_thumb_3: - /* case for r0 == 9 */ sub r0, #1 - cmp r0, #5 - beq load_test_thumb_1 + cmp r0, #B + blo load_test_thumb_1 ldr r2, =test_thumb_3+1 /* Need to set Thumb bit */ b exit_test_thumb_3 load_test_thumb_1: -- cgit v1.2.3 From b008ad83d84b6c6d26488cc482356d749eeff36b Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:37:05 +0800 Subject: fix syntax error for hex constant --- Debugger/debug_test.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 7f74b17..78514c2 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -129,7 +129,7 @@ test_thumb_2: test_thumb_3: sub r0, #1 - cmp r0, #B + cmp r0, #0xB blo load_test_thumb_1 ldr r2, =test_thumb_3+1 /* Need to set Thumb bit */ b exit_test_thumb_3 -- cgit v1.2.3 From f8c4fe18c0793b2b5229e1de4b9782082216a465 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:39:42 +0800 Subject: revised loop constants again --- Debugger/debug_test.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 78514c2..eec7a01 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -121,7 +121,7 @@ test_thumb_1: test_thumb_2: sub r0, #1 - cmp r0, #8 + cmp r0, #5 bls test_thumb_1 bhi test_thumb_3 beq test_thumb_2 -- cgit v1.2.3 From 8149bcca21537f3522bf12afdad905ec5aeb28d8 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 07:42:44 +0800 Subject: arm subroutines called from thumb mode must be declared global --- Debugger/debug_test.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index eec7a01..a4082a5 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -70,10 +70,12 @@ exit_dbg__test_arm_instrstep: bl dbg__test_thumb_instr_sub1 ldmfd sp!, {pc} + .global dbg__test_arm_instr_sub1 dbg__test_arm_instr_sub1: mov r0, #10 bx lr + .global dbg__test_arm_instr_sub1 dbg__test_arm_instr_sub2: stmfd sp!, {r4, lr} mov r0, #TRUE -- cgit v1.2.3 From d85fa5f7a8d9c18fb960d51195b4dfb67c6396bf Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 08:30:18 +0800 Subject: fix thumb mode bx pc target address calculation BX PC is used to call ARM subroutines from Thumb mode. The address returned by BX PC should be 2 instructions after the current PC value (PC+4). --- Debugger/debug_opcodes.S | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index d0b4226..12872dd 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -1317,14 +1317,16 @@ _exit_arm_coproc_swi_handler: * R6: Default Following Instruction Address (PC+2) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed + * R1, R2: destroyed */ _thumb_bx_blx_handler: stmfd sp!, {lr} - and r0, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */ - mov r0, r0, lsr #3 /* Shift Rn Enum to R0[3:0] */ - _regenum2index r0, r1 /* Convert Enum into Index in R1 */ + and r2, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R2[6:3] (Hi-Reg indicated by B6) */ + mov r2, r2, lsr #3 /* Shift Rn Enum to R2[3:0] */ + _regenum2index r2, r1 /* Convert Enum into Index in R1 */ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ + teq r2, #REG_PC + addeq r0, r0, #4 /* Adjust PC relative register value (for BX PC) */ /* Here, the register value would have R0[0] set to indicate switch to Thumb mode */ ldmfd sp!, {pc} -- cgit v1.2.3 From 58574d9e237773a18dc2c430f6b674e9e267eb15 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 08:53:24 +0800 Subject: added bx pc support for arm instruction decoding, updated comments BX PC for ARM mode does not account for PC relative offsets. Updated comments regarding instruction parsing. --- Debugger/debug_opcodes.S | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Debugger/debug_opcodes.S b/Debugger/debug_opcodes.S index 12872dd..307da8b 100644 --- a/Debugger/debug_opcodes.S +++ b/Debugger/debug_opcodes.S @@ -12,6 +12,17 @@ * See COPYING for redistribution license * */ + +/* WARNING: The following excepted code from eCos arm_stub.c has bugs in + * the next instruction address calculation logic. The C code has not been + * updated since it is only used for documentation purposes. + * + * Correct code behavior should be determined from the ARMDEBUG source code + * whenever there is conflict in the algorithms. + * + * Of note: ARM and Thumb mode BX PC handling (missing PC+8/PC+4 adjustment). + * LDM PC handling (missing Pre/Post Incr/Decr adjustment). + */ /**************************************************************************** // Selected Routines from the eCos arm_stub.c related to next instruction address // determination in ARM processors. @@ -1155,13 +1166,15 @@ _opcode_mvn: * R6: Default Following Instruction Address (PC+4) * On exit: * R0: following instruction address (B0 set to indicate Thumb mode) - * R1: destroyed + * R1,R2: destroyed */ _arm_bx_blx_handler: stmfd sp!, {lr} - and r0, r4, #NIBBLE0 /* Register Rn Enum in R0 */ - _regenum2index r0, r1 /* Convert Enum into Index in R1 */ + and r2, r4, #NIBBLE0 /* Register Rn Enum in R2 */ + _regenum2index r2, r1 /* Convert Enum into Index in R1 */ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */ + teq r2, #REG_PC + addeq r0, r0, #8 /* Adjust PC relative register value (for BX PC) */ /* Here, the register value would have B0 set to indicate switch to Thumb mode */ ldmfd sp!, {pc} -- cgit v1.2.3 From db794b0fb270d533b97d54094b855c2da1377a16 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:00:29 +0800 Subject: fix loop logic in arm test routine --- Debugger/debug_test.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index a4082a5..10afc57 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -55,9 +55,9 @@ test_arm_1: test_arm_2: sub r0, r0, #1 cmp r0, #5 - bgt test_arm_1 - ldrle pc, =test_arm_2 - ldr pc, =test_arm_1 + bgt test_arm_3 + ldrle pc, =test_arm_1 + ldr pc, =exit_dbg__test_arm_instrstep test_arm_3: sub r0, r0, #1 -- cgit v1.2.3 From e895a0266a11e76a19291f584e2876e7796b024c Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:04:55 +0800 Subject: more fixes to arm test routine --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 10afc57..bf443c2 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -55,8 +55,8 @@ test_arm_1: test_arm_2: sub r0, r0, #1 cmp r0, #5 - bgt test_arm_3 - ldrle pc, =test_arm_1 + bgt test_arm_1 + ldrle pc, =test_arm_2 ldr pc, =exit_dbg__test_arm_instrstep test_arm_3: -- cgit v1.2.3 From 7cb1f500462a6e4ab49fc617f9f9be6d2ec0545c Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:13:45 +0800 Subject: fix branch logic in arm test case --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index bf443c2..0bedca2 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -42,8 +42,8 @@ dbg__test_arm_bkpt: dbg__test_arm_instrstep: stmfd sp!, {lr} bl dbg__test_arm_instr_sub1 - ldr r1, =test_arm_2 /* R1: pointer to test_arm_2 */ - ldr r2, =test_arm_2 /* R2: pointer to test_arm_2 (should not be triggered) */ + ldr r1, =test_arm_3 /* R1: pointer to test_arm_3 */ + ldr r2, =test_arm_3 /* R2: pointer to test_arm_3 (should not be triggered) */ mov pc, r1 test_arm_1: -- cgit v1.2.3 From 09b1c9c95f54b58f1d08fedc17b23479c7f5894c Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:17:45 +0800 Subject: more logic bugs in arm loop branch test --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 0bedca2..30d7604 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -43,12 +43,12 @@ dbg__test_arm_instrstep: stmfd sp!, {lr} bl dbg__test_arm_instr_sub1 ldr r1, =test_arm_3 /* R1: pointer to test_arm_3 */ - ldr r2, =test_arm_3 /* R2: pointer to test_arm_3 (should not be triggered) */ + ldr r2, =test_arm_2 /* R2: pointer to test_arm_2 */ mov pc, r1 test_arm_1: subs r0, r0, #1 - addne pc, r1, #4 /* If R0 > 0, keep branching to a new location */ + addne pc, r2, #4 /* If R0 > 0, keep branching to a new location */ /* else R0 == 0 */ b exit_dbg__test_arm_instrstep -- cgit v1.2.3 From 1948f5135e382466abe63b589dea37d88b4cb44e Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:20:23 +0800 Subject: use r3 in test_arm_3 to avoid clobbering r2 --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 30d7604..2f799b8 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -63,8 +63,8 @@ test_arm_3: sub r0, r0, #1 teq r0, #8 beq test_arm_1 - ldrne r2, =test_arm_3 - bx r2 + ldrne r3, =test_arm_3 + bx r3 exit_dbg__test_arm_instrstep: bl dbg__test_thumb_instr_sub1 -- cgit v1.2.3 From ca5ac8bff5119c6ee644c774eb2707a6e6cc245f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 09:24:54 +0800 Subject: avoid endless loop in test_arm_2 routine --- Debugger/debug_test.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Debugger/debug_test.S b/Debugger/debug_test.S index 2f799b8..7f8c85f 100644 --- a/Debugger/debug_test.S +++ b/Debugger/debug_test.S @@ -56,8 +56,8 @@ test_arm_2: sub r0, r0, #1 cmp r0, #5 bgt test_arm_1 - ldrle pc, =test_arm_2 - ldr pc, =exit_dbg__test_arm_instrstep + ldrle pc, =exit_dbg__test_arm_instrstep + b exit_dbg__test_arm_instrstep test_arm_3: sub r0, r0, #1 -- cgit v1.2.3 From ac98beb0b3b8b0d67e7c599ade2cc2b01dd80bde Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 13:26:14 +0800 Subject: return lowecase hex chars to avoid conflict with gdb error response GDB error response starts with E NN, which can be triggered if the hex value starts with an E digit. Use lowercase hex digits to avoid this conflict. --- Debugger/debug_hexutils.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_hexutils.S b/Debugger/debug_hexutils.S index d54445b..267406f 100644 --- a/Debugger/debug_hexutils.S +++ b/Debugger/debug_hexutils.S @@ -22,7 +22,9 @@ .align 4 hex2char_lut: - .ascii "0123456789ABCDEF" + /* .ascii "0123456789ABCDEF" */ + /* Need to use lowercase hex chars to avoid confusion with GDB Error (E NN) response */ + .ascii "0123456789abcdef" /* Macros */ -- cgit v1.2.3 From 22bff6020346e7588983100c04b1d8061ff241e6 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 15:07:20 +0800 Subject: fix register corruption in __dbg__iterate_breakpoint_array Handler routine corrupts register used by __dbg__iterate_breakpoint_array. Added comments to indicate entry and exit register state for breakpoint related routines. --- Debugger/debug_stub.S | 83 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 15 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index c75f297..3848cd4 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -1141,15 +1141,23 @@ _dbg__cont_check_breakpoint_type: beq _dbg__cont_is_manual_bkpt_or_address_specified @ FIXME: Need to validate the following code +/* Autobreakpoint handling is not robust. If there are intervening Exceptions which triggers the + * Debugger before the Auto Breakpoint is triggered, the Single Step instruction gets lost and + * the Breakpoint Opcode is left in the code. + * + * In addition, GDB knows to Step from a breakpointed instruction before continuing when + * Continue is issued. + */ _dbg__cont_is_normal_breakpoint: _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ +#if 0 bl dbg_following_instruction_addr /* following instruction address returned in r1 */ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ b _dbg__switch2undefmode - +#endif _dbg__cont_is_manual_bkpt_or_address_specified: bl _dbg__activate_breakpoints /* Restore exisiting breakpoints */ b _dbg__switch2undefmode @@ -1391,8 +1399,14 @@ _dbg__clear_breakpoints: .global dbg__install_singlestep /* dbg__install_singlestep * Install the Single Step Breakpoint + * * On entry: * R1: Instruction Address (31 bits, b0 = THUMB flag) + * On exit: + * R0: Breakpoint index (preserved) + * R1: Instruction Address (preserved) + * R2: Breakpoint Instruction + * R3: Breakpoint Entry address */ dbg__install_singlestep: mov r0, #0 @@ -1400,11 +1414,13 @@ dbg__install_singlestep: /* _dbg__install_one_breakpoint * Install breakpoint entry into Breakpoint State Table + * * On entry: * R0: Breakpoint index (assumed valid) * R1: Instruction Address (31 bits, b0 = THUMB flag) - * * On exit: + * R0: Breakpoint index (preserved) + * R1: Instruction Address (preserved) * R2: Breakpoint Instruction * R3: Breakpoint Entry address */ @@ -1422,6 +1438,11 @@ _dbg__install_one_breakpoint: /* _dbg__restore_singlestep * Restores the contents of the single step breakpoint to memory + * + * On entry: + * None + * On exit: + * R0-R2: Destroyed */ _dbg__restore_singlestep: mov r0, #0 /* single step breakpoint index */ @@ -1433,10 +1454,15 @@ _dbg__restore_singlestep: /* _dbg__restore_one_breakpoint * Restores the contents to memory for one breakpoint + * * On entry: * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT] * R1: Breakpoint Address (assumed valid) * R2: Breakpoint Instruction (assumed valid) + * On exit: + * R0: Breakpoint index (preserved) + * R1: B0 cleared if Thumb Instruction Address + * R2: Breakpoint Instruction (preserved) */ _dbg__restore_one_breakpoint: /* Check for Thumb bit */ @@ -1450,15 +1476,25 @@ _dbg__restore_one_breakpoint: /* _dbg__restore_breakpoints * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory * Only Active breakpoints (i.e., Non-zero Address) are processed. + * + * On entry: + * None + * On exit: + * R0-R6: Destroyed */ _dbg__restore_breakpoints: stmfd sp!, {lr} - ldr r5, =_dbg__restore_one_breakpoint + ldr r6, =_dbg__restore_one_breakpoint b __dbg__iterate_breakpoint_array .global dbg__activate_singlestep /* dbg__activate_singlestep * Activate the single step breakpoint to memory + * + * On entry: + * None + * On exit: + * R0-R3: Destroyed */ dbg__activate_singlestep: mov r0, #0 /* single step breakpoint index */ @@ -1470,10 +1506,14 @@ dbg__activate_singlestep: /* _dbg__activate_one_breakpoint * Activate one breakpoint to memory + * * On entry: * R0: Breakpoint index (assumed valid) * R1: Breakpoint Address (assumed valid) * R2: Breakpoint Instruction (assumed valid) + * On exit: + * R0: Breakpoint index (preserved) + * R1-R3: Destroyed */ _dbg__activate_one_breakpoint: /* Check for Thumb bit */ @@ -1503,43 +1543,56 @@ _dbg__breakpoint_invalid_thumb: /* _dbg__activate_breakpoints * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them * Only Active breakpoints (i.e., Non-zero Address) are processed. + * + * On entry: + * None + * On exit: + * R0-R6: Destroyed */ _dbg__activate_breakpoints: stmfd sp!, {lr} - ldr r5, =_dbg__activate_one_breakpoint + ldr r6, =_dbg__activate_one_breakpoint b __dbg__iterate_breakpoint_array /* __dbg__iterate_breakpoint_array - * Common routine iterates through the array of breakpoints (incl single step breakpoint) - * and executes routine given in R5, passing: + * WARNING: DO NOT CALL THIS ROUTINE DIRECTLY. + * Internal Routine, assumes that lr has been push to stack + * + * Common routine to iterate through the array of breakpoints (incl single step breakpoint) + * Only Active breakpoints (i.e., Non-zero Address entries) are processed. + * + * On Entry: * R0: Breakpoint index * R1: Breakpoint Address * R2: Breakpoint Instruction + * R6: Handler Routine + * On exit: + * R0-R5: Destroyed + * R6: Handler routine (preserved) * - * On Entry: - * Assumes that lr has been push to stack (routine can't be called directly) - * - * Only Active breakpoints (i.e., Non-zero Address entries) are processed. */ __dbg__iterate_breakpoint_array: - ldr r4, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */ - ldr r3, =__breakpoints_start__ /* end address check */ + ldr r5, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */ + ldr r4, =__breakpoints_start__ /* end address check */ ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ 4: sub r0, r0, #1 /* Decrement breakpoint index in r0 */ - ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + ldmea r5!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ teq r1, #0 /* Is it active? */ movne lr, pc - bxne r5 /* active entry */ - cmp r4, r3 + bxne r6 /* active entry */ + cmp r5, r4 bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ ldmfd sp!, {pc} /* _dbg__activate_autobreakpoint * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot + * * On entry: * R0: Current Breakpoint index (assumed valid) * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info] + * On exit: + * R0-R5: Destroyed */ _dbg__activate_autobreakpoint: stmfd sp!, {lr} -- cgit v1.2.3 From 47ce28faf2797edf0c3bc7b10f7ae453d1f6a152 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Tue, 12 Jul 2011 18:10:42 +0800 Subject: conditionally exclude dead code from breakpoint handling logic --- Debugger/debug_stub.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 3848cd4..ed45dd4 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -481,13 +481,15 @@ _dbg__switch2undefmode: ldr lr, =resume_execution mov pc, lr /* Exit via UNDEF mode */ +#if 0 _process_manual_breakpoint_thumb: mov r0, #DBG_MANUAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ b _restore_normal_breakpoints _process_normal_breakpoint_thumb: mov r0, #DBG_NORMAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ - b _restore_normal_breakpoints +/* b _restore_normal_breakpoints */ +#endif _restore_normal_breakpoints: _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */ -- cgit v1.2.3 From b14d454a454ffc35a94c3f99e176c40a68b31c0f Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 13 Jul 2011 07:50:49 +0800 Subject: remote autobreakpoint code from master branch Autobreakpoint support is not robust. It is removed from the master branch. The autobreakpoint_stub branch contains the old autobreakpoint code. --- Debugger/debug_internals.h | 2 +- Debugger/debug_stub.S | 118 ++++++++------------------------------------- Debugger/debug_stub.h | 4 +- 3 files changed, 24 insertions(+), 100 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index 74a695c..13efba2 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -287,7 +287,7 @@ ENUM_END(dbg_state_t) * The enums must be consecutive, starting from 0 */ ENUM_BEGIN -ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< Auto Breakpoint (Instruction resume after breakpoint). */ +ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< RESERVED: Auto Breakpoint (Instruction resume after breakpoint). */ ENUM_VAL(DBG_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */ ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */ ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index ed45dd4..136a86c 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -390,6 +390,16 @@ _dbg__flush_icache: /* nop */ bx lr +/* _dbg__switch2undefmode + * Common internal routine to return execution to user program + */ +_dbg__switch2undefmode: + bl _dbg__flush_icache + msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Configure Undef Mode */ + _dbg_setmode FALSE /* Debug Mode = False */ + ldr lr, =resume_execution + mov pc, lr /* Exit via UNDEF mode */ + /* dbg__abort_exception_handler * Handle Abort Exceptions * On entry: @@ -411,24 +421,19 @@ dbg__abort_exception_handler: */ .global dbg__thumb_bkpt_handler dbg__thumb_bkpt_handler: - and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ + /* On entry, r0 contains breakpoint index value */ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ ldr r1, =BKPT16_MANUAL_BKPT teq r0, r1 moveq r0, #DBG_MANUAL_BKPT_THUMB /* Manual Thumb Breakpoint, process it */ beq _restore_normal_breakpoints -_process_normal_or_auto_breakpoint_thumb: +_process_normal_breakpoint_thumb: ldr r1, =__breakpoints_num__ cmp r0, r1 /* Sanity check that index is in range */ bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */ - -_check_auto_breakpoint_thumb: - teq r4, #0 /* Check if AUTO flag set */ - moveq r0, #DBG_NORMAL_BKPT_THUMB /* No, it is a normal breakpoint */ - beq _restore_normal_breakpoints - b _process_auto_breakpoint + mov r0, #DBG_NORMAL_BKPT_THUMB /* It is a valid normal breakpoint */ + b _restore_normal_breakpoints /* dbg__arm_bkpt_handler * GDB handle_exception() routine (ARM Mode) @@ -440,56 +445,18 @@ _check_auto_breakpoint_thumb: .global dbg__arm_bkpt_handler dbg__arm_bkpt_handler: /* On entry, r0 contains breakpoint index value */ - and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ ldr r1, =BKPT32_MANUAL_BKPT teq r0, r1 moveq r0, #DBG_MANUAL_BKPT_ARM /* Manual ARM Breakpoint, process it */ beq _restore_normal_breakpoints -_process_normal_or_auto_breakpoint_arm: +_process_normal_breakpoint_arm: ldr r1, =__breakpoints_num__ cmp r0, r1 /* Sanity check that index is in range */ bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */ - -_check_auto_breakpoint_arm: - teq r4, #0 /* Check if AUTO flag set */ - moveq r0, #DBG_NORMAL_BKPT_ARM /* No, it is a normal breakpoint */ - beq _restore_normal_breakpoints -/* b _process_auto_breakpoint */ - -_process_auto_breakpoint: - /* Load Auto BKPT for Breakpoint index given in r0 */ - _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ - ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 /* Check that Breakpoint is active */ - beq dbg__bkpt_inactive - bl _dbg__activate_one_breakpoint - bl _dbg__restore_singlestep - bl _dbg__clear_singlestep - _dbg_set_bkpt_type_val DBG_AUTO_BKPT -/* b _dbg__switch2undefmode */ - -/* _dbg__switch2undefmode - * Common internal routine to return execution to user program - */ -_dbg__switch2undefmode: - bl _dbg__flush_icache - msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Configure Undef Mode */ - _dbg_setmode FALSE /* Debug Mode = False */ - ldr lr, =resume_execution - mov pc, lr /* Exit via UNDEF mode */ - -#if 0 -_process_manual_breakpoint_thumb: - mov r0, #DBG_MANUAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ - b _restore_normal_breakpoints - -_process_normal_breakpoint_thumb: - mov r0, #DBG_NORMAL_BKPT_THUMB /* Setup Breakpoint type before executing common routine */ -/* b _restore_normal_breakpoints */ -#endif + mov r0, #DBG_NORMAL_BKPT_ARM /* It is a valid normal breakpoint */ +/* b _restore_normal_breakpoints */ _restore_normal_breakpoints: _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */ @@ -1108,8 +1075,7 @@ _dbg__cmd_Detach: * * If Address is specified, update the next instruction address to specified address * - * If this is a Normal Breakpoint, then we need to install an Autobreakpoint at next instruction address - * and resume from current (Breakpoint) exception address + * If this is a Normal Breakpoint, then we resume from current (Breakpoint) exception address * Else (it is a Manual Breakpoint or Address Specified) * We need to resume from the next instruction address * On entry: @@ -1142,24 +1108,12 @@ _dbg__cont_check_breakpoint_type: teq r0, #DBG_MANUAL_BKPT_THUMB beq _dbg__cont_is_manual_bkpt_or_address_specified -@ FIXME: Need to validate the following code -/* Autobreakpoint handling is not robust. If there are intervening Exceptions which triggers the - * Debugger before the Auto Breakpoint is triggered, the Single Step instruction gets lost and - * the Breakpoint Opcode is left in the code. - * - * In addition, GDB knows to Step from a breakpointed instruction before continuing when - * Continue is issued. - */ _dbg__cont_is_normal_breakpoint: _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */ -#if 0 - bl dbg_following_instruction_addr /* following instruction address returned in r1 */ - bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ - _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ - bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ - b _dbg__switch2undefmode -#endif + /* GDB knows to Step from a breakpointed instruction before continuing when + * Continue is issued, so it is safe to activate all defined breakpoints and continue. + */ _dbg__cont_is_manual_bkpt_or_address_specified: bl _dbg__activate_breakpoints /* Restore exisiting breakpoints */ b _dbg__switch2undefmode @@ -1587,33 +1541,3 @@ __dbg__iterate_breakpoint_array: bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ ldmfd sp!, {pc} -/* _dbg__activate_autobreakpoint - * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot - * - * On entry: - * R0: Current Breakpoint index (assumed valid) - * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info] - * On exit: - * R0-R5: Destroyed - */ -_dbg__activate_autobreakpoint: - stmfd sp!, {lr} - mov r5, r0 /* Keep Current Breakpoint Index in r5 */ - ldr r4, =__breakpoints_end__ /* start from top of the table */ - ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ -4: subs r0, r0, #1 /* Decrement breakpoint index in r0 */ - ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - bls 5f /* Flag set by subs instruction previously. Reached Single Step, go activate AUTO Breakpoint */ - teq r0, r5 /* Is it the Current Breakpoint? */ - beq 4b /* Yes, so skip */ - teq r1, #0 /* Is it active? */ - blne _dbg__activate_one_breakpoint /* active entry */ - b 4b /* Next iteration */ -5: -/* Here, r1: Breakpoint Address, r2: Breakpoint Instruction */ - tst r1, #BKPT_STATE_THUMB_FLAG /* Check for Thumb bit -- 1: Thumb instruction */ - orreq r0, r5, #BKPT32_AUTO_BKPT /* Is ARM Instruction, merge AUTO flag with Current Breakpoint Index */ - orrne r0, r5, #BKPT16_AUTO_BKPT /* Is Thumb Instruction, merge AUTO flag with Current Breakpoint Index */ - bl _dbg__activate_one_breakpoint /* Activate AUTO Breakpoint */ - ldmfd sp!, {pc} - diff --git a/Debugger/debug_stub.h b/Debugger/debug_stub.h index 11b348e..6807ac1 100644 --- a/Debugger/debug_stub.h +++ b/Debugger/debug_stub.h @@ -34,12 +34,12 @@ #endif #define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */ -#define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */ +#define BKPT32_AUTO_BKPT 0x00080000 /* RESERVED: ARM BKPT Auto-Step Flag (for CONT support) */ #define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */ #define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction */ #define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */ -#define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */ +#define BKPT16_AUTO_BKPT 0x0080 /* RESERVED: Thumb BKPT Auto-Step Flag (for CONT support) */ #define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ /*@}*/ -- cgit v1.2.3 From c3a288fc5a3db3383dbc9e85bee032e4cd1b7c8d Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Mon, 18 Jul 2011 15:47:54 +0800 Subject: added explicit wait for nxt brick to be ready before client connection Python startup delay may be incurred where the GDB Client connection retransmits requests since no reply has been received from the NXT brick. This causes GDB to go out of sync. --- Host/nxt-gdb-server.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index fea3d9e..a631952 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -22,6 +22,7 @@ import select #import usb import pyfantom import struct +import sys CTRLC = chr(3) NAKCHAR = '-' @@ -156,14 +157,17 @@ class NXTGDBServer: s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind (('', self.port)) s.listen (1) - print "Waiting for GDB connection on port %s..." % self.port while True: - # Wait for a connection. - client, addr = s.accept () - print "Client from", addr + # We should open the NXT connection first, otherwise Python startup delay + # may cause GDB to misbehave + dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') # Open connection to the NXT brick. brick = nxt.locator.find_one_brick () brick.sock.debug = DEBUG + # Wait for a connection. + print "Waiting for GDB connection on port %s..." % self.port + client, addr = s.accept () + print "Client from", addr # Work loop, wait for a message from client socket or NXT brick. while client is not None: data = '' @@ -213,7 +217,7 @@ class NXTGDBServer: client.send (data) data = '' brick.sock.close() - print "Connection closed, waiting for GDB connection on port %s..." % self.port + print "Connection closed." if __name__ == '__main__': # Read options from command line. @@ -226,5 +230,9 @@ if __name__ == '__main__': if args: parser.error ("Too many arguments") # Run. - s = NXTGDBServer (options.port) - s.run () + try: + s = NXTGDBServer (options.port) + s.run () + except KeyboardInterrupt: + print "\n\nException caught. Bye!" + sys.exit() -- cgit v1.2.3 From 720aa337c19691c3dc3edbf816ca8141516b8ac2 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 10:05:09 +0800 Subject: implement query current thread support --- Debugger/debug_internals.h | 17 +++++++++++++---- Debugger/debug_macros.h | 14 ++++++++++++++ Debugger/debug_stub.S | 17 ++++++++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index 13efba2..c0291f3 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -119,6 +119,15 @@ #define CMD_STEP_MINPARAMLEN 0 /*@}*/ +/** @name Debug Query Command Constants. + * + * Debug Query Command + */ +/*@{*/ +#define CMD_QUERY_MINPARAMLEN 0 +#define CMD_QUERY_CURRTID_PARAMLEN 1 +#define CMD_QUERY_CURRTID_CHAR 'C' +/*@}*/ /** @name Debug Breakpoint Command Constants. @@ -167,12 +176,12 @@ #define RESET_VECTOR 0x00000000 #define UNDEF_VECTOR 0x00000004 -#define SVC_VECTOR 0x00000008 +#define SVC_VECTOR 0x00000008 #define PABRT_VECTOR 0x0000000C #define DABRT_VECTOR 0x00000010 #define RESERVED_VECTOR 0x00000014 -#define IRQ_VECTOR 0x00000018 -#define FIQ_VECTOR 0x0000001C +#define IRQ_VECTOR 0x00000018 +#define FIQ_VECTOR 0x0000001C /*@}*/ @@ -210,7 +219,7 @@ #define CPSR_FIQ 0x00000040 #define CPSR_IRQ 0x00000080 #define CPSR_MODE 0x0000001F -#define CPSR_COND 0xF0000000 +#define CPSR_COND 0xF0000000 /* ARM Exception Modes */ #define MODE_USR 0x10 /* User mode */ diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index fcf6ca6..b25c7b4 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -265,6 +265,20 @@ __dbg_outputSigMsg .endm +/* _dbg_outputMsgCurrTID + * Return Message with Default Thread ID ('+$QC0') + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R1: destroyed + * R2: destroyed + */ + .macro _dbg_outputMsgCurrTID + ldr r0, =debug_OutMsgBuf + ldr r1, =debug_ThreadIDResponse /* ASCIIZ terminated */ + _dbg_stpcpy r0, r1, r2 + .endm + + /* _regenum2index * Convert register enum to debugger stack index * diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 136a86c..eacdd5d 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -251,6 +251,9 @@ debug_SignalResponsePrefix: debug_OkResponse: .byte '+','$','O','K',0 +debug_ThreadIDResponse: + .byte '+','$','Q','C','0',0 /* 0: Any thread */ + /* The CmdIndexTable and CmdJumpTable must be kept in sync */ debug_cmdIndexTable: .byte 'g','G','p','P','m','M','D','c','s','k','z','Z','?','q','Q',0 @@ -738,7 +741,19 @@ _exit_dmg__cmd_Status: _dbg__cmd_Query: stmfd sp!, {lr} _dbg_setstate DBG_CONFIGURED /* We have exchanged query messages with the GDB server */ - b __dbg__procUnimplementedError /* FIXME: return an empty message to GDB (no modifiable settings) */ + bl __dbg__cmdParamLen + cmp r1, #CMD_QUERY_CURRTID_PARAMLEN + bne _dbg__cmd_Query_default + +_dbg__cmd_Query_check: + ldrb r2, [r0] /* Get First Query Param Char */ + teq r2, #CMD_QUERY_CURRTID_CHAR /* Handle Current Thread ID Query */ + bne _dbg__cmd_Query_default + _dbg_outputMsgCurrTID + b __dbg__sendDebugMsgExit + +_dbg__cmd_Query_default: + b __dbg__procUnimplementedError /* FIXME: return an empty message to GDB (no modifiable settings) */ /* _dbg__cmd_GetOneReg -- cgit v1.2.3 From 0c0b43214104217fe4616a7600e2165d192202df Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 10:32:49 +0800 Subject: fix register corruption when using setstate macro We must preserve R0 and R1 which are destroyed by the setstate macro. --- Debugger/debug_stub.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index eacdd5d..1b0ef8c 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -739,8 +739,9 @@ _exit_dmg__cmd_Status: * r0, r1, r2, r3: destroyed */ _dbg__cmd_Query: - stmfd sp!, {lr} + stmfd sp!, {r0,r1, lr} _dbg_setstate DBG_CONFIGURED /* We have exchanged query messages with the GDB server */ + ldmfd sp!, {r0, r1} /* Restore parameters needed for subsequent processing */ bl __dbg__cmdParamLen cmp r1, #CMD_QUERY_CURRTID_PARAMLEN bne _dbg__cmd_Query_default -- cgit v1.2.3 From c459f880d4a63516664434c0da480905e4481400 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 11:43:49 +0800 Subject: refactoring of message copying macros Cleaned up macros used to copy debug messages to output buffers --- Debugger/debug_internals.h | 6 +- Debugger/debug_macros.h | 165 ++++++++++++++++++++++----------------------- Debugger/debug_stub.S | 31 +++++++-- 3 files changed, 113 insertions(+), 89 deletions(-) diff --git a/Debugger/debug_internals.h b/Debugger/debug_internals.h index c0291f3..e187b82 100644 --- a/Debugger/debug_internals.h +++ b/Debugger/debug_internals.h @@ -126,7 +126,11 @@ /*@{*/ #define CMD_QUERY_MINPARAMLEN 0 #define CMD_QUERY_CURRTID_PARAMLEN 1 -#define CMD_QUERY_CURRTID_CHAR 'C' +#define CMD_QUERY_FTINFO_PARAMLEN 11 +#define CMD_QUERY_STINFO_PARAMLEN 11 +#define CMD_QUERY_CURRTID_CHAR 'C' +#define CMD_QUERY_FTINFO_CHAR 'f' +#define CMD_QUERY_STINFO_CHAR 's' /*@}*/ diff --git a/Debugger/debug_macros.h b/Debugger/debug_macros.h index b25c7b4..8d63e46 100644 --- a/Debugger/debug_macros.h +++ b/Debugger/debug_macros.h @@ -122,17 +122,44 @@ bne 1b .endm +/* _dbg_CopyMsg2OutputBuf + * Copies source message to output buffer + * On entry: + * R2: source message buffer (ASCIIZ terminated) + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R2-R3: destroyed + */ + .macro _dbg_CopyMsg2OutputBuf + ldr r0, =debug_OutMsgBuf + _dbg_stpcpy r0, r2, r3 + .endm + +/* _dbg_CopyMsg2OutputBuf_withParam + * Internal Routine called to output message with parameters + * Return Message with byte-sized parameter + * On entry: + * R1: byte-sized param + * R2: source message buffer (ASCIIZ terminated) + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R1-R3: destroyed + */ + .macro _dbg_CopyMsg2OutputBuf_withParam + _dbg_CopyMsg2OutputBuf /* R1 unchanged */ + bl byte2ascii /* R0 points to buffer position after byte value */ + _asciiz r0, r1 + .endm + /* _dbg_outputAckOnlyFlag * Return Flag ('+') for Continue or Step * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R2-R3: destroyed */ .macro _dbg_outputAckOnlyFlag - ldr r0, =debug_OutMsgBuf - ldr r1, =debug_AckOnlyFlag /* ASCIIZ terminated */ - _dbg_stpcpy r0, r1, r2 + ldr r2, =debug_AckOnlyFlag /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf .endm @@ -140,60 +167,67 @@ * Return Flag ('-') for Checksum Error (retransmission needed) * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R2-R3: destroyed */ .macro _dbg_outputRetransmitFlag - ldr r0, =debug_OutMsgBuf - ldr r1, =debug_RetransmitFlag /* ASCIIZ terminated */ - _dbg_stpcpy r0, r1, r2 + ldr r2, =debug_RetransmitFlag /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf .endm /* _dbg_outputMsgValidResponse * Return Message with valid response ('+$') * On exit: * R0: Pointer to Output Buffer next character slot location - * R1: destroyed - * R2: destroyed + * R2-R3: destroyed */ .macro _dbg_outputMsgValidResponse - ldr r0, =debug_OutMsgBuf - ldr r1, =debug_ValidResponsePrefix - _dbg_stpcpy r0, r1, r2 + ldr r2, =debug_ValidResponsePrefix + _dbg_CopyMsg2OutputBuf .endm - /* _dbg_outputMsgStatusOk * Return Message with Ok ('+$OK') status * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R2-R3: destroyed */ .macro _dbg_outputMsgStatusOk - ldr r0, =debug_OutMsgBuf - ldr r1, =debug_OkResponse /* ASCIIZ terminated */ - _dbg_stpcpy r0, r1, r2 + ldr r2, =debug_OkResponse /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf .endm -/* __dbg_outputErrMsg - * Internal Routine called to generate error messages - * Return Message with Error ('+$ENN') status - * On entry: - * R1: error code - * On exit: +/* _dbg_outputMsgCurrTID + * Return Message with Default Thread ID ('+$QC0') + * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed - * R3: destroyed - */ - .macro __dbg_outputErrMsg - ldr r0, =debug_OutMsgBuf - ldr r2, =debug_ErrorResponsePrefix - _dbg_stpcpy r0, r2, r3 - bl byte2ascii /* R0 points to buffer position after byte value */ - _asciiz r0, r1 - .endm + * R2-R3: destroyed + */ + .macro _dbg_outputMsgCurrTID + ldr r2, =debug_ThreadIDResponse /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf + .endm + +/* _dbg_outputMsgFirstThreadInfo + * Return Message with Default Current Thread ID ('+$m0') + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R2-R3: destroyed + */ + .macro _dbg_outputMsgFirstThreadInfo + ldr r2, =debug_FirstThreadInfoResponse /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf + .endm + +/* _dbg_outputMsgSubsequentThreadInfo + * Return Message with Default Current Thread ID ('+$m0') + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R2-R3: destroyed + */ + .macro _dbg_outputMsgSubsequentThreadInfo + ldr r2, =debug_SubsequentThreadInfoResponse /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf + .endm /* _dbg_outputMsgStatusErr * Return Message with Error ('+$ENN') status @@ -201,43 +235,22 @@ * R1: error code * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed - * R3: destroyed + * R1-R3: destroyed */ .macro _dbg_outputMsgStatusErr - __dbg_outputErrMsg + ldr r2, =debug_ErrorResponsePrefix + _dbg_CopyMsg2OutputBuf_withParam .endm /* _dbg_outputMsgStatusErrCode * Return Message with Error ('+$ENN') status * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R1-R3: destroyed */ .macro _dbg_outputMsgStatusErrCode errcode mov r1, #\errcode - __dbg_outputErrMsg - .endm - -/* __dbg_outputSigMsg - * Internal Routine called to generate Signal messages - * Return Message with Signal ('+$SNN') status - * On entry: - * R1: signal code - * On exit: - * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed - * R3: destroyed - */ - .macro __dbg_outputSigMsg - ldr r0, =debug_OutMsgBuf - ldr r2, =debug_SignalResponsePrefix - _dbg_stpcpy r0, r2, r3 - bl byte2ascii /* R0 points to buffer position after byte value */ - _asciiz r0, r1 + _dbg_outputMsgStatusErr .endm /* _dbg_outputMsgStatusSig @@ -246,38 +259,24 @@ * R1: signal code * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R1-R3: destroyed */ .macro _dbg_outputMsgStatusSig - __dbg_outputSigMsg + ldr r2, =debug_SignalResponsePrefix + _dbg_CopyMsg2OutputBuf_withParam .endm /* _dbg_outputMsgStatusSigCode * Return Message with Signal ('+$SNN') status * On exit: * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed + * R1-R3: destroyed */ .macro _dbg_outputMsgStatusSigCode statuscode mov r1, #\statuscode - __dbg_outputSigMsg + _dbg_outputMsgStatusSig .endm -/* _dbg_outputMsgCurrTID - * Return Message with Default Thread ID ('+$QC0') - * On exit: - * R0: Pointer to Output Buffer ASCIIZ location - * R1: destroyed - * R2: destroyed - */ - .macro _dbg_outputMsgCurrTID - ldr r0, =debug_OutMsgBuf - ldr r1, =debug_ThreadIDResponse /* ASCIIZ terminated */ - _dbg_stpcpy r0, r1, r2 - .endm - /* _regenum2index * Convert register enum to debugger stack index diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 1b0ef8c..cbb253a 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -254,6 +254,11 @@ debug_OkResponse: debug_ThreadIDResponse: .byte '+','$','Q','C','0',0 /* 0: Any thread */ +debug_FirstThreadInfoResponse: + .byte '+','$','m','0',0 /* 0: One default thread */ +debug_SubsequentThreadInfoResponse: + .byte '+','$','l',0 /* End of Thread List */ + /* The CmdIndexTable and CmdJumpTable must be kept in sync */ debug_cmdIndexTable: .byte 'g','G','p','P','m','M','D','c','s','k','z','Z','?','q','Q',0 @@ -693,11 +698,11 @@ __dbg__procCmdReturnOutputLengthError: */ __dbg__procBreakpointAddrError: mov r1, #MSG_UNKNOWNBRKPT - b __dbg__procErrorMsg +/* b __dbg__procErrorMsg */ __dbg__procErrorMsg: - __dbg_outputErrMsg + _dbg_outputMsgStatusErr /* b __dbg__sendDebugMsgExit */ __dbg__sendDebugMsgExit: @@ -743,15 +748,31 @@ _dbg__cmd_Query: _dbg_setstate DBG_CONFIGURED /* We have exchanged query messages with the GDB server */ ldmfd sp!, {r0, r1} /* Restore parameters needed for subsequent processing */ bl __dbg__cmdParamLen - cmp r1, #CMD_QUERY_CURRTID_PARAMLEN - bne _dbg__cmd_Query_default + cmp r1, #CMD_QUERY_MINPARAMLEN + beq _dbg__cmd_Query_default -_dbg__cmd_Query_check: ldrb r2, [r0] /* Get First Query Param Char */ +_dbg__cmd_Query_check_C: teq r2, #CMD_QUERY_CURRTID_CHAR /* Handle Current Thread ID Query */ + bne _dbg__cmd_Query_check_fThreadInfo + cmp r1, #CMD_QUERY_CURRTID_PARAMLEN bne _dbg__cmd_Query_default _dbg_outputMsgCurrTID b __dbg__sendDebugMsgExit +_dbg__cmd_Query_check_fThreadInfo: + teq r2, #CMD_QUERY_FTINFO_CHAR /* Handle fThreadInfo Query */ + bne _dbg__cmd_Query_check_sThreadInfo + cmp r1, #CMD_QUERY_FTINFO_PARAMLEN + bne _dbg__cmd_Query_default + _dbg_outputMsgFirstThreadInfo + b __dbg__sendDebugMsgExit +_dbg__cmd_Query_check_sThreadInfo: + teq r2, #CMD_QUERY_STINFO_CHAR /* Handle sThreadInfo ID Query */ + bne _dbg__cmd_Query_default + cmp r1, #CMD_QUERY_STINFO_PARAMLEN + bne _dbg__cmd_Query_default + _dbg_outputMsgSubsequentThreadInfo + b __dbg__sendDebugMsgExit _dbg__cmd_Query_default: b __dbg__procUnimplementedError /* FIXME: return an empty message to GDB (no modifiable settings) */ -- cgit v1.2.3 From 638903cb029c3b64c11bed2de2132880349b81c8 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 12:09:57 +0800 Subject: fix register usage clobbered by revised output macros R3 was clobbered by buffer output macros. Don't use R3 to store important data. --- Debugger/debug_stub.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index cbb253a..7b8e2f3 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -786,7 +786,7 @@ _dbg__cmd_Query_default: * r0: parameter buffer pointer (contents after '$' and '') * x * On exit: - * r0, r1, r2, r3: destroyed + * r0, r1, r2, r3, r4: destroyed * */ _dbg__cmd_GetOneReg: @@ -799,9 +799,9 @@ _dbg__cmd_GetOneReg: bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */ _dbg__proc_getRegister: - mov r3, r0 /* Keep register index safe */ + mov r4, r0 /* Keep register index safe */ _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */ - mov r1, r3 /* Move register index value to R1 */ + mov r1, r4 /* Move register index value to R1 */ bl _dbg_outputOneRegValue /* update output buffer */ _asciiz r0, r1 bl dbg__putDebugMsg /* Send response to the GDB server */ @@ -1012,7 +1012,7 @@ _dbg__nop: * r0: parameter buffer pointer (contents after '$' and '') * AA..AA,LLLL * On exit: - * r0, r1, r2, r3, r4: destroyed + * r0, r1, r2, r3, r4, r5: destroyed */ _dbg__cmd_ReadMem: stmfd sp!, {lr} @@ -1023,7 +1023,7 @@ _dbg__cmd_ReadMem: bl ascii2word_be /* convert ASCII address location to Hex (in R0), R1 has address of next buffer char */ #endif bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ - mov r3, r0 /* Keep Address location in R3 */ + mov r5, r0 /* Keep Address location in R5 */ _check_msgseparator r1 bne __dbg__procCmdParamError /* Can't find ',' */ mov r0, r1 /* move buffer pointer to R0 for subsequent processing */ @@ -1034,7 +1034,7 @@ _dbg__cmd_ReadMem: /* FIXME: Should validate the address? */ _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */ -1: ldrb r1, [r3], #1 +1: ldrb r1, [r5], #1 bl byte2ascii /* update output buffer */ subs r4, r4, #1 bne 1b -- cgit v1.2.3 From 2b908b104aa9be49c77627dfa3a57833e75cdc20 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 12:51:48 +0800 Subject: revised get register logic GDB will query for CPSR register value explicitly. Return dummy values for FP0-FP7, FPSCR --- Debugger/debug_stub.S | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 7b8e2f3..90bc9ce 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -827,11 +827,15 @@ _dbg_outputOneRegValue: moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ beq _retrieve_RegVal + bhi _exit_dbg_outputOneRegValue /* No match (reg enum > REG_CPSR), skip */ + +#if 0 cmp r1, #REG_FPSCR bne _exit_dbg_outputOneRegValue /* No match, skip */ +#endif -_output_dummy_fpscr: - /* Output Dummy FPSCR value */ +_output_dummy_regval: + /* Output Dummy Register value (for FP0-FP7, FPSR) */ mov r1, #0 b _output2buffer /* Output all zeros for FPSCR */ @@ -873,10 +877,12 @@ _dbg__cmd_GetAllRegs: add r3, r3, #1 /* increment index */ cmp r3, #REG_PC bls 1b /* process all the registers */ +#if 0 _get_cpsr: + /* GDB will query for CPSR value specifically */ mov r1, #REG_CPSR /* Output User CPSR Value last */ bl _dbg_outputOneRegValue /* update output buffer */ - +#endif _asciiz r0, r1 bl dbg__putDebugMsg /* Send response to the GDB server */ ldmfd sp!, {pc} -- cgit v1.2.3 From 7d8a7f48a367091ab99a9e075205478fa3edb8c3 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 20 Jul 2011 13:07:26 +0800 Subject: updated comments for fp reg processing, set one reg logic Updated comments related to set one register, fixed logic for updating dummy FP registers --- Debugger/debug_stub.S | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 90bc9ce..404eb4d 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -72,7 +72,7 @@ * px get the value of one register (x) hex data or ENN * Px=rrrr set the value of one register (x) to OK or ENN * 32-bit hex value rrrr. - * x = ['0','F'] for R0-R15, + * x = ['0','F'] for R0-R15, ['10','17'] for F0-F7 (dummy) * '18' for FPSCR (dummy), '19' for User CPSR * * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN @@ -835,9 +835,9 @@ _dbg_outputOneRegValue: #endif _output_dummy_regval: - /* Output Dummy Register value (for FP0-FP7, FPSR) */ + /* Output Dummy Register value (for F0-F7, FPSR) */ mov r1, #0 - b _output2buffer /* Output all zeros for FPSCR */ + b _output2buffer /* Output all zeros for F0-F7, FPSCR */ _retrieve_RegVal: _getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */ @@ -906,11 +906,15 @@ _dbg_setOneRegValue: moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ beq _store_RegVal + bhi _exit_dbg_setOneRegValue /* No match (reg enum > REG_CPSR), skip */ + +#if 0 cmp r1, #REG_FPSCR bne _exit_dbg_setOneRegValue /* No match, skip */ /* FIXME: If we get SetAllRegs with FP reg values, this will not skip pass the FP regs! */ +#endif -_set_dummy_fpscr: +_set_dummy_regval: /* Set dummy FPSCR value (ignored) */ add r1, r0, #CMD_REG_REGPARAMLEN /* Just increment the pointer */ b _done_store_RegVal -- cgit v1.2.3 From 3c27ee0902ba21bcb2517f1e09db6f58caafee45 Mon Sep 17 00:00:00 2001 From: TC Wan Date: Wed, 20 Jul 2011 15:19:34 +0800 Subject: disable setting of fpscr dummy register Updated comments related to register manipulatuion --- Debugger/debug_stub.S | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 404eb4d..51bb0c6 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -836,6 +836,7 @@ _dbg_outputOneRegValue: _output_dummy_regval: /* Output Dummy Register value (for F0-F7, FPSR) */ + /* FIXME: F0-F7 expects output value that is more than 32-bits */ mov r1, #0 b _output2buffer /* Output all zeros for F0-F7, FPSCR */ @@ -855,7 +856,7 @@ _exit_dbg_outputOneRegValue: /* _dbg__cmd_GetAllRegs * Get All Register Values Command Handler - * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15, CPSR + * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15 * On entry: * r0: parameter buffer pointer (contents after '$' and '') * (no parameters) @@ -895,6 +896,8 @@ _get_cpsr: * On exit: * r0: (Updated) Address of parameter in buffer * r1, r2, r3: destroyed + * + * FIXME: This routine assumes that the input buffer contains exactly 8-Hex digits for each register value. */ _dbg_setOneRegValue: stmfd sp!, {lr} @@ -911,10 +914,10 @@ _dbg_setOneRegValue: #if 0 cmp r1, #REG_FPSCR bne _exit_dbg_setOneRegValue /* No match, skip */ - /* FIXME: If we get SetAllRegs with FP reg values, this will not skip pass the FP regs! */ #endif _set_dummy_regval: + /* FIXME: This assumes that we will never get FP reg values (96-bits) in this routine */ /* Set dummy FPSCR value (ignored) */ add r1, r0, #CMD_REG_REGPARAMLEN /* Just increment the pointer */ b _done_store_RegVal @@ -952,7 +955,14 @@ _dbg__cmd_SetOneReg: cmp r1, #CMD_REG_SETONE_MAXPARAMLEN /* Check for correct length */ bhi __dbg__procCmdParamError /* Unexpected input, report error */ + /* FIXME: We can't set FP regs. + * Fortunately the values required by FP regs are 96 bits (24 nibbles) + * so it fails the CMD_REG_SETONE_MAXPARAMLEN check + */ + bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */ + cmp r0, #REG_FPSCR + beq __dbg__procCmdParamError /* Don't allow setting of FPSCR */ mov r4, r0 /* Keep enum in R4 */ _check_msgassignment r1 /* R1 points to next char in buffer */ bne __dbg__procCmdParamError /* Can't find '=' */ @@ -973,7 +983,7 @@ _dbg__proc_setRegister: * */ _dbg__cmd_SetAllRegs: - /* Assumes that the registers are in the sequence R0, R1, ... R15, CPSR */ + /* Assumes that the registers are in the sequence R0, R1, ... R15 */ stmfd sp!, {lr} bl __dbg__cmdParamLen /* R0: pointer to parameters in buffer */ teq r1, #CMD_REG_SETALL_PARAMLEN /* Check for correct length */ @@ -985,20 +995,6 @@ _dbg__cmd_SetAllRegs: cmp r4, #REG_PC bls 1b -_set_cpsr: -#if 0 - /* GDB was not happy when this was added */ - /* Read dummy FPSCR value (ignored) */ -#ifdef __BIG_ENDIAN__ - bl ascii2word_be -#else - bl ascii2word_le -#endif - mov r0, r1 /* Copy buffer pointer to next parameter to R0 for return value */ -#endif - - mov r1, #REG_CPSR /* Use CPSR enum */ - bl _dbg_setOneRegValue /* R0: next parameter address pointer */ ldrb r0, [r0] teq r0, #0 /* Look for ASCIIZ character to terminate loop */ beq __dbg__procCmdOk -- cgit v1.2.3 From 0df4f4935d61c45789bf2ed744f809c8b71f57a1 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Fri, 22 Jul 2011 10:38:01 +0800 Subject: provide verbose, nowait options for invoking nxt-gdb-server Default is non-verbose, wait when invoking nxt-gdb-server. Allow nowait option to enable Eclipse external tool launching --- Host/nxt-gdb-server.py | 17 +++++++++++++---- Host/pyenv-nxt-gdb-server | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index a631952..453e62b 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -30,7 +30,7 @@ ACKCHAR = '+' STATUS_QUERY = "$?#3F" DEFAULT_PORT = 2828 SELECT_TIMEOUT = 0.1 -DEBUG = True +DEBUG = False DEBUG2 = False NXT_RECV_ERR = -1 @@ -48,8 +48,9 @@ class NXTGDBServer: # Debug command header, no reply. debug_command = 0x8d - def __init__ (self, port): + def __init__ (self, port, nowait): """Initialise server.""" + self.nowait = nowait self.port = port self.in_buf = '' @@ -160,7 +161,8 @@ class NXTGDBServer: while True: # We should open the NXT connection first, otherwise Python startup delay # may cause GDB to misbehave - dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') + if not self.nowait: + dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') # Open connection to the NXT brick. brick = nxt.locator.find_one_brick () brick.sock.debug = DEBUG @@ -226,12 +228,19 @@ if __name__ == '__main__': """) parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, help = "server listening port (default: %default)", metavar = "PORT") + parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, + help = "verbose mode (default: %default)") + parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, + help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") (options, args) = parser.parse_args () if args: parser.error ("Too many arguments") # Run. try: - s = NXTGDBServer (options.port) + DEBUG = options.verbose + if DEBUG: + print "Debug Mode Enabled!" + s = NXTGDBServer (options.port, options.nowait) s.run () except KeyboardInterrupt: print "\n\nException caught. Bye!" diff --git a/Host/pyenv-nxt-gdb-server b/Host/pyenv-nxt-gdb-server index b98c2d8..875e92e 100755 --- a/Host/pyenv-nxt-gdb-server +++ b/Host/pyenv-nxt-gdb-server @@ -1,3 +1,3 @@ #!/bin/sh export PYTHONPATH=~/svnrepo/nxt-python:~/gitrepo/pyfantom -arch -i386 /usr/bin/python2.6 ~/gitrepo/armdebug/Host/nxt-gdb-server.py +arch -i386 /usr/bin/python2.6 ~/gitrepo/armdebug/Host/nxt-gdb-server.py $* -- cgit v1.2.3 From dd98ff78d4169f216b5275c39f173828cbc462ec Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Thu, 28 Jul 2011 08:57:45 +0800 Subject: cleanup socket if user exception caught Close socket when CTRL-C pressed by user, to avoid Fantom driver errors on subsequent invocations --- Host/nxt-gdb-server.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index 453e62b..8df8f3c 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -164,8 +164,8 @@ class NXTGDBServer: if not self.nowait: dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') # Open connection to the NXT brick. - brick = nxt.locator.find_one_brick () - brick.sock.debug = DEBUG + server.brick = nxt.locator.find_one_brick () + server.brick.sock.debug = DEBUG # Wait for a connection. print "Waiting for GDB connection on port %s..." % self.port client, addr = s.accept () @@ -194,7 +194,7 @@ class NXTGDBServer: data = '' for seg in segments: try: - brick.sock.send (seg) + server.brick.sock.send (seg) except usb.USBError as e: # Some pyusb are buggy, ignore some "errors". if e.args != ('No error', ): @@ -202,14 +202,14 @@ class NXTGDBServer: if segments != [] and LIBUSB_RECEIVE_BLOCKING: if DEBUG2: print "Accessing Blocking sock.recv()" - data = self.reassemble (brick.sock) + data = self.reassemble (server.brick.sock) else: client.close () client = None if not LIBUSB_RECEIVE_BLOCKING: if DEBUG2: print "Accessing Non-Blocking sock.recv()" - data = self.reassemble (brick.sock) + data = self.reassemble (server.brick.sock) # Is there something from NXT brick? if data: @@ -218,7 +218,7 @@ class NXTGDBServer: if client: client.send (data) data = '' - brick.sock.close() + server.brick.sock.close() print "Connection closed." if __name__ == '__main__': @@ -240,8 +240,9 @@ if __name__ == '__main__': DEBUG = options.verbose if DEBUG: print "Debug Mode Enabled!" - s = NXTGDBServer (options.port, options.nowait) - s.run () + server = NXTGDBServer (options.port, options.nowait) + server.run () except KeyboardInterrupt: print "\n\nException caught. Bye!" + server.brick.sock.close() sys.exit() -- cgit v1.2.3 From 12dfcabe61faf7af3686d42163e636ec0f32175d Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Thu, 28 Jul 2011 09:08:16 +0800 Subject: cleanup exception handling to check for valid brick object Check for valid brick object before accessing it. --- Host/nxt-gdb-server.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index 8df8f3c..c1ca25a 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -53,6 +53,7 @@ class NXTGDBServer: self.nowait = nowait self.port = port self.in_buf = '' + self.brick = None def pack (self, data, segment_no): """Return packed data to send to NXT.""" @@ -164,8 +165,8 @@ class NXTGDBServer: if not self.nowait: dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') # Open connection to the NXT brick. - server.brick = nxt.locator.find_one_brick () - server.brick.sock.debug = DEBUG + self.brick = nxt.locator.find_one_brick () + self.brick.sock.debug = DEBUG # Wait for a connection. print "Waiting for GDB connection on port %s..." % self.port client, addr = s.accept () @@ -194,7 +195,7 @@ class NXTGDBServer: data = '' for seg in segments: try: - server.brick.sock.send (seg) + self.brick.sock.send (seg) except usb.USBError as e: # Some pyusb are buggy, ignore some "errors". if e.args != ('No error', ): @@ -202,14 +203,14 @@ class NXTGDBServer: if segments != [] and LIBUSB_RECEIVE_BLOCKING: if DEBUG2: print "Accessing Blocking sock.recv()" - data = self.reassemble (server.brick.sock) + data = self.reassemble (self.brick.sock) else: client.close () client = None if not LIBUSB_RECEIVE_BLOCKING: if DEBUG2: print "Accessing Non-Blocking sock.recv()" - data = self.reassemble (server.brick.sock) + data = self.reassemble (self.brick.sock) # Is there something from NXT brick? if data: @@ -218,7 +219,7 @@ class NXTGDBServer: if client: client.send (data) data = '' - server.brick.sock.close() + self.brick.sock.close() print "Connection closed." if __name__ == '__main__': @@ -244,5 +245,6 @@ if __name__ == '__main__': server.run () except KeyboardInterrupt: print "\n\nException caught. Bye!" - server.brick.sock.close() + if server.brick is not None: + server.brick.sock.close() sys.exit() -- cgit v1.2.3 From c1e8f425ec163ab87708e494be56f70e8f184999 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 3 Aug 2011 08:10:01 +0800 Subject: exit after gdb client disconnect in nowait mode Nowait mode (Eclipse IDE unattended invocation) should exit once the GDB client disconnects, to avoid the attempt to reattach to the NXT if it has shut down.--- Host/nxt-gdb-server.py | 402 +++++++++++++++++++++++++------------------------ 1 file changed, 202 insertions(+), 200 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index c1ca25a..ea5823a 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -3,7 +3,7 @@ # Copyright (C) 2011 the NxOS developers # # Module Developed by: Nicolas Schodet -# TC Wan +# TC Wan # # See AUTHORS for a full list of the developers. # @@ -39,212 +39,214 @@ LIBUSB_RECEIVE_BLOCKING = True class NXTGDBServer: - # Socket read size. - recv_size = 1024 + # Socket read size. + recv_size = 1024 - # Maximum message size. - pack_size = 61 - - # Debug command header, no reply. - debug_command = 0x8d + # Maximum message size. + pack_size = 61 + + # Debug command header, no reply. + debug_command = 0x8d - def __init__ (self, port, nowait): - """Initialise server.""" - self.nowait = nowait - self.port = port - self.in_buf = '' - self.brick = None + def __init__ (self, port, nowait): + """Initialise server.""" + self.nowait = nowait + self.port = port + self.in_buf = '' + self.brick = None - def pack (self, data, segment_no): - """Return packed data to send to NXT.""" - # Insert command and length. - assert len (data) <= self.pack_size - return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data + def pack (self, data, segment_no): + """Return packed data to send to NXT.""" + # Insert command and length. + assert len (data) <= self.pack_size + return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data - def unpack (self, data): - """Return unpacked data from NXT.""" - # May be improved, for now, check command and announced length. - if len (data) == 0: - return '', 0 # No message, exit - if len (data) < 3: - return '', NXT_RECV_ERR - header, body = data[0:3], data[3:] - command, segment_no, length = struct.unpack ('BBB', header) - if command != self.debug_command or length != len (body): - return '', NXT_RECV_ERR - return body, segment_no + def unpack (self, data): + """Return unpacked data from NXT.""" + # May be improved, for now, check command and announced length. + if len (data) == 0: + return '', 0 # No message, exit + if len (data) < 3: + return '', NXT_RECV_ERR + header, body = data[0:3], data[3:] + command, segment_no, length = struct.unpack ('BBB', header) + if command != self.debug_command or length != len (body): + return '', NXT_RECV_ERR + return body, segment_no - def segment (self, data): - """Split messages in GDB commands and make segments with each command.""" - segs = [ ] - self.in_buf += data + def segment (self, data): + """Split messages in GDB commands and make segments with each command.""" + segs = [ ] + self.in_buf += data - # Find ACK '+' - end = self.in_buf.find (ACKCHAR) - while end == 0: - self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR - if DEBUG2: - print "stripped ACK, remain: ", self.in_buf - end = self.in_buf.find (ACKCHAR) + # Find ACK '+' + end = self.in_buf.find (ACKCHAR) + while end == 0: + self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR + if DEBUG2: + print "stripped ACK, remain: ", self.in_buf + end = self.in_buf.find (ACKCHAR) - # Find NAK '-' - end = self.in_buf.find (NAKCHAR) - if end == 0: - msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] - segs.append (self.pack (msg, 0)) - end = self.in_buf.find (NAKCHAR) + # Find NAK '-' + end = self.in_buf.find (NAKCHAR) + if end == 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (NAKCHAR) - # Find Ctrl-C (assumed to be by itself and not following a normal command) - end = self.in_buf.find (CTRLC) - if end >= 0: - msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] - assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" - segs.append (self.pack (msg, 0)) - end = self.in_buf.find (CTRLC) - - end = self.in_buf.find ('#') - # Is # found and enough place for the checkum? - while end >= 0 and end < len (self.in_buf) - 2: - msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] - i = 0 - gdbprefix = msg[i] - while gdbprefix in [ACKCHAR]: - # Ignore any '+' - i += 1 - gdbprefix = msg[i] - if DEBUG2: - print "Checking '", gdbprefix, "'" - assert gdbprefix == '$', "not a GDB command" - # Make segments. - seg_no = 0 - while msg: - seg, msg = msg[0:self.pack_size], msg[self.pack_size:] - seg_no += 1 - if not msg: # Last segment. - seg_no = 0 - segs.append (self.pack (seg, seg_no)) - # Look for next one. - end = self.in_buf.find ('#') - return segs - - def reassemble (self, sock): - msg = '' - prev_segno = 0 - segno = NXT_RECV_ERR # force initial pass through while loop - while segno != 0: - try: - s, segno = self.unpack (sock.recv ()) - if len (s) == 0: - if segno == 0 and prev_segno == 0: - return '' # No message pending - else: - segno = NXT_RECV_ERR # Keep waiting for segments - # Ignore error packets - if segno >= 0: - # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0 - if segno > 0: - assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno) - prev_segno = segno - msg += s - except usb.USBError as e: - # Some pyusb are buggy, ignore some "errors". - if e.args != ('No error', ): - raise e - return msg - - def run (self): - """Endless run loop.""" - # Create the listening socket. - s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind (('', self.port)) - s.listen (1) - while True: - # We should open the NXT connection first, otherwise Python startup delay - # may cause GDB to misbehave - if not self.nowait: - dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') - # Open connection to the NXT brick. - self.brick = nxt.locator.find_one_brick () - self.brick.sock.debug = DEBUG - # Wait for a connection. - print "Waiting for GDB connection on port %s..." % self.port - client, addr = s.accept () - print "Client from", addr - # Work loop, wait for a message from client socket or NXT brick. - while client is not None: - data = '' - # Wait for a message from client or timeout. - rlist, wlist, xlist = select.select ([ client ], [ ], [ ], - SELECT_TIMEOUT) - for c in rlist: - assert c is client - # Data from client, read it and forward it to NXT brick. - data = client.recv (self.recv_size) - data = data.strip() - if len (data) > 0: - #if len (data) == 1 and data.find(CTRLC) >= 0: - # print "CTRL-C Received!" - # data = STATUS_QUERY - if DEBUG: - if data[0] == CTRLC: - print "[GDB->NXT] " - else: - print "[GDB->NXT] %s" % data - segments = self.segment (data) - data = '' - for seg in segments: - try: - self.brick.sock.send (seg) - except usb.USBError as e: - # Some pyusb are buggy, ignore some "errors". - if e.args != ('No error', ): - raise e - if segments != [] and LIBUSB_RECEIVE_BLOCKING: - if DEBUG2: - print "Accessing Blocking sock.recv()" - data = self.reassemble (self.brick.sock) - else: - client.close () - client = None - if not LIBUSB_RECEIVE_BLOCKING: - if DEBUG2: - print "Accessing Non-Blocking sock.recv()" - data = self.reassemble (self.brick.sock) - - # Is there something from NXT brick? - if data: - if DEBUG: - print "[NXT->GDB] %s" % data - if client: - client.send (data) - data = '' - self.brick.sock.close() - print "Connection closed." + # Find Ctrl-C (assumed to be by itself and not following a normal command) + end = self.in_buf.find (CTRLC) + if end >= 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (CTRLC) + + end = self.in_buf.find ('#') + # Is # found and enough place for the checkum? + while end >= 0 and end < len (self.in_buf) - 2: + msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] + i = 0 + gdbprefix = msg[i] + while gdbprefix in [ACKCHAR]: + # Ignore any '+' + i += 1 + gdbprefix = msg[i] + if DEBUG2: + print "Checking '", gdbprefix, "'" + assert gdbprefix == '$', "not a GDB command" + # Make segments. + seg_no = 0 + while msg: + seg, msg = msg[0:self.pack_size], msg[self.pack_size:] + seg_no += 1 + if not msg: # Last segment. + seg_no = 0 + segs.append (self.pack (seg, seg_no)) + # Look for next one. + end = self.in_buf.find ('#') + return segs + + def reassemble (self, sock): + msg = '' + prev_segno = 0 + segno = NXT_RECV_ERR # force initial pass through while loop + while segno != 0: + try: + s, segno = self.unpack (sock.recv ()) + if len (s) == 0: + if segno == 0 and prev_segno == 0: + return '' # No message pending + else: + segno = NXT_RECV_ERR # Keep waiting for segments + # Ignore error packets + if segno >= 0: + # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0 + if segno > 0: + assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno) + prev_segno = segno + msg += s + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + return msg + + def run (self): + """Endless run loop.""" + # Create the listening socket. + s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind (('', self.port)) + s.listen (1) + while True: + # We should open the NXT connection first, otherwise Python startup delay + # may cause GDB to misbehave + if not self.nowait: + dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') + # Open connection to the NXT brick. + self.brick = nxt.locator.find_one_brick () + self.brick.sock.debug = DEBUG + # Wait for a connection. + print "Waiting for GDB connection on port %s..." % self.port + client, addr = s.accept () + print "Client from", addr + # Work loop, wait for a message from client socket or NXT brick. + while client is not None: + data = '' + # Wait for a message from client or timeout. + rlist, wlist, xlist = select.select ([ client ], [ ], [ ], + SELECT_TIMEOUT) + for c in rlist: + assert c is client + # Data from client, read it and forward it to NXT brick. + data = client.recv (self.recv_size) + data = data.strip() + if len (data) > 0: + #if len (data) == 1 and data.find(CTRLC) >= 0: + # print "CTRL-C Received!" + # data = STATUS_QUERY + if DEBUG: + if data[0] == CTRLC: + print "[GDB->NXT] " + else: + print "[GDB->NXT] %s" % data + segments = self.segment (data) + data = '' + for seg in segments: + try: + self.brick.sock.send (seg) + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + if segments != [] and LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + else: + client.close () + client = None + if not LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Non-Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + + # Is there something from NXT brick? + if data: + if DEBUG: + print "[NXT->GDB] %s" % data + if client: + client.send (data) + data = '' + self.brick.sock.close() + print "Connection closed." + if self.nowait: + break if __name__ == '__main__': - # Read options from command line. - parser = optparse.OptionParser (description = """ - Gateway between the GNU debugger and a NXT brick. - """) - parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, - help = "server listening port (default: %default)", metavar = "PORT") - parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, - help = "verbose mode (default: %default)") - parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, - help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") - (options, args) = parser.parse_args () - if args: - parser.error ("Too many arguments") - # Run. - try: - DEBUG = options.verbose - if DEBUG: - print "Debug Mode Enabled!" - server = NXTGDBServer (options.port, options.nowait) - server.run () - except KeyboardInterrupt: - print "\n\nException caught. Bye!" - if server.brick is not None: - server.brick.sock.close() - sys.exit() + # Read options from command line. + parser = optparse.OptionParser (description = """ + Gateway between the GNU debugger and a NXT brick. + """) + parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, + help = "server listening port (default: %default)", metavar = "PORT") + parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, + help = "verbose mode (default: %default)") + parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, + help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") + (options, args) = parser.parse_args () + if args: + parser.error ("Too many arguments") + # Run. + try: + DEBUG = options.verbose + if DEBUG: + print "Debug Mode Enabled!" + server = NXTGDBServer (options.port, options.nowait) + server.run () + except KeyboardInterrupt: + print "\n\nException caught. Bye!" + if server.brick is not None: + server.brick.sock.close() + sys.exit() -- cgit v1.2.3 From 2d73bfd4a555acbb40523a02fa2dc9043e5f0444 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan (USM) Date: Wed, 3 Aug 2011 08:22:35 +0800 Subject: recheckin with tab-space cleanup --- Host/nxt-gdb-server.py | 404 ++++++++++++++++++++++++------------------------- 1 file changed, 202 insertions(+), 202 deletions(-) diff --git a/Host/nxt-gdb-server.py b/Host/nxt-gdb-server.py index ea5823a..edd3143 100755 --- a/Host/nxt-gdb-server.py +++ b/Host/nxt-gdb-server.py @@ -3,7 +3,7 @@ # Copyright (C) 2011 the NxOS developers # # Module Developed by: Nicolas Schodet -# TC Wan +# TC Wan # # See AUTHORS for a full list of the developers. # @@ -39,214 +39,214 @@ LIBUSB_RECEIVE_BLOCKING = True class NXTGDBServer: - # Socket read size. - recv_size = 1024 + # Socket read size. + recv_size = 1024 - # Maximum message size. - pack_size = 61 - - # Debug command header, no reply. - debug_command = 0x8d + # Maximum message size. + pack_size = 61 + + # Debug command header, no reply. + debug_command = 0x8d - def __init__ (self, port, nowait): - """Initialise server.""" - self.nowait = nowait - self.port = port - self.in_buf = '' - self.brick = None + def __init__ (self, port, nowait): + """Initialise server.""" + self.nowait = nowait + self.port = port + self.in_buf = '' + self.brick = None - def pack (self, data, segment_no): - """Return packed data to send to NXT.""" - # Insert command and length. - assert len (data) <= self.pack_size - return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data + def pack (self, data, segment_no): + """Return packed data to send to NXT.""" + # Insert command and length. + assert len (data) <= self.pack_size + return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data - def unpack (self, data): - """Return unpacked data from NXT.""" - # May be improved, for now, check command and announced length. - if len (data) == 0: - return '', 0 # No message, exit - if len (data) < 3: - return '', NXT_RECV_ERR - header, body = data[0:3], data[3:] - command, segment_no, length = struct.unpack ('BBB', header) - if command != self.debug_command or length != len (body): - return '', NXT_RECV_ERR - return body, segment_no + def unpack (self, data): + """Return unpacked data from NXT.""" + # May be improved, for now, check command and announced length. + if len (data) == 0: + return '', 0 # No message, exit + if len (data) < 3: + return '', NXT_RECV_ERR + header, body = data[0:3], data[3:] + command, segment_no, length = struct.unpack ('BBB', header) + if command != self.debug_command or length != len (body): + return '', NXT_RECV_ERR + return body, segment_no - def segment (self, data): - """Split messages in GDB commands and make segments with each command.""" - segs = [ ] - self.in_buf += data + def segment (self, data): + """Split messages in GDB commands and make segments with each command.""" + segs = [ ] + self.in_buf += data - # Find ACK '+' - end = self.in_buf.find (ACKCHAR) - while end == 0: - self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR - if DEBUG2: - print "stripped ACK, remain: ", self.in_buf - end = self.in_buf.find (ACKCHAR) + # Find ACK '+' + end = self.in_buf.find (ACKCHAR) + while end == 0: + self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR + if DEBUG2: + print "stripped ACK, remain: ", self.in_buf + end = self.in_buf.find (ACKCHAR) - # Find NAK '-' - end = self.in_buf.find (NAKCHAR) - if end == 0: - msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] - segs.append (self.pack (msg, 0)) - end = self.in_buf.find (NAKCHAR) + # Find NAK '-' + end = self.in_buf.find (NAKCHAR) + if end == 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (NAKCHAR) - # Find Ctrl-C (assumed to be by itself and not following a normal command) - end = self.in_buf.find (CTRLC) - if end >= 0: - msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] - assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" - segs.append (self.pack (msg, 0)) - end = self.in_buf.find (CTRLC) - - end = self.in_buf.find ('#') - # Is # found and enough place for the checkum? - while end >= 0 and end < len (self.in_buf) - 2: - msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] - i = 0 - gdbprefix = msg[i] - while gdbprefix in [ACKCHAR]: - # Ignore any '+' - i += 1 - gdbprefix = msg[i] - if DEBUG2: - print "Checking '", gdbprefix, "'" - assert gdbprefix == '$', "not a GDB command" - # Make segments. - seg_no = 0 - while msg: - seg, msg = msg[0:self.pack_size], msg[self.pack_size:] - seg_no += 1 - if not msg: # Last segment. - seg_no = 0 - segs.append (self.pack (seg, seg_no)) - # Look for next one. - end = self.in_buf.find ('#') - return segs - - def reassemble (self, sock): - msg = '' - prev_segno = 0 - segno = NXT_RECV_ERR # force initial pass through while loop - while segno != 0: - try: - s, segno = self.unpack (sock.recv ()) - if len (s) == 0: - if segno == 0 and prev_segno == 0: - return '' # No message pending - else: - segno = NXT_RECV_ERR # Keep waiting for segments - # Ignore error packets - if segno >= 0: - # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0 - if segno > 0: - assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno) - prev_segno = segno - msg += s - except usb.USBError as e: - # Some pyusb are buggy, ignore some "errors". - if e.args != ('No error', ): - raise e - return msg - - def run (self): - """Endless run loop.""" - # Create the listening socket. - s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind (('', self.port)) - s.listen (1) - while True: - # We should open the NXT connection first, otherwise Python startup delay - # may cause GDB to misbehave - if not self.nowait: - dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') - # Open connection to the NXT brick. - self.brick = nxt.locator.find_one_brick () - self.brick.sock.debug = DEBUG - # Wait for a connection. - print "Waiting for GDB connection on port %s..." % self.port - client, addr = s.accept () - print "Client from", addr - # Work loop, wait for a message from client socket or NXT brick. - while client is not None: - data = '' - # Wait for a message from client or timeout. - rlist, wlist, xlist = select.select ([ client ], [ ], [ ], - SELECT_TIMEOUT) - for c in rlist: - assert c is client - # Data from client, read it and forward it to NXT brick. - data = client.recv (self.recv_size) - data = data.strip() - if len (data) > 0: - #if len (data) == 1 and data.find(CTRLC) >= 0: - # print "CTRL-C Received!" - # data = STATUS_QUERY - if DEBUG: - if data[0] == CTRLC: - print "[GDB->NXT] " - else: - print "[GDB->NXT] %s" % data - segments = self.segment (data) - data = '' - for seg in segments: - try: - self.brick.sock.send (seg) - except usb.USBError as e: - # Some pyusb are buggy, ignore some "errors". - if e.args != ('No error', ): - raise e - if segments != [] and LIBUSB_RECEIVE_BLOCKING: - if DEBUG2: - print "Accessing Blocking sock.recv()" - data = self.reassemble (self.brick.sock) - else: - client.close () - client = None - if not LIBUSB_RECEIVE_BLOCKING: - if DEBUG2: - print "Accessing Non-Blocking sock.recv()" - data = self.reassemble (self.brick.sock) - - # Is there something from NXT brick? - if data: - if DEBUG: - print "[NXT->GDB] %s" % data - if client: - client.send (data) - data = '' - self.brick.sock.close() - print "Connection closed." - if self.nowait: - break + # Find Ctrl-C (assumed to be by itself and not following a normal command) + end = self.in_buf.find (CTRLC) + if end >= 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (CTRLC) + + end = self.in_buf.find ('#') + # Is # found and enough place for the checkum? + while end >= 0 and end < len (self.in_buf) - 2: + msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] + i = 0 + gdbprefix = msg[i] + while gdbprefix in [ACKCHAR]: + # Ignore any '+' + i += 1 + gdbprefix = msg[i] + if DEBUG2: + print "Checking '", gdbprefix, "'" + assert gdbprefix == '$', "not a GDB command" + # Make segments. + seg_no = 0 + while msg: + seg, msg = msg[0:self.pack_size], msg[self.pack_size:] + seg_no += 1 + if not msg: # Last segment. + seg_no = 0 + segs.append (self.pack (seg, seg_no)) + # Look for next one. + end = self.in_buf.find ('#') + return segs + + def reassemble (self, sock): + msg = '' + prev_segno = 0 + segno = NXT_RECV_ERR # force initial pass through while loop + while segno != 0: + try: + s, segno = self.unpack (sock.recv ()) + if len (s) == 0: + if segno == 0 and prev_segno == 0: + return '' # No message pending + else: + segno = NXT_RECV_ERR # Keep waiting for segments + # Ignore error packets + if segno >= 0: + # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0 + if segno > 0: + assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno) + prev_segno = segno + msg += s + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + return msg + + def run (self): + """Endless run loop.""" + # Create the listening socket. + s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind (('', self.port)) + s.listen (1) + while True: + # We should open the NXT connection first, otherwise Python startup delay + # may cause GDB to misbehave + if not self.nowait: + dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') + # Open connection to the NXT brick. + self.brick = nxt.locator.find_one_brick () + self.brick.sock.debug = DEBUG + # Wait for a connection. + print "Waiting for GDB connection on port %s..." % self.port + client, addr = s.accept () + print "Client from", addr + # Work loop, wait for a message from client socket or NXT brick. + while client is not None: + data = '' + # Wait for a message from client or timeout. + rlist, wlist, xlist = select.select ([ client ], [ ], [ ], + SELECT_TIMEOUT) + for c in rlist: + assert c is client + # Data from client, read it and forward it to NXT brick. + data = client.recv (self.recv_size) + data = data.strip() + if len (data) > 0: + #if len (data) == 1 and data.find(CTRLC) >= 0: + # print "CTRL-C Received!" + # data = STATUS_QUERY + if DEBUG: + if data[0] == CTRLC: + print "[GDB->NXT] " + else: + print "[GDB->NXT] %s" % data + segments = self.segment (data) + data = '' + for seg in segments: + try: + self.brick.sock.send (seg) + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + if segments != [] and LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + else: + client.close () + client = None + if not LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Non-Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + + # Is there something from NXT brick? + if data: + if DEBUG: + print "[NXT->GDB] %s" % data + if client: + client.send (data) + data = '' + self.brick.sock.close() + print "Connection closed." + if self.nowait: + break if __name__ == '__main__': - # Read options from command line. - parser = optparse.OptionParser (description = """ - Gateway between the GNU debugger and a NXT brick. - """) - parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, - help = "server listening port (default: %default)", metavar = "PORT") - parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, - help = "verbose mode (default: %default)") - parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, - help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") - (options, args) = parser.parse_args () - if args: - parser.error ("Too many arguments") - # Run. - try: - DEBUG = options.verbose - if DEBUG: - print "Debug Mode Enabled!" - server = NXTGDBServer (options.port, options.nowait) - server.run () - except KeyboardInterrupt: - print "\n\nException caught. Bye!" - if server.brick is not None: - server.brick.sock.close() - sys.exit() + # Read options from command line. + parser = optparse.OptionParser (description = """ + Gateway between the GNU debugger and a NXT brick. + """) + parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, + help = "server listening port (default: %default)", metavar = "PORT") + parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, + help = "verbose mode (default: %default)") + parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, + help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") + (options, args) = parser.parse_args () + if args: + parser.error ("Too many arguments") + # Run. + try: + DEBUG = options.verbose + if DEBUG: + print "Debug Mode Enabled!" + server = NXTGDBServer (options.port, options.nowait) + server.run () + except KeyboardInterrupt: + print "\n\nException caught. Bye!" + if server.brick is not None: + server.brick.sock.close() + sys.exit() -- cgit v1.2.3