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