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