/* Core dump and executable file functions below target vector, for GDB.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2021 Free Software Foundation, Inc.
This file is part of GDB.
#include "build-id.h"
#include "gdbsupport/pathstuff.h"
#include <unordered_map>
+#include <unordered_set>
#include "gdbcmd.h"
+#include "xml-tdesc.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
{
public:
core_target ();
- ~core_target () override;
const target_info &info () const override
{ return core_target_info; }
shared library bfds. The core bfd sections are an implementation
detail of the core target, just like ptrace is for unix child
targets. */
- target_section_table m_core_section_table {};
+ target_section_table m_core_section_table;
/* File-backed address space mappings: some core files include
information about memory mapped files. */
- target_section_table m_core_file_mappings {};
+ target_section_table m_core_file_mappings;
+
+ /* Unavailable mappings. These correspond to pathnames which either
+ weren't found or could not be opened. Knowing these addresses can
+ still be useful. */
+ std::vector<mem_range> m_core_unavailable_mappings;
/* Build m_core_file_mappings. Called from the constructor. */
void build_file_mappings ();
+ /* Helper method for xfer_partial. */
+ enum target_xfer_status xfer_memory_via_mappings (gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ ULONGEST len,
+ ULONGEST *xfered_len);
+
/* FIXME: kettenis/20031023: Eventually this field should
disappear. */
struct gdbarch *m_core_gdbarch = NULL;
core_target::core_target ()
{
+ /* Find a first arch based on the BFD. We need the initial gdbarch so
+ we can setup the hooks to find a target description. */
m_core_gdbarch = gdbarch_from_bfd (core_bfd);
+ /* If the arch is able to read a target description from the core, it
+ could yield a more specific gdbarch. */
+ const struct target_desc *tdesc = read_description ();
+
+ if (tdesc != nullptr)
+ {
+ struct gdbarch_info info;
+ info.abfd = core_bfd;
+ info.target_desc = tdesc;
+ m_core_gdbarch = gdbarch_find_by_info (info);
+ }
+
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,
- &m_core_section_table.sections,
- &m_core_section_table.sections_end))
- error (_("\"%s\": Can't find sections: %s"),
- bfd_get_filename (core_bfd), bfd_errmsg (bfd_get_error ()));
+ m_core_section_table = build_section_table (core_bfd);
build_file_mappings ();
}
-core_target::~core_target ()
-{
- xfree (m_core_section_table.sections);
- xfree (m_core_file_mappings.sections);
-}
-
/* Construct the target_section_table for file-backed mappings if
they exist.
core_target::build_file_mappings ()
{
std::unordered_map<std::string, struct bfd *> bfd_map;
+ std::unordered_set<std::string> unavailable_paths;
/* See linux_read_core_file_mappings() in linux-tdep.c for an example
read_core_file_mappings method. */
gdbarch_read_core_file_mappings (m_core_gdbarch, core_bfd,
/* After determining the number of mappings, read_core_file_mappings
- will invoke this lambda which allocates target_section storage for
- the mappings. */
- [&] (ULONGEST count)
+ will invoke this lambda. */
+ [&] (ULONGEST)
{
- m_core_file_mappings.sections = XNEWVEC (struct target_section, count);
- m_core_file_mappings.sections_end = m_core_file_mappings.sections;
},
/* read_core_file_mappings will invoke this lambda for each mapping
that it finds. */
[&] (int num, ULONGEST start, ULONGEST end, ULONGEST file_ofs,
- const char *filename, const void *other)
+ const char *filename)
{
/* Architecture-specific read_core_mapping methods are expected to
weed out non-file-backed mappings. */
= exec_file_find (filename, NULL);
if (expanded_fname == nullptr)
{
- warning (_("Can't open file %s during file-backed mapping "
- "note processing"),
- expanded_fname.get ());
+ m_core_unavailable_mappings.emplace_back (start, end - start);
+ /* Print just one warning per path. */
+ if (unavailable_paths.insert (filename).second)
+ warning (_("Can't open file %s during file-backed mapping "
+ "note processing"),
+ filename);
return;
}
bfd = bfd_map[filename] = bfd_openr (expanded_fname.get (),
- "binary");
+ "binary");
if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
{
+ m_core_unavailable_mappings.emplace_back (start, end - start);
/* If we get here, there's a good chance that it's due to
an internal error. We issue a warning instead of an
internal error because of the possibility that the
bfd_set_section_alignment (sec, 2);
/* Set target_section fields. */
- struct target_section *ts = m_core_file_mappings.sections_end++;
- ts->addr = start;
- ts->endaddr = end;
- ts->owner = nullptr;
- ts->the_bfd_section = sec;
+ m_core_file_mappings.emplace_back (start, end, sec);
});
-}
-static void add_to_thread_list (bfd *, asection *, void *);
+ normalize_mem_ranges (&m_core_unavailable_mappings);
+}
/* An arbitrary identifier for the core inferior. */
#define CORELOW_PID 1
exit_inferior_silent (current_inferior ());
/* Clear out solib state while the bfd is still open. See
- comments in clear_solib in solib.c. */
+ comments in clear_solib in solib.c. */
clear_solib ();
current_program_space->cbfd.reset (nullptr);
extract the list of threads in a core file. */
static void
-add_to_thread_list (bfd *abfd, asection *asect, void *reg_sect_arg)
+add_to_thread_list (asection *asect, asection *reg_sect)
{
int core_tid;
int pid, lwpid;
- asection *reg_sect = (asection *) reg_sect_arg;
bool fake_pid_p = false;
struct inferior *inf;
{
/* Do it after the err msg */
/* FIXME: should be checking for errors from bfd_close (for one
- thing, on error it does not free all the storage associated
- with the bfd). */
+ thing, on error it does not free all the storage associated
+ with the bfd). */
error (_("\"%s\" is not a core dump: %s"),
filename.get (), bfd_errmsg (bfd_get_error ()));
}
core file. We don't do this unconditionally since an exec file
typically contains more information that helps us determine the
architecture than a core file. */
- if (!exec_bfd)
+ if (!current_program_space->exec_bfd ())
set_gdbarch_from_file (core_bfd);
- push_target (std::move (target_holder));
+ current_inferior ()->push_target (std::move (target_holder));
switch_to_no_thread ();
/* Build up thread list from BFD sections, and possibly set the
current thread to the .reg/NN section matching the .reg
section. */
- bfd_map_over_sections (core_bfd, add_to_thread_list,
- bfd_get_section_by_name (core_bfd, ".reg"));
+ asection *reg_sect = bfd_get_section_by_name (core_bfd, ".reg");
+ for (asection *sect : gdb_bfd_sections (core_bfd))
+ add_to_thread_list (sect, reg_sect);
if (inferior_ptid == null_ptid)
{
switch_to_thread (thread);
}
- if (exec_bfd == nullptr)
+ if (current_program_space->exec_bfd () == nullptr)
locate_exec_from_corefile_build_id (core_bfd, from_tty);
- post_create_inferior (target, from_tty);
+ post_create_inferior (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
/* Note that 'this' is dangling after this call. unpush_target
closes the target, and our close implementation deletes
'this'. */
- unpush_target (this);
+ inf->unpush_target (this);
/* Clear the register cache and the frame cache. */
registers_changed ();
print_section_info (&m_core_section_table, core_bfd);
}
\f
+/* Helper method for core_target::xfer_partial. */
+
+enum target_xfer_status
+core_target::xfer_memory_via_mappings (gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len)
+{
+ enum target_xfer_status xfer_status;
+
+ xfer_status = (section_table_xfer_memory_partial
+ (readbuf, writebuf,
+ offset, len, xfered_len,
+ m_core_file_mappings));
+
+ if (xfer_status == TARGET_XFER_OK || m_core_unavailable_mappings.empty ())
+ return xfer_status;
+
+ /* There are instances - e.g. when debugging within a docker
+ container using the AUFS storage driver - where the pathnames
+ obtained from the note section are incorrect. Despite the path
+ being wrong, just knowing the start and end addresses of the
+ mappings is still useful; we can attempt an access of the file
+ stratum constrained to the address ranges corresponding to the
+ unavailable mappings. */
+
+ ULONGEST memaddr = offset;
+ ULONGEST memend = offset + len;
+
+ for (const auto &mr : m_core_unavailable_mappings)
+ {
+ if (address_in_mem_range (memaddr, &mr))
+ {
+ if (!address_in_mem_range (memend, &mr))
+ len = mr.start + mr.length - memaddr;
+
+ xfer_status = this->beneath ()->xfer_partial (TARGET_OBJECT_MEMORY,
+ NULL,
+ readbuf,
+ writebuf,
+ offset,
+ len,
+ xfered_len);
+ break;
+ }
+ }
+
+ return xfer_status;
+}
+
enum target_xfer_status
core_target::xfer_partial (enum target_object object, const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
xfer_status = section_table_xfer_memory_partial
(readbuf, writebuf,
offset, len, xfered_len,
- m_core_section_table.sections,
- m_core_section_table.sections_end,
+ m_core_section_table,
has_contents_cb);
if (xfer_status == TARGET_XFER_OK)
return TARGET_XFER_OK;
core file provided mappings (e.g. from .note.linuxcore.file
or the like) as this should provide a more accurate
result. If not, check the stratum beneath us, which should
- be the file stratum. */
- if (m_core_file_mappings.sections != nullptr)
- xfer_status = section_table_xfer_memory_partial
- (readbuf, writebuf,
- offset, len, xfered_len,
- m_core_file_mappings.sections,
- m_core_file_mappings.sections_end);
+ be the file stratum.
+
+ We also check unavailable mappings due to Docker/AUFS driver
+ issues. */
+ if (!m_core_file_mappings.empty ()
+ || !m_core_unavailable_mappings.empty ())
+ {
+ xfer_status = xfer_memory_via_mappings (readbuf, writebuf, offset,
+ len, xfered_len);
+ }
else
xfer_status = this->beneath ()->xfer_partial (object, annex, readbuf,
writebuf, offset, len,
xfer_status = section_table_xfer_memory_partial
(readbuf, writebuf,
offset, len, xfered_len,
- m_core_section_table.sections,
- m_core_section_table.sections_end,
+ m_core_section_table,
no_contents_cb);
return xfer_status;
const struct target_desc *
core_target::read_description ()
{
+ /* If the core file contains a target description note then we will use
+ that in preference to anything else. */
+ bfd_size_type tdesc_note_size = 0;
+ struct bfd_section *tdesc_note_section
+ = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+ if (tdesc_note_section != nullptr)
+ tdesc_note_size = bfd_section_size (tdesc_note_section);
+ if (tdesc_note_size > 0)
+ {
+ gdb::char_vector contents (tdesc_note_size + 1);
+ if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+ contents.data (), (file_ptr) 0,
+ tdesc_note_size))
+ {
+ /* Ensure we have a null terminator. */
+ contents[tdesc_note_size] = '\0';
+ const struct target_desc *result
+ = string_read_description_xml (contents.data ());
+ if (result != nullptr)
+ return result;
+ }
+ }
+
if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
{
const struct target_desc *result;
void
core_target::info_proc_mappings (struct gdbarch *gdbarch)
{
- if (m_core_file_mappings.sections != m_core_file_mappings.sections_end)
+ if (!m_core_file_mappings.empty ())
{
printf_filtered (_("Mapped address spaces:\n\n"));
if (gdbarch_addr_bit (gdbarch) == 32)
}
}
- for (const struct target_section *tsp = m_core_file_mappings.sections;
- tsp < m_core_file_mappings.sections_end;
- tsp++)
+ for (const target_section &tsp : m_core_file_mappings)
{
- ULONGEST start = tsp->addr;
- ULONGEST end = tsp->endaddr;
- ULONGEST file_ofs = tsp->the_bfd_section->filepos;
- const char *filename = bfd_get_filename (tsp->the_bfd_section->owner);
+ ULONGEST start = tsp.addr;
+ ULONGEST end = tsp.endaddr;
+ ULONGEST file_ofs = tsp.the_bfd_section->filepos;
+ const char *filename = bfd_get_filename (tsp.the_bfd_section->owner);
if (gdbarch_addr_bit (gdbarch) == 32)
printf_filtered ("\t%10s %10s %10s %10s %s\n",
{
add_target (core_target_info, core_target_open, filename_completer);
add_cmd ("core-file-backed-mappings", class_maintenance,
- maintenance_print_core_file_backed_mappings,
+ maintenance_print_core_file_backed_mappings,
_("Print core file's file-backed mappings."),
&maintenanceprintlist);
}