diff options
-rw-r--r-- | rda/samples/ChangeLog | 20 | ||||
-rw-r--r-- | rda/samples/demo-target.c | 56 | ||||
-rw-r--r-- | rda/samples/demo-target.h | 13 | ||||
-rw-r--r-- | rda/samples/demo-tfind.c | 205 |
4 files changed, 285 insertions, 9 deletions
diff --git a/rda/samples/ChangeLog b/rda/samples/ChangeLog index 60d56cfc12d..38e1cdf6873 100644 --- a/rda/samples/ChangeLog +++ b/rda/samples/ChangeLog @@ -1,3 +1,23 @@ +2008-06-12 Michael Snyder <msnyder@specifix.com> + + * demo-target.c: Implement hooks for software breakpoints. + (demo_remove_swbp): New function. + (demo_set_swbp): New function. + (demo_target): Set up method vectors for set/remove breakpoints. + * demo-target.h: Export interface for software breakpoints. + * demo-tfind.c: Implement software breakpoints. + (tfind_insert_breakpoint): New function. + (tfind_unlink_breakpoint): New function. + (tfind_set_swbp): New function. + (tfind_remove_swbp): New function. + + * demo-target.c: Implement hooks for continue_thread. + (demo_continue_thread): call tfind_continue_thread. + * demo-target.h: Export interface for tfind_continue_thread. + * demo-tfind.c: Implement continue_thread with software breakpoints. + (tfind_continue_thread): New function. Find a new frame + based on software breakpoints. + 2008-06-11 Michael Snyder <msnyder@specifix.com> * demo-tfind.c (tfind_singlestep_program): diff --git a/rda/samples/demo-target.c b/rda/samples/demo-target.c index 7f56f4f9dd7..608f7475f34 100644 --- a/rda/samples/demo-target.c +++ b/rda/samples/demo-target.c @@ -44,6 +44,9 @@ #include "demo-target.h" #include "gdbsched.h" +struct gdbserv; +struct gdbserv_reg; + /* This is a sample gdbserv target that demonstrates use of the RDA library routines. It acts to gdb like a strange generic remote target. */ @@ -82,8 +85,17 @@ static void demo_sigkill_program (struct gdbserv* serv); static void demo_continue_thread (struct gdbserv *serv, struct gdbserv_thread *thread, const struct gdbserv_reg *sigval); - /* remove_breakpoint */ - /* set_breakpoint */ + +static enum gdbserv_target_rc demo_remove_swbp (struct gdbserv * serv, + enum gdbserv_target_bp type, + struct gdbserv_reg *addr, + struct gdbserv_reg *len); + +static enum gdbserv_target_rc demo_set_swbp (struct gdbserv * serv, + enum gdbserv_target_bp type, + struct gdbserv_reg *addr, + struct gdbserv_reg *len); + /* process_target */ static void demo_detach (struct gdbserv* serv, struct gdbserv_target* target); @@ -192,8 +204,8 @@ demo_target (struct gdbserv *serv, void *context) target->cyclestep_program = demo_cyclestep_program; target->sigkill_program = demo_sigkill_program; target->continue_thread = demo_continue_thread; - target->remove_breakpoint = NULL; - target->set_breakpoint = NULL; + target->remove_breakpoint = demo_remove_swbp; + target->set_breakpoint = demo_set_swbp; target->process_target_packet = NULL; target->detach = demo_detach; @@ -332,11 +344,11 @@ demo_restart_program (struct gdbserv* serv) sched_break (serv, 1); } - void demo_singlestep_program (struct gdbserv* serv) { - sched_break (serv, tfind_singlestep_program (serv)); + sched_break (serv, + tfind_singlestep_program (serv)); } void @@ -356,9 +368,8 @@ demo_continue_thread (struct gdbserv *serv, struct gdbserv_thread *thread, const struct gdbserv_reg *sigval) { - fprintf (stderr, "Resumed fictional target program - send break from gdb or wait a while.\n"); - /* Enqueue a break response */ - sched_break (serv, 10); + sched_break (serv, + tfind_continue_thread (serv, thread, sigval)); } @@ -465,3 +476,30 @@ void demo_flush_i_cache (struct gdbserv* serv) { } + +/* + * demo_remove_swbp -- remove software breakpoint + */ + +static enum gdbserv_target_rc +demo_remove_swbp (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + return tfind_remove_swbp (serv, bptype, addr, len); +} + +/* + * demo_set_swbp -- remove software breakpoint + */ + +static enum gdbserv_target_rc +demo_set_swbp (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + return tfind_set_swbp (serv, bptype, addr, len); +} + diff --git a/rda/samples/demo-target.h b/rda/samples/demo-target.h index a99b8ec7066..679d7614f88 100644 --- a/rda/samples/demo-target.h +++ b/rda/samples/demo-target.h @@ -49,4 +49,17 @@ extern int (*demo_get_mem_hook) (unsigned long); extern void demo_tfind_open (char *); extern int tfind_singlestep_program (struct gdbserv *); +extern int tfind_continue_thread (struct gdbserv *, + struct gdbserv_thread *, + const struct gdbserv_reg *); + +extern enum gdbserv_target_rc tfind_remove_swbp (struct gdbserv *, + enum gdbserv_target_bp, + struct gdbserv_reg *, + struct gdbserv_reg *); +extern enum gdbserv_target_rc tfind_set_swbp (struct gdbserv *, + enum gdbserv_target_bp, + struct gdbserv_reg *, + struct gdbserv_reg *); + #endif diff --git a/rda/samples/demo-tfind.c b/rda/samples/demo-tfind.c index c4ca7c1f785..309d37c2c1f 100644 --- a/rda/samples/demo-tfind.c +++ b/rda/samples/demo-tfind.c @@ -388,6 +388,7 @@ tfind_singlestep_program (struct gdbserv *serv) { if (cur_frame == -1) { + fprintf (stderr, "TFIND: fake singlestep (not at trace frame).\n"); return 2; /*sched_break (serv, 2);*/ } else if (demo_reverse_flag == 0) @@ -395,6 +396,7 @@ tfind_singlestep_program (struct gdbserv *serv) if (cur_frame >= last_cached_frame - 1) { /* Stepped past the end of the tfind buffer. */ + fprintf (stderr, "TFIND: stepped past end of trace buffer.\n"); demo_get_regs_hook = NULL; demo_get_mem_hook = NULL; cur_frame = -1; @@ -403,6 +405,7 @@ tfind_singlestep_program (struct gdbserv *serv) else { /* Increment cur_frame and schedule an immediate break. */ + fprintf (stderr, "TFIND: stepi.\n"); cur_frame++; return 0; /*sched_break (serv, 0);*/ } @@ -412,6 +415,7 @@ tfind_singlestep_program (struct gdbserv *serv) if (cur_frame == 0) { /* Stepped past the beginning of the tfind buffer. */ + fprintf (stderr, "TFIND: backstepped past start of trace buffer.\n"); demo_get_regs_hook = NULL; demo_get_mem_hook = NULL; cur_frame = -1; @@ -420,8 +424,209 @@ tfind_singlestep_program (struct gdbserv *serv) else { /* Decrement cur_frame and schedule an immediate break. */ + fprintf (stderr, "TFIND: reverse-stepi.\n"); cur_frame--; return 0; /*sched_break (serv, 0);*/ } } } + +typedef struct tfind_breakpoint_type { + unsigned long addr; + unsigned long len; + struct tfind_breakpoint_type *next; +} tfind_breakpoint; + +static tfind_breakpoint *tfind_bplist[5]; + +int +tfind_continue_thread (struct gdbserv *serv, + struct gdbserv_thread *thread, + const struct gdbserv_reg *sigval) +{ + int index_frame; + tfind_breakpoint *index_bp; + + if (cur_frame == -1) + { + fprintf (stderr, + "TFIND: continue - send break from gdb or wait 10 seconds.\n"); + /* Enqueue a break response after 10 seconds. */ + return 10; + } + else if (demo_reverse_flag == 0) + { + /* Search forward for a breakpoint/checkpoint match. */ + for (index_frame = cur_frame + 1; + index_frame < last_cached_frame; + index_frame++) + { + for (index_bp = tfind_bplist[GDBSERV_TARGET_BP_SOFTWARE]; + index_bp != NULL; + index_bp = index_bp->next) + { + if (index_bp->addr == frame[index_frame].pc) + { + /* Hit breakpoint at index_frame. */ + fprintf (stderr, "TFIND: continue / break\n"); + cur_frame = index_frame; + /* Stop immediately. */ + return 0; + } + } + } + /* No match. Run to end (set cur_frame to last valid one). */ + fprintf (stderr, "TFIND: continue / end\n"); + cur_frame = last_cached_frame - 1; + return 0; + } + else + { + /* Search backward for a breakpoint/checkpoint match. */ + for (index_frame = cur_frame - 1; + index_frame >= 0; + index_frame--) + { + for (index_bp = tfind_bplist[GDBSERV_TARGET_BP_SOFTWARE]; + index_bp != NULL; + index_bp = index_bp->next) + { + if (index_bp->addr == frame[index_frame].pc) + { + /* Hit breakpoint at index_frame. */ + fprintf (stderr, "TFIND: reverse-continue / break\n"); + cur_frame = index_frame; + /* Stop immediately. */ + return 0; + } + } + } + /* No match. Stop at beginning (set cur_frame to 0). */ + fprintf (stderr, "TFIND: reverse-continue / start\n"); + cur_frame = 0; + return 0; + } +} + +/* + * tfind_insert_breakpoint + * + * returns: 0 for fail, 1 for success + */ + +static int +tfind_insert_breakpoint (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + tfind_breakpoint *this_bp; + + switch (bptype) { + case GDBSERV_TARGET_BP_ACCESS: + case GDBSERV_TARGET_BP_HARDWARE: + case GDBSERV_TARGET_BP_READ: + default: + /* Can't do those. */ + return 0; + break; + case GDBSERV_TARGET_BP_SOFTWARE: + case GDBSERV_TARGET_BP_WRITE: + this_bp = malloc (sizeof (tfind_breakpoint)); + gdbserv_reg_to_ulong (serv, addr, &this_bp->addr); + gdbserv_reg_to_ulong (serv, len, &this_bp->len); + this_bp->next = tfind_bplist[bptype]; + tfind_bplist[bptype] = this_bp; + return 1; + } +} + +/* + * tfind_unlink_breakpoint + * + * returns: 0 for fail, 1 for success + */ + +static int +tfind_unlink_breakpoint (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + tfind_breakpoint *this_bp, *tmp; + unsigned long laddr; + unsigned long llen; + switch (bptype) { + case GDBSERV_TARGET_BP_ACCESS: + case GDBSERV_TARGET_BP_HARDWARE: + case GDBSERV_TARGET_BP_READ: + default: + /* Can't do those. */ + return 0; + break; + case GDBSERV_TARGET_BP_SOFTWARE: + case GDBSERV_TARGET_BP_WRITE: + /* Special case - list is empty. */ + if (tfind_bplist[bptype] == NULL) + return 0; + + gdbserv_reg_to_ulong (serv, addr, &laddr); + gdbserv_reg_to_ulong (serv, len, &llen); + + /* Start from list head. */ + this_bp = tfind_bplist[bptype]; + /* Special case -- remove head of list. */ + if (this_bp->addr == laddr && + this_bp->len == llen) + { + tfind_bplist[bptype] = this_bp->next; + return 1; + } + + /* Scan list. */ + for (; this_bp && this_bp->next; this_bp = this_bp->next) + if (this_bp->next->addr == laddr && + this_bp->next->len == llen) + { + /* Remove from middle of list. */ + tmp = this_bp->next->next; + free (this_bp->next); + this_bp->next = tmp; + return 1; + } + + /* Not found. */ + return 0; + } +} + + +extern enum gdbserv_target_rc +tfind_remove_swbp (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + fprintf (stderr, "TFIND: Remove sw breakpoint type %d\n", bptype); + if (tfind_unlink_breakpoint (serv, bptype, addr, len) == 0) + { + fprintf (stderr, " FAILED!\n"); + return GDBSERV_TARGET_RC_ERROR; + } + return GDBSERV_TARGET_RC_OK; +} + +extern enum gdbserv_target_rc +tfind_set_swbp (struct gdbserv *serv, + enum gdbserv_target_bp bptype, + struct gdbserv_reg *addr, + struct gdbserv_reg *len) +{ + fprintf (stderr, "TFIND: Set sw breakpoint type %d\n", bptype); + if (tfind_insert_breakpoint (serv, bptype, addr, len) == 0) + { + fprintf (stderr, " FAILED!\n"); + return GDBSERV_TARGET_RC_ERROR; + } + return GDBSERV_TARGET_RC_OK; +} |