[vxworks 06/14] VxWorks breakpoint-handling module.

Joel Brobecker
2010-04-25T15:56:15Z

This unit provides a set of routines that allow us to insert/remove
breakpoints and watchpoints on the target. The target takes care of
the insertion/removal, but we need to keep track of respective IDs...

2010-04-24 Joel Brobecker <brobecker@adacore.com>

* remote-wtx-bp.h, remote-wtx-bp.c: New files.
---
gdb/remote-wtx-bp.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/remote-wtx-bp.h | 159 ++++++++++++++++++++++++++++++++++
2 files changed, 394 insertions(+), 0 deletions(-)
create mode 100644 gdb/remote-wtx-bp.c
create mode 100644 gdb/remote-wtx-bp.h

diff --git a/gdb/remote-wtx-bp.c b/gdb/remote-wtx-bp.c
new file mode 100644
index 0000000..25bb92a
--- /dev/null
+++ b/gdb/remote-wtx-bp.c
@@ -0,0 +1,235 @@
+/* WTX backend for GDB.
+
+ Copyright 2007, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "remote-wtx-bp.h"
+
+static enum wtx_breakpoint_action break_command_action = action_task;
+
+void
+set_break_command_action (enum wtx_breakpoint_action action)
+{
+ break_command_action = action;
+}
+
+enum wtx_breakpoint_action
+get_break_command_action (void)
+{
+ return break_command_action;
+}
+
+/* Handling of breakpoint command call routine. */
+
+static CORE_ADDR break_command_call_rtn = 0;
+
+void
+set_break_command_call_rtn (CORE_ADDR call_rtn)
+{
+ break_command_call_rtn = call_rtn;
+}
+
+CORE_ADDR
+get_break_command_call_rtn (void)
+{
+ return break_command_call_rtn;
+}
+
+/* --------------------------
+ -- Breakpoint support --
+ -------------------------- */
+
+/* Handling of eventpoint IDs.
+
+ VxWorks provides eventpoints for breakpoints and watchpoints. For each
+ inserted breakpoint, the target server returns an evenpoint ID that we
+ need to record, because we will need this ID to remove this breakpoint. */
+
+struct eventpoint_info
+{
+ struct bp_target_info *target_info;
+ evtpt_id_t id;
+ WTX_CONTEXT_TYPE context_type;
+ WTX_CONTEXT_ID_T context_id;
+
+ struct eventpoint_info *next;
+};
+
+struct eventpoint_info *eventpoints;
+
+/* Create an new eventpoint_info structure with the given parameters,
+ and insert it at the head of our EVENTPOINTS list. */
+
+void
+wtx_bp_register_eventpoint_id (evtpt_id_t id,
+ struct bp_target_info *target_info,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id)
+{
+ struct eventpoint_info *new_info =
+ xmalloc (sizeof (struct eventpoint_info));
+
+ new_info->target_info = target_info;
+ new_info->id = id;
+ new_info->context_type = context_type;
+ new_info->context_id = context_id;
+
+ /* Insert at the head of our EVENTPOINTS list. */
+ new_info->next = eventpoints;
+ eventpoints = new_info;
+}
+
+/* Return the eventpoint ID associated to the given TARGET_INFO,
+ and remove its entry in our EVENTPOINTS list. Return the
+ associated context in CONTEXT_TYPE and CONTEXT_ID.
+
+ Return invalid_evtpt_id if the target_info is unknown to us. */
+
+evtpt_id_t
+wtx_bp_pop_eventpoint_id (struct bp_target_info *target_info,
+ WTX_CONTEXT_TYPE *context_type,
+ WTX_CONTEXT_ID_T *context_id)
+{
+ struct eventpoint_info *info = eventpoints;
+ struct eventpoint_info *prev_info = NULL;
+ evtpt_id_t evtpt_id = invalid_evtpt_id;
+
+ while (info != NULL)
+ {
+ if (info->target_info == target_info)
+ {
+ evtpt_id = info->id;
+ *context_type = info->context_type;
+ *context_id = info->context_id;
+
+ /* Delete this node. */
+ if (prev_info != NULL)
+ prev_info->next = info->next;
+ else
+ eventpoints = info->next;
+ xfree (info);
+
+ break;
+ }
+ prev_info = info;
+ info = info->next;
+ }
+
+ return evtpt_id;
+}
+
+/* --------------------------
+ -- Watchpoint support --
+ -------------------------- */
+
+/* A structure to do the mapping between a GDB watchpoint and the associated
+ eventpoint ID created by the target. We use this mapping in order to
+ be able to remove a watchpoint. */
+
+struct watchpoint_info
+{
+ CORE_ADDR data_addr;
+ int data_len;
+ int type;
+ evtpt_id_t watchpoint_id;
+
+ struct watchpoint_info *next;
+};
+
+/* The list of watchpoints we inserted in the target. */
+static struct watchpoint_info *watchpoint_list = NULL;
+
+/* Return non-zero if INFO matches (DATA_ADDR, DATA_LEN, TYPE).
+ In other words, return non-zero if INFO is the watchpont_info
+ object that corresponds to a GDB watchpoint. */
+
+static int
+watchpoint_info_matches (struct watchpoint_info *info,
+ CORE_ADDR data_addr, int data_len, int type)
+{
+ return (info->data_addr == data_addr
+ && info->data_len == data_len
+ && info->type == type);
+}
+
+/* Record in our watchpoint list the fact that we just inserted a watchpoint
+ on the target. */
+
+void
+wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id, CORE_ADDR data_addr,
+ int data_len, int type)
+{
+ struct watchpoint_info *info = xmalloc (sizeof (struct watchpoint_info));
+
+ info->data_addr = data_addr;
+ info->data_len = data_len;
+ info->type = type;
+ info->watchpoint_id = watchpoint_id;
+
+ /* Now insert this new node at the head. */
+ info->next = watchpoint_list;
+ watchpoint_list = info;
+}
+
+/* Search our list of watchpoint_info objects, and pop the entry
+ that matches the watchpoint corresponding to (DATA_ADDR, DATA_LEN,
+ TYPE). Return the associated eventpoint ID.
+
+ Return invalid_evtpt_id if no match was found. */
+
+evtpt_id_t
+wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len, int type)
+{
+ struct watchpoint_info *info = watchpoint_list;
+ evtpt_id_t watchpoint_id;
+
+ /* Check to see if the node at the head of the watchpoint list matches
+ the description. If yes, then destroy that node. Given that on certain
+ architectures, we only have access to one watchpoints, this condition
+ should be true most of the time. */
+
+ if (info != NULL
+ && watchpoint_info_matches (info, data_addr, data_len, type))
+ {
+ watchpoint_id = info->watchpoint_id;
+ watchpoint_list = info->next;
+ free (info);
+ return watchpoint_id;
+ }
+
+ /* If not, then look for the node that is immediately preceding the node
+ we're looking for. Then do the freeing and reconnecting. */
+ while (info != NULL)
+ {
+ if (info->next != NULL
+ && watchpoint_info_matches (info->next, data_addr, data_len, type))
+ {
+ struct watchpoint_info *tmp = info->next;
+
+ watchpoint_id = tmp->watchpoint_id;
+ info->next = tmp->next;
+ free (tmp);
+ return watchpoint_id;
+ }
+ info = info->next;
+ }
+
+ /* No corresponding watchpoint eventpoint found. */
+ return invalid_evtpt_id;
+}
+
diff --git a/gdb/remote-wtx-bp.h b/gdb/remote-wtx-bp.h
new file mode 100644
index 0000000..3e241e0
--- /dev/null
+++ b/gdb/remote-wtx-bp.h
@@ -0,0 +1,159 @@
+/* WTX backend for GDB.
+
+ Copyright 2007, 2010 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef REMOTE_WTX_BP_H
+#define REMOTE_WTX_BP_H
+
+#include "remote-wtxapi.h"
+
+/* A note about breakpoint command "scope" and "action" settings:
+ --------------------------------------------------------------
+
+ These as concepts that were introduced in VxWorks AE, but no longer
+ make much sense in VxWorks 653. On 653, the user will debug either:
+
+ 1. A task inside the kernel partition;
+
+ 2. An entire partition, which in pratice is exactly similar to (1),
+ since it is done by debugging the task associated to that partition;
+
+ 3. The entire system in "system-mode".
+
+ This means that are are actually realy only debugging modes available
+ to the user:
+ a. The single-task mode
+ b. The system-mode.
+
+ In system-mode, the scope and action are, by design from the system,
+ irrelevant. Breakpoints will stop the entire system when any task
+ hits them.
+
+ In single-task mode, we user is debugging his task independently
+ of the rest of the system. This means that the scope of breakpoints
+ in that mode will be that task and only that task. Similarly, we
+ are forcing the action to that task as well.
+
+ As a result, the scope and actions can be implicitly determined
+ from the debugging context, and thus do not require user input.
+ This is why there is no longer a "set" command that allows the
+ user to change it anymore.
+
+ Also, this also means that the context and action can no longer
+ change during a debugging session. As a consequence, although
+ the system does allow tools to use independent scope and action
+ settings for every breakpoints, the debugger will be using
+ consistent settings, thus avoiding the need to track what
+ breakpoint uses what setting. This knowledge is important
+ when resuming breakpoints, because if a breakpoint stopped
+ all tasks, then we need to resume all tasks when doing a
+ "continue" for instance.
+
+ brobecker/2007-09-25: It is conceivable that some users might
+ find that have the choice of setting the action to "all" for
+ their debugging session would be helpful, or even necessary.
+ In that case, the system-mode might be more approriate to their
+ needs. However, the system-mode does have some limitations that
+ might not be acceptable either. This code has been designed in
+ such a way that adding that feature, this extra choice, should
+ just be a matter of adding a "set" command to let the user change
+ the action. */
+
+/* Advance declarations. */
+
+struct bp_target_info;
+
+/* The following enum defines the various actions that can be taken
+ when a breakpoint is hit. */
+
+enum wtx_breakpoint_action
+{
+ action_task, /* Stop the current task. */
+ action_all, /* Stop all breakable tasks in all partitions. */
+ action_call /* Stop the current task and call a stop function on the
+ target, if this function is defined. */
+};
+
+/* Exported routines. */
+
+void wtx_bp_register_eventpoint_id (evtpt_id_t id,
+ struct bp_target_info *target_info,
+ WTX_CONTEXT_TYPE context_type,
+ WTX_CONTEXT_ID_T context_id);
+
+evtpt_id_t wtx_bp_pop_eventpoint_id (struct bp_target_info *target_info,
+ WTX_CONTEXT_TYPE *context_type,
+ WTX_CONTEXT_ID_T *context_id);
+
+void set_break_command_call_rtn (CORE_ADDR call_rtn);
+
+CORE_ADDR get_break_command_call_rtn (void);
+
+void set_break_command_action (enum wtx_breakpoint_action);
+
+enum wtx_breakpoint_action get_break_command_action (void);
+
+/* Watchpoint support. */
+
+/* HARDWARE WATCHPOINT SUPPORT:
+ ============================
+
+ Strictly speaking, the only systems that support hardware watchpoints
+ are the targets that implement BoDA (Break on Data Access) events.
+ This functionality was introduced in a limited number of versions
+ of VxWorks 653 which can be identified once we're connected to
+ the system (see wtxapi_target_has_BoDA).
+
+ For systems that do not support BoDA, there is another type of
+ watchpoint event (WTX_EVENT_DATA_ACCESS) which, according to
+ WindRiver is not strictly speaking a hardware watchpoint because
+ it doesn't use the features of the target hardware to implement it.
+ However, from the debugger's perspective, these watchpoint events
+ are still viewed as hardware, because they do not require us to
+ emulate watchpoint support at the debugger level. Although not as
+ fast as strict hardware watchpoint support, these events are still
+ faster than having to emulate them at the debugger level, since it
+ avoids a very large amount of interaction between the debugger and
+ the target. Experimentations on VxWorks 5.5 and VxWorks 653 have
+ revealed that only one such event can be used at the same time:
+ - On VxWorks 5.5, the system lets you insert the events, but
+ somehow then fails to notify the tools for any of the watchpoints
+ - On VxWorks 653, the system returns an error when trying to
+ insert the second data-access event.
+
+ For systems supporting BoDA, there is one and only one watchpoint
+ available. Any other watchpoints must be emulated at the debugger
+ level. */
+
+/* brobecker/2007-10-05: For some reason, I remembered that hardware-assisted
+ watchpoints do not stop at the instruction that caused the watchpoint
+ trigger, but rather stops at the next instruction. So single-stepping
+ of one instruction in order to get the new value is not necessary for
+ WTX_EVENT_HW_BP and WTX_EVENT_BODA. But a previous implementation
+ seems to contradict my memory. So for now, we do not adjust
+ GDBARCH_HAVE_NONSTEPPABLE_WATCHPOINT. We will worry about this when
+ we actually encounter a problem. */
+
+void wtx_bp_register_watchpoint_id (evtpt_id_t watchpoint_id,
+ CORE_ADDR data_addr,
+ int data_len, int type);
+
+evtpt_id_t wtx_bp_pop_watchpoint_id (CORE_ADDR data_addr, int data_len,
+ int type);
+
+#endif
--
1.6.3.3