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