/* Core dump and executable file functions below target vector, for GDB.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "arch-utils.h"
#include <signal.h>
#include <fcntl.h>
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h> /* needed for F_OK and friends */
-#endif
#include "frame.h" /* required by inferior.h */
#include "inferior.h"
#include "infrun.h"
#include "command.h"
#include "bfd.h"
#include "target.h"
+#include "process-stratum-target.h"
#include "gdbcore.h"
#include "gdbthread.h"
#include "regcache.h"
#include "regset.h"
#include "symfile.h"
#include "exec.h"
-#include "readline/readline.h"
+#include "readline/tilde.h"
#include "solib.h"
#include "filenames.h"
#include "progspace.h"
#include "objfiles.h"
#include "gdb_bfd.h"
#include "completer.h"
-#include "filestuff.h"
+#include "gdbsupport/filestuff.h"
+#include "build-id.h"
+#include "gdbsupport/pathstuff.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
-static core_fns *sniff_core_bfd (gdbarch *core_gdbarch,
- bfd *abfd);
-
/* The core file target. */
static const target_info core_target_info = {
"core",
N_("Local core dump file"),
- N_("Use a core file as a target. Specify the filename of the core file.")
+ N_("Use a core file as a target.\n\
+Specify the filename of the core file.")
};
-class core_target final : public target_ops
+class core_target final : public process_stratum_target
{
public:
core_target ();
bool thread_alive (ptid_t ptid) override;
const struct target_desc *read_description () override;
- const char *pid_to_str (ptid_t) override;
+ std::string pid_to_str (ptid_t) override;
const char *thread_name (struct thread_info *) override;
+ bool has_all_memory () override { return false; }
bool has_memory () override;
bool has_stack () override;
bool has_registers () override;
+ bool has_execution (inferior *inf) override { return false; }
+
bool info_proc (const char *, enum info_proc_what) override;
/* A few helpers. */
void get_core_register_section (struct regcache *regcache,
const struct regset *regset,
const char *name,
- int min_size,
- int which,
+ int section_min_size,
const char *human_name,
bool required);
targets. */
target_section_table m_core_section_table {};
- /* The core_fns for a core file handler that is prepared to read the
- core file currently open on core_bfd. */
- core_fns *m_core_vec = NULL;
-
/* FIXME: kettenis/20031023: Eventually this field should
disappear. */
struct gdbarch *m_core_gdbarch = NULL;
core_target::core_target ()
{
- to_stratum = process_stratum;
-
m_core_gdbarch = gdbarch_from_bfd (core_bfd);
- /* Find a suitable core file handler to munch on core_bfd */
- m_core_vec = sniff_core_bfd (m_core_gdbarch, core_bfd);
+ if (!m_core_gdbarch
+ || !gdbarch_iterate_over_regset_sections_p (m_core_gdbarch))
+ error (_("\"%s\": Core file format not supported"),
+ bfd_get_filename (core_bfd));
/* Find the data section */
if (build_section_table (core_bfd,
xfree (m_core_section_table.sections);
}
-/* List of all available core_fns. On gdb startup, each core file
- register reader calls deprecated_add_core_fns() to register
- information on each core format it is prepared to read. */
-
-static struct core_fns *core_file_fns = NULL;
-
-static int gdb_check_format (bfd *);
-
static void add_to_thread_list (bfd *, asection *, void *);
/* An arbitrary identifier for the core inferior. */
#define CORELOW_PID 1
-/* Link a new core_fns into the global core_file_fns list. Called on
- gdb startup by the _initialize routine in each core file register
- reader, to register information about each format the reader is
- prepared to handle. */
-
-void
-deprecated_add_core_fns (struct core_fns *cf)
-{
- cf->next = core_file_fns;
- core_file_fns = cf;
-}
-
-/* The default function that core file handlers can use to examine a
- core file BFD and decide whether or not to accept the job of
- reading the core file. */
-
-int
-default_core_sniffer (struct core_fns *our_fns, bfd *abfd)
-{
- int result;
-
- result = (bfd_get_flavour (abfd) == our_fns -> core_flavour);
- return (result);
-}
-
-/* Walk through the list of core functions to find a set that can
- handle the core file open on ABFD. Returns pointer to set that is
- selected. */
-
-static struct core_fns *
-sniff_core_bfd (struct gdbarch *core_gdbarch, bfd *abfd)
-{
- struct core_fns *cf;
- struct core_fns *yummy = NULL;
- int matches = 0;
-
- /* Don't sniff if we have support for register sets in
- CORE_GDBARCH. */
- if (core_gdbarch && gdbarch_iterate_over_regset_sections_p (core_gdbarch))
- return NULL;
-
- for (cf = core_file_fns; cf != NULL; cf = cf->next)
- {
- if (cf->core_sniffer (cf, abfd))
- {
- yummy = cf;
- matches++;
- }
- }
- if (matches > 1)
- {
- warning (_("\"%s\": ambiguous core format, %d handlers match"),
- bfd_get_filename (abfd), matches);
- }
- else if (matches == 0)
- error (_("\"%s\": no core file handler recognizes format"),
- bfd_get_filename (abfd));
-
- return (yummy);
-}
-
-/* The default is to reject every core file format we see. Either
- BFD has to recognize it, or we have to provide a function in the
- core file handler that recognizes it. */
-
-int
-default_check_format (bfd *abfd)
-{
- return (0);
-}
-
-/* Attempt to recognize core file formats that BFD rejects. */
-
-static int
-gdb_check_format (bfd *abfd)
-{
- struct core_fns *cf;
-
- for (cf = core_file_fns; cf != NULL; cf = cf->next)
- {
- if (cf->check_format (abfd))
- {
- return (1);
- }
- }
- return (0);
-}
-
/* Close the core target. */
void
{
if (core_bfd)
{
- int pid = ptid_get_pid (inferior_ptid);
inferior_ptid = null_ptid; /* Avoid confusion from thread
stuff. */
- if (pid != 0)
- exit_inferior_silent (pid);
+ exit_inferior_silent (current_inferior ());
/* Clear out solib state while the bfd is still open. See
comments in clear_solib in solib.c. */
int core_tid;
int pid, lwpid;
asection *reg_sect = (asection *) reg_sect_arg;
- int fake_pid_p = 0;
+ bool fake_pid_p = false;
struct inferior *inf;
- if (!startswith (bfd_section_name (abfd, asect), ".reg/"))
+ if (!startswith (bfd_section_name (asect), ".reg/"))
return;
- core_tid = atoi (bfd_section_name (abfd, asect) + 5);
+ core_tid = atoi (bfd_section_name (asect) + 5);
pid = bfd_core_file_pid (core_bfd);
if (pid == 0)
{
- fake_pid_p = 1;
+ fake_pid_p = true;
pid = CORELOW_PID;
}
inf->fake_pid_p = fake_pid_p;
}
- ptid = ptid_build (pid, lwpid, 0);
+ ptid = ptid_t (pid, lwpid, 0);
- add_thread (ptid);
+ add_thread (inf->process_target (), ptid);
/* Warning, Will Robinson, looking at BFD private data! */
printf_filtered (_("No core file now.\n"));
}
-/* Backward compatability with old way of specifying core files. */
+/* Backward compatibility with old way of specifying core files. */
void
core_file_command (const char *filename, int from_tty)
core_target_open (filename, from_tty);
}
+/* Locate (and load) an executable file (and symbols) given the core file
+ BFD ABFD. */
+
+static void
+locate_exec_from_corefile_build_id (bfd *abfd, int from_tty)
+{
+ const bfd_build_id *build_id = build_id_bfd_get (abfd);
+ if (build_id == nullptr)
+ return;
+
+ gdb_bfd_ref_ptr execbfd
+ = build_id_to_exec_bfd (build_id->size, build_id->data);
+
+ if (execbfd != nullptr)
+ {
+ exec_file_attach (bfd_get_filename (execbfd.get ()), from_tty);
+ symbol_file_add_main (bfd_get_filename (execbfd.get ()),
+ symfile_add_flag (from_tty ? SYMFILE_VERBOSE : 0));
+ }
+}
+
/* See gdbcore.h. */
void
{
const char *p;
int siggy;
- struct cleanup *old_chain;
int scratch_chan;
int flags;
gdb::unique_xmalloc_ptr<char> filename (tilde_expand (arg));
if (!IS_ABSOLUTE_PATH (filename.get ()))
- filename.reset (concat (current_directory, "/",
- filename.get (), (char *) NULL));
+ filename = gdb_abspath (filename.get ());
flags = O_BINARY | O_LARGEFILE;
if (write_files)
if (temp_bfd == NULL)
perror_with_name (filename.get ());
- if (!bfd_check_format (temp_bfd.get (), bfd_core)
- && !gdb_check_format (temp_bfd.get ()))
+ if (!bfd_check_format (temp_bfd.get (), bfd_core))
{
/* Do it after the err msg */
/* FIXME: should be checking for errors from bfd_close (for one
if (!exec_bfd)
set_gdbarch_from_file (core_bfd);
- push_target (target);
- target_holder.release ();
-
- /* Do this before acknowledging the inferior, so if
- post_create_inferior throws (can happen easilly if you're loading
- a core file with the wrong exec), we aren't left with threads
- from the previous inferior. */
- init_thread_list ();
+ push_target (std::move (target_holder));
inferior_ptid = null_ptid;
bfd_map_over_sections (core_bfd, add_to_thread_list,
bfd_get_section_by_name (core_bfd, ".reg"));
- if (ptid_equal (inferior_ptid, null_ptid))
+ if (inferior_ptid == null_ptid)
{
/* Either we found no .reg/NN section, and hence we have a
non-threaded core (single-threaded, from gdb's perspective),
which was the "main" thread. The latter case shouldn't
usually happen, but we're dealing with input here, which can
always be broken in different ways. */
- struct thread_info *thread = first_thread_of_process (-1);
+ thread_info *thread = first_thread_of_inferior (current_inferior ());
if (thread == NULL)
{
inferior_appeared (current_inferior (), CORELOW_PID);
- inferior_ptid = pid_to_ptid (CORELOW_PID);
- add_thread_silent (inferior_ptid);
+ inferior_ptid = ptid_t (CORELOW_PID);
+ add_thread_silent (target, inferior_ptid);
}
else
- switch_to_thread (thread->ptid);
+ switch_to_thread (thread);
}
+ if (exec_bfd == nullptr)
+ locate_exec_from_corefile_build_id (core_bfd, from_tty);
+
post_create_inferior (target, from_tty);
/* Now go through the target stack looking for threads since there
may be a thread_stratum target loaded on top of target core by
now. The layer above should claim threads found in the BFD
sections. */
- TRY
+ try
{
target_update_thread_list ();
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
exception_print (gdb_stderr, except);
}
- END_CATCH
p = bfd_core_file_failing_command (core_bfd);
if (p)
/* Current thread should be NUM 1 but the user does not know that.
If a program is single threaded gdb in general does not mention
anything about threads. That is why the test is >= 2. */
- if (thread_count () >= 2)
+ if (thread_count (target) >= 2)
{
- TRY
+ try
{
thread_command (NULL, from_tty);
}
- CATCH (except, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &except)
{
exception_print (gdb_stderr, except);
}
- END_CATCH
}
}
'this'. */
unpush_target (this);
+ /* Clear the register cache and the frame cache. */
+ registers_changed ();
reinit_frame_cache ();
maybe_say_no_core_file_now (from_tty);
}
/* Try to retrieve registers from a section in core_bfd, and supply
- them to m_core_vec->core_read_registers, as the register set
- numbered WHICH.
+ them to REGSET.
If ptid's lwp member is zero, do the single-threaded
thing: look for a section named NAME. If ptid's lwp
core_target::get_core_register_section (struct regcache *regcache,
const struct regset *regset,
const char *name,
- int min_size,
- int which,
+ int section_min_size,
const char *human_name,
bool required)
{
+ gdb_assert (regset != nullptr);
+
struct bfd_section *section;
bfd_size_type size;
- char *contents;
- bool variable_size_section = (regset != NULL
- && regset->flags & REGSET_VARIABLE_SIZE);
+ bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE);
thread_section_name section_name (name, regcache->ptid ());
return;
}
- size = bfd_section_size (core_bfd, section);
- if (size < min_size)
+ size = bfd_section_size (section);
+ if (size < section_min_size)
{
warning (_("Section `%s' in core file too small."),
section_name.c_str ());
return;
}
- if (size != min_size && !variable_size_section)
+ if (size != section_min_size && !variable_size_section)
{
warning (_("Unexpected size of section `%s' in core file."),
section_name.c_str ());
}
- contents = (char *) alloca (size);
- if (! bfd_get_section_contents (core_bfd, section, contents,
- (file_ptr) 0, size))
+ gdb::byte_vector contents (size);
+ if (!bfd_get_section_contents (core_bfd, section, contents.data (),
+ (file_ptr) 0, size))
{
warning (_("Couldn't read %s registers from `%s' section in core file."),
human_name, section_name.c_str ());
return;
}
- if (regset != NULL)
- {
- regset->supply_regset (regset, regcache, -1, contents, size);
- return;
- }
-
- gdb_assert (m_core_vec != nullptr);
- m_core_vec->core_read_registers (regcache, contents, size, which,
- ((CORE_ADDR)
- bfd_section_vma (core_bfd, section)));
+ regset->supply_regset (regset, regcache, -1, contents.data (), size);
}
/* Data passed to gdbarch_iterate_over_regset_sections's callback. */
register note section. */
static void
-get_core_registers_cb (const char *sect_name, int size,
+get_core_registers_cb (const char *sect_name, int supply_size, int collect_size,
const struct regset *regset,
const char *human_name, void *cb_data)
{
+ gdb_assert (regset != nullptr);
+
auto *data = (get_core_registers_cb_data *) cb_data;
bool required = false;
+ bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE);
+
+ if (!variable_size_section)
+ gdb_assert (supply_size == collect_size);
if (strcmp (sect_name, ".reg") == 0)
{
human_name = "floating-point";
}
- /* The 'which' parameter is only used when no regset is provided.
- Thus we just set it to -1. */
data->target->get_core_register_section (data->regcache, regset, sect_name,
- size, -1, human_name, required);
+ supply_size, human_name, required);
}
/* Get the registers out of a core file. This is the machine-
void
core_target::fetch_registers (struct regcache *regcache, int regno)
{
- int i;
- struct gdbarch *gdbarch;
-
if (!(m_core_gdbarch != nullptr
- && gdbarch_iterate_over_regset_sections_p (m_core_gdbarch))
- && (m_core_vec == NULL || m_core_vec->core_read_registers == NULL))
+ && gdbarch_iterate_over_regset_sections_p (m_core_gdbarch)))
{
fprintf_filtered (gdb_stderr,
"Can't fetch registers from this type of core file\n");
return;
}
- gdbarch = regcache->arch ();
- if (gdbarch_iterate_over_regset_sections_p (gdbarch))
- {
- get_core_registers_cb_data data = { this, regcache };
- gdbarch_iterate_over_regset_sections (gdbarch,
- get_core_registers_cb,
- (void *) &data, NULL);
- }
- else
- {
- get_core_register_section (regcache, NULL,
- ".reg", 0, 0, "general-purpose", 1);
- get_core_register_section (regcache, NULL,
- ".reg2", 0, 2, "floating-point", 0);
- }
+ struct gdbarch *gdbarch = regcache->arch ();
+ get_core_registers_cb_data data = { this, regcache };
+ gdbarch_iterate_over_regset_sections (gdbarch,
+ get_core_registers_cb,
+ (void *) &data, NULL);
/* Mark all registers not found in the core as unavailable. */
- for (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
+ for (int i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
if (regcache->get_register_status (i) == REG_UNKNOWN)
regcache->raw_supply (i, NULL);
}
print_section_info (&m_core_section_table, core_bfd);
}
\f
-struct spuid_list
-{
- gdb_byte *buf;
- ULONGEST offset;
- LONGEST len;
- ULONGEST pos;
- ULONGEST written;
-};
-
-static void
-add_to_spuid_list (bfd *abfd, asection *asect, void *list_p)
-{
- struct spuid_list *list = (struct spuid_list *) list_p;
- enum bfd_endian byte_order
- = bfd_big_endian (abfd) ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
- int fd, pos = 0;
-
- sscanf (bfd_section_name (abfd, asect), "SPU/%d/regs%n", &fd, &pos);
- if (pos == 0)
- return;
-
- if (list->pos >= list->offset && list->pos + 4 <= list->offset + list->len)
- {
- store_unsigned_integer (list->buf + list->pos - list->offset,
- 4, byte_order, fd);
- list->written += 4;
- }
- list->pos += 4;
-}
-
enum target_xfer_status
core_target::xfer_partial (enum target_object object, const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
if (section == NULL)
return TARGET_XFER_E_IO;
- size = bfd_section_size (core_bfd, section);
+ size = bfd_section_size (section);
if (offset >= size)
return TARGET_XFER_EOF;
size -= offset;
if (section == NULL)
return TARGET_XFER_E_IO;
- size = bfd_section_size (core_bfd, section);
+ size = bfd_section_size (section);
if (offset >= size)
return TARGET_XFER_EOF;
size -= offset;
}
/* FALL THROUGH */
- case TARGET_OBJECT_SPU:
- if (readbuf && annex)
- {
- /* When the SPU contexts are stored in a core file, BFD
- represents this with a fake section called
- "SPU/<annex>". */
-
- struct bfd_section *section;
- bfd_size_type size;
- char sectionstr[100];
-
- xsnprintf (sectionstr, sizeof sectionstr, "SPU/%s", annex);
-
- section = bfd_get_section_by_name (core_bfd, sectionstr);
- if (section == NULL)
- return TARGET_XFER_E_IO;
-
- size = bfd_section_size (core_bfd, section);
- if (offset >= size)
- return TARGET_XFER_EOF;
- size -= offset;
- if (size > len)
- size = len;
-
- if (size == 0)
- return TARGET_XFER_EOF;
- if (!bfd_get_section_contents (core_bfd, section, readbuf,
- (file_ptr) offset, size))
- {
- warning (_("Couldn't read SPU section in core file."));
- return TARGET_XFER_E_IO;
- }
-
- *xfered_len = (ULONGEST) size;
- return TARGET_XFER_OK;
- }
- else if (readbuf)
- {
- /* NULL annex requests list of all present spuids. */
- struct spuid_list list;
-
- list.buf = readbuf;
- list.offset = offset;
- list.len = len;
- list.pos = 0;
- list.written = 0;
- bfd_map_over_sections (core_bfd, add_to_spuid_list, &list);
-
- if (list.written == 0)
- return TARGET_XFER_EOF;
- else
- {
- *xfered_len = (ULONGEST) list.written;
- return TARGET_XFER_OK;
- }
- }
- return TARGET_XFER_E_IO;
-
case TARGET_OBJECT_SIGNAL_INFO:
if (readbuf)
{
return this->beneath ()->read_description ();
}
-const char *
+std::string
core_target::pid_to_str (ptid_t ptid)
{
- static char buf[64];
struct inferior *inf;
int pid;
"process", with normal_pid_to_str. */
/* Try the LWPID field first. */
- pid = ptid_get_lwp (ptid);
+ pid = ptid.lwp ();
if (pid != 0)
- return normal_pid_to_str (pid_to_ptid (pid));
+ return normal_pid_to_str (ptid_t (pid));
/* Otherwise, this isn't a "threaded" core -- use the PID field, but
only if it isn't a fake PID. */
- inf = find_inferior_ptid (ptid);
+ inf = find_inferior_ptid (this, ptid);
if (inf != NULL && !inf->fake_pid_p)
return normal_pid_to_str (ptid);
/* No luck. We simply don't have a valid PID to print. */
- xsnprintf (buf, sizeof buf, "<main task>");
- return buf;
+ return "<main task>";
}
const char *
return true;
}
+void _initialize_corelow ();
void
-_initialize_corelow (void)
+_initialize_corelow ()
{
add_target (core_target_info, core_target_open, filename_completer);
}