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