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