tracefile-tfile.c revision 1.10 1 1.1 christos /* Trace file TFILE format support in GDB.
2 1.1 christos
3 1.9 christos Copyright (C) 1997-2024 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This file is part of GDB.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.9 christos #include "extract-store-integer.h"
21 1.1 christos #include "tracefile.h"
22 1.1 christos #include "readline/tilde.h"
23 1.7 christos #include "gdbsupport/filestuff.h"
24 1.9 christos #include "gdbsupport/rsp-low.h"
25 1.1 christos #include "regcache.h"
26 1.1 christos #include "inferior.h"
27 1.1 christos #include "gdbthread.h"
28 1.8 christos #include "exec.h"
29 1.1 christos #include "completer.h"
30 1.1 christos #include "filenames.h"
31 1.4 christos #include "remote.h"
32 1.4 christos #include "xml-tdesc.h"
33 1.4 christos #include "target-descriptions.h"
34 1.7 christos #include "gdbsupport/pathstuff.h"
35 1.5 christos #include <algorithm>
36 1.1 christos
37 1.1 christos #ifndef O_LARGEFILE
38 1.1 christos #define O_LARGEFILE 0
39 1.1 christos #endif
40 1.1 christos
41 1.6 christos /* The tfile target. */
42 1.6 christos
43 1.6 christos static const target_info tfile_target_info = {
44 1.6 christos "tfile",
45 1.6 christos N_("Local trace dump file"),
46 1.7 christos N_("Use a trace file as a target.\n\
47 1.7 christos Specify the filename of the trace file.")
48 1.6 christos };
49 1.6 christos
50 1.6 christos class tfile_target final : public tracefile_target
51 1.6 christos {
52 1.6 christos public:
53 1.6 christos const target_info &info () const override
54 1.6 christos { return tfile_target_info; }
55 1.6 christos
56 1.6 christos void close () override;
57 1.6 christos void fetch_registers (struct regcache *, int) override;
58 1.6 christos enum target_xfer_status xfer_partial (enum target_object object,
59 1.6 christos const char *annex,
60 1.6 christos gdb_byte *readbuf,
61 1.6 christos const gdb_byte *writebuf,
62 1.6 christos ULONGEST offset, ULONGEST len,
63 1.6 christos ULONGEST *xfered_len) override;
64 1.6 christos void files_info () override;
65 1.6 christos int trace_find (enum trace_find_type type, int num,
66 1.6 christos CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override;
67 1.6 christos bool get_trace_state_variable_value (int tsv, LONGEST *val) override;
68 1.6 christos traceframe_info_up traceframe_info () override;
69 1.6 christos
70 1.9 christos void get_tracepoint_status (tracepoint *tp,
71 1.6 christos struct uploaded_tp *utp) override;
72 1.6 christos };
73 1.6 christos
74 1.1 christos /* TFILE trace writer. */
75 1.1 christos
76 1.1 christos struct tfile_trace_file_writer
77 1.1 christos {
78 1.1 christos struct trace_file_writer base;
79 1.1 christos
80 1.1 christos /* File pointer to tfile trace file. */
81 1.1 christos FILE *fp;
82 1.1 christos /* Path name of the tfile trace file. */
83 1.1 christos char *pathname;
84 1.1 christos };
85 1.1 christos
86 1.1 christos /* This is the implementation of trace_file_write_ops method
87 1.1 christos target_save. We just call the generic target
88 1.1 christos target_save_trace_data to do target-side saving. */
89 1.1 christos
90 1.1 christos static int
91 1.1 christos tfile_target_save (struct trace_file_writer *self,
92 1.1 christos const char *filename)
93 1.1 christos {
94 1.1 christos int err = target_save_trace_data (filename);
95 1.1 christos
96 1.1 christos return (err >= 0);
97 1.1 christos }
98 1.1 christos
99 1.1 christos /* This is the implementation of trace_file_write_ops method
100 1.1 christos dtor. */
101 1.1 christos
102 1.1 christos static void
103 1.1 christos tfile_dtor (struct trace_file_writer *self)
104 1.1 christos {
105 1.1 christos struct tfile_trace_file_writer *writer
106 1.1 christos = (struct tfile_trace_file_writer *) self;
107 1.1 christos
108 1.1 christos xfree (writer->pathname);
109 1.1 christos
110 1.1 christos if (writer->fp != NULL)
111 1.1 christos fclose (writer->fp);
112 1.1 christos }
113 1.1 christos
114 1.1 christos /* This is the implementation of trace_file_write_ops method
115 1.1 christos start. It creates the trace file FILENAME and registers some
116 1.1 christos cleanups. */
117 1.1 christos
118 1.1 christos static void
119 1.1 christos tfile_start (struct trace_file_writer *self, const char *filename)
120 1.1 christos {
121 1.1 christos struct tfile_trace_file_writer *writer
122 1.1 christos = (struct tfile_trace_file_writer *) self;
123 1.1 christos
124 1.1 christos writer->pathname = tilde_expand (filename);
125 1.6 christos writer->fp = gdb_fopen_cloexec (writer->pathname, "wb").release ();
126 1.1 christos if (writer->fp == NULL)
127 1.1 christos error (_("Unable to open file '%s' for saving trace data (%s)"),
128 1.1 christos writer->pathname, safe_strerror (errno));
129 1.1 christos }
130 1.1 christos
131 1.1 christos /* This is the implementation of trace_file_write_ops method
132 1.1 christos write_header. Write the TFILE header. */
133 1.1 christos
134 1.1 christos static void
135 1.1 christos tfile_write_header (struct trace_file_writer *self)
136 1.1 christos {
137 1.1 christos struct tfile_trace_file_writer *writer
138 1.1 christos = (struct tfile_trace_file_writer *) self;
139 1.1 christos int written;
140 1.1 christos
141 1.1 christos /* Write a file header, with a high-bit-set char to indicate a
142 1.1 christos binary file, plus a hint as what this file is, and a version
143 1.1 christos number in case of future needs. */
144 1.1 christos written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
145 1.1 christos if (written < 1)
146 1.1 christos perror_with_name (writer->pathname);
147 1.1 christos }
148 1.1 christos
149 1.1 christos /* This is the implementation of trace_file_write_ops method
150 1.1 christos write_regblock_type. Write the size of register block. */
151 1.1 christos
152 1.1 christos static void
153 1.1 christos tfile_write_regblock_type (struct trace_file_writer *self, int size)
154 1.1 christos {
155 1.1 christos struct tfile_trace_file_writer *writer
156 1.1 christos = (struct tfile_trace_file_writer *) self;
157 1.1 christos
158 1.1 christos fprintf (writer->fp, "R %x\n", size);
159 1.1 christos }
160 1.1 christos
161 1.1 christos /* This is the implementation of trace_file_write_ops method
162 1.1 christos write_status. */
163 1.1 christos
164 1.1 christos static void
165 1.1 christos tfile_write_status (struct trace_file_writer *self,
166 1.1 christos struct trace_status *ts)
167 1.1 christos {
168 1.1 christos struct tfile_trace_file_writer *writer
169 1.1 christos = (struct tfile_trace_file_writer *) self;
170 1.1 christos
171 1.1 christos fprintf (writer->fp, "status %c;%s",
172 1.1 christos (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
173 1.1 christos if (ts->stop_reason == tracepoint_error
174 1.5 christos || ts->stop_reason == trace_stop_command)
175 1.1 christos {
176 1.1 christos char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
177 1.1 christos
178 1.1 christos bin2hex ((gdb_byte *) ts->stop_desc, buf, strlen (ts->stop_desc));
179 1.1 christos fprintf (writer->fp, ":%s", buf);
180 1.1 christos }
181 1.1 christos fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
182 1.1 christos if (ts->traceframe_count >= 0)
183 1.1 christos fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
184 1.1 christos if (ts->traceframes_created >= 0)
185 1.1 christos fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
186 1.1 christos if (ts->buffer_free >= 0)
187 1.1 christos fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
188 1.1 christos if (ts->buffer_size >= 0)
189 1.1 christos fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
190 1.1 christos if (ts->disconnected_tracing)
191 1.1 christos fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
192 1.1 christos if (ts->circular_buffer)
193 1.1 christos fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
194 1.1 christos if (ts->start_time)
195 1.1 christos {
196 1.1 christos fprintf (writer->fp, ";starttime:%s",
197 1.1 christos phex_nz (ts->start_time, sizeof (ts->start_time)));
198 1.1 christos }
199 1.1 christos if (ts->stop_time)
200 1.1 christos {
201 1.1 christos fprintf (writer->fp, ";stoptime:%s",
202 1.1 christos phex_nz (ts->stop_time, sizeof (ts->stop_time)));
203 1.1 christos }
204 1.1 christos if (ts->notes != NULL)
205 1.1 christos {
206 1.1 christos char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
207 1.1 christos
208 1.1 christos bin2hex ((gdb_byte *) ts->notes, buf, strlen (ts->notes));
209 1.1 christos fprintf (writer->fp, ";notes:%s", buf);
210 1.1 christos }
211 1.1 christos if (ts->user_name != NULL)
212 1.1 christos {
213 1.1 christos char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
214 1.1 christos
215 1.1 christos bin2hex ((gdb_byte *) ts->user_name, buf, strlen (ts->user_name));
216 1.1 christos fprintf (writer->fp, ";username:%s", buf);
217 1.1 christos }
218 1.1 christos fprintf (writer->fp, "\n");
219 1.1 christos }
220 1.1 christos
221 1.1 christos /* This is the implementation of trace_file_write_ops method
222 1.1 christos write_uploaded_tsv. */
223 1.1 christos
224 1.1 christos static void
225 1.1 christos tfile_write_uploaded_tsv (struct trace_file_writer *self,
226 1.1 christos struct uploaded_tsv *utsv)
227 1.1 christos {
228 1.9 christos gdb::unique_xmalloc_ptr<char> buf;
229 1.1 christos struct tfile_trace_file_writer *writer
230 1.1 christos = (struct tfile_trace_file_writer *) self;
231 1.1 christos
232 1.1 christos if (utsv->name)
233 1.1 christos {
234 1.9 christos buf.reset ((char *) xmalloc (strlen (utsv->name) * 2 + 1));
235 1.9 christos bin2hex ((gdb_byte *) (utsv->name), buf.get (), strlen (utsv->name));
236 1.1 christos }
237 1.1 christos
238 1.1 christos fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
239 1.1 christos utsv->number, phex_nz (utsv->initial_value, 8),
240 1.9 christos utsv->builtin, buf != NULL ? buf.get () : "");
241 1.1 christos }
242 1.1 christos
243 1.1 christos #define MAX_TRACE_UPLOAD 2000
244 1.1 christos
245 1.1 christos /* This is the implementation of trace_file_write_ops method
246 1.1 christos write_uploaded_tp. */
247 1.1 christos
248 1.1 christos static void
249 1.1 christos tfile_write_uploaded_tp (struct trace_file_writer *self,
250 1.1 christos struct uploaded_tp *utp)
251 1.1 christos {
252 1.1 christos struct tfile_trace_file_writer *writer
253 1.1 christos = (struct tfile_trace_file_writer *) self;
254 1.1 christos char buf[MAX_TRACE_UPLOAD];
255 1.1 christos
256 1.1 christos fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
257 1.1 christos utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
258 1.1 christos (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
259 1.1 christos if (utp->type == bp_fast_tracepoint)
260 1.1 christos fprintf (writer->fp, ":F%x", utp->orig_size);
261 1.1 christos if (utp->cond)
262 1.1 christos fprintf (writer->fp,
263 1.6 christos ":X%x,%s", (unsigned int) strlen (utp->cond.get ()) / 2,
264 1.6 christos utp->cond.get ());
265 1.1 christos fprintf (writer->fp, "\n");
266 1.6 christos for (const auto &act : utp->actions)
267 1.1 christos fprintf (writer->fp, "tp A%x:%s:%s\n",
268 1.6 christos utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
269 1.6 christos for (const auto &act : utp->step_actions)
270 1.1 christos fprintf (writer->fp, "tp S%x:%s:%s\n",
271 1.6 christos utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
272 1.1 christos if (utp->at_string)
273 1.1 christos {
274 1.1 christos encode_source_string (utp->number, utp->addr,
275 1.6 christos "at", utp->at_string.get (),
276 1.6 christos buf, MAX_TRACE_UPLOAD);
277 1.1 christos fprintf (writer->fp, "tp Z%s\n", buf);
278 1.1 christos }
279 1.1 christos if (utp->cond_string)
280 1.1 christos {
281 1.1 christos encode_source_string (utp->number, utp->addr,
282 1.6 christos "cond", utp->cond_string.get (),
283 1.1 christos buf, MAX_TRACE_UPLOAD);
284 1.1 christos fprintf (writer->fp, "tp Z%s\n", buf);
285 1.1 christos }
286 1.6 christos for (const auto &act : utp->cmd_strings)
287 1.1 christos {
288 1.6 christos encode_source_string (utp->number, utp->addr, "cmd", act.get (),
289 1.1 christos buf, MAX_TRACE_UPLOAD);
290 1.1 christos fprintf (writer->fp, "tp Z%s\n", buf);
291 1.1 christos }
292 1.1 christos fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
293 1.1 christos utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
294 1.1 christos utp->hit_count,
295 1.1 christos phex_nz (utp->traceframe_usage,
296 1.1 christos sizeof (utp->traceframe_usage)));
297 1.1 christos }
298 1.1 christos
299 1.1 christos /* This is the implementation of trace_file_write_ops method
300 1.4 christos write_tdesc. */
301 1.4 christos
302 1.4 christos static void
303 1.4 christos tfile_write_tdesc (struct trace_file_writer *self)
304 1.4 christos {
305 1.4 christos struct tfile_trace_file_writer *writer
306 1.4 christos = (struct tfile_trace_file_writer *) self;
307 1.4 christos
308 1.9 christos std::optional<std::string> tdesc
309 1.8 christos = target_fetch_description_xml (current_inferior ()->top_target ());
310 1.6 christos
311 1.6 christos if (!tdesc)
312 1.4 christos return;
313 1.4 christos
314 1.6 christos const char *ptr = tdesc->c_str ();
315 1.6 christos
316 1.4 christos /* Write tdesc line by line, prefixing each line with "tdesc ". */
317 1.4 christos while (ptr != NULL)
318 1.4 christos {
319 1.6 christos const char *next = strchr (ptr, '\n');
320 1.4 christos if (next != NULL)
321 1.4 christos {
322 1.4 christos fprintf (writer->fp, "tdesc %.*s\n", (int) (next - ptr), ptr);
323 1.4 christos /* Skip the \n. */
324 1.4 christos next++;
325 1.4 christos }
326 1.4 christos else if (*ptr != '\0')
327 1.4 christos {
328 1.4 christos /* Last line, doesn't have a newline. */
329 1.4 christos fprintf (writer->fp, "tdesc %s\n", ptr);
330 1.4 christos }
331 1.4 christos ptr = next;
332 1.4 christos }
333 1.4 christos }
334 1.4 christos
335 1.4 christos /* This is the implementation of trace_file_write_ops method
336 1.1 christos write_definition_end. */
337 1.1 christos
338 1.1 christos static void
339 1.1 christos tfile_write_definition_end (struct trace_file_writer *self)
340 1.1 christos {
341 1.1 christos struct tfile_trace_file_writer *writer
342 1.1 christos = (struct tfile_trace_file_writer *) self;
343 1.1 christos
344 1.1 christos fprintf (writer->fp, "\n");
345 1.1 christos }
346 1.1 christos
347 1.1 christos /* This is the implementation of trace_file_write_ops method
348 1.1 christos write_raw_data. */
349 1.1 christos
350 1.1 christos static void
351 1.1 christos tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
352 1.1 christos LONGEST len)
353 1.1 christos {
354 1.1 christos struct tfile_trace_file_writer *writer
355 1.1 christos = (struct tfile_trace_file_writer *) self;
356 1.1 christos
357 1.1 christos if (fwrite (buf, len, 1, writer->fp) < 1)
358 1.1 christos perror_with_name (writer->pathname);
359 1.1 christos }
360 1.1 christos
361 1.1 christos /* This is the implementation of trace_file_write_ops method
362 1.1 christos end. */
363 1.1 christos
364 1.1 christos static void
365 1.1 christos tfile_end (struct trace_file_writer *self)
366 1.1 christos {
367 1.1 christos struct tfile_trace_file_writer *writer
368 1.1 christos = (struct tfile_trace_file_writer *) self;
369 1.1 christos uint32_t gotten = 0;
370 1.1 christos
371 1.1 christos /* Mark the end of trace data. */
372 1.1 christos if (fwrite (&gotten, 4, 1, writer->fp) < 1)
373 1.1 christos perror_with_name (writer->pathname);
374 1.1 christos }
375 1.1 christos
376 1.1 christos /* Operations to write trace buffers into TFILE format. */
377 1.1 christos
378 1.1 christos static const struct trace_file_write_ops tfile_write_ops =
379 1.1 christos {
380 1.1 christos tfile_dtor,
381 1.1 christos tfile_target_save,
382 1.1 christos tfile_start,
383 1.1 christos tfile_write_header,
384 1.1 christos tfile_write_regblock_type,
385 1.1 christos tfile_write_status,
386 1.1 christos tfile_write_uploaded_tsv,
387 1.1 christos tfile_write_uploaded_tp,
388 1.4 christos tfile_write_tdesc,
389 1.1 christos tfile_write_definition_end,
390 1.1 christos tfile_write_raw_data,
391 1.1 christos NULL,
392 1.1 christos tfile_end,
393 1.1 christos };
394 1.1 christos
395 1.1 christos /* Return a trace writer for TFILE format. */
396 1.1 christos
397 1.1 christos struct trace_file_writer *
398 1.1 christos tfile_trace_file_writer_new (void)
399 1.1 christos {
400 1.1 christos struct tfile_trace_file_writer *writer
401 1.4 christos = XNEW (struct tfile_trace_file_writer);
402 1.1 christos
403 1.1 christos writer->base.ops = &tfile_write_ops;
404 1.1 christos writer->fp = NULL;
405 1.1 christos writer->pathname = NULL;
406 1.1 christos
407 1.1 christos return (struct trace_file_writer *) writer;
408 1.1 christos }
409 1.1 christos
410 1.1 christos /* target tfile command */
411 1.1 christos
412 1.6 christos static tfile_target tfile_ops;
413 1.1 christos
414 1.1 christos #define TRACE_HEADER_SIZE 8
415 1.1 christos
416 1.1 christos #define TFILE_PID (1)
417 1.1 christos
418 1.9 christos static gdb::unique_xmalloc_ptr<char> trace_filename;
419 1.1 christos static int trace_fd = -1;
420 1.1 christos static off_t trace_frames_offset;
421 1.1 christos static off_t cur_offset;
422 1.1 christos static int cur_data_size;
423 1.1 christos int trace_regblock_size;
424 1.9 christos static std::string trace_tdesc;
425 1.1 christos
426 1.4 christos static void tfile_append_tdesc_line (const char *line);
427 1.9 christos static void tfile_interp_line (const char *line,
428 1.1 christos struct uploaded_tp **utpp,
429 1.1 christos struct uploaded_tsv **utsvp);
430 1.1 christos
431 1.1 christos /* Read SIZE bytes into READBUF from the trace frame, starting at
432 1.1 christos TRACE_FD's current position. Note that this call `read'
433 1.1 christos underneath, hence it advances the file's seek position. Throws an
434 1.1 christos error if the `read' syscall fails, or less than SIZE bytes are
435 1.1 christos read. */
436 1.1 christos
437 1.1 christos static void
438 1.1 christos tfile_read (gdb_byte *readbuf, int size)
439 1.1 christos {
440 1.1 christos int gotten;
441 1.1 christos
442 1.1 christos gotten = read (trace_fd, readbuf, size);
443 1.1 christos if (gotten < 0)
444 1.9 christos perror_with_name (trace_filename.get ());
445 1.1 christos else if (gotten < size)
446 1.1 christos error (_("Premature end of file while reading trace file"));
447 1.1 christos }
448 1.1 christos
449 1.6 christos /* Open the tfile target. */
450 1.6 christos
451 1.1 christos static void
452 1.6 christos tfile_target_open (const char *arg, int from_tty)
453 1.1 christos {
454 1.1 christos int flags;
455 1.1 christos int scratch_chan;
456 1.1 christos char header[TRACE_HEADER_SIZE];
457 1.1 christos char linebuf[1000]; /* Should be max remote packet size or so. */
458 1.1 christos gdb_byte byte;
459 1.1 christos int bytes, i;
460 1.1 christos struct trace_status *ts;
461 1.1 christos struct uploaded_tp *uploaded_tps = NULL;
462 1.1 christos struct uploaded_tsv *uploaded_tsvs = NULL;
463 1.1 christos
464 1.1 christos target_preopen (from_tty);
465 1.10 christos std::string filename = extract_single_filename_arg (arg);
466 1.10 christos if (filename.empty ())
467 1.1 christos error (_("No trace file specified."));
468 1.1 christos
469 1.10 christos if (!IS_ABSOLUTE_PATH (filename.c_str ()))
470 1.10 christos filename = gdb_abspath (filename);
471 1.1 christos
472 1.1 christos flags = O_BINARY | O_LARGEFILE;
473 1.1 christos flags |= O_RDONLY;
474 1.10 christos scratch_chan = gdb_open_cloexec (filename.c_str (), flags, 0).release ();
475 1.1 christos if (scratch_chan < 0)
476 1.10 christos perror_with_name (filename.c_str ());
477 1.1 christos
478 1.1 christos /* Looks semi-reasonable. Toss the old trace file and work on the new. */
479 1.1 christos
480 1.8 christos current_inferior ()->unpush_target (&tfile_ops);
481 1.1 christos
482 1.10 christos trace_filename = make_unique_xstrdup (filename.c_str ());
483 1.1 christos trace_fd = scratch_chan;
484 1.1 christos
485 1.4 christos /* Make sure this is clear. */
486 1.9 christos trace_tdesc.clear ();
487 1.4 christos
488 1.1 christos bytes = 0;
489 1.1 christos /* Read the file header and test for validity. */
490 1.1 christos tfile_read ((gdb_byte *) &header, TRACE_HEADER_SIZE);
491 1.1 christos
492 1.1 christos bytes += TRACE_HEADER_SIZE;
493 1.1 christos if (!(header[0] == 0x7f
494 1.3 christos && (startswith (header + 1, "TRACE0\n"))))
495 1.1 christos error (_("File is not a valid trace file."));
496 1.1 christos
497 1.8 christos current_inferior ()->push_target (&tfile_ops);
498 1.1 christos
499 1.1 christos trace_regblock_size = 0;
500 1.1 christos ts = current_trace_status ();
501 1.1 christos /* We know we're working with a file. Record its name. */
502 1.9 christos ts->filename = trace_filename.get ();
503 1.1 christos /* Set defaults in case there is no status line. */
504 1.1 christos ts->running_known = 0;
505 1.1 christos ts->stop_reason = trace_stop_reason_unknown;
506 1.1 christos ts->traceframe_count = -1;
507 1.1 christos ts->buffer_free = 0;
508 1.1 christos ts->disconnected_tracing = 0;
509 1.1 christos ts->circular_buffer = 0;
510 1.1 christos
511 1.7 christos try
512 1.1 christos {
513 1.1 christos /* Read through a section of newline-terminated lines that
514 1.1 christos define things like tracepoints. */
515 1.1 christos i = 0;
516 1.1 christos while (1)
517 1.1 christos {
518 1.1 christos tfile_read (&byte, 1);
519 1.1 christos
520 1.1 christos ++bytes;
521 1.1 christos if (byte == '\n')
522 1.1 christos {
523 1.1 christos /* Empty line marks end of the definition section. */
524 1.1 christos if (i == 0)
525 1.1 christos break;
526 1.1 christos linebuf[i] = '\0';
527 1.1 christos i = 0;
528 1.1 christos tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
529 1.1 christos }
530 1.1 christos else
531 1.1 christos linebuf[i++] = byte;
532 1.1 christos if (i >= 1000)
533 1.1 christos error (_("Excessively long lines in trace file"));
534 1.1 christos }
535 1.1 christos
536 1.4 christos /* By now, tdesc lines have been read from tfile - let's parse them. */
537 1.4 christos target_find_description ();
538 1.4 christos
539 1.1 christos /* Record the starting offset of the binary trace data. */
540 1.1 christos trace_frames_offset = bytes;
541 1.1 christos
542 1.1 christos /* If we don't have a blocksize, we can't interpret the
543 1.1 christos traceframes. */
544 1.1 christos if (trace_regblock_size == 0)
545 1.1 christos error (_("No register block size recorded in trace file"));
546 1.1 christos }
547 1.7 christos catch (const gdb_exception &ex)
548 1.1 christos {
549 1.1 christos /* Remove the partially set up target. */
550 1.8 christos current_inferior ()->unpush_target (&tfile_ops);
551 1.7 christos throw;
552 1.1 christos }
553 1.1 christos
554 1.1 christos inferior_appeared (current_inferior (), TFILE_PID);
555 1.7 christos
556 1.7 christos thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID));
557 1.7 christos switch_to_thread (thr);
558 1.1 christos
559 1.1 christos if (ts->traceframe_count <= 0)
560 1.1 christos warning (_("No traceframes present in this file."));
561 1.1 christos
562 1.1 christos /* Add the file's tracepoints and variables into the current mix. */
563 1.1 christos
564 1.1 christos /* Get trace state variables first, they may be checked when parsing
565 1.1 christos uploaded commands. */
566 1.1 christos merge_uploaded_trace_state_variables (&uploaded_tsvs);
567 1.1 christos
568 1.1 christos merge_uploaded_tracepoints (&uploaded_tps);
569 1.1 christos
570 1.8 christos post_create_inferior (from_tty);
571 1.1 christos }
572 1.1 christos
573 1.1 christos /* Interpret the given line from the definitions part of the trace
574 1.1 christos file. */
575 1.1 christos
576 1.1 christos static void
577 1.9 christos tfile_interp_line (const char *line, struct uploaded_tp **utpp,
578 1.1 christos struct uploaded_tsv **utsvp)
579 1.1 christos {
580 1.9 christos const char *p = line;
581 1.1 christos
582 1.3 christos if (startswith (p, "R "))
583 1.1 christos {
584 1.1 christos p += strlen ("R ");
585 1.9 christos trace_regblock_size = strtol (p, nullptr, 16);
586 1.1 christos }
587 1.3 christos else if (startswith (p, "status "))
588 1.1 christos {
589 1.1 christos p += strlen ("status ");
590 1.1 christos parse_trace_status (p, current_trace_status ());
591 1.1 christos }
592 1.3 christos else if (startswith (p, "tp "))
593 1.1 christos {
594 1.1 christos p += strlen ("tp ");
595 1.1 christos parse_tracepoint_definition (p, utpp);
596 1.1 christos }
597 1.3 christos else if (startswith (p, "tsv "))
598 1.1 christos {
599 1.1 christos p += strlen ("tsv ");
600 1.1 christos parse_tsv_definition (p, utsvp);
601 1.1 christos }
602 1.4 christos else if (startswith (p, "tdesc "))
603 1.4 christos {
604 1.4 christos p += strlen ("tdesc ");
605 1.4 christos tfile_append_tdesc_line (p);
606 1.4 christos }
607 1.1 christos else
608 1.1 christos warning (_("Ignoring trace file definition \"%s\""), line);
609 1.1 christos }
610 1.1 christos
611 1.1 christos /* Close the trace file and generally clean up. */
612 1.1 christos
613 1.6 christos void
614 1.6 christos tfile_target::close ()
615 1.1 christos {
616 1.7 christos gdb_assert (trace_fd != -1);
617 1.1 christos
618 1.7 christos switch_to_no_thread (); /* Avoid confusion from thread stuff. */
619 1.9 christos exit_inferior (current_inferior ());
620 1.1 christos
621 1.6 christos ::close (trace_fd);
622 1.1 christos trace_fd = -1;
623 1.9 christos trace_filename.reset ();
624 1.9 christos trace_tdesc.clear ();
625 1.1 christos
626 1.1 christos trace_reset_local_state ();
627 1.1 christos }
628 1.1 christos
629 1.6 christos void
630 1.6 christos tfile_target::files_info ()
631 1.1 christos {
632 1.9 christos gdb_printf ("\t`%s'\n", trace_filename.get ());
633 1.1 christos }
634 1.1 christos
635 1.6 christos void
636 1.9 christos tfile_target::get_tracepoint_status (tracepoint *tp, struct uploaded_tp *utp)
637 1.1 christos {
638 1.1 christos /* Other bits of trace status were collected as part of opening the
639 1.1 christos trace files, so nothing to do here. */
640 1.1 christos }
641 1.1 christos
642 1.1 christos /* Given the position of a traceframe in the file, figure out what
643 1.1 christos address the frame was collected at. This would normally be the
644 1.1 christos value of a collected PC register, but if not available, we
645 1.1 christos improvise. */
646 1.1 christos
647 1.1 christos static CORE_ADDR
648 1.1 christos tfile_get_traceframe_address (off_t tframe_offset)
649 1.1 christos {
650 1.1 christos CORE_ADDR addr = 0;
651 1.1 christos short tpnum;
652 1.1 christos struct tracepoint *tp;
653 1.1 christos off_t saved_offset = cur_offset;
654 1.1 christos
655 1.1 christos /* FIXME dig pc out of collected registers. */
656 1.1 christos
657 1.1 christos /* Fall back to using tracepoint address. */
658 1.1 christos lseek (trace_fd, tframe_offset, SEEK_SET);
659 1.1 christos tfile_read ((gdb_byte *) &tpnum, 2);
660 1.1 christos tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
661 1.1 christos gdbarch_byte_order
662 1.9 christos (current_inferior ()->arch ()));
663 1.1 christos
664 1.1 christos tp = get_tracepoint_by_number_on_target (tpnum);
665 1.1 christos /* FIXME this is a poor heuristic if multiple locations. */
666 1.9 christos if (tp != nullptr && tp->has_locations ())
667 1.9 christos addr = tp->first_loc ().address;
668 1.1 christos
669 1.1 christos /* Restore our seek position. */
670 1.1 christos cur_offset = saved_offset;
671 1.1 christos lseek (trace_fd, cur_offset, SEEK_SET);
672 1.1 christos return addr;
673 1.1 christos }
674 1.1 christos
675 1.1 christos /* Given a type of search and some parameters, scan the collection of
676 1.1 christos traceframes in the file looking for a match. When found, return
677 1.1 christos both the traceframe and tracepoint number, otherwise -1 for
678 1.1 christos each. */
679 1.1 christos
680 1.6 christos int
681 1.6 christos tfile_target::trace_find (enum trace_find_type type, int num,
682 1.6 christos CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
683 1.1 christos {
684 1.1 christos short tpnum;
685 1.1 christos int tfnum = 0, found = 0;
686 1.1 christos unsigned int data_size;
687 1.1 christos struct tracepoint *tp;
688 1.1 christos off_t offset, tframe_offset;
689 1.1 christos CORE_ADDR tfaddr;
690 1.1 christos
691 1.1 christos if (num == -1)
692 1.1 christos {
693 1.1 christos if (tpp)
694 1.8 christos *tpp = -1;
695 1.1 christos return -1;
696 1.1 christos }
697 1.1 christos
698 1.1 christos lseek (trace_fd, trace_frames_offset, SEEK_SET);
699 1.1 christos offset = trace_frames_offset;
700 1.1 christos while (1)
701 1.1 christos {
702 1.1 christos tframe_offset = offset;
703 1.1 christos tfile_read ((gdb_byte *) &tpnum, 2);
704 1.1 christos tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
705 1.1 christos gdbarch_byte_order
706 1.9 christos (current_inferior ()->arch ()));
707 1.1 christos offset += 2;
708 1.1 christos if (tpnum == 0)
709 1.1 christos break;
710 1.1 christos tfile_read ((gdb_byte *) &data_size, 4);
711 1.1 christos data_size = (unsigned int) extract_unsigned_integer
712 1.9 christos ((gdb_byte *) &data_size, 4,
713 1.9 christos gdbarch_byte_order
714 1.9 christos (current_inferior ()->arch ()));
715 1.1 christos offset += 4;
716 1.1 christos
717 1.1 christos if (type == tfind_number)
718 1.1 christos {
719 1.1 christos /* Looking for a specific trace frame. */
720 1.1 christos if (tfnum == num)
721 1.1 christos found = 1;
722 1.1 christos }
723 1.1 christos else
724 1.1 christos {
725 1.1 christos /* Start from the _next_ trace frame. */
726 1.1 christos if (tfnum > get_traceframe_number ())
727 1.1 christos {
728 1.1 christos switch (type)
729 1.1 christos {
730 1.1 christos case tfind_pc:
731 1.1 christos tfaddr = tfile_get_traceframe_address (tframe_offset);
732 1.1 christos if (tfaddr == addr1)
733 1.1 christos found = 1;
734 1.1 christos break;
735 1.1 christos case tfind_tp:
736 1.1 christos tp = get_tracepoint (num);
737 1.1 christos if (tp && tpnum == tp->number_on_target)
738 1.1 christos found = 1;
739 1.1 christos break;
740 1.1 christos case tfind_range:
741 1.1 christos tfaddr = tfile_get_traceframe_address (tframe_offset);
742 1.1 christos if (addr1 <= tfaddr && tfaddr <= addr2)
743 1.1 christos found = 1;
744 1.1 christos break;
745 1.1 christos case tfind_outside:
746 1.1 christos tfaddr = tfile_get_traceframe_address (tframe_offset);
747 1.1 christos if (!(addr1 <= tfaddr && tfaddr <= addr2))
748 1.1 christos found = 1;
749 1.1 christos break;
750 1.1 christos default:
751 1.8 christos internal_error (_("unknown tfind type"));
752 1.1 christos }
753 1.1 christos }
754 1.1 christos }
755 1.1 christos
756 1.1 christos if (found)
757 1.1 christos {
758 1.1 christos if (tpp)
759 1.1 christos *tpp = tpnum;
760 1.1 christos cur_offset = offset;
761 1.1 christos cur_data_size = data_size;
762 1.1 christos
763 1.1 christos return tfnum;
764 1.1 christos }
765 1.1 christos /* Skip past the traceframe's data. */
766 1.1 christos lseek (trace_fd, data_size, SEEK_CUR);
767 1.1 christos offset += data_size;
768 1.1 christos /* Update our own count of traceframes. */
769 1.1 christos ++tfnum;
770 1.1 christos }
771 1.1 christos /* Did not find what we were looking for. */
772 1.1 christos if (tpp)
773 1.1 christos *tpp = -1;
774 1.1 christos return -1;
775 1.1 christos }
776 1.1 christos
777 1.1 christos /* Walk over all traceframe block starting at POS offset from
778 1.9 christos CUR_OFFSET, and call CALLBACK for each block found. If CALLBACK
779 1.9 christos returns true, this returns the position in the traceframe where the
780 1.9 christos block is found, relative to the start of the traceframe
781 1.9 christos (cur_offset). Returns -1 if no callback call returned true,
782 1.9 christos indicating that all blocks have been walked. */
783 1.1 christos
784 1.1 christos static int
785 1.9 christos traceframe_walk_blocks (gdb::function_view<bool (char)> callback, int pos)
786 1.1 christos {
787 1.1 christos /* Iterate through a traceframe's blocks, looking for a block of the
788 1.1 christos requested type. */
789 1.1 christos
790 1.1 christos lseek (trace_fd, cur_offset + pos, SEEK_SET);
791 1.1 christos while (pos < cur_data_size)
792 1.1 christos {
793 1.1 christos unsigned short mlen;
794 1.1 christos char block_type;
795 1.1 christos
796 1.1 christos tfile_read ((gdb_byte *) &block_type, 1);
797 1.1 christos
798 1.1 christos ++pos;
799 1.1 christos
800 1.9 christos if (callback (block_type))
801 1.1 christos return pos;
802 1.1 christos
803 1.1 christos switch (block_type)
804 1.1 christos {
805 1.1 christos case 'R':
806 1.1 christos lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
807 1.1 christos pos += trace_regblock_size;
808 1.1 christos break;
809 1.1 christos case 'M':
810 1.1 christos lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
811 1.1 christos tfile_read ((gdb_byte *) &mlen, 2);
812 1.8 christos mlen = (unsigned short)
813 1.8 christos extract_unsigned_integer ((gdb_byte *) &mlen, 2,
814 1.8 christos gdbarch_byte_order
815 1.9 christos (current_inferior ()->arch ()));
816 1.1 christos lseek (trace_fd, mlen, SEEK_CUR);
817 1.1 christos pos += (8 + 2 + mlen);
818 1.1 christos break;
819 1.1 christos case 'V':
820 1.1 christos lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
821 1.1 christos pos += (4 + 8);
822 1.1 christos break;
823 1.1 christos default:
824 1.1 christos error (_("Unknown block type '%c' (0x%x) in trace frame"),
825 1.1 christos block_type, block_type);
826 1.1 christos break;
827 1.1 christos }
828 1.1 christos }
829 1.1 christos
830 1.1 christos return -1;
831 1.1 christos }
832 1.1 christos
833 1.1 christos /* Convenience wrapper around traceframe_walk_blocks. Looks for the
834 1.1 christos position offset of a block of type TYPE_WANTED in the current trace
835 1.1 christos frame, starting at POS. Returns -1 if no such block was found. */
836 1.1 christos
837 1.1 christos static int
838 1.1 christos traceframe_find_block_type (char type_wanted, int pos)
839 1.1 christos {
840 1.9 christos return traceframe_walk_blocks ([&] (char blocktype)
841 1.9 christos {
842 1.9 christos return blocktype == type_wanted;
843 1.9 christos }, pos);
844 1.1 christos }
845 1.1 christos
846 1.1 christos /* Look for a block of saved registers in the traceframe, and get the
847 1.1 christos requested register from it. */
848 1.1 christos
849 1.6 christos void
850 1.6 christos tfile_target::fetch_registers (struct regcache *regcache, int regno)
851 1.1 christos {
852 1.6 christos struct gdbarch *gdbarch = regcache->arch ();
853 1.4 christos int offset, regn, regsize, dummy;
854 1.1 christos
855 1.1 christos /* An uninitialized reg size says we're not going to be
856 1.1 christos successful at getting register blocks. */
857 1.1 christos if (!trace_regblock_size)
858 1.1 christos return;
859 1.1 christos
860 1.1 christos if (traceframe_find_block_type ('R', 0) >= 0)
861 1.1 christos {
862 1.4 christos gdb_byte *regs = (gdb_byte *) alloca (trace_regblock_size);
863 1.1 christos
864 1.1 christos tfile_read (regs, trace_regblock_size);
865 1.1 christos
866 1.1 christos for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
867 1.1 christos {
868 1.6 christos if (!remote_register_number_and_offset (regcache->arch (),
869 1.4 christos regn, &dummy, &offset))
870 1.4 christos continue;
871 1.4 christos
872 1.1 christos regsize = register_size (gdbarch, regn);
873 1.1 christos /* Make sure we stay within block bounds. */
874 1.4 christos if (offset + regsize > trace_regblock_size)
875 1.1 christos break;
876 1.6 christos if (regcache->get_register_status (regn) == REG_UNKNOWN)
877 1.1 christos {
878 1.1 christos if (regno == regn)
879 1.1 christos {
880 1.6 christos regcache->raw_supply (regno, regs + offset);
881 1.1 christos break;
882 1.1 christos }
883 1.1 christos else if (regno == -1)
884 1.1 christos {
885 1.6 christos regcache->raw_supply (regn, regs + offset);
886 1.1 christos }
887 1.1 christos }
888 1.1 christos }
889 1.1 christos }
890 1.1 christos else
891 1.1 christos tracefile_fetch_registers (regcache, regno);
892 1.1 christos }
893 1.1 christos
894 1.1 christos static enum target_xfer_status
895 1.6 christos tfile_xfer_partial_features (const char *annex,
896 1.4 christos gdb_byte *readbuf, const gdb_byte *writebuf,
897 1.4 christos ULONGEST offset, ULONGEST len,
898 1.4 christos ULONGEST *xfered_len)
899 1.4 christos {
900 1.4 christos if (strcmp (annex, "target.xml"))
901 1.4 christos return TARGET_XFER_E_IO;
902 1.4 christos
903 1.4 christos if (readbuf == NULL)
904 1.4 christos error (_("tfile_xfer_partial: tdesc is read-only"));
905 1.4 christos
906 1.9 christos if (trace_tdesc.empty ())
907 1.4 christos return TARGET_XFER_E_IO;
908 1.4 christos
909 1.9 christos if (offset >= trace_tdesc.length ())
910 1.4 christos return TARGET_XFER_EOF;
911 1.4 christos
912 1.9 christos if (len > trace_tdesc.length () - offset)
913 1.9 christos len = trace_tdesc.length () - offset;
914 1.4 christos
915 1.9 christos memcpy (readbuf, trace_tdesc.c_str () + offset, len);
916 1.4 christos *xfered_len = len;
917 1.4 christos
918 1.4 christos return TARGET_XFER_OK;
919 1.4 christos }
920 1.4 christos
921 1.6 christos enum target_xfer_status
922 1.6 christos tfile_target::xfer_partial (enum target_object object,
923 1.6 christos const char *annex, gdb_byte *readbuf,
924 1.6 christos const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
925 1.6 christos ULONGEST *xfered_len)
926 1.1 christos {
927 1.4 christos /* We're only doing regular memory and tdesc for now. */
928 1.4 christos if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
929 1.6 christos return tfile_xfer_partial_features (annex, readbuf, writebuf,
930 1.4 christos offset, len, xfered_len);
931 1.1 christos if (object != TARGET_OBJECT_MEMORY)
932 1.1 christos return TARGET_XFER_E_IO;
933 1.1 christos
934 1.1 christos if (readbuf == NULL)
935 1.1 christos error (_("tfile_xfer_partial: trace file is read-only"));
936 1.1 christos
937 1.1 christos if (get_traceframe_number () != -1)
938 1.1 christos {
939 1.1 christos int pos = 0;
940 1.1 christos enum target_xfer_status res;
941 1.1 christos /* Records the lowest available address of all blocks that
942 1.1 christos intersects the requested range. */
943 1.1 christos ULONGEST low_addr_available = 0;
944 1.1 christos
945 1.1 christos /* Iterate through the traceframe's blocks, looking for
946 1.1 christos memory. */
947 1.1 christos while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
948 1.1 christos {
949 1.1 christos ULONGEST maddr, amt;
950 1.1 christos unsigned short mlen;
951 1.9 christos bfd_endian byte_order
952 1.9 christos = gdbarch_byte_order (current_inferior ()->arch ());
953 1.1 christos
954 1.1 christos tfile_read ((gdb_byte *) &maddr, 8);
955 1.1 christos maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
956 1.1 christos byte_order);
957 1.1 christos tfile_read ((gdb_byte *) &mlen, 2);
958 1.1 christos mlen = (unsigned short)
959 1.1 christos extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
960 1.1 christos
961 1.1 christos /* If the block includes the first part of the desired
962 1.1 christos range, return as much it has; GDB will re-request the
963 1.1 christos remainder, which might be in a different block of this
964 1.1 christos trace frame. */
965 1.1 christos if (maddr <= offset && offset < (maddr + mlen))
966 1.1 christos {
967 1.1 christos amt = (maddr + mlen) - offset;
968 1.1 christos if (amt > len)
969 1.1 christos amt = len;
970 1.1 christos
971 1.1 christos if (maddr != offset)
972 1.8 christos lseek (trace_fd, offset - maddr, SEEK_CUR);
973 1.1 christos tfile_read (readbuf, amt);
974 1.1 christos *xfered_len = amt;
975 1.1 christos return TARGET_XFER_OK;
976 1.1 christos }
977 1.1 christos
978 1.1 christos if (offset < maddr && maddr < (offset + len))
979 1.1 christos if (low_addr_available == 0 || low_addr_available > maddr)
980 1.1 christos low_addr_available = maddr;
981 1.1 christos
982 1.1 christos /* Skip over this block. */
983 1.1 christos pos += (8 + 2 + mlen);
984 1.1 christos }
985 1.1 christos
986 1.1 christos /* Requested memory is unavailable in the context of traceframes,
987 1.1 christos and this address falls within a read-only section, fallback
988 1.1 christos to reading from executable, up to LOW_ADDR_AVAILABLE. */
989 1.1 christos if (offset < low_addr_available)
990 1.5 christos len = std::min (len, low_addr_available - offset);
991 1.1 christos res = exec_read_partial_read_only (readbuf, offset, len, xfered_len);
992 1.1 christos
993 1.1 christos if (res == TARGET_XFER_OK)
994 1.1 christos return TARGET_XFER_OK;
995 1.1 christos else
996 1.1 christos {
997 1.1 christos /* No use trying further, we know some memory starting
998 1.1 christos at MEMADDR isn't available. */
999 1.1 christos *xfered_len = len;
1000 1.1 christos return TARGET_XFER_UNAVAILABLE;
1001 1.1 christos }
1002 1.1 christos }
1003 1.1 christos else
1004 1.1 christos {
1005 1.1 christos /* Fallback to reading from read-only sections. */
1006 1.1 christos return section_table_read_available_memory (readbuf, offset, len,
1007 1.1 christos xfered_len);
1008 1.1 christos }
1009 1.1 christos }
1010 1.1 christos
1011 1.1 christos /* Iterate through the blocks of a trace frame, looking for a 'V'
1012 1.1 christos block with a matching tsv number. */
1013 1.1 christos
1014 1.6 christos bool
1015 1.6 christos tfile_target::get_trace_state_variable_value (int tsvnum, LONGEST *val)
1016 1.1 christos {
1017 1.1 christos int pos;
1018 1.6 christos bool found = false;
1019 1.1 christos
1020 1.1 christos /* Iterate over blocks in current frame and find the last 'V'
1021 1.1 christos block in which tsv number is TSVNUM. In one trace frame, there
1022 1.1 christos may be multiple 'V' blocks created for a given trace variable,
1023 1.1 christos and the last matched 'V' block contains the updated value. */
1024 1.1 christos pos = 0;
1025 1.1 christos while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
1026 1.1 christos {
1027 1.1 christos int vnum;
1028 1.1 christos
1029 1.1 christos tfile_read ((gdb_byte *) &vnum, 4);
1030 1.1 christos vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
1031 1.1 christos gdbarch_byte_order
1032 1.9 christos (current_inferior ()->arch ()));
1033 1.1 christos if (tsvnum == vnum)
1034 1.1 christos {
1035 1.1 christos tfile_read ((gdb_byte *) val, 8);
1036 1.1 christos *val = extract_signed_integer ((gdb_byte *) val, 8,
1037 1.1 christos gdbarch_byte_order
1038 1.9 christos (current_inferior ()->arch ()));
1039 1.6 christos found = true;
1040 1.1 christos }
1041 1.1 christos pos += (4 + 8);
1042 1.1 christos }
1043 1.1 christos
1044 1.1 christos return found;
1045 1.1 christos }
1046 1.1 christos
1047 1.1 christos /* Callback for traceframe_walk_blocks. Builds a traceframe_info
1048 1.1 christos object for the tfile target's current traceframe. */
1049 1.1 christos
1050 1.9 christos static bool
1051 1.9 christos build_traceframe_info (char blocktype, struct traceframe_info *info)
1052 1.1 christos {
1053 1.1 christos switch (blocktype)
1054 1.1 christos {
1055 1.1 christos case 'M':
1056 1.1 christos {
1057 1.1 christos ULONGEST maddr;
1058 1.1 christos unsigned short mlen;
1059 1.1 christos
1060 1.1 christos tfile_read ((gdb_byte *) &maddr, 8);
1061 1.1 christos maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
1062 1.1 christos gdbarch_byte_order
1063 1.9 christos (current_inferior ()->arch ()));
1064 1.1 christos tfile_read ((gdb_byte *) &mlen, 2);
1065 1.1 christos mlen = (unsigned short)
1066 1.1 christos extract_unsigned_integer ((gdb_byte *) &mlen,
1067 1.9 christos 2,
1068 1.9 christos gdbarch_byte_order
1069 1.9 christos (current_inferior ()->arch ()));
1070 1.1 christos
1071 1.6 christos info->memory.emplace_back (maddr, mlen);
1072 1.1 christos break;
1073 1.1 christos }
1074 1.1 christos case 'V':
1075 1.1 christos {
1076 1.1 christos int vnum;
1077 1.1 christos
1078 1.1 christos tfile_read ((gdb_byte *) &vnum, 4);
1079 1.6 christos info->tvars.push_back (vnum);
1080 1.1 christos }
1081 1.1 christos case 'R':
1082 1.1 christos case 'S':
1083 1.1 christos {
1084 1.1 christos break;
1085 1.1 christos }
1086 1.1 christos default:
1087 1.1 christos warning (_("Unhandled trace block type (%d) '%c ' "
1088 1.1 christos "while building trace frame info."),
1089 1.1 christos blocktype, blocktype);
1090 1.1 christos break;
1091 1.1 christos }
1092 1.1 christos
1093 1.9 christos return false;
1094 1.1 christos }
1095 1.1 christos
1096 1.6 christos traceframe_info_up
1097 1.6 christos tfile_target::traceframe_info ()
1098 1.1 christos {
1099 1.6 christos traceframe_info_up info (new struct traceframe_info);
1100 1.6 christos
1101 1.9 christos traceframe_walk_blocks ([&] (char blocktype)
1102 1.9 christos {
1103 1.9 christos return build_traceframe_info (blocktype, info.get ());
1104 1.9 christos }, 0);
1105 1.1 christos
1106 1.1 christos return info;
1107 1.1 christos }
1108 1.1 christos
1109 1.4 christos /* Handles tdesc lines from tfile by appending the payload to
1110 1.4 christos a global trace_tdesc variable. */
1111 1.4 christos
1112 1.4 christos static void
1113 1.4 christos tfile_append_tdesc_line (const char *line)
1114 1.4 christos {
1115 1.9 christos trace_tdesc += line;
1116 1.9 christos trace_tdesc += "\n";
1117 1.4 christos }
1118 1.4 christos
1119 1.7 christos void _initialize_tracefile_tfile ();
1120 1.1 christos void
1121 1.7 christos _initialize_tracefile_tfile ()
1122 1.1 christos {
1123 1.10 christos add_target (tfile_target_info, tfile_target_open,
1124 1.10 christos filename_maybe_quoted_completer);
1125 1.1 christos }
1126