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