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