1 /* Copyright (C) 2021-2023 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 #include "gdbsupport/tdesc.h" 28 29 /* Structure for passing information from GCORE_COLLECT_THREAD_REGISTERS 30 via an iterator to GCORE_COLLECT_REGSET_SECTION_CB. */ 31 32 struct gcore_elf_collect_regset_section_cb_data 33 { 34 gcore_elf_collect_regset_section_cb_data 35 (struct gdbarch *gdbarch, const struct regcache *regcache, 36 bfd *obfd, ptid_t ptid, gdb_signal stop_signal, 37 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size) 38 : gdbarch (gdbarch), regcache (regcache), obfd (obfd), 39 note_data (note_data), note_size (note_size), 40 stop_signal (stop_signal) 41 { 42 /* The LWP is often not available for bare metal target, in which case 43 use the tid instead. */ 44 if (ptid.lwp_p ()) 45 lwp = ptid.lwp (); 46 else 47 lwp = ptid.tid (); 48 } 49 50 struct gdbarch *gdbarch; 51 const struct regcache *regcache; 52 bfd *obfd; 53 gdb::unique_xmalloc_ptr<char> *note_data; 54 int *note_size; 55 unsigned long lwp; 56 enum gdb_signal stop_signal; 57 bool abort_iteration = false; 58 }; 59 60 /* Callback for ITERATE_OVER_REGSET_SECTIONS that records a single 61 regset in the core file note section. */ 62 63 static void 64 gcore_elf_collect_regset_section_cb (const char *sect_name, 65 int supply_size, int collect_size, 66 const struct regset *regset, 67 const char *human_name, void *cb_data) 68 { 69 struct gcore_elf_collect_regset_section_cb_data *data 70 = (struct gcore_elf_collect_regset_section_cb_data *) cb_data; 71 bool variable_size_section = (regset != nullptr 72 && regset->flags & REGSET_VARIABLE_SIZE); 73 74 gdb_assert (variable_size_section || supply_size == collect_size); 75 76 if (data->abort_iteration) 77 return; 78 79 gdb_assert (regset != nullptr && regset->collect_regset != nullptr); 80 81 /* This is intentionally zero-initialized by using std::vector, so 82 that any padding bytes in the core file will show as 0. */ 83 std::vector<gdb_byte> buf (collect_size); 84 85 regset->collect_regset (regset, data->regcache, -1, buf.data (), 86 collect_size); 87 88 /* PRSTATUS still needs to be treated specially. */ 89 if (strcmp (sect_name, ".reg") == 0) 90 data->note_data->reset (elfcore_write_prstatus 91 (data->obfd, data->note_data->release (), 92 data->note_size, data->lwp, 93 gdb_signal_to_host (data->stop_signal), 94 buf.data ())); 95 else 96 data->note_data->reset (elfcore_write_register_note 97 (data->obfd, data->note_data->release (), 98 data->note_size, sect_name, buf.data (), 99 collect_size)); 100 101 if (*data->note_data == nullptr) 102 data->abort_iteration = true; 103 } 104 105 /* Records the register state of thread PTID out of REGCACHE into the note 106 buffer represented by *NOTE_DATA and NOTE_SIZE. OBFD is the bfd into 107 which the core file is being created, and STOP_SIGNAL is the signal that 108 cause thread PTID to stop. */ 109 110 static void 111 gcore_elf_collect_thread_registers 112 (const struct regcache *regcache, ptid_t ptid, bfd *obfd, 113 gdb::unique_xmalloc_ptr<char> *note_data, int *note_size, 114 enum gdb_signal stop_signal) 115 { 116 struct gdbarch *gdbarch = regcache->arch (); 117 gcore_elf_collect_regset_section_cb_data data (gdbarch, regcache, obfd, 118 ptid, stop_signal, 119 note_data, note_size); 120 gdbarch_iterate_over_regset_sections 121 (gdbarch, gcore_elf_collect_regset_section_cb, &data, regcache); 122 } 123 124 /* See gcore-elf.h. */ 125 126 void 127 gcore_elf_build_thread_register_notes 128 (struct gdbarch *gdbarch, struct thread_info *info, gdb_signal stop_signal, 129 bfd *obfd, gdb::unique_xmalloc_ptr<char> *note_data, int *note_size) 130 { 131 struct regcache *regcache 132 = get_thread_arch_regcache (info->inf->process_target (), 133 info->ptid, gdbarch); 134 target_fetch_registers (regcache, -1); 135 gcore_elf_collect_thread_registers (regcache, info->ptid, obfd, 136 note_data, note_size, stop_signal); 137 } 138 139 /* See gcore-elf.h. */ 140 141 void 142 gcore_elf_make_tdesc_note (bfd *obfd, 143 gdb::unique_xmalloc_ptr<char> *note_data, 144 int *note_size) 145 { 146 /* Append the target description to the core file. */ 147 const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ()); 148 const char *tdesc_xml 149 = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc); 150 if (tdesc_xml != nullptr && *tdesc_xml != '\0') 151 { 152 /* Skip the leading '@'. */ 153 if (*tdesc_xml == '@') 154 ++tdesc_xml; 155 156 /* Include the null terminator in the length. */ 157 size_t tdesc_len = strlen (tdesc_xml) + 1; 158 159 /* Now add the target description into the core file. */ 160 note_data->reset (elfcore_write_register_note (obfd, 161 note_data->release (), 162 note_size, 163 ".gdb-tdesc", tdesc_xml, 164 tdesc_len)); 165 } 166 } 167