/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986-2020 Free Software Foundation, Inc.
+ Copyright (C) 1986-2023 Free Software Foundation, Inc.
This file is part of GDB.
#include "linux-record.h"
#include "record-full.h"
#include "infrun.h"
+#include "expop.h"
#include "stap-probe.h"
#include "ax.h"
#include "user-regs.h"
#include <ctype.h>
#include "elf-bfd.h"
+#include "producer.h"
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
static enum return_value_convention
ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *valtype, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
+ struct value **read_value, const gdb_byte *writebuf)
{
- if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
- || TYPE_CODE (valtype) == TYPE_CODE_UNION)
- && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8)
- && TYPE_VECTOR (valtype)))
+ gdb_byte *readbuf = nullptr;
+ if (read_value != nullptr)
+ {
+ *read_value = value::allocate (valtype);
+ readbuf = (*read_value)->contents_raw ().data ();
+ }
+
+ if ((valtype->code () == TYPE_CODE_STRUCT
+ || valtype->code () == TYPE_CODE_UNION)
+ && !((valtype->length () == 16 || valtype->length () == 8)
+ && valtype->is_vector ()))
return RETURN_VALUE_STRUCT_CONVENTION;
else
return ppc_sysv_abi_return_value (gdbarch, function, valtype, regcache,
stub sequence. */
static CORE_ADDR
-ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+ppc_skip_trampoline_code (frame_info_ptr frame, CORE_ADDR pc)
{
unsigned int insnbuf[POWERPC32_PLT_CHECK_LEN];
struct gdbarch *gdbarch = get_frame_arch (frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR target = 0;
int scan_limit, i;
const struct regset *
ppc_linux_cgprregset (struct gdbarch *gdbarch)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
if (tdep->wordsize == 4)
{
int regnum, void *buf, size_t len)
{
struct gdbarch *gdbarch = regcache->arch ();
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
const struct regset *cgprregset = ppc_linux_cgprregset (gdbarch);
void *cb_data,
const struct regcache *regcache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
int have_altivec = tdep->ppc_vr0_regnum != -1;
int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
int have_ppr = tdep->ppc_ppr_regnum != -1;
}
static void
-ppc_linux_sigtramp_cache (struct frame_info *this_frame,
+ppc_linux_sigtramp_cache (frame_info_ptr this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func, LONGEST offset,
int bias)
CORE_ADDR fpregs;
int i;
struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
base = get_frame_register_unsigned (this_frame,
fpregs + i * tdep->wordsize);
}
trad_frame_set_reg_addr (this_cache, tdep->ppc_fpscr_regnum,
- fpregs + 32 * tdep->wordsize);
+ fpregs + 32 * tdep->wordsize);
}
trad_frame_set_id (this_cache, frame_id_build (base, func));
}
static void
ppc32_linux_sigaction_cache_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
static void
ppc64_linux_sigaction_cache_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
static void
ppc32_linux_sighandler_cache_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
static void
ppc64_linux_sighandler_cache_init (const struct tramp_frame *self,
- struct frame_info *this_frame,
+ frame_info_ptr this_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
/* If we do, then it is safe to check the size. */
return register_size (gdbarch, PPC_ORIG_R3_REGNUM) > 0
- && register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
+ && register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
}
/* Return the current system call's number present in the
thread_info *thread)
{
struct regcache *regcache = get_thread_regcache (thread);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Make sure we're in a 32- or 64-bit machine */
SYSCALL. */
static enum gdb_syscall
-ppc_canonicalize_syscall (int syscall)
+ppc_canonicalize_syscall (int syscall, int wordsize)
{
int result = -1;
result = syscall += 259 - 240;
else if (syscall >= 250 && syscall <= 251) /* tgkill */
result = syscall + 270 - 250;
+ else if (syscall == 286)
+ result = gdb_sys_openat;
+ else if (syscall == 291)
+ {
+ if (wordsize == 64)
+ result = gdb_sys_newfstatat;
+ else
+ result = gdb_sys_fstatat64;
+ }
+ else if (syscall == 317)
+ result = gdb_sys_pipe2;
else if (syscall == 336)
result = gdb_sys_recv;
else if (syscall == 337)
result = gdb_sys_recvfrom;
else if (syscall == 342)
result = gdb_sys_recvmsg;
+ else if (syscall == 359)
+ result = gdb_sys_getrandom;
return (enum gdb_syscall) result;
}
ppc_linux_syscall_record (struct regcache *regcache)
{
struct gdbarch *gdbarch = regcache->arch ();
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
ULONGEST scnum;
enum gdb_syscall syscall_gdb;
int ret;
regcache_raw_read_unsigned (regcache, tdep->ppc_gp0_regnum, &scnum);
- syscall_gdb = ppc_canonicalize_syscall (scnum);
+ syscall_gdb = ppc_canonicalize_syscall (scnum, tdep->wordsize);
if (syscall_gdb < 0)
{
- printf_unfiltered (_("Process record and replay target doesn't "
- "support syscall number %d\n"), (int) scnum);
+ gdb_printf (gdb_stderr,
+ _("Process record and replay target doesn't "
+ "support syscall number %d\n"), (int) scnum);
return 0;
}
const int SIGNAL_FRAMESIZE = 128;
const int sizeof_rt_sigframe = 1440 * 2 + 8 * 2 + 4 * 6 + 8 + 8 + 128 + 512;
ULONGEST sp;
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
int i;
for (i = 3; i <= 12; i++)
if (vsx)
features.vsx = true;
- CORE_ADDR hwcap = linux_get_hwcap (target);
+ gdb::optional<gdb::byte_vector> auxv = target_read_auxv_raw (target);
+ CORE_ADDR hwcap = linux_get_hwcap (auxv, target, gdbarch);
features.isa205 = ppc_linux_has_isa205 (hwcap);
static void
ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
{
+ if ((sym->flags & BSF_SYNTHETIC) != 0)
+ /* ELFv2 synthetic symbols (the PLT stubs and the __glink_PLTresolve
+ trampoline) do not have a local entry point. */
+ return;
+
elf_symbol_type *elf_sym = (elf_symbol_type *)sym;
/* If the symbol is marked as having a local entry point, set a target
default:
break;
case 8:
- MSYMBOL_TARGET_FLAG_1 (msym) = 1;
+ msym->set_target_flag_1 (true);
break;
}
}
/* See ppc_elfv2_elf_make_msymbol_special for how local entry point
offset values are encoded. */
- if (MSYMBOL_TARGET_FLAG_1 (fun.minsym))
+ if (fun.minsym->target_flag_1 ())
local_entry_offset = 8;
- if (BMSYMBOL_VALUE_ADDRESS (fun) <= pc
- && pc < BMSYMBOL_VALUE_ADDRESS (fun) + local_entry_offset)
- return BMSYMBOL_VALUE_ADDRESS (fun) + local_entry_offset;
+ if (fun.value_address () <= pc
+ && pc < fun.value_address () + local_entry_offset)
+ return fun.value_address () + local_entry_offset;
return pc;
}
/* Implementation of `gdbarch_stap_parse_special_token', as defined in
gdbarch.h. */
-static int
+static expr::operation_up
ppc_stap_parse_special_token (struct gdbarch *gdbarch,
struct stap_parse_info *p)
{
const char *s = p->arg;
char *regname;
int len;
- struct stoken str;
while (isdigit (*s))
++s;
{
/* It is a register displacement indeed. Returning 0 means we are
deferring the treatment of this case to the generic parser. */
- return 0;
+ return {};
}
len = s - p->arg;
error (_("Invalid register name `%s' on expression `%s'."),
regname, p->saved_arg);
- write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- str.ptr = regname;
- str.length = len;
- write_exp_string (&p->pstate, str);
- write_exp_elt_opcode (&p->pstate, OP_REGISTER);
-
p->arg = s;
- }
- else
- {
- /* All the other tokens should be handled correctly by the generic
- parser. */
- return 0;
+
+ return expr::make_operation<expr::register_operation> (regname);
}
- return 1;
+ /* All the other tokens should be handled correctly by the generic
+ parser. */
+ return {};
}
/* Initialize linux_record_tdep if not initialized yet.
ppc_init_linux_record_tdep (struct linux_record_tdep *record_tdep,
int wordsize)
{
+ /* The values for TCGETS, TCSETS, TCSETSW, TCSETSF are based on the
+ size of struct termios in the kernel source.
+ include/uapi/asm-generic/termbits.h */
+#define SIZE_OF_STRUCT_TERMIOS 0x2c
+
/* Simply return if it had been initialized. */
if (record_tdep->size_pointer != 0)
return;
record_tdep->size_time_t = 4;
}
else
- internal_error (__FILE__, __LINE__, _("unexpected wordsize"));
+ internal_error (_("unexpected wordsize"));
/* These values are the second argument of system call "sys_fcntl"
and "sys_fcntl64". They are obtained from Linux Kernel source. */
/* These values are the second argument of system call "sys_ioctl".
They are obtained from Linux Kernel source.
See arch/powerpc/include/uapi/asm/ioctls.h. */
- record_tdep->ioctl_TCGETS = 0x403c7413;
- record_tdep->ioctl_TCSETS = 0x803c7414;
- record_tdep->ioctl_TCSETSW = 0x803c7415;
- record_tdep->ioctl_TCSETSF = 0x803c7416;
record_tdep->ioctl_TCGETA = 0x40147417;
record_tdep->ioctl_TCSETA = 0x80147418;
record_tdep->ioctl_TCSETAW = 0x80147419;
record_tdep->ioctl_TCSETAF = 0x8014741c;
+ record_tdep->ioctl_TCGETS = 0x40007413 | (SIZE_OF_STRUCT_TERMIOS << 16);
+ record_tdep->ioctl_TCSETS = 0x80007414 | (SIZE_OF_STRUCT_TERMIOS << 16);
+ record_tdep->ioctl_TCSETSW = 0x80007415 | (SIZE_OF_STRUCT_TERMIOS << 16);
+ record_tdep->ioctl_TCSETSF = 0x80007416 | (SIZE_OF_STRUCT_TERMIOS << 16);
+
record_tdep->ioctl_TCSBRK = 0x2000741d;
record_tdep->ioctl_TCXONC = 0x2000741e;
record_tdep->ioctl_TCFLSH = 0x2000741f;
static const struct floatformat **
ppc_floatformat_for_type (struct gdbarch *gdbarch,
- const char *name, int len)
+ const char *name, int len)
{
if (len == 128 && name)
{
|| strcmp (name, "_Float64x") == 0
|| strcmp (name, "complex _Float128") == 0
|| strcmp (name, "complex _Float64x") == 0)
- return floatformats_ia64_quad;
+ return floatformats_ieee_quad;
if (strcmp (name, "__ibm128") == 0)
return floatformats_ibm_long_double;
return default_floatformat_for_type (gdbarch, name, len);
}
+static bool
+linux_dwarf2_omit_typedef_p (struct type *target_type,
+ const char *producer, const char *name)
+{
+ int gcc_major, gcc_minor;
+
+ if (producer_is_gcc (producer, &gcc_major, &gcc_minor))
+ {
+ if ((target_type->code () == TYPE_CODE_FLT
+ || target_type->code () == TYPE_CODE_COMPLEX)
+ && (strcmp (name, "long double") == 0
+ || strcmp (name, "complex long double") == 0))
+ {
+ /* IEEE 128-bit floating point and IBM long double are two
+ encodings for 128-bit values. The DWARF debug data can't
+ distinguish between them. See bugzilla:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104194
+
+ A GCC hack was introduced to still allow the debugger to identify
+ the case where "long double" uses the IEEE 128-bit floating point
+ format: GCC will emit a bogus DWARF type record pretending that
+ "long double" is a typedef alias for the _Float128 type.
+
+ This hack should not be visible to the GDB user, so we replace
+ this bogus typedef by a normal floating-point type, copying the
+ format information from the target type of the bogus typedef. */
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Specify the powerpc64le target triplet.
+ This can be variations of
+ ppc64le-{distro}-linux-gcc
+ and
+ powerpc64le-{distro}-linux-gcc. */
+
+static const char *
+ppc64le_gnu_triplet_regexp (struct gdbarch *gdbarch)
+{
+ return "p(ower)?pc64le";
+}
+
+/* Specify the powerpc64 target triplet.
+ This can be variations of
+ ppc64-{distro}-linux-gcc
+ and
+ powerpc64-{distro}-linux-gcc. */
+
+static const char *
+ppc64_gnu_triplet_regexp (struct gdbarch *gdbarch)
+{
+ return "p(ower)?pc64";
+}
+
+/* Implement the linux_gcc_target_options method. */
+
+static std::string
+ppc64_linux_gcc_target_options (struct gdbarch *gdbarch)
+{
+ return "";
+}
+
+static displaced_step_prepare_status
+ppc_linux_displaced_step_prepare (gdbarch *arch, thread_info *thread,
+ CORE_ADDR &displaced_pc)
+{
+ ppc_inferior_data *per_inferior = get_ppc_per_inferior (thread->inf);
+ if (!per_inferior->disp_step_buf.has_value ())
+ {
+ /* Figure out where the displaced step buffer is. */
+ CORE_ADDR disp_step_buf_addr
+ = linux_displaced_step_location (thread->inf->gdbarch);
+
+ per_inferior->disp_step_buf.emplace (disp_step_buf_addr);
+ }
+
+ return per_inferior->disp_step_buf->prepare (thread, displaced_pc);
+}
+
static void
ppc_linux_init_abi (struct gdbarch_info info,
- struct gdbarch *gdbarch)
+ struct gdbarch *gdbarch)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
struct tdesc_arch_data *tdesc_data = info.tdesc_data;
static const char *const stap_integer_prefixes[] = { "i", NULL };
static const char *const stap_register_indirection_prefixes[] = { "(",
static const char *const stap_register_indirection_suffixes[] = { ")",
NULL };
- linux_init_abi (info, gdbarch);
+ linux_init_abi (info, gdbarch, 0);
/* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
128-bit, they can be either IBM long double or IEEE quad long double.
to distinguish between the IBM long double and IEEE quad cases. */
set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
if (tdep->long_double_abi == POWERPC_LONG_DOUBLE_IEEE128)
- set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_quad);
else
set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
/* Support for floating-point data type variants. */
set_gdbarch_floatformat_for_type (gdbarch, ppc_floatformat_for_type);
+ /* Support for replacing typedef record. */
+ set_gdbarch_dwarf2_omit_typedef_p (gdbarch, linux_dwarf2_omit_typedef_p);
+
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
(well ignoring vectors that is). When this was corrected, it
wasn't fixed for GNU/Linux native platform. Use the
PowerOpen struct convention. */
- set_gdbarch_return_value (gdbarch, ppc_linux_return_value);
+ set_gdbarch_return_value_as_value (gdbarch, ppc_linux_return_value);
+ set_gdbarch_return_value (gdbarch, nullptr);
set_gdbarch_memory_remove_breakpoint (gdbarch,
- ppc_linux_memory_remove_breakpoint);
+ ppc_linux_memory_remove_breakpoint);
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, ppc_skip_trampoline_code);
set_solib_svr4_fetch_link_map_offsets
- (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+ (gdbarch, linux_ilp32_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC);
powerpc_so_ops.in_dynsym_resolve_code =
powerpc_linux_in_dynsym_resolve_code;
}
- set_solib_ops (gdbarch, &powerpc_so_ops);
+ set_gdbarch_so_ops (gdbarch, &powerpc_so_ops);
set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
}
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
set_solib_svr4_fetch_link_map_offsets
- (gdbarch, svr4_lp64_fetch_link_map_offsets);
+ (gdbarch, linux_lp64_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC64);
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpcle");
else
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
+ /* Set compiler triplet. */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+ set_gdbarch_gnu_triplet_regexp (gdbarch, ppc64le_gnu_triplet_regexp);
+ else
+ set_gdbarch_gnu_triplet_regexp (gdbarch, ppc64_gnu_triplet_regexp);
+ /* Set GCC target options. */
+ set_gdbarch_gcc_target_options (gdbarch, ppc64_linux_gcc_target_options);
}
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
- svr4_fetch_objfile_link_map);
+ svr4_fetch_objfile_link_map);
if (tdesc_data)
{
const struct tdesc_feature *feature;
/* If we have target-described registers, then we can safely
- reserve a number for PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM
+ reserve a number for PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM
(whether they are described or not). */
gdb_assert (gdbarch_num_regs (gdbarch) <= PPC_ORIG_R3_REGNUM);
set_gdbarch_num_regs (gdbarch, PPC_TRAP_REGNUM + 1);
/* If they are present, then assign them to the reserved number. */
feature = tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.linux");
+ "org.gnu.gdb.power.linux");
if (feature != NULL)
{
tdesc_numbered_register (feature, tdesc_data,
}
}
- set_gdbarch_displaced_step_location (gdbarch,
- linux_displaced_step_location);
-
/* Support reverse debugging. */
set_gdbarch_process_record (gdbarch, ppc_process_record);
set_gdbarch_process_record_signal (gdbarch, ppc_linux_record_signal);
ppc_init_linux_record_tdep (&ppc_linux_record_tdep, 4);
ppc_init_linux_record_tdep (&ppc64_linux_record_tdep, 8);
+
+ /* Setup displaced stepping. */
+ set_gdbarch_displaced_step_prepare (gdbarch,
+ ppc_linux_displaced_step_prepare);
+
}
+void _initialize_ppc_linux_tdep ();
void
-_initialize_ppc_linux_tdep (void)
+_initialize_ppc_linux_tdep ()
{
/* Register for all sub-families of the POWER/PowerPC: 32-bit and
64-bit PowerPC, and the older rs6k. */
gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_LINUX,
- ppc_linux_init_abi);
+ ppc_linux_init_abi);
gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64, GDB_OSABI_LINUX,
- ppc_linux_init_abi);
+ ppc_linux_init_abi);
gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
- ppc_linux_init_abi);
+ ppc_linux_init_abi);
/* Initialize the Linux target descriptions. */
initialize_tdesc_powerpc_32l ();