From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11527 invoked by alias); 29 Jul 2013 16:45:39 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 11462 invoked by uid 89); 29 Jul 2013 16:45:39 -0000 X-Spam-SWARE-Status: No, score=-4.7 required=5.0 tests=AWL,BAYES_50,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,RDNS_NONE,SPF_HELO_PASS,SPF_PASS autolearn=no version=3.3.1 Received: from Unknown (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Mon, 29 Jul 2013 16:45:35 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r6TGjRxV030411 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 29 Jul 2013 12:45:28 -0400 Received: from barimba.redhat.com (ovpn-113-128.phx2.redhat.com [10.3.113.128]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r6TGjPbF023425; Mon, 29 Jul 2013 12:45:26 -0400 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [PATCH 2/8] add target method delegation Date: Mon, 29 Jul 2013 16:45:00 -0000 Message-Id: <1375116324-32092-3-git-send-email-tromey@redhat.com> In-Reply-To: <1375116324-32092-1-git-send-email-tromey@redhat.com> References: <1375116324-32092-1-git-send-email-tromey@redhat.com> X-SW-Source: 2013-07/txt/msg00721.txt.bz2 This patch replaces some code in the record targets with target method delegation. Right now there are two latent problems in the record target. First, record-full.c stores pointers to many target methods when the record target is pushed. Then it later delegates some calls via these. This is wrong because it violates the target stack contract. In particular it is ok to unpush a target at any stratum, but record-full does not keep track of this, so it could potentially call into an unpushed target. Second, RECORD_IS_USED and some other spots look at current_target.to_stratum to determine whether a record target is in use. This is bad because arch_stratum is greater than record_stratum. To fix the first problem, this patch introduces a handful of target_delegate_* functions, which forward calls further down the target stack. To fix the second problem, this patch adds find_target_at to determine whether a target appears at a given stratum. This may seem like overkill somehow, but I have a subsequent patch series (see archer.git tromey/multi-target) that uses it more heavily. * record-full.c (record_full_beneath_to_resume_ops) (record_full_beneath_to_resume, record_full_beneath_to_wait_ops) (record_full_beneath_to_wait) (record_full_beneath_to_store_registers_ops) (record_full_beneath_to_store_registers) (record_full_beneath_to_xfer_partial_ops) (record_full_beneath_to_xfer_partial) (record_full_beneath_to_insert_breakpoint) (record_full_beneath_to_remove_breakpoint) (record_full_beneath_to_stopped_by_watchpoint) (record_full_beneath_to_stopped_data_address) (record_full_beneath_to_async, tmp_to_resume_ops, tmp_to_resume) (tmp_to_wait_ops, tmp_to_wait, tmp_to_store_registers_ops) (tmp_to_store_registers, tmp_to_xfer_partial_ops) (tmp_to_xfer_partial, tmp_to_insert_breakpoint) (tmp_to_remove_breakpoint, tmp_to_stopped_by_watchpoint) (tmp_to_stopped_data_address, tmp_to_async): Remove. (record_full_open_1, record_full_open): Update. Use RECORD_IS_USED. (record_full_resume, record_full_wait_1) (record_full_stopped_by_watchpoint, record_full_stopped_data_address) (record_full_store_registers, record_full_xfer_partial) (record_full_insert_breakpoint, record_full_remove_breakpoint) (record_full_async, record_full_can_async_p, record_full_is_async_p) (record_full_core_xfer_partial): Use target delegation. * record.c (find_record_target): Use find_target_at. * record.h (RECORD_IS_USED): Use find_target_at. * target.c (update_current_target): Use target_delegate_xfer_partial. (target_delegate_xfer_partial): Now public. Renamed from... (current_xfer_partial): ...this. Remove. (target_delegate_async, target_delegate_is_async_p) (target_delegate_can_async_p, target_delegate_insert_breakpoint) (target_delegate_remove_breakpoint, target_delegate_wait) (target_delegate_resume, find_target_at) (target_delegate_store_registers) (target_delegate_stopped_by_watchpoint) (target_delegate_stopped_data_address): New functions. * target.h (target_delegate_async, target_delegate_is_async_p) (target_delegate_can_async_p, target_delegate_insert_breakpoint) (target_delegate_remove_breakpoint, target_delegate_wait) (target_delegate_resume, find_target_at) (target_delegate_store_registers) (target_delegate_stopped_by_watchpoint) (target_delegate_stopped_data_address) (target_delegate_xfer_partial): Declare. --- gdb/record-full.c | 204 ++++++----------------------------------------------- gdb/record.c | 8 +-- gdb/record.h | 2 +- gdb/target.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++---- gdb/target.h | 68 ++++++++++++++++++ 5 files changed, 285 insertions(+), 203 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 1c4e68b..c3c9c3d 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -215,40 +215,6 @@ static struct cmd_list_element *show_record_full_cmdlist; /* Command list for "record full". */ static struct cmd_list_element *record_full_cmdlist; -/* The beneath function pointers. */ -static struct target_ops *record_full_beneath_to_resume_ops; -static void (*record_full_beneath_to_resume) (struct target_ops *, ptid_t, int, - enum gdb_signal); -static struct target_ops *record_full_beneath_to_wait_ops; -static ptid_t (*record_full_beneath_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, - int); -static struct target_ops *record_full_beneath_to_store_registers_ops; -static void (*record_full_beneath_to_store_registers) (struct target_ops *, - struct regcache *, - int regno); -static struct target_ops *record_full_beneath_to_xfer_partial_ops; -static LONGEST - (*record_full_beneath_to_xfer_partial) (struct target_ops *ops, - enum target_object object, - const char *annex, - gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - LONGEST len); -static int - (*record_full_beneath_to_insert_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int - (*record_full_beneath_to_remove_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*record_full_beneath_to_stopped_by_watchpoint) (void); -static int (*record_full_beneath_to_stopped_data_address) (struct target_ops *, - CORE_ADDR *); -static void - (*record_full_beneath_to_async) (void (*) (enum inferior_event_type, void *), - void *); - static void record_full_goto_insn (struct record_full_entry *entry, enum exec_direction_kind dir); static void record_full_save (const char *recfilename); @@ -795,34 +761,6 @@ record_full_exec_insn (struct regcache *regcache, } } -static struct target_ops *tmp_to_resume_ops; -static void (*tmp_to_resume) (struct target_ops *, ptid_t, int, - enum gdb_signal); -static struct target_ops *tmp_to_wait_ops; -static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t, - struct target_waitstatus *, - int); -static struct target_ops *tmp_to_store_registers_ops; -static void (*tmp_to_store_registers) (struct target_ops *, - struct regcache *, - int regno); -static struct target_ops *tmp_to_xfer_partial_ops; -static LONGEST (*tmp_to_xfer_partial) (struct target_ops *ops, - enum target_object object, - const char *annex, - gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, - LONGEST len); -static int (*tmp_to_insert_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*tmp_to_remove_breakpoint) (struct gdbarch *, - struct bp_target_info *); -static int (*tmp_to_stopped_by_watchpoint) (void); -static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); -static int (*tmp_to_stopped_data_address) (struct target_ops *, CORE_ADDR *); -static void (*tmp_to_async) (void (*) (enum inferior_event_type, void *), void *); - static void record_full_restore (void); /* Asynchronous signal handle registered as event loop source for when @@ -885,26 +823,6 @@ record_full_open_1 (char *name, int from_tty) error (_("Process record: the current architecture doesn't support " "record function.")); - if (!tmp_to_resume) - error (_("Could not find 'to_resume' method on the target stack.")); - if (!tmp_to_wait) - error (_("Could not find 'to_wait' method on the target stack.")); - if (!tmp_to_store_registers) - error (_("Could not find 'to_store_registers' " - "method on the target stack.")); - if (!tmp_to_insert_breakpoint) - error (_("Could not find 'to_insert_breakpoint' " - "method on the target stack.")); - if (!tmp_to_remove_breakpoint) - error (_("Could not find 'to_remove_breakpoint' " - "method on the target stack.")); - if (!tmp_to_stopped_by_watchpoint) - error (_("Could not find 'to_stopped_by_watchpoint' " - "method on the target stack.")); - if (!tmp_to_stopped_data_address) - error (_("Could not find 'to_stopped_data_address' " - "method on the target stack.")); - push_target (&record_full_ops); } @@ -921,83 +839,16 @@ record_full_open (char *name, int from_tty) fprintf_unfiltered (gdb_stdlog, "Process record: record_full_open\n"); /* Check if record target is already running. */ - if (current_target.to_stratum == record_stratum) + if (RECORD_IS_USED) error (_("Process record target already running. Use \"record stop\" to " "stop record target first.")); - /* Reset the tmp beneath pointers. */ - tmp_to_resume_ops = NULL; - tmp_to_resume = NULL; - tmp_to_wait_ops = NULL; - tmp_to_wait = NULL; - tmp_to_store_registers_ops = NULL; - tmp_to_store_registers = NULL; - tmp_to_xfer_partial_ops = NULL; - tmp_to_xfer_partial = NULL; - tmp_to_insert_breakpoint = NULL; - tmp_to_remove_breakpoint = NULL; - tmp_to_stopped_by_watchpoint = NULL; - tmp_to_stopped_data_address = NULL; - tmp_to_async = NULL; - - /* Set the beneath function pointers. */ - for (t = current_target.beneath; t != NULL; t = t->beneath) - { - if (!tmp_to_resume) - { - tmp_to_resume = t->to_resume; - tmp_to_resume_ops = t; - } - if (!tmp_to_wait) - { - tmp_to_wait = t->to_wait; - tmp_to_wait_ops = t; - } - if (!tmp_to_store_registers) - { - tmp_to_store_registers = t->to_store_registers; - tmp_to_store_registers_ops = t; - } - if (!tmp_to_xfer_partial) - { - tmp_to_xfer_partial = t->to_xfer_partial; - tmp_to_xfer_partial_ops = t; - } - if (!tmp_to_insert_breakpoint) - tmp_to_insert_breakpoint = t->to_insert_breakpoint; - if (!tmp_to_remove_breakpoint) - tmp_to_remove_breakpoint = t->to_remove_breakpoint; - if (!tmp_to_stopped_by_watchpoint) - tmp_to_stopped_by_watchpoint = t->to_stopped_by_watchpoint; - if (!tmp_to_stopped_data_address) - tmp_to_stopped_data_address = t->to_stopped_data_address; - if (!tmp_to_async) - tmp_to_async = t->to_async; - } - if (!tmp_to_xfer_partial) - error (_("Could not find 'to_xfer_partial' method on the target stack.")); - /* Reset */ record_full_insn_num = 0; record_full_insn_count = 0; record_full_list = &record_full_first; record_full_list->next = NULL; - /* Set the tmp beneath pointers to beneath pointers. */ - record_full_beneath_to_resume_ops = tmp_to_resume_ops; - record_full_beneath_to_resume = tmp_to_resume; - record_full_beneath_to_wait_ops = tmp_to_wait_ops; - record_full_beneath_to_wait = tmp_to_wait; - record_full_beneath_to_store_registers_ops = tmp_to_store_registers_ops; - record_full_beneath_to_store_registers = tmp_to_store_registers; - record_full_beneath_to_xfer_partial_ops = tmp_to_xfer_partial_ops; - record_full_beneath_to_xfer_partial = tmp_to_xfer_partial; - record_full_beneath_to_insert_breakpoint = tmp_to_insert_breakpoint; - record_full_beneath_to_remove_breakpoint = tmp_to_remove_breakpoint; - record_full_beneath_to_stopped_by_watchpoint = tmp_to_stopped_by_watchpoint; - record_full_beneath_to_stopped_data_address = tmp_to_stopped_data_address; - record_full_beneath_to_async = tmp_to_async; - if (core_bfd) record_full_core_open_1 (name, from_tty); else @@ -1121,8 +972,7 @@ record_full_resume (struct target_ops *ops, ptid_t ptid, int step, /* Make sure the target beneath reports all signals. */ target_pass_signals (0, NULL); - record_full_beneath_to_resume (record_full_beneath_to_resume_ops, - ptid, step, signal); + target_delegate_resume (ops, ptid, step, signal); } /* We are about to start executing the inferior (or simulate it), @@ -1212,8 +1062,7 @@ record_full_wait_1 (struct target_ops *ops, if (record_full_resume_step) { /* This is a single step. */ - return record_full_beneath_to_wait (record_full_beneath_to_wait_ops, - ptid, status, options); + return target_delegate_wait (ops, ptid, status, options); } else { @@ -1224,8 +1073,7 @@ record_full_wait_1 (struct target_ops *ops, while (1) { - ret = record_full_beneath_to_wait - (record_full_beneath_to_wait_ops, ptid, status, options); + ret = target_delegate_wait (ops, ptid, status, options); if (status->kind == TARGET_WAITKIND_IGNORE) { if (record_debug) @@ -1309,9 +1157,7 @@ record_full_wait_1 (struct target_ops *ops, "Process record: record_full_wait " "issuing one more step in the " "target beneath\n"); - record_full_beneath_to_resume - (record_full_beneath_to_resume_ops, ptid, step, - GDB_SIGNAL_0); + target_delegate_resume (ops, ptid, step, GDB_SIGNAL_0); continue; } } @@ -1515,7 +1361,7 @@ record_full_stopped_by_watchpoint (void) if (RECORD_FULL_IS_REPLAY) return record_full_hw_watchpoint; else - return record_full_beneath_to_stopped_by_watchpoint (); + return target_delegate_stopped_by_watchpoint (find_target_at (record_stratum)); } static int @@ -1524,7 +1370,7 @@ record_full_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) if (RECORD_FULL_IS_REPLAY) return 0; else - return record_full_beneath_to_stopped_data_address (ops, addr_p); + return target_delegate_stopped_data_address (ops, addr_p); } /* Record registers change (by user or by GDB) to list as an instruction. */ @@ -1627,8 +1473,7 @@ record_full_store_registers (struct target_ops *ops, record_full_registers_change (regcache, regno); } - record_full_beneath_to_store_registers - (record_full_beneath_to_store_registers_ops, regcache, regno); + target_delegate_store_registers (ops, regcache, regno); } /* "to_xfer_partial" method. Behavior is conditional on @@ -1693,9 +1538,8 @@ record_full_xfer_partial (struct target_ops *ops, enum target_object object, record_full_insn_num++; } - return record_full_beneath_to_xfer_partial - (record_full_beneath_to_xfer_partial_ops, object, annex, - readbuf, writebuf, offset, len); + return target_delegate_xfer_partial (ops, object, annex, + readbuf, writebuf, offset, len); } /* This structure represents a breakpoint inserted while the record @@ -1775,7 +1619,8 @@ record_full_insert_breakpoint (struct gdbarch *gdbarch, int ret; old_cleanups = record_full_gdb_operation_disable_set (); - ret = record_full_beneath_to_insert_breakpoint (gdbarch, bp_tgt); + ret = target_delegate_insert_breakpoint (find_target_at (record_stratum), + gdbarch, bp_tgt); do_cleanups (old_cleanups); if (ret != 0) @@ -1815,7 +1660,8 @@ record_full_remove_breakpoint (struct gdbarch *gdbarch, int ret; old_cleanups = record_full_gdb_operation_disable_set (); - ret = record_full_beneath_to_remove_breakpoint (gdbarch, bp_tgt); + ret = target_delegate_remove_breakpoint (find_target_at (record_stratum), + gdbarch, bp_tgt); do_cleanups (old_cleanups); if (ret != 0) @@ -1896,22 +1742,19 @@ record_full_async (void (*callback) (enum inferior_event_type event_type, /* If we're on top of a line target (e.g., linux-nat, remote), then set it to async mode as well. Will be NULL if we're sitting on top of the core target, for "record restore". */ - if (record_full_beneath_to_async != NULL) - record_full_beneath_to_async (callback, context); + target_delegate_async (find_target_at (record_stratum), callback, context); } static int record_full_can_async_p (void) { - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; + return target_delegate_can_async_p (find_target_at (record_stratum)); } static int record_full_is_async_p (void) { - /* We only enable async when the user specifically asks for it. */ - return target_async_permitted; + return target_delegate_is_async_p (find_target_at (record_stratum)); } static enum exec_direction_kind @@ -2237,10 +2080,10 @@ record_full_core_xfer_partial (struct target_ops *ops, else { if (!entry) - return record_full_beneath_to_xfer_partial - (record_full_beneath_to_xfer_partial_ops, - object, annex, readbuf, writebuf, - offset, len); + return target_delegate_xfer_partial (ops, + object, annex, + readbuf, writebuf, + offset, len); memcpy (readbuf, entry->buf + sec_offset, (size_t) len); @@ -2256,9 +2099,8 @@ record_full_core_xfer_partial (struct target_ops *ops, error (_("You can't do that without a process to debug.")); } - return record_full_beneath_to_xfer_partial - (record_full_beneath_to_xfer_partial_ops, object, annex, - readbuf, writebuf, offset, len); + return target_delegate_xfer_partial (ops, object, annex, + readbuf, writebuf, offset, len); } /* "to_insert_breakpoint" method for prec over corefile. */ diff --git a/gdb/record.c b/gdb/record.c index cbbe365..8a199f9 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -62,13 +62,7 @@ struct cmd_list_element *info_record_cmdlist = NULL; static struct target_ops * find_record_target (void) { - struct target_ops *t; - - for (t = current_target.beneath; t != NULL; t = t->beneath) - if (t->to_stratum == record_stratum) - return t; - - return NULL; + return find_target_at (record_stratum); } /* Check that recording is active. Throw an error, if it isn't. */ diff --git a/gdb/record.h b/gdb/record.h index 86e6bc6..00fbd3f 100644 --- a/gdb/record.h +++ b/gdb/record.h @@ -22,7 +22,7 @@ struct cmd_list_element; -#define RECORD_IS_USED (current_target.to_stratum == record_stratum) +#define RECORD_IS_USED (find_target_at (record_stratum) != NULL) extern unsigned int record_debug; diff --git a/gdb/target.c b/gdb/target.c index e3dcb47..2c55187 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -75,12 +75,6 @@ static LONGEST default_xfer_partial (struct target_ops *ops, const gdb_byte *writebuf, ULONGEST offset, LONGEST len); -static LONGEST current_xfer_partial (struct target_ops *ops, - enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, - ULONGEST offset, LONGEST len); - static LONGEST target_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, @@ -866,7 +860,7 @@ update_current_target (void) de_fault (to_stop, (void (*) (ptid_t)) target_ignore); - current_target.to_xfer_partial = current_xfer_partial; + current_target.to_xfer_partial = target_delegate_xfer_partial; de_fault (to_rcmd, (void (*) (char *, struct ui_file *)) tcomplain); @@ -1992,14 +1986,14 @@ default_xfer_partial (struct target_ops *ops, enum target_object object, return -1; } -/* The xfer_partial handler for the topmost target. Unlike the default, - it does not need to handle memory specially; it just passes all - requests down the stack. */ +/* See target.h. */ -static LONGEST -current_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +LONGEST +target_delegate_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) { if (ops->beneath != NULL) return ops->beneath->to_xfer_partial (ops->beneath, object, annex, @@ -2008,6 +2002,53 @@ current_xfer_partial (struct target_ops *ops, enum target_object object, return -1; } +/* See target.h. */ + +void +target_delegate_async (struct target_ops *self, + void (*callback) (enum inferior_event_type, void *), + void *datum) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_async) + { + t->to_async (callback, datum); + break; + } + } +} + +/* See target.h. */ + +int +target_delegate_is_async_p (struct target_ops *self) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + if (t->to_is_async_p != NULL) + return t->to_is_async_p (); + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + +/* See target.h. */ + +int +target_delegate_can_async_p (struct target_ops *self) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + if (t->to_can_async_p != NULL) + return t->to_can_async_p (); + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + /* Target vector read/write partial wrapper functions. */ static LONGEST @@ -2458,6 +2499,24 @@ target_insert_breakpoint (struct gdbarch *gdbarch, return (*current_target.to_insert_breakpoint) (gdbarch, bp_tgt); } +/* See target.h. */ + +int +target_delegate_insert_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_insert_breakpoint) + return t->to_insert_breakpoint (gdbarch, bp_tgt); + } + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + int target_remove_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt) @@ -2475,6 +2534,24 @@ target_remove_breakpoint (struct gdbarch *gdbarch, return (*current_target.to_remove_breakpoint) (gdbarch, bp_tgt); } +/* See target.h. */ + +int +target_delegate_remove_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_remove_breakpoint) + return t->to_remove_breakpoint (gdbarch, bp_tgt); + } + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + static void target_info (char *args, int from_tty) { @@ -2681,6 +2758,24 @@ target_wait (ptid_t ptid, struct target_waitstatus *status, int options) noprocess (); } +/* See target.h. */ + +ptid_t +target_delegate_wait (struct target_ops *self, + ptid_t ptid, struct target_waitstatus *status, + int options) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_wait) + return t->to_wait (t, ptid, status, options); + } + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + char * target_pid_to_str (ptid_t ptid) { @@ -2738,6 +2833,24 @@ target_resume (ptid_t ptid, int step, enum gdb_signal signal) noprocess (); } +/* See target.h. */ + +void +target_delegate_resume (struct target_ops *self, + ptid_t ptid, int step, enum gdb_signal signal) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_resume) + { + t->to_resume (t, ptid, step, signal); + break; + } + } +} + void target_pass_signals (int numsigs, unsigned char *pass_signals) { @@ -3633,6 +3746,20 @@ find_target_beneath (struct target_ops *t) return t->beneath; } +/* See target.h. */ + +struct target_ops * +find_target_at (enum strata stratum) +{ + struct target_ops *t; + + for (t = current_target.beneath; t != NULL; t = t->beneath) + if (t->to_stratum == stratum) + return t; + + return NULL; +} + /* The inferior process has died. Long live the inferior! */ @@ -3985,6 +4112,24 @@ target_store_registers (struct regcache *regcache, int regno) noprocess (); } +/* See target.h. */ + +void +target_delegate_store_registers (struct target_ops *self, + struct regcache *regcache, int regno) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_store_registers) + { + t->to_store_registers (t, regcache, regno); + break; + } + } +} + int target_core_of_thread (ptid_t ptid) { @@ -4118,6 +4263,39 @@ target_ranged_break_num_registers (void) /* See target.h. */ int +target_delegate_stopped_by_watchpoint (struct target_ops *self) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_stopped_by_watchpoint) + return t->to_stopped_by_watchpoint (); + } + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + +/* See target.h. */ + +int +target_delegate_stopped_data_address (struct target_ops *self, + CORE_ADDR *addr_p) +{ + struct target_ops *t; + + for (t = self->beneath; t != NULL; t = t->beneath) + { + if (t->to_stopped_data_address) + return t->to_stopped_data_address (t, addr_p); + } + + gdb_assert_not_reached (_("reached end of target stack during delegation")); +} + +/* See target.h. */ + +int target_supports_btrace (void) { struct target_ops *t; diff --git a/gdb/target.h b/gdb/target.h index 1d73bcd..2e00911 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -937,6 +937,12 @@ extern void target_disconnect (char *, int); extern void target_resume (ptid_t ptid, int step, enum gdb_signal signal); +/* Delegate "target_resume" to a target beneath SELF. */ + +extern void target_delegate_resume (struct target_ops *self, + ptid_t ptid, int step, + enum gdb_signal signal); + /* Wait for process pid to do something. PTID = -1 to wait for any pid to do something. Return pid of child, or -1 in case of error; store status through argument pointer STATUS. Note that it is @@ -949,6 +955,13 @@ extern void target_resume (ptid_t ptid, int step, enum gdb_signal signal); extern ptid_t target_wait (ptid_t ptid, struct target_waitstatus *status, int options); +/* Delegate "target_wait" to a target beneath SELF. */ + +extern ptid_t target_delegate_wait (struct target_ops *self, + ptid_t ptid, + struct target_waitstatus *status, + int options); + /* Fetch at least register REGNO, or all regs if regno == -1. No result. */ extern void target_fetch_registers (struct regcache *regcache, int regno); @@ -959,6 +972,12 @@ extern void target_fetch_registers (struct regcache *regcache, int regno); extern void target_store_registers (struct regcache *regcache, int regs); +/* Delegate "target_store_registers" to a target beneath SELF. */ + +extern void target_delegate_store_registers (struct target_ops *self, + struct regcache *regcache, + int regno); + /* Get ready to modify the registers array. On machines which store individual registers, this doesn't need to do anything. On machines which store all the registers in one fell swoop, this makes sure @@ -1091,12 +1110,24 @@ int target_write_memory_blocks (VEC(memory_write_request_s) *requests, extern int target_insert_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt); +/* Delegate "target_insert_breakpoint" to a target beneath SELF. */ + +extern int target_delegate_insert_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt); + /* Remove a breakpoint at address BP_TGT->placed_address in the target machine. Result is 0 for success, or an errno value. */ extern int target_remove_breakpoint (struct gdbarch *gdbarch, struct bp_target_info *bp_tgt); +/* Delegate "target_remove_breakpoint" to a target beneath SELF. */ + +extern int target_delegate_remove_breakpoint (struct target_ops *self, + struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt); + /* Initialize the terminal settings we record for the inferior, before we actually run the inferior. */ @@ -1375,15 +1406,29 @@ extern int target_async_permitted; /* Can the target support asynchronous execution? */ #define target_can_async_p() (current_target.to_can_async_p ()) +/* Delegate "target_can_async_p" to a target beneath SELF. */ + +extern int target_delegate_can_async_p (struct target_ops *self); + /* Is the target in asynchronous execution mode? */ #define target_is_async_p() (current_target.to_is_async_p ()) +/* Delegate "target_is_async_p" to a target beneath SELF. */ + +extern int target_delegate_is_async_p (struct target_ops *self); + int target_supports_non_stop (void); /* Put the target in async mode with the specified callback function. */ #define target_async(CALLBACK,CONTEXT) \ (current_target.to_async ((CALLBACK), (CONTEXT))) +/* Delegate "target_async" to a target beneath SELF. */ + +extern void target_delegate_async (struct target_ops *, + void (*) (enum inferior_event_type, void *), + void *); + #define target_execution_direction() \ (current_target.to_execution_direction ()) @@ -1459,6 +1504,10 @@ extern char *target_thread_name (struct thread_info *); #define target_stopped_by_watchpoint \ (*current_target.to_stopped_by_watchpoint) +/* Delegate "target_stopped_by_watchpoint" to a target beneath SELF. */ + +extern int target_delegate_stopped_by_watchpoint (struct target_ops *self); + /* Non-zero if we have steppable watchpoints */ #define target_have_steppable_watchpoint \ @@ -1532,6 +1581,11 @@ extern int target_ranged_break_num_registers (void); #define target_stopped_data_address(target, addr_p) \ (*target.to_stopped_data_address) (target, addr_p) +/* Delegate "target_stopped_data_address" to a target beneath SELF. */ + +extern int target_delegate_stopped_data_address (struct target_ops *self, + CORE_ADDR *addr_p); + /* Return non-zero if ADDR is within the range of a watchpoint spanning LENGTH bytes beginning at START. */ #define target_watchpoint_addr_within_range(target, addr, start, length) \ @@ -1860,6 +1914,11 @@ extern void find_default_create_inferior (struct target_ops *, extern struct target_ops *find_target_beneath (struct target_ops *); +/* Find the target at STRATUM. If no target is at that stratum, + return NULL. */ + +struct target_ops *find_target_at (enum strata stratum); + /* Read OS data object of type TYPE from the target, and return it in XML format. The result is NUL-terminated and returned as a string, allocated using xmalloc. If an error occurs or the transfer is @@ -1962,4 +2021,13 @@ extern void target_call_history_from (ULONGEST begin, int size, int flags); /* See to_call_history_range. */ extern void target_call_history_range (ULONGEST begin, ULONGEST end, int flags); +/* Delegate "target_xfer_partial" to a target beneath SELF. */ + +extern LONGEST target_delegate_xfer_partial (struct target_ops *ops, + enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, LONGEST len); + #endif /* !defined (TARGET_H) */ -- 1.8.1.4