This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Improve readability of x86's SystemTap SDT probe support & fix bug & add testcase
- From: Sergio Durigan Junior <sergiodj at redhat dot com>
- To: GDB Patches <gdb-patches at sourceware dot org>
- Date: Fri, 27 Dec 2013 02:26:45 -0200
- Subject: [PATCH] Improve readability of x86's SystemTap SDT probe support & fix bug & add testcase
- Authentication-results: sourceware.org; auth=none
Hi,
This patch reorganizes code on gdb/i386-tdep.c's SystemTap SDT probe
support functions. Before it, the code to parse special operands on x86
lived in a single, big function. This patch creates 2 new functions
that makes the code more organized and removes a few indentation levels
(which is always good IMO).
While I was making the patch, I decided to create some testcases for it
(by tweaking the probe's asm generated by GCC), and found a bug on the
parsing code for the triplet displacement operand (i.e., things like
"-4+8-20(%rbp)"). Well, since I was already at it, I created some
testcases for the two kinds of special operands handled by the code (the
triplet displacement mentioned above, and the three-argument
displacement like "(%rbx,%ebx,-8)"). This code is target-dependent so I
created it under gdb.arch/.
Comments? OK to apply?
Thanks,
--
Sergio
gdb/ChangeLog
2013-12-27 Sergio Durigan Junior <sergiodj@redhat.com>
* i386-tdep.c (i386_stap_parse_special_token_triplet): New
function, with code from i386_stap_parse_special_token. Fix bug
with the parsing of triplet displacement.
(i386_stap_parse_special_token_three_arg_disp): New function, with
code from i386_stap_parse_special_token.
(i386_stap_parse_special_token): Move code to the two functions
created above.
gdb/testsuite/ChangeLog
2013-12-27 Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.arch/amd64-stap-special-operands.exp: New file.
* gdb.arch/amd64-stap-three-arg-disp.S: Likewise.
* gdb.arch/amd64-stap-three-arg-disp.c: Likewise.
* gdb.arch/amd64-stap-triplet.S: Likewise.
* gdb.arch/amd64-stap-triplet.c: Likewise.
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 4f86f0c..a4f5dbe 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -3605,311 +3605,334 @@ i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
|| (*s == '%' && isalpha (s[1]))); /* Register access. */
}
-/* Implementation of `gdbarch_stap_parse_special_token', as defined in
- gdbarch.h. */
+/* Helper function for i386_stap_parse_special_token.
-int
-i386_stap_parse_special_token (struct gdbarch *gdbarch,
- struct stap_parse_info *p)
+ This function parses operands of the form `-8+3+1(%rbp)', which
+ must be interpreted as `*(-8 + 3 - 1 + (void *) $eax)'.
+
+ Return 1 if the operand was parsed successfully, zero
+ otherwise. */
+
+static int
+i386_stap_parse_special_token_triplet (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
{
- /* In order to parse special tokens, we use a state-machine that go
- through every known token and try to get a match. */
- enum
+ int got_minus[3];
+ int i;
+ LONGEST displacements[3];
+ const char *start;
+ char *regname;
+ int len;
+ struct stoken str;
+ char *endp;
+ const char *s = p->arg;
+
+ /* If we are not dealing with a digit, then just return 0. */
+ if (!isdigit (*s) && *s != '-' && *s != '+')
+ return 0;
+
+ got_minus[0] = 0;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
{
- TRIPLET,
- THREE_ARG_DISPLACEMENT,
- DONE
- } current_state;
+ ++s;
+ got_minus[0] = 1;
+ }
- current_state = TRIPLET;
+ if (!isdigit (*s))
+ return 0;
- /* The special tokens to be parsed here are:
+ displacements[0] = strtol (s, &endp, 10);
+ s = endp;
- - `register base + (register index * size) + offset', as represented
- in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
+ if (*s != '+' && *s != '-')
+ {
+ /* We are not dealing with a triplet. */
+ return 0;
+ }
- - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
- `*(-8 + 3 - 1 + (void *) $eax)'. */
+ got_minus[1] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[1] = 1;
+ }
- while (current_state != DONE)
+ displacements[1] = strtol (s, &endp, 10);
+ s = endp;
+
+ if (*s != '+' && *s != '-')
{
- const char *s = p->arg;
+ /* We are not dealing with a triplet. */
+ return 0;
+ }
- switch (current_state)
- {
- case TRIPLET:
- {
- if (isdigit (*s) || *s == '-' || *s == '+')
- {
- int got_minus[3];
- int i;
- long displacements[3];
- const char *start;
- char *regname;
- int len;
- struct stoken str;
- char *endp;
-
- got_minus[0] = 0;
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- got_minus[0] = 1;
- }
+ got_minus[2] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[2] = 1;
+ }
- displacements[0] = strtol (s, &endp, 10);
- s = endp;
+ displacements[2] = strtol (s, &endp, 10);
+ s = endp;
- if (*s != '+' && *s != '-')
- {
- /* We are not dealing with a triplet. */
- break;
- }
+ if (*s != '(' || s[1] != '%')
+ return 0;
- got_minus[1] = 0;
- if (*s == '+')
- ++s;
- else
- {
- ++s;
- got_minus[1] = 1;
- }
+ s += 2;
+ start = s;
- displacements[1] = strtol (s, &endp, 10);
- s = endp;
+ while (isalnum (*s))
+ ++s;
- if (*s != '+' && *s != '-')
- {
- /* We are not dealing with a triplet. */
- break;
- }
+ if (*s++ != ')')
+ return 0;
- got_minus[2] = 0;
- if (*s == '+')
- ++s;
- else
- {
- ++s;
- got_minus[2] = 1;
- }
+ len = s - start - 1;
+ regname = alloca (len + 1);
- displacements[2] = strtol (s, &endp, 10);
- s = endp;
+ strncpy (regname, start, len);
+ regname[len] = '\0';
- if (*s != '(' || s[1] != '%')
- break;
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
- s += 2;
- start = s;
+ for (i = 0; i < 3; i++)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacements[i]);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus[i])
+ write_exp_elt_opcode (UNOP_NEG);
+ }
- while (isalnum (*s))
- ++s;
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
- if (*s++ != ')')
- break;
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
+ write_exp_elt_opcode (UNOP_CAST);
- len = s - start;
- regname = alloca (len + 1);
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
- strncpy (regname, start, len);
- regname[len] = '\0';
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
- if (user_reg_map_name_to_regnum (gdbarch,
- regname, len) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- regname, p->saved_arg);
+ write_exp_elt_opcode (UNOP_IND);
- for (i = 0; i < 3; i++)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (displacements[i]);
- write_exp_elt_opcode (OP_LONG);
- if (got_minus[i])
- write_exp_elt_opcode (UNOP_NEG);
- }
+ p->arg = s;
- write_exp_elt_opcode (OP_REGISTER);
- str.ptr = regname;
- str.length = len;
- write_exp_string (str);
- write_exp_elt_opcode (OP_REGISTER);
+ return 1;
+}
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
- write_exp_elt_opcode (UNOP_CAST);
+/* Helper function for i386_stap_parse_special_token.
- write_exp_elt_opcode (BINOP_ADD);
- write_exp_elt_opcode (BINOP_ADD);
- write_exp_elt_opcode (BINOP_ADD);
+ This function parses operands of the form `register base +
+ (register index * size) + offset', as represented in
+ `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
- write_exp_elt_opcode (UNOP_CAST);
- write_exp_elt_type (lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (UNOP_CAST);
+ Return 1 if the operand was parsed successfully, zero
+ otherwise. */
- write_exp_elt_opcode (UNOP_IND);
+static int
+i386_stap_parse_special_token_three_arg_disp (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ int offset_minus = 0;
+ long offset = 0;
+ int size_minus = 0;
+ long size = 0;
+ const char *start;
+ char *base;
+ int len_base;
+ char *index;
+ int len_index;
+ struct stoken base_token, index_token;
+ const char *s = p->arg;
+
+ if (!isdigit (*s) && *s != '(' && *s != '-' && *s != '+')
+ return 0;
- p->arg = s;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ offset_minus = 1;
+ }
- return 1;
- }
- break;
- }
- case THREE_ARG_DISPLACEMENT:
- {
- if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
- {
- int offset_minus = 0;
- long offset = 0;
- int size_minus = 0;
- long size = 0;
- const char *start;
- char *base;
- int len_base;
- char *index;
- int len_index;
- struct stoken base_token, index_token;
-
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- offset_minus = 1;
- }
+ if (offset_minus && !isdigit (*s))
+ return 0;
- if (offset_minus && !isdigit (*s))
- break;
+ if (isdigit (*s))
+ {
+ char *endp;
- if (isdigit (*s))
- {
- char *endp;
+ offset = strtol (s, &endp, 10);
+ s = endp;
+ }
- offset = strtol (s, &endp, 10);
- s = endp;
- }
+ if (*s != '(' || s[1] != '%')
+ return 0;
- if (*s != '(' || s[1] != '%')
- break;
+ s += 2;
+ start = s;
- s += 2;
- start = s;
+ while (isalnum (*s))
+ ++s;
- while (isalnum (*s))
- ++s;
+ if (*s != ',' || s[1] != '%')
+ return 0;
- if (*s != ',' || s[1] != '%')
- break;
+ len_base = s - start;
+ base = alloca (len_base + 1);
+ strncpy (base, start, len_base);
+ base[len_base] = '\0';
- len_base = s - start;
- base = alloca (len_base + 1);
- strncpy (base, start, len_base);
- base[len_base] = '\0';
+ if (user_reg_map_name_to_regnum (gdbarch, base, len_base) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ base, p->saved_arg);
- if (user_reg_map_name_to_regnum (gdbarch,
- base, len_base) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- base, p->saved_arg);
+ s += 2;
+ start = s;
- s += 2;
- start = s;
+ while (isalnum (*s))
+ ++s;
- while (isalnum (*s))
- ++s;
+ len_index = s - start;
+ index = alloca (len_index + 1);
+ strncpy (index, start, len_index);
+ index[len_index] = '\0';
- len_index = s - start;
- index = alloca (len_index + 1);
- strncpy (index, start, len_index);
- index[len_index] = '\0';
+ if (user_reg_map_name_to_regnum (gdbarch, index, len_index) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ index, p->saved_arg);
- if (user_reg_map_name_to_regnum (gdbarch,
- index, len_index) == -1)
- error (_("Invalid register name `%s' "
- "on expression `%s'."),
- index, p->saved_arg);
+ if (*s != ',' && *s != ')')
+ return 0;
- if (*s != ',' && *s != ')')
- break;
+ if (*s == ',')
+ {
+ char *endp;
- if (*s == ',')
- {
- char *endp;
+ ++s;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ size_minus = 1;
+ }
- ++s;
- if (*s == '+')
- ++s;
- else if (*s == '-')
- {
- ++s;
- size_minus = 1;
- }
+ size = strtol (s, &endp, 10);
+ s = endp;
- size = strtol (s, &endp, 10);
- s = endp;
+ if (*s != ')')
+ return 0;
+ }
- if (*s != ')')
- break;
- }
+ ++s;
- ++s;
+ if (offset)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (offset);
+ write_exp_elt_opcode (OP_LONG);
+ if (offset_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ }
- if (offset)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (offset);
- write_exp_elt_opcode (OP_LONG);
- if (offset_minus)
- write_exp_elt_opcode (UNOP_NEG);
- }
+ write_exp_elt_opcode (OP_REGISTER);
+ base_token.ptr = base;
+ base_token.length = len_base;
+ write_exp_string (base_token);
+ write_exp_elt_opcode (OP_REGISTER);
- write_exp_elt_opcode (OP_REGISTER);
- base_token.ptr = base;
- base_token.length = len_base;
- write_exp_string (base_token);
- write_exp_elt_opcode (OP_REGISTER);
+ if (offset)
+ write_exp_elt_opcode (BINOP_ADD);
- if (offset)
- write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (OP_REGISTER);
+ index_token.ptr = index;
+ index_token.length = len_index;
+ write_exp_string (index_token);
+ write_exp_elt_opcode (OP_REGISTER);
- write_exp_elt_opcode (OP_REGISTER);
- index_token.ptr = index;
- index_token.length = len_index;
- write_exp_string (index_token);
- write_exp_elt_opcode (OP_REGISTER);
+ if (size)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (size);
+ write_exp_elt_opcode (OP_LONG);
+ if (size_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ write_exp_elt_opcode (BINOP_MUL);
+ }
- if (size)
- {
- write_exp_elt_opcode (OP_LONG);
- write_exp_elt_type
- (builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (size);
- write_exp_elt_opcode (OP_LONG);
- if (size_minus)
- write_exp_elt_opcode (UNOP_NEG);
- write_exp_elt_opcode (BINOP_MUL);
- }
+ write_exp_elt_opcode (BINOP_ADD);
- write_exp_elt_opcode (BINOP_ADD);
+ 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_CAST);
- write_exp_elt_type (lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_opcode (UNOP_IND);
- write_exp_elt_opcode (UNOP_IND);
+ p->arg = s;
- p->arg = s;
+ return 1;
+}
- return 1;
- }
- break;
- }
+/* Implementation of `gdbarch_stap_parse_special_token', as defined in
+ gdbarch.h. */
+
+int
+i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ /* In order to parse special tokens, we use a state-machine that go
+ through every known token and try to get a match. */
+ enum
+ {
+ TRIPLET,
+ THREE_ARG_DISPLACEMENT,
+ DONE
+ } current_state;
+
+ current_state = TRIPLET;
+
+ while (current_state != DONE)
+ {
+ switch (current_state)
+ {
+ case TRIPLET:
+ {
+ if (i386_stap_parse_special_token_triplet (gdbarch, p))
+ return 1;
+
+ break;
+ }
+
+ case THREE_ARG_DISPLACEMENT:
+ {
+ if (i386_stap_parse_special_token_three_arg_disp (gdbarch, p))
+ return 1;
+
+ break;
+ }
}
/* Advancing to the next state. */
diff --git a/gdb/testsuite/gdb.arch/amd64-stap-special-operands.exp b/gdb/testsuite/gdb.arch/amd64-stap-special-operands.exp
new file mode 100644
index 0000000..a6ce7f5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-stap-special-operands.exp
@@ -0,0 +1,47 @@
+# Copyright 2013 Free Software Foundation, Inc.
+
+# 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/>.
+
+if { ![istarget "x86_64-*-*"] && ![istarget "i?86-*-*"] } {
+ verbose "Skipping amd64-stap-special-operands.exp"
+ return
+}
+
+proc test_probe { probe_name } {
+ if { ![runto "-pstap $probe_name"] } {
+ fail "run to probe $probe_name"
+ return
+ }
+
+ gdb_test "print \$_probe_argc" " = 1"
+ gdb_test "print \$_probe_arg0" " = 10"
+}
+
+standard_testfile amd64-stap-triplet.S
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+ untested amd64-stap-special-operands.exp
+ return -1
+}
+
+test_probe "triplet"
+
+standard_testfile amd64-stap-three-arg-disp.S
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+ untested amd64-stap-special-operands.exp
+ return -1
+}
+
+test_probe "three_arg"
diff --git a/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.S b/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.S
new file mode 100644
index 0000000..cf3856f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.S
@@ -0,0 +1,58 @@
+ .file "amd64-stap-three-arg-disp.c"
+ .text
+ .globl main
+ .type main, @function
+main:
+.LFB0:
+ .cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movl %edi, -20(%rbp)
+ movq %rsi, -32(%rbp)
+ movl $10, -4(%rbp)
+#APP
+# 8 "amd64-stap-three-arg-disp.c" 1
+ 990: nop
+.pushsection .note.stapsdt,"?","note"
+.balign 4
+.4byte 992f-991f,994f-993f,3
+991: .asciz "stapsdt"
+992: .balign 4
+993: .8byte 990b
+.8byte _.stapsdt.base
+.8byte 0
+.asciz "test"
+.asciz "three_arg"
+.asciz "-4@-4(%rbp,%ebx,0)"
+994: .balign 4
+.popsection
+
+# 0 "" 2
+# 8 "amd64-stap-three-arg-disp.c" 1
+ .ifndef _.stapsdt.base
+.pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat
+.weak _.stapsdt.base
+.hidden _.stapsdt.base
+_.stapsdt.base: .space 1
+.size _.stapsdt.base,1
+.popsection
+.endif
+
+# 0 "" 2
+#NO_APP
+ movl $0, %eax
+ movl $0, %ebx
+ popq %rbp
+ .cfi_def_cfa 7, 8
+# SUCC: EXIT [100.0%]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size main, .-main
+ .ident "GCC: (GNU) 4.7.2 20120921 (Red Hat 4.7.2-2)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.c b/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.c
new file mode 100644
index 0000000..f32d495
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-stap-three-arg-disp.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2013 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/>.
+
+ This file is not used directly. Please, see the equivalent .S file
+ for more details. */
+
+#include <sys/sdt.h>
+
+int
+main (int argc, char *argv[])
+{
+ int a = 10;
+
+ STAP_PROBE1 (test, three_arg, a);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-stap-triplet.S b/gdb/testsuite/gdb.arch/amd64-stap-triplet.S
new file mode 100644
index 0000000..f3a6bf7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-stap-triplet.S
@@ -0,0 +1,88 @@
+/* Copyright (C) 2013 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/>.
+
+ This file was generated from the equivalent .c file using the
+ following command:
+
+ #> gcc -S amd64-stap-triplet.c -o amd64-stap-triplet.S
+
+ Then, the SystemTap SDT probe definition below was tweaked. See below
+ for more details. */
+
+ .file "amd64-stap-triplet.c"
+ .text
+ .globl main
+ .type main, @function
+main:
+.LFB0:
+ .cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (fallthru)
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movl %edi, -20(%rbp)
+ movq %rsi, -32(%rbp)
+ movl $10, -4(%rbp)
+#APP
+# 8 "amd64-stap-triplet.c" 1
+ 990: nop
+.pushsection .note.stapsdt,"?","note"
+.balign 4
+.4byte 992f-991f,994f-993f,3
+991: .asciz "stapsdt"
+992: .balign 4
+993: .8byte 990b
+.8byte _.stapsdt.base
+.8byte 0
+.asciz "test"
+.asciz "triplet"
+/* The probe's argument definition below was tweaked in order to mimic a
+ triplet displacement in x86 asm. The original probe argument was:
+
+ -4@-4(%rbp)
+
+ The argument below is equivalent to that. */
+.asciz "-4@-4+16-16(%rbp)"
+994: .balign 4
+.popsection
+
+# 0 "" 2
+# 8 "amd64-stap-triplet.c" 1
+ .ifndef _.stapsdt.base
+.pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat
+.weak _.stapsdt.base
+.hidden _.stapsdt.base
+_.stapsdt.base: .space 1
+.size _.stapsdt.base,1
+.popsection
+.endif
+
+# 0 "" 2
+#NO_APP
+ movl $0, %eax
+ popq %rbp
+ .cfi_def_cfa 7, 8
+# SUCC: EXIT [100.0%]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size main, .-main
+ .ident "GCC: (GNU) 4.7.2 20120921 (Red Hat 4.7.2-2)"
+ .section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-stap-triplet.c b/gdb/testsuite/gdb.arch/amd64-stap-triplet.c
new file mode 100644
index 0000000..7ca64bf
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-stap-triplet.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2013 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/>.
+
+ This file is not used directly. Please, see the equivalent .S file
+ for more details. */
+
+#include <sys/sdt.h>
+
+int
+main (int argc, char *argv[])
+{
+ int a = 10;
+
+ STAP_PROBE1 (test, triplet, a);
+
+ return 0;
+}