Update copyright year in version of output (gdb/gdbserver/gdbreplay)
[deliverable/binutils-gdb.git] / gdb / ravenscar-thread.c
CommitLineData
036b1ba8
JB
1/* Ada Ravenscar thread support.
2
3 Copyright 2004, 2009, 2010 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "gdbcore.h"
22#include "gdbthread.h"
23#include "ada-lang.h"
24#include "target.h"
25#include "inferior.h"
26#include "command.h"
27#include "ravenscar-thread.h"
28#include "observer.h"
29#include "gdb_string.h"
30#include "gdbcmd.h"
31#include "top.h"
32#include "regcache.h"
33
34/* If non-null, ravenscar task support is enabled. */
35static int ravenscar_task_support = 1;
36
37/* Non-null if the ravenscar thread layer has been pushed on the target
38 stack. */
39static int ravenscar_is_open = 0;
40
41/* This module's target-specific operations. */
42static struct target_ops ravenscar_ops;
43
44/* Some base target uses a special value for the null PID (exempli gratia
45 remote). */
46static ptid_t base_magic_null_ptid;
47
48/* Ptid of the inferior as seen by the process stratum. */
49static ptid_t base_ptid;
50
7f39f34a 51static const char running_thread_name[] = "__gnat_running_thread_table";
036b1ba8
JB
52
53static const char known_tasks_name[] = "system__tasking__debug__known_tasks";
54
55static const char ravenscar_runtime_initializer[] = "system__bb__threads__initialize";
56
57static struct observer *update_target_observer = NULL;
58
59/* Architecture-specific hooks. */
60static struct ravenscar_arch_ops* current_arch_ops;
61
036b1ba8
JB
62static void ravenscar_find_new_threads (struct target_ops *ops);
63static ptid_t ravenscar_running_thread (void);
64static char *ravenscar_extra_thread_info (struct thread_info *tp);
65static int ravenscar_thread_alive (struct target_ops *ops, ptid_t ptid);
66static void ravenscar_fetch_registers (struct target_ops *ops,
67 struct regcache *regcache, int regnum);
68static void ravenscar_store_registers (struct target_ops *ops,
69 struct regcache *regcache, int regnum);
70static void ravenscar_prepare_to_store (struct regcache *regcache);
71static void ravenscar_initialize (char *name, int from_tty);
72static void ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step,
73 enum target_signal siggnal);
74static void ravenscar_mourn_inferior (struct target_ops *ops);
75static void ravenscar_update_inferior_ptid (void);
76static int has_ravenscar_runtime (void);
77static int ravenscar_runtime_initialized (void);
78static void ravenscar_inferior_created (struct target_ops *target,
79 int from_tty);
80
81/* Fetch the ravenscar running thread from target memory and
82 update inferior_ptid accordingly. */
83
84static void
85ravenscar_update_inferior_ptid (void)
86{
87 base_ptid = inferior_ptid;
88
89 /* If the runtime has not been initialized yet, the inferior_ptid is
90 the only ptid that there is. */
91 if (!ravenscar_runtime_initialized ())
92 return;
93
94 /* Make sure we set base_ptid before calling ravenscar_running_thread
95 as the latter relies on it. */
96 inferior_ptid = ravenscar_running_thread ();
97 gdb_assert (!ptid_equal (inferior_ptid, null_ptid));
98
99 /* The running thread may not have been added to
100 system.tasking.debug's list yet; so ravenscar_find_new_threads
101 may not always add it to the thread list. Add it here. */
102 if (!find_thread_ptid (inferior_ptid))
103 add_thread (inferior_ptid);
104}
105
7f39f34a
JB
106/* The Ravenscar Runtime exports a symbol which contains the ID of
107 the thread that is currently running. Try to locate that symbol
108 and return its associated minimal symbol.
109 Return NULL if not found. */
110
111static struct minimal_symbol *
112get_running_thread_msymbol (void)
113{
114 struct minimal_symbol *msym;
115
116 msym = lookup_minimal_symbol (running_thread_name, NULL, NULL);
117 if (!msym)
118 /* Older versions of the GNAT runtime were using a different
119 (less ideal) name for the symbol where the active thread ID
120 is stored. If we couldn't find the symbol using the latest
121 name, then try the old one. */
122 msym = lookup_minimal_symbol ("running_thread", NULL, NULL);
123
124 return msym;
125}
126
036b1ba8
JB
127/* Return True if the Ada Ravenscar run-time can be found in the
128 application. */
129
130static int
131has_ravenscar_runtime (void)
132{
133 struct minimal_symbol *msym_ravenscar_runtime_initializer =
134 lookup_minimal_symbol (ravenscar_runtime_initializer, NULL, NULL);
135 struct minimal_symbol *msym_known_tasks =
136 lookup_minimal_symbol (known_tasks_name, NULL, NULL);
7f39f34a 137 struct minimal_symbol *msym_running_thread = get_running_thread_msymbol ();
036b1ba8
JB
138
139 return (msym_ravenscar_runtime_initializer
140 && msym_known_tasks
141 && msym_running_thread);
142}
143
144/* Return True if the Ada Ravenscar run-time can be found in the
145 application, and if it has been initialized on target. */
146
147static int
148ravenscar_runtime_initialized (void)
149{
150 return (!(ptid_equal (ravenscar_running_thread (), null_ptid)));
151}
152
7f39f34a
JB
153/* Return the ID of the thread that is currently running.
154 Return 0 if the ID could not be determined. */
036b1ba8
JB
155
156static CORE_ADDR
7f39f34a 157get_running_thread_id (void)
036b1ba8 158{
7f39f34a 159 const struct minimal_symbol *object_msym = get_running_thread_msymbol ();
036b1ba8
JB
160 int object_size;
161 int buf_size;
162 char *buf;
163 CORE_ADDR object_addr;
164 struct type *builtin_type_void_data_ptr =
165 builtin_type (target_gdbarch)->builtin_data_ptr;
166
167 if (!object_msym)
168 return 0;
169
170 object_addr = SYMBOL_VALUE_ADDRESS (object_msym);
171 object_size = TYPE_LENGTH (builtin_type_void_data_ptr);
172 buf_size = object_size;
173 buf = alloca (buf_size);
174 read_memory (object_addr, buf, buf_size);
175 return extract_typed_address (buf, builtin_type_void_data_ptr);
176}
177
178static void
179ravenscar_close (int quitting)
180{
181 ravenscar_is_open = 0;
182}
183
184static void
185ravenscar_resume (struct target_ops *ops, ptid_t ptid, int step,
186 enum target_signal siggnal)
187{
188 struct target_ops *beneath = find_target_beneath (ops);
189
190 inferior_ptid = base_ptid;
191 beneath->to_resume (beneath, base_ptid, step, siggnal);
192}
193
194static ptid_t
195ravenscar_wait (struct target_ops *ops, ptid_t ptid,
196 struct target_waitstatus *status,
197 int options)
198{
199 struct target_ops *beneath = find_target_beneath (ops);
200
201 inferior_ptid = base_ptid;
202 beneath->to_wait (beneath, base_ptid, status, 0);
203 ravenscar_find_new_threads (ops);
204 ravenscar_update_inferior_ptid ();
205 return inferior_ptid;
206}
207
208/* Add the thread associated to the given TASK to the thread list
209 (if the thread has already been added, this is a no-op). */
210
211static void
212ravenscar_add_thread (struct ada_task_info *task)
213{
214 if (find_thread_ptid (task->ptid) == NULL)
215 add_thread (task->ptid);
216}
217
218static void
219ravenscar_find_new_threads (struct target_ops *ops)
220{
221 ada_build_task_list (0);
222
223 /* Do not clear the thread list before adding the Ada task, to keep
224 the thread that the process stratum has included into it
225 (base_ptid) and the running thread, that may not have been included
226 to system.tasking.debug's list yet. */
227
228 iterate_over_live_ada_tasks (ravenscar_add_thread);
229}
230
231static ptid_t
232ravenscar_running_thread (void)
233{
7f39f34a 234 CORE_ADDR tid = get_running_thread_id ();
036b1ba8
JB
235
236 if (tid == 0)
237 return null_ptid;
238 else
239 return ptid_build (ptid_get_pid (base_ptid), 0, tid);
240}
241
242static char *
243ravenscar_extra_thread_info (struct thread_info *tp)
244{
245 return "Ravenscar task";
246}
247
248static int
249ravenscar_thread_alive (struct target_ops *ops, ptid_t ptid)
250{
251 /* Ravenscar tasks are non-terminating. */
252 return 1;
253}
254
255static char *
256ravenscar_pid_to_str (struct target_ops *ops, ptid_t ptid)
257{
258 static char buf[30];
259
260 snprintf (buf, sizeof (buf), "Thread %#x", (int) ptid_get_tid (ptid));
261 return buf;
262}
263
264static void
265ravenscar_fetch_registers (struct target_ops *ops,
266 struct regcache *regcache, int regnum)
267{
268 struct target_ops *beneath = find_target_beneath (ops);
269
270 if (!ravenscar_runtime_initialized ()
271 || ptid_equal (inferior_ptid, base_magic_null_ptid)
272 || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
273 beneath->to_fetch_registers (beneath, regcache, regnum);
274 else
275 current_arch_ops->to_fetch_registers (regcache, regnum);
276}
277
278static void
279ravenscar_store_registers (struct target_ops *ops,
280 struct regcache *regcache, int regnum)
281{
282 struct target_ops *beneath = find_target_beneath (ops);
283
284 if (!ravenscar_runtime_initialized ()
285 || ptid_equal (inferior_ptid, base_magic_null_ptid)
286 || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
287 beneath->to_store_registers (beneath, regcache, regnum);
288 else
289 current_arch_ops->to_store_registers (regcache, regnum);
290}
291
292static void
293ravenscar_prepare_to_store (struct regcache *regcache)
294{
295 struct target_ops *beneath = find_target_beneath (&ravenscar_ops);
296
297 if (!ravenscar_runtime_initialized ()
298 || ptid_equal (inferior_ptid, base_magic_null_ptid)
299 || ptid_equal (inferior_ptid, ravenscar_running_thread ()))
300 beneath->to_prepare_to_store (regcache);
301 else
302 current_arch_ops->to_prepare_to_store (regcache);
303}
304
305static void
306ravenscar_mourn_inferior (struct target_ops *ops)
307{
308 struct target_ops *beneath = find_target_beneath (&ravenscar_ops);
309
310 base_ptid = null_ptid;
311 beneath->to_mourn_inferior (beneath);
312 unpush_target (&ravenscar_ops);
313}
314
315/* Observer on inferior_created: push ravenscar thread stratum if needed. */
316
317static void
318ravenscar_inferior_created (struct target_ops *target, int from_tty)
319{
320 if (ravenscar_task_support
321 && has_ravenscar_runtime ())
322 ravenscar_initialize (NULL, 0);
323}
324
325void
326ravenscar_register_arch_ops (struct ravenscar_arch_ops *ops)
327{
328 /* FIXME: To be clean, we would need to handle a list of
329 architectures, just like in remote-wtx-hw.c. However, for now the
330 only Ravenscar run-time for bare board that is implemented in
331 GNAT is for only one architecture: erc32-elf. So no need to care about
332 that for now...*/
333 current_arch_ops = ops;
334}
335
336/* Initialize Ravenscar support. */
337
338static void
339ravenscar_initialize (char *name, int from_tty)
340{
341 if (ravenscar_is_open)
342 return;
343
344 base_magic_null_ptid = inferior_ptid;
345 ravenscar_update_inferior_ptid ();
346 push_target (&ravenscar_ops);
347 ravenscar_is_open = 1;
348}
349
350static ptid_t
351ravenscar_get_ada_task_ptid (long lwp, long thread)
352{
353 return ptid_build (ptid_get_pid (base_ptid), 0, thread);
354}
355
356static void
357init_ravenscar_thread_ops (void)
358{
359 ravenscar_ops.to_shortname = "ravenscar";
360 ravenscar_ops.to_longname = "Ravenscar tasks.";
361 ravenscar_ops.to_doc = "Ravenscar tasks support.";
362 ravenscar_ops.to_close = ravenscar_close;
363 ravenscar_ops.to_resume = ravenscar_resume;
364 ravenscar_ops.to_wait = ravenscar_wait;
365 ravenscar_ops.to_fetch_registers = ravenscar_fetch_registers;
366 ravenscar_ops.to_store_registers = ravenscar_store_registers;
367 ravenscar_ops.to_prepare_to_store = ravenscar_prepare_to_store;
368 ravenscar_ops.to_thread_alive = ravenscar_thread_alive;
369 ravenscar_ops.to_find_new_threads = ravenscar_find_new_threads;
370 ravenscar_ops.to_pid_to_str = ravenscar_pid_to_str;
371 ravenscar_ops.to_extra_thread_info = ravenscar_extra_thread_info;
372 ravenscar_ops.to_get_ada_task_ptid = ravenscar_get_ada_task_ptid;
373 ravenscar_ops.to_mourn_inferior = ravenscar_mourn_inferior;
374 ravenscar_ops.to_has_all_memory = default_child_has_all_memory;
375 ravenscar_ops.to_has_memory = default_child_has_memory;
376 ravenscar_ops.to_has_stack = default_child_has_stack;
377 ravenscar_ops.to_has_registers = default_child_has_registers;
378 ravenscar_ops.to_has_execution = default_child_has_execution;
379 ravenscar_ops.to_stratum = thread_stratum;
380 ravenscar_ops.to_magic = OPS_MAGIC;
381}
382
383/* Command-list for the "set/show ravenscar" prefix command. */
384static struct cmd_list_element *set_ravenscar_list;
385static struct cmd_list_element *show_ravenscar_list;
386
387/* Implement the "set ravenscar" prefix command. */
388
389static void
390set_ravenscar_command (char *arg, int from_tty)
391{
392 printf_unfiltered (_(\
393"\"set ravenscar\" must be followed by the name of a setting.\n"));
394 help_list (set_ravenscar_list, "set ravenscar ", -1, gdb_stdout);
395}
396
397/* Implement the "show ravenscar" prefix command. */
398
399static void
400show_ravenscar_command (char *args, int from_tty)
401{
402 cmd_show_list (show_ravenscar_list, from_tty, "");
403}
404
405/* Implement the "show ravenscar task-switching" command. */
406
407static void
408show_ravenscar_task_switching_command (struct ui_file *file, int from_tty,
409 struct cmd_list_element *c,
410 const char *value)
411{
412 if (ravenscar_task_support)
413 fprintf_filtered (file, _("\
b64edec4 414Support for Ravenscar task/thread switching is enabled\n"));
036b1ba8
JB
415 else
416 fprintf_filtered (file, _("\
b64edec4 417Support for Ravenscar task/thread switching is disabled\n"));
036b1ba8
JB
418}
419
420/* Module startup initialization function, automagically called by
421 init.c. */
422
423void
424_initialize_ravenscar (void)
425{
426 init_ravenscar_thread_ops ();
427 base_ptid = null_ptid;
428
429 /* Notice when the inferior is created in order to push the
430 ravenscar ops if needed. */
431 observer_attach_inferior_created (ravenscar_inferior_created);
432
433 add_target (&ravenscar_ops);
434
435 add_prefix_cmd ("ravenscar", no_class, set_ravenscar_command,
436 _("Prefix command for changing Ravenscar-specific settings"),
437 &set_ravenscar_list, "set ravenscar ", 0, &setlist);
438
439 add_prefix_cmd ("ravenscar", no_class, show_ravenscar_command,
440 _("Prefix command for showing Ravenscar-specific settings"),
04f9d4d0 441 &show_ravenscar_list, "show ravenscar ", 0, &showlist);
036b1ba8
JB
442
443 add_setshow_boolean_cmd ("task-switching", class_obscure,
444 &ravenscar_task_support, _("\
445Enable or disable support for GNAT Ravenscar tasks"), _("\
446Show whether support for GNAT Ravenscar tasks is enabled"),
447 _("\
448Enable or disable support for task/thread switching with the GNAT\n\
449Ravenscar run-time library for bareboard configuration."),
450 NULL, show_ravenscar_task_switching_command,
451 &set_ravenscar_list, &show_ravenscar_list);
452}
This page took 0.057115 seconds and 4 git commands to generate.