/* Core dump and executable file functions below target vector, for GDB.
- Copyright (C) 1986-2019 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
#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 "gdb_bfd.h"
#include "completer.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 = {
bool has_memory () override;
bool has_stack () override;
bool has_registers () override;
- bool has_execution (ptid_t) override { return false; }
+ bool has_execution (inferior *inf) override { return false; }
bool info_proc (const char *, enum info_proc_what) override;
const struct regset *regset,
const char *name,
int section_min_size,
- int which,
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;
{
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
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
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
{
inferior_appeared (current_inferior (), CORELOW_PID);
inferior_ptid = ptid_t (CORELOW_PID);
- add_thread_silent (inferior_ptid);
+ add_thread_silent (target, inferior_ptid);
}
else
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
/* 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 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
const struct regset *regset,
const char *name,
int section_min_size,
- int which,
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 ());
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 (section));
+ regset->supply_regset (regset, regcache, -1, contents.data (), size);
}
/* Data passed to gdbarch_iterate_over_regset_sections's callback. */
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 != NULL
- && regset->flags & REGSET_VARIABLE_SIZE);
+ bool variable_size_section = (regset->flags & REGSET_VARIABLE_SIZE);
if (!variable_size_section)
gdb_assert (supply_size == collect_size);
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,
- supply_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 (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,
}
/* 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 (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)
{
/* 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);
return true;
}
+void _initialize_corelow ();
void
-_initialize_corelow (void)
+_initialize_corelow ()
{
add_target (core_target_info, core_target_open, filename_completer);
}