ARM thumb-2 software breakpoints support

I have been trying to figure out how to give support for software breakpoints thumb-2 for arm cortex-8.

The hardware I am using for tests is TI OMAP3 beaglebone.

I am not the best person to do that but anyway while no other volunteer decide to help I will keep trying.

What do I know about the problem.

  1. openocd knows that the board is running in thumb state.

Debug: 1481 22479 armv4_5.c:395 arm_set_cpsr(): set CPSR 0x400001b3: Supervisor mode, Thumb state

  1. While gdb find thumb (16 bits) instructions, the breakpoints succeed.

  2. gdb find a thumb-2 instruction and requires a 32 bits software breakpoint.

Debug: 1629 24548 gdb_server.c:2050 gdb_input_inner(): received packet: ‘Z0,80008100,3’

Debug: 1630 24548 gdb_server.c:1394 gdb_breakpoint_watchpoint_packet(): -

Debug: 1631 24548 gdb_server.c:1413 gdb_breakpoint_watchpoint_packet(): =======> gdb watch/breakpoint type(0)

Debug: 1632 24548 cortex_a.c:1986 cortex_a8_read_memory(): Reading memory at address 0x80008100; size 3; count 1

Debug: 1633 24548 cortex_a.c:1939 cortex_a8_read_phys_memory(): Reading memory at real address 0x80008100; size 3; count 1

Error: 1634 24548 cortex_a.c:1408 cortex_a8_set_breakpoint(): Error @ cortex_a8 read_memory:-601

Error: 1635 24548 breakpoints.c:96 breakpoint_add_internal(): can’t add breakpoint: unknown reason

Debug: 1636 24548 gdb_server.c:1163 gdb_error(): Reporting -601 to GDB as generic error

And here is the key point: gdb is trying to install a break point type 3 (32-bit Thumb-2 mode breakpoint) that at this time is not supported by openocd.

My first simple idea was consider type 3 (thumb-2 breakpoint 32 bits) breakpoint as the same like type 4 (ARM breakpoint 32 bits) so that openocd can handle memory in the same way but unfortunately it doesn’t work and I don’t know why. Any suggestion or explanation is welcome.

This is the patch I submitted this week at openocd mailing list to fix the single step in thumb2 for cortex-a8.

diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c

index 3b516d0…51ed842 100644

— a/src/target/breakpoints.c

+++ b/src/target/breakpoints.c

@@ -73,7 +73,22 @@ int breakpoint_add_internal(struct target *target,

(*breakpoint_p) = malloc(sizeof(struct breakpoint));

(*breakpoint_p)->address = address;

(*breakpoint_p)->asid = 0;

  • (*breakpoint_p)->length = length;
  • switch (length) {

  • case 2:

  • (*breakpoint_p)->kind = BPK_THUMB_16;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 3:

  • (*breakpoint_p)->kind = BPK_THUMB_32;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 4:

  • (*breakpoint_p)->kind = BPK_ARM_32;

  • (*breakpoint_p)->length = 4;

  • break;

  • }

(*breakpoint_p)->type = type;

(*breakpoint_p)->set = 0;

(*breakpoint_p)->orig_instr = malloc(length);

@@ -137,7 +152,22 @@ int context_breakpoint_add_internal(struct target *target,

(*breakpoint_p) = malloc(sizeof(struct breakpoint));

(*breakpoint_p)->address = 0;

(*breakpoint_p)->asid = asid;

  • (*breakpoint_p)->length = length;
  • switch (length) {

  • case 2:

  • (*breakpoint_p)->kind = BPK_THUMB_16;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 3:

  • (*breakpoint_p)->kind = BPK_THUMB_32;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 4:

  • (*breakpoint_p)->kind = BPK_ARM_32;

  • (*breakpoint_p)->length = 4;

  • break;

  • }

(*breakpoint_p)->type = type;

(*breakpoint_p)->set = 0;

(*breakpoint_p)->orig_instr = malloc(length);

@@ -193,7 +223,22 @@ int hybrid_breakpoint_add_internal(struct target *target,

(*breakpoint_p) = malloc(sizeof(struct breakpoint));

(*breakpoint_p)->address = address;

(*breakpoint_p)->asid = asid;

  • (*breakpoint_p)->length = length;
  • switch (length) {

  • case 2:

  • (*breakpoint_p)->kind = BPK_THUMB_16;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 3:

  • (*breakpoint_p)->kind = BPK_THUMB_32;

  • (*breakpoint_p)->length = 2;

  • break;

  • case 4:

  • (*breakpoint_p)->kind = BPK_ARM_32;

  • (*breakpoint_p)->length = 4;

  • break;

  • }

(*breakpoint_p)->type = type;

(*breakpoint_p)->set = 0;

(*breakpoint_p)->orig_instr = malloc(length);

diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h

index a019e96…0cfcd7b 100644

— a/src/target/breakpoints.h

+++ b/src/target/breakpoints.h

@@ -23,6 +23,18 @@

struct target;

+/*

    • These breakpoint kinds are defined for the
    • ‘Z0’ and ‘Z1’ packets in gdb remote serial protocol.
  • */

+enum breakpoint_kind {

  • BPK_THUMB_16 = 2,

  • BPK_THUMB_32 = 3,

  • BPK_ARM_32 = 4

+};

enum breakpoint_type {

BKPT_HARD,

BKPT_SOFT,

@@ -37,6 +49,7 @@ struct breakpoint {

uint32_t asid;

int length;

enum breakpoint_type type;

  • enum breakpoint_kind kind;

int set;

uint8_t *orig_instr;

struct breakpoint *next;

diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c

index e1c4c9c…29c568d 100644

— a/src/target/cortex_a.c

+++ b/src/target/cortex_a.c

@@ -1393,10 +1393,19 @@ static int cortex_a8_set_breakpoint(struct target *target,

brp_list[brp_i].value);

} else if (breakpoint->type == BKPT_SOFT) {

uint8_t code[4];

  • if (breakpoint->length == 2)

  • buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));

  • else

  • buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11));

  • switch (breakpoint->kind) {

  • case BPK_THUMB_16:

  • case BPK_THUMB_32:

  • buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));

  • break;

  • case BPK_ARM_32:

  • buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11));

  • break;

  • }

retval = target->type->read_memory(target,

breakpoint->address & 0xFFFFFFFE,

breakpoint->length, 1,