Move trace file writer out of tracepoint.c
[deliverable/binutils-gdb.git] / gdb / tracefile.c
CommitLineData
7951c4eb
YQ
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
24/* Helper macros. */
25
26#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
27 writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
28#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
29 writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
30 (size))
31#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
32 writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
33 (size))
34#define TRACE_WRITE_V_BLOCK(writer, num, val) \
35 writer->ops->frame_ops->write_v_block ((writer), (num), (val))
36
37/* Free trace file writer. */
38
39static void
40trace_file_writer_xfree (void *arg)
41{
42 struct trace_file_writer *writer = arg;
43
44 writer->ops->dtor (writer);
45 xfree (writer);
46}
47
48/* Save tracepoint data to file named FILENAME through WRITER. WRITER
49 determines the trace file format. If TARGET_DOES_SAVE is non-zero,
50 the save is performed on the target, otherwise GDB obtains all trace
51 data and saves it locally. */
52
53static void
54trace_save (const char *filename, struct trace_file_writer *writer,
55 int target_does_save)
56{
57 struct trace_status *ts = current_trace_status ();
58 int status;
59 struct uploaded_tp *uploaded_tps = NULL, *utp;
60 struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
61
62 ULONGEST offset = 0;
63#define MAX_TRACE_UPLOAD 2000
64 gdb_byte buf[MAX_TRACE_UPLOAD];
65 int written;
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. */
80 status = target_get_trace_status (ts);
81
82 writer->ops->start (writer, filename);
83
84 writer->ops->write_header (writer);
85
86 /* Write descriptive info. */
87
88 /* Write out the size of a register block. */
89 writer->ops->write_regblock_type (writer, trace_regblock_size);
90
91 /* Write out status of the tracing run (aka "tstatus" info). */
92 writer->ops->write_status (writer, ts);
93
94 /* Note that we want to upload tracepoints and save those, rather
95 than simply writing out the local ones, because the user may have
96 changed tracepoints in GDB in preparation for a future tracing
97 run, or maybe just mass-deleted all types of breakpoints as part
98 of cleaning up. So as not to contaminate the session, leave the
99 data in its uploaded form, don't make into real tracepoints. */
100
101 /* Get trace state variables first, they may be checked when parsing
102 uploaded commands. */
103
104 target_upload_trace_state_variables (&uploaded_tsvs);
105
106 for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
107 writer->ops->write_uploaded_tsv (writer, utsv);
108
109 free_uploaded_tsvs (&uploaded_tsvs);
110
111 target_upload_tracepoints (&uploaded_tps);
112
113 for (utp = uploaded_tps; utp; utp = utp->next)
114 target_get_tracepoint_status (NULL, utp);
115
116 for (utp = uploaded_tps; utp; utp = utp->next)
117 writer->ops->write_uploaded_tp (writer, utp);
118
119 free_uploaded_tps (&uploaded_tps);
120
121 /* Mark the end of the definition section. */
122 writer->ops->write_definition_end (writer);
123
124 /* Get and write the trace data proper. */
125 while (1)
126 {
127 LONGEST gotten = 0;
128
129 /* The writer supports writing the contents of trace buffer
130 directly to trace file. Don't parse the contents of trace
131 buffer. */
132 if (writer->ops->write_trace_buffer != NULL)
133 {
134 /* We ask for big blocks, in the hopes of efficiency, but
135 will take less if the target has packet size limitations
136 or some such. */
137 gotten = target_get_raw_trace_data (buf, offset,
138 MAX_TRACE_UPLOAD);
139 if (gotten < 0)
140 error (_("Failure to get requested trace buffer data"));
141 /* No more data is forthcoming, we're done. */
142 if (gotten == 0)
143 break;
144
145 writer->ops->write_trace_buffer (writer, buf, gotten);
146
147 offset += gotten;
148 }
149 else
150 {
151 uint16_t tp_num;
152 uint32_t tf_size;
153 /* Parse the trace buffers according to how data are stored
154 in trace buffer in GDBserver. */
155
156 gotten = target_get_raw_trace_data (buf, offset, 6);
157
158 if (gotten == 0)
159 break;
160
161 /* Read the first six bytes in, which is the tracepoint
162 number and trace frame size. */
163 tp_num = (uint16_t)
164 extract_unsigned_integer (&buf[0], 2, byte_order);
165
166 tf_size = (uint32_t)
167 extract_unsigned_integer (&buf[2], 4, byte_order);
168
169 writer->ops->frame_ops->start (writer, tp_num);
170 gotten = 6;
171
172 if (tf_size > 0)
173 {
174 unsigned int block;
175
176 offset += 6;
177
178 for (block = 0; block < tf_size; )
179 {
180 gdb_byte block_type;
181
182 /* We'll fetch one block each time, in order to
183 handle the extremely large 'M' block. We first
184 fetch one byte to get the type of the block. */
185 gotten = target_get_raw_trace_data (buf, offset, 1);
186 if (gotten < 1)
187 error (_("Failure to get requested trace buffer data"));
188
189 gotten = 1;
190 block += 1;
191 offset += 1;
192
193 block_type = buf[0];
194 switch (block_type)
195 {
196 case 'R':
197 gotten
198 = target_get_raw_trace_data (buf, offset,
199 trace_regblock_size);
200 if (gotten < trace_regblock_size)
201 error (_("Failure to get requested trace"
202 " buffer data"));
203
204 TRACE_WRITE_R_BLOCK (writer, buf,
205 trace_regblock_size);
206 break;
207 case 'M':
208 {
209 unsigned short mlen;
210 ULONGEST addr;
211 LONGEST t;
212 int j;
213
214 t = target_get_raw_trace_data (buf,offset, 10);
215 if (t < 10)
216 error (_("Failure to get requested trace"
217 " buffer data"));
218
219 offset += 10;
220 block += 10;
221
222 gotten = 0;
223 addr = (ULONGEST)
224 extract_unsigned_integer (buf, 8,
225 byte_order);
226 mlen = (unsigned short)
227 extract_unsigned_integer (&buf[8], 2,
228 byte_order);
229
230 TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
231 mlen);
232
233 /* The memory contents in 'M' block may be
234 very large. Fetch the data from the target
235 and write them into file one by one. */
236 for (j = 0; j < mlen; )
237 {
238 unsigned int read_length;
239
240 if (mlen - j > MAX_TRACE_UPLOAD)
241 read_length = MAX_TRACE_UPLOAD;
242 else
243 read_length = mlen - j;
244
245 t = target_get_raw_trace_data (buf,
246 offset + j,
247 read_length);
248 if (t < read_length)
249 error (_("Failure to get requested"
250 " trace buffer data"));
251
252 TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
253 read_length);
254
255 j += read_length;
256 gotten += read_length;
257 }
258
259 break;
260 }
261 case 'V':
262 {
263 int vnum;
264 LONGEST val;
265
266 gotten
267 = target_get_raw_trace_data (buf, offset,
268 12);
269 if (gotten < 12)
270 error (_("Failure to get requested"
271 " trace buffer data"));
272
273 vnum = (int) extract_signed_integer (buf,
274 4,
275 byte_order);
276 val
277 = extract_signed_integer (&buf[4], 8,
278 byte_order);
279
280 TRACE_WRITE_V_BLOCK (writer, vnum, val);
281 }
282 break;
283 default:
284 error (_("Unknown block type '%c' (0x%x) in"
285 " trace frame"),
286 block_type, block_type);
287 }
288
289 block += gotten;
290 offset += gotten;
291 }
292 }
293 else
294 offset += gotten;
295
296 writer->ops->frame_ops->end (writer);
297 }
298 }
299
300 writer->ops->end (writer);
301}
302
303static void
304trace_save_command (char *args, int from_tty)
305{
306 int target_does_save = 0;
307 char **argv;
308 char *filename = NULL;
309 struct cleanup *back_to;
310 int generate_ctf = 0;
311 struct trace_file_writer *writer = NULL;
312
313 if (args == NULL)
314 error_no_arg (_("file in which to save trace data"));
315
316 argv = gdb_buildargv (args);
317 back_to = make_cleanup_freeargv (argv);
318
319 for (; *argv; ++argv)
320 {
321 if (strcmp (*argv, "-r") == 0)
322 target_does_save = 1;
323 if (strcmp (*argv, "-ctf") == 0)
324 generate_ctf = 1;
325 else if (**argv == '-')
326 error (_("unknown option `%s'"), *argv);
327 else
328 filename = *argv;
329 }
330
331 if (!filename)
332 error_no_arg (_("file in which to save trace data"));
333
334 if (generate_ctf)
335 writer = ctf_trace_file_writer_new ();
336 else
337 writer = tfile_trace_file_writer_new ();
338
339 make_cleanup (trace_file_writer_xfree, writer);
340
341 trace_save (filename, writer, target_does_save);
342
343 if (from_tty)
344 printf_filtered (_("Trace data saved to %s '%s'.\n"),
345 generate_ctf ? "directory" : "file", filename);
346
347 do_cleanups (back_to);
348}
349
350/* Save the trace data to file FILENAME of tfile format. */
351
352void
353trace_save_tfile (const char *filename, int target_does_save)
354{
355 struct trace_file_writer *writer;
356 struct cleanup *back_to;
357
358 writer = tfile_trace_file_writer_new ();
359 back_to = make_cleanup (trace_file_writer_xfree, writer);
360 trace_save (filename, writer, target_does_save);
361 do_cleanups (back_to);
362}
363
364/* Save the trace data to dir DIRNAME of ctf format. */
365
366void
367trace_save_ctf (const char *dirname, int target_does_save)
368{
369 struct trace_file_writer *writer;
370 struct cleanup *back_to;
371
372 writer = ctf_trace_file_writer_new ();
373 back_to = make_cleanup (trace_file_writer_xfree, writer);
374
375 trace_save (dirname, writer, target_does_save);
376 do_cleanups (back_to);
377}
378
379extern initialize_file_ftype _initialize_tracefile;
380
381void
382_initialize_tracefile (void)
383{
384 add_com ("tsave", class_trace, trace_save_command, _("\
385Save the trace data to a file.\n\
386Use the '-ctf' option to save the data to CTF format.\n\
387Use the '-r' option to direct the target to save directly to the file,\n\
388using its own filesystem."));
389}
This page took 0.038071 seconds and 4 git commands to generate.