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