gdb/aarch64-linux-tdep.c - gdb

Global variables defined

Functions defined

Macros defined

Source code

  1. /* Target-dependent code for GNU/Linux AArch64.

  2.    Copyright (C) 2009-2015 Free Software Foundation, Inc.
  3.    Contributed by ARM Ltd.

  4.    This file is part of GDB.

  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 3 of the License, or
  8.    (at your option) any later version.

  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.

  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  15. #include "defs.h"

  16. #include "gdbarch.h"
  17. #include "glibc-tdep.h"
  18. #include "linux-tdep.h"
  19. #include "aarch64-tdep.h"
  20. #include "aarch64-linux-tdep.h"
  21. #include "osabi.h"
  22. #include "solib-svr4.h"
  23. #include "symtab.h"
  24. #include "tramp-frame.h"
  25. #include "trad-frame.h"

  26. #include "inferior.h"
  27. #include "regcache.h"
  28. #include "regset.h"

  29. #include "cli/cli-utils.h"
  30. #include "stap-probe.h"
  31. #include "parser-defs.h"
  32. #include "user-regs.h"
  33. #include <ctype.h>

  34. /* Signal frame handling.

  35.       +------------+  ^
  36.       | saved lr   |  |
  37.    +->| saved fp   |--+
  38.    |  |            |
  39.    |  |            |
  40.    |  +------------+
  41.    |  | saved lr   |
  42.    +--| saved fp   |
  43.    ^  |            |
  44.    |  |            |
  45.    |  +------------+
  46.    ^  |            |
  47.    |  | signal     |
  48.    |  |            |        SIGTRAMP_FRAME (struct rt_sigframe)
  49.    |  | saved regs |
  50.    +--| saved sp   |--> interrupted_sp
  51.    |  | saved pc   |--> interrupted_pc
  52.    |  |            |
  53.    |  +------------+
  54.    |  | saved lr   |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
  55.    +--| saved fp   |<- FP
  56.       |            |         NORMAL_FRAME
  57.       |            |<- SP
  58.       +------------+

  59.   On signal delivery, the kernel will create a signal handler stack
  60.   frame and setup the return address in LR to point at restorer stub.
  61.   The signal stack frame is defined by:

  62.   struct rt_sigframe
  63.   {
  64.     siginfo_t info;
  65.     struct ucontext uc;
  66.   };

  67.   typedef struct
  68.   {
  69.     ...                                    128 bytes
  70.   } siginfo_t;

  71.   The ucontext has the following form:
  72.   struct ucontext
  73.   {
  74.     unsigned long uc_flags;
  75.     struct ucontext *uc_link;
  76.     stack_t uc_stack;
  77.     sigset_t uc_sigmask;
  78.     struct sigcontext uc_mcontext;
  79.   };

  80.   typedef struct sigaltstack
  81.   {
  82.     void *ss_sp;
  83.     int ss_flags;
  84.     size_t ss_size;
  85.   } stack_t;

  86.   struct sigcontext
  87.   {
  88.     unsigned long fault_address;
  89.     unsigned long regs[31];
  90.     unsigned long sp;                / * 31 * /
  91.     unsigned long pc;                / * 32 * /
  92.     unsigned long pstate;        / * 33 * /
  93.     __u8 __reserved[4096]
  94.   };

  95.   The restorer stub will always have the form:

  96.   d28015a8        movz    x8, #0xad
  97.   d4000001        svc     #0x0

  98.   This is a system call sys_rt_sigreturn.

  99.   We detect signal frames by snooping the return code for the restorer
  100.   instruction sequence.

  101.   The handler then needs to recover the saved register set from
  102.   ucontext.uc_mcontext.  */

  103. /* These magic numbers need to reflect the layout of the kernel
  104.    defined struct rt_sigframe and ucontext.  */
  105. #define AARCH64_SIGCONTEXT_REG_SIZE             8
  106. #define AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET     128
  107. #define AARCH64_UCONTEXT_SIGCONTEXT_OFFSET      176
  108. #define AARCH64_SIGCONTEXT_XO_OFFSET            8

  109. /* Implement the "init" method of struct tramp_frame.  */

  110. static void
  111. aarch64_linux_sigframe_init (const struct tramp_frame *self,
  112.                              struct frame_info *this_frame,
  113.                              struct trad_frame_cache *this_cache,
  114.                              CORE_ADDR func)
  115. {
  116.   struct gdbarch *gdbarch = get_frame_arch (this_frame);
  117.   CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
  118.   CORE_ADDR sigcontext_addr =
  119.     sp
  120.     + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
  121.     + AARCH64_UCONTEXT_SIGCONTEXT_OFFSET;
  122.   int i;

  123.   for (i = 0; i < 31; i++)
  124.     {
  125.       trad_frame_set_reg_addr (this_cache,
  126.                                AARCH64_X0_REGNUM + i,
  127.                                sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
  128.                                + i * AARCH64_SIGCONTEXT_REG_SIZE);
  129.     }
  130.   trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
  131.                            sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
  132.                              + 31 * AARCH64_SIGCONTEXT_REG_SIZE);
  133.   trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
  134.                            sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
  135.                              + 32 * AARCH64_SIGCONTEXT_REG_SIZE);

  136.   trad_frame_set_id (this_cache, frame_id_build (sp, func));
  137. }

  138. static const struct tramp_frame aarch64_linux_rt_sigframe =
  139. {
  140.   SIGTRAMP_FRAME,
  141.   4,
  142.   {
  143.     /* movz x8, 0x8b (S=1,o=10,h=0,i=0x8b,r=8)
  144.        Soo1 0010 1hhi iiii iiii iiii iiir rrrr  */
  145.     {0xd2801168, -1},

  146.     /* svc  0x0      (o=0, l=1)
  147.        1101 0100 oooi iiii iiii iiii iii0 00ll  */
  148.     {0xd4000001, -1},
  149.     {TRAMP_SENTINEL_INSN, -1}
  150.   },
  151.   aarch64_linux_sigframe_init
  152. };

  153. /* Register maps.  */

  154. static const struct regcache_map_entry aarch64_linux_gregmap[] =
  155.   {
  156.     { 31, AARCH64_X0_REGNUM, 8 }, /* x0 ... x30 */
  157.     { 1, AARCH64_SP_REGNUM, 8 },
  158.     { 1, AARCH64_PC_REGNUM, 8 },
  159.     { 1, AARCH64_CPSR_REGNUM, 8 },
  160.     { 0 }
  161.   };

  162. static const struct regcache_map_entry aarch64_linux_fpregmap[] =
  163.   {
  164.     { 32, AARCH64_V0_REGNUM, 16 }, /* v0 ... v31 */
  165.     { 1, AARCH64_FPSR_REGNUM, 4 },
  166.     { 1, AARCH64_FPCR_REGNUM, 4 },
  167.     { 0 }
  168.   };

  169. /* Register set definitions.  */

  170. const struct regset aarch64_linux_gregset =
  171.   {
  172.     aarch64_linux_gregmap,
  173.     regcache_supply_regset, regcache_collect_regset
  174.   };

  175. const struct regset aarch64_linux_fpregset =
  176.   {
  177.     aarch64_linux_fpregmap,
  178.     regcache_supply_regset, regcache_collect_regset
  179.   };

  180. /* Implement the "regset_from_core_section" gdbarch method.  */

  181. static void
  182. aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
  183.                                             iterate_over_regset_sections_cb *cb,
  184.                                             void *cb_data,
  185.                                             const struct regcache *regcache)
  186. {
  187.   cb (".reg", AARCH64_LINUX_SIZEOF_GREGSET, &aarch64_linux_gregset,
  188.       NULL, cb_data);
  189.   cb (".reg2", AARCH64_LINUX_SIZEOF_FPREGSET, &aarch64_linux_fpregset,
  190.       NULL, cb_data);
  191. }

  192. /* Implementation of `gdbarch_stap_is_single_operand', as defined in
  193.    gdbarch.h.  */

  194. static int
  195. aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
  196. {
  197.   return (*s == '#' || isdigit (*s) /* Literal number.  */
  198.           || *s == '[' /* Register indirection.  */
  199.           || isalpha (*s)); /* Register value.  */
  200. }

  201. /* This routine is used to parse a special token in AArch64's assembly.

  202.    The special tokens parsed by it are:

  203.       - Register displacement (e.g, [fp, #-8])

  204.    It returns one if the special token has been parsed successfully,
  205.    or zero if the current token is not considered special.  */

  206. static int
  207. aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
  208.                                   struct stap_parse_info *p)
  209. {
  210.   if (*p->arg == '[')
  211.     {
  212.       /* Temporary holder for lookahead.  */
  213.       const char *tmp = p->arg;
  214.       char *endp;
  215.       /* Used to save the register name.  */
  216.       const char *start;
  217.       char *regname;
  218.       int len;
  219.       int got_minus = 0;
  220.       long displacement;
  221.       struct stoken str;

  222.       ++tmp;
  223.       start = tmp;

  224.       /* Register name.  */
  225.       while (isalnum (*tmp))
  226.         ++tmp;

  227.       if (*tmp != ',')
  228.         return 0;

  229.       len = tmp - start;
  230.       regname = alloca (len + 2);

  231.       strncpy (regname, start, len);
  232.       regname[len] = '\0';

  233.       if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
  234.         error (_("Invalid register name `%s' on expression `%s'."),
  235.                regname, p->saved_arg);

  236.       ++tmp;
  237.       tmp = skip_spaces_const (tmp);
  238.       /* Now we expect a number.  It can begin with '#' or simply
  239.          a digit.  */
  240.       if (*tmp == '#')
  241.         ++tmp;

  242.       if (*tmp == '-')
  243.         {
  244.           ++tmp;
  245.           got_minus = 1;
  246.         }
  247.       else if (*tmp == '+')
  248.         ++tmp;

  249.       if (!isdigit (*tmp))
  250.         return 0;

  251.       displacement = strtol (tmp, &endp, 10);
  252.       tmp = endp;

  253.       /* Skipping last `]'.  */
  254.       if (*tmp++ != ']')
  255.         return 0;

  256.       /* The displacement.  */
  257.       write_exp_elt_opcode (&p->pstate, OP_LONG);
  258.       write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
  259.       write_exp_elt_longcst (&p->pstate, displacement);
  260.       write_exp_elt_opcode (&p->pstate, OP_LONG);
  261.       if (got_minus)
  262.         write_exp_elt_opcode (&p->pstate, UNOP_NEG);

  263.       /* The register name.  */
  264.       write_exp_elt_opcode (&p->pstate, OP_REGISTER);
  265.       str.ptr = regname;
  266.       str.length = len;
  267.       write_exp_string (&p->pstate, str);
  268.       write_exp_elt_opcode (&p->pstate, OP_REGISTER);

  269.       write_exp_elt_opcode (&p->pstate, BINOP_ADD);

  270.       /* Casting to the expected type.  */
  271.       write_exp_elt_opcode (&p->pstate, UNOP_CAST);
  272.       write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
  273.       write_exp_elt_opcode (&p->pstate, UNOP_CAST);

  274.       write_exp_elt_opcode (&p->pstate, UNOP_IND);

  275.       p->arg = tmp;
  276.     }
  277.   else
  278.     return 0;

  279.   return 1;
  280. }

  281. static void
  282. aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
  283. {
  284.   static const char *const stap_integer_prefixes[] = { "#", "", NULL };
  285.   static const char *const stap_register_prefixes[] = { "", NULL };
  286.   static const char *const stap_register_indirection_prefixes[] = { "[",
  287.                                                                     NULL };
  288.   static const char *const stap_register_indirection_suffixes[] = { "]",
  289.                                                                     NULL };
  290.   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

  291.   tdep->lowest_pc = 0x8000;

  292.   linux_init_abi (info, gdbarch);

  293.   set_solib_svr4_fetch_link_map_offsets (gdbarch,
  294.                                          svr4_lp64_fetch_link_map_offsets);

  295.   /* Enable TLS support.  */
  296.   set_gdbarch_fetch_tls_load_module_address (gdbarch,
  297.                                              svr4_fetch_objfile_link_map);

  298.   /* Shared library handling.  */
  299.   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);

  300.   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
  301.   tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);

  302.   /* Enable longjmp.  */
  303.   tdep->jb_pc = 11;

  304.   set_gdbarch_iterate_over_regset_sections
  305.     (gdbarch, aarch64_linux_iterate_over_regset_sections);

  306.   /* SystemTap related.  */
  307.   set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
  308.   set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
  309.   set_gdbarch_stap_register_indirection_prefixes (gdbarch,
  310.                                             stap_register_indirection_prefixes);
  311.   set_gdbarch_stap_register_indirection_suffixes (gdbarch,
  312.                                             stap_register_indirection_suffixes);
  313.   set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand);
  314.   set_gdbarch_stap_parse_special_token (gdbarch,
  315.                                         aarch64_stap_parse_special_token);
  316. }

  317. /* Provide a prototype to silence -Wmissing-prototypes.  */
  318. extern initialize_file_ftype _initialize_aarch64_linux_tdep;

  319. void
  320. _initialize_aarch64_linux_tdep (void)
  321. {
  322.   gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
  323.                           aarch64_linux_init_abi);
  324. }