Compare commits

...

1 Commits

Author SHA1 Message Date
fredrikhederstierna
3bc35691f1 Support for corefiles for arm-none-eabi target.
Change-Id: I8f4c57e653ae4e0400475ea55069f0dde280babb
2020-10-21 21:46:18 -04:00
7 changed files with 561 additions and 1 deletions

View File

@@ -721,6 +721,7 @@ ALL_TARGET_OBS = \
arm-fbsd-tdep.o \
arm-linux-tdep.o \
arm-netbsd-tdep.o \
arm-none-tdep.o \
arm-obsd-tdep.o \
arm-pikeos-tdep.o \
arm-symbian-tdep.o \
@@ -788,6 +789,7 @@ ALL_TARGET_OBS = \
nds32-tdep.o \
nios2-linux-tdep.o \
nios2-tdep.o \
none-tdep.o \
nto-tdep.o \
obsd-tdep.o \
or1k-linux-tdep.o \
@@ -1225,6 +1227,7 @@ HFILES_NO_SRCDIR = \
arch-utils.h \
arm-linux-tdep.h \
arm-netbsd-tdep.h \
arm-none-tdep.h \
arm-tdep.h \
async-event.h \
auto-load.h \
@@ -1350,6 +1353,7 @@ HFILES_NO_SRCDIR = \
netbsd-tdep.h \
nds32-tdep.h \
nios2-tdep.h \
none-tdep.h \
nto-tdep.h \
objc-lang.h \
objfiles.h \
@@ -2152,6 +2156,7 @@ ALLDEPFILES = \
arm-linux-tdep.c \
arm-netbsd-nat.c \
arm-netbsd-tdep.c \
arm-none-tdep.c \
arm-obsd-tdep.c \
arm-symbian-tdep.c \
arm-tdep.c \
@@ -2238,6 +2243,7 @@ ALLDEPFILES = \
nds32-tdep.c \
nios2-linux-tdep.c \
nios2-tdep.c \
none-tdep.c \
obsd-nat.c \
obsd-tdep.c \
posix-hdep.c \

184
gdb/arm-none-tdep.c Normal file
View File

@@ -0,0 +1,184 @@
/* none on ARM target support.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "target.h"
#include "value.h"
#include "gdbtypes.h"
#include "gdbcore.h"
#include "frame.h"
#include "regcache.h"
#include "solib-svr4.h"
#include "osabi.h"
#include "regset.h"
#include "trad-frame.h"
#include "tramp-frame.h"
#include "breakpoint.h"
#include "auxv.h"
#include "aarch32-tdep.h"
#include "arch/arm.h"
#include "arm-tdep.h"
#include "arm-none-tdep.h"
#include "glibc-tdep.h"
#include "arch-utils.h"
#include "inferior.h"
#include "gdbthread.h"
#include "symfile.h"
#include "cli/cli-utils.h"
#include "stap-probe.h"
#include "parser-defs.h"
#include "user-regs.h"
#include <ctype.h>
#include "elf-bfd.h"
#include "coff/internal.h"
#include "elf/arm.h"
#include "elf/common.h"
/* The ARM none register setup is based on the ARM GNU/Linux design. */
static void
arm_none_supply_gregset (const struct regset *regset,
struct regcache *regcache,
int regnum, const void *gregs_buf, size_t len)
{
struct gdbarch *gdbarch = regcache->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
int regno;
CORE_ADDR reg_pc;
gdb_byte pc_buf[ARM_INT_REGISTER_SIZE];
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno);
if (regnum == ARM_PS_REGNUM || regnum == -1)
{
if (arm_apcs_32)
regcache->raw_supply (ARM_PS_REGNUM,
gregs + ARM_INT_REGISTER_SIZE * ARM_NONE_CPSR_GREGNUM);
else
regcache->raw_supply (ARM_PS_REGNUM,
gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
if (regnum == ARM_PC_REGNUM || regnum == -1)
{
reg_pc = extract_unsigned_integer (
gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM,
ARM_INT_REGISTER_SIZE, byte_order);
reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order,
reg_pc);
regcache->raw_supply (ARM_PC_REGNUM, pc_buf);
}
}
static void
arm_none_collect_gregset (const struct regset *regset,
const struct regcache *regcache,
int regnum, void *gregs_buf, size_t len)
{
gdb_byte *gregs = (gdb_byte *) gregs_buf;
int regno;
for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
regcache->raw_collect (regno,
gregs + ARM_INT_REGISTER_SIZE * regno);
if (regnum == ARM_PS_REGNUM || regnum == -1)
{
if (arm_apcs_32)
regcache->raw_collect (ARM_PS_REGNUM,
gregs + ARM_INT_REGISTER_SIZE * ARM_NONE_CPSR_GREGNUM);
else
regcache->raw_collect (ARM_PS_REGNUM,
gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
if (regnum == ARM_PC_REGNUM || regnum == -1)
regcache->raw_collect (ARM_PC_REGNUM,
gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM);
}
/* Support VFP register format. */
static void
arm_none_supply_vfp (const struct regset *regset,
struct regcache *regcache,
int regnum, const void *regs_buf, size_t len)
{
const gdb_byte *regs = (const gdb_byte *) regs_buf;
int regno;
if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8);
for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8);
}
static void
arm_none_collect_vfp (const struct regset *regset,
const struct regcache *regcache,
int regnum, void *regs_buf, size_t len)
{
gdb_byte *regs = (gdb_byte *) regs_buf;
int regno;
if (regnum == ARM_FPSCR_REGNUM || regnum == -1)
regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8);
for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++)
if (regnum == -1 || regnum == regno)
regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8);
}
static const struct regset arm_none_gregset =
{
nullptr, arm_none_supply_gregset, arm_none_collect_gregset
};
static const struct regset arm_none_vfpregset =
{
nullptr, arm_none_supply_vfp, arm_none_collect_vfp
};
/* Iterate over core file register note sections. */
void
arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
iterate_over_regset_sections_cb *cb,
void *cb_data,
const struct regcache *regcache)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET,
&arm_none_gregset, nullptr, cb_data);
if (tdep->vfp_register_count > 0)
cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP,
&arm_none_vfpregset, "VFP floating-point", cb_data);
}

42
gdb/arm-none-tdep.h Normal file
View File

@@ -0,0 +1,42 @@
/* none on ARM target support, prototypes.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef ARM_NONE_TDEP_H
#define ARM_NONE_TDEP_H
#include "bfd.h"
#include "regset.h"
struct regcache;
/* Core file and register set support. */
#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE)
/* Support VFP register format. */
#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4)
/* The index to access CSPR in user_regs as defined in GLIBC. */
#define ARM_NONE_CPSR_GREGNUM 16
void
arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
iterate_over_regset_sections_cb *cb,
void *cb_data,
const struct regcache *regcache);
#endif /* ARM_NONE_TDEP_H */

View File

@@ -50,6 +50,8 @@
#include "arch/arm.h"
#include "arch/arm-get-next-pcs.h"
#include "arm-tdep.h"
#include "none-tdep.h"
#include "arm-none-tdep.h"
#include "gdb/sim-arm.h"
#include "elf-bfd.h"
@@ -9453,6 +9455,11 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Virtual tables. */
set_gdbarch_vbit_in_delta (gdbarch, 1);
/* Default none core file support, can be overridden by osabi. */
none_init_corefile (info, gdbarch);
set_gdbarch_iterate_over_regset_sections (gdbarch,
arm_none_iterate_over_regset_sections);
/* Hook in the ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);

View File

@@ -64,7 +64,8 @@ arc*-*-*)
arm*-*-*)
cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \
arch/arm-get-next-pcs.o arm-tdep.o";;
arch/arm-get-next-pcs.o arm-tdep.o \
none-tdep.o arm-none-tdep.o";;
hppa*-*-*)
# Target: HP PA-RISC

290
gdb/none-tdep.c Normal file
View File

@@ -0,0 +1,290 @@
/* Target-dependent code for none, architecture independent.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "gdbtypes.h"
#include "none-tdep.h"
#include "target.h"
#include "gdbthread.h"
#include "gdbcore.h"
#include "regcache.h"
#include "regset.h"
#include "elf/common.h"
#include "elf-bfd.h" /* for elfcore_write_* */
#include "inferior.h"
#include "cli/cli-utils.h"
#include "arch-utils.h"
#include "gdb_obstack.h"
#include "observable.h"
#include "objfiles.h"
#include "infcall.h"
#include "gdbcmd.h"
#include "gdb_regex.h"
#include "gdbsupport/enum-flags.h"
#include "gdbsupport/gdb_optional.h"
#include <ctype.h>
using none_collect_thread_registers_ftype
= void (const struct regcache *, ptid_t, bfd *,
gdb::unique_xmalloc_ptr<char> &, int *, enum gdb_signal);
/* The ARM none corefile setup is based on the ARM GNU/Linux design. */
/* Structure for passing information from
none_collect_thread_registers via an iterator to
none_collect_regset_section_cb. */
struct none_collect_regset_section_cb_data
{
none_collect_regset_section_cb_data (struct gdbarch *gdbarch,
const struct regcache *regcache,
bfd *obfd,
gdb::unique_xmalloc_ptr<char> &note_data,
int *note_size,
unsigned long lwp,
enum gdb_signal stop_signal)
: gdbarch (gdbarch), regcache (regcache), obfd (obfd),
note_data (note_data), note_size (note_size),
lwp (lwp), stop_signal (stop_signal)
{}
struct gdbarch *gdbarch;
const struct regcache *regcache;
bfd *obfd;
gdb::unique_xmalloc_ptr<char> &note_data;
int *note_size;
unsigned long lwp;
enum gdb_signal stop_signal;
bool abort_iteration = false;
};
/* Callback for iterate_over_regset_sections that records a single
regset in the corefile note section. */
static void
none_collect_regset_section_cb (const char *sect_name, int supply_size,
int collect_size, const struct regset *regset,
const char *human_name, void *cb_data)
{
struct none_collect_regset_section_cb_data *data
= (struct none_collect_regset_section_cb_data *) cb_data;
bool variable_size_section = (regset != nullptr
&& regset->flags & REGSET_VARIABLE_SIZE);
if (!variable_size_section)
gdb_assert (supply_size == collect_size);
if (data->abort_iteration)
return;
gdb_assert (regset && regset->collect_regset);
/* This is intentionally zero-initialized by using std::vector, so
that any padding bytes in the core file will show as 0. */
std::vector<gdb_byte> buf (collect_size);
regset->collect_regset (regset, data->regcache, -1, buf.data (),
collect_size);
/* PRSTATUS still needs to be treated specially. */
if (strcmp (sect_name, ".reg") == 0)
data->note_data.reset (elfcore_write_prstatus
(data->obfd, data->note_data.release (),
data->note_size, data->lwp,
gdb_signal_to_host (data->stop_signal),
buf.data ()));
else
data->note_data.reset (elfcore_write_register_note
(data->obfd, data->note_data.release (),
data->note_size, sect_name, buf.data (),
collect_size));
if (data->note_data == nullptr)
data->abort_iteration = 1;
}
/* Records the thread's register state for the corefile note
section. */
static void
none_collect_thread_registers (const struct regcache *regcache,
ptid_t ptid, bfd *obfd,
gdb::unique_xmalloc_ptr<char> &note_data,
int *note_size, enum gdb_signal stop_signal)
{
struct gdbarch *gdbarch = regcache->arch ();
unsigned long lwp;
/* For remote targets the LWP may not be available, so use the TID. */
lwp = ptid.lwp ();
if (lwp == 0)
lwp = ptid.tid ();
none_collect_regset_section_cb_data data (gdbarch, regcache, obfd, note_data,
note_size, lwp, stop_signal);
gdbarch_iterate_over_regset_sections (gdbarch,
none_collect_regset_section_cb,
&data, regcache);
}
struct none_corefile_thread_data
{
none_corefile_thread_data (struct gdbarch *gdbarch,
bfd *obfd,
gdb::unique_xmalloc_ptr<char> &note_data,
int *note_size,
enum gdb_signal stop_signal)
: gdbarch (gdbarch), obfd (obfd), note_data (note_data),
note_size (note_size), stop_signal (stop_signal)
{}
struct gdbarch *gdbarch;
bfd *obfd;
gdb::unique_xmalloc_ptr<char> &note_data;
int *note_size;
enum gdb_signal stop_signal;
};
/* Records the thread's register state for the corefile note
section. */
static void
none_corefile_thread (struct thread_info *info,
struct none_corefile_thread_data *args)
{
struct regcache *regcache;
regcache = get_thread_arch_regcache (info->inf->process_target (),
info->ptid, args->gdbarch);
target_fetch_registers (regcache, -1);
none_collect_thread_registers
(regcache, info->ptid, args->obfd, args->note_data,
args->note_size, args->stop_signal);
}
/* Find the signalled thread. In case there's more than one signalled
thread, prefer the current thread, if it is signalled. If no
thread was signalled, default to the current thread, unless it has
exited, in which case return nullptr. */
static thread_info *
find_signalled_thread ()
{
thread_info *curr_thr = inferior_thread ();
if (curr_thr->state != THREAD_EXITED
&& curr_thr->suspend.stop_signal != GDB_SIGNAL_0)
return curr_thr;
for (thread_info *thr : current_inferior ()->non_exited_threads ())
if (thr->suspend.stop_signal != GDB_SIGNAL_0)
return thr;
/* Default to the current thread, unless it has exited. */
if (curr_thr->state != THREAD_EXITED)
return curr_thr;
return nullptr;
}
/* Fills the "to_make_corefile_note" target vector. Builds the note
section for a corefile, and returns it in a malloc buffer. */
static gdb::unique_xmalloc_ptr<char>
none_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size,
none_collect_thread_registers_ftype collect)
{
gdb::unique_xmalloc_ptr<char> note_data;
/* Process information. */
if (get_exec_file (0))
{
const char *fname = lbasename (get_exec_file (0));
std::string psargs = fname;
if (get_inferior_args ())
{
psargs += " ";
psargs += get_inferior_args ();
}
note_data.reset (elfcore_write_prpsinfo (obfd, note_data.release (),
note_size, fname,
psargs.c_str ()));
}
if (!note_data)
return nullptr;
/* Thread register information. */
try
{
update_thread_list ();
}
catch (const gdb_exception_error &e)
{
exception_print (gdb_stderr, e);
}
/* Like the kernel, prefer dumping the signalled thread first.
"First thread" is what tools use to infer the signalled
thread. */
thread_info *signalled_thr = find_signalled_thread ();
gdb_signal stop_signal;
if (signalled_thr != nullptr)
stop_signal = signalled_thr->suspend.stop_signal;
else
stop_signal = GDB_SIGNAL_0;
none_corefile_thread_data thread_args (gdbarch, obfd, note_data, note_size,
stop_signal);
if (signalled_thr != nullptr)
none_corefile_thread (signalled_thr, &thread_args);
for (thread_info *thr : current_inferior ()->non_exited_threads ())
{
if (thr == signalled_thr)
continue;
none_corefile_thread (thr, &thread_args);
}
return note_data;
}
static gdb::unique_xmalloc_ptr<char>
none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
return none_make_corefile_notes_1 (gdbarch, obfd, note_size,
none_collect_thread_registers);
}
/* Setup default core file support for none targets.
Can be overridden later by OSABI. */
void
none_init_corefile (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
/* Default core file support. */
set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes);
}

30
gdb/none-tdep.h Normal file
View File

@@ -0,0 +1,30 @@
/* Target-dependent code for none, architecture independent.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef NONE_TDEP_H
#define NONE_TDEP_H
#include "bfd.h"
struct regcache;
void none_init_corefile (struct gdbarch_info info,
struct gdbarch *gdbarch);
#endif /* none-tdep.h */