GDB (xrefs)
Loading...
Searching...
No Matches
tracefile.c
Go to the documentation of this file.
1/* Trace file support in GDB.
2
3 Copyright (C) 1997-2023 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
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
55typedef std::unique_ptr<trace_file_writer, trace_file_writer_deleter>
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
63static void
64trace_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. */
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. */
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
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)
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,
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,
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 (),
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
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"),
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
319static void
320tsave_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
360void
361trace_save_tfile (const char *filename, int target_does_save)
362{
364 trace_save (filename, writer.get (), target_does_save);
365}
366
367/* Save the trace data to dir DIRNAME of ctf format. */
368
369void
370trace_save_ctf (const char *dirname, int target_does_save)
371{
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
379void
381{
382 struct gdbarch *gdbarch = regcache->arch ();
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 == nullptr || !tp->has_locations ())
394 return;
395
396 /* But don't try to guess if tracepoint is multi-location... */
397 if (tp->has_multiple_locations ())
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. */
415 tp->first_loc ().address);
416}
417
418/* This is the implementation of target_ops method to_has_all_memory. */
419
420bool
422{
423 return true;
424}
425
426/* This is the implementation of target_ops method to_has_memory. */
427
428bool
430{
431 return true;
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
438bool
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
448bool
453
454/* This is the implementation of target_ops method to_thread_alive.
455 tracefile has one thread faked by GDB. */
456
457bool
459{
460 return true;
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
466int
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
476void
478{
479 add_com ("tsave", class_trace, tsave_command, _("\
480Save the trace data to a file.\n\
481Use the '-ctf' option to save the data to CTF format.\n\
482Use the '-r' option to direct the target to save directly to the file,\n\
483using its own filesystem."));
484}
void xfree(void *)
struct gdbarch * target_gdbarch(void)
struct tracepoint * get_tracepoint(int num)
CORE_ADDR address
Definition breakpoint.h:437
gdbarch * arch() const
Definition regcache.c:231
void raw_supply(int regnum, const void *buf) override
Definition regcache.c:1062
bool has_registers() override
Definition tracefile.c:449
bool has_stack() override
Definition tracefile.c:439
bool has_all_memory() override
Definition tracefile.c:421
bool has_memory() override
Definition tracefile.c:429
int get_trace_status(trace_status *ts) override
Definition tracefile.c:467
bool thread_alive(ptid_t ptid) override
Definition tracefile.c:458
void error_no_arg(const char *why)
Definition cli-cmds.c:206
struct cmd_list_element * add_com(const char *name, enum command_class theclass, cmd_simple_func_ftype *fun, const char *doc)
@ class_trace
Definition command.h:61
static LONGEST extract_signed_integer(gdb::array_view< const gdb_byte > buf, enum bfd_endian byte_order)
Definition defs.h:465
static ULONGEST extract_unsigned_integer(gdb::array_view< const gdb_byte > buf, enum bfd_endian byte_order)
Definition defs.h:480
enum bfd_endian gdbarch_byte_order(struct gdbarch *gdbarch)
Definition gdbarch.c:1396
int gdbarch_num_regs(struct gdbarch *gdbarch)
Definition gdbarch.c:1930
void gdbarch_guess_tracepoint_registers(struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr)
Definition gdbarch.c:4922
block_type
Definition mdebugread.c:237
Definition block.h:109
bool has_locations() const
Definition breakpoint.h:661
bp_location & first_loc()
Definition breakpoint.h:683
bool has_multiple_locations() const
Definition breakpoint.h:674
void(* start)(struct trace_file_writer *self, const char *name)
Definition tracefile.h:66
void(* write_header)(struct trace_file_writer *self)
Definition tracefile.h:70
void(* write_definition_end)(struct trace_file_writer *self)
Definition tracefile.h:93
void(* write_uploaded_tsv)(struct trace_file_writer *self, struct uploaded_tsv *tsv)
Definition tracefile.h:82
void(* dtor)(struct trace_file_writer *self)
Definition tracefile.h:57
void(* end)(struct trace_file_writer *self)
Definition tracefile.h:106
void(* write_regblock_type)(struct trace_file_writer *self, int size)
Definition tracefile.h:74
void(* write_trace_buffer)(struct trace_file_writer *self, gdb_byte *buf, LONGEST len)
Definition tracefile.h:97
void(* write_uploaded_tp)(struct trace_file_writer *self, struct uploaded_tp *tp)
Definition tracefile.h:86
int(* target_save)(struct trace_file_writer *self, const char *name)
Definition tracefile.h:62
const struct trace_frame_write_ops * frame_ops
Definition tracefile.h:103
void(* write_tdesc)(struct trace_file_writer *self)
Definition tracefile.h:90
void(* write_status)(struct trace_file_writer *self, struct trace_status *ts)
Definition tracefile.h:78
void operator()(struct trace_file_writer *writer)
Definition tracefile.c:46
const struct trace_file_write_ops * ops
Definition tracefile.h:113
void(* end)(struct trace_file_writer *self)
Definition tracefile.h:48
void(* start)(struct trace_file_writer *self, uint16_t tpnum)
Definition tracefile.h:16
long step_count
struct uploaded_tp * next
Definition tracepoint.h:203
struct uploaded_tsv * next
Definition tracepoint.h:214
LONGEST target_get_raw_trace_data(gdb_byte *buf, ULONGEST offset, LONGEST len)
Definition target.c:719
int target_upload_trace_state_variables(uploaded_tsv **utsvp)
Definition target.c:711
int target_upload_tracepoints(uploaded_tp **utpp)
Definition target.c:705
int target_get_trace_status(trace_status *ts)
Definition target.c:664
void target_get_tracepoint_status(tracepoint *tp, uploaded_tp *utp)
Definition target.c:670
struct trace_file_writer * ctf_trace_file_writer_new(void)
Definition tracectf.c:808
struct trace_file_writer * tfile_trace_file_writer_new(void)
int trace_regblock_size
void _initialize_tracefile()
Definition tracefile.c:477
void tracefile_fetch_registers(struct regcache *regcache, int regno)
Definition tracefile.c:380
#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size)
Definition tracefile.c:36
#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size)
Definition tracefile.c:33
std::unique_ptr< trace_file_writer, trace_file_writer_deleter > trace_file_writer_up
Definition tracefile.c:56
static void tsave_command(const char *args, int from_tty)
Definition tracefile.c:320
static void trace_save(const char *filename, struct trace_file_writer *writer, int target_does_save)
Definition tracefile.c:64
#define TRACE_WRITE_V_BLOCK(writer, num, val)
Definition tracefile.c:39
#define TRACE_WRITE_R_BLOCK(writer, buf, size)
Definition tracefile.c:31
#define MAX_TRACE_UPLOAD
void trace_save_tfile(const char *filename, int target_does_save)
Definition tracefile.c:361
void trace_save_ctf(const char *dirname, int target_does_save)
Definition tracefile.c:370
int get_tracepoint_number(void)
struct trace_status * current_trace_status(void)
Definition tracepoint.c:175
int get_traceframe_number(void)
void free_uploaded_tps(struct uploaded_tp **utpp)
void free_uploaded_tsvs(struct uploaded_tsv **utsvp)
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1886