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