Commit | Line | Data |
---|---|---|
036b1ba8 JB |
1 | /* Ada Ravenscar thread support. |
2 | ||
42a4f53d | 3 | Copyright (C) 2004-2019 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" | |
76727919 | 28 | #include "observable.h" |
036b1ba8 JB |
29 | #include "gdbcmd.h" |
30 | #include "top.h" | |
31 | #include "regcache.h" | |
77e371c0 | 32 | #include "objfiles.h" |
036b1ba8 | 33 | |
9edcc12f JB |
34 | /* This module provides support for "Ravenscar" tasks (Ada) when |
35 | debugging on bare-metal targets. | |
36 | ||
37 | The typical situation is when debugging a bare-metal target over | |
38 | the remote protocol. In that situation, the system does not know | |
e397fd39 | 39 | about high-level concepts such as threads, only about some code |
9edcc12f JB |
40 | running on one or more CPUs. And since the remote protocol does not |
41 | provide any handling for CPUs, the de facto standard for handling | |
42 | them is to have one thread per CPU, where the thread's ptid has | |
43 | its lwp field set to the CPU number (eg: 1 for the first CPU, | |
44 | 2 for the second one, etc). This module will make that assumption. | |
45 | ||
46 | This module then creates and maintains the list of threads based | |
e397fd39 | 47 | on the list of Ada tasks, with one thread per Ada task. The convention |
9edcc12f | 48 | is that threads corresponding to the CPUs (see assumption above) |
e397fd39 | 49 | have a ptid_t of the form (PID, LWP, 0), while threads corresponding |
9edcc12f JB |
50 | to our Ada tasks have a ptid_t of the form (PID, 0, TID) where TID |
51 | is the Ada task's ID as extracted from Ada runtime information. | |
52 | ||
e397fd39 TT |
53 | Switching to a given Ada task (or its underlying thread) is performed |
54 | by fetching the registers of that task from the memory area where | |
9edcc12f JB |
55 | the registers were saved. For any of the other operations, the |
56 | operation is performed by first finding the CPU on which the task | |
57 | is running, switching to its corresponding ptid, and then performing | |
58 | the operation on that ptid using the target beneath us. */ | |
59 | ||
036b1ba8 JB |
60 | /* If non-null, ravenscar task support is enabled. */ |
61 | static int ravenscar_task_support = 1; | |
62 | ||
9edcc12f JB |
63 | /* PTID of the last thread that received an event. |
64 | This can be useful to determine the associated task that received | |
65 | the event, to make it the current task. */ | |
036b1ba8 JB |
66 | static ptid_t base_ptid; |
67 | ||
7f39f34a | 68 | static const char running_thread_name[] = "__gnat_running_thread_table"; |
036b1ba8 JB |
69 | |
70 | static const char known_tasks_name[] = "system__tasking__debug__known_tasks"; | |
6040a59d | 71 | static const char first_task_name[] = "system__tasking__debug__first_task"; |
036b1ba8 | 72 | |
6cbcc006 TT |
73 | static const char ravenscar_runtime_initializer[] |
74 | = "system__bb__threads__initialize"; | |
036b1ba8 | 75 | |
d9f719f1 PA |
76 | static const target_info ravenscar_target_info = { |
77 | "ravenscar", | |
78 | N_("Ravenscar tasks."), | |
79 | N_("Ravenscar tasks support.") | |
80 | }; | |
81 | ||
f6ac5f3d PA |
82 | struct ravenscar_thread_target final : public target_ops |
83 | { | |
d9f719f1 PA |
84 | const target_info &info () const override |
85 | { return ravenscar_target_info; } | |
f6ac5f3d | 86 | |
66b4deae PA |
87 | strata stratum () const override { return thread_stratum; } |
88 | ||
f6ac5f3d PA |
89 | ptid_t wait (ptid_t, struct target_waitstatus *, int) override; |
90 | void resume (ptid_t, int, enum gdb_signal) override; | |
91 | ||
92 | void fetch_registers (struct regcache *, int) override; | |
93 | void store_registers (struct regcache *, int) override; | |
94 | ||
95 | void prepare_to_store (struct regcache *) override; | |
96 | ||
57810aa7 | 97 | bool stopped_by_sw_breakpoint () override; |
f6ac5f3d | 98 | |
57810aa7 | 99 | bool stopped_by_hw_breakpoint () override; |
f6ac5f3d | 100 | |
57810aa7 | 101 | bool stopped_by_watchpoint () override; |
f6ac5f3d | 102 | |
57810aa7 | 103 | bool stopped_data_address (CORE_ADDR *) override; |
f6ac5f3d | 104 | |
57810aa7 | 105 | bool thread_alive (ptid_t ptid) override; |
f6ac5f3d PA |
106 | |
107 | int core_of_thread (ptid_t ptid) override; | |
108 | ||
109 | void update_thread_list () override; | |
110 | ||
111 | const char *extra_thread_info (struct thread_info *) override; | |
112 | ||
113 | const char *pid_to_str (ptid_t) override; | |
114 | ||
115 | ptid_t get_ada_task_ptid (long lwp, long thread) override; | |
116 | ||
117 | void mourn_inferior () override; | |
f6ac5f3d PA |
118 | }; |
119 | ||
120 | /* This module's target-specific operations. */ | |
121 | static ravenscar_thread_target ravenscar_ops; | |
122 | ||
9edcc12f | 123 | static ptid_t ravenscar_active_task (int cpu); |
989f3c58 | 124 | static bool ravenscar_runtime_initialized (); |
036b1ba8 | 125 | |
989f3c58 | 126 | /* Return true iff PTID corresponds to a ravenscar task. */ |
9edcc12f | 127 | |
989f3c58 | 128 | static bool |
9edcc12f JB |
129 | is_ravenscar_task (ptid_t ptid) |
130 | { | |
54aa6c67 JB |
131 | /* By construction, ravenscar tasks have their LWP set to zero. |
132 | Also make sure that the TID is nonzero, as some remotes, when | |
133 | asked for the list of threads, will return the first thread | |
134 | as having its TID set to zero. For instance, TSIM version | |
135 | 2.0.48 for LEON3 sends 'm0' as a reply to the 'qfThreadInfo' | |
136 | query, which the remote protocol layer then treats as a thread | |
137 | whose TID is 0. This is obviously not a ravenscar task. */ | |
cc6bcb54 | 138 | return ptid.lwp () == 0 && ptid.tid () != 0; |
9edcc12f JB |
139 | } |
140 | ||
141 | /* Given PTID, which can be either a ravenscar task or a CPU thread, | |
142 | return which CPU that ptid is running on. | |
143 | ||
144 | This assume that PTID is a valid ptid_t. Otherwise, a gdb_assert | |
145 | will be triggered. */ | |
146 | ||
147 | static int | |
148 | ravenscar_get_thread_base_cpu (ptid_t ptid) | |
149 | { | |
150 | int base_cpu; | |
151 | ||
152 | if (is_ravenscar_task (ptid)) | |
153 | { | |
154 | struct ada_task_info *task_info = ada_get_task_info_from_ptid (ptid); | |
155 | ||
156 | gdb_assert (task_info != NULL); | |
157 | base_cpu = task_info->base_cpu; | |
158 | } | |
159 | else | |
160 | { | |
161 | /* We assume that the LWP of the PTID is equal to the CPU number. */ | |
e38504b3 | 162 | base_cpu = ptid.lwp (); |
9edcc12f JB |
163 | } |
164 | ||
165 | return base_cpu; | |
166 | } | |
167 | ||
989f3c58 | 168 | /* Given a ravenscar task (identified by its ptid_t PTID), return true |
9edcc12f JB |
169 | if this task is the currently active task on the cpu that task is |
170 | running on. | |
171 | ||
172 | In other words, this function determine which CPU this task is | |
173 | currently running on, and then return nonzero if the CPU in question | |
174 | is executing the code for that task. If that's the case, then | |
175 | that task's registers are in the CPU bank. Otherwise, the task | |
176 | is currently suspended, and its registers have been saved in memory. */ | |
177 | ||
989f3c58 | 178 | static bool |
9edcc12f JB |
179 | ravenscar_task_is_currently_active (ptid_t ptid) |
180 | { | |
181 | ptid_t active_task_ptid | |
182 | = ravenscar_active_task (ravenscar_get_thread_base_cpu (ptid)); | |
183 | ||
d7e15655 | 184 | return ptid == active_task_ptid; |
9edcc12f JB |
185 | } |
186 | ||
187 | /* Return the CPU thread (as a ptid_t) on which the given ravenscar | |
188 | task is running. | |
189 | ||
190 | This is the thread that corresponds to the CPU on which the task | |
191 | is running. */ | |
192 | ||
193 | static ptid_t | |
194 | get_base_thread_from_ravenscar_task (ptid_t ptid) | |
195 | { | |
196 | int base_cpu; | |
197 | ||
198 | if (!is_ravenscar_task (ptid)) | |
199 | return ptid; | |
200 | ||
201 | base_cpu = ravenscar_get_thread_base_cpu (ptid); | |
e99b03dc | 202 | return ptid_t (ptid.pid (), base_cpu, 0); |
9edcc12f JB |
203 | } |
204 | ||
036b1ba8 JB |
205 | /* Fetch the ravenscar running thread from target memory and |
206 | update inferior_ptid accordingly. */ | |
207 | ||
208 | static void | |
989f3c58 | 209 | ravenscar_update_inferior_ptid () |
036b1ba8 | 210 | { |
9edcc12f JB |
211 | int base_cpu; |
212 | ||
036b1ba8 JB |
213 | base_ptid = inferior_ptid; |
214 | ||
9edcc12f JB |
215 | gdb_assert (!is_ravenscar_task (inferior_ptid)); |
216 | base_cpu = ravenscar_get_thread_base_cpu (base_ptid); | |
217 | ||
036b1ba8 JB |
218 | /* If the runtime has not been initialized yet, the inferior_ptid is |
219 | the only ptid that there is. */ | |
220 | if (!ravenscar_runtime_initialized ()) | |
221 | return; | |
222 | ||
9edcc12f | 223 | /* Make sure we set base_ptid before calling ravenscar_active_task |
036b1ba8 | 224 | as the latter relies on it. */ |
9edcc12f | 225 | inferior_ptid = ravenscar_active_task (base_cpu); |
d7e15655 | 226 | gdb_assert (inferior_ptid != null_ptid); |
036b1ba8 JB |
227 | |
228 | /* The running thread may not have been added to | |
e8032dde | 229 | system.tasking.debug's list yet; so ravenscar_update_thread_list |
036b1ba8 JB |
230 | may not always add it to the thread list. Add it here. */ |
231 | if (!find_thread_ptid (inferior_ptid)) | |
232 | add_thread (inferior_ptid); | |
233 | } | |
234 | ||
7f39f34a JB |
235 | /* The Ravenscar Runtime exports a symbol which contains the ID of |
236 | the thread that is currently running. Try to locate that symbol | |
237 | and return its associated minimal symbol. | |
238 | Return NULL if not found. */ | |
239 | ||
3b7344d5 | 240 | static struct bound_minimal_symbol |
989f3c58 | 241 | get_running_thread_msymbol () |
7f39f34a | 242 | { |
3b7344d5 | 243 | struct bound_minimal_symbol msym; |
7f39f34a JB |
244 | |
245 | msym = lookup_minimal_symbol (running_thread_name, NULL, NULL); | |
3b7344d5 | 246 | if (!msym.minsym) |
7f39f34a JB |
247 | /* Older versions of the GNAT runtime were using a different |
248 | (less ideal) name for the symbol where the active thread ID | |
249 | is stored. If we couldn't find the symbol using the latest | |
250 | name, then try the old one. */ | |
251 | msym = lookup_minimal_symbol ("running_thread", NULL, NULL); | |
252 | ||
253 | return msym; | |
254 | } | |
255 | ||
036b1ba8 JB |
256 | /* Return True if the Ada Ravenscar run-time can be found in the |
257 | application. */ | |
258 | ||
989f3c58 TT |
259 | static bool |
260 | has_ravenscar_runtime () | |
036b1ba8 | 261 | { |
6cbcc006 TT |
262 | struct bound_minimal_symbol msym_ravenscar_runtime_initializer |
263 | = lookup_minimal_symbol (ravenscar_runtime_initializer, NULL, NULL); | |
264 | struct bound_minimal_symbol msym_known_tasks | |
265 | = lookup_minimal_symbol (known_tasks_name, NULL, NULL); | |
266 | struct bound_minimal_symbol msym_first_task | |
267 | = lookup_minimal_symbol (first_task_name, NULL, NULL); | |
3b7344d5 TT |
268 | struct bound_minimal_symbol msym_running_thread |
269 | = get_running_thread_msymbol (); | |
036b1ba8 | 270 | |
3b7344d5 TT |
271 | return (msym_ravenscar_runtime_initializer.minsym |
272 | && (msym_known_tasks.minsym || msym_first_task.minsym) | |
273 | && msym_running_thread.minsym); | |
036b1ba8 JB |
274 | } |
275 | ||
276 | /* Return True if the Ada Ravenscar run-time can be found in the | |
277 | application, and if it has been initialized on target. */ | |
278 | ||
989f3c58 TT |
279 | static bool |
280 | ravenscar_runtime_initialized () | |
036b1ba8 | 281 | { |
989f3c58 | 282 | return ravenscar_active_task (1) != null_ptid; |
036b1ba8 JB |
283 | } |
284 | ||
7f39f34a JB |
285 | /* Return the ID of the thread that is currently running. |
286 | Return 0 if the ID could not be determined. */ | |
036b1ba8 JB |
287 | |
288 | static CORE_ADDR | |
9edcc12f | 289 | get_running_thread_id (int cpu) |
036b1ba8 | 290 | { |
3b7344d5 | 291 | struct bound_minimal_symbol object_msym = get_running_thread_msymbol (); |
036b1ba8 JB |
292 | int object_size; |
293 | int buf_size; | |
948f8e3d | 294 | gdb_byte *buf; |
036b1ba8 | 295 | CORE_ADDR object_addr; |
6cbcc006 TT |
296 | struct type *builtin_type_void_data_ptr |
297 | = builtin_type (target_gdbarch ())->builtin_data_ptr; | |
036b1ba8 | 298 | |
3b7344d5 | 299 | if (!object_msym.minsym) |
036b1ba8 JB |
300 | return 0; |
301 | ||
036b1ba8 | 302 | object_size = TYPE_LENGTH (builtin_type_void_data_ptr); |
9edcc12f JB |
303 | object_addr = (BMSYMBOL_VALUE_ADDRESS (object_msym) |
304 | + (cpu - 1) * object_size); | |
036b1ba8 | 305 | buf_size = object_size; |
224c3ddb | 306 | buf = (gdb_byte *) alloca (buf_size); |
036b1ba8 JB |
307 | read_memory (object_addr, buf, buf_size); |
308 | return extract_typed_address (buf, builtin_type_void_data_ptr); | |
309 | } | |
310 | ||
f6ac5f3d | 311 | void |
6cbcc006 TT |
312 | ravenscar_thread_target::resume (ptid_t ptid, int step, |
313 | enum gdb_signal siggnal) | |
036b1ba8 | 314 | { |
036b1ba8 | 315 | inferior_ptid = base_ptid; |
d6ca69cd | 316 | beneath ()->resume (base_ptid, step, siggnal); |
036b1ba8 JB |
317 | } |
318 | ||
f6ac5f3d PA |
319 | ptid_t |
320 | ravenscar_thread_target::wait (ptid_t ptid, | |
321 | struct target_waitstatus *status, | |
322 | int options) | |
036b1ba8 | 323 | { |
3b1b69bf | 324 | ptid_t event_ptid; |
036b1ba8 JB |
325 | |
326 | inferior_ptid = base_ptid; | |
d6ca69cd | 327 | event_ptid = beneath ()->wait (base_ptid, status, 0); |
bed0c243 JB |
328 | /* Find any new threads that might have been created, and update |
329 | inferior_ptid to the active thread. | |
330 | ||
331 | Only do it if the program is still alive, though. Otherwise, | |
332 | this causes problems when debugging through the remote protocol, | |
333 | because we might try switching threads (and thus sending packets) | |
334 | after the remote has disconnected. */ | |
335 | if (status->kind != TARGET_WAITKIND_EXITED | |
336 | && status->kind != TARGET_WAITKIND_SIGNALLED) | |
337 | { | |
3b1b69bf | 338 | inferior_ptid = event_ptid; |
f6ac5f3d | 339 | this->update_thread_list (); |
bed0c243 JB |
340 | ravenscar_update_inferior_ptid (); |
341 | } | |
036b1ba8 JB |
342 | return inferior_ptid; |
343 | } | |
344 | ||
345 | /* Add the thread associated to the given TASK to the thread list | |
346 | (if the thread has already been added, this is a no-op). */ | |
347 | ||
348 | static void | |
349 | ravenscar_add_thread (struct ada_task_info *task) | |
350 | { | |
351 | if (find_thread_ptid (task->ptid) == NULL) | |
352 | add_thread (task->ptid); | |
353 | } | |
354 | ||
f6ac5f3d PA |
355 | void |
356 | ravenscar_thread_target::update_thread_list () | |
036b1ba8 | 357 | { |
79779fa9 | 358 | ada_build_task_list (); |
036b1ba8 JB |
359 | |
360 | /* Do not clear the thread list before adding the Ada task, to keep | |
361 | the thread that the process stratum has included into it | |
362 | (base_ptid) and the running thread, that may not have been included | |
363 | to system.tasking.debug's list yet. */ | |
364 | ||
365 | iterate_over_live_ada_tasks (ravenscar_add_thread); | |
366 | } | |
367 | ||
368 | static ptid_t | |
9edcc12f | 369 | ravenscar_active_task (int cpu) |
036b1ba8 | 370 | { |
9edcc12f | 371 | CORE_ADDR tid = get_running_thread_id (cpu); |
036b1ba8 JB |
372 | |
373 | if (tid == 0) | |
374 | return null_ptid; | |
375 | else | |
e99b03dc | 376 | return ptid_t (base_ptid.pid (), 0, tid); |
036b1ba8 JB |
377 | } |
378 | ||
f6ac5f3d PA |
379 | const char * |
380 | ravenscar_thread_target::extra_thread_info (thread_info *tp) | |
036b1ba8 JB |
381 | { |
382 | return "Ravenscar task"; | |
383 | } | |
384 | ||
57810aa7 | 385 | bool |
f6ac5f3d | 386 | ravenscar_thread_target::thread_alive (ptid_t ptid) |
036b1ba8 JB |
387 | { |
388 | /* Ravenscar tasks are non-terminating. */ | |
57810aa7 | 389 | return true; |
036b1ba8 JB |
390 | } |
391 | ||
f6ac5f3d PA |
392 | const char * |
393 | ravenscar_thread_target::pid_to_str (ptid_t ptid) | |
036b1ba8 JB |
394 | { |
395 | static char buf[30]; | |
396 | ||
cc6bcb54 | 397 | snprintf (buf, sizeof (buf), "Thread %#x", (int) ptid.tid ()); |
036b1ba8 JB |
398 | return buf; |
399 | } | |
400 | ||
f6ac5f3d PA |
401 | void |
402 | ravenscar_thread_target::fetch_registers (struct regcache *regcache, int regnum) | |
036b1ba8 | 403 | { |
222312d3 | 404 | ptid_t ptid = regcache->ptid (); |
036b1ba8 | 405 | |
9edcc12f JB |
406 | if (ravenscar_runtime_initialized () |
407 | && is_ravenscar_task (ptid) | |
408 | && !ravenscar_task_is_currently_active (ptid)) | |
7e35103a | 409 | { |
ac7936df | 410 | struct gdbarch *gdbarch = regcache->arch (); |
7e35103a JB |
411 | struct ravenscar_arch_ops *arch_ops |
412 | = gdbarch_ravenscar_ops (gdbarch); | |
413 | ||
7657f14d | 414 | arch_ops->fetch_registers (regcache, regnum); |
7e35103a | 415 | } |
9edcc12f | 416 | else |
d6ca69cd | 417 | beneath ()->fetch_registers (regcache, regnum); |
036b1ba8 JB |
418 | } |
419 | ||
f6ac5f3d PA |
420 | void |
421 | ravenscar_thread_target::store_registers (struct regcache *regcache, | |
422 | int regnum) | |
036b1ba8 | 423 | { |
222312d3 | 424 | ptid_t ptid = regcache->ptid (); |
036b1ba8 | 425 | |
9edcc12f JB |
426 | if (ravenscar_runtime_initialized () |
427 | && is_ravenscar_task (ptid) | |
428 | && !ravenscar_task_is_currently_active (ptid)) | |
7e35103a | 429 | { |
ac7936df | 430 | struct gdbarch *gdbarch = regcache->arch (); |
7e35103a JB |
431 | struct ravenscar_arch_ops *arch_ops |
432 | = gdbarch_ravenscar_ops (gdbarch); | |
433 | ||
7657f14d | 434 | arch_ops->store_registers (regcache, regnum); |
7e35103a | 435 | } |
9edcc12f | 436 | else |
d6ca69cd | 437 | beneath ()->store_registers (regcache, regnum); |
036b1ba8 JB |
438 | } |
439 | ||
f6ac5f3d PA |
440 | void |
441 | ravenscar_thread_target::prepare_to_store (struct regcache *regcache) | |
036b1ba8 | 442 | { |
222312d3 | 443 | ptid_t ptid = regcache->ptid (); |
036b1ba8 | 444 | |
9edcc12f JB |
445 | if (ravenscar_runtime_initialized () |
446 | && is_ravenscar_task (ptid) | |
447 | && !ravenscar_task_is_currently_active (ptid)) | |
7e35103a | 448 | { |
7657f14d | 449 | /* Nothing. */ |
7e35103a | 450 | } |
9edcc12f | 451 | else |
d6ca69cd | 452 | beneath ()->prepare_to_store (regcache); |
036b1ba8 JB |
453 | } |
454 | ||
e02544b2 JB |
455 | /* Implement the to_stopped_by_sw_breakpoint target_ops "method". */ |
456 | ||
57810aa7 | 457 | bool |
f6ac5f3d | 458 | ravenscar_thread_target::stopped_by_sw_breakpoint () |
e02544b2 | 459 | { |
5b6ea500 TT |
460 | scoped_restore save_ptid = make_scoped_restore (&inferior_ptid); |
461 | inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid); | |
462 | return beneath ()->stopped_by_sw_breakpoint (); | |
e02544b2 JB |
463 | } |
464 | ||
465 | /* Implement the to_stopped_by_hw_breakpoint target_ops "method". */ | |
466 | ||
57810aa7 | 467 | bool |
f6ac5f3d | 468 | ravenscar_thread_target::stopped_by_hw_breakpoint () |
e02544b2 | 469 | { |
5b6ea500 TT |
470 | scoped_restore save_ptid = make_scoped_restore (&inferior_ptid); |
471 | inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid); | |
472 | return beneath ()->stopped_by_hw_breakpoint (); | |
e02544b2 JB |
473 | } |
474 | ||
475 | /* Implement the to_stopped_by_watchpoint target_ops "method". */ | |
476 | ||
57810aa7 | 477 | bool |
f6ac5f3d | 478 | ravenscar_thread_target::stopped_by_watchpoint () |
e02544b2 | 479 | { |
5b6ea500 TT |
480 | scoped_restore save_ptid = make_scoped_restore (&inferior_ptid); |
481 | inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid); | |
482 | return beneath ()->stopped_by_watchpoint (); | |
e02544b2 JB |
483 | } |
484 | ||
485 | /* Implement the to_stopped_data_address target_ops "method". */ | |
486 | ||
57810aa7 | 487 | bool |
f6ac5f3d | 488 | ravenscar_thread_target::stopped_data_address (CORE_ADDR *addr_p) |
e02544b2 | 489 | { |
5b6ea500 TT |
490 | scoped_restore save_ptid = make_scoped_restore (&inferior_ptid); |
491 | inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid); | |
492 | return beneath ()->stopped_data_address (addr_p); | |
e02544b2 JB |
493 | } |
494 | ||
f6ac5f3d PA |
495 | void |
496 | ravenscar_thread_target::mourn_inferior () | |
036b1ba8 | 497 | { |
036b1ba8 | 498 | base_ptid = null_ptid; |
d6ca69cd | 499 | beneath ()->mourn_inferior (); |
036b1ba8 JB |
500 | unpush_target (&ravenscar_ops); |
501 | } | |
502 | ||
e02544b2 JB |
503 | /* Implement the to_core_of_thread target_ops "method". */ |
504 | ||
f6ac5f3d PA |
505 | int |
506 | ravenscar_thread_target::core_of_thread (ptid_t ptid) | |
e02544b2 | 507 | { |
5b6ea500 TT |
508 | scoped_restore save_ptid = make_scoped_restore (&inferior_ptid); |
509 | inferior_ptid = get_base_thread_from_ravenscar_task (inferior_ptid); | |
510 | return beneath ()->core_of_thread (inferior_ptid); | |
e02544b2 JB |
511 | } |
512 | ||
036b1ba8 JB |
513 | /* Observer on inferior_created: push ravenscar thread stratum if needed. */ |
514 | ||
515 | static void | |
516 | ravenscar_inferior_created (struct target_ops *target, int from_tty) | |
517 | { | |
cf3fbed4 | 518 | const char *err_msg; |
7e35103a JB |
519 | |
520 | if (!ravenscar_task_support | |
7dc7c195 | 521 | || gdbarch_ravenscar_ops (target_gdbarch ()) == NULL |
7e35103a | 522 | || !has_ravenscar_runtime ()) |
25abf4de JB |
523 | return; |
524 | ||
cf3fbed4 JB |
525 | err_msg = ada_get_tcb_types_info (); |
526 | if (err_msg != NULL) | |
527 | { | |
8f6cb6c3 | 528 | warning (_("%s. Task/thread support disabled."), err_msg); |
cf3fbed4 JB |
529 | return; |
530 | } | |
531 | ||
25abf4de JB |
532 | ravenscar_update_inferior_ptid (); |
533 | push_target (&ravenscar_ops); | |
036b1ba8 JB |
534 | } |
535 | ||
f6ac5f3d PA |
536 | ptid_t |
537 | ravenscar_thread_target::get_ada_task_ptid (long lwp, long thread) | |
036b1ba8 | 538 | { |
e99b03dc | 539 | return ptid_t (base_ptid.pid (), 0, thread); |
036b1ba8 JB |
540 | } |
541 | ||
036b1ba8 JB |
542 | /* Command-list for the "set/show ravenscar" prefix command. */ |
543 | static struct cmd_list_element *set_ravenscar_list; | |
544 | static struct cmd_list_element *show_ravenscar_list; | |
545 | ||
546 | /* Implement the "set ravenscar" prefix command. */ | |
547 | ||
548 | static void | |
981a3fb3 | 549 | set_ravenscar_command (const char *arg, int from_tty) |
036b1ba8 JB |
550 | { |
551 | printf_unfiltered (_(\ | |
552 | "\"set ravenscar\" must be followed by the name of a setting.\n")); | |
635c7e8a | 553 | help_list (set_ravenscar_list, "set ravenscar ", all_commands, gdb_stdout); |
036b1ba8 JB |
554 | } |
555 | ||
556 | /* Implement the "show ravenscar" prefix command. */ | |
557 | ||
558 | static void | |
981a3fb3 | 559 | show_ravenscar_command (const char *args, int from_tty) |
036b1ba8 JB |
560 | { |
561 | cmd_show_list (show_ravenscar_list, from_tty, ""); | |
562 | } | |
563 | ||
564 | /* Implement the "show ravenscar task-switching" command. */ | |
565 | ||
566 | static void | |
567 | show_ravenscar_task_switching_command (struct ui_file *file, int from_tty, | |
568 | struct cmd_list_element *c, | |
569 | const char *value) | |
570 | { | |
571 | if (ravenscar_task_support) | |
572 | fprintf_filtered (file, _("\ | |
b64edec4 | 573 | Support for Ravenscar task/thread switching is enabled\n")); |
036b1ba8 JB |
574 | else |
575 | fprintf_filtered (file, _("\ | |
b64edec4 | 576 | Support for Ravenscar task/thread switching is disabled\n")); |
036b1ba8 JB |
577 | } |
578 | ||
579 | /* Module startup initialization function, automagically called by | |
580 | init.c. */ | |
581 | ||
582 | void | |
989f3c58 | 583 | _initialize_ravenscar () |
036b1ba8 | 584 | { |
036b1ba8 JB |
585 | base_ptid = null_ptid; |
586 | ||
587 | /* Notice when the inferior is created in order to push the | |
588 | ravenscar ops if needed. */ | |
76727919 | 589 | gdb::observers::inferior_created.attach (ravenscar_inferior_created); |
036b1ba8 | 590 | |
036b1ba8 JB |
591 | add_prefix_cmd ("ravenscar", no_class, set_ravenscar_command, |
592 | _("Prefix command for changing Ravenscar-specific settings"), | |
593 | &set_ravenscar_list, "set ravenscar ", 0, &setlist); | |
594 | ||
595 | add_prefix_cmd ("ravenscar", no_class, show_ravenscar_command, | |
596 | _("Prefix command for showing Ravenscar-specific settings"), | |
04f9d4d0 | 597 | &show_ravenscar_list, "show ravenscar ", 0, &showlist); |
036b1ba8 JB |
598 | |
599 | add_setshow_boolean_cmd ("task-switching", class_obscure, | |
600 | &ravenscar_task_support, _("\ | |
601 | Enable or disable support for GNAT Ravenscar tasks"), _("\ | |
602 | Show whether support for GNAT Ravenscar tasks is enabled"), | |
603 | _("\ | |
604 | Enable or disable support for task/thread switching with the GNAT\n\ | |
605 | Ravenscar run-time library for bareboard configuration."), | |
606 | NULL, show_ravenscar_task_switching_command, | |
607 | &set_ravenscar_list, &show_ravenscar_list); | |
608 | } |