gdb.trace: Save XML target description in tfile.
[deliverable/binutils-gdb.git] / gdb / tracefile-tfile.c
1 /* Trace file TFILE format support in GDB.
2
3 Copyright (C) 1997-2016 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 "readline/tilde.h"
23 #include "filestuff.h"
24 #include "rsp-low.h" /* bin2hex */
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"
31 #include "remote.h"
32 #include "xml-tdesc.h"
33
34 #ifndef O_LARGEFILE
35 #define O_LARGEFILE 0
36 #endif
37
38 /* TFILE trace writer. */
39
40 struct 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
54 static int
55 tfile_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
66 static void
67 tfile_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
82 static void
83 tfile_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
98 static void
99 tfile_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
116 static void
117 tfile_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
128 static void
129 tfile_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
188 static void
189 tfile_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
215 static void
216 tfile_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
267 /* This is the implementation of trace_file_write_ops method
268 write_tdesc. */
269
270 static void
271 tfile_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
303 /* This is the implementation of trace_file_write_ops method
304 write_definition_end. */
305
306 static void
307 tfile_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
318 static void
319 tfile_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
332 static void
333 tfile_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
346 static 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,
356 tfile_write_tdesc,
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
365 struct trace_file_writer *
366 tfile_trace_file_writer_new (void)
367 {
368 struct tfile_trace_file_writer *writer
369 = XNEW (struct tfile_trace_file_writer);
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 }
377
378 /* target tfile command */
379
380 static 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
388 static char *trace_filename;
389 static int trace_fd = -1;
390 static off_t trace_frames_offset;
391 static off_t cur_offset;
392 static int cur_data_size;
393 int trace_regblock_size;
394
395 static 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
405 static void
406 tfile_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
417 static void
418 tfile_open (const char *arg, int from_tty)
419 {
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;
431 char *filename;
432
433 target_preopen (from_tty);
434 if (!arg)
435 error (_("No trace file specified."));
436
437 filename = tilde_expand (arg);
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
467 && (startswith (header + 1, "TRACE0\n"))))
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
484 TRY
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 }
517 CATCH (ex, RETURN_MASK_ALL)
518 {
519 /* Remove the partially set up target. */
520 unpush_target (&tfile_ops);
521 throw_exception (ex);
522 }
523 END_CATCH
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
546 static void
547 tfile_interp_line (char *line, struct uploaded_tp **utpp,
548 struct uploaded_tsv **utsvp)
549 {
550 char *p = line;
551
552 if (startswith (p, "R "))
553 {
554 p += strlen ("R ");
555 trace_regblock_size = strtol (p, &p, 16);
556 }
557 else if (startswith (p, "status "))
558 {
559 p += strlen ("status ");
560 parse_trace_status (p, current_trace_status ());
561 }
562 else if (startswith (p, "tp "))
563 {
564 p += strlen ("tp ");
565 parse_tracepoint_definition (p, utpp);
566 }
567 else if (startswith (p, "tsv "))
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
578 static void
579 tfile_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
598 static void
599 tfile_files_info (struct target_ops *t)
600 {
601 printf_filtered ("\t`%s'\n", trace_filename);
602 }
603
604 static void
605 tfile_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
617 static CORE_ADDR
618 tfile_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
650 static int
651 tfile_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. */
747 typedef 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
752 static int
753 match_blocktype (char blocktype, void *data)
754 {
755 char *wantedp = (char *) data;
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
770 static int
771 traceframe_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
824 static int
825 traceframe_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
833 static void
834 tfile_fetch_registers (struct target_ops *ops,
835 struct regcache *regcache, int regno)
836 {
837 struct gdbarch *gdbarch = get_regcache_arch (regcache);
838 int offset, regn, regsize, dummy;
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
845 if (traceframe_find_block_type ('R', 0) >= 0)
846 {
847 gdb_byte *regs = (gdb_byte *) alloca (trace_regblock_size);
848
849 tfile_read (regs, trace_regblock_size);
850
851 for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
852 {
853 if (!remote_register_number_and_offset (get_regcache_arch (regcache),
854 regn, &dummy, &offset))
855 continue;
856
857 regsize = register_size (gdbarch, regn);
858 /* Make sure we stay within block bounds. */
859 if (offset + regsize > trace_regblock_size)
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 }
873 }
874 }
875 else
876 tracefile_fetch_registers (regcache, regno);
877 }
878
879 static enum target_xfer_status
880 tfile_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;
895 enum target_xfer_status res;
896 /* Records the lowest available address of all blocks that
897 intersects the requested range. */
898 ULONGEST low_addr_available = 0;
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
932 if (offset < maddr && maddr < (offset + len))
933 if (low_addr_available == 0 || low_addr_available > maddr)
934 low_addr_available = maddr;
935
936 /* Skip over this block. */
937 pos += (8 + 2 + mlen);
938 }
939
940 /* Requested memory is unavailable in the context of traceframes,
941 and this address falls within a read-only section, fallback
942 to reading from executable, up to LOW_ADDR_AVAILABLE. */
943 if (offset < low_addr_available)
944 len = min (len, low_addr_available - offset);
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 }
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 }
963 }
964
965 /* Iterate through the blocks of a trace frame, looking for a 'V'
966 block with a matching tsv number. */
967
968 static int
969 tfile_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
1002 /* Callback for traceframe_walk_blocks. Builds a traceframe_info
1003 object for the tfile target's current traceframe. */
1004
1005 static int
1006 build_traceframe_info (char blocktype, void *data)
1007 {
1008 struct traceframe_info *info = (struct traceframe_info *) data;
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
1056 static struct traceframe_info *
1057 tfile_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
1065 static void
1066 init_tfile_ops (void)
1067 {
1068 init_tracefile_ops (&tfile_ops);
1069
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;
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;
1083 tfile_ops.to_traceframe_info = tfile_traceframe_info;
1084 }
1085
1086 extern initialize_file_ftype _initialize_tracefile_tfile;
1087
1088 void
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.051853 seconds and 5 git commands to generate.