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