| /* Target-dependent code for FreeBSD, architecture-independent. |
| |
| Copyright (C) 2002-2015 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #include "defs.h" |
| #include "gdbcore.h" |
| #include "inferior.h" |
| #include "regcache.h" |
| #include "regset.h" |
| #include "gdbthread.h" |
| |
| #include "elf-bfd.h" |
| #include "fbsd-tdep.h" |
| |
| |
| static int |
| find_signalled_thread (struct thread_info *info, void *data) |
| { |
| if (info->suspend.stop_signal != GDB_SIGNAL_0 |
| && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid)) |
| return 1; |
| |
| return 0; |
| } |
| |
| static enum gdb_signal |
| find_stop_signal (void) |
| { |
| struct thread_info *info = |
| iterate_over_threads (find_signalled_thread, NULL); |
| |
| if (info) |
| return info->suspend.stop_signal; |
| else |
| return GDB_SIGNAL_0; |
| } |
| |
| struct fbsd_collect_regset_section_cb_data |
| { |
| const struct regcache *regcache; |
| bfd *obfd; |
| char *note_data; |
| int *note_size; |
| }; |
| |
| static void |
| fbsd_collect_regset_section_cb (const char *sect_name, int size, |
| const struct regset *regset, |
| const char *human_name, void *cb_data) |
| { |
| char *buf; |
| struct fbsd_collect_regset_section_cb_data *data = cb_data; |
| |
| gdb_assert (regset->collect_regset); |
| |
| buf = xmalloc (size); |
| regset->collect_regset (regset, data->regcache, -1, buf, size); |
| |
| /* PRSTATUS still needs to be treated specially. */ |
| if (strcmp (sect_name, ".reg") == 0) |
| data->note_data = (char *) elfcore_write_prstatus |
| (data->obfd, data->note_data, data->note_size, |
| ptid_get_pid (inferior_ptid), find_stop_signal (), buf); |
| else |
| data->note_data = (char *) elfcore_write_register_note |
| (data->obfd, data->note_data, data->note_size, |
| sect_name, buf, size); |
| xfree (buf); |
| } |
| |
| /* Create appropriate note sections for a corefile, returning them in |
| allocated memory. */ |
| |
| static char * |
| fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size) |
| { |
| const struct regcache *regcache = get_current_regcache (); |
| char *note_data; |
| Elf_Internal_Ehdr *i_ehdrp; |
| struct fbsd_collect_regset_section_cb_data data; |
| |
| /* Put a "FreeBSD" label in the ELF header. */ |
| i_ehdrp = elf_elfheader (obfd); |
| i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
| |
| gdb_assert (gdbarch_iterate_over_regset_sections_p (gdbarch)); |
| |
| data.regcache = regcache; |
| data.obfd = obfd; |
| data.note_data = NULL; |
| data.note_size = note_size; |
| gdbarch_iterate_over_regset_sections (gdbarch, |
| fbsd_collect_regset_section_cb, |
| &data, regcache); |
| note_data = data.note_data; |
| |
| if (get_exec_file (0)) |
| { |
| const char *fname = lbasename (get_exec_file (0)); |
| char *psargs = xstrdup (fname); |
| |
| if (get_inferior_args ()) |
| psargs = reconcat (psargs, psargs, " ", get_inferior_args (), |
| (char *) NULL); |
| |
| note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, |
| fname, psargs); |
| } |
| |
| return note_data; |
| } |
| |
| /* To be called from GDB_OSABI_FREEBSD_ELF handlers. */ |
| |
| void |
| fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) |
| { |
| set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes); |
| } |