]> Git Repo - binutils.git/blob - gdb/tracefile.c
gdb: remove SYMBOL_CLASS macro, add getter
[binutils.git] / gdb / tracefile.c
1 /* Trace file support in GDB.
2
3    Copyright (C) 1997-2022 Free Software Foundation, Inc.
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"
21 #include "tracefile.h"
22 #include "tracectf.h"
23 #include "exec.h"
24 #include "regcache.h"
25 #include "gdbsupport/byte-vector.h"
26 #include "gdbarch.h"
27 #include "gdbsupport/buildargv.h"
28
29 /* Helper macros.  */
30
31 #define TRACE_WRITE_R_BLOCK(writer, buf, size)  \
32   writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
33 #define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size)            \
34   writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
35                                                 (size))
36 #define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size)     \
37   writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
38                                                 (size))
39 #define TRACE_WRITE_V_BLOCK(writer, num, val)   \
40   writer->ops->frame_ops->write_v_block ((writer), (num), (val))
41
42 /* A unique pointer policy class for trace_file_writer.  */
43
44 struct trace_file_writer_deleter
45 {
46   void operator() (struct trace_file_writer *writer)
47   {
48     writer->ops->dtor (writer);
49     xfree (writer);
50   }
51 };
52
53 /* A unique_ptr specialization for trace_file_writer.  */
54
55 typedef std::unique_ptr<trace_file_writer, trace_file_writer_deleter>
56     trace_file_writer_up;
57
58 /* Save tracepoint data to file named FILENAME through WRITER.  WRITER
59    determines the trace file format.  If TARGET_DOES_SAVE is non-zero,
60    the save is performed on the target, otherwise GDB obtains all trace
61    data and saves it locally.  */
62
63 static void
64 trace_save (const char *filename, struct trace_file_writer *writer,
65             int target_does_save)
66 {
67   struct trace_status *ts = current_trace_status ();
68   struct uploaded_tp *uploaded_tps = NULL, *utp;
69   struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
70
71   ULONGEST offset = 0;
72 #define MAX_TRACE_UPLOAD 2000
73   gdb::byte_vector buf (std::max (MAX_TRACE_UPLOAD, trace_regblock_size));
74   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
75
76   /* If the target is to save the data to a file on its own, then just
77      send the command and be done with it.  */
78   if (target_does_save)
79     {
80       if (!writer->ops->target_save (writer, filename))
81         error (_("Target failed to save trace data to '%s'."),
82                filename);
83       return;
84     }
85
86   /* Get the trace status first before opening the file, so if the
87      target is losing, we can get out without touching files.  Since
88      we're just calling this for side effects, we ignore the
89      result.  */
90   target_get_trace_status (ts);
91
92   writer->ops->start (writer, filename);
93
94   writer->ops->write_header (writer);
95
96   /* Write descriptive info.  */
97
98   /* Write out the size of a register block.  */
99   writer->ops->write_regblock_type (writer, trace_regblock_size);
100
101   /* Write out the target description info.  */
102   writer->ops->write_tdesc (writer);
103
104   /* Write out status of the tracing run (aka "tstatus" info).  */
105   writer->ops->write_status (writer, ts);
106
107   /* Note that we want to upload tracepoints and save those, rather
108      than simply writing out the local ones, because the user may have
109      changed tracepoints in GDB in preparation for a future tracing
110      run, or maybe just mass-deleted all types of breakpoints as part
111      of cleaning up.  So as not to contaminate the session, leave the
112      data in its uploaded form, don't make into real tracepoints.  */
113
114   /* Get trace state variables first, they may be checked when parsing
115      uploaded commands.  */
116
117   target_upload_trace_state_variables (&uploaded_tsvs);
118
119   for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
120     writer->ops->write_uploaded_tsv (writer, utsv);
121
122   free_uploaded_tsvs (&uploaded_tsvs);
123
124   target_upload_tracepoints (&uploaded_tps);
125
126   for (utp = uploaded_tps; utp; utp = utp->next)
127     target_get_tracepoint_status (NULL, utp);
128
129   for (utp = uploaded_tps; utp; utp = utp->next)
130     writer->ops->write_uploaded_tp (writer, utp);
131
132   free_uploaded_tps (&uploaded_tps);
133
134   /* Mark the end of the definition section.  */
135   writer->ops->write_definition_end (writer);
136
137   /* Get and write the trace data proper.  */
138   while (1)
139     {
140       LONGEST gotten = 0;
141
142       /* The writer supports writing the contents of trace buffer
143           directly to trace file.  Don't parse the contents of trace
144           buffer.  */
145       if (writer->ops->write_trace_buffer != NULL)
146         {
147           /* We ask for big blocks, in the hopes of efficiency, but
148              will take less if the target has packet size limitations
149              or some such.  */
150           gotten = target_get_raw_trace_data (buf.data (), offset,
151                                               MAX_TRACE_UPLOAD);
152           if (gotten < 0)
153             error (_("Failure to get requested trace buffer data"));
154           /* No more data is forthcoming, we're done.  */
155           if (gotten == 0)
156             break;
157
158           writer->ops->write_trace_buffer (writer, buf.data (), gotten);
159
160           offset += gotten;
161         }
162       else
163         {
164           uint16_t tp_num;
165           uint32_t tf_size;
166           /* Parse the trace buffers according to how data are stored
167              in trace buffer in GDBserver.  */
168
169           gotten = target_get_raw_trace_data (buf.data (), offset, 6);
170
171           if (gotten == 0)
172             break;
173
174           /* Read the first six bytes in, which is the tracepoint
175              number and trace frame size.  */
176           tp_num = (uint16_t)
177             extract_unsigned_integer (&((buf.data ())[0]), 2, byte_order);
178
179           tf_size = (uint32_t)
180             extract_unsigned_integer (&((buf.data ())[2]), 4, byte_order);
181
182           writer->ops->frame_ops->start (writer, tp_num);
183           gotten = 6;
184
185           if (tf_size > 0)
186             {
187               unsigned int block;
188
189               offset += 6;
190
191               for (block = 0; block < tf_size; )
192                 {
193                   gdb_byte block_type;
194
195                   /* We'll fetch one block each time, in order to
196                      handle the extremely large 'M' block.  We first
197                      fetch one byte to get the type of the block.  */
198                   gotten = target_get_raw_trace_data (buf.data (),
199                                                       offset, 1);
200                   if (gotten < 1)
201                     error (_("Failure to get requested trace buffer data"));
202
203                   gotten = 1;
204                   block += 1;
205                   offset += 1;
206
207                   block_type = buf[0];
208                   switch (block_type)
209                     {
210                     case 'R':
211                       gotten
212                         = target_get_raw_trace_data (buf.data (), offset,
213                                                      trace_regblock_size);
214                       if (gotten < trace_regblock_size)
215                         error (_("Failure to get requested trace"
216                                  " buffer data"));
217
218                       TRACE_WRITE_R_BLOCK (writer, buf.data (),
219                                            trace_regblock_size);
220                       break;
221                     case 'M':
222                       {
223                         unsigned short mlen;
224                         ULONGEST addr;
225                         LONGEST t;
226                         int j;
227
228                         t = target_get_raw_trace_data (buf.data (),
229                                                        offset, 10);
230                         if (t < 10)
231                           error (_("Failure to get requested trace"
232                                    " buffer data"));
233
234                         offset += 10;
235                         block += 10;
236
237                         gotten = 0;
238                         addr = (ULONGEST)
239                           extract_unsigned_integer (buf.data (), 8,
240                                                     byte_order);
241                         mlen = (unsigned short)
242                           extract_unsigned_integer (&((buf.data ())[8]), 2,
243                                                     byte_order);
244
245                         TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
246                                                     mlen);
247
248                         /* The memory contents in 'M' block may be
249                            very large.  Fetch the data from the target
250                            and write them into file one by one.  */
251                         for (j = 0; j < mlen; )
252                           {
253                             unsigned int read_length;
254
255                             if (mlen - j > MAX_TRACE_UPLOAD)
256                               read_length = MAX_TRACE_UPLOAD;
257                             else
258                               read_length = mlen - j;
259
260                             t = target_get_raw_trace_data (buf.data (),
261                                                            offset + j,
262                                                            read_length);
263                             if (t < read_length)
264                               error (_("Failure to get requested"
265                                        " trace buffer data"));
266
267                             TRACE_WRITE_M_BLOCK_MEMORY (writer,
268                                                         buf.data (),
269                                                         read_length);
270
271                             j += read_length;
272                             gotten += read_length;
273                           }
274
275                         break;
276                       }
277                     case 'V':
278                       {
279                         int vnum;
280                         LONGEST val;
281
282                         gotten
283                           = target_get_raw_trace_data (buf.data (),
284                                                        offset, 12);
285                         if (gotten < 12)
286                           error (_("Failure to get requested"
287                                    " trace buffer data"));
288
289                         vnum  = (int) extract_signed_integer (buf.data (),
290                                                               4,
291                                                               byte_order);
292                         val
293                           = extract_signed_integer (&((buf.data ())[4]),
294                                                     8, byte_order);
295
296                         TRACE_WRITE_V_BLOCK (writer, vnum, val);
297                       }
298                       break;
299                     default:
300                       error (_("Unknown block type '%c' (0x%x) in"
301                                " trace frame"),
302                              block_type, block_type);
303                     }
304
305                   block += gotten;
306                   offset += gotten;
307                 }
308             }
309           else
310             offset += gotten;
311
312           writer->ops->frame_ops->end (writer);
313         }
314     }
315
316   writer->ops->end (writer);
317 }
318
319 static void
320 tsave_command (const char *args, int from_tty)
321 {
322   int target_does_save = 0;
323   char **argv;
324   char *filename = NULL;
325   int generate_ctf = 0;
326
327   if (args == NULL)
328     error_no_arg (_("file in which to save trace data"));
329
330   gdb_argv built_argv (args);
331   argv = built_argv.get ();
332
333   for (; *argv; ++argv)
334     {
335       if (strcmp (*argv, "-r") == 0)
336         target_does_save = 1;
337       else if (strcmp (*argv, "-ctf") == 0)
338         generate_ctf = 1;
339       else if (**argv == '-')
340         error (_("unknown option `%s'"), *argv);
341       else
342         filename = *argv;
343     }
344
345   if (!filename)
346     error_no_arg (_("file in which to save trace data"));
347
348   if (generate_ctf)
349     trace_save_ctf (filename, target_does_save);
350   else
351     trace_save_tfile (filename, target_does_save);
352
353   if (from_tty)
354     printf_filtered (_("Trace data saved to %s '%s'.\n"),
355                      generate_ctf ? "directory" : "file", filename);
356 }
357
358 /* Save the trace data to file FILENAME of tfile format.  */
359
360 void
361 trace_save_tfile (const char *filename, int target_does_save)
362 {
363   trace_file_writer_up writer (tfile_trace_file_writer_new ());
364   trace_save (filename, writer.get (), target_does_save);
365 }
366
367 /* Save the trace data to dir DIRNAME of ctf format.  */
368
369 void
370 trace_save_ctf (const char *dirname, int target_does_save)
371 {
372   trace_file_writer_up writer (ctf_trace_file_writer_new ());
373   trace_save (dirname, writer.get (), target_does_save);
374 }
375
376 /* Fetch register data from tracefile, shared for both tfile and
377    ctf.  */
378
379 void
380 tracefile_fetch_registers (struct regcache *regcache, int regno)
381 {
382   struct gdbarch *gdbarch = regcache->arch ();
383   struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
384   int regn;
385
386   /* We get here if no register data has been found.  Mark registers
387      as unavailable.  */
388   for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
389     regcache->raw_supply (regn, NULL);
390
391   /* We can often usefully guess that the PC is going to be the same
392      as the address of the tracepoint.  */
393   if (tp == NULL || tp->loc == NULL)
394     return;
395
396   /* But don't try to guess if tracepoint is multi-location...  */
397   if (tp->loc->next)
398     {
399       warning (_("Tracepoint %d has multiple "
400                  "locations, cannot infer $pc"),
401                tp->number);
402       return;
403     }
404   /* ... or does while-stepping.  */
405   else if (tp->step_count > 0)
406     {
407       warning (_("Tracepoint %d does while-stepping, "
408                  "cannot infer $pc"),
409                tp->number);
410       return;
411     }
412
413   /* Guess what we can from the tracepoint location.  */
414   gdbarch_guess_tracepoint_registers (gdbarch, regcache,
415                                       tp->loc->address);
416 }
417
418 /* This is the implementation of target_ops method to_has_all_memory.  */
419
420 bool
421 tracefile_target::has_all_memory ()
422 {
423   return 1;
424 }
425
426 /* This is the implementation of target_ops method to_has_memory.  */
427
428 bool
429 tracefile_target::has_memory ()
430 {
431   return 1;
432 }
433
434 /* This is the implementation of target_ops method to_has_stack.
435    The target has a stack when GDB has already selected one trace
436    frame.  */
437
438 bool
439 tracefile_target::has_stack ()
440 {
441   return get_traceframe_number () != -1;
442 }
443
444 /* This is the implementation of target_ops method to_has_registers.
445    The target has registers when GDB has already selected one trace
446    frame.  */
447
448 bool
449 tracefile_target::has_registers ()
450 {
451   return get_traceframe_number () != -1;
452 }
453
454 /* This is the implementation of target_ops method to_thread_alive.
455    tracefile has one thread faked by GDB.  */
456
457 bool
458 tracefile_target::thread_alive (ptid_t ptid)
459 {
460   return 1;
461 }
462
463 /* This is the implementation of target_ops method to_get_trace_status.
464    The trace status for a file is that tracing can never be run.  */
465
466 int
467 tracefile_target::get_trace_status (struct trace_status *ts)
468 {
469   /* Other bits of trace status were collected as part of opening the
470      trace files, so nothing to do here.  */
471
472   return -1;
473 }
474
475 void _initialize_tracefile ();
476 void
477 _initialize_tracefile ()
478 {
479   add_com ("tsave", class_trace, tsave_command, _("\
480 Save the trace data to a file.\n\
481 Use the '-ctf' option to save the data to CTF format.\n\
482 Use the '-r' option to direct the target to save directly to the file,\n\
483 using its own filesystem."));
484 }
This page took 0.052182 seconds and 4 git commands to generate.