1 /* Trace file TFILE format support in GDB.
2 
3    Copyright (C) 1997-2024 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 "extract-store-integer.h"
21 #include "tracefile.h"
22 #include "readline/tilde.h"
23 #include "gdbsupport/filestuff.h"
24 #include "gdbsupport/rsp-low.h"
25 #include "regcache.h"
26 #include "inferior.h"
27 #include "gdbthread.h"
28 #include "exec.h"
29 #include "completer.h"
30 #include "filenames.h"
31 #include "remote.h"
32 #include "xml-tdesc.h"
33 #include "target-descriptions.h"
34 #include "gdbsupport/pathstuff.h"
35 #include <algorithm>
36 
37 #ifndef O_LARGEFILE
38 #define O_LARGEFILE 0
39 #endif
40 
41 /* The tfile target.  */
42 
43 static const target_info tfile_target_info = {
44   "tfile",
45   N_("Local trace dump file"),
46   N_("Use a trace file as a target.\n\
47 Specify the filename of the trace file.")
48 };
49 
50 class tfile_target final : public tracefile_target
51 {
52  public:
info()53   const target_info &info () const override
54   { return tfile_target_info; }
55 
56   void close () override;
57   void fetch_registers (struct regcache *, int) override;
58   enum target_xfer_status xfer_partial (enum target_object object,
59                                                             const char *annex,
60                                                             gdb_byte *readbuf,
61                                                             const gdb_byte *writebuf,
62                                                             ULONGEST offset, ULONGEST len,
63                                                             ULONGEST *xfered_len) override;
64   void files_info () override;
65   int trace_find (enum trace_find_type type, int num,
66                                 CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override;
67   bool get_trace_state_variable_value (int tsv, LONGEST *val) override;
68   traceframe_info_up traceframe_info () override;
69 
70   void get_tracepoint_status (tracepoint *tp,
71                                     struct uploaded_tp *utp) override;
72 };
73 
74 /* TFILE trace writer.  */
75 
76 struct tfile_trace_file_writer
77 {
78   struct trace_file_writer base;
79 
80   /* File pointer to tfile trace file.  */
81   FILE *fp;
82   /* Path name of the tfile trace file.  */
83   char *pathname;
84 };
85 
86 /* This is the implementation of trace_file_write_ops method
87    target_save.  We just call the generic target
88    target_save_trace_data to do target-side saving.  */
89 
90 static int
tfile_target_save(struct trace_file_writer * self,const char * filename)91 tfile_target_save (struct trace_file_writer *self,
92                        const char *filename)
93 {
94   int err = target_save_trace_data (filename);
95 
96   return (err >= 0);
97 }
98 
99 /* This is the implementation of trace_file_write_ops method
100    dtor.  */
101 
102 static void
tfile_dtor(struct trace_file_writer * self)103 tfile_dtor (struct trace_file_writer *self)
104 {
105   struct tfile_trace_file_writer *writer
106     = (struct tfile_trace_file_writer *) self;
107 
108   xfree (writer->pathname);
109 
110   if (writer->fp != NULL)
111     fclose (writer->fp);
112 }
113 
114 /* This is the implementation of trace_file_write_ops method
115    start.  It creates the trace file FILENAME and registers some
116    cleanups.  */
117 
118 static void
tfile_start(struct trace_file_writer * self,const char * filename)119 tfile_start (struct trace_file_writer *self, const char *filename)
120 {
121   struct tfile_trace_file_writer *writer
122     = (struct tfile_trace_file_writer *) self;
123 
124   writer->pathname = tilde_expand (filename);
125   writer->fp = gdb_fopen_cloexec (writer->pathname, "wb").release ();
126   if (writer->fp == NULL)
127     error (_("Unable to open file '%s' for saving trace data (%s)"),
128              writer->pathname, safe_strerror (errno));
129 }
130 
131 /* This is the implementation of trace_file_write_ops method
132    write_header.  Write the TFILE header.  */
133 
134 static void
tfile_write_header(struct trace_file_writer * self)135 tfile_write_header (struct trace_file_writer *self)
136 {
137   struct tfile_trace_file_writer *writer
138     = (struct tfile_trace_file_writer *) self;
139   int written;
140 
141   /* Write a file header, with a high-bit-set char to indicate a
142      binary file, plus a hint as what this file is, and a version
143      number in case of future needs.  */
144   written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
145   if (written < 1)
146     perror_with_name (writer->pathname);
147 }
148 
149 /* This is the implementation of trace_file_write_ops method
150    write_regblock_type.  Write the size of register block.  */
151 
152 static void
tfile_write_regblock_type(struct trace_file_writer * self,int size)153 tfile_write_regblock_type (struct trace_file_writer *self, int size)
154 {
155   struct tfile_trace_file_writer *writer
156     = (struct tfile_trace_file_writer *) self;
157 
158   fprintf (writer->fp, "R %x\n", size);
159 }
160 
161 /* This is the implementation of trace_file_write_ops method
162    write_status.  */
163 
164 static void
tfile_write_status(struct trace_file_writer * self,struct trace_status * ts)165 tfile_write_status (struct trace_file_writer *self,
166                         struct trace_status *ts)
167 {
168   struct tfile_trace_file_writer *writer
169     = (struct tfile_trace_file_writer *) self;
170 
171   fprintf (writer->fp, "status %c;%s",
172              (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
173   if (ts->stop_reason == tracepoint_error
174       || ts->stop_reason == trace_stop_command)
175     {
176       char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
177 
178       bin2hex ((gdb_byte *) ts->stop_desc, buf, strlen (ts->stop_desc));
179       fprintf (writer->fp, ":%s", buf);
180     }
181   fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
182   if (ts->traceframe_count >= 0)
183     fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
184   if (ts->traceframes_created >= 0)
185     fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
186   if (ts->buffer_free >= 0)
187     fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
188   if (ts->buffer_size >= 0)
189     fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
190   if (ts->disconnected_tracing)
191     fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
192   if (ts->circular_buffer)
193     fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
194   if (ts->start_time)
195     {
196       fprintf (writer->fp, ";starttime:%s",
197       phex_nz (ts->start_time, sizeof (ts->start_time)));
198     }
199   if (ts->stop_time)
200     {
201       fprintf (writer->fp, ";stoptime:%s",
202       phex_nz (ts->stop_time, sizeof (ts->stop_time)));
203     }
204   if (ts->notes != NULL)
205     {
206       char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
207 
208       bin2hex ((gdb_byte *) ts->notes, buf, strlen (ts->notes));
209       fprintf (writer->fp, ";notes:%s", buf);
210     }
211   if (ts->user_name != NULL)
212     {
213       char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
214 
215       bin2hex ((gdb_byte *) ts->user_name, buf, strlen (ts->user_name));
216       fprintf (writer->fp, ";username:%s", buf);
217     }
218   fprintf (writer->fp, "\n");
219 }
220 
221 /* This is the implementation of trace_file_write_ops method
222    write_uploaded_tsv.  */
223 
224 static void
tfile_write_uploaded_tsv(struct trace_file_writer * self,struct uploaded_tsv * utsv)225 tfile_write_uploaded_tsv (struct trace_file_writer *self,
226                                 struct uploaded_tsv *utsv)
227 {
228   gdb::unique_xmalloc_ptr<char> buf;
229   struct tfile_trace_file_writer *writer
230     = (struct tfile_trace_file_writer *) self;
231 
232   if (utsv->name)
233     {
234       buf.reset ((char *) xmalloc (strlen (utsv->name) * 2 + 1));
235       bin2hex ((gdb_byte *) (utsv->name), buf.get (), strlen (utsv->name));
236     }
237 
238   fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
239              utsv->number, phex_nz (utsv->initial_value, 8),
240              utsv->builtin, buf != NULL ? buf.get () : "");
241 }
242 
243 #define MAX_TRACE_UPLOAD 2000
244 
245 /* This is the implementation of trace_file_write_ops method
246    write_uploaded_tp.  */
247 
248 static void
tfile_write_uploaded_tp(struct trace_file_writer * self,struct uploaded_tp * utp)249 tfile_write_uploaded_tp (struct trace_file_writer *self,
250                                struct uploaded_tp *utp)
251 {
252   struct tfile_trace_file_writer *writer
253     = (struct tfile_trace_file_writer *) self;
254   char buf[MAX_TRACE_UPLOAD];
255 
256   fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
257              utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
258              (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
259   if (utp->type == bp_fast_tracepoint)
260     fprintf (writer->fp, ":F%x", utp->orig_size);
261   if (utp->cond)
262     fprintf (writer->fp,
263                ":X%x,%s", (unsigned int) strlen (utp->cond.get ()) / 2,
264                utp->cond.get ());
265   fprintf (writer->fp, "\n");
266   for (const auto &act : utp->actions)
267     fprintf (writer->fp, "tp A%x:%s:%s\n",
268                utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
269   for (const auto &act : utp->step_actions)
270     fprintf (writer->fp, "tp S%x:%s:%s\n",
271                utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
272   if (utp->at_string)
273     {
274       encode_source_string (utp->number, utp->addr,
275                                   "at", utp->at_string.get (),
276                                   buf, MAX_TRACE_UPLOAD);
277       fprintf (writer->fp, "tp Z%s\n", buf);
278     }
279   if (utp->cond_string)
280     {
281       encode_source_string (utp->number, utp->addr,
282                                   "cond", utp->cond_string.get (),
283                                   buf, MAX_TRACE_UPLOAD);
284       fprintf (writer->fp, "tp Z%s\n", buf);
285     }
286   for (const auto &act : utp->cmd_strings)
287     {
288       encode_source_string (utp->number, utp->addr, "cmd", act.get (),
289                                   buf, MAX_TRACE_UPLOAD);
290       fprintf (writer->fp, "tp Z%s\n", buf);
291     }
292   fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
293              utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
294              utp->hit_count,
295              phex_nz (utp->traceframe_usage,
296                         sizeof (utp->traceframe_usage)));
297 }
298 
299 /* This is the implementation of trace_file_write_ops method
300    write_tdesc.  */
301 
302 static void
tfile_write_tdesc(struct trace_file_writer * self)303 tfile_write_tdesc (struct trace_file_writer *self)
304 {
305   struct tfile_trace_file_writer *writer
306     = (struct tfile_trace_file_writer *) self;
307 
308   std::optional<std::string> tdesc
309     = target_fetch_description_xml (current_inferior ()->top_target ());
310 
311   if (!tdesc)
312     return;
313 
314   const char *ptr = tdesc->c_str ();
315 
316   /* Write tdesc line by line, prefixing each line with "tdesc ".  */
317   while (ptr != NULL)
318     {
319       const char *next = strchr (ptr, '\n');
320       if (next != NULL)
321           {
322             fprintf (writer->fp, "tdesc %.*s\n", (int) (next - ptr), ptr);
323             /* Skip the \n.  */
324             next++;
325           }
326       else if (*ptr != '\0')
327           {
328             /* Last line, doesn't have a newline.  */
329             fprintf (writer->fp, "tdesc %s\n", ptr);
330           }
331       ptr = next;
332     }
333 }
334 
335 /* This is the implementation of trace_file_write_ops method
336    write_definition_end.  */
337 
338 static void
tfile_write_definition_end(struct trace_file_writer * self)339 tfile_write_definition_end (struct trace_file_writer *self)
340 {
341   struct tfile_trace_file_writer *writer
342     = (struct tfile_trace_file_writer *) self;
343 
344   fprintf (writer->fp, "\n");
345 }
346 
347 /* This is the implementation of trace_file_write_ops method
348    write_raw_data.  */
349 
350 static void
tfile_write_raw_data(struct trace_file_writer * self,gdb_byte * buf,LONGEST len)351 tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
352                           LONGEST len)
353 {
354   struct tfile_trace_file_writer *writer
355     = (struct tfile_trace_file_writer *) self;
356 
357   if (fwrite (buf, len, 1, writer->fp) < 1)
358     perror_with_name (writer->pathname);
359 }
360 
361 /* This is the implementation of trace_file_write_ops method
362    end.  */
363 
364 static void
tfile_end(struct trace_file_writer * self)365 tfile_end (struct trace_file_writer *self)
366 {
367   struct tfile_trace_file_writer *writer
368     = (struct tfile_trace_file_writer *) self;
369   uint32_t gotten = 0;
370 
371   /* Mark the end of trace data.  */
372   if (fwrite (&gotten, 4, 1, writer->fp) < 1)
373     perror_with_name (writer->pathname);
374 }
375 
376 /* Operations to write trace buffers into TFILE format.  */
377 
378 static const struct trace_file_write_ops tfile_write_ops =
379 {
380   tfile_dtor,
381   tfile_target_save,
382   tfile_start,
383   tfile_write_header,
384   tfile_write_regblock_type,
385   tfile_write_status,
386   tfile_write_uploaded_tsv,
387   tfile_write_uploaded_tp,
388   tfile_write_tdesc,
389   tfile_write_definition_end,
390   tfile_write_raw_data,
391   NULL,
392   tfile_end,
393 };
394 
395 /* Return a trace writer for TFILE format.  */
396 
397 struct trace_file_writer *
tfile_trace_file_writer_new(void)398 tfile_trace_file_writer_new (void)
399 {
400   struct tfile_trace_file_writer *writer
401     = XNEW (struct tfile_trace_file_writer);
402 
403   writer->base.ops = &tfile_write_ops;
404   writer->fp = NULL;
405   writer->pathname = NULL;
406 
407   return (struct trace_file_writer *) writer;
408 }
409 
410 /* target tfile command */
411 
412 static tfile_target tfile_ops;
413 
414 #define TRACE_HEADER_SIZE 8
415 
416 #define TFILE_PID (1)
417 
418 static gdb::unique_xmalloc_ptr<char> trace_filename;
419 static int trace_fd = -1;
420 static off_t trace_frames_offset;
421 static off_t cur_offset;
422 static int cur_data_size;
423 int trace_regblock_size;
424 static std::string trace_tdesc;
425 
426 static void tfile_append_tdesc_line (const char *line);
427 static void tfile_interp_line (const char *line,
428                                      struct uploaded_tp **utpp,
429                                      struct uploaded_tsv **utsvp);
430 
431 /* Read SIZE bytes into READBUF from the trace frame, starting at
432    TRACE_FD's current position.  Note that this call `read'
433    underneath, hence it advances the file's seek position.  Throws an
434    error if the `read' syscall fails, or less than SIZE bytes are
435    read.  */
436 
437 static void
tfile_read(gdb_byte * readbuf,int size)438 tfile_read (gdb_byte *readbuf, int size)
439 {
440   int gotten;
441 
442   gotten = read (trace_fd, readbuf, size);
443   if (gotten < 0)
444     perror_with_name (trace_filename.get ());
445   else if (gotten < size)
446     error (_("Premature end of file while reading trace file"));
447 }
448 
449 /* Open the tfile target.  */
450 
451 static void
tfile_target_open(const char * arg,int from_tty)452 tfile_target_open (const char *arg, int from_tty)
453 {
454   int flags;
455   int scratch_chan;
456   char header[TRACE_HEADER_SIZE];
457   char linebuf[1000]; /* Should be max remote packet size or so.  */
458   gdb_byte byte;
459   int bytes, i;
460   struct trace_status *ts;
461   struct uploaded_tp *uploaded_tps = NULL;
462   struct uploaded_tsv *uploaded_tsvs = NULL;
463 
464   target_preopen (from_tty);
465   if (!arg)
466     error (_("No trace file specified."));
467 
468   gdb::unique_xmalloc_ptr<char> filename (tilde_expand (arg));
469   if (!IS_ABSOLUTE_PATH (filename.get ()))
470     filename = make_unique_xstrdup (gdb_abspath (filename.get ()).c_str ());
471 
472   flags = O_BINARY | O_LARGEFILE;
473   flags |= O_RDONLY;
474   scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release ();
475   if (scratch_chan < 0)
476     perror_with_name (filename.get ());
477 
478   /* Looks semi-reasonable.  Toss the old trace file and work on the new.  */
479 
480   current_inferior ()->unpush_target (&tfile_ops);
481 
482   trace_filename = std::move (filename);
483   trace_fd = scratch_chan;
484 
485   /* Make sure this is clear.  */
486   trace_tdesc.clear ();
487 
488   bytes = 0;
489   /* Read the file header and test for validity.  */
490   tfile_read ((gdb_byte *) &header, TRACE_HEADER_SIZE);
491 
492   bytes += TRACE_HEADER_SIZE;
493   if (!(header[0] == 0x7f
494           && (startswith (header + 1, "TRACE0\n"))))
495     error (_("File is not a valid trace file."));
496 
497   current_inferior ()->push_target (&tfile_ops);
498 
499   trace_regblock_size = 0;
500   ts = current_trace_status ();
501   /* We know we're working with a file.  Record its name.  */
502   ts->filename = trace_filename.get ();
503   /* Set defaults in case there is no status line.  */
504   ts->running_known = 0;
505   ts->stop_reason = trace_stop_reason_unknown;
506   ts->traceframe_count = -1;
507   ts->buffer_free = 0;
508   ts->disconnected_tracing = 0;
509   ts->circular_buffer = 0;
510 
511   try
512     {
513       /* Read through a section of newline-terminated lines that
514            define things like tracepoints.  */
515       i = 0;
516       while (1)
517           {
518             tfile_read (&byte, 1);
519 
520             ++bytes;
521             if (byte == '\n')
522               {
523                 /* Empty line marks end of the definition section.  */
524                 if (i == 0)
525                     break;
526                 linebuf[i] = '\0';
527                 i = 0;
528                 tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
529               }
530             else
531               linebuf[i++] = byte;
532             if (i >= 1000)
533               error (_("Excessively long lines in trace file"));
534           }
535 
536       /* By now, tdesc lines have been read from tfile - let's parse them.  */
537       target_find_description ();
538 
539       /* Record the starting offset of the binary trace data.  */
540       trace_frames_offset = bytes;
541 
542       /* If we don't have a blocksize, we can't interpret the
543            traceframes.  */
544       if (trace_regblock_size == 0)
545           error (_("No register block size recorded in trace file"));
546     }
547   catch (const gdb_exception &ex)
548     {
549       /* Remove the partially set up target.  */
550       current_inferior ()->unpush_target (&tfile_ops);
551       throw;
552     }
553 
554   inferior_appeared (current_inferior (), TFILE_PID);
555 
556   thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID));
557   switch_to_thread (thr);
558 
559   if (ts->traceframe_count <= 0)
560     warning (_("No traceframes present in this file."));
561 
562   /* Add the file's tracepoints and variables into the current mix.  */
563 
564   /* Get trace state variables first, they may be checked when parsing
565      uploaded commands.  */
566   merge_uploaded_trace_state_variables (&uploaded_tsvs);
567 
568   merge_uploaded_tracepoints (&uploaded_tps);
569 
570   post_create_inferior (from_tty);
571 }
572 
573 /* Interpret the given line from the definitions part of the trace
574    file.  */
575 
576 static void
tfile_interp_line(const char * line,struct uploaded_tp ** utpp,struct uploaded_tsv ** utsvp)577 tfile_interp_line (const char *line, struct uploaded_tp **utpp,
578                        struct uploaded_tsv **utsvp)
579 {
580   const char *p = line;
581 
582   if (startswith (p, "R "))
583     {
584       p += strlen ("R ");
585       trace_regblock_size = strtol (p, nullptr, 16);
586     }
587   else if (startswith (p, "status "))
588     {
589       p += strlen ("status ");
590       parse_trace_status (p, current_trace_status ());
591     }
592   else if (startswith (p, "tp "))
593     {
594       p += strlen ("tp ");
595       parse_tracepoint_definition (p, utpp);
596     }
597   else if (startswith (p, "tsv "))
598     {
599       p += strlen ("tsv ");
600       parse_tsv_definition (p, utsvp);
601     }
602   else if (startswith (p, "tdesc "))
603     {
604       p += strlen ("tdesc ");
605       tfile_append_tdesc_line (p);
606     }
607   else
608     warning (_("Ignoring trace file definition \"%s\""), line);
609 }
610 
611 /* Close the trace file and generally clean up.  */
612 
613 void
close()614 tfile_target::close ()
615 {
616   gdb_assert (trace_fd != -1);
617 
618   switch_to_no_thread ();     /* Avoid confusion from thread stuff.  */
619   exit_inferior (current_inferior ());
620 
621   ::close (trace_fd);
622   trace_fd = -1;
623   trace_filename.reset ();
624   trace_tdesc.clear ();
625 
626   trace_reset_local_state ();
627 }
628 
629 void
files_info()630 tfile_target::files_info ()
631 {
632   gdb_printf ("\t`%s'\n", trace_filename.get ());
633 }
634 
635 void
get_tracepoint_status(tracepoint * tp,struct uploaded_tp * utp)636 tfile_target::get_tracepoint_status (tracepoint *tp, struct uploaded_tp *utp)
637 {
638   /* Other bits of trace status were collected as part of opening the
639      trace files, so nothing to do here.  */
640 }
641 
642 /* Given the position of a traceframe in the file, figure out what
643    address the frame was collected at.  This would normally be the
644    value of a collected PC register, but if not available, we
645    improvise.  */
646 
647 static CORE_ADDR
tfile_get_traceframe_address(off_t tframe_offset)648 tfile_get_traceframe_address (off_t tframe_offset)
649 {
650   CORE_ADDR addr = 0;
651   short tpnum;
652   struct tracepoint *tp;
653   off_t saved_offset = cur_offset;
654 
655   /* FIXME dig pc out of collected registers.  */
656 
657   /* Fall back to using tracepoint address.  */
658   lseek (trace_fd, tframe_offset, SEEK_SET);
659   tfile_read ((gdb_byte *) &tpnum, 2);
660   tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
661                                                     gdbarch_byte_order
662                                                       (current_inferior ()->arch ()));
663 
664   tp = get_tracepoint_by_number_on_target (tpnum);
665   /* FIXME this is a poor heuristic if multiple locations.  */
666   if (tp != nullptr && tp->has_locations ())
667     addr = tp->first_loc ().address;
668 
669   /* Restore our seek position.  */
670   cur_offset = saved_offset;
671   lseek (trace_fd, cur_offset, SEEK_SET);
672   return addr;
673 }
674 
675 /* Given a type of search and some parameters, scan the collection of
676    traceframes in the file looking for a match.  When found, return
677    both the traceframe and tracepoint number, otherwise -1 for
678    each.  */
679 
680 int
trace_find(enum trace_find_type type,int num,CORE_ADDR addr1,CORE_ADDR addr2,int * tpp)681 tfile_target::trace_find (enum trace_find_type type, int num,
682                                 CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
683 {
684   short tpnum;
685   int tfnum = 0, found = 0;
686   unsigned int data_size;
687   struct tracepoint *tp;
688   off_t offset, tframe_offset;
689   CORE_ADDR tfaddr;
690 
691   if (num == -1)
692     {
693       if (tpp)
694           *tpp = -1;
695       return -1;
696     }
697 
698   lseek (trace_fd, trace_frames_offset, SEEK_SET);
699   offset = trace_frames_offset;
700   while (1)
701     {
702       tframe_offset = offset;
703       tfile_read ((gdb_byte *) &tpnum, 2);
704       tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
705                                                         gdbarch_byte_order
706                                                             (current_inferior ()->arch ()));
707       offset += 2;
708       if (tpnum == 0)
709           break;
710       tfile_read ((gdb_byte *) &data_size, 4);
711       data_size = (unsigned int) extract_unsigned_integer
712                                            ((gdb_byte *) &data_size, 4,
713                                             gdbarch_byte_order
714                                               (current_inferior ()->arch ()));
715       offset += 4;
716 
717       if (type == tfind_number)
718           {
719             /* Looking for a specific trace frame.  */
720             if (tfnum == num)
721               found = 1;
722           }
723       else
724           {
725             /* Start from the _next_ trace frame.  */
726             if (tfnum > get_traceframe_number ())
727               {
728                 switch (type)
729                     {
730                     case tfind_pc:
731                       tfaddr = tfile_get_traceframe_address (tframe_offset);
732                       if (tfaddr == addr1)
733                         found = 1;
734                       break;
735                     case tfind_tp:
736                       tp = get_tracepoint (num);
737                       if (tp && tpnum == tp->number_on_target)
738                         found = 1;
739                       break;
740                     case tfind_range:
741                       tfaddr = tfile_get_traceframe_address (tframe_offset);
742                       if (addr1 <= tfaddr && tfaddr <= addr2)
743                         found = 1;
744                       break;
745                     case tfind_outside:
746                       tfaddr = tfile_get_traceframe_address (tframe_offset);
747                       if (!(addr1 <= tfaddr && tfaddr <= addr2))
748                         found = 1;
749                       break;
750                     default:
751                       internal_error (_("unknown tfind type"));
752                     }
753               }
754           }
755 
756       if (found)
757           {
758             if (tpp)
759               *tpp = tpnum;
760             cur_offset = offset;
761             cur_data_size = data_size;
762 
763             return tfnum;
764           }
765       /* Skip past the traceframe's data.  */
766       lseek (trace_fd, data_size, SEEK_CUR);
767       offset += data_size;
768       /* Update our own count of traceframes.  */
769       ++tfnum;
770     }
771   /* Did not find what we were looking for.  */
772   if (tpp)
773     *tpp = -1;
774   return -1;
775 }
776 
777 /* Walk over all traceframe block starting at POS offset from
778    CUR_OFFSET, and call CALLBACK for each block found.  If CALLBACK
779    returns true, this returns the position in the traceframe where the
780    block is found, relative to the start of the traceframe
781    (cur_offset).  Returns -1 if no callback call returned true,
782    indicating that all blocks have been walked.  */
783 
784 static int
traceframe_walk_blocks(gdb::function_view<bool (char)> callback,int pos)785 traceframe_walk_blocks (gdb::function_view<bool (char)> callback, int pos)
786 {
787   /* Iterate through a traceframe's blocks, looking for a block of the
788      requested type.  */
789 
790   lseek (trace_fd, cur_offset + pos, SEEK_SET);
791   while (pos < cur_data_size)
792     {
793       unsigned short mlen;
794       char block_type;
795 
796       tfile_read ((gdb_byte *) &block_type, 1);
797 
798       ++pos;
799 
800       if (callback (block_type))
801           return pos;
802 
803       switch (block_type)
804           {
805           case 'R':
806             lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
807             pos += trace_regblock_size;
808             break;
809           case 'M':
810             lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
811             tfile_read ((gdb_byte *) &mlen, 2);
812             mlen = (unsigned short)
813                     extract_unsigned_integer ((gdb_byte *) &mlen, 2,
814                                                     gdbarch_byte_order
815                                                       (current_inferior ()->arch ()));
816             lseek (trace_fd, mlen, SEEK_CUR);
817             pos += (8 + 2 + mlen);
818             break;
819           case 'V':
820             lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
821             pos += (4 + 8);
822             break;
823           default:
824             error (_("Unknown block type '%c' (0x%x) in trace frame"),
825                      block_type, block_type);
826             break;
827           }
828     }
829 
830   return -1;
831 }
832 
833 /* Convenience wrapper around traceframe_walk_blocks.  Looks for the
834    position offset of a block of type TYPE_WANTED in the current trace
835    frame, starting at POS.  Returns -1 if no such block was found.  */
836 
837 static int
traceframe_find_block_type(char type_wanted,int pos)838 traceframe_find_block_type (char type_wanted, int pos)
839 {
840   return traceframe_walk_blocks ([&] (char blocktype)
841     {
842       return blocktype == type_wanted;
843     }, pos);
844 }
845 
846 /* Look for a block of saved registers in the traceframe, and get the
847    requested register from it.  */
848 
849 void
fetch_registers(struct regcache * regcache,int regno)850 tfile_target::fetch_registers (struct regcache *regcache, int regno)
851 {
852   struct gdbarch *gdbarch = regcache->arch ();
853   int offset, regn, regsize, dummy;
854 
855   /* An uninitialized reg size says we're not going to be
856      successful at getting register blocks.  */
857   if (!trace_regblock_size)
858     return;
859 
860   if (traceframe_find_block_type ('R', 0) >= 0)
861     {
862       gdb_byte *regs = (gdb_byte *) alloca (trace_regblock_size);
863 
864       tfile_read (regs, trace_regblock_size);
865 
866       for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
867           {
868             if (!remote_register_number_and_offset (regcache->arch (),
869                                                               regn, &dummy, &offset))
870               continue;
871 
872             regsize = register_size (gdbarch, regn);
873             /* Make sure we stay within block bounds.  */
874             if (offset + regsize > trace_regblock_size)
875               break;
876             if (regcache->get_register_status (regn) == REG_UNKNOWN)
877               {
878                 if (regno == regn)
879                     {
880                       regcache->raw_supply (regno, regs + offset);
881                       break;
882                     }
883                 else if (regno == -1)
884                     {
885                       regcache->raw_supply (regn, regs + offset);
886                     }
887               }
888           }
889     }
890   else
891     tracefile_fetch_registers (regcache, regno);
892 }
893 
894 static enum target_xfer_status
tfile_xfer_partial_features(const char * annex,gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,ULONGEST len,ULONGEST * xfered_len)895 tfile_xfer_partial_features (const char *annex,
896                                    gdb_byte *readbuf, const gdb_byte *writebuf,
897                                    ULONGEST offset, ULONGEST len,
898                                    ULONGEST *xfered_len)
899 {
900   if (strcmp (annex, "target.xml"))
901     return TARGET_XFER_E_IO;
902 
903   if (readbuf == NULL)
904     error (_("tfile_xfer_partial: tdesc is read-only"));
905 
906   if (trace_tdesc.empty ())
907     return TARGET_XFER_E_IO;
908 
909   if (offset >= trace_tdesc.length ())
910     return TARGET_XFER_EOF;
911 
912   if (len > trace_tdesc.length () - offset)
913     len = trace_tdesc.length () - offset;
914 
915   memcpy (readbuf, trace_tdesc.c_str () + offset, len);
916   *xfered_len = len;
917 
918   return TARGET_XFER_OK;
919 }
920 
921 enum target_xfer_status
xfer_partial(enum target_object object,const char * annex,gdb_byte * readbuf,const gdb_byte * writebuf,ULONGEST offset,ULONGEST len,ULONGEST * xfered_len)922 tfile_target::xfer_partial (enum target_object object,
923                                   const char *annex, gdb_byte *readbuf,
924                                   const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
925                                   ULONGEST *xfered_len)
926 {
927   /* We're only doing regular memory and tdesc for now.  */
928   if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
929     return tfile_xfer_partial_features (annex, readbuf, writebuf,
930                                                   offset, len, xfered_len);
931   if (object != TARGET_OBJECT_MEMORY)
932     return TARGET_XFER_E_IO;
933 
934   if (readbuf == NULL)
935     error (_("tfile_xfer_partial: trace file is read-only"));
936 
937   if (get_traceframe_number () != -1)
938     {
939       int pos = 0;
940       enum target_xfer_status res;
941       /* Records the lowest available address of all blocks that
942            intersects the requested range.  */
943       ULONGEST low_addr_available = 0;
944 
945       /* Iterate through the traceframe's blocks, looking for
946            memory.  */
947       while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
948           {
949             ULONGEST maddr, amt;
950             unsigned short mlen;
951             bfd_endian byte_order
952               = gdbarch_byte_order (current_inferior ()->arch ());
953 
954             tfile_read ((gdb_byte *) &maddr, 8);
955             maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
956                                                       byte_order);
957             tfile_read ((gdb_byte *) &mlen, 2);
958             mlen = (unsigned short)
959               extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
960 
961             /* If the block includes the first part of the desired
962                range, return as much it has; GDB will re-request the
963                remainder, which might be in a different block of this
964                trace frame.  */
965             if (maddr <= offset && offset < (maddr + mlen))
966               {
967                 amt = (maddr + mlen) - offset;
968                 if (amt > len)
969                     amt = len;
970 
971                 if (maddr != offset)
972                     lseek (trace_fd, offset - maddr, SEEK_CUR);
973                 tfile_read (readbuf, amt);
974                 *xfered_len = amt;
975                 return TARGET_XFER_OK;
976               }
977 
978             if (offset < maddr && maddr < (offset + len))
979               if (low_addr_available == 0 || low_addr_available > maddr)
980                 low_addr_available = maddr;
981 
982             /* Skip over this block.  */
983             pos += (8 + 2 + mlen);
984           }
985 
986       /* Requested memory is unavailable in the context of traceframes,
987            and this address falls within a read-only section, fallback
988            to reading from executable, up to LOW_ADDR_AVAILABLE.  */
989       if (offset < low_addr_available)
990           len = std::min (len, low_addr_available - offset);
991       res = exec_read_partial_read_only (readbuf, offset, len, xfered_len);
992 
993       if (res == TARGET_XFER_OK)
994           return TARGET_XFER_OK;
995       else
996           {
997             /* No use trying further, we know some memory starting
998                at MEMADDR isn't available.  */
999             *xfered_len = len;
1000             return TARGET_XFER_UNAVAILABLE;
1001           }
1002     }
1003   else
1004     {
1005       /* Fallback to reading from read-only sections.  */
1006       return section_table_read_available_memory (readbuf, offset, len,
1007                                                               xfered_len);
1008     }
1009 }
1010 
1011 /* Iterate through the blocks of a trace frame, looking for a 'V'
1012    block with a matching tsv number.  */
1013 
1014 bool
get_trace_state_variable_value(int tsvnum,LONGEST * val)1015 tfile_target::get_trace_state_variable_value (int tsvnum, LONGEST *val)
1016 {
1017   int pos;
1018   bool found = false;
1019 
1020   /* Iterate over blocks in current frame and find the last 'V'
1021      block in which tsv number is TSVNUM.  In one trace frame, there
1022      may be multiple 'V' blocks created for a given trace variable,
1023      and the last matched 'V' block contains the updated value.  */
1024   pos = 0;
1025   while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
1026     {
1027       int vnum;
1028 
1029       tfile_read ((gdb_byte *) &vnum, 4);
1030       vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
1031                                                      gdbarch_byte_order
1032                                                        (current_inferior ()->arch ()));
1033       if (tsvnum == vnum)
1034           {
1035             tfile_read ((gdb_byte *) val, 8);
1036             *val = extract_signed_integer ((gdb_byte *) val, 8,
1037                                                    gdbarch_byte_order
1038                                                      (current_inferior ()->arch ()));
1039             found = true;
1040           }
1041       pos += (4 + 8);
1042     }
1043 
1044   return found;
1045 }
1046 
1047 /* Callback for traceframe_walk_blocks.  Builds a traceframe_info
1048    object for the tfile target's current traceframe.  */
1049 
1050 static bool
build_traceframe_info(char blocktype,struct traceframe_info * info)1051 build_traceframe_info (char blocktype, struct traceframe_info *info)
1052 {
1053   switch (blocktype)
1054     {
1055     case 'M':
1056       {
1057           ULONGEST maddr;
1058           unsigned short mlen;
1059 
1060           tfile_read ((gdb_byte *) &maddr, 8);
1061           maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
1062                                                     gdbarch_byte_order
1063                                                       (current_inferior ()->arch ()));
1064           tfile_read ((gdb_byte *) &mlen, 2);
1065           mlen = (unsigned short)
1066                     extract_unsigned_integer ((gdb_byte *) &mlen,
1067                                                     2,
1068                                                     gdbarch_byte_order
1069                                                       (current_inferior ()->arch ()));
1070 
1071           info->memory.emplace_back (maddr, mlen);
1072           break;
1073       }
1074     case 'V':
1075       {
1076           int vnum;
1077 
1078           tfile_read ((gdb_byte *) &vnum, 4);
1079           info->tvars.push_back (vnum);
1080       }
1081     case 'R':
1082     case 'S':
1083       {
1084           break;
1085       }
1086     default:
1087       warning (_("Unhandled trace block type (%d) '%c ' "
1088                      "while building trace frame info."),
1089                  blocktype, blocktype);
1090       break;
1091     }
1092 
1093   return false;
1094 }
1095 
1096 traceframe_info_up
traceframe_info()1097 tfile_target::traceframe_info ()
1098 {
1099   traceframe_info_up info (new struct traceframe_info);
1100 
1101   traceframe_walk_blocks ([&] (char blocktype)
1102     {
1103       return build_traceframe_info (blocktype, info.get ());
1104     }, 0);
1105 
1106   return info;
1107 }
1108 
1109 /* Handles tdesc lines from tfile by appending the payload to
1110    a global trace_tdesc variable.  */
1111 
1112 static void
tfile_append_tdesc_line(const char * line)1113 tfile_append_tdesc_line (const char *line)
1114 {
1115   trace_tdesc += line;
1116   trace_tdesc += "\n";
1117 }
1118 
1119 void _initialize_tracefile_tfile ();
1120 void
_initialize_tracefile_tfile()1121 _initialize_tracefile_tfile ()
1122 {
1123   add_target (tfile_target_info, tfile_target_open, filename_completer);
1124 }
1125