-/* Close the trace file and generally clean up. */
-
-static void
-tfile_close (int quitting)
-{
- int pid;
-
- if (trace_fd < 0)
- return;
-
- pid = ptid_get_pid (inferior_ptid);
- inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */
- exit_inferior_silent (pid);
-
- close (trace_fd);
- trace_fd = -1;
- xfree (trace_filename);
- trace_filename = NULL;
-}
-
-static void
-tfile_files_info (struct target_ops *t)
-{
- /* (it would be useful to mention the name of the file). */
- printf_filtered ("Looking at a trace file.\n");
-}
-
-/* The trace status for a file is that tracing can never be run. */
-
-static int
-tfile_get_trace_status (struct trace_status *ts)
-{
- /* Other bits of trace status were collected as part of opening the
- trace files, so nothing to do here. */
-
- return -1;
-}
-
-static void
-tfile_get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp)
-{
- /* Other bits of trace status were collected as part of opening the
- trace files, so nothing to do here. */
-}
-
-/* Given the position of a traceframe in the file, figure out what
- address the frame was collected at. This would normally be the
- value of a collected PC register, but if not available, we
- improvise. */
-
-static ULONGEST
-tfile_get_traceframe_address (off_t tframe_offset)
-{
- ULONGEST addr = 0;
- short tpnum;
- struct tracepoint *tp;
- off_t saved_offset = cur_offset;
-
- /* FIXME dig pc out of collected registers. */
-
- /* Fall back to using tracepoint address. */
- lseek (trace_fd, tframe_offset, SEEK_SET);
- tfile_read ((gdb_byte *) &tpnum, 2);
- tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
- gdbarch_byte_order
- (target_gdbarch));
-
- tp = get_tracepoint_by_number_on_target (tpnum);
- /* FIXME this is a poor heuristic if multiple locations. */
- if (tp && tp->base.loc)
- addr = tp->base.loc->address;
-
- /* Restore our seek position. */
- cur_offset = saved_offset;
- lseek (trace_fd, cur_offset, SEEK_SET);
- return addr;
-}
-
-/* Given a type of search and some parameters, scan the collection of
- traceframes in the file looking for a match. When found, return
- both the traceframe and tracepoint number, otherwise -1 for
- each. */
-
-static int
-tfile_trace_find (enum trace_find_type type, int num,
- ULONGEST addr1, ULONGEST addr2, int *tpp)
-{
- short tpnum;
- int tfnum = 0, found = 0;
- unsigned int data_size;
- struct tracepoint *tp;
- off_t offset, tframe_offset;
- ULONGEST tfaddr;
-
- if (num == -1)
- {
- if (tpp)
- *tpp = -1;
- return -1;
- }
-
- lseek (trace_fd, trace_frames_offset, SEEK_SET);
- offset = trace_frames_offset;
- while (1)
- {
- tframe_offset = offset;
- tfile_read ((gdb_byte *) &tpnum, 2);
- tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
- gdbarch_byte_order
- (target_gdbarch));
- offset += 2;
- if (tpnum == 0)
- break;
- tfile_read ((gdb_byte *) &data_size, 4);
- data_size = (unsigned int) extract_unsigned_integer
- ((gdb_byte *) &data_size, 4,
- gdbarch_byte_order (target_gdbarch));
- offset += 4;
- switch (type)
- {
- case tfind_number:
- if (tfnum == num)
- found = 1;
- break;
- case tfind_pc:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (tfaddr == addr1)
- found = 1;
- break;
- case tfind_tp:
- tp = get_tracepoint (num);
- if (tp && tpnum == tp->number_on_target)
- found = 1;
- break;
- case tfind_range:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (addr1 <= tfaddr && tfaddr <= addr2)
- found = 1;
- break;
- case tfind_outside:
- tfaddr = tfile_get_traceframe_address (tframe_offset);
- if (!(addr1 <= tfaddr && tfaddr <= addr2))
- found = 1;
- break;
- default:
- internal_error (__FILE__, __LINE__, _("unknown tfind type"));
- }
- if (found)
- {
- if (tpp)
- *tpp = tpnum;
- cur_offset = offset;
- cur_data_size = data_size;
-
- return tfnum;
- }
- /* Skip past the traceframe's data. */
- lseek (trace_fd, data_size, SEEK_CUR);
- offset += data_size;
- /* Update our own count of traceframes. */
- ++tfnum;
- }
- /* Did not find what we were looking for. */
- if (tpp)
- *tpp = -1;
- return -1;
-}
-
-/* Prototype of the callback passed to tframe_walk_blocks. */
-typedef int (*walk_blocks_callback_func) (char blocktype, void *data);
-
-/* Callback for traceframe_walk_blocks, used to find a given block
- type in a traceframe. */
-
-static int
-match_blocktype (char blocktype, void *data)
-{
- char *wantedp = data;
-
- if (*wantedp == blocktype)
- return 1;
-
- return 0;
-}
-
-/* Walk over all traceframe block starting at POS offset from
- CUR_OFFSET, and call CALLBACK for each block found, passing in DATA
- unmodified. If CALLBACK returns true, this returns the position in
- the traceframe where the block is found, relative to the start of
- the traceframe (cur_offset). Returns -1 if no callback call
- returned true, indicating that all blocks have been walked. */
-
-static int
-traceframe_walk_blocks (walk_blocks_callback_func callback,
- int pos, void *data)
-{
- /* Iterate through a traceframe's blocks, looking for a block of the
- requested type. */
-
- lseek (trace_fd, cur_offset + pos, SEEK_SET);
- while (pos < cur_data_size)
- {
- unsigned short mlen;
- char block_type;
-
- tfile_read (&block_type, 1);
-
- ++pos;
-
- if ((*callback) (block_type, data))
- return pos;
-
- switch (block_type)
- {
- case 'R':
- lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
- pos += trace_regblock_size;
- break;
- case 'M':
- lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
- tfile_read ((gdb_byte *) &mlen, 2);
- mlen = (unsigned short)
- extract_unsigned_integer ((gdb_byte *) &mlen, 2,
- gdbarch_byte_order
- (target_gdbarch));
- lseek (trace_fd, mlen, SEEK_CUR);
- pos += (8 + 2 + mlen);
- break;
- case 'V':
- lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
- pos += (4 + 8);
- break;
- default:
- error (_("Unknown block type '%c' (0x%x) in trace frame"),
- block_type, block_type);
- break;
- }
- }
-
- return -1;
-}
-
-/* Convenience wrapper around traceframe_walk_blocks. Looks for the
- position offset of a block of type TYPE_WANTED in the current trace
- frame, starting at POS. Returns -1 if no such block was found. */
-
-static int
-traceframe_find_block_type (char type_wanted, int pos)
-{
- return traceframe_walk_blocks (match_blocktype, pos, &type_wanted);
-}
-
-/* Look for a block of saved registers in the traceframe, and get the
- requested register from it. */
-
-static void
-tfile_fetch_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
-{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- int offset, regn, regsize, pc_regno;
- char *regs;
-
- /* An uninitialized reg size says we're not going to be
- successful at getting register blocks. */
- if (!trace_regblock_size)
- return;
-
- regs = alloca (trace_regblock_size);
-
- if (traceframe_find_block_type ('R', 0) >= 0)
- {
- tfile_read (regs, trace_regblock_size);
-
- /* Assume the block is laid out in GDB register number order,
- each register with the size that it has in GDB. */
- offset = 0;
- for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
- {
- regsize = register_size (gdbarch, regn);
- /* Make sure we stay within block bounds. */
- if (offset + regsize >= trace_regblock_size)
- break;
- if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
- {
- if (regno == regn)
- {
- regcache_raw_supply (regcache, regno, regs + offset);
- break;
- }
- else if (regno == -1)
- {
- regcache_raw_supply (regcache, regn, regs + offset);
- }
- }
- offset += regsize;
- }
- return;
- }
-
- /* We get here if no register data has been found. Mark registers
- as unavailable. */
- for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
- regcache_raw_supply (regcache, regn, NULL);
-
- /* We can often usefully guess that the PC is going to be the same
- as the address of the tracepoint. */
- pc_regno = gdbarch_pc_regnum (gdbarch);
- if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
- {
- struct tracepoint *tp = get_tracepoint (tracepoint_number);
-
- if (tp && tp->base.loc)
- {
- /* But don't try to guess if tracepoint is multi-location... */
- if (tp->base.loc->next)
- {
- warning (_("Tracepoint %d has multiple "
- "locations, cannot infer $pc"),
- tp->base.number);
- return;
- }
- /* ... or does while-stepping. */
- if (tp->step_count > 0)
- {
- warning (_("Tracepoint %d does while-stepping, "
- "cannot infer $pc"),
- tp->base.number);
- return;
- }
-
- store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
- gdbarch_byte_order (gdbarch),
- tp->base.loc->address);
- regcache_raw_supply (regcache, pc_regno, regs);
- }
- }
-}
-
-static LONGEST
-tfile_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
-{
- /* We're only doing regular memory for now. */
- if (object != TARGET_OBJECT_MEMORY)
- return -1;
-
- if (readbuf == NULL)
- error (_("tfile_xfer_partial: trace file is read-only"));
-
- if (traceframe_number != -1)
- {
- int pos = 0;
-
- /* Iterate through the traceframe's blocks, looking for
- memory. */
- while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
- {
- ULONGEST maddr, amt;
- unsigned short mlen;
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
-
- tfile_read ((gdb_byte *) &maddr, 8);
- maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
- byte_order);
- tfile_read ((gdb_byte *) &mlen, 2);
- mlen = (unsigned short)
- extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
-
- /* If the block includes the first part of the desired
- range, return as much it has; GDB will re-request the
- remainder, which might be in a different block of this
- trace frame. */
- if (maddr <= offset && offset < (maddr + mlen))
- {
- amt = (maddr + mlen) - offset;
- if (amt > len)
- amt = len;
-
- if (maddr != offset)
- lseek (trace_fd, offset - maddr, SEEK_CUR);
- tfile_read (readbuf, amt);
- return amt;
- }
-
- /* Skip over this block. */
- pos += (8 + 2 + mlen);
- }
- }
-
- /* It's unduly pedantic to refuse to look at the executable for
- read-only pieces; so do the equivalent of readonly regions aka
- QTro packet. */
- /* FIXME account for relocation at some point. */
- if (exec_bfd)
- {
- asection *s;
- bfd_size_type size;
- bfd_vma vma;
-
- for (s = exec_bfd->sections; s; s = s->next)
- {
- if ((s->flags & SEC_LOAD) == 0
- || (s->flags & SEC_READONLY) == 0)
- continue;
-
- vma = s->vma;
- size = bfd_get_section_size (s);
- if (vma <= offset && offset < (vma + size))
- {
- ULONGEST amt;
-
- amt = (vma + size) - offset;
- if (amt > len)
- amt = len;
-
- amt = bfd_get_section_contents (exec_bfd, s,
- readbuf, offset - vma, amt);
- return amt;
- }
- }
- }
-
- /* Indicate failure to find the requested memory block. */
- return -1;
-}
-
-/* Iterate through the blocks of a trace frame, looking for a 'V'
- block with a matching tsv number. */
-
-static int
-tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
-{
- int pos;
-
- pos = 0;
- while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
- {
- int vnum;
-
- tfile_read ((gdb_byte *) &vnum, 4);
- vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
- gdbarch_byte_order
- (target_gdbarch));
- if (tsvnum == vnum)
- {
- tfile_read ((gdb_byte *) val, 8);
- *val = extract_signed_integer ((gdb_byte *) val, 8,
- gdbarch_byte_order
- (target_gdbarch));
- return 1;
- }
- pos += (4 + 8);
- }
-
- /* Didn't find anything. */
- return 0;
-}
-
-static int
-tfile_has_all_memory (struct target_ops *ops)
-{
- return 1;
-}
-
-static int
-tfile_has_memory (struct target_ops *ops)
-{
- return 1;
-}
-
-static int
-tfile_has_stack (struct target_ops *ops)
-{
- return traceframe_number != -1;
-}
-
-static int
-tfile_has_registers (struct target_ops *ops)
-{
- return traceframe_number != -1;
-}
-
-static int
-tfile_thread_alive (struct target_ops *ops, ptid_t ptid)
-{
- return 1;
-}
-
-/* Callback for traceframe_walk_blocks. Builds a traceframe_info
- object for the tfile target's current traceframe. */
-
-static int
-build_traceframe_info (char blocktype, void *data)
-{
- struct traceframe_info *info = data;
-
- switch (blocktype)
- {
- case 'M':
- {
- struct mem_range *r;
- ULONGEST maddr;
- unsigned short mlen;
-
- tfile_read ((gdb_byte *) &maddr, 8);
- tfile_read ((gdb_byte *) &mlen, 2);
-
- r = VEC_safe_push (mem_range_s, info->memory, NULL);
-
- r->start = maddr;
- r->length = mlen;
- break;
- }
- case 'V':
- case 'R':
- case 'S':
- {
- break;
- }
- default:
- warning (_("Unhandled trace block type (%d) '%c ' "
- "while building trace frame info."),
- blocktype, blocktype);
- break;
- }
-
- return 0;
-}
-
-static struct traceframe_info *
-tfile_traceframe_info (void)
-{
- struct traceframe_info *info = XCNEW (struct traceframe_info);
-
- traceframe_walk_blocks (build_traceframe_info, 0, info);
- return info;
-}
-
-static void
-init_tfile_ops (void)
-{
- tfile_ops.to_shortname = "tfile";
- tfile_ops.to_longname = "Local trace dump file";
- tfile_ops.to_doc
- = "Use a trace file as a target. Specify the filename of the trace file.";
- tfile_ops.to_open = tfile_open;
- tfile_ops.to_close = tfile_close;
- tfile_ops.to_fetch_registers = tfile_fetch_registers;
- tfile_ops.to_xfer_partial = tfile_xfer_partial;
- tfile_ops.to_files_info = tfile_files_info;
- tfile_ops.to_get_trace_status = tfile_get_trace_status;
- tfile_ops.to_get_tracepoint_status = tfile_get_tracepoint_status;
- tfile_ops.to_trace_find = tfile_trace_find;
- tfile_ops.to_get_trace_state_variable_value
- = tfile_get_trace_state_variable_value;
- tfile_ops.to_stratum = process_stratum;
- tfile_ops.to_has_all_memory = tfile_has_all_memory;
- tfile_ops.to_has_memory = tfile_has_memory;
- tfile_ops.to_has_stack = tfile_has_stack;
- tfile_ops.to_has_registers = tfile_has_registers;
- tfile_ops.to_traceframe_info = tfile_traceframe_info;
- tfile_ops.to_thread_alive = tfile_thread_alive;
- tfile_ops.to_magic = OPS_MAGIC;
-}
-