From 1ae3db1961c057cfb1455827b7bc8f930f583c24 Mon Sep 17 00:00:00 2001 From: Marcus Shawcroft Date: Mon, 4 Feb 2013 12:53:59 +0000 Subject: Adding aarch64-linux-tdep support. 2013-02-04 Jim MacArthur Marcus Shawcroft Nigel Stephens Yufeng Zhang * Makefile.in (ALL_64_TARGET_OBS): Add aarch64-linux-tdep.o. (ALLDEPFILES): Add aarch64-linux-tdep.c. * aarch64-linux-tdep.c: New file. * aarch64-linux-tdep.h: New file. * aarch64-tdep.h (gdbarch_tdep): Define gregset and fpregset. * configure.tgt: Add aarch64-none-linux-gnu. --- gdb/ChangeLog | 12 ++ gdb/Makefile.in | 4 +- gdb/aarch64-linux-tdep.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++ gdb/aarch64-linux-tdep.h | 26 +++++ gdb/aarch64-tdep.h | 4 + gdb/configure.tgt | 6 + 6 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 gdb/aarch64-linux-tdep.c create mode 100644 gdb/aarch64-linux-tdep.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 05dc1da..032ac1d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -3,6 +3,18 @@ Nigel Stephens Yufeng Zhang + * Makefile.in (ALL_64_TARGET_OBS): Add aarch64-linux-tdep.o. + (ALLDEPFILES): Add aarch64-linux-tdep.c. + * aarch64-linux-tdep.c: New file. + * aarch64-linux-tdep.h: New file. + * aarch64-tdep.h (gdbarch_tdep): Define gregset and fpregset. + * configure.tgt: Add aarch64-none-linux-gnu. + +2013-02-04 Jim MacArthur + Marcus Shawcroft + Nigel Stephens + Yufeng Zhang + * Makefile.in (ALL_64_TARGET_OBS): Add arch64-tdep.o. (HFILES_NO_SRCDIR): Add aarch64-tdep.h. (ALLDEPFILES): Add aarch64-tdep.c. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index bbe210e..2a0e4ac 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -521,7 +521,7 @@ TARGET_OBS = @TARGET_OBS@ # All target-dependent objects files that require 64-bit CORE_ADDR # (used with --enable-targets=all --enable-64-bit-bfd). ALL_64_TARGET_OBS = \ - aarch64-tdep.o \ + aarch64-tdep.o aarch64-linux-tdep.o \ alphabsd-tdep.o alphafbsd-tdep.o alpha-linux-tdep.o alpha-mdebug-tdep.o \ alphanbsd-tdep.o alphaobsd-tdep.o alpha-osf1-tdep.o alpha-tdep.o \ amd64fbsd-tdep.o amd64-darwin-tdep.o amd64-dicos-tdep.o \ @@ -1421,7 +1421,7 @@ force_update: MAKEOVERRIDES= ALLDEPFILES = \ - aarch64-tdep.c \ + aarch64-tdep.c aarch64-linux-tdep.c \ aix-thread.c \ alpha-nat.c alphabsd-nat.c alpha-linux-nat.c \ alpha-tdep.c alpha-mdebug-tdep.c \ diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c new file mode 100644 index 0000000..1622a43 --- /dev/null +++ b/gdb/aarch64-linux-tdep.c @@ -0,0 +1,297 @@ +/* Target-dependent code for GNU/Linux AArch64. + + Copyright (C) 2009-2013 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + 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 . */ + +#include "defs.h" + +#include "gdbarch.h" +#include "glibc-tdep.h" +#include "linux-tdep.h" +#include "aarch64-tdep.h" +#include "aarch64-linux-tdep.h" +#include "osabi.h" +#include "solib-svr4.h" +#include "symtab.h" +#include "tramp-frame.h" +#include "trad-frame.h" + +#include "inferior.h" +#include "regcache.h" +#include "regset.h" + +/* The general-purpose regset consists of 31 X registers, plus SP, PC, + PSTATE and two extra pseudo 64-bit registers, as defined in the + AArch64 port of the Linux kernel. */ +#define AARCH64_LINUX_SIZEOF_GREGSET (36 * X_REGISTER_SIZE) + +/* The fp regset consists of 32 V registers, plus FPCR and FPSR which + are 4 bytes wide each, and the whole structure is padded to 128 bit + alignment. */ +#define AARCH64_LINUX_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE) + +/* Signal frame handling. + + +----------+ ^ + | saved lr | | + +->| saved fp |--+ + | | | + | | | + | +----------+ + | | saved lr | + +--| saved fp | + ^ | | + | | | + | +----------+ + ^ | | + | | signal | + | | | + | | saved lr |-->interrupted_function_pc + +--| saved fp | + | +----------+ + | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0) + +--| saved fp |<- FP + | | + | |<- SP + +----------+ + + On signal delivery, the kernel will create a signal handler stack + frame and setup the return address in LR to point at restorer stub. + The signal stack frame is defined by: + + struct rt_sigframe + { + siginfo_t info; + struct ucontext uc; + }; + + typedef struct + { + ... 128 bytes + } siginfo_t; + + The ucontext has the following form: + struct ucontext + { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + sigset_t uc_sigmask; + struct sigcontext uc_mcontext; + }; + + typedef struct sigaltstack + { + void *ss_sp; + int ss_flags; + size_t ss_size; + } stack_t; + + struct sigcontext + { + unsigned long fault_address; + unsigned long regs[31]; + unsigned long sp; / * 31 * / + unsigned long pc; / * 32 * / + unsigned long pstate; / * 33 * / + __u8 __reserved[4096] + }; + + The restorer stub will always have the form: + + d28015a8 movz x8, #0xad + d4000001 svc #0x0 + + We detect signal frames by snooping the return code for the restorer + instruction sequence. + + The handler then needs to recover the saved register set from + ucontext.uc_mcontext. */ + +/* These magic numbers need to reflect the layout of the kernel + defined struct rt_sigframe and ucontext. */ +#define AARCH64_SIGCONTEXT_REG_SIZE 8 +#define AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET 128 +#define AARCH64_UCONTEXT_SIGCONTEXT_OFFSET 176 +#define AARCH64_SIGCONTEXT_XO_OFFSET 8 + +/* Implement the "init" method of struct tramp_frame. */ + +static void +aarch64_linux_sigframe_init (const struct tramp_frame *self, + struct frame_info *this_frame, + struct trad_frame_cache *this_cache, + CORE_ADDR func) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM); + CORE_ADDR fp = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM); + CORE_ADDR sigcontext_addr = + sp + + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET + + AARCH64_UCONTEXT_SIGCONTEXT_OFFSET; + int i; + + for (i = 0; i < 31; i++) + { + trad_frame_set_reg_addr (this_cache, + AARCH64_X0_REGNUM + i, + sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + + i * AARCH64_SIGCONTEXT_REG_SIZE); + } + + trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp); + trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8); + trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8); + + trad_frame_set_id (this_cache, frame_id_build (fp, func)); +} + +static const struct tramp_frame aarch64_linux_rt_sigframe = +{ + SIGTRAMP_FRAME, + 4, + { + /* movz x8, 0x8b (S=1,o=10,h=0,i=0x8b,r=8) + Soo1 0010 1hhi iiii iiii iiii iiir rrrr */ + {0xd2801168, -1}, + + /* svc 0x0 (o=0, l=1) + 1101 0100 oooi iiii iiii iiii iii0 00ll */ + {0xd4000001, -1}, + {TRAMP_SENTINEL_INSN, -1} + }, + aarch64_linux_sigframe_init +}; + +/* Fill GDB's register array with the general-purpose register values + in the buffer pointed by GREGS_BUF. */ + +void +aarch64_linux_supply_gregset (struct regcache *regcache, + const gdb_byte *gregs_buf) +{ + int regno; + + for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++) + regcache_raw_supply (regcache, regno, + gregs_buf + X_REGISTER_SIZE + * (regno - AARCH64_X0_REGNUM)); +} + +/* The "supply_regset" function for the general-purpose register set. */ + +static void +supply_gregset_from_core (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *regbuf, size_t len) +{ + aarch64_linux_supply_gregset (regcache, (const gdb_byte *) regbuf); +} + +/* Fill GDB's register array with the floating-point register values + in the buffer pointed by FPREGS_BUF. */ + +void +aarch64_linux_supply_fpregset (struct regcache *regcache, + const gdb_byte *fpregs_buf) +{ + int regno; + + for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++) + regcache_raw_supply (regcache, regno, + fpregs_buf + V_REGISTER_SIZE + * (regno - AARCH64_V0_REGNUM)); + + regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM, + fpregs_buf + V_REGISTER_SIZE * 32); + regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM, + fpregs_buf + V_REGISTER_SIZE * 32 + 4); +} + +/* The "supply_regset" function for the floating-point register set. */ + +static void +supply_fpregset_from_core (const struct regset *regset, + struct regcache *regcache, + int regnum, const void *regbuf, size_t len) +{ + aarch64_linux_supply_fpregset (regcache, (const gdb_byte *) regbuf); +} + +/* Implement the "regset_from_core_section" gdbarch method. */ + +static const struct regset * +aarch64_linux_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, + size_t sect_size) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (strcmp (sect_name, ".reg") == 0 + && sect_size == AARCH64_LINUX_SIZEOF_GREGSET) + { + if (tdep->gregset == NULL) + tdep->gregset = regset_alloc (gdbarch, supply_gregset_from_core, + NULL); + return tdep->gregset; + } + + if (strcmp (sect_name, ".reg2") == 0 + && sect_size == AARCH64_LINUX_SIZEOF_FPREGSET) + { + if (tdep->fpregset == NULL) + tdep->fpregset = regset_alloc (gdbarch, supply_fpregset_from_core, + NULL); + return tdep->fpregset; + } + return NULL; +} + +static void +aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->lowest_pc = 0x8000; + + set_solib_svr4_fetch_link_map_offsets (gdbarch, + svr4_lp64_fetch_link_map_offsets); + + /* Shared library handling. */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); + tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe); + + /* Enable longjmp. */ + tdep->jb_pc = 11; + + set_gdbarch_regset_from_core_section (gdbarch, + aarch64_linux_regset_from_core_section); +} + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern initialize_file_ftype _initialize_aarch64_linux_tdep; + +void +_initialize_aarch64_linux_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX, + aarch64_linux_init_abi); +} diff --git a/gdb/aarch64-linux-tdep.h b/gdb/aarch64-linux-tdep.h new file mode 100644 index 0000000..b1c3646 --- /dev/null +++ b/gdb/aarch64-linux-tdep.h @@ -0,0 +1,26 @@ +/* GNU/Linux on AArch64 target support, prototypes. + + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by ARM Ltd. + + 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 . */ + +struct regcache; + +extern void aarch64_linux_supply_gregset (struct regcache *regcache, + const gdb_byte *gregs_buf); +extern void aarch64_linux_supply_fpregset (struct regcache *regcache, + const gdb_byte *fpregs_buf); diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index a2f3e36..0de3ba6 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -82,6 +82,10 @@ struct gdbarch_tdep /* And the size of each entry in the buf. */ size_t jb_elt_size; + /* Cached core file helpers. */ + struct regset *gregset; + struct regset *fpregset; + /* Types for AdvSISD registers. */ struct type *vnq_type; struct type *vnd_type; diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 0b479b1..92514ff 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -36,6 +36,12 @@ aarch64*-*-elf) gdb_target_obs="aarch64-tdep.o" ;; +aarch64*-*-linux*) + # Target: AArch64 linux + gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o \ + glibc-tdep.o linux-tdep.o solib-svr4.o \ + symfile-mem.o" + ;; alpha*-*-osf*) # Target: Little-endian Alpha running OSF/1 -- cgit v1.1