Commit | Line | Data |
---|---|---|
f3a5df7b AB |
1 | /* Copyright (C) 2021 Free Software Foundation, Inc. |
2 | ||
3 | This file is part of GDB. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #include "defs.h" | |
19 | #include "gcore-elf.h" | |
20 | #include "elf-bfd.h" | |
21 | #include "target.h" | |
22 | #include "regcache.h" | |
23 | #include "gdbarch.h" | |
24 | #include "gdbthread.h" | |
25 | #include "inferior.h" | |
26 | #include "regset.h" | |
27 | ||
28 | /* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS | |
29 | via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */ | |
30 | ||
31 | struct gcore_elf_collect_regset_section_cb_data | |
32 | { | |
33 | gcore_elf_collect_regset_section_cb_data | |
34 | (struct gdbarch *gdbarch, const struct regcache *regcache, | |
35 | bfd *obfd, ptid_t ptid, gdb_signal stop_signal, | |
36 | gdb::unique_xmalloc_ptr<char> *note_data, int *note_size) | |
37 | : gdbarch (gdbarch), regcache (regcache), obfd (obfd), | |
38 | note_data (note_data), note_size (note_size), | |
39 | stop_signal (stop_signal) | |
40 | { | |
41 | /* The LWP is often not available for bare metal target, in which case | |
42 | use the tid instead. */ | |
43 | if (ptid.lwp_p ()) | |
44 | lwp = ptid.lwp (); | |
45 | else | |
46 | lwp = ptid.tid (); | |
47 | } | |
48 | ||
49 | struct gdbarch *gdbarch; | |
50 | const struct regcache *regcache; | |
51 | bfd *obfd; | |
52 | gdb::unique_xmalloc_ptr<char> *note_data; | |
53 | int *note_size; | |
54 | unsigned long lwp; | |
55 | enum gdb_signal stop_signal; | |
56 | bool abort_iteration = false; | |
57 | }; | |
58 | ||
59 | /* Callback for ITERATE_OVER_REGSET_SECTIONS that records a single | |
60 | regset in the core file note section. */ | |
61 | ||
62 | static void | |
63 | gcore_elf_collect_regset_section_cb (const char *sect_name, | |
64 | int supply_size, int collect_size, | |
65 | const struct regset *regset, | |
66 | const char *human_name, void *cb_data) | |
67 | { | |
68 | struct gcore_elf_collect_regset_section_cb_data *data | |
69 | = (struct gcore_elf_collect_regset_section_cb_data *) cb_data; | |
70 | bool variable_size_section = (regset != nullptr | |
71 | && regset->flags & REGSET_VARIABLE_SIZE); | |
72 | ||
73 | gdb_assert (variable_size_section || supply_size == collect_size); | |
74 | ||
75 | if (data->abort_iteration) | |
76 | return; | |
77 | ||
78 | gdb_assert (regset != nullptr && regset->collect_regset != nullptr); | |
79 | ||
80 | /* This is intentionally zero-initialized by using std::vector, so | |
81 | that any padding bytes in the core file will show as 0. */ | |
82 | std::vector<gdb_byte> buf (collect_size); | |
83 | ||
84 | regset->collect_regset (regset, data->regcache, -1, buf.data (), | |
85 | collect_size); | |
86 | ||
87 | /* PRSTATUS still needs to be treated specially. */ | |
88 | if (strcmp (sect_name, ".reg") == 0) | |
89 | data->note_data->reset (elfcore_write_prstatus | |
90 | (data->obfd, data->note_data->release (), | |
91 | data->note_size, data->lwp, | |
92 | gdb_signal_to_host (data->stop_signal), | |
93 | buf.data ())); | |
94 | else | |
95 | data->note_data->reset (elfcore_write_register_note | |
96 | (data->obfd, data->note_data->release (), | |
97 | data->note_size, sect_name, buf.data (), | |
98 | collect_size)); | |
99 | ||
100 | if (*data->note_data == nullptr) | |
101 | data->abort_iteration = true; | |
102 | } | |
103 | ||
104 | /* Records the register state of thread PTID out of REGCACHE into the note | |
105 | buffer represented by *NOTE_DATA and NOTE_SIZE. OBFD is the bfd into | |
106 | which the core file is being created, and STOP_SIGNAL is the signal that | |
107 | cause thread PTID to stop. */ | |
108 | ||
109 | static void | |
110 | gcore_elf_collect_thread_registers | |
111 | (const struct regcache *regcache, ptid_t ptid, bfd *obfd, | |
112 | gdb::unique_xmalloc_ptr<char> *note_data, int *note_size, | |
113 | enum gdb_signal stop_signal) | |
114 | { | |
115 | struct gdbarch *gdbarch = regcache->arch (); | |
116 | gcore_elf_collect_regset_section_cb_data data (gdbarch, regcache, obfd, | |
117 | ptid, stop_signal, | |
118 | note_data, note_size); | |
119 | gdbarch_iterate_over_regset_sections | |
120 | (gdbarch, gcore_elf_collect_regset_section_cb, &data, regcache); | |
121 | } | |
122 | ||
123 | /* See gcore-elf.h. */ | |
124 | ||
125 | void | |
126 | gcore_elf_build_thread_register_notes | |
127 | (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal, | |
128 | bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size) | |
129 | { | |
130 | struct regcache *regcache | |
131 | = get_thread_arch_regcache (info->inf->process_target (), | |
132 | info->ptid, gdbarch); | |
133 | target_fetch_registers (regcache, -1); | |
134 | gcore_elf_collect_thread_registers (regcache, info->ptid, obfd, | |
135 | note_data, note_size, stop_signal); | |
136 | } |