Re: [PATCH 2/2] Add support for GNAT Ravenscar run-time library.

Joel Brobecker
2010-09-23T21:58:44Z

[-- Attachment #1: Type: text/plain, Size: 262 bytes --]

Hi guys,

Thanks for the review. How about this new version? That should fix
all the little things that you commented on.

(I actually left out the comment about needing symbols before
the program is started - I'll treat this as a limitation for now)

--
Joel

[-- Attachment #2: ravenscar-2.diff --]
[-- Type: text/x-diff, Size: 23348 bytes --]

commit c416803e767be496d76855af593586f9d921aa0d
Author: Joel Brobecker <brobecker@adacore.com>
Date: Thu Sep 23 11:16:53 2010 -0700

Add support for GNAT Ravenscar run-time library.

gdb/ChangeLog (Jerome Guitton, Joel Brobecker):

* ravenscar-thread.c, ravenscar-thread.h, ravenscar-sparc-thread.c:
New files.
* configure.tgt (sparc-*-*): Add ravenscar-thread.o and
ravenscar-sparc-thread.o to gdb_target_obs.

diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 0b44005..80cfb49 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -521,7 +521,8 @@ sparc-*-rtems*)
;;
sparc-*-*)
# Target: SPARC
- gdb_target_obs="sparc-tdep.o"
+ gdb_target_obs="sparc-tdep.o ravenscar-thread.o \
+ ravenscar-sparc-thread.o"
;;
sparc64-*-*)
# Target: UltraSPARC
diff --git a/gdb/ravenscar-sparc-thread.c b/gdb/ravenscar-sparc-thread.c
new file mode 100644
index 0000000..197b745
--- /dev/null
+++ b/gdb/ravenscar-sparc-thread.c
@@ -0,0 +1,185 @@
+/* Ravenscar SPARC target support.
+
+ Copyright 2004, 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 "gdbcore.h"
+#include "regcache.h"
+#include "sparc-tdep.h"
+#include "inferior.h"
+#include "ravenscar-thread.h"
+
+static struct ravenscar_arch_ops ravenscar_sparc_ops;
+
+static void ravenscar_sparc_fetch_registers (struct regcache *regcache,
+ int regnum);
+static void ravenscar_sparc_store_registers (struct regcache *regcache,
+ int regnum);
+static void ravenscar_sparc_prepare_to_store (struct regcache *regcache);
+
+/* Register offsets from a referenced address (exempli gratia the
+ Thread_Descriptor). The referenced address depends on the register
+ number. The Thread_Descriptor layout and the stack layout are documented
+ in the GNAT sources, in sparc-bb.h. */
+
+static const int sparc_register_offsets[] =
+{
+ /* G0 - G7 */
+ -1, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
+ /* O0 - O7 */
+ 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
+ /* L0 - L7 */
+ 0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C,
+ /* I0 - I7 */
+ 0x20, 0x24, 0x28, 0x2C, 0x30, 0x34, 0x38, 0x3C,
+ /* F0 - F31 */
+ 0x50, 0x54, 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C,
+ 0x70, 0x74, 0x78, 0x7C, 0x80, 0x84, 0x88, 0x8C,
+ 0x90, 0x94, 0x99, 0x9C, 0xA0, 0xA4, 0xA8, 0xAC,
+ 0xB0, 0xB4, 0xBB, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC,
+ /* Y PSR WIM TBR PC NPC FPSR CPSR */
+ 0x40, 0x20, 0x44, -1, 0x1C, -1, 0x4C, -1
+};
+
+/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
+ regcache. */
+
+static void
+supply_register_at_address (struct regcache *regcache, int regnum,
+ CORE_ADDR register_addr)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int buf_size = register_size (gdbarch, regnum);
+ char *buf;
+
+ buf = (char *) alloca (buf_size);
+ read_memory (register_addr, buf, buf_size);
+ regcache_raw_supply (regcache, regnum, &buf);
+}
+
+/* Return true if, for a non-running thread, REGNUM has been saved on the
+ stack. */
+
+static int
+register_on_stack_p (int regnum)
+{
+ return (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
+ || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM);
+}
+
+/* Return true if, for a non-running thread, REGNUM has been saved on the
+ Thread_Descriptor. */
+
+static int
+register_in_thread_descriptor_p (int regnum)
+{
+ return (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ || (regnum == SPARC32_PSR_REGNUM)
+ || (regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
+ || (regnum == SPARC32_Y_REGNUM)
+ || (regnum == SPARC32_WIM_REGNUM)
+ || (regnum == SPARC32_FSR_REGNUM)
+ || (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F0_REGNUM + 31)
+ || (regnum == SPARC32_PC_REGNUM);
+}
+
+/* to_fetch_registers when inferior_ptid is different from the running
+ thread. */
+
+static void
+ravenscar_sparc_fetch_registers (struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ const int sp_regnum = gdbarch_sp_regnum (gdbarch);
+ const int num_regs = gdbarch_num_regs (gdbarch);
+ int current_regnum;
+ CORE_ADDR current_address;
+ CORE_ADDR thread_descriptor_address;
+ ULONGEST stack_address;
+
+ thread_descriptor_address = (CORE_ADDR) ptid_get_tid (inferior_ptid);
+ current_address = thread_descriptor_address
+ + sparc_register_offsets [sp_regnum];
+ supply_register_at_address (regcache, sp_regnum, current_address);
+ regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address);
+
+ for (current_regnum = 0; current_regnum < num_regs; current_regnum ++)
+ {
+ if (register_in_thread_descriptor_p (current_regnum))
+ {
+ current_address = thread_descriptor_address
+ + sparc_register_offsets [current_regnum];
+ supply_register_at_address (regcache, current_regnum,
+ current_address);
+ }
+ else if (register_on_stack_p (current_regnum))
+ {
+ current_address = stack_address
+ + sparc_register_offsets [current_regnum];
+ supply_register_at_address (regcache, current_regnum,
+ current_address);
+ }
+ }
+}
+
+/* to_prepare_to_store when inferior_ptid is different from the running
+ thread. */
+
+static void
+ravenscar_sparc_prepare_to_store (struct regcache *regcache)
+{
+ /* Nothing to do. */
+}
+
+/* to_store_registers when inferior_ptid is different from the running
+ thread. */
+
+static void
+ravenscar_sparc_store_registers (struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int buf_size = register_size (gdbarch, regnum);
+ char buf [buf_size];
+ ULONGEST register_address;
+
+ if (register_in_thread_descriptor_p (regnum))
+ register_address =
+ ptid_get_tid (inferior_ptid) + sparc_register_offsets [regnum];
+ else if (register_on_stack_p (regnum))
+ {
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM,
+ &register_address);
+ register_address += sparc_register_offsets [regnum];
+ }
+ else
+ return;
+
+ regcache_raw_collect (regcache, regnum, buf);
+ write_memory (register_address,
+ buf,
+ buf_size);
+}
+
+void
+_initialize_ravenscar_sparc (void)
+{
+ ravenscar_sparc_ops.to_fetch_registers = ravenscar_sparc_fetch_registers;
+ ravenscar_sparc_ops.to_store_registers = ravenscar_sparc_store_registers;
+ ravenscar_sparc_ops.to_prepare_to_store = ravenscar_sparc_prepare_to_store;
+ ravenscar_register_arch_ops (&ravenscar_sparc_ops);
+}
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c
new file mode 100644
index 0000000..4d3fe8d
--- /dev/null
+++ b/gdb/ravenscar-thread.c
@@ -0,0 +1,420 @@
+/* Ada Ravenscar thread support.
+
+ Copyright 2004, 2009, 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 "gdbcore.h"
+#include "gdbthread.h"
+#include "ada-lang.h"
+#include "target.h"
+#include "inferior.h"
+#include "command.h"
+#include "ravenscar-thread.h"
+#include "observer.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include "top.h"
+#include "regcache.h"
+
+/* If non-null, ravenscar task support is enabled. */
+static int ravenscar_task_support = 1;
+
+/* This module's target-specific operations. */
+static struct target_ops ravenscar_ops;
+
+/* Some base target uses a special value for the null PID (exempli gratia
+ remote). */
+static ptid_t base_magic_null_ptid;
+
+/* Ptid of the inferior as seen by the process stratum. */
+static ptid_t base_ptid;
+
+static const char running_thread_name[] = "running_thread";
+
+static const char known_tasks_name[] = "system__tasking__debug__known_tasks";
+
+static const char ravenscar_runtime_initializer[] = "system__bb__threads__initialize";
+
+static struct observer *update_target_observer = NULL;
+
+/* Architecture-specific hooks. */
+static struct ravenscar_arch_ops* current_arch_ops;
+
+static CORE_ADDR read_thread_id (const char *symbol_name);
+
+static void ravenscar_find_new_threads (struct target_ops *ops);
+static ptid_t ravenscar_running_thread (void);
+static char *ravenscar_extra_thread_info (struct thread_info *tp);
+static int ravenscar_thread_alive (struct target_ops *ops, ptid_t ptid);
+static void ravenscar_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum);
+static void ravenscar_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum);
+static void ravenscar_prepare_to_store (struct regcache *regcache);
+static void ravenscar_initialize (char *name, int from_tty);
+static void ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum target_signal siggnal);
+static void ravenscar_mourn_inferior (struct target_ops *ops);
+static void ravenscar_update_inferior_ptid (void);
+static int has_ravenscar_runtime (void);
+static int ravenscar_runtime_initialized (void);
+static void ravenscar_inferior_created (struct target_ops *target,
+ int from_tty);
+
+/* Fetch the ravenscar running thread from target memory and
+ update inferior_ptid accordingly. */
+
+static void
+ravenscar_update_inferior_ptid (void)
+{
+ base_ptid = inferior_ptid;
+
+ /* If the runtime has not been initialized yet, the inferior_ptid is
+ the only ptid that there is. */
+ if (!ravenscar_runtime_initialized ())
+ return;
+
+ /* Make sure we set base_ptid before calling ravenscar_running_thread
+ as the latter relies on it. */
+ inferior_ptid = ravenscar_running_thread ();
+ gdb_assert (!ptid_equal (inferior_ptid, null_ptid));
+
+ /* The running thread may not have been added to
+ system.tasking.debug's list yet; so ravenscar_find_new_threads
+ may not always add it to the thread list. Add it here. */
+ if (!find_thread_ptid (inferior_ptid))
+ add_thread (inferior_ptid);
+}
+
+/* Return True if the Ada Ravenscar run-time can be found in the
+ application. */
+
+static int
+has_ravenscar_runtime (void)
+{
+ struct minimal_symbol *msym_ravenscar_runtime_initializer =
+ lookup_minimal_symbol (ravenscar_runtime_initializer, NULL, NULL);
+ struct minimal_symbol *msym_known_tasks =
+ lookup_minimal_symbol (known_tasks_name, NULL, NULL);
+ struct minimal_symbol *msym_running_thread =
+ lookup_minimal_symbol (running_thread_name, NULL, NULL);
+
+ return (msym_ravenscar_runtime_initializer
+ && msym_known_tasks
+ && msym_running_thread);
+}
+
+/* Return True if the Ada Ravenscar run-time can be found in the
+ application, and if it has been initialized on target. */
+
+static int
+ravenscar_runtime_initialized (void)
+{
+ return (!(ptid_equal (ravenscar_running_thread (), null_ptid)));
+}
+
+/* Read the thread ID whose symbol name is SYMBOL_NAME. */
+
+static CORE_ADDR
+read_thread_id (const char *symbol_name)
+{
+ const struct minimal_symbol *object_msym =
+ lookup_minimal_symbol (symbol_name, NULL, NULL);
+ int object_size;
+ int buf_size;
+ char *buf;
+ CORE_ADDR object_addr;
+ struct type *builtin_type_void_data_ptr =
+ builtin_type (target_gdbarch)->builtin_data_ptr;
+
+ if (!object_msym)
+ return 0;
+
+ object_addr = SYMBOL_VALUE_ADDRESS (object_msym);
+ object_size = TYPE_LENGTH (builtin_type_void_data_ptr);
+ buf_size = object_size;
+ buf = alloca (buf_size);
+ read_memory (object_addr, buf, buf_size);
+ return extract_typed_address (buf, builtin_type_void_data_ptr);
+}
+
+static ptid_t
+ravenscar_wait (struct target_ops *ops, ptid_t ptid,
+ struct target_waitstatus *status,
+ int options)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ inferior_ptid = base_ptid;
+ beneath->to_wait (beneath, base_ptid, status, 0);
+ ravenscar_find_new_threads (ops);
+ ravenscar_update_inferior_ptid ();
+ return inferior_ptid;
+}
+
+static void
+ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step,
+ enum target_signal siggnal)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ inferior_ptid = base_ptid;
+ beneath->to_resume (beneath, base_ptid, step, siggnal);
+}
+
+/* Add the thread associated to the given TASK to the thread list
+ (if the thread has already been added, this is a no-op). */
+
+static void
+ravenscar_add_thread (struct ada_task_info *task)
+{
+ if (find_thread_ptid (task->ptid) == NULL)
+ add_thread (task->ptid);
+}
+
+static void
+ravenscar_find_new_threads (struct target_ops *ops)
+{
+ ada_build_task_list (0);
+
+ /* Do not clear the thread list before adding the Ada task, to keep
+ the thread that the process stratum has included into it
+ (base_ptid) and the running thread, that may not have been included
+ to system.tasking.debug's list yet. */
+
+ iterate_over_live_ada_tasks (ravenscar_add_thread);
+}
+
+static ptid_t
+ravenscar_running_thread (void)
+{
+ CORE_ADDR tid = read_thread_id (running_thread_name);
+
+ if (tid == 0)
+ return null_ptid;
+ else
+ return ptid_build (ptid_get_pid (base_ptid), 0, tid);
+}
+
+static char *
+ravenscar_extra_thread_info (struct thread_info *tp)
+{
+ return "Ravenscar task";
+}
+
+static int
+ravenscar_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ /* Ravenscar tasks are non-terminating. */
+ return 1;
+}
+
+static char *
+ravenscar_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+ static char buf[30];
+
+ snprintf (buf, sizeof (buf), "Thread %#x", (int) ptid_get_tid (ptid));
+ return buf;
+}
+
+static void
+ravenscar_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ if (!ravenscar_runtime_initialized ()
+ || ptid_equal (inferior_ptid, base_magic_null_ptid)
+ || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
+ beneath->to_fetch_registers (beneath, regcache, regnum);
+ else
+ current_arch_ops->to_fetch_registers (regcache, regnum);
+}
+
+static void
+ravenscar_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ if (!ravenscar_runtime_initialized ()
+ || ptid_equal (inferior_ptid, base_magic_null_ptid)
+ || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
+ beneath->to_store_registers (beneath, regcache, regnum);
+ else
+ current_arch_ops->to_store_registers (regcache, regnum);
+}
+
+static void
+ravenscar_prepare_to_store (struct regcache *regcache)
+{
+ struct target_ops *beneath = find_target_beneath (&ravenscar_ops);
+
+ if (!ravenscar_runtime_initialized ()
+ || ptid_equal (inferior_ptid, base_magic_null_ptid)
+ || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
+ beneath->to_prepare_to_store (regcache);
+ else
+ current_arch_ops->to_prepare_to_store (regcache);
+}
+
+static void
+ravenscar_mourn_inferior (struct target_ops *ops)
+{
+ struct target_ops *beneath = find_target_beneath (&ravenscar_ops);
+
+ base_ptid = null_ptid;
+ beneath->to_mourn_inferior (beneath);
+ unpush_target (&ravenscar_ops);
+}
+
+/* Observer on inferior_created: push ravenscar thread stratum if needed. */
+
+static void
+ravenscar_inferior_created (struct target_ops *target, int from_tty)
+{
+ if (ravenscar_task_support
+ && has_ravenscar_runtime ()
+ && strcmp (target_shortname, ravenscar_ops.to_shortname) != 0)
+ ravenscar_initialize (NULL, 0);
+}
+
+void
+ravenscar_register_arch_ops (struct ravenscar_arch_ops *ops)
+{
+ /* FIXME: To be clean, we would need to handle a list of
+ architectures, just like in remote-wtx-hw.c. However, for now the
+ only Ravenscar run-time for bare board that is implemented in
+ GNAT is for only one architecture: erc32-elf. So no need to care about
+ that for now...*/
+ current_arch_ops = ops;
+}
+
+/* Initialize Ravenscar support. */
+
+static void
+ravenscar_initialize (char *name, int from_tty)
+{
+ base_magic_null_ptid = inferior_ptid;
+ ravenscar_update_inferior_ptid ();
+ push_target (&ravenscar_ops);
+}
+
+static ptid_t
+ravenscar_get_ada_task_ptid (long lwp, long thread)
+{
+ return ptid_build (ptid_get_pid (base_ptid), 0, thread);
+}
+
+static void
+init_ravenscar_thread_ops (void)
+{
+ ravenscar_ops.to_shortname = "ravenscar";
+ ravenscar_ops.to_longname = "Ravenscar tasks.";
+ ravenscar_ops.to_doc = "Ravenscar tasks support.";
+ ravenscar_ops.to_wait = ravenscar_wait;
+ ravenscar_ops.to_resume = ravenscar_resume;
+ ravenscar_ops.to_fetch_registers = ravenscar_fetch_registers;
+ ravenscar_ops.to_store_registers = ravenscar_store_registers;
+ ravenscar_ops.to_prepare_to_store = ravenscar_prepare_to_store;
+ ravenscar_ops.to_thread_alive = ravenscar_thread_alive;
+ ravenscar_ops.to_find_new_threads = ravenscar_find_new_threads;
+ ravenscar_ops.to_pid_to_str = ravenscar_pid_to_str;
+ ravenscar_ops.to_extra_thread_info = ravenscar_extra_thread_info;
+ ravenscar_ops.to_get_ada_task_ptid = ravenscar_get_ada_task_ptid;
+ ravenscar_ops.to_mourn_inferior = ravenscar_mourn_inferior;
+ ravenscar_ops.to_has_all_memory = default_child_has_all_memory;
+ ravenscar_ops.to_has_memory = default_child_has_memory;
+ ravenscar_ops.to_has_stack = default_child_has_stack;
+ ravenscar_ops.to_has_registers = default_child_has_registers;
+ ravenscar_ops.to_has_execution = default_child_has_execution;
+ ravenscar_ops.to_stratum = thread_stratum;
+ ravenscar_ops.to_magic = OPS_MAGIC;
+}
+
+/* Command-list for the "set/show ravenscar" prefix command. */
+static struct cmd_list_element *set_ravenscar_list;
+static struct cmd_list_element *show_ravenscar_list;
+
+/* Implement the "set ravenscar" prefix command. */
+
+static void
+set_ravenscar_command (char *arg, int from_tty)
+{
+ printf_unfiltered (_(\
+"\"set ravenscar\" must be followed by the name of a setting.\n"));
+ help_list (set_ravenscar_list, "set ravenscar ", -1, gdb_stdout);
+}
+
+/* Implement the "show ravenscar" prefix command. */
+
+static void
+show_ravenscar_command (char *args, int from_tty)
+{
+ cmd_show_list (show_ravenscar_list, from_tty, "");
+}
+
+/* Implement the "show ravenscar task-switching" command. */
+
+static void
+show_ravenscar_task_switching_command (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ if (ravenscar_task_support)
+ fprintf_filtered (file, _("\
+Support for Ravenscar task/thread switching is enabled"));
+ else
+ fprintf_filtered (file, _("\
+Support for Ravenscar task/thread switching is disabled"));
+}
+
+/* Module startup initialization function, automagically called by
+ init.c. */
+
+void
+_initialize_ravenscar (void)
+{
+ init_ravenscar_thread_ops ();
+ base_ptid = null_ptid;
+
+ /* Notice when the inferior is created in order to push the
+ ravenscar ops if needed. */
+ observer_attach_inferior_created (ravenscar_inferior_created);
+
+ add_target (&ravenscar_ops);
+
+ add_prefix_cmd ("ravenscar", no_class, set_ravenscar_command,
+ _("Prefix command for changing Ravenscar-specific settings"),
+ &set_ravenscar_list, "set ravenscar ", 0, &setlist);
+
+ add_prefix_cmd ("ravenscar", no_class, show_ravenscar_command,
+ _("Prefix command for showing Ravenscar-specific settings"),
+ &show_ravenscar_list, "set ravenscar ", 0, &showlist);
+
+ add_setshow_boolean_cmd ("task-switching", class_obscure,
+ &ravenscar_task_support, _("\
+Enable or disable support for GNAT Ravenscar tasks"), _("\
+Show whether support for GNAT Ravenscar tasks is enabled"),
+ _("\
+Enable or disable support for task/thread switching with the GNAT\n\
+Ravenscar run-time library for bareboard configuration."),
+ NULL, show_ravenscar_task_switching_command,
+ &set_ravenscar_list, &show_ravenscar_list);
+}
diff --git a/gdb/ravenscar-thread.h b/gdb/ravenscar-thread.h
new file mode 100644
index 0000000..c8844e3
--- /dev/null
+++ b/gdb/ravenscar-thread.h
@@ -0,0 +1,41 @@
+/* Ada Ravenscar thread support.
+
+ Copyright 2004, 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 RAVENSCAR_THREAD_H
+#define RAVENSCAR_THREAD_H
+
+/* Architecture-specific hooks. */
+
+struct ravenscar_arch_ops
+{
+ void (*to_fetch_registers) (struct regcache *, int);
+ void (*to_store_registers) (struct regcache *, int);
+ void (*to_prepare_to_store) (struct regcache *);
+};
+
+/* Register implementations for target ops to_store_registers,
+ to_prepare_to_store and to_fetch_registers when the inferior_ptid
+ is different from the running thread. In that case, the registers
+ are saved in a architecture-specific location. */
+/* FIXME: only one architecture can be registered for now. See
+ implementation. */
+
+extern void ravenscar_register_arch_ops (struct ravenscar_arch_ops *ops);
+
+#endif /* !defined (RAVENSCAR_THREAD_H) */