Home | History | Annotate | Line # | Download | only in gdb
      1 /* Copyright (C) 2021-2024 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 "gcore-elf.h"
     19 #include "elf-bfd.h"
     20 #include "target.h"
     21 #include "regcache.h"
     22 #include "gdbarch.h"
     23 #include "gdbthread.h"
     24 #include "inferior.h"
     25 #include "regset.h"
     26 #include "gdbsupport/tdesc.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   regcache *regcache
    131     = get_thread_arch_regcache (info->inf, info->ptid, gdbarch);
    132   target_fetch_registers (regcache, -1);
    133   gcore_elf_collect_thread_registers (regcache, info->ptid, obfd,
    134 				      note_data, note_size, stop_signal);
    135 }
    136 
    137 /* See gcore-elf.h.  */
    138 
    139 void
    140 gcore_elf_make_tdesc_note (struct gdbarch *gdbarch, bfd *obfd,
    141 			   gdb::unique_xmalloc_ptr<char> *note_data,
    142 			   int *note_size)
    143 {
    144   /* Append the target description to the core file.  */
    145   const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
    146   const char *tdesc_xml
    147     = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
    148   if (tdesc_xml != nullptr && *tdesc_xml != '\0')
    149     {
    150       /* Skip the leading '@'.  */
    151       if (*tdesc_xml == '@')
    152 	++tdesc_xml;
    153 
    154       /* Include the null terminator in the length.  */
    155       size_t tdesc_len = strlen (tdesc_xml) + 1;
    156 
    157       /* Now add the target description into the core file.  */
    158       note_data->reset (elfcore_write_register_note (obfd,
    159 						     note_data->release (),
    160 						     note_size,
    161 						     ".gdb-tdesc", tdesc_xml,
    162 						     tdesc_len));
    163     }
    164 }
    165