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