- char *recfilename, recfilename_buffer[40];
- int recfd;
- struct record_entry *cur_record_list;
- uint32_t magic;
- struct regcache *regcache;
- struct gdbarch *gdbarch;
- struct cleanup *old_cleanups;
- struct cleanup *set_cleanups;
- bfd *obfd;
- int save_size = 0;
- asection *osec = NULL;
- int bfd_offset = 0;
-
- if (strcmp (current_target.to_shortname, "record") != 0)
- error (_("This command can only be used with target 'record'.\n"
- "Use 'target record' first.\n"));
-
- if (args && *args)
- recfilename = args;
- else
- {
- /* Default recfile name is "gdb_record.PID". */
- snprintf (recfilename_buffer, sizeof (recfilename_buffer),
- "gdb_record.%d", PIDGET (inferior_ptid));
- recfilename = recfilename_buffer;
- }
-
- /* Open the save file. */
- if (record_debug)
- printf_filtered ("Saving execution log to core file '%s'\n", recfilename);
-
- /* Open the output file. */
- obfd = create_gcore_bfd (recfilename);
- old_cleanups = make_cleanup (record_save_cleanups, obfd);
-
- /* Save the current record entry to "cur_record_list". */
- cur_record_list = record_list;
-
- /* Get the values of regcache and gdbarch. */
- regcache = get_current_regcache ();
- gdbarch = get_regcache_arch (regcache);
-
- /* Disable the GDB operation record. */
- set_cleanups = record_gdb_operation_disable_set ();
-
- /* Reverse execute to the begin of record list. */
- while (1)
- {
- /* Check for beginning and end of log. */
- if (record_list == &record_first)
- break;
-
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->prev)
- record_list = record_list->prev;
- }
-
- /* Compute the size needed for the extra bfd section. */
- save_size = 4; /* magic cookie */
- for (record_list = record_first.next; record_list;
- record_list = record_list->next)
- switch (record_list->type)
- {
- case record_end:
- save_size += 1 + 4 + 4;
- break;
- case record_reg:
- save_size += 1 + 4 + record_list->u.reg.len;
- break;
- case record_mem:
- save_size += 1 + 4 + 8 + record_list->u.mem.len;
- break;
- }
-
- /* Make the new bfd section. */
- osec = bfd_make_section_anyway_with_flags (obfd, "precord",
- SEC_HAS_CONTENTS
- | SEC_READONLY);
- if (osec == NULL)
- error (_("Failed to create 'precord' section for corefile %s: %s"),
- recfilename,
- bfd_errmsg (bfd_get_error ()));
- bfd_set_section_size (obfd, osec, save_size);
- bfd_set_section_vma (obfd, osec, 0);
- bfd_set_section_alignment (obfd, osec, 0);
- bfd_section_lma (obfd, osec) = 0;
-
- /* Save corefile state. */
- write_gcore_file (obfd);
-
- /* Write out the record log. */
- /* Write the magic code. */
- magic = RECORD_FILE_MAGIC;
- if (record_debug)
- printf_filtered ("\
- Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n",
- magic);
- bfdcore_write (obfd, osec, &magic, sizeof (magic), &bfd_offset);
-
- /* Save the entries to recfd and forward execute to the end of
- record list. */
- record_list = &record_first;
- while (1)
- {
- /* Save entry. */
- if (record_list != &record_first)
- {
- uint8_t type;
- uint32_t regnum, len, signal, count;
- uint64_t addr;
-
- type = record_list->type;
- bfdcore_write (obfd, osec, &type, sizeof (type), &bfd_offset);
-
- switch (record_list->type)
- {
- case record_reg: /* reg */
- if (record_debug)
- printf_filtered ("\
- Writing register %d (1 plus %d plus %d bytes)\n",
- record_list->u.reg.num,
- sizeof (regnum),
- record_list->u.reg.len);
-
- /* Write regnum. */
- regnum = netorder32 (record_list->u.reg.num);
- bfdcore_write (obfd, osec, ®num,
- sizeof (regnum), &bfd_offset);
-
- /* Write regval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.reg.len, &bfd_offset);
- break;
-
- case record_mem: /* mem */
- if (record_debug)
- printf_filtered ("\
- Writing memory %s (1 plus %d plus %d plus %d bytes)\n",
- paddress (gdbarch,
- record_list->u.mem.addr),
- sizeof (addr),
- sizeof (len),
- record_list->u.mem.len);
-
- /* Write memlen. */
- len = netorder32 (record_list->u.mem.len);
- bfdcore_write (obfd, osec, &len, sizeof (len), &bfd_offset);
-
- /* Write memaddr. */
- addr = netorder64 (record_list->u.mem.addr);
- bfdcore_write (obfd, osec, &addr,
- sizeof (addr), &bfd_offset);
-
- /* Write memval. */
- bfdcore_write (obfd, osec, record_get_loc (record_list),
- record_list->u.mem.len, &bfd_offset);
- break;
-
- case record_end:
- if (record_debug)
- printf_filtered ("\
- Writing record_end (1 + %d + %d bytes)\n",
- sizeof (signal),
- sizeof (count));
- /* Write signal value. */
- signal = netorder32 (record_list->u.end.sigval);
- bfdcore_write (obfd, osec, &signal,
- sizeof (signal), &bfd_offset);
-
- /* Write insn count. */
- count = netorder32 (record_list->u.end.insn_num);
- bfdcore_write (obfd, osec, &count,
- sizeof (count), &bfd_offset);
- break;
- }
- }
-
- /* Execute entry. */
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->next)
- record_list = record_list->next;
- else
- break;
- }
-
- /* Reverse execute to cur_record_list. */
- while (1)
- {
- /* Check for beginning and end of log. */
- if (record_list == cur_record_list)
- break;
-
- record_exec_insn (regcache, gdbarch, record_list);
-
- if (record_list->prev)
- record_list = record_list->prev;
- }
-
- do_cleanups (set_cleanups);
- bfd_close (obfd);
- discard_cleanups (old_cleanups);
-
- /* Succeeded. */
- printf_filtered (_("Saved core file %s with execution log.\n"),
- recfilename);