Commit | Line | Data |
---|---|---|
a904c024 AA |
1 | /* Target-dependent code for FreeBSD, architecture-independent. |
2 | ||
618f726f | 3 | Copyright (C) 2002-2016 Free Software Foundation, Inc. |
a904c024 AA |
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" | |
82372b2f | 21 | #include "auxv.h" |
a904c024 AA |
22 | #include "gdbcore.h" |
23 | #include "inferior.h" | |
24 | #include "regcache.h" | |
25 | #include "regset.h" | |
26 | #include "gdbthread.h" | |
27 | ||
a904c024 AA |
28 | #include "elf-bfd.h" |
29 | #include "fbsd-tdep.h" | |
30 | ||
31 | ||
79117428 JB |
32 | /* This is how we want PTIDs from core files to be printed. */ |
33 | ||
34 | static char * | |
35 | fbsd_core_pid_to_str (struct gdbarch *gdbarch, ptid_t ptid) | |
36 | { | |
37 | static char buf[80]; | |
38 | ||
39 | if (ptid_get_lwp (ptid) != 0) | |
40 | { | |
41 | xsnprintf (buf, sizeof buf, "LWP %ld", ptid_get_lwp (ptid)); | |
42 | return buf; | |
43 | } | |
44 | ||
45 | return normal_pid_to_str (ptid); | |
46 | } | |
47 | ||
48 | /* Extract the name assigned to a thread from a core. Returns the | |
49 | string in a static buffer. */ | |
50 | ||
51 | static const char * | |
52 | fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr) | |
53 | { | |
54 | static char buf[80]; | |
55 | struct bfd_section *section; | |
56 | bfd_size_type size; | |
57 | char sectionstr[32]; | |
58 | ||
59 | if (ptid_get_lwp (thr->ptid) != 0) | |
60 | { | |
61 | /* FreeBSD includes a NT_FREEBSD_THRMISC note for each thread | |
62 | whose contents are defined by a "struct thrmisc" declared in | |
63 | <sys/procfs.h> on FreeBSD. The per-thread name is stored as | |
64 | a null-terminated string as the first member of the | |
65 | structure. Rather than define the full structure here, just | |
66 | extract the null-terminated name from the start of the | |
67 | note. */ | |
68 | xsnprintf (sectionstr, sizeof sectionstr, ".thrmisc/%ld", | |
69 | ptid_get_lwp (thr->ptid)); | |
70 | section = bfd_get_section_by_name (core_bfd, sectionstr); | |
71 | if (section != NULL && bfd_section_size (core_bfd, section) > 0) | |
72 | { | |
73 | /* Truncate the name if it is longer than "buf". */ | |
74 | size = bfd_section_size (core_bfd, section); | |
75 | if (size > sizeof buf - 1) | |
76 | size = sizeof buf - 1; | |
77 | if (bfd_get_section_contents (core_bfd, section, buf, (file_ptr) 0, | |
78 | size) | |
79 | && buf[0] != '\0') | |
80 | { | |
81 | buf[size] = '\0'; | |
82 | ||
83 | /* Note that each thread will report the process command | |
84 | as its thread name instead of an empty name if a name | |
85 | has not been set explicitly. Return a NULL name in | |
86 | that case. */ | |
87 | if (strcmp (buf, elf_tdata (core_bfd)->core->program) != 0) | |
88 | return buf; | |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | return NULL; | |
94 | } | |
95 | ||
a904c024 AA |
96 | static int |
97 | find_signalled_thread (struct thread_info *info, void *data) | |
98 | { | |
99 | if (info->suspend.stop_signal != GDB_SIGNAL_0 | |
100 | && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid)) | |
101 | return 1; | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
20a0aab3 JB |
106 | /* Structure for passing information from |
107 | fbsd_collect_thread_registers via an iterator to | |
108 | fbsd_collect_regset_section_cb. */ | |
a904c024 AA |
109 | |
110 | struct fbsd_collect_regset_section_cb_data | |
111 | { | |
112 | const struct regcache *regcache; | |
113 | bfd *obfd; | |
114 | char *note_data; | |
115 | int *note_size; | |
20a0aab3 JB |
116 | unsigned long lwp; |
117 | enum gdb_signal stop_signal; | |
118 | int abort_iteration; | |
a904c024 AA |
119 | }; |
120 | ||
121 | static void | |
122 | fbsd_collect_regset_section_cb (const char *sect_name, int size, | |
123 | const struct regset *regset, | |
124 | const char *human_name, void *cb_data) | |
125 | { | |
126 | char *buf; | |
7567e115 SM |
127 | struct fbsd_collect_regset_section_cb_data *data |
128 | = (struct fbsd_collect_regset_section_cb_data *) cb_data; | |
a904c024 | 129 | |
20a0aab3 JB |
130 | if (data->abort_iteration) |
131 | return; | |
132 | ||
a904c024 AA |
133 | gdb_assert (regset->collect_regset); |
134 | ||
224c3ddb | 135 | buf = (char *) xmalloc (size); |
a904c024 AA |
136 | regset->collect_regset (regset, data->regcache, -1, buf, size); |
137 | ||
138 | /* PRSTATUS still needs to be treated specially. */ | |
139 | if (strcmp (sect_name, ".reg") == 0) | |
140 | data->note_data = (char *) elfcore_write_prstatus | |
20a0aab3 JB |
141 | (data->obfd, data->note_data, data->note_size, data->lwp, |
142 | gdb_signal_to_host (data->stop_signal), buf); | |
a904c024 AA |
143 | else |
144 | data->note_data = (char *) elfcore_write_register_note | |
145 | (data->obfd, data->note_data, data->note_size, | |
146 | sect_name, buf, size); | |
147 | xfree (buf); | |
20a0aab3 JB |
148 | |
149 | if (data->note_data == NULL) | |
150 | data->abort_iteration = 1; | |
151 | } | |
152 | ||
153 | /* Records the thread's register state for the corefile note | |
154 | section. */ | |
155 | ||
156 | static char * | |
157 | fbsd_collect_thread_registers (const struct regcache *regcache, | |
158 | ptid_t ptid, bfd *obfd, | |
159 | char *note_data, int *note_size, | |
160 | enum gdb_signal stop_signal) | |
161 | { | |
162 | struct gdbarch *gdbarch = get_regcache_arch (regcache); | |
163 | struct fbsd_collect_regset_section_cb_data data; | |
164 | ||
165 | data.regcache = regcache; | |
166 | data.obfd = obfd; | |
167 | data.note_data = note_data; | |
168 | data.note_size = note_size; | |
169 | data.stop_signal = stop_signal; | |
170 | data.abort_iteration = 0; | |
171 | data.lwp = ptid_get_lwp (ptid); | |
172 | ||
173 | gdbarch_iterate_over_regset_sections (gdbarch, | |
174 | fbsd_collect_regset_section_cb, | |
175 | &data, regcache); | |
176 | return data.note_data; | |
177 | } | |
178 | ||
179 | struct fbsd_corefile_thread_data | |
180 | { | |
181 | struct gdbarch *gdbarch; | |
182 | bfd *obfd; | |
183 | char *note_data; | |
184 | int *note_size; | |
185 | enum gdb_signal stop_signal; | |
186 | }; | |
187 | ||
188 | /* Records the thread's register state for the corefile note | |
189 | section. */ | |
190 | ||
191 | static void | |
192 | fbsd_corefile_thread (struct thread_info *info, | |
193 | struct fbsd_corefile_thread_data *args) | |
194 | { | |
195 | struct cleanup *old_chain; | |
196 | struct regcache *regcache; | |
197 | ||
198 | regcache = get_thread_arch_regcache (info->ptid, args->gdbarch); | |
199 | ||
200 | old_chain = save_inferior_ptid (); | |
201 | inferior_ptid = info->ptid; | |
202 | target_fetch_registers (regcache, -1); | |
203 | do_cleanups (old_chain); | |
204 | ||
205 | args->note_data = fbsd_collect_thread_registers | |
206 | (regcache, info->ptid, args->obfd, args->note_data, | |
207 | args->note_size, args->stop_signal); | |
a904c024 AA |
208 | } |
209 | ||
210 | /* Create appropriate note sections for a corefile, returning them in | |
211 | allocated memory. */ | |
212 | ||
213 | static char * | |
214 | fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) | |
215 | { | |
20a0aab3 JB |
216 | struct fbsd_corefile_thread_data thread_args; |
217 | char *note_data = NULL; | |
a904c024 | 218 | Elf_Internal_Ehdr *i_ehdrp; |
20a0aab3 | 219 | struct thread_info *curr_thr, *signalled_thr, *thr; |
a904c024 AA |
220 | |
221 | /* Put a "FreeBSD" label in the ELF header. */ | |
222 | i_ehdrp = elf_elfheader (obfd); | |
223 | i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | |
224 | ||
225 | gdb_assert (gdbarch_iterate_over_regset_sections_p (gdbarch)); | |
226 | ||
a904c024 AA |
227 | if (get_exec_file (0)) |
228 | { | |
229 | const char *fname = lbasename (get_exec_file (0)); | |
230 | char *psargs = xstrdup (fname); | |
231 | ||
232 | if (get_inferior_args ()) | |
233 | psargs = reconcat (psargs, psargs, " ", get_inferior_args (), | |
234 | (char *) NULL); | |
235 | ||
236 | note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, | |
237 | fname, psargs); | |
238 | } | |
239 | ||
20a0aab3 JB |
240 | /* Thread register information. */ |
241 | TRY | |
242 | { | |
243 | update_thread_list (); | |
244 | } | |
245 | CATCH (e, RETURN_MASK_ERROR) | |
246 | { | |
247 | exception_print (gdb_stderr, e); | |
248 | } | |
249 | END_CATCH | |
250 | ||
251 | /* Like the kernel, prefer dumping the signalled thread first. | |
252 | "First thread" is what tools use to infer the signalled thread. | |
253 | In case there's more than one signalled thread, prefer the | |
254 | current thread, if it is signalled. */ | |
255 | curr_thr = inferior_thread (); | |
256 | if (curr_thr->suspend.stop_signal != GDB_SIGNAL_0) | |
257 | signalled_thr = curr_thr; | |
258 | else | |
259 | { | |
260 | signalled_thr = iterate_over_threads (find_signalled_thread, NULL); | |
261 | if (signalled_thr == NULL) | |
262 | signalled_thr = curr_thr; | |
263 | } | |
264 | ||
265 | thread_args.gdbarch = gdbarch; | |
266 | thread_args.obfd = obfd; | |
267 | thread_args.note_data = note_data; | |
268 | thread_args.note_size = note_size; | |
269 | thread_args.stop_signal = signalled_thr->suspend.stop_signal; | |
270 | ||
271 | fbsd_corefile_thread (signalled_thr, &thread_args); | |
272 | ALL_NON_EXITED_THREADS (thr) | |
273 | { | |
274 | if (thr == signalled_thr) | |
275 | continue; | |
276 | if (ptid_get_pid (thr->ptid) != ptid_get_pid (inferior_ptid)) | |
277 | continue; | |
278 | ||
279 | fbsd_corefile_thread (thr, &thread_args); | |
280 | } | |
281 | ||
282 | note_data = thread_args.note_data; | |
283 | ||
a904c024 AA |
284 | return note_data; |
285 | } | |
286 | ||
82372b2f JB |
287 | /* Print descriptions of FreeBSD-specific AUXV entries to FILE. */ |
288 | ||
289 | static void | |
290 | fbsd_print_auxv_entry (struct gdbarch *gdbarch, struct ui_file *file, | |
291 | CORE_ADDR type, CORE_ADDR val) | |
292 | { | |
293 | const char *name; | |
294 | const char *description; | |
295 | enum auxv_format format; | |
296 | ||
297 | switch (type) | |
298 | { | |
299 | #define _TAGNAME(tag) #tag | |
300 | #define TAGNAME(tag) _TAGNAME(AT_##tag) | |
301 | #define TAG(tag, text, kind) \ | |
302 | case AT_FREEBSD_##tag: name = TAGNAME(tag); description = text; format = kind; break | |
303 | TAG (EXECPATH, _("Executable path"), AUXV_FORMAT_STR); | |
304 | TAG (CANARY, _("Canary for SSP"), AUXV_FORMAT_HEX); | |
305 | TAG (CANARYLEN, ("Length of the SSP canary"), AUXV_FORMAT_DEC); | |
306 | TAG (OSRELDATE, _("OSRELDATE"), AUXV_FORMAT_DEC); | |
307 | TAG (NCPUS, _("Number of CPUs"), AUXV_FORMAT_DEC); | |
308 | TAG (PAGESIZES, _("Pagesizes"), AUXV_FORMAT_HEX); | |
309 | TAG (PAGESIZESLEN, _("Number of pagesizes"), AUXV_FORMAT_DEC); | |
310 | TAG (TIMEKEEP, _("Pointer to timehands"), AUXV_FORMAT_HEX); | |
311 | TAG (STACKPROT, _("Initial stack protection"), AUXV_FORMAT_HEX); | |
312 | default: | |
313 | default_print_auxv_entry (gdbarch, file, type, val); | |
314 | return; | |
315 | } | |
316 | ||
317 | fprint_auxv_entry (file, name, description, format, type, val); | |
318 | } | |
319 | ||
a904c024 AA |
320 | /* To be called from GDB_OSABI_FREEBSD_ELF handlers. */ |
321 | ||
322 | void | |
323 | fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
324 | { | |
79117428 JB |
325 | set_gdbarch_core_pid_to_str (gdbarch, fbsd_core_pid_to_str); |
326 | set_gdbarch_core_thread_name (gdbarch, fbsd_core_thread_name); | |
a904c024 | 327 | set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes); |
82372b2f | 328 | set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry); |
a904c024 | 329 | } |