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