diff options
Diffstat (limited to 'gdb/ravenscar-thread.c')
-rw-r--r-- | gdb/ravenscar-thread.c | 170 |
1 files changed, 136 insertions, 34 deletions
diff --git a/gdb/ravenscar-thread.c b/gdb/ravenscar-thread.c index 7edfa29..83dfd9d 100644 --- a/gdb/ravenscar-thread.c +++ b/gdb/ravenscar-thread.c @@ -31,17 +31,41 @@ #include "regcache.h" #include "objfiles.h" +/* This module provides support for "Ravenscar" tasks (Ada) when + debugging on bare-metal targets. + + The typical situation is when debugging a bare-metal target over + the remote protocol. In that situation, the system does not know + about high-level comcepts such as threads, only about some code + running on one or more CPUs. And since the remote protocol does not + provide any handling for CPUs, the de facto standard for handling + them is to have one thread per CPU, where the thread's ptid has + its lwp field set to the CPU number (eg: 1 for the first CPU, + 2 for the second one, etc). This module will make that assumption. + + This module then creates and maintains the list of threads based + on the list of Ada tasks, with one thread per Ada tasks. The convention + is that threads corresponding to the CPUs (see assumption above) + have a ptid_t of the form (PID, LWP, 0), which threads corresponding + to our Ada tasks have a ptid_t of the form (PID, 0, TID) where TID + is the Ada task's ID as extracted from Ada runtime information. + + Switching to a given Ada tasks (or its underlying thread) is performed + by fetching the registers of that tasks from the memory area where + the registers were saved. For any of the other operations, the + operation is performed by first finding the CPU on which the task + is running, switching to its corresponding ptid, and then performing + the operation on that ptid using the target beneath us. */ + /* 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. */ +/* PTID of the last thread that received an event. + This can be useful to determine the associated task that received + the event, to make it the current task. */ static ptid_t base_ptid; static const char running_thread_name[] = "__gnat_running_thread_table"; @@ -53,7 +77,7 @@ static const char ravenscar_runtime_initializer[] = "system__bb__threads__initialize"; static void ravenscar_update_thread_list (struct target_ops *ops); -static ptid_t ravenscar_running_thread (void); +static ptid_t ravenscar_active_task (int cpu); static const char *ravenscar_extra_thread_info (struct target_ops *self, struct thread_info *tp); static int ravenscar_thread_alive (struct target_ops *ops, ptid_t ptid); @@ -72,22 +96,100 @@ static int ravenscar_runtime_initialized (void); static void ravenscar_inferior_created (struct target_ops *target, int from_tty); +/* Return nonzero iff PTID corresponds to a ravenscar task. */ + +static int +is_ravenscar_task (ptid_t ptid) +{ + /* By construction, ravenscar tasks have their LWP set to zero. */ + return ptid_get_lwp (ptid) == 0; +} + +/* Given PTID, which can be either a ravenscar task or a CPU thread, + return which CPU that ptid is running on. + + This assume that PTID is a valid ptid_t. Otherwise, a gdb_assert + will be triggered. */ + +static int +ravenscar_get_thread_base_cpu (ptid_t ptid) +{ + int base_cpu; + + if (is_ravenscar_task (ptid)) + { + struct ada_task_info *task_info = ada_get_task_info_from_ptid (ptid); + + gdb_assert (task_info != NULL); + base_cpu = task_info->base_cpu; + } + else + { + /* We assume that the LWP of the PTID is equal to the CPU number. */ + base_cpu = ptid_get_lwp (ptid); + } + + return base_cpu; +} + +/* Given a ravenscar task (identified by its ptid_t PTID), return nonzero + if this task is the currently active task on the cpu that task is + running on. + + In other words, this function determine which CPU this task is + currently running on, and then return nonzero if the CPU in question + is executing the code for that task. If that's the case, then + that task's registers are in the CPU bank. Otherwise, the task + is currently suspended, and its registers have been saved in memory. */ + +static int +ravenscar_task_is_currently_active (ptid_t ptid) +{ + ptid_t active_task_ptid + = ravenscar_active_task (ravenscar_get_thread_base_cpu (ptid)); + + return ptid_equal (ptid, active_task_ptid); +} + +/* Return the CPU thread (as a ptid_t) on which the given ravenscar + task is running. + + This is the thread that corresponds to the CPU on which the task + is running. */ + +static ptid_t +get_base_thread_from_ravenscar_task (ptid_t ptid) +{ + int base_cpu; + + if (!is_ravenscar_task (ptid)) + return ptid; + + base_cpu = ravenscar_get_thread_base_cpu (ptid); + return ptid_build (ptid_get_pid (ptid), base_cpu, 0); +} + /* Fetch the ravenscar running thread from target memory and update inferior_ptid accordingly. */ static void ravenscar_update_inferior_ptid (void) { + int base_cpu; + base_ptid = inferior_ptid; + gdb_assert (!is_ravenscar_task (inferior_ptid)); + base_cpu = ravenscar_get_thread_base_cpu (base_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 + /* Make sure we set base_ptid before calling ravenscar_active_task as the latter relies on it. */ - inferior_ptid = ravenscar_running_thread (); + inferior_ptid = ravenscar_active_task (base_cpu); gdb_assert (!ptid_equal (inferior_ptid, null_ptid)); /* The running thread may not have been added to @@ -144,14 +246,14 @@ has_ravenscar_runtime (void) static int ravenscar_runtime_initialized (void) { - return (!(ptid_equal (ravenscar_running_thread (), null_ptid))); + return (!(ptid_equal (ravenscar_active_task (1), null_ptid))); } /* Return the ID of the thread that is currently running. Return 0 if the ID could not be determined. */ static CORE_ADDR -get_running_thread_id (void) +get_running_thread_id (int cpu) { struct bound_minimal_symbol object_msym = get_running_thread_msymbol (); int object_size; @@ -164,8 +266,9 @@ get_running_thread_id (void) if (!object_msym.minsym) return 0; - object_addr = BMSYMBOL_VALUE_ADDRESS (object_msym); object_size = TYPE_LENGTH (builtin_type_void_data_ptr); + object_addr = (BMSYMBOL_VALUE_ADDRESS (object_msym) + + (cpu - 1) * object_size); buf_size = object_size; buf = (gdb_byte *) alloca (buf_size); read_memory (object_addr, buf, buf_size); @@ -231,9 +334,9 @@ ravenscar_update_thread_list (struct target_ops *ops) } static ptid_t -ravenscar_running_thread (void) +ravenscar_active_task (int cpu) { - CORE_ADDR tid = get_running_thread_id (); + CORE_ADDR tid = get_running_thread_id (cpu); if (tid == 0) return null_ptid; @@ -270,11 +373,9 @@ ravenscar_fetch_registers (struct target_ops *ops, struct target_ops *beneath = find_target_beneath (ops); ptid_t ptid = regcache_get_ptid (regcache); - if (!ravenscar_runtime_initialized () - || ptid_equal (ptid, base_magic_null_ptid) - || ptid_equal (ptid, ravenscar_running_thread ())) - beneath->to_fetch_registers (beneath, regcache, regnum); - else + if (ravenscar_runtime_initialized () + && is_ravenscar_task (ptid) + && !ravenscar_task_is_currently_active (ptid)) { struct gdbarch *gdbarch = regcache->arch (); struct ravenscar_arch_ops *arch_ops @@ -282,6 +383,8 @@ ravenscar_fetch_registers (struct target_ops *ops, arch_ops->to_fetch_registers (regcache, regnum); } + else + beneath->to_fetch_registers (beneath, regcache, regnum); } static void @@ -291,11 +394,9 @@ ravenscar_store_registers (struct target_ops *ops, struct target_ops *beneath = find_target_beneath (ops); ptid_t ptid = regcache_get_ptid (regcache); - if (!ravenscar_runtime_initialized () - || ptid_equal (ptid, base_magic_null_ptid) - || ptid_equal (ptid, ravenscar_running_thread ())) - beneath->to_store_registers (beneath, regcache, regnum); - else + if (ravenscar_runtime_initialized () + && is_ravenscar_task (ptid) + && !ravenscar_task_is_currently_active (ptid)) { struct gdbarch *gdbarch = regcache->arch (); struct ravenscar_arch_ops *arch_ops @@ -303,6 +404,8 @@ ravenscar_store_registers (struct target_ops *ops, arch_ops->to_store_registers (regcache, regnum); } + else + beneath->to_store_registers (beneath, regcache, regnum); } static void @@ -312,11 +415,9 @@ ravenscar_prepare_to_store (struct target_ops *self, struct target_ops *beneath = find_target_beneath (self); ptid_t ptid = regcache_get_ptid (regcache); - if (!ravenscar_runtime_initialized () - || ptid_equal (ptid, base_magic_null_ptid) - || ptid_equal (ptid, ravenscar_running_thread ())) - beneath->to_prepare_to_store (beneath, regcache); - else + if (ravenscar_runtime_initialized () + && is_ravenscar_task (ptid) + && !ravenscar_task_is_currently_active (ptid)) { struct gdbarch *gdbarch = regcache->arch (); struct ravenscar_arch_ops *arch_ops @@ -324,6 +425,8 @@ ravenscar_prepare_to_store (struct target_ops *self, arch_ops->to_prepare_to_store (regcache); } + else + beneath->to_prepare_to_store (beneath, regcache); } /* Implement the to_stopped_by_sw_breakpoint target_ops "method". */ @@ -335,7 +438,7 @@ ravenscar_stopped_by_sw_breakpoint (struct target_ops *ops) struct target_ops *beneath = find_target_beneath (ops); int result; - inferior_ptid = base_ptid; + inferior_ptid = get_base_thread_from_ravenscar_task (saved_ptid); result = beneath->to_stopped_by_sw_breakpoint (beneath); inferior_ptid = saved_ptid; return result; @@ -350,7 +453,7 @@ ravenscar_stopped_by_hw_breakpoint (struct target_ops *ops) struct target_ops *beneath = find_target_beneath (ops); int result; - inferior_ptid = base_ptid; + inferior_ptid = get_base_thread_from_ravenscar_task (saved_ptid); result = beneath->to_stopped_by_hw_breakpoint (beneath); inferior_ptid = saved_ptid; return result; @@ -365,7 +468,7 @@ ravenscar_stopped_by_watchpoint (struct target_ops *ops) struct target_ops *beneath = find_target_beneath (ops); int result; - inferior_ptid = base_ptid; + inferior_ptid = get_base_thread_from_ravenscar_task (saved_ptid); result = beneath->to_stopped_by_watchpoint (beneath); inferior_ptid = saved_ptid; return result; @@ -380,7 +483,7 @@ ravenscar_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p) struct target_ops *beneath = find_target_beneath (ops); int result; - inferior_ptid = base_ptid; + inferior_ptid = get_base_thread_from_ravenscar_task (saved_ptid); result = beneath->to_stopped_data_address (beneath, addr_p); inferior_ptid = saved_ptid; return result; @@ -405,7 +508,7 @@ ravenscar_core_of_thread (struct target_ops *ops, ptid_t ptid) struct target_ops *beneath = find_target_beneath (ops); int result; - inferior_ptid = base_ptid; + inferior_ptid = get_base_thread_from_ravenscar_task (saved_ptid); result = beneath->to_core_of_thread (beneath, inferior_ptid); inferior_ptid = saved_ptid; return result; @@ -422,7 +525,6 @@ ravenscar_inferior_created (struct target_ops *target, int from_tty) || !has_ravenscar_runtime ()) return; - base_magic_null_ptid = inferior_ptid; ravenscar_update_inferior_ptid (); push_target (&ravenscar_ops); } |