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