Implement SystemTap SDT probe support for AArch64
authorSergio Durigan Junior <sergiodj@redhat.com>
Sat, 28 Dec 2013 16:14:11 +0000 (14:14 -0200)
committerSergio Durigan Junior <sergiodj@redhat.com>
Sat, 28 Dec 2013 16:14:11 +0000 (14:14 -0200)
This commit implements the needed bits for SystemTap SDT probe support
on AArch64 architectures.

First, I started by looking at AArch64 assembly specification and
filling the necessary options on gdbarch's stap machinery in order to
make the generic asm parser (implemented in stap-probe.c) recognize
AArch64's asm.

After my last patch for the SystemTap SDT API, which extends it in order
to accept multiple prefixes and suffixes, this patch became simpler.  I
also followed Marcus suggestion and did not shared code between 32- and
64-bit ARM.

Tom asked me in a previous message how I did my tests.  I believe I
replied that, but just in case: I ran the tests on
gdb.base/stap-probe.exp by hand.  I also managed to run the tests on
real hardware, and they pass without regressions.

2013-12-28  Sergio Durigan Junior  <sergiodj@redhat.com>

PR tdep/15653
* NEWS: Mention SystemTap SDT probe support for AArch64 GNU/Linux.
* aarch64-linux-tdep.c: Include necessary headers for parsing of
SystemTap SDT probes.
(aarch64_stap_is_single_operand): New function.
(aarch64_stap_parse_special_token): Likewise.
(aarch64_linux_init_abi): Declare SystemTap SDT probe argument
prefixes and suffixes.  Initialize gdbarch with them.

gdb/ChangeLog
gdb/NEWS
gdb/aarch64-linux-tdep.c

index 87701b409ef42ce05f7b7d344bfc873486015f7d..c6f37e5f68a8985ccb5d43ffd7cf25e8f34a7235 100644 (file)
@@ -1,3 +1,14 @@
+2013-12-28  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       PR tdep/15653
+       * NEWS: Mention SystemTap SDT probe support for AArch64 GNU/Linux.
+       * aarch64-linux-tdep.c: Include necessary headers for parsing of
+       SystemTap SDT probes.
+       (aarch64_stap_is_single_operand): New function.
+       (aarch64_stap_parse_special_token): Likewise.
+       (aarch64_linux_init_abi): Declare SystemTap SDT probe argument
+       prefixes and suffixes.  Initialize gdbarch with them.
+
 2013-12-23  Sterling Augustine  <saugustine@google.com>
 
        * linespec.c (add_sal_to_sals): Use "<unknown>" when a symbol
index e4baf503dfda00487244e11b2b6b0dfc6218a44d..b64967eaedb4bcc520364b357c5a797c1698b2d0 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,8 @@
 
 *** Changes since GDB 7.6
 
+* GDB now supports SystemTap SDT probes on AArch64 GNU/Linux.
+
 * GDB now supports Fission DWP file format version 2.
   http://gcc.gnu.org/wiki/DebugFission
 
index bcfcce254f010ef953c9e9f53b0a9a17e8244bbd..52c5d97e92001ef7e5770a9d9bb0c1a03a6325f7 100644 (file)
 #include "regcache.h"
 #include "regset.h"
 
+#include "cli/cli-utils.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
 /* The general-purpose regset consists of 31 X registers, plus SP, PC,
    and PSTATE registers, as defined in the AArch64 port of the Linux
    kernel.  */
@@ -263,9 +269,129 @@ aarch64_linux_regset_from_core_section (struct gdbarch *gdbarch,
   return NULL;
 }
 
+/* Implementation of `gdbarch_stap_is_single_operand', as defined in
+   gdbarch.h.  */
+
+static int
+aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+  return (*s == '#' || isdigit (*s) /* Literal number.  */
+         || *s == '[' /* Register indirection.  */
+         || isalpha (*s)); /* Register value.  */
+}
+
+/* This routine is used to parse a special token in AArch64's assembly.
+
+   The special tokens parsed by it are:
+
+      - Register displacement (e.g, [fp, #-8])
+
+   It returns one if the special token has been parsed successfully,
+   or zero if the current token is not considered special.  */
+
+static int
+aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
+                                 struct stap_parse_info *p)
+{
+  if (*p->arg == '[')
+    {
+      /* Temporary holder for lookahead.  */
+      const char *tmp = p->arg;
+      char *endp;
+      /* Used to save the register name.  */
+      const char *start;
+      char *regname;
+      int len;
+      int got_minus = 0;
+      long displacement;
+      struct stoken str;
+
+      ++tmp;
+      start = tmp;
+
+      /* Register name.  */
+      while (isalnum (*tmp))
+       ++tmp;
+
+      if (*tmp != ',')
+       return 0;
+
+      len = tmp - start;
+      regname = alloca (len + 2);
+
+      strncpy (regname, start, len);
+      regname[len] = '\0';
+
+      if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+       error (_("Invalid register name `%s' on expression `%s'."),
+              regname, p->saved_arg);
+
+      ++tmp;
+      tmp = skip_spaces_const (tmp);
+      /* Now we expect a number.  It can begin with '#' or simply
+        a digit.  */
+      if (*tmp == '#')
+       ++tmp;
+
+      if (*tmp == '-')
+       {
+         ++tmp;
+         got_minus = 1;
+       }
+      else if (*tmp == '+')
+       ++tmp;
+
+      if (!isdigit (*tmp))
+       return 0;
+
+      displacement = strtol (tmp, &endp, 10);
+      tmp = endp;
+
+      /* Skipping last `]'.  */
+      if (*tmp++ != ']')
+       return 0;
+
+      /* The displacement.  */
+      write_exp_elt_opcode (OP_LONG);
+      write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+      write_exp_elt_longcst (displacement);
+      write_exp_elt_opcode (OP_LONG);
+      if (got_minus)
+       write_exp_elt_opcode (UNOP_NEG);
+
+      /* The register name.  */
+      write_exp_elt_opcode (OP_REGISTER);
+      str.ptr = regname;
+      str.length = len;
+      write_exp_string (str);
+      write_exp_elt_opcode (OP_REGISTER);
+
+      write_exp_elt_opcode (BINOP_ADD);
+
+      /* Casting to the expected type.  */
+      write_exp_elt_opcode (UNOP_CAST);
+      write_exp_elt_type (lookup_pointer_type (p->arg_type));
+      write_exp_elt_opcode (UNOP_CAST);
+
+      write_exp_elt_opcode (UNOP_IND);
+
+      p->arg = tmp;
+    }
+  else
+    return 0;
+
+  return 1;
+}
+
 static void
 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
+  static const char *const stap_integer_prefixes[] = { "#", "", NULL };
+  static const char *const stap_register_prefixes[] = { "", NULL };
+  static const char *const stap_register_indirection_prefixes[] = { "[",
+                                                                   NULL };
+  static const char *const stap_register_indirection_suffixes[] = { "]",
+                                                                   NULL };
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   tdep->lowest_pc = 0x8000;
@@ -290,6 +416,17 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   set_gdbarch_regset_from_core_section (gdbarch,
                                        aarch64_linux_regset_from_core_section);
+
+  /* SystemTap related.  */
+  set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
+  set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
+  set_gdbarch_stap_register_indirection_prefixes (gdbarch,
+                                           stap_register_indirection_prefixes);
+  set_gdbarch_stap_register_indirection_suffixes (gdbarch,
+                                           stap_register_indirection_suffixes);
+  set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand);
+  set_gdbarch_stap_parse_special_token (gdbarch,
+                                       aarch64_stap_parse_special_token);
 }
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */