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