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