* [PATCH V3 6/9] Support for DTrace USDT probes in x86_64 targets.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 20:28 ` Sergio Durigan Junior
2014-10-28 13:45 ` [PATCH V3 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
` (7 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch adds the target-specific code in order to support the
calculation of DTrace probes arguments in x86_64 targets, and also the
enabling and disabling of probes. This is done by implementing the
`dtrace_*' gdbarch handlers.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* amd64-linux-tdep.c: Include "parser-defs.h" and "user-regs.h".
(amd64_dtrace_parse_probe_argument): New function.
(amd64_dtrace_probe_is_enabled): Likewise.
(amd64_dtrace_enable_probe): Likewise.
(amd64_dtrace_disable_probe): Likewise.
(amd64_linux_init_abi): Register the
`gdbarch_dtrace_probe_argument', `gdbarch_dtrace_enable_probe',
`gdbarch_dtrace_disable_probe' and
`gdbarch_dtrace_probe_is_enabled' hooks.
(amd64_dtrace_disabled_probe_sequence_1): New constant.
(amd64_dtrace_disabled_probe_sequence_2): Likewise.
(amd64_dtrace_enable_probe_sequence): Likewise.
(amd64_dtrace_disable_probe_sequence): Likewise.
---
gdb/ChangeLog | 16 ++++++
gdb/amd64-linux-tdep.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+)
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index edbb1b3..9fe68b9 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -28,6 +28,8 @@
#include "gdbtypes.h"
#include "reggroups.h"
#include "regset.h"
+#include "parser-defs.h"
+#include "user-regs.h"
#include "amd64-linux-tdep.h"
#include "i386-linux-tdep.h"
#include "linux-tdep.h"
@@ -1643,6 +1645,146 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
&amd64_linux_xstateregset, "XSAVE extended state", cb_data);
}
+/* The instruction sequences used in x86_64 machines for a
+ disabled is-enabled probe. */
+
+const gdb_byte amd64_dtrace_disabled_probe_sequence_1[] = {
+ /* xor %rax, %rax */ 0x48, 0x33, 0xc0,
+ /* nop */ 0x90,
+ /* nop */ 0x90
+};
+
+const gdb_byte amd64_dtrace_disabled_probe_sequence_2[] = {
+ /* xor %rax, %rax */ 0x48, 0x33, 0xc0,
+ /* ret */ 0xc3,
+ /* nop */ 0x90
+};
+
+/* The instruction sequence used in x86_64 machines for enabling a
+ DTrace is-enabled probe. */
+
+const gdb_byte amd64_dtrace_enable_probe_sequence[] = {
+ /* mov $0x1, %eax */ 0xb8, 0x01, 0x00, 0x00, 0x00
+};
+
+/* The instruction sequence used in x86_64 machines for disabling a
+ DTrace is-enabled probe. */
+
+const gdb_byte amd64_dtrace_disable_probe_sequence[] = {
+ /* xor %rax, %rax; nop; nop */ 0x48, 0x33, 0xC0, 0x90, 0x90
+};
+
+/* Implementation of `gdbarch_dtrace_probe_is_enabled', as defined in
+ gdbarch.h. */
+
+static int
+amd64_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[5];
+
+ /* This function returns 1 if the instructions at ADDR do _not_
+ follow any of the amd64_dtrace_disabled_probe_sequence_*
+ patterns.
+
+ Note that ADDR is offset 3 bytes from the beginning of these
+ sequences. */
+
+ read_code (addr - 3, buf, 5);
+ return (memcmp (buf, amd64_dtrace_disabled_probe_sequence_1, 5) != 0
+ && memcmp (buf, amd64_dtrace_disabled_probe_sequence_2, 5) != 0);
+}
+
+/* Implementation of `gdbarch_dtrace_enable_probe', as defined in
+ gdbarch.h. */
+
+static void
+amd64_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* Note also that ADDR is offset 3 bytes from the beginning of
+ amd64_dtrace_enable_probe_sequence. */
+
+ write_memory (addr - 3, amd64_dtrace_enable_probe_sequence, 5);
+}
+
+/* Implementation of `gdbarch_dtrace_disable_probe', as defined in
+ gdbarch.h. */
+
+static void
+amd64_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* Note also that ADDR is offset 3 bytes from the beginning of
+ amd64_dtrace_disable_probe_sequence. */
+
+ write_memory (addr - 3, amd64_dtrace_disable_probe_sequence, 5);
+}
+
+/* Implementation of `gdbarch_dtrace_parse_probe_argument', as defined
+ in gdbarch.h. */
+
+static void
+amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
+ struct parser_state *pstate,
+ int narg)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct frame_info *this_frame = get_selected_frame (NULL);
+ struct stoken str;
+
+ /* DTrace probe arguments can be found on the ABI-defined places for
+ regular arguments at the current PC. The probe abstraction
+ currently supports up to 12 arguments for probes. */
+
+ if (narg < 6)
+ {
+ static const int arg_reg_map[6] =
+ {
+ AMD64_RDI_REGNUM, /* Arg 1. */
+ AMD64_RSI_REGNUM, /* Arg 2. */
+ AMD64_RDX_REGNUM, /* Arg 3. */
+ AMD64_RCX_REGNUM, /* Arg 4. */
+ AMD64_R8_REGNUM, /* Arg 5. */
+ AMD64_R9_REGNUM /* Arg 6. */
+ };
+ int regno = arg_reg_map[narg];
+ const char *regname = user_reg_map_regnum_to_name (gdbarch, regno);
+
+ write_exp_elt_opcode (pstate, OP_REGISTER);
+ str.ptr = regname;
+ str.length = strlen (regname);
+ write_exp_string (pstate, str);
+ write_exp_elt_opcode (pstate, OP_REGISTER);
+ }
+ else
+ {
+ /* Additional arguments are passed on the stack. */
+ CORE_ADDR sp;
+ const char *regname = user_reg_map_regnum_to_name (gdbarch, AMD64_RSP_REGNUM);
+
+ /* Displacement. */
+ write_exp_elt_opcode (pstate, OP_LONG);
+ write_exp_elt_type (pstate, builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (pstate, narg - 6);
+ write_exp_elt_opcode (pstate, OP_LONG);
+
+ /* Register: SP. */
+ write_exp_elt_opcode (pstate, OP_REGISTER);
+ str.ptr = regname;
+ str.length = strlen (regname);
+ write_exp_string (pstate, str);
+ write_exp_elt_opcode (pstate, OP_REGISTER);
+
+ write_exp_elt_opcode (pstate, BINOP_ADD);
+
+ /* Cast to long. */
+ write_exp_elt_opcode (pstate, UNOP_CAST);
+ write_exp_elt_type (pstate,
+ lookup_pointer_type (builtin_type (gdbarch)->builtin_long));
+ write_exp_elt_opcode (pstate, UNOP_CAST);
+
+ write_exp_elt_opcode (pstate, UNOP_IND);
+ }
+}
+
static void
amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -1907,6 +2049,12 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* GNU/Linux uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
+
+ /* Register DTrace handlers. */
+ set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
+ set_gdbarch_dtrace_probe_is_enabled (gdbarch, amd64_dtrace_probe_is_enabled);
+ set_gdbarch_dtrace_enable_probe (gdbarch, amd64_dtrace_enable_probe);
+ set_gdbarch_dtrace_disable_probe (gdbarch, amd64_dtrace_disable_probe);
}
static void
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 6/9] Support for DTrace USDT probes in x86_64 targets.
2014-10-28 13:45 ` [PATCH V3 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
@ 2014-10-31 20:28 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 20:28 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch adds the target-specific code in order to support the
> calculation of DTrace probes arguments in x86_64 targets, and also the
> enabling and disabling of probes. This is done by implementing the
> `dtrace_*' gdbarch handlers.
Thanks for the patch, Jose. This is much easier to read after you
reworked based on Pedro's suggestions.
I have no further comments to make.
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * amd64-linux-tdep.c: Include "parser-defs.h" and "user-regs.h".
> (amd64_dtrace_parse_probe_argument): New function.
> (amd64_dtrace_probe_is_enabled): Likewise.
> (amd64_dtrace_enable_probe): Likewise.
> (amd64_dtrace_disable_probe): Likewise.
> (amd64_linux_init_abi): Register the
> `gdbarch_dtrace_probe_argument', `gdbarch_dtrace_enable_probe',
> `gdbarch_dtrace_disable_probe' and
> `gdbarch_dtrace_probe_is_enabled' hooks.
> (amd64_dtrace_disabled_probe_sequence_1): New constant.
> (amd64_dtrace_disabled_probe_sequence_2): Likewise.
> (amd64_dtrace_enable_probe_sequence): Likewise.
> (amd64_dtrace_disable_probe_sequence): Likewise.
> ---
> gdb/ChangeLog | 16 ++++++
> gdb/amd64-linux-tdep.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 164 insertions(+)
>
> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
> index edbb1b3..9fe68b9 100644
> --- a/gdb/amd64-linux-tdep.c
> +++ b/gdb/amd64-linux-tdep.c
> @@ -28,6 +28,8 @@
> #include "gdbtypes.h"
> #include "reggroups.h"
> #include "regset.h"
> +#include "parser-defs.h"
> +#include "user-regs.h"
> #include "amd64-linux-tdep.h"
> #include "i386-linux-tdep.h"
> #include "linux-tdep.h"
> @@ -1643,6 +1645,146 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
> &amd64_linux_xstateregset, "XSAVE extended state", cb_data);
> }
>
> +/* The instruction sequences used in x86_64 machines for a
> + disabled is-enabled probe. */
> +
> +const gdb_byte amd64_dtrace_disabled_probe_sequence_1[] = {
> + /* xor %rax, %rax */ 0x48, 0x33, 0xc0,
> + /* nop */ 0x90,
> + /* nop */ 0x90
> +};
> +
> +const gdb_byte amd64_dtrace_disabled_probe_sequence_2[] = {
> + /* xor %rax, %rax */ 0x48, 0x33, 0xc0,
> + /* ret */ 0xc3,
> + /* nop */ 0x90
> +};
> +
> +/* The instruction sequence used in x86_64 machines for enabling a
> + DTrace is-enabled probe. */
> +
> +const gdb_byte amd64_dtrace_enable_probe_sequence[] = {
> + /* mov $0x1, %eax */ 0xb8, 0x01, 0x00, 0x00, 0x00
> +};
> +
> +/* The instruction sequence used in x86_64 machines for disabling a
> + DTrace is-enabled probe. */
> +
> +const gdb_byte amd64_dtrace_disable_probe_sequence[] = {
> + /* xor %rax, %rax; nop; nop */ 0x48, 0x33, 0xC0, 0x90, 0x90
> +};
> +
> +/* Implementation of `gdbarch_dtrace_probe_is_enabled', as defined in
> + gdbarch.h. */
> +
> +static int
> +amd64_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_byte buf[5];
> +
> + /* This function returns 1 if the instructions at ADDR do _not_
> + follow any of the amd64_dtrace_disabled_probe_sequence_*
> + patterns.
> +
> + Note that ADDR is offset 3 bytes from the beginning of these
> + sequences. */
> +
> + read_code (addr - 3, buf, 5);
> + return (memcmp (buf, amd64_dtrace_disabled_probe_sequence_1, 5) != 0
> + && memcmp (buf, amd64_dtrace_disabled_probe_sequence_2, 5) != 0);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_enable_probe', as defined in
> + gdbarch.h. */
> +
> +static void
> +amd64_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + /* Note also that ADDR is offset 3 bytes from the beginning of
> + amd64_dtrace_enable_probe_sequence. */
> +
> + write_memory (addr - 3, amd64_dtrace_enable_probe_sequence, 5);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_disable_probe', as defined in
> + gdbarch.h. */
> +
> +static void
> +amd64_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + /* Note also that ADDR is offset 3 bytes from the beginning of
> + amd64_dtrace_disable_probe_sequence. */
> +
> + write_memory (addr - 3, amd64_dtrace_disable_probe_sequence, 5);
> +}
> +
> +/* Implementation of `gdbarch_dtrace_parse_probe_argument', as defined
> + in gdbarch.h. */
> +
> +static void
> +amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
> + struct parser_state *pstate,
> + int narg)
> +{
> + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + struct frame_info *this_frame = get_selected_frame (NULL);
> + struct stoken str;
> +
> + /* DTrace probe arguments can be found on the ABI-defined places for
> + regular arguments at the current PC. The probe abstraction
> + currently supports up to 12 arguments for probes. */
> +
> + if (narg < 6)
> + {
> + static const int arg_reg_map[6] =
> + {
> + AMD64_RDI_REGNUM, /* Arg 1. */
> + AMD64_RSI_REGNUM, /* Arg 2. */
> + AMD64_RDX_REGNUM, /* Arg 3. */
> + AMD64_RCX_REGNUM, /* Arg 4. */
> + AMD64_R8_REGNUM, /* Arg 5. */
> + AMD64_R9_REGNUM /* Arg 6. */
> + };
> + int regno = arg_reg_map[narg];
> + const char *regname = user_reg_map_regnum_to_name (gdbarch, regno);
> +
> + write_exp_elt_opcode (pstate, OP_REGISTER);
> + str.ptr = regname;
> + str.length = strlen (regname);
> + write_exp_string (pstate, str);
> + write_exp_elt_opcode (pstate, OP_REGISTER);
> + }
> + else
> + {
> + /* Additional arguments are passed on the stack. */
> + CORE_ADDR sp;
> + const char *regname = user_reg_map_regnum_to_name (gdbarch, AMD64_RSP_REGNUM);
> +
> + /* Displacement. */
> + write_exp_elt_opcode (pstate, OP_LONG);
> + write_exp_elt_type (pstate, builtin_type (gdbarch)->builtin_long);
> + write_exp_elt_longcst (pstate, narg - 6);
> + write_exp_elt_opcode (pstate, OP_LONG);
> +
> + /* Register: SP. */
> + write_exp_elt_opcode (pstate, OP_REGISTER);
> + str.ptr = regname;
> + str.length = strlen (regname);
> + write_exp_string (pstate, str);
> + write_exp_elt_opcode (pstate, OP_REGISTER);
> +
> + write_exp_elt_opcode (pstate, BINOP_ADD);
> +
> + /* Cast to long. */
> + write_exp_elt_opcode (pstate, UNOP_CAST);
> + write_exp_elt_type (pstate,
> + lookup_pointer_type (builtin_type (gdbarch)->builtin_long));
> + write_exp_elt_opcode (pstate, UNOP_CAST);
> +
> + write_exp_elt_opcode (pstate, UNOP_IND);
> + }
> +}
> +
> static void
> amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
> {
> @@ -1907,6 +2049,12 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> /* GNU/Linux uses SVR4-style shared libraries. */
> set_solib_svr4_fetch_link_map_offsets
> (gdbarch, svr4_lp64_fetch_link_map_offsets);
> +
> + /* Register DTrace handlers. */
> + set_gdbarch_dtrace_parse_probe_argument (gdbarch, amd64_dtrace_parse_probe_argument);
> + set_gdbarch_dtrace_probe_is_enabled (gdbarch, amd64_dtrace_probe_is_enabled);
> + set_gdbarch_dtrace_enable_probe (gdbarch, amd64_dtrace_enable_probe);
> + set_gdbarch_dtrace_disable_probe (gdbarch, amd64_dtrace_disable_probe);
> }
>
> static void
> --
> 1.7.10.4
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 19:06 ` Sergio Durigan Junior
2014-10-28 13:45 ` [PATCH V3 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
` (6 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch adds several gdbarch functions (along with the
corresponding predicates): `dtrace_parse_probe_argument',
`dtrace_probe_is_enabled', `dtrace_enable_probe' and
`dtrace_disable_probe'. These functions will be implemented by
target-specific code, and called from the DTrace probes implementation
in order to calculate the value of probe arguments, and manipulate
is-enabled probes.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* gdbarch.sh (dtrace_parse_probe_argument): New.
(dtrace_probe_is_enabled): Likewise.
(dtrace_enable_probe): Likewise.
(dtrace_disable_probe): Likewise.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
---
gdb/ChangeLog | 9 ++++
gdb/gdbarch.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbarch.h | 36 ++++++++++++++++
gdb/gdbarch.sh | 16 +++++++
4 files changed, 189 insertions(+)
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 2984358..cf41342 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -298,6 +298,10 @@ struct gdbarch
const char * stap_gdb_register_suffix;
gdbarch_stap_is_single_operand_ftype *stap_is_single_operand;
gdbarch_stap_parse_special_token_ftype *stap_parse_special_token;
+ gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument;
+ gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled;
+ gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe;
+ gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe;
int has_global_solist;
int has_global_breakpoints;
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
@@ -612,6 +616,10 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
/* Skip verify of stap_is_single_operand, has predicate. */
/* Skip verify of stap_parse_special_token, has predicate. */
+ /* Skip verify of dtrace_parse_probe_argument, has predicate. */
+ /* Skip verify of dtrace_probe_is_enabled, has predicate. */
+ /* Skip verify of dtrace_enable_probe, has predicate. */
+ /* Skip verify of dtrace_disable_probe, has predicate. */
/* Skip verify of has_global_solist, invalid_p == 0 */
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
/* Skip verify of has_shared_address_space, invalid_p == 0 */
@@ -818,6 +826,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: double_format = %s\n",
pformat (gdbarch->double_format));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_dtrace_disable_probe_p() = %d\n",
+ gdbarch_dtrace_disable_probe_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dtrace_disable_probe = <%s>\n",
+ host_address_to_string (gdbarch->dtrace_disable_probe));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_dtrace_enable_probe_p() = %d\n",
+ gdbarch_dtrace_enable_probe_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dtrace_enable_probe = <%s>\n",
+ host_address_to_string (gdbarch->dtrace_enable_probe));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_dtrace_parse_probe_argument_p() = %d\n",
+ gdbarch_dtrace_parse_probe_argument_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dtrace_parse_probe_argument = <%s>\n",
+ host_address_to_string (gdbarch->dtrace_parse_probe_argument));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_dtrace_probe_is_enabled_p() = %d\n",
+ gdbarch_dtrace_probe_is_enabled_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dtrace_probe_is_enabled = <%s>\n",
+ host_address_to_string (gdbarch->dtrace_probe_is_enabled));
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
gdbarch_dummy_id_p (gdbarch));
fprintf_unfiltered (file,
@@ -4081,6 +4113,102 @@ set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
}
int
+gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->dtrace_parse_probe_argument != NULL;
+}
+
+void
+gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dtrace_parse_probe_argument != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_parse_probe_argument called\n");
+ gdbarch->dtrace_parse_probe_argument (gdbarch, pstate, narg);
+}
+
+void
+set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
+ gdbarch_dtrace_parse_probe_argument_ftype dtrace_parse_probe_argument)
+{
+ gdbarch->dtrace_parse_probe_argument = dtrace_parse_probe_argument;
+}
+
+int
+gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->dtrace_probe_is_enabled != NULL;
+}
+
+int
+gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dtrace_probe_is_enabled != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_probe_is_enabled called\n");
+ return gdbarch->dtrace_probe_is_enabled (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch,
+ gdbarch_dtrace_probe_is_enabled_ftype dtrace_probe_is_enabled)
+{
+ gdbarch->dtrace_probe_is_enabled = dtrace_probe_is_enabled;
+}
+
+int
+gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->dtrace_enable_probe != NULL;
+}
+
+void
+gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dtrace_enable_probe != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_enable_probe called\n");
+ gdbarch->dtrace_enable_probe (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch,
+ gdbarch_dtrace_enable_probe_ftype dtrace_enable_probe)
+{
+ gdbarch->dtrace_enable_probe = dtrace_enable_probe;
+}
+
+int
+gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->dtrace_disable_probe != NULL;
+}
+
+void
+gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->dtrace_disable_probe != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_disable_probe called\n");
+ gdbarch->dtrace_disable_probe (gdbarch, addr);
+}
+
+void
+set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch,
+ gdbarch_dtrace_disable_probe_ftype dtrace_disable_probe)
+{
+ gdbarch->dtrace_disable_probe = dtrace_disable_probe;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index f5330c2..3617553 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -57,6 +57,7 @@ struct syscall;
struct agent_expr;
struct axs_value;
struct stap_parse_info;
+struct parser_state;
struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
struct mem_range;
@@ -1183,6 +1184,41 @@ typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, s
extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token);
+/* DTrace related functions.
+ The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
+ NARG must be >= 0. */
+
+extern int gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
+extern void gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
+extern void set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument);
+
+/* True if the given ADDR does not contain the instruction sequence
+ corresponding to a disabled DTrace is-enabled probe. */
+
+extern int gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_dtrace_probe_is_enabled_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern int gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled);
+
+/* Enable a DTrace is-enabled probe at ADDR. */
+
+extern int gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_enable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe);
+
+/* Disable a DTrace is-enabled probe at ADDR. */
+
+extern int gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_dtrace_disable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe);
+
/* True if the list of shared libraries is one and only for all
processes, as opposed to a list of shared libraries per inferior.
This usually means that all processes, although may or may not share
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 5442799..63ec8a1 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -945,6 +945,21 @@ M:int:stap_is_single_operand:const char *s:s
# parser), and should advance the buffer pointer (p->arg).
M:int:stap_parse_special_token:struct stap_parse_info *p:p
+# DTrace related functions.
+
+# The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
+# NARG must be >= 0.
+M:void:dtrace_parse_probe_argument:struct parser_state *pstate, int narg:pstate, narg
+
+# True if the given ADDR does not contain the instruction sequence
+# corresponding to a disabled DTrace is-enabled probe.
+M:int:dtrace_probe_is_enabled:CORE_ADDR addr:addr
+
+# Enable a DTrace is-enabled probe at ADDR.
+M:void:dtrace_enable_probe:CORE_ADDR addr:addr
+
+# Disable a DTrace is-enabled probe at ADDR.
+M:void:dtrace_disable_probe:CORE_ADDR addr:addr
# True if the list of shared libraries is one and only for all
# processes, as opposed to a list of shared libraries per inferior.
@@ -1153,6 +1168,7 @@ struct syscall;
struct agent_expr;
struct axs_value;
struct stap_parse_info;
+struct parser_state;
struct ravenscar_arch_ops;
struct elf_internal_linux_prpsinfo;
struct mem_range;
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe.
2014-10-28 13:45 ` [PATCH V3 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
@ 2014-10-31 19:06 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 19:06 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch adds several gdbarch functions (along with the
> corresponding predicates): `dtrace_parse_probe_argument',
> `dtrace_probe_is_enabled', `dtrace_enable_probe' and
> `dtrace_disable_probe'. These functions will be implemented by
> target-specific code, and called from the DTrace probes implementation
> in order to calculate the value of probe arguments, and manipulate
> is-enabled probes.
Thanks a lot. I guess this patch was approved already, so no further
comments here.
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * gdbarch.sh (dtrace_parse_probe_argument): New.
> (dtrace_probe_is_enabled): Likewise.
> (dtrace_enable_probe): Likewise.
> (dtrace_disable_probe): Likewise.
> * gdbarch.c: Regenerate.
> * gdbarch.h: Regenerate.
> ---
> gdb/ChangeLog | 9 ++++
> gdb/gdbarch.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/gdbarch.h | 36 ++++++++++++++++
> gdb/gdbarch.sh | 16 +++++++
> 4 files changed, 189 insertions(+)
>
> diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
> index 2984358..cf41342 100644
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -298,6 +298,10 @@ struct gdbarch
> const char * stap_gdb_register_suffix;
> gdbarch_stap_is_single_operand_ftype *stap_is_single_operand;
> gdbarch_stap_parse_special_token_ftype *stap_parse_special_token;
> + gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument;
> + gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled;
> + gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe;
> + gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe;
> int has_global_solist;
> int has_global_breakpoints;
> gdbarch_has_shared_address_space_ftype *has_shared_address_space;
> @@ -612,6 +616,10 @@ verify_gdbarch (struct gdbarch *gdbarch)
> /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
> /* Skip verify of stap_is_single_operand, has predicate. */
> /* Skip verify of stap_parse_special_token, has predicate. */
> + /* Skip verify of dtrace_parse_probe_argument, has predicate. */
> + /* Skip verify of dtrace_probe_is_enabled, has predicate. */
> + /* Skip verify of dtrace_enable_probe, has predicate. */
> + /* Skip verify of dtrace_disable_probe, has predicate. */
> /* Skip verify of has_global_solist, invalid_p == 0 */
> /* Skip verify of has_global_breakpoints, invalid_p == 0 */
> /* Skip verify of has_shared_address_space, invalid_p == 0 */
> @@ -818,6 +826,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
> "gdbarch_dump: double_format = %s\n",
> pformat (gdbarch->double_format));
> fprintf_unfiltered (file,
> + "gdbarch_dump: gdbarch_dtrace_disable_probe_p() = %d\n",
> + gdbarch_dtrace_disable_probe_p (gdbarch));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: dtrace_disable_probe = <%s>\n",
> + host_address_to_string (gdbarch->dtrace_disable_probe));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: gdbarch_dtrace_enable_probe_p() = %d\n",
> + gdbarch_dtrace_enable_probe_p (gdbarch));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: dtrace_enable_probe = <%s>\n",
> + host_address_to_string (gdbarch->dtrace_enable_probe));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: gdbarch_dtrace_parse_probe_argument_p() = %d\n",
> + gdbarch_dtrace_parse_probe_argument_p (gdbarch));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: dtrace_parse_probe_argument = <%s>\n",
> + host_address_to_string (gdbarch->dtrace_parse_probe_argument));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: gdbarch_dtrace_probe_is_enabled_p() = %d\n",
> + gdbarch_dtrace_probe_is_enabled_p (gdbarch));
> + fprintf_unfiltered (file,
> + "gdbarch_dump: dtrace_probe_is_enabled = <%s>\n",
> + host_address_to_string (gdbarch->dtrace_probe_is_enabled));
> + fprintf_unfiltered (file,
> "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
> gdbarch_dummy_id_p (gdbarch));
> fprintf_unfiltered (file,
> @@ -4081,6 +4113,102 @@ set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
> }
>
> int
> +gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != NULL);
> + return gdbarch->dtrace_parse_probe_argument != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg)
> +{
> + gdb_assert (gdbarch != NULL);
> + gdb_assert (gdbarch->dtrace_parse_probe_argument != NULL);
> + if (gdbarch_debug >= 2)
> + fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_parse_probe_argument called\n");
> + gdbarch->dtrace_parse_probe_argument (gdbarch, pstate, narg);
> +}
> +
> +void
> +set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
> + gdbarch_dtrace_parse_probe_argument_ftype dtrace_parse_probe_argument)
> +{
> + gdbarch->dtrace_parse_probe_argument = dtrace_parse_probe_argument;
> +}
> +
> +int
> +gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != NULL);
> + return gdbarch->dtrace_probe_is_enabled != NULL;
> +}
> +
> +int
> +gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_assert (gdbarch != NULL);
> + gdb_assert (gdbarch->dtrace_probe_is_enabled != NULL);
> + if (gdbarch_debug >= 2)
> + fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_probe_is_enabled called\n");
> + return gdbarch->dtrace_probe_is_enabled (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch,
> + gdbarch_dtrace_probe_is_enabled_ftype dtrace_probe_is_enabled)
> +{
> + gdbarch->dtrace_probe_is_enabled = dtrace_probe_is_enabled;
> +}
> +
> +int
> +gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != NULL);
> + return gdbarch->dtrace_enable_probe != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_assert (gdbarch != NULL);
> + gdb_assert (gdbarch->dtrace_enable_probe != NULL);
> + if (gdbarch_debug >= 2)
> + fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_enable_probe called\n");
> + gdbarch->dtrace_enable_probe (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch,
> + gdbarch_dtrace_enable_probe_ftype dtrace_enable_probe)
> +{
> + gdbarch->dtrace_enable_probe = dtrace_enable_probe;
> +}
> +
> +int
> +gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != NULL);
> + return gdbarch->dtrace_disable_probe != NULL;
> +}
> +
> +void
> +gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_assert (gdbarch != NULL);
> + gdb_assert (gdbarch->dtrace_disable_probe != NULL);
> + if (gdbarch_debug >= 2)
> + fprintf_unfiltered (gdb_stdlog, "gdbarch_dtrace_disable_probe called\n");
> + gdbarch->dtrace_disable_probe (gdbarch, addr);
> +}
> +
> +void
> +set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch,
> + gdbarch_dtrace_disable_probe_ftype dtrace_disable_probe)
> +{
> + gdbarch->dtrace_disable_probe = dtrace_disable_probe;
> +}
> +
> +int
> gdbarch_has_global_solist (struct gdbarch *gdbarch)
> {
> gdb_assert (gdbarch != NULL);
> diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
> index f5330c2..3617553 100644
> --- a/gdb/gdbarch.h
> +++ b/gdb/gdbarch.h
> @@ -57,6 +57,7 @@ struct syscall;
> struct agent_expr;
> struct axs_value;
> struct stap_parse_info;
> +struct parser_state;
> struct ravenscar_arch_ops;
> struct elf_internal_linux_prpsinfo;
> struct mem_range;
> @@ -1183,6 +1184,41 @@ typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, s
> extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
> extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token);
>
> +/* DTrace related functions.
> + The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
> + NARG must be >= 0. */
> +
> +extern int gdbarch_dtrace_parse_probe_argument_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_parse_probe_argument_ftype) (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
> +extern void gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct parser_state *pstate, int narg);
> +extern void set_gdbarch_dtrace_parse_probe_argument (struct gdbarch *gdbarch, gdbarch_dtrace_parse_probe_argument_ftype *dtrace_parse_probe_argument);
> +
> +/* True if the given ADDR does not contain the instruction sequence
> + corresponding to a disabled DTrace is-enabled probe. */
> +
> +extern int gdbarch_dtrace_probe_is_enabled_p (struct gdbarch *gdbarch);
> +
> +typedef int (gdbarch_dtrace_probe_is_enabled_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern int gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_probe_is_enabled (struct gdbarch *gdbarch, gdbarch_dtrace_probe_is_enabled_ftype *dtrace_probe_is_enabled);
> +
> +/* Enable a DTrace is-enabled probe at ADDR. */
> +
> +extern int gdbarch_dtrace_enable_probe_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_enable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_enable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_enable_probe_ftype *dtrace_enable_probe);
> +
> +/* Disable a DTrace is-enabled probe at ADDR. */
> +
> +extern int gdbarch_dtrace_disable_probe_p (struct gdbarch *gdbarch);
> +
> +typedef void (gdbarch_dtrace_disable_probe_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, CORE_ADDR addr);
> +extern void set_gdbarch_dtrace_disable_probe (struct gdbarch *gdbarch, gdbarch_dtrace_disable_probe_ftype *dtrace_disable_probe);
> +
> /* True if the list of shared libraries is one and only for all
> processes, as opposed to a list of shared libraries per inferior.
> This usually means that all processes, although may or may not share
> diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
> index 5442799..63ec8a1 100755
> --- a/gdb/gdbarch.sh
> +++ b/gdb/gdbarch.sh
> @@ -945,6 +945,21 @@ M:int:stap_is_single_operand:const char *s:s
> # parser), and should advance the buffer pointer (p->arg).
> M:int:stap_parse_special_token:struct stap_parse_info *p:p
>
> +# DTrace related functions.
> +
> +# The expression to compute the NARTGth+1 argument to a DTrace USDT probe.
> +# NARG must be >= 0.
> +M:void:dtrace_parse_probe_argument:struct parser_state *pstate, int narg:pstate, narg
> +
> +# True if the given ADDR does not contain the instruction sequence
> +# corresponding to a disabled DTrace is-enabled probe.
> +M:int:dtrace_probe_is_enabled:CORE_ADDR addr:addr
> +
> +# Enable a DTrace is-enabled probe at ADDR.
> +M:void:dtrace_enable_probe:CORE_ADDR addr:addr
> +
> +# Disable a DTrace is-enabled probe at ADDR.
> +M:void:dtrace_disable_probe:CORE_ADDR addr:addr
>
> # True if the list of shared libraries is one and only for all
> # processes, as opposed to a list of shared libraries per inferior.
> @@ -1153,6 +1168,7 @@ struct syscall;
> struct agent_expr;
> struct axs_value;
> struct stap_parse_info;
> +struct parser_state;
> struct ravenscar_arch_ops;
> struct elf_internal_linux_prpsinfo;
> struct mem_range;
> --
> 1.7.10.4
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 5/9] New probe type: DTrace USDT probes.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 6/9] Support for DTrace USDT probes in x86_64 targets Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 4/9] New gdbarch functions: dtrace_parse_probe_argument, dtrace_probe_is_enabled, dtrace_enable_probe, dtrace_disable_probe Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 20:03 ` Sergio Durigan Junior
2014-10-28 13:45 ` [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
` (5 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch adds a new type of probe to GDB: the DTrace USDT probes. The new
type is added by providing functions implementing all the entries of the
`probe_ops' structure defined in `probe.h'. The implementation is
self-contained and does not depend on DTrace source code in any way.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* breakpoint.c (BREAK_ARGS_HELP): help string updated to mention
the -probe-dtrace new vpossible value for PROBE_MODIFIER.
* configure.ac (CONFIG_OBS): dtrace-probe.o added if BFD can
handle ELF files.
* Makefile.in (SFILES): dtrace-probe.c added.
* configure: Regenerate.
* dtrace-probe.c: New file.
(SHT_SUNW_dof): New constant.
(dtrace_probe_type): New enum.
(dtrace_probe_arg): New struct.
(dtrace_probe_arg_s): New typedef.
(struct dtrace_probe_enabler): New struct.
(dtrace_probe_enabler_s): New typedef.
(dtrace_probe): New struct.
(dtrace_probe_is_linespec): New function.
(dtrace_dof_sect_type): New enum.
(dtrace_dof_dofh_ident): Likewise.
(dtrace_dof_encoding): Likewise.
(DTRACE_DOF_ENCODE_LSB): Likewise.
(DTRACE_DOF_ENCODE_MSB): Likewise.
(dtrace_dof_hdr): New struct.
(dtrace_dof_sect): Likewise.
(dtrace_dof_provider): Likewise.
(dtrace_dof_probe): Likewise.
(DOF_UINT): New macro.
(DTRACE_DOF_PTR): Likewise.
(DTRACE_DOF_SECT): Likewise.
(dtrace_process_dof_probe): New function.
(dtrace_process_dof): Likewise.
(dtrace_build_arg_exprs): Likewise.
(dtrace_get_arg): Likewise.
(dtrace_get_probes): Likewise.
(dtrace_get_probe_argument_count): Likewise.
(dtrace_can_evaluate_probe_arguments): Likewise.
(dtrace_evaluate_probe_argument): Likewise.
(dtrace_compile_to_ax): Likewise.
(dtrace_probe_destroy): Likewise.
(dtrace_gen_info_probes_table_header): Likewise.
(dtrace_gen_info_probes_table_values): Likewise.
(dtrace_probe_is_enabled): Likewise.
(dtrace_probe_ops): New variable.
(info_probes_dtrace_command): New function.
(_initialize_dtrace_probe): Likewise.
(dtrace_type_name): Likewise.
---
gdb/ChangeLog | 47 +++
gdb/Makefile.in | 3 +-
gdb/breakpoint.c | 3 +-
gdb/configure | 2 +-
gdb/configure.ac | 2 +-
gdb/dtrace-probe.c | 909 ++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 962 insertions(+), 4 deletions(-)
create mode 100644 gdb/dtrace-probe.c
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 1da8af6..a237a1f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -800,7 +800,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
d-exp.y d-lang.c d-valprint.c \
cp-name-parser.y \
- dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
+ dbxread.c demangle.c dictionary.c disasm.c doublest.c \
+ dtrace-probe.c dummy-frame.c \
dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
dwarf2-frame-tailcall.c \
elfread.c environ.c eval.c event-loop.c event-top.c \
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index cab6c56..ebaa9ce 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -15998,7 +15998,8 @@ all_tracepoints (void)
command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
PROBE_MODIFIER shall be present if the command is to be placed in a\n\
probe point. Accepted values are `-probe' (for a generic, automatically\n\
-guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\
+guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
+`-probe-dtrace' (for a DTrace probe).\n\
LOCATION may be a line number, function name, or \"*\" and an address.\n\
If a line number is specified, break at start of code for that line.\n\
If a function is specified, break at start of code for that function.\n\
diff --git a/gdb/configure b/gdb/configure
index 1d6d88b..a1660bc 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -13241,7 +13241,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
LDFLAGS=$OLD_LDFLAGS
LIBS=$OLD_LIBS
if test $gdb_cv_var_elf = yes; then
- CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
+ CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
$as_echo "#define HAVE_ELF 1" >>confdefs.h
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 2d73669..4ac5f7b 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2063,7 +2063,7 @@ AC_SUBST(WIN32LIBS)
GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
[bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
if test $gdb_cv_var_elf = yes; then
- CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
+ CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
AC_DEFINE(HAVE_ELF, 1,
[Define if ELF support should be included.])
# -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
new file mode 100644
index 0000000..f4bfc70
--- /dev/null
+++ b/gdb/dtrace-probe.c
@@ -0,0 +1,909 @@
+/* DTrace probe support for GDB.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ Contributed by Oracle, 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/>. */
+
+#include "defs.h"
+#include "probe.h"
+#include "vec.h"
+#include "elf-bfd.h"
+#include "gdbtypes.h"
+#include "obstack.h"
+#include "objfiles.h"
+#include "complaints.h"
+#include "value.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "language.h"
+#include "parser-defs.h"
+#include "inferior.h"
+
+/* The type of the ELF sections where we will find the DOF programs
+ with information about probes. */
+
+#ifndef SHT_SUNW_dof
+# define SHT_SUNW_dof 0x6ffffff4
+#endif
+
+/* Forward declaration. */
+
+static const struct probe_ops dtrace_probe_ops;
+
+/* The following structure represents a single argument for the
+ probe. */
+
+struct dtrace_probe_arg
+{
+ /* The type of the probe argument. */
+ struct type *type;
+
+ /* A string describing the type. */
+ char *type_str;
+
+ /* The argument converted to an internal GDB expression. */
+ struct expression *expr;
+};
+
+typedef struct dtrace_probe_arg dtrace_probe_arg_s;
+DEF_VEC_O (dtrace_probe_arg_s);
+
+/* The following structure represents an enabler for a probe. */
+
+struct dtrace_probe_enabler
+{
+ /* Program counter where the is-enabled probe is installed. The
+ contents (nops, whatever...) stored at this address are
+ architecture dependent. */
+ CORE_ADDR address;
+};
+
+typedef struct dtrace_probe_enabler dtrace_probe_enabler_s;
+DEF_VEC_O (dtrace_probe_enabler_s);
+
+/* The following structure represents a dtrace probe. */
+
+struct dtrace_probe
+{
+ /* Generic information about the probe. This must be the first
+ element of this struct, in order to maintain binary compatibility
+ with the `struct probe' and be able to fully abstract it. */
+ struct probe p;
+
+ /* A probe can have zero or more arguments. */
+ int probe_argc;
+ VEC (dtrace_probe_arg_s) *args;
+
+ /* A probe can have zero or more "enablers" associated with it. */
+ VEC (dtrace_probe_enabler_s) *enablers;
+
+ /* Whether the expressions for the arguments have been built. */
+ unsigned int args_expr_built : 1;
+};
+
+/* Implementation of the probe_is_linespec method. */
+
+static int
+dtrace_probe_is_linespec (const char **linespecp)
+{
+ static const char *const keywords[] = { "-pdtrace", "-probe-dtrace", NULL };
+
+ return probe_is_linespec_by_keyword (linespecp, keywords);
+}
+
+/* DOF programs can contain an arbitrary number of sections of 26
+ different types. In order to support DTrace USDT probes we only
+ need to handle a subset of these section types, fortunately. These
+ section types are defined in the following enumeration.
+
+ See linux/dtrace/dof_defines.h for a complete list of section types
+ along with their values. */
+
+enum dtrace_dof_sect_type
+{
+ /* Null section. */
+ DTRACE_DOF_SECT_TYPE_NONE = 0,
+ /* A dof_ecbdesc_t. */
+ DTRACE_DOF_SECT_TYPE_ECBDESC = 3,
+ /* A string table. */
+ DTRACE_DOF_SECT_TYPE_STRTAB = 8,
+ /* A dof_provider_t */
+ DTRACE_DOF_SECT_TYPE_PROVIDER = 15,
+ /* Array of dof_probe_t */
+ DTRACE_DOF_SECT_TYPE_PROBES = 16,
+ /* An array of probe arg mappings. */
+ DTRACE_DOF_SECT_TYPE_PRARGS = 17,
+ /* An array of probe arg offsets. */
+ DTRACE_DOF_SECT_TYPE_PROFFS = 18,
+ /* An array of probe is-enabled offsets. */
+ DTRACE_DOF_SECT_TYPE_PRENOFFS = 26
+};
+
+/* The following collection of data structures map the structure of
+ DOF entities. Again, we only cover the subset of DOF used to
+ implement USDT probes.
+
+ See linux/dtrace/dof.h header for a complete list of data
+ structures. */
+
+/* Offsets to index the dofh_ident[] array defined below. */
+
+enum dtrace_dof_ident
+{
+ /* First byte of the magic number. */
+ DTRACE_DOF_ID_MAG0 = 0,
+ /* Second byte of the magic number. */
+ DTRACE_DOF_ID_MAG1 = 1,
+ /* Third byte of the magic number. */
+ DTRACE_DOF_ID_MAG2 = 2,
+ /* Fourth byte of the magic number. */
+ DTRACE_DOF_ID_MAG3 = 3,
+ /* An enum_dof_encoding value. */
+ DTRACE_DOF_ID_ENCODING = 5
+};
+
+/* Possible values for dofh_ident[DOF_ID_ENCODING]. */
+
+enum dtrace_dof_encoding
+{
+ /* The DOF program is little-endian. */
+ DTRACE_DOF_ENCODE_LSB = 1,
+ /* The DOF program is big-endian. */
+ DTRACE_DOF_ENCODE_MSB = 2
+};
+
+/* A DOF header, which describes the contents of a DOF program: number
+ of sections, size, etc. */
+
+struct dtrace_dof_hdr
+{
+ /* Identification bytes (see above). */
+ uint8_t dofh_ident[16];
+ /* File attribute flags (if any). */
+ uint32_t dofh_flags;
+ /* Size of file header in bytes. */
+ uint32_t dofh_hdrsize;
+ /* Size of section header in bytes. */
+ uint32_t dofh_secsize;
+ /* Number of section headers. */
+ uint32_t dofh_secnum;
+ /* File offset of section headers. */
+ uint64_t dofh_secoff;
+ /* File size of loadable portion. */
+ uint64_t dofh_loadsz;
+ /* File size of entire DOF file. */
+ uint64_t dofh_filesz;
+ /* Reserved for future use. */
+ uint64_t dofh_pad;
+};
+
+/* A DOF section, whose contents depend on its type. The several
+ supported section types are described in the enum
+ dtrace_dof_sect_type above. */
+
+struct dtrace_dof_sect
+{
+ /* Section type (see the define above). */
+ uint32_t dofs_type;
+ /* Section data memory alignment. */
+ uint32_t dofs_align;
+ /* Section flags (if any). */
+ uint32_t dofs_flags;
+ /* Size of section entry (if table). */
+ uint32_t dofs_entsize;
+ /* DOF + offset points to the section data. */
+ uint64_t dofs_offset;
+ /* Size of section data in bytes. */
+ uint64_t dofs_size;
+};
+
+/* A DOF provider, which is the provider of a probe. */
+
+struct dtrace_dof_provider
+{
+ /* Link to a DTRACE_DOF_SECT_TYPE_STRTAB section. */
+ uint32_t dofpv_strtab;
+ /* Link to a DTRACE_DOF_SECT_TYPE_PROBES section. */
+ uint32_t dofpv_probes;
+ /* Link to a DTRACE_DOF_SECT_TYPE_PRARGS section. */
+ uint32_t dofpv_prargs;
+ /* Link to a DTRACE_DOF_SECT_TYPE_PROFFS section. */
+ uint32_t dofpv_proffs;
+ /* Provider name string. */
+ uint32_t dofpv_name;
+ /* Provider attributes. */
+ uint32_t dofpv_provattr;
+ /* Module attributes. */
+ uint32_t dofpv_modattr;
+ /* Function attributes. */
+ uint32_t dofpv_funcattr;
+ /* Name attributes. */
+ uint32_t dofpv_nameattr;
+ /* Args attributes. */
+ uint32_t dofpv_argsattr;
+ /* Link to a DTRACE_DOF_SECT_PRENOFFS section. */
+ uint32_t dofpv_prenoffs;
+};
+
+/* A set of DOF probes and is-enabled probes sharing a base address
+ and several attributes. The particular locations and attributes of
+ each probe are maintained in arrays in several other DOF sections.
+ See the comment in dtrace_process_dof_probe for details on how
+ these attributes are stored. */
+
+struct dtrace_dof_probe
+{
+ /* Probe base address or offset. */
+ uint64_t dofpr_addr;
+ /* Probe function string. */
+ uint32_t dofpr_func;
+ /* Probe name string. */
+ uint32_t dofpr_name;
+ /* Native argument type strings. */
+ uint32_t dofpr_nargv;
+ /* Translated argument type strings. */
+ uint32_t dofpr_xargv;
+ /* Index of first argument mapping. */
+ uint32_t dofpr_argidx;
+ /* Index of first offset entry. */
+ uint32_t dofpr_offidx;
+ /* Native argument count. */
+ uint8_t dofpr_nargc;
+ /* Translated argument count. */
+ uint8_t dofpr_xargc;
+ /* Number of offset entries for probe. */
+ uint16_t dofpr_noffs;
+ /* Index of first is-enabled offset. */
+ uint32_t dofpr_enoffidx;
+ /* Number of is-enabled offsets. */
+ uint16_t dofpr_nenoffs;
+ /* Reserved for future use. */
+ uint16_t dofpr_pad1;
+ /* Reserved for future use. */
+ uint32_t dofpr_pad2;
+};
+
+/* DOF supports two different encodings: MSB (big-endian) and LSB
+ (little-endian). The encoding is itself encoded in the DOF header.
+ The following function returns an unsigned value in the host
+ endianness. */
+
+#define DOF_UINT(dof, field) \
+ extract_unsigned_integer ((gdb_byte *) &(field), \
+ sizeof ((field)), \
+ (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \
+ == DTRACE_DOF_ENCODE_MSB) \
+ ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE))
+
+/* The following macro applies a given byte offset to a DOF (a pointer
+ to a dtrace_dof_hdr structure) and returns the resulting
+ address. */
+
+#define DTRACE_DOF_PTR(dof, offset) (&((char *) (dof))[(offset)])
+
+/* The following macro returns a pointer to the beginning of a given
+ section in a DOF object. The section is referred to by its index
+ in the sections array. */
+
+#define DTRACE_DOF_SECT(dof, idx) \
+ ((struct dtrace_dof_sect *) \
+ DTRACE_DOF_PTR ((dof), \
+ DOF_UINT ((dof), (dof)->dofh_secoff) \
+ + ((idx) * DOF_UINT ((dof), (dof)->dofh_secsize))))
+
+/* Helper function to examine the probe described by the given PROBE
+ and PROVIDER data structures and add it to the PROBESP vector.
+ STRTAB, OFFTAB, EOFFTAB and ARGTAB are pointers to tables in the
+ DOF program containing the attributes for the probe. */
+
+static void
+dtrace_process_dof_probe (struct objfile *objfile,
+ struct gdbarch *gdbarch, VEC (probe_p) **probesp,
+ struct dtrace_dof_hdr *dof,
+ struct dtrace_dof_probe *probe,
+ struct dtrace_dof_provider *provider,
+ char *strtab, char *offtab, char *eofftab,
+ char *argtab, uint64_t strtab_size)
+{
+ int i, j, num_probes, num_enablers;
+ struct cleanup *cleanup;
+ VEC (dtrace_probe_enabler_s) *enablers;
+ char *p;
+
+ /* Each probe section can define zero or more probes of two
+ different types:
+
+ - probe->dofpr_noffs regular probes whose program counters are
+ stored in 32bit words starting at probe->dofpr_addr +
+ offtab[probe->dofpr_offidx].
+
+ - probe->dofpr_nenoffs is-enabled probes whose program counters
+ are stored in 32bit words starting at probe->dofpr_addr +
+ eofftab[probe->dofpr_enoffidx].
+
+ However is-enabled probes are not probes per-se, but an
+ optimization hack that is implemented in the kernel in a very
+ similar way than normal probes. This is how we support
+ is-enabled probes on GDB:
+
+ - Our probes are always DTrace regular probes.
+
+ - Our probes can be associated with zero or more "enablers". The
+ list of enablers is built from the is-enabled probes defined in
+ the Probe section.
+
+ - Probes having a non-empty list of enablers can be enabled or
+ disabled using the `enable probe' and `disable probe' commands
+ respectively. The `Enabled' column in the output of `info
+ probes' will read `yes' if the enablers are activated, `no'
+ otherwise.
+
+ - Probes having an empty list of enablers are always enabled.
+ The `Enabled' column in the output of `info probes' will
+ read `always'.
+
+ It follows that if there are DTrace is-enabled probes defined for
+ some provider/name but no DTrace regular probes defined then the
+ GDB user wont be able to enable/disable these conditionals. */
+
+ num_probes = DOF_UINT (dof, probe->dofpr_noffs);
+ if (num_probes == 0)
+ return;
+
+ /* Build the list of enablers for the probes defined in this Probe
+ DOF section. */
+ enablers = NULL;
+ cleanup
+ = make_cleanup (VEC_cleanup (dtrace_probe_enabler_s), &enablers);
+ num_enablers = DOF_UINT (dof, probe->dofpr_nenoffs);
+ for (i = 0; i < num_enablers; i++)
+ {
+ struct dtrace_probe_enabler enabler;
+ uint32_t enabler_offset
+ = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
+
+ enabler.address = DOF_UINT (dof, probe->dofpr_addr)
+ + DOF_UINT (dof, enabler_offset);
+ VEC_safe_push (dtrace_probe_enabler_s, enablers, &enabler);
+ }
+
+ for (i = 0; i < num_probes; i++)
+ {
+ uint32_t probe_offset
+ = ((uint32_t *) offtab)[DOF_UINT (dof, probe->dofpr_offidx) + i];
+ struct dtrace_probe *ret
+ = obstack_alloc (&objfile->per_bfd->storage_obstack, sizeof (*ret));
+
+ ret->p.pops = &dtrace_probe_ops;
+ ret->p.arch = gdbarch;
+ ret->args_expr_built = 0;
+
+ /* Set the provider and the name of the probe. */
+ ret->p.provider
+ = xstrdup (strtab + DOF_UINT (dof, provider->dofpv_name));
+ ret->p.name = xstrdup (strtab + DOF_UINT (dof, probe->dofpr_name));
+
+ /* The probe address. */
+ ret->p.address
+ = DOF_UINT (dof, probe->dofpr_addr) + DOF_UINT (dof, probe_offset);
+
+ /* Number of arguments in the probe. */
+ ret->probe_argc = DOF_UINT (dof, probe->dofpr_nargc);
+
+ /* Store argument type descriptions. A description of the type
+ of the argument is in the (J+1)th null-terminated string
+ starting at 'strtab' + 'probe->dofpr_nargv'. */
+ ret->args = NULL;
+ p = strtab + DOF_UINT (dof, probe->dofpr_nargv);
+ for (j = 0; j < ret->probe_argc; j++)
+ {
+ struct dtrace_probe_arg arg;
+ struct expression *expr;
+
+ arg.type_str = xstrdup (p);
+
+ /* Use strtab_size as a sentinel. */
+ while (*p++ != '\0' && p - strtab < strtab_size);
+
+ /* Try to parse a type expression from the type string. If
+ this does not work then we set the type to `long
+ int'. */
+ arg.type = builtin_type (gdbarch)->builtin_long;
+ expr = parse_expression (arg.type_str);
+ if (expr->elts[0].opcode == OP_TYPE)
+ arg.type = expr->elts[1].type;
+
+ VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
+ }
+
+ /* Add the vector of enablers to this probe, if any. */
+ ret->enablers = VEC_copy (dtrace_probe_enabler_s, enablers);
+
+ /* Successfully created probe. */
+ VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* Helper function to collect the probes described in the DOF program
+ whose header is pointed by DOF and add them to the PROBESP vector.
+ SECT is the ELF section containing the DOF program and OBJFILE is
+ its containing object file. */
+
+static void
+dtrace_process_dof (asection *sect, struct objfile *objfile,
+ VEC (probe_p) **probesp, struct dtrace_dof_hdr *dof)
+{
+ bfd *abfd = objfile->obfd;
+ int size = bfd_get_arch_size (abfd) / 8;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ struct dtrace_dof_sect *section;
+ int i;
+
+ /* The first step is to check for the DOF magic number. If no valid
+ DOF data is found in the section then a complaint is issued to
+ the user and the section skipped. */
+ if (dof->dofh_ident[DTRACE_DOF_ID_MAG0] != 0x7F
+ || dof->dofh_ident[DTRACE_DOF_ID_MAG1] != 'D'
+ || dof->dofh_ident[DTRACE_DOF_ID_MAG2] != 'O'
+ || dof->dofh_ident[DTRACE_DOF_ID_MAG3] != 'F')
+ goto invalid_dof_data;
+
+ /* Make sure the encoding mark is either DTRACE_DOF_ENCODE_LSB or
+ DTRACE_DOF_ENCODE_MSB. */
+ if (dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_LSB
+ && dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_MSB)
+ goto invalid_dof_data;
+
+ /* Make sure this DOF is not an enabling DOF, i.e. there are no ECB
+ Description sections. */
+ section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
+ DOF_UINT (dof, dof->dofh_secoff));
+ for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
+ if (section->dofs_type == DTRACE_DOF_SECT_TYPE_ECBDESC)
+ return;
+
+ /* Iterate over any section of type Provider and extract the probe
+ information from them. If there are no "provider" sections on
+ the DOF then we just return. */
+ section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
+ DOF_UINT (dof, dof->dofh_secoff));
+ for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
+ if (DOF_UINT (dof, section->dofs_type) == DTRACE_DOF_SECT_TYPE_PROVIDER)
+ {
+ struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
+ DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
+ struct dtrace_dof_sect *strtab_s
+ = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_strtab));
+ struct dtrace_dof_sect *probes_s
+ = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_probes));
+ struct dtrace_dof_sect *args_s
+ = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prargs));
+ struct dtrace_dof_sect *offsets_s
+ = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_proffs));
+ struct dtrace_dof_sect *eoffsets_s
+ = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prenoffs));
+ char *strtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, strtab_s->dofs_offset));
+ char *offtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, offsets_s->dofs_offset));
+ char *eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
+ char *argtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, args_s->dofs_offset));
+ unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
+ int num_probes;
+
+ /* Very, unlikely, but could crash gdb if not handled
+ properly. */
+ if (entsize == 0)
+ goto invalid_dof_data;
+
+ num_probes = DOF_UINT (dof, probes_s->dofs_size) / entsize;
+
+ for (i = 0; i < num_probes; i++)
+ {
+ struct dtrace_dof_probe *probe = (struct dtrace_dof_probe *)
+ DTRACE_DOF_PTR (dof, DOF_UINT (dof, probes_s->dofs_offset)
+ + (i * DOF_UINT (dof, probes_s->dofs_entsize)));
+
+ dtrace_process_dof_probe (objfile,
+ gdbarch, probesp,
+ dof, probe,
+ provider, strtab, offtab, eofftab, argtab,
+ DOF_UINT (dof, strtab_s->dofs_size));
+ }
+ }
+
+ return;
+
+ invalid_dof_data:
+ complaint (&symfile_complaints,
+ _("skipping section '%s' which does not contain valid DOF data."),
+ sect->name);
+}
+
+/* Helper function to build the GDB internal expressiosn that, once
+ evaluated, will calculate the values of the arguments of a given
+ PROBE. */
+
+static void
+dtrace_build_arg_exprs (struct dtrace_probe *probe,
+ struct gdbarch *gdbarch)
+{
+ struct parser_state pstate;
+ struct dtrace_probe_arg *arg;
+ int i;
+
+ probe->args_expr_built = 1;
+
+ /* Iterate over the arguments in the probe and build the
+ corresponding GDB internal expression that will generate the
+ value of the argument when executed at the PC of the probe. */
+ for (i = 0; i < probe->probe_argc; i++)
+ {
+ struct cleanup *back_to;
+
+ arg = VEC_index (dtrace_probe_arg_s, probe->args, i);
+
+ /* Initialize the expression buffer in the parser state. The
+ language does not matter, since we are using our own
+ parser. */
+ initialize_expout (&pstate, 10, current_language, gdbarch);
+ back_to = make_cleanup (free_current_contents, &pstate.expout);
+
+ /* The argument value, which is ABI dependent and casted to
+ `long int'. */
+ gdbarch_dtrace_parse_probe_argument (gdbarch, &pstate, i);
+
+ discard_cleanups (back_to);
+
+ /* Casting to the expected type, but only if the type was
+ recognized at probe load time. Otherwise the argument will
+ be evaluated as the long integer passed to the probe. */
+ if (arg->type != NULL)
+ {
+ write_exp_elt_opcode (&pstate, UNOP_CAST);
+ write_exp_elt_type (&pstate, arg->type);
+ write_exp_elt_opcode (&pstate, UNOP_CAST);
+ }
+
+ reallocate_expout (&pstate);
+ arg->expr = pstate.expout;
+ prefixify_expression (arg->expr);
+ }
+}
+
+/* Helper function to return the Nth argument of a given PROBE. */
+
+static struct dtrace_probe_arg *
+dtrace_get_arg (struct dtrace_probe *probe, unsigned n,
+ struct gdbarch *gdbarch)
+{
+ if (!probe->args_expr_built)
+ dtrace_build_arg_exprs (probe, gdbarch);
+
+ return VEC_index (dtrace_probe_arg_s, probe->args, n);
+}
+
+/* Implementation of the get_probes method. */
+
+static void
+dtrace_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ asection *sect = NULL;
+
+ /* Do nothing in case this is a .debug file, instead of the objfile
+ itself. */
+ if (objfile->separate_debug_objfile_backlink != NULL)
+ return;
+
+ /* Iterate over the sections in OBJFILE looking for DTrace
+ information. */
+ for (sect = abfd->sections; sect != NULL; sect = sect->next)
+ {
+ if (elf_section_data (sect)->this_hdr.sh_type == SHT_SUNW_dof)
+ {
+ struct dtrace_dof_hdr *dof;
+
+ /* Read the contents of the DOF section and then process it to
+ extract the information of any probe defined into it. */
+ if (!bfd_malloc_and_get_section (abfd, sect, (bfd_byte **) &dof))
+ complaint (&symfile_complaints,
+ _("could not obtain the contents of"
+ "section '%s' in objfile `%s'."),
+ sect->name, abfd->filename);
+
+ dtrace_process_dof (sect, objfile, probesp, dof);
+ xfree (dof);
+ }
+ }
+}
+
+/* Helper function to determine whether a given probe is "enabled" or
+ "disabled". A disabled probe is a probe in which one or more
+ enablers are disabled. */
+
+static int
+dtrace_probe_is_enabled (struct dtrace_probe *probe)
+{
+ int i;
+ struct gdbarch *gdbarch = probe->p.arch;
+ struct dtrace_probe_enabler *enabler;
+
+ for (i = 0;
+ VEC_iterate (dtrace_probe_enabler_s, probe->enablers, i, enabler);
+ i++)
+ if (!gdbarch_dtrace_probe_is_enabled (gdbarch, enabler->address))
+ return 0;
+
+ return 1;
+}
+
+/* Implementation of the get_probe_address method. */
+
+static CORE_ADDR
+dtrace_get_probe_address (struct probe *probe, struct objfile *objfile)
+{
+ gdb_assert (probe->pops == &dtrace_probe_ops);
+ return probe->address + ANOFFSET (objfile->section_offsets,
+ SECT_OFF_DATA (objfile));
+}
+
+/* Implementation of the get_probe_argument_count method. */
+
+static unsigned
+dtrace_get_probe_argument_count (struct probe *probe_generic,
+ struct frame_info *frame)
+{
+ struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+ return dtrace_probe->probe_argc;
+}
+
+/* Implementation of the can_evaluate_probe_arguments method. */
+
+static int
+dtrace_can_evaluate_probe_arguments (struct probe *probe_generic)
+{
+ struct gdbarch *gdbarch = probe_generic->arch;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+ return gdbarch_dtrace_parse_probe_argument_p (gdbarch);
+}
+
+/* Implementation of the evaluate_probe_argument method. */
+
+static struct value *
+dtrace_evaluate_probe_argument (struct probe *probe_generic, unsigned n,
+ struct frame_info *frame)
+{
+ struct gdbarch *gdbarch = probe_generic->arch;
+ struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+ struct dtrace_probe_arg *arg;
+ int pos = 0;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+ arg = dtrace_get_arg (dtrace_probe, n, gdbarch);
+ return evaluate_subexp_standard (arg->type, arg->expr, &pos, EVAL_NORMAL);
+}
+
+/* Implementation of the compile_to_ax method. */
+
+static void
+dtrace_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr,
+ struct axs_value *value, unsigned n)
+{
+ struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
+ struct dtrace_probe_arg *arg;
+ union exp_element *pc;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+ arg = dtrace_get_arg (dtrace_probe, n, expr->gdbarch);
+
+ pc = arg->expr->elts;
+ gen_expr (arg->expr, &pc, expr, value);
+
+ require_rvalue (expr, value);
+ value->type = arg->type;
+}
+
+/* Implementation of the probe_destroy method. */
+
+static void
+dtrace_probe_destroy (struct probe *probe_generic)
+{
+ struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
+ struct dtrace_probe_arg *arg;
+ int i;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+ for (i = 0; VEC_iterate (dtrace_probe_arg_s, probe->args, i, arg); i++)
+ {
+ xfree (arg->type_str);
+ xfree (arg->expr);
+ }
+
+ VEC_free (dtrace_probe_enabler_s, probe->enablers);
+ VEC_free (dtrace_probe_arg_s, probe->args);
+}
+
+/* Implementation of the type_name method. */
+
+static const char *
+dtrace_type_name (struct probe *probe_generic)
+{
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+ return "dtrace";
+}
+
+/* Implementation of the gen_info_probes_table_header method. */
+
+static void
+dtrace_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
+{
+ info_probe_column_s dtrace_probe_column;
+
+ dtrace_probe_column.field_name = "enabled";
+ dtrace_probe_column.print_name = _("Enabled");
+
+ VEC_safe_push (info_probe_column_s, *heads, &dtrace_probe_column);
+}
+
+/* Implementation of the gen_info_probes_table_values method. */
+
+static void
+dtrace_gen_info_probes_table_values (struct probe *probe_generic,
+ VEC (const_char_ptr) **ret)
+{
+ struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
+ const char *val = NULL;
+
+ gdb_assert (probe_generic->pops == &dtrace_probe_ops);
+
+ if (VEC_empty (dtrace_probe_enabler_s, probe->enablers))
+ val = "always";
+ else if (!gdbarch_dtrace_probe_is_enabled_p (probe_generic->arch))
+ val = "unknown";
+ else if (dtrace_probe_is_enabled (probe))
+ val = "yes";
+ else
+ val = "no";
+
+ VEC_safe_push (const_char_ptr, *ret, val);
+}
+
+/* Implementation of the enable_probe method. */
+
+static void
+dtrace_enable_probe (struct probe *probe)
+{
+ struct gdbarch *gdbarch = probe->arch;
+ struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
+ struct dtrace_probe_enabler *enabler;
+ int i;
+
+ gdb_assert (probe->pops == &dtrace_probe_ops);
+
+ /* Enabling a dtrace probe implies patching the text section of the
+ running process, so make sure the inferior is indeed running. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No inferior running"));
+
+ /* Fast path. */
+ if (dtrace_probe_is_enabled (dtrace_probe))
+ return;
+
+ /* Iterate over all defined enabler in the given probe and enable
+ them all using the corresponding gdbarch hook. */
+
+ for (i = 0;
+ VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
+ i++)
+ if (gdbarch_dtrace_enable_probe_p (gdbarch))
+ gdbarch_dtrace_enable_probe (gdbarch, enabler->address);
+}
+
+
+/* Implementation of the disable_probe method. */
+
+static void
+dtrace_disable_probe (struct probe *probe)
+{
+ struct gdbarch *gdbarch = probe->arch;
+ struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
+ struct dtrace_probe_enabler *enabler;
+ int i;
+
+ gdb_assert (probe->pops == &dtrace_probe_ops);
+
+ /* Disabling a dtrace probe implies patching the text section of the
+ running process, so make sure the inferior is indeed running. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No inferior running"));
+
+ /* Fast path. */
+ if (!dtrace_probe_is_enabled (dtrace_probe))
+ return;
+
+ /* Are we trying to disable a probe that does not have any enabler
+ associated? */
+ if (VEC_empty (dtrace_probe_enabler_s, dtrace_probe->enablers))
+ error (_("Probe %s:%s cannot be disabled."), probe->provider, probe->name);
+
+ /* Iterate over all defined enabler in the given probe and disable
+ them all using the corresponding gdbarch hook. */
+
+ for (i = 0;
+ VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
+ i++)
+ {
+ if (gdbarch_dtrace_disable_probe_p (gdbarch))
+ gdbarch_dtrace_disable_probe (gdbarch, enabler->address);
+ }
+}
+
+/* DTrace probe_ops. */
+
+static const struct probe_ops dtrace_probe_ops =
+{
+ dtrace_probe_is_linespec,
+ dtrace_get_probes,
+ dtrace_get_probe_address,
+ dtrace_get_probe_argument_count,
+ dtrace_can_evaluate_probe_arguments,
+ dtrace_evaluate_probe_argument,
+ dtrace_compile_to_ax,
+ NULL, /* set_semaphore */
+ NULL, /* clear_semaphore */
+ dtrace_probe_destroy,
+ dtrace_type_name,
+ dtrace_gen_info_probes_table_header,
+ dtrace_gen_info_probes_table_values,
+ dtrace_enable_probe,
+ dtrace_disable_probe
+};
+
+/* Implementation of the `info probes dtrace' command. */
+
+static void
+info_probes_dtrace_command (char *arg, int from_tty)
+{
+ info_probes_for_ops (arg, from_tty, &dtrace_probe_ops);
+}
+
+void _initialize_dtrace_probe (void);
+
+void
+_initialize_dtrace_probe (void)
+{
+ VEC_safe_push (probe_ops_cp, all_probe_ops, &dtrace_probe_ops);
+
+ add_cmd ("dtrace", class_info, info_probes_dtrace_command,
+ _("\
+Show information about DTrace static probes.\n\
+Usage: info probes dtrace [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name."),
+ info_probes_cmdlist_get ());
+}
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 5/9] New probe type: DTrace USDT probes.
2014-10-28 13:45 ` [PATCH V3 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
@ 2014-10-31 20:03 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 20:03 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch adds a new type of probe to GDB: the DTrace USDT probes. The new
> type is added by providing functions implementing all the entries of the
> `probe_ops' structure defined in `probe.h'. The implementation is
> self-contained and does not depend on DTrace source code in any way.
Thanks! I skimmed through the patch and did not see anything wrong with
it. It seems to be in a much better shape than the first version, and
I'm happy with it. I just want to take some more time to look deeper
into the details, but so far, so good.
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * breakpoint.c (BREAK_ARGS_HELP): help string updated to mention
> the -probe-dtrace new vpossible value for PROBE_MODIFIER.
> * configure.ac (CONFIG_OBS): dtrace-probe.o added if BFD can
> handle ELF files.
> * Makefile.in (SFILES): dtrace-probe.c added.
> * configure: Regenerate.
> * dtrace-probe.c: New file.
> (SHT_SUNW_dof): New constant.
> (dtrace_probe_type): New enum.
> (dtrace_probe_arg): New struct.
> (dtrace_probe_arg_s): New typedef.
> (struct dtrace_probe_enabler): New struct.
> (dtrace_probe_enabler_s): New typedef.
> (dtrace_probe): New struct.
> (dtrace_probe_is_linespec): New function.
> (dtrace_dof_sect_type): New enum.
> (dtrace_dof_dofh_ident): Likewise.
> (dtrace_dof_encoding): Likewise.
> (DTRACE_DOF_ENCODE_LSB): Likewise.
> (DTRACE_DOF_ENCODE_MSB): Likewise.
> (dtrace_dof_hdr): New struct.
> (dtrace_dof_sect): Likewise.
> (dtrace_dof_provider): Likewise.
> (dtrace_dof_probe): Likewise.
> (DOF_UINT): New macro.
> (DTRACE_DOF_PTR): Likewise.
> (DTRACE_DOF_SECT): Likewise.
> (dtrace_process_dof_probe): New function.
> (dtrace_process_dof): Likewise.
> (dtrace_build_arg_exprs): Likewise.
> (dtrace_get_arg): Likewise.
> (dtrace_get_probes): Likewise.
> (dtrace_get_probe_argument_count): Likewise.
> (dtrace_can_evaluate_probe_arguments): Likewise.
> (dtrace_evaluate_probe_argument): Likewise.
> (dtrace_compile_to_ax): Likewise.
> (dtrace_probe_destroy): Likewise.
> (dtrace_gen_info_probes_table_header): Likewise.
> (dtrace_gen_info_probes_table_values): Likewise.
> (dtrace_probe_is_enabled): Likewise.
> (dtrace_probe_ops): New variable.
> (info_probes_dtrace_command): New function.
> (_initialize_dtrace_probe): Likewise.
> (dtrace_type_name): Likewise.
> ---
> gdb/ChangeLog | 47 +++
> gdb/Makefile.in | 3 +-
> gdb/breakpoint.c | 3 +-
> gdb/configure | 2 +-
> gdb/configure.ac | 2 +-
> gdb/dtrace-probe.c | 909 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 962 insertions(+), 4 deletions(-)
> create mode 100644 gdb/dtrace-probe.c
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 1da8af6..a237a1f 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -800,7 +800,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
> cp-abi.c cp-support.c cp-namespace.c cp-valprint.c \
> d-exp.y d-lang.c d-valprint.c \
> cp-name-parser.y \
> - dbxread.c demangle.c dictionary.c disasm.c doublest.c dummy-frame.c \
> + dbxread.c demangle.c dictionary.c disasm.c doublest.c \
> + dtrace-probe.c dummy-frame.c \
> dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
> dwarf2-frame-tailcall.c \
> elfread.c environ.c eval.c event-loop.c event-top.c \
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index cab6c56..ebaa9ce 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -15998,7 +15998,8 @@ all_tracepoints (void)
> command" [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] [if CONDITION]\n\
> PROBE_MODIFIER shall be present if the command is to be placed in a\n\
> probe point. Accepted values are `-probe' (for a generic, automatically\n\
> -guessed probe type) or `-probe-stap' (for a SystemTap probe).\n\
> +guessed probe type), `-probe-stap' (for a SystemTap probe) or \n\
> +`-probe-dtrace' (for a DTrace probe).\n\
> LOCATION may be a line number, function name, or \"*\" and an address.\n\
> If a line number is specified, break at start of code for that line.\n\
> If a function is specified, break at start of code for that function.\n\
> diff --git a/gdb/configure b/gdb/configure
> index 1d6d88b..a1660bc 100755
> --- a/gdb/configure
> +++ b/gdb/configure
> @@ -13241,7 +13241,7 @@ $as_echo "$gdb_cv_var_elf" >&6; }
> LDFLAGS=$OLD_LDFLAGS
> LIBS=$OLD_LIBS
> if test $gdb_cv_var_elf = yes; then
> - CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
> + CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
>
> $as_echo "#define HAVE_ELF 1" >>confdefs.h
>
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index 2d73669..4ac5f7b 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -2063,7 +2063,7 @@ AC_SUBST(WIN32LIBS)
> GDB_AC_CHECK_BFD([for ELF support in BFD], gdb_cv_var_elf,
> [bfd_get_elf_phdr_upper_bound (NULL)], elf-bfd.h)
> if test $gdb_cv_var_elf = yes; then
> - CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
> + CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o dtrace-probe.o"
> AC_DEFINE(HAVE_ELF, 1,
> [Define if ELF support should be included.])
> # -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.
> diff --git a/gdb/dtrace-probe.c b/gdb/dtrace-probe.c
> new file mode 100644
> index 0000000..f4bfc70
> --- /dev/null
> +++ b/gdb/dtrace-probe.c
> @@ -0,0 +1,909 @@
> +/* DTrace probe support for GDB.
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + Contributed by Oracle, 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/>. */
> +
> +#include "defs.h"
> +#include "probe.h"
> +#include "vec.h"
> +#include "elf-bfd.h"
> +#include "gdbtypes.h"
> +#include "obstack.h"
> +#include "objfiles.h"
> +#include "complaints.h"
> +#include "value.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
> +#include "language.h"
> +#include "parser-defs.h"
> +#include "inferior.h"
> +
> +/* The type of the ELF sections where we will find the DOF programs
> + with information about probes. */
> +
> +#ifndef SHT_SUNW_dof
> +# define SHT_SUNW_dof 0x6ffffff4
> +#endif
> +
> +/* Forward declaration. */
> +
> +static const struct probe_ops dtrace_probe_ops;
> +
> +/* The following structure represents a single argument for the
> + probe. */
> +
> +struct dtrace_probe_arg
> +{
> + /* The type of the probe argument. */
> + struct type *type;
> +
> + /* A string describing the type. */
> + char *type_str;
> +
> + /* The argument converted to an internal GDB expression. */
> + struct expression *expr;
> +};
> +
> +typedef struct dtrace_probe_arg dtrace_probe_arg_s;
> +DEF_VEC_O (dtrace_probe_arg_s);
> +
> +/* The following structure represents an enabler for a probe. */
> +
> +struct dtrace_probe_enabler
> +{
> + /* Program counter where the is-enabled probe is installed. The
> + contents (nops, whatever...) stored at this address are
> + architecture dependent. */
> + CORE_ADDR address;
> +};
> +
> +typedef struct dtrace_probe_enabler dtrace_probe_enabler_s;
> +DEF_VEC_O (dtrace_probe_enabler_s);
> +
> +/* The following structure represents a dtrace probe. */
> +
> +struct dtrace_probe
> +{
> + /* Generic information about the probe. This must be the first
> + element of this struct, in order to maintain binary compatibility
> + with the `struct probe' and be able to fully abstract it. */
> + struct probe p;
> +
> + /* A probe can have zero or more arguments. */
> + int probe_argc;
> + VEC (dtrace_probe_arg_s) *args;
> +
> + /* A probe can have zero or more "enablers" associated with it. */
> + VEC (dtrace_probe_enabler_s) *enablers;
> +
> + /* Whether the expressions for the arguments have been built. */
> + unsigned int args_expr_built : 1;
> +};
> +
> +/* Implementation of the probe_is_linespec method. */
> +
> +static int
> +dtrace_probe_is_linespec (const char **linespecp)
> +{
> + static const char *const keywords[] = { "-pdtrace", "-probe-dtrace", NULL };
> +
> + return probe_is_linespec_by_keyword (linespecp, keywords);
> +}
> +
> +/* DOF programs can contain an arbitrary number of sections of 26
> + different types. In order to support DTrace USDT probes we only
> + need to handle a subset of these section types, fortunately. These
> + section types are defined in the following enumeration.
> +
> + See linux/dtrace/dof_defines.h for a complete list of section types
> + along with their values. */
> +
> +enum dtrace_dof_sect_type
> +{
> + /* Null section. */
> + DTRACE_DOF_SECT_TYPE_NONE = 0,
> + /* A dof_ecbdesc_t. */
> + DTRACE_DOF_SECT_TYPE_ECBDESC = 3,
> + /* A string table. */
> + DTRACE_DOF_SECT_TYPE_STRTAB = 8,
> + /* A dof_provider_t */
> + DTRACE_DOF_SECT_TYPE_PROVIDER = 15,
> + /* Array of dof_probe_t */
> + DTRACE_DOF_SECT_TYPE_PROBES = 16,
> + /* An array of probe arg mappings. */
> + DTRACE_DOF_SECT_TYPE_PRARGS = 17,
> + /* An array of probe arg offsets. */
> + DTRACE_DOF_SECT_TYPE_PROFFS = 18,
> + /* An array of probe is-enabled offsets. */
> + DTRACE_DOF_SECT_TYPE_PRENOFFS = 26
> +};
> +
> +/* The following collection of data structures map the structure of
> + DOF entities. Again, we only cover the subset of DOF used to
> + implement USDT probes.
> +
> + See linux/dtrace/dof.h header for a complete list of data
> + structures. */
> +
> +/* Offsets to index the dofh_ident[] array defined below. */
> +
> +enum dtrace_dof_ident
> +{
> + /* First byte of the magic number. */
> + DTRACE_DOF_ID_MAG0 = 0,
> + /* Second byte of the magic number. */
> + DTRACE_DOF_ID_MAG1 = 1,
> + /* Third byte of the magic number. */
> + DTRACE_DOF_ID_MAG2 = 2,
> + /* Fourth byte of the magic number. */
> + DTRACE_DOF_ID_MAG3 = 3,
> + /* An enum_dof_encoding value. */
> + DTRACE_DOF_ID_ENCODING = 5
> +};
> +
> +/* Possible values for dofh_ident[DOF_ID_ENCODING]. */
> +
> +enum dtrace_dof_encoding
> +{
> + /* The DOF program is little-endian. */
> + DTRACE_DOF_ENCODE_LSB = 1,
> + /* The DOF program is big-endian. */
> + DTRACE_DOF_ENCODE_MSB = 2
> +};
> +
> +/* A DOF header, which describes the contents of a DOF program: number
> + of sections, size, etc. */
> +
> +struct dtrace_dof_hdr
> +{
> + /* Identification bytes (see above). */
> + uint8_t dofh_ident[16];
> + /* File attribute flags (if any). */
> + uint32_t dofh_flags;
> + /* Size of file header in bytes. */
> + uint32_t dofh_hdrsize;
> + /* Size of section header in bytes. */
> + uint32_t dofh_secsize;
> + /* Number of section headers. */
> + uint32_t dofh_secnum;
> + /* File offset of section headers. */
> + uint64_t dofh_secoff;
> + /* File size of loadable portion. */
> + uint64_t dofh_loadsz;
> + /* File size of entire DOF file. */
> + uint64_t dofh_filesz;
> + /* Reserved for future use. */
> + uint64_t dofh_pad;
> +};
> +
> +/* A DOF section, whose contents depend on its type. The several
> + supported section types are described in the enum
> + dtrace_dof_sect_type above. */
> +
> +struct dtrace_dof_sect
> +{
> + /* Section type (see the define above). */
> + uint32_t dofs_type;
> + /* Section data memory alignment. */
> + uint32_t dofs_align;
> + /* Section flags (if any). */
> + uint32_t dofs_flags;
> + /* Size of section entry (if table). */
> + uint32_t dofs_entsize;
> + /* DOF + offset points to the section data. */
> + uint64_t dofs_offset;
> + /* Size of section data in bytes. */
> + uint64_t dofs_size;
> +};
> +
> +/* A DOF provider, which is the provider of a probe. */
> +
> +struct dtrace_dof_provider
> +{
> + /* Link to a DTRACE_DOF_SECT_TYPE_STRTAB section. */
> + uint32_t dofpv_strtab;
> + /* Link to a DTRACE_DOF_SECT_TYPE_PROBES section. */
> + uint32_t dofpv_probes;
> + /* Link to a DTRACE_DOF_SECT_TYPE_PRARGS section. */
> + uint32_t dofpv_prargs;
> + /* Link to a DTRACE_DOF_SECT_TYPE_PROFFS section. */
> + uint32_t dofpv_proffs;
> + /* Provider name string. */
> + uint32_t dofpv_name;
> + /* Provider attributes. */
> + uint32_t dofpv_provattr;
> + /* Module attributes. */
> + uint32_t dofpv_modattr;
> + /* Function attributes. */
> + uint32_t dofpv_funcattr;
> + /* Name attributes. */
> + uint32_t dofpv_nameattr;
> + /* Args attributes. */
> + uint32_t dofpv_argsattr;
> + /* Link to a DTRACE_DOF_SECT_PRENOFFS section. */
> + uint32_t dofpv_prenoffs;
> +};
> +
> +/* A set of DOF probes and is-enabled probes sharing a base address
> + and several attributes. The particular locations and attributes of
> + each probe are maintained in arrays in several other DOF sections.
> + See the comment in dtrace_process_dof_probe for details on how
> + these attributes are stored. */
> +
> +struct dtrace_dof_probe
> +{
> + /* Probe base address or offset. */
> + uint64_t dofpr_addr;
> + /* Probe function string. */
> + uint32_t dofpr_func;
> + /* Probe name string. */
> + uint32_t dofpr_name;
> + /* Native argument type strings. */
> + uint32_t dofpr_nargv;
> + /* Translated argument type strings. */
> + uint32_t dofpr_xargv;
> + /* Index of first argument mapping. */
> + uint32_t dofpr_argidx;
> + /* Index of first offset entry. */
> + uint32_t dofpr_offidx;
> + /* Native argument count. */
> + uint8_t dofpr_nargc;
> + /* Translated argument count. */
> + uint8_t dofpr_xargc;
> + /* Number of offset entries for probe. */
> + uint16_t dofpr_noffs;
> + /* Index of first is-enabled offset. */
> + uint32_t dofpr_enoffidx;
> + /* Number of is-enabled offsets. */
> + uint16_t dofpr_nenoffs;
> + /* Reserved for future use. */
> + uint16_t dofpr_pad1;
> + /* Reserved for future use. */
> + uint32_t dofpr_pad2;
> +};
> +
> +/* DOF supports two different encodings: MSB (big-endian) and LSB
> + (little-endian). The encoding is itself encoded in the DOF header.
> + The following function returns an unsigned value in the host
> + endianness. */
> +
> +#define DOF_UINT(dof, field) \
> + extract_unsigned_integer ((gdb_byte *) &(field), \
> + sizeof ((field)), \
> + (((dof)->dofh_ident[DTRACE_DOF_ID_ENCODING] \
> + == DTRACE_DOF_ENCODE_MSB) \
> + ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE))
> +
> +/* The following macro applies a given byte offset to a DOF (a pointer
> + to a dtrace_dof_hdr structure) and returns the resulting
> + address. */
> +
> +#define DTRACE_DOF_PTR(dof, offset) (&((char *) (dof))[(offset)])
> +
> +/* The following macro returns a pointer to the beginning of a given
> + section in a DOF object. The section is referred to by its index
> + in the sections array. */
> +
> +#define DTRACE_DOF_SECT(dof, idx) \
> + ((struct dtrace_dof_sect *) \
> + DTRACE_DOF_PTR ((dof), \
> + DOF_UINT ((dof), (dof)->dofh_secoff) \
> + + ((idx) * DOF_UINT ((dof), (dof)->dofh_secsize))))
> +
> +/* Helper function to examine the probe described by the given PROBE
> + and PROVIDER data structures and add it to the PROBESP vector.
> + STRTAB, OFFTAB, EOFFTAB and ARGTAB are pointers to tables in the
> + DOF program containing the attributes for the probe. */
> +
> +static void
> +dtrace_process_dof_probe (struct objfile *objfile,
> + struct gdbarch *gdbarch, VEC (probe_p) **probesp,
> + struct dtrace_dof_hdr *dof,
> + struct dtrace_dof_probe *probe,
> + struct dtrace_dof_provider *provider,
> + char *strtab, char *offtab, char *eofftab,
> + char *argtab, uint64_t strtab_size)
> +{
> + int i, j, num_probes, num_enablers;
> + struct cleanup *cleanup;
> + VEC (dtrace_probe_enabler_s) *enablers;
> + char *p;
> +
> + /* Each probe section can define zero or more probes of two
> + different types:
> +
> + - probe->dofpr_noffs regular probes whose program counters are
> + stored in 32bit words starting at probe->dofpr_addr +
> + offtab[probe->dofpr_offidx].
> +
> + - probe->dofpr_nenoffs is-enabled probes whose program counters
> + are stored in 32bit words starting at probe->dofpr_addr +
> + eofftab[probe->dofpr_enoffidx].
> +
> + However is-enabled probes are not probes per-se, but an
> + optimization hack that is implemented in the kernel in a very
> + similar way than normal probes. This is how we support
> + is-enabled probes on GDB:
> +
> + - Our probes are always DTrace regular probes.
> +
> + - Our probes can be associated with zero or more "enablers". The
> + list of enablers is built from the is-enabled probes defined in
> + the Probe section.
> +
> + - Probes having a non-empty list of enablers can be enabled or
> + disabled using the `enable probe' and `disable probe' commands
> + respectively. The `Enabled' column in the output of `info
> + probes' will read `yes' if the enablers are activated, `no'
> + otherwise.
> +
> + - Probes having an empty list of enablers are always enabled.
> + The `Enabled' column in the output of `info probes' will
> + read `always'.
> +
> + It follows that if there are DTrace is-enabled probes defined for
> + some provider/name but no DTrace regular probes defined then the
> + GDB user wont be able to enable/disable these conditionals. */
> +
> + num_probes = DOF_UINT (dof, probe->dofpr_noffs);
> + if (num_probes == 0)
> + return;
> +
> + /* Build the list of enablers for the probes defined in this Probe
> + DOF section. */
> + enablers = NULL;
> + cleanup
> + = make_cleanup (VEC_cleanup (dtrace_probe_enabler_s), &enablers);
> + num_enablers = DOF_UINT (dof, probe->dofpr_nenoffs);
> + for (i = 0; i < num_enablers; i++)
> + {
> + struct dtrace_probe_enabler enabler;
> + uint32_t enabler_offset
> + = ((uint32_t *) eofftab)[DOF_UINT (dof, probe->dofpr_enoffidx) + i];
> +
> + enabler.address = DOF_UINT (dof, probe->dofpr_addr)
> + + DOF_UINT (dof, enabler_offset);
> + VEC_safe_push (dtrace_probe_enabler_s, enablers, &enabler);
> + }
> +
> + for (i = 0; i < num_probes; i++)
> + {
> + uint32_t probe_offset
> + = ((uint32_t *) offtab)[DOF_UINT (dof, probe->dofpr_offidx) + i];
> + struct dtrace_probe *ret
> + = obstack_alloc (&objfile->per_bfd->storage_obstack, sizeof (*ret));
> +
> + ret->p.pops = &dtrace_probe_ops;
> + ret->p.arch = gdbarch;
> + ret->args_expr_built = 0;
> +
> + /* Set the provider and the name of the probe. */
> + ret->p.provider
> + = xstrdup (strtab + DOF_UINT (dof, provider->dofpv_name));
> + ret->p.name = xstrdup (strtab + DOF_UINT (dof, probe->dofpr_name));
> +
> + /* The probe address. */
> + ret->p.address
> + = DOF_UINT (dof, probe->dofpr_addr) + DOF_UINT (dof, probe_offset);
> +
> + /* Number of arguments in the probe. */
> + ret->probe_argc = DOF_UINT (dof, probe->dofpr_nargc);
> +
> + /* Store argument type descriptions. A description of the type
> + of the argument is in the (J+1)th null-terminated string
> + starting at 'strtab' + 'probe->dofpr_nargv'. */
> + ret->args = NULL;
> + p = strtab + DOF_UINT (dof, probe->dofpr_nargv);
> + for (j = 0; j < ret->probe_argc; j++)
> + {
> + struct dtrace_probe_arg arg;
> + struct expression *expr;
> +
> + arg.type_str = xstrdup (p);
> +
> + /* Use strtab_size as a sentinel. */
> + while (*p++ != '\0' && p - strtab < strtab_size);
> +
> + /* Try to parse a type expression from the type string. If
> + this does not work then we set the type to `long
> + int'. */
> + arg.type = builtin_type (gdbarch)->builtin_long;
> + expr = parse_expression (arg.type_str);
> + if (expr->elts[0].opcode == OP_TYPE)
> + arg.type = expr->elts[1].type;
> +
> + VEC_safe_push (dtrace_probe_arg_s, ret->args, &arg);
> + }
> +
> + /* Add the vector of enablers to this probe, if any. */
> + ret->enablers = VEC_copy (dtrace_probe_enabler_s, enablers);
> +
> + /* Successfully created probe. */
> + VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
> + }
> +
> + do_cleanups (cleanup);
> +}
> +
> +/* Helper function to collect the probes described in the DOF program
> + whose header is pointed by DOF and add them to the PROBESP vector.
> + SECT is the ELF section containing the DOF program and OBJFILE is
> + its containing object file. */
> +
> +static void
> +dtrace_process_dof (asection *sect, struct objfile *objfile,
> + VEC (probe_p) **probesp, struct dtrace_dof_hdr *dof)
> +{
> + bfd *abfd = objfile->obfd;
> + int size = bfd_get_arch_size (abfd) / 8;
> + struct gdbarch *gdbarch = get_objfile_arch (objfile);
> + struct dtrace_dof_sect *section;
> + int i;
> +
> + /* The first step is to check for the DOF magic number. If no valid
> + DOF data is found in the section then a complaint is issued to
> + the user and the section skipped. */
> + if (dof->dofh_ident[DTRACE_DOF_ID_MAG0] != 0x7F
> + || dof->dofh_ident[DTRACE_DOF_ID_MAG1] != 'D'
> + || dof->dofh_ident[DTRACE_DOF_ID_MAG2] != 'O'
> + || dof->dofh_ident[DTRACE_DOF_ID_MAG3] != 'F')
> + goto invalid_dof_data;
> +
> + /* Make sure the encoding mark is either DTRACE_DOF_ENCODE_LSB or
> + DTRACE_DOF_ENCODE_MSB. */
> + if (dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_LSB
> + && dof->dofh_ident[DTRACE_DOF_ID_ENCODING] != DTRACE_DOF_ENCODE_MSB)
> + goto invalid_dof_data;
> +
> + /* Make sure this DOF is not an enabling DOF, i.e. there are no ECB
> + Description sections. */
> + section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
> + DOF_UINT (dof, dof->dofh_secoff));
> + for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
> + if (section->dofs_type == DTRACE_DOF_SECT_TYPE_ECBDESC)
> + return;
> +
> + /* Iterate over any section of type Provider and extract the probe
> + information from them. If there are no "provider" sections on
> + the DOF then we just return. */
> + section = (struct dtrace_dof_sect *) DTRACE_DOF_PTR (dof,
> + DOF_UINT (dof, dof->dofh_secoff));
> + for (i = 0; i < DOF_UINT (dof, dof->dofh_secnum); i++, section++)
> + if (DOF_UINT (dof, section->dofs_type) == DTRACE_DOF_SECT_TYPE_PROVIDER)
> + {
> + struct dtrace_dof_provider *provider = (struct dtrace_dof_provider *)
> + DTRACE_DOF_PTR (dof, DOF_UINT (dof, section->dofs_offset));
> + struct dtrace_dof_sect *strtab_s
> + = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_strtab));
> + struct dtrace_dof_sect *probes_s
> + = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_probes));
> + struct dtrace_dof_sect *args_s
> + = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prargs));
> + struct dtrace_dof_sect *offsets_s
> + = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_proffs));
> + struct dtrace_dof_sect *eoffsets_s
> + = DTRACE_DOF_SECT (dof, DOF_UINT (dof, provider->dofpv_prenoffs));
> + char *strtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, strtab_s->dofs_offset));
> + char *offtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, offsets_s->dofs_offset));
> + char *eofftab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, eoffsets_s->dofs_offset));
> + char *argtab = DTRACE_DOF_PTR (dof, DOF_UINT (dof, args_s->dofs_offset));
> + unsigned int entsize = DOF_UINT (dof, probes_s->dofs_entsize);
> + int num_probes;
> +
> + /* Very, unlikely, but could crash gdb if not handled
> + properly. */
> + if (entsize == 0)
> + goto invalid_dof_data;
> +
> + num_probes = DOF_UINT (dof, probes_s->dofs_size) / entsize;
> +
> + for (i = 0; i < num_probes; i++)
> + {
> + struct dtrace_dof_probe *probe = (struct dtrace_dof_probe *)
> + DTRACE_DOF_PTR (dof, DOF_UINT (dof, probes_s->dofs_offset)
> + + (i * DOF_UINT (dof, probes_s->dofs_entsize)));
> +
> + dtrace_process_dof_probe (objfile,
> + gdbarch, probesp,
> + dof, probe,
> + provider, strtab, offtab, eofftab, argtab,
> + DOF_UINT (dof, strtab_s->dofs_size));
> + }
> + }
> +
> + return;
> +
> + invalid_dof_data:
> + complaint (&symfile_complaints,
> + _("skipping section '%s' which does not contain valid DOF data."),
> + sect->name);
> +}
> +
> +/* Helper function to build the GDB internal expressiosn that, once
> + evaluated, will calculate the values of the arguments of a given
> + PROBE. */
> +
> +static void
> +dtrace_build_arg_exprs (struct dtrace_probe *probe,
> + struct gdbarch *gdbarch)
> +{
> + struct parser_state pstate;
> + struct dtrace_probe_arg *arg;
> + int i;
> +
> + probe->args_expr_built = 1;
> +
> + /* Iterate over the arguments in the probe and build the
> + corresponding GDB internal expression that will generate the
> + value of the argument when executed at the PC of the probe. */
> + for (i = 0; i < probe->probe_argc; i++)
> + {
> + struct cleanup *back_to;
> +
> + arg = VEC_index (dtrace_probe_arg_s, probe->args, i);
> +
> + /* Initialize the expression buffer in the parser state. The
> + language does not matter, since we are using our own
> + parser. */
> + initialize_expout (&pstate, 10, current_language, gdbarch);
> + back_to = make_cleanup (free_current_contents, &pstate.expout);
> +
> + /* The argument value, which is ABI dependent and casted to
> + `long int'. */
> + gdbarch_dtrace_parse_probe_argument (gdbarch, &pstate, i);
> +
> + discard_cleanups (back_to);
> +
> + /* Casting to the expected type, but only if the type was
> + recognized at probe load time. Otherwise the argument will
> + be evaluated as the long integer passed to the probe. */
> + if (arg->type != NULL)
> + {
> + write_exp_elt_opcode (&pstate, UNOP_CAST);
> + write_exp_elt_type (&pstate, arg->type);
> + write_exp_elt_opcode (&pstate, UNOP_CAST);
> + }
> +
> + reallocate_expout (&pstate);
> + arg->expr = pstate.expout;
> + prefixify_expression (arg->expr);
> + }
> +}
> +
> +/* Helper function to return the Nth argument of a given PROBE. */
> +
> +static struct dtrace_probe_arg *
> +dtrace_get_arg (struct dtrace_probe *probe, unsigned n,
> + struct gdbarch *gdbarch)
> +{
> + if (!probe->args_expr_built)
> + dtrace_build_arg_exprs (probe, gdbarch);
> +
> + return VEC_index (dtrace_probe_arg_s, probe->args, n);
> +}
> +
> +/* Implementation of the get_probes method. */
> +
> +static void
> +dtrace_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
> +{
> + bfd *abfd = objfile->obfd;
> + asection *sect = NULL;
> +
> + /* Do nothing in case this is a .debug file, instead of the objfile
> + itself. */
> + if (objfile->separate_debug_objfile_backlink != NULL)
> + return;
> +
> + /* Iterate over the sections in OBJFILE looking for DTrace
> + information. */
> + for (sect = abfd->sections; sect != NULL; sect = sect->next)
> + {
> + if (elf_section_data (sect)->this_hdr.sh_type == SHT_SUNW_dof)
> + {
> + struct dtrace_dof_hdr *dof;
> +
> + /* Read the contents of the DOF section and then process it to
> + extract the information of any probe defined into it. */
> + if (!bfd_malloc_and_get_section (abfd, sect, (bfd_byte **) &dof))
> + complaint (&symfile_complaints,
> + _("could not obtain the contents of"
> + "section '%s' in objfile `%s'."),
> + sect->name, abfd->filename);
> +
> + dtrace_process_dof (sect, objfile, probesp, dof);
> + xfree (dof);
> + }
> + }
> +}
> +
> +/* Helper function to determine whether a given probe is "enabled" or
> + "disabled". A disabled probe is a probe in which one or more
> + enablers are disabled. */
> +
> +static int
> +dtrace_probe_is_enabled (struct dtrace_probe *probe)
> +{
> + int i;
> + struct gdbarch *gdbarch = probe->p.arch;
> + struct dtrace_probe_enabler *enabler;
> +
> + for (i = 0;
> + VEC_iterate (dtrace_probe_enabler_s, probe->enablers, i, enabler);
> + i++)
> + if (!gdbarch_dtrace_probe_is_enabled (gdbarch, enabler->address))
> + return 0;
> +
> + return 1;
> +}
> +
> +/* Implementation of the get_probe_address method. */
> +
> +static CORE_ADDR
> +dtrace_get_probe_address (struct probe *probe, struct objfile *objfile)
> +{
> + gdb_assert (probe->pops == &dtrace_probe_ops);
> + return probe->address + ANOFFSET (objfile->section_offsets,
> + SECT_OFF_DATA (objfile));
> +}
> +
> +/* Implementation of the get_probe_argument_count method. */
> +
> +static unsigned
> +dtrace_get_probe_argument_count (struct probe *probe_generic,
> + struct frame_info *frame)
> +{
> + struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> + return dtrace_probe->probe_argc;
> +}
> +
> +/* Implementation of the can_evaluate_probe_arguments method. */
> +
> +static int
> +dtrace_can_evaluate_probe_arguments (struct probe *probe_generic)
> +{
> + struct gdbarch *gdbarch = probe_generic->arch;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> + return gdbarch_dtrace_parse_probe_argument_p (gdbarch);
> +}
> +
> +/* Implementation of the evaluate_probe_argument method. */
> +
> +static struct value *
> +dtrace_evaluate_probe_argument (struct probe *probe_generic, unsigned n,
> + struct frame_info *frame)
> +{
> + struct gdbarch *gdbarch = probe_generic->arch;
> + struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> + struct dtrace_probe_arg *arg;
> + int pos = 0;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> + arg = dtrace_get_arg (dtrace_probe, n, gdbarch);
> + return evaluate_subexp_standard (arg->type, arg->expr, &pos, EVAL_NORMAL);
> +}
> +
> +/* Implementation of the compile_to_ax method. */
> +
> +static void
> +dtrace_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr,
> + struct axs_value *value, unsigned n)
> +{
> + struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe_generic;
> + struct dtrace_probe_arg *arg;
> + union exp_element *pc;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> + arg = dtrace_get_arg (dtrace_probe, n, expr->gdbarch);
> +
> + pc = arg->expr->elts;
> + gen_expr (arg->expr, &pc, expr, value);
> +
> + require_rvalue (expr, value);
> + value->type = arg->type;
> +}
> +
> +/* Implementation of the probe_destroy method. */
> +
> +static void
> +dtrace_probe_destroy (struct probe *probe_generic)
> +{
> + struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
> + struct dtrace_probe_arg *arg;
> + int i;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> + for (i = 0; VEC_iterate (dtrace_probe_arg_s, probe->args, i, arg); i++)
> + {
> + xfree (arg->type_str);
> + xfree (arg->expr);
> + }
> +
> + VEC_free (dtrace_probe_enabler_s, probe->enablers);
> + VEC_free (dtrace_probe_arg_s, probe->args);
> +}
> +
> +/* Implementation of the type_name method. */
> +
> +static const char *
> +dtrace_type_name (struct probe *probe_generic)
> +{
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> + return "dtrace";
> +}
> +
> +/* Implementation of the gen_info_probes_table_header method. */
> +
> +static void
> +dtrace_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
> +{
> + info_probe_column_s dtrace_probe_column;
> +
> + dtrace_probe_column.field_name = "enabled";
> + dtrace_probe_column.print_name = _("Enabled");
> +
> + VEC_safe_push (info_probe_column_s, *heads, &dtrace_probe_column);
> +}
> +
> +/* Implementation of the gen_info_probes_table_values method. */
> +
> +static void
> +dtrace_gen_info_probes_table_values (struct probe *probe_generic,
> + VEC (const_char_ptr) **ret)
> +{
> + struct dtrace_probe *probe = (struct dtrace_probe *) probe_generic;
> + const char *val = NULL;
> +
> + gdb_assert (probe_generic->pops == &dtrace_probe_ops);
> +
> + if (VEC_empty (dtrace_probe_enabler_s, probe->enablers))
> + val = "always";
> + else if (!gdbarch_dtrace_probe_is_enabled_p (probe_generic->arch))
> + val = "unknown";
> + else if (dtrace_probe_is_enabled (probe))
> + val = "yes";
> + else
> + val = "no";
> +
> + VEC_safe_push (const_char_ptr, *ret, val);
> +}
> +
> +/* Implementation of the enable_probe method. */
> +
> +static void
> +dtrace_enable_probe (struct probe *probe)
> +{
> + struct gdbarch *gdbarch = probe->arch;
> + struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
> + struct dtrace_probe_enabler *enabler;
> + int i;
> +
> + gdb_assert (probe->pops == &dtrace_probe_ops);
> +
> + /* Enabling a dtrace probe implies patching the text section of the
> + running process, so make sure the inferior is indeed running. */
> + if (ptid_equal (inferior_ptid, null_ptid))
> + error (_("No inferior running"));
> +
> + /* Fast path. */
> + if (dtrace_probe_is_enabled (dtrace_probe))
> + return;
> +
> + /* Iterate over all defined enabler in the given probe and enable
> + them all using the corresponding gdbarch hook. */
> +
> + for (i = 0;
> + VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
> + i++)
> + if (gdbarch_dtrace_enable_probe_p (gdbarch))
> + gdbarch_dtrace_enable_probe (gdbarch, enabler->address);
> +}
> +
> +
> +/* Implementation of the disable_probe method. */
> +
> +static void
> +dtrace_disable_probe (struct probe *probe)
> +{
> + struct gdbarch *gdbarch = probe->arch;
> + struct dtrace_probe *dtrace_probe = (struct dtrace_probe *) probe;
> + struct dtrace_probe_enabler *enabler;
> + int i;
> +
> + gdb_assert (probe->pops == &dtrace_probe_ops);
> +
> + /* Disabling a dtrace probe implies patching the text section of the
> + running process, so make sure the inferior is indeed running. */
> + if (ptid_equal (inferior_ptid, null_ptid))
> + error (_("No inferior running"));
> +
> + /* Fast path. */
> + if (!dtrace_probe_is_enabled (dtrace_probe))
> + return;
> +
> + /* Are we trying to disable a probe that does not have any enabler
> + associated? */
> + if (VEC_empty (dtrace_probe_enabler_s, dtrace_probe->enablers))
> + error (_("Probe %s:%s cannot be disabled."), probe->provider, probe->name);
> +
> + /* Iterate over all defined enabler in the given probe and disable
> + them all using the corresponding gdbarch hook. */
> +
> + for (i = 0;
> + VEC_iterate (dtrace_probe_enabler_s, dtrace_probe->enablers, i, enabler);
> + i++)
> + {
> + if (gdbarch_dtrace_disable_probe_p (gdbarch))
> + gdbarch_dtrace_disable_probe (gdbarch, enabler->address);
> + }
> +}
> +
> +/* DTrace probe_ops. */
> +
> +static const struct probe_ops dtrace_probe_ops =
> +{
> + dtrace_probe_is_linespec,
> + dtrace_get_probes,
> + dtrace_get_probe_address,
> + dtrace_get_probe_argument_count,
> + dtrace_can_evaluate_probe_arguments,
> + dtrace_evaluate_probe_argument,
> + dtrace_compile_to_ax,
> + NULL, /* set_semaphore */
> + NULL, /* clear_semaphore */
> + dtrace_probe_destroy,
> + dtrace_type_name,
> + dtrace_gen_info_probes_table_header,
> + dtrace_gen_info_probes_table_values,
> + dtrace_enable_probe,
> + dtrace_disable_probe
> +};
> +
> +/* Implementation of the `info probes dtrace' command. */
> +
> +static void
> +info_probes_dtrace_command (char *arg, int from_tty)
> +{
> + info_probes_for_ops (arg, from_tty, &dtrace_probe_ops);
> +}
> +
> +void _initialize_dtrace_probe (void);
> +
> +void
> +_initialize_dtrace_probe (void)
> +{
> + VEC_safe_push (probe_ops_cp, all_probe_ops, &dtrace_probe_ops);
> +
> + add_cmd ("dtrace", class_info, info_probes_dtrace_command,
> + _("\
> +Show information about DTrace static probes.\n\
> +Usage: info probes dtrace [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name."),
> + info_probes_cmdlist_get ());
> +}
> --
> 1.7.10.4
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (2 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 5/9] New probe type: DTrace USDT probes Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 18:56 ` Sergio Durigan Junior
2014-10-28 13:45 ` [PATCH V3 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
` (4 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
A "probe type" (backend for the probe abstraction implemented in
probe.[ch]) can extend the information printed by `info probes' by
defining additional columns. This means that when `info probes' is
used to print all the probes regardless of their types, some of the
columns will be "not applicable" to some of the probes (like, say, the
Semaphore column only makes sense for SystemTap probes). This patch
makes `info probes' fill these slots with "n/a" marks (currently it
breaks the table) and not include headers for which no actual probe
has been found in the list of defined probes.
This patch also adds support for a new generic column "Type", that
displays the type of each probe. SystemTap probes identify themselves
as "stap" probes.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* stap-probe.c (stap_probe_ops): Add `stap_type_name'.
(stap_type_name): New function.
* probe.h (probe_ops): Added a new probe operation `type_name'.
* probe.c (print_ui_out_not_applicables): New function.
(exists_probe_with_pops): Likewise.
(info_probes_for_ops): Do not include column headers for probe
types for which no probe has been actually found on any object.
Also invoke `print_ui_out_not_applicables' in order to match the
column rows with the header when probes of several types are
listed.
Print the "Type" column.
---
gdb/ChangeLog | 14 ++++++++++
gdb/probe.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
gdb/probe.h | 8 +++++-
gdb/stap-probe.c | 12 ++++++++-
4 files changed, 98 insertions(+), 12 deletions(-)
diff --git a/gdb/probe.c b/gdb/probe.c
index 3b8882e..3151ada 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -410,6 +410,31 @@ gen_ui_out_table_header_info (VEC (bound_probe_s) *probes,
do_cleanups (c);
}
+/* Helper function to print not-applicable strings for all the extra
+ columns defined in a probe_ops. */
+
+static void
+print_ui_out_not_applicables (const struct probe_ops *pops)
+{
+ struct cleanup *c;
+ VEC (info_probe_column_s) *headings = NULL;
+ info_probe_column_s *column;
+ int ix;
+
+ if (pops->gen_info_probes_table_header == NULL)
+ return;
+
+ c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
+ pops->gen_info_probes_table_header (&headings);
+
+ for (ix = 0;
+ VEC_iterate (info_probe_column_s, headings, ix, column);
+ ++ix)
+ ui_out_field_string (current_uiout, column->field_name, _("n/a"));
+
+ do_cleanups (c);
+}
+
/* Helper function to print extra information about a probe and an objfile
represented by PROBE. */
@@ -482,6 +507,23 @@ get_number_extra_fields (const struct probe_ops *pops)
return n;
}
+/* Helper function that returns 1 if there is a probe in PROBES
+ featuring the given POPS. It returns 0 otherwise. */
+
+static int
+exists_probe_with_pops (VEC (bound_probe_s) *probes,
+ const struct probe_ops *pops)
+{
+ struct bound_probe *probe;
+ int ix;
+
+ for (ix = 0; VEC_iterate (bound_probe_s, probes, ix, probe); ++ix)
+ if (probe->probe->pops == pops)
+ return 1;
+
+ return 0;
+}
+
/* See comment in probe.h. */
void
@@ -497,6 +539,7 @@ info_probes_for_ops (const char *arg, int from_tty,
size_t size_name = strlen ("Name");
size_t size_objname = strlen ("Object");
size_t size_provider = strlen ("Provider");
+ size_t size_type = strlen ("Type");
struct bound_probe *probe;
struct gdbarch *gdbarch = get_current_arch ();
@@ -517,6 +560,9 @@ info_probes_for_ops (const char *arg, int from_tty,
}
}
+ probes = collect_probes (objname, provider, probe_name, pops);
+ make_cleanup (VEC_cleanup (probe_p), &probes);
+
if (pops == NULL)
{
const struct probe_ops *po;
@@ -529,18 +575,18 @@ info_probes_for_ops (const char *arg, int from_tty,
To do that, we iterate over all probe_ops, querying each one about
its extra fields, and incrementing `ui_out_extra_fields' to reflect
- that number. */
+ that number. But note that we ignore the probe_ops for which no probes
+ are defined with the given search criteria. */
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
- ui_out_extra_fields += get_number_extra_fields (po);
+ if (exists_probe_with_pops (probes, po))
+ ui_out_extra_fields += get_number_extra_fields (po);
}
else
ui_out_extra_fields = get_number_extra_fields (pops);
- probes = collect_probes (objname, provider, probe_name, pops);
- make_cleanup (VEC_cleanup (probe_p), &probes);
make_cleanup_ui_out_table_begin_end (current_uiout,
- 4 + ui_out_extra_fields,
+ 5 + ui_out_extra_fields,
VEC_length (bound_probe_s, probes),
"StaticProbes");
@@ -552,15 +598,19 @@ info_probes_for_ops (const char *arg, int from_tty,
/* What's the size of an address in our architecture? */
size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
- /* Determining the maximum size of each field (`provider', `name' and
- `objname'). */
+ /* Determining the maximum size of each field (`type', `provider',
+ `name' and `objname'). */
for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
{
+ const char *probe_type = probe->probe->pops->type_name (probe->probe);
+
+ size_type = max (strlen (probe_type), size_type);
size_name = max (strlen (probe->probe->name), size_name);
size_provider = max (strlen (probe->probe->provider), size_provider);
size_objname = max (strlen (objfile_name (probe->objfile)), size_objname);
}
+ ui_out_table_header (current_uiout, size_type, ui_left, "type", _("Type"));
ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
_("Provider"));
ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
@@ -571,10 +621,12 @@ info_probes_for_ops (const char *arg, int from_tty,
const struct probe_ops *po;
int ix;
- /* We have to generate the table header for each new probe type that we
- will print. */
+ /* We have to generate the table header for each new probe type
+ that we will print. Note that this excludes probe types not
+ having any defined probe with the search criteria. */
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
- gen_ui_out_table_header_info (probes, po);
+ if (exists_probe_with_pops (probes, po))
+ gen_ui_out_table_header_info (probes, po);
}
else
gen_ui_out_table_header_info (probes, pops);
@@ -586,9 +638,11 @@ info_probes_for_ops (const char *arg, int from_tty,
for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
{
struct cleanup *inner;
+ const char *probe_type = probe->probe->pops->type_name (probe->probe);
inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
+ ui_out_field_string (current_uiout, "type",probe_type);
ui_out_field_string (current_uiout, "provider", probe->probe->provider);
ui_out_field_string (current_uiout, "name", probe->probe->name);
ui_out_field_core_addr (current_uiout, "addr",
@@ -604,6 +658,8 @@ info_probes_for_ops (const char *arg, int from_tty,
++ix)
if (probe->probe->pops == po)
print_ui_out_info (probe->probe);
+ else if (exists_probe_with_pops (probes, po))
+ print_ui_out_not_applicables (po);
}
else
print_ui_out_info (probe->probe);
diff --git a/gdb/probe.h b/gdb/probe.h
index a128151..66c8c53 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -50,7 +50,7 @@ DEF_VEC_O (info_probe_column_s);
/* Operations associated with a probe. */
struct probe_ops
- {
+{
/* Method responsible for verifying if LINESPECP is a valid linespec for
a probe breakpoint. It should return 1 if it is, or zero if it is not.
It also should update LINESPECP in order to discard the breakpoint
@@ -113,6 +113,12 @@ struct probe_ops
void (*destroy) (struct probe *probe);
+ /* Return a pointer to a name identifying the probe type. This is
+ the string that will be displayed in the "Type" column of the
+ `info probes' command. */
+
+ const char *(*type_name) (struct probe *probe);
+
/* Function responsible for providing the extra fields that will be
printed in the `info probes' command. It should fill HEADS
with whatever extra fields it needs. If the backend doesn't need
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 3902997..061f6d3 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1703,6 +1703,15 @@ stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
}
}
+/* Implementation of the type_name method. */
+
+static const char *
+stap_type_name (struct probe *probe)
+{
+ gdb_assert (probe->pops == &stap_probe_ops);
+ return "stap";
+}
+
static int
stap_probe_is_linespec (const char **linespecp)
{
@@ -1743,7 +1752,7 @@ stap_gen_info_probes_table_values (struct probe *probe_generic,
/* SystemTap probe_ops. */
static const struct probe_ops stap_probe_ops =
-{
+ {
stap_probe_is_linespec,
stap_get_probes,
stap_get_probe_address,
@@ -1754,6 +1763,7 @@ static const struct probe_ops stap_probe_ops =
stap_set_semaphore,
stap_clear_semaphore,
stap_probe_destroy,
+ stap_type_name,
stap_gen_info_probes_table_header,
stap_gen_info_probes_table_values,
};
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-10-28 13:45 ` [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
@ 2014-10-31 18:56 ` Sergio Durigan Junior
2014-11-14 12:38 ` Pedro Alves
0 siblings, 1 reply; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 18:56 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> A "probe type" (backend for the probe abstraction implemented in
> probe.[ch]) can extend the information printed by `info probes' by
> defining additional columns. This means that when `info probes' is
> used to print all the probes regardless of their types, some of the
> columns will be "not applicable" to some of the probes (like, say, the
> Semaphore column only makes sense for SystemTap probes). This patch
> makes `info probes' fill these slots with "n/a" marks (currently it
> breaks the table) and not include headers for which no actual probe
> has been found in the list of defined probes.
>
> This patch also adds support for a new generic column "Type", that
> displays the type of each probe. SystemTap probes identify themselves
> as "stap" probes.
Thanks a lot for persevering! I think we are almost there :-).
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * stap-probe.c (stap_probe_ops): Add `stap_type_name'.
> (stap_type_name): New function.
> * probe.h (probe_ops): Added a new probe operation `type_name'.
> * probe.c (print_ui_out_not_applicables): New function.
> (exists_probe_with_pops): Likewise.
> (info_probes_for_ops): Do not include column headers for probe
> types for which no probe has been actually found on any object.
> Also invoke `print_ui_out_not_applicables' in order to match the
> column rows with the header when probes of several types are
> listed.
> Print the "Type" column.
My personal preference (and I saw Pedro commenting about that a while
ago, so it's not just me) is that we sort the ChangeLog entries
according to the diff. So in this case, it would be
* probe.c ...
* probe.h ...
* stap-probe.c ...
It makes it easier to follow the flow when you read it. But it is just
my preference; the ChangeLog is OK the way it is already.
> ---
> gdb/ChangeLog | 14 ++++++++++
> gdb/probe.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------
> gdb/probe.h | 8 +++++-
> gdb/stap-probe.c | 12 ++++++++-
> 4 files changed, 98 insertions(+), 12 deletions(-)
>
> diff --git a/gdb/probe.c b/gdb/probe.c
> index 3b8882e..3151ada 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -410,6 +410,31 @@ gen_ui_out_table_header_info (VEC (bound_probe_s) *probes,
> do_cleanups (c);
> }
>
> +/* Helper function to print not-applicable strings for all the extra
> + columns defined in a probe_ops. */
> +
> +static void
> +print_ui_out_not_applicables (const struct probe_ops *pops)
> +{
> + struct cleanup *c;
> + VEC (info_probe_column_s) *headings = NULL;
> + info_probe_column_s *column;
> + int ix;
> +
> + if (pops->gen_info_probes_table_header == NULL)
> + return;
> +
> + c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
> + pops->gen_info_probes_table_header (&headings);
> +
> + for (ix = 0;
> + VEC_iterate (info_probe_column_s, headings, ix, column);
> + ++ix)
> + ui_out_field_string (current_uiout, column->field_name, _("n/a"));
> +
> + do_cleanups (c);
> +}
> +
> /* Helper function to print extra information about a probe and an objfile
> represented by PROBE. */
>
> @@ -482,6 +507,23 @@ get_number_extra_fields (const struct probe_ops *pops)
> return n;
> }
>
> +/* Helper function that returns 1 if there is a probe in PROBES
> + featuring the given POPS. It returns 0 otherwise. */
> +
> +static int
> +exists_probe_with_pops (VEC (bound_probe_s) *probes,
> + const struct probe_ops *pops)
> +{
> + struct bound_probe *probe;
> + int ix;
> +
> + for (ix = 0; VEC_iterate (bound_probe_s, probes, ix, probe); ++ix)
> + if (probe->probe->pops == pops)
> + return 1;
> +
> + return 0;
> +}
> +
> /* See comment in probe.h. */
>
> void
> @@ -497,6 +539,7 @@ info_probes_for_ops (const char *arg, int from_tty,
> size_t size_name = strlen ("Name");
> size_t size_objname = strlen ("Object");
> size_t size_provider = strlen ("Provider");
> + size_t size_type = strlen ("Type");
> struct bound_probe *probe;
> struct gdbarch *gdbarch = get_current_arch ();
>
> @@ -517,6 +560,9 @@ info_probes_for_ops (const char *arg, int from_tty,
> }
> }
>
> + probes = collect_probes (objname, provider, probe_name, pops);
> + make_cleanup (VEC_cleanup (probe_p), &probes);
> +
Extraneous whitespaces.
> if (pops == NULL)
> {
> const struct probe_ops *po;
> @@ -529,18 +575,18 @@ info_probes_for_ops (const char *arg, int from_tty,
>
> To do that, we iterate over all probe_ops, querying each one about
> its extra fields, and incrementing `ui_out_extra_fields' to reflect
> - that number. */
> + that number. But note that we ignore the probe_ops for which no probes
> + are defined with the given search criteria. */
>
> for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
> - ui_out_extra_fields += get_number_extra_fields (po);
> + if (exists_probe_with_pops (probes, po))
> + ui_out_extra_fields += get_number_extra_fields (po);
> }
> else
> ui_out_extra_fields = get_number_extra_fields (pops);
>
> - probes = collect_probes (objname, provider, probe_name, pops);
> - make_cleanup (VEC_cleanup (probe_p), &probes);
> make_cleanup_ui_out_table_begin_end (current_uiout,
> - 4 + ui_out_extra_fields,
> + 5 + ui_out_extra_fields,
I wouldn't oppose a #define naming this number "5" there... In fact, I
wanted to fix it long ago, but I forgot.
> VEC_length (bound_probe_s, probes),
> "StaticProbes");
>
> @@ -552,15 +598,19 @@ info_probes_for_ops (const char *arg, int from_tty,
> /* What's the size of an address in our architecture? */
> size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
>
> - /* Determining the maximum size of each field (`provider', `name' and
> - `objname'). */
> + /* Determining the maximum size of each field (`type', `provider',
> + `name' and `objname'). */
> for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> {
> + const char *probe_type = probe->probe->pops->type_name (probe->probe);
> +
Extraneous whitespaces.
Also, any particular reason why you did not create a field "type" inside
"struct probe", instead of making a function that returns the string? I
consider the field would be simpler (i.e., not pollute the probe_ops
structure), and it could be set when creating the probes.
> + size_type = max (strlen (probe_type), size_type);
> size_name = max (strlen (probe->probe->name), size_name);
> size_provider = max (strlen (probe->probe->provider), size_provider);
> size_objname = max (strlen (objfile_name (probe->objfile)), size_objname);
> }
>
> + ui_out_table_header (current_uiout, size_type, ui_left, "type", _("Type"));
> ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
> _("Provider"));
> ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
> @@ -571,10 +621,12 @@ info_probes_for_ops (const char *arg, int from_tty,
> const struct probe_ops *po;
> int ix;
>
> - /* We have to generate the table header for each new probe type that we
> - will print. */
> + /* We have to generate the table header for each new probe type
> + that we will print. Note that this excludes probe types not
> + having any defined probe with the search criteria. */
> for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
> - gen_ui_out_table_header_info (probes, po);
> + if (exists_probe_with_pops (probes, po))
> + gen_ui_out_table_header_info (probes, po);
> }
> else
> gen_ui_out_table_header_info (probes, pops);
> @@ -586,9 +638,11 @@ info_probes_for_ops (const char *arg, int from_tty,
> for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> {
> struct cleanup *inner;
> + const char *probe_type = probe->probe->pops->type_name (probe->probe);
>
> inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
>
> + ui_out_field_string (current_uiout, "type",probe_type);
> ui_out_field_string (current_uiout, "provider", probe->probe->provider);
> ui_out_field_string (current_uiout, "name", probe->probe->name);
> ui_out_field_core_addr (current_uiout, "addr",
> @@ -604,6 +658,8 @@ info_probes_for_ops (const char *arg, int from_tty,
> ++ix)
> if (probe->probe->pops == po)
> print_ui_out_info (probe->probe);
> + else if (exists_probe_with_pops (probes, po))
> + print_ui_out_not_applicables (po);
> }
> else
> print_ui_out_info (probe->probe);
> diff --git a/gdb/probe.h b/gdb/probe.h
> index a128151..66c8c53 100644
> --- a/gdb/probe.h
> +++ b/gdb/probe.h
> @@ -50,7 +50,7 @@ DEF_VEC_O (info_probe_column_s);
> /* Operations associated with a probe. */
>
> struct probe_ops
> - {
> +{
This hunk is reindenting code, so it shouldn't be in this patch.
> /* Method responsible for verifying if LINESPECP is a valid linespec for
> a probe breakpoint. It should return 1 if it is, or zero if it is not.
> It also should update LINESPECP in order to discard the breakpoint
> @@ -113,6 +113,12 @@ struct probe_ops
>
> void (*destroy) (struct probe *probe);
>
> + /* Return a pointer to a name identifying the probe type. This is
> + the string that will be displayed in the "Type" column of the
> + `info probes' command. */
> +
> + const char *(*type_name) (struct probe *probe);
> +
> /* Function responsible for providing the extra fields that will be
> printed in the `info probes' command. It should fill HEADS
> with whatever extra fields it needs. If the backend doesn't need
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index 3902997..061f6d3 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1703,6 +1703,15 @@ stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
> }
> }
>
> +/* Implementation of the type_name method. */
> +
> +static const char *
> +stap_type_name (struct probe *probe)
> +{
> + gdb_assert (probe->pops == &stap_probe_ops);
> + return "stap";
> +}
> +
> static int
> stap_probe_is_linespec (const char **linespecp)
> {
> @@ -1743,7 +1752,7 @@ stap_gen_info_probes_table_values (struct probe *probe_generic,
> /* SystemTap probe_ops. */
>
> static const struct probe_ops stap_probe_ops =
> -{
> + {
> stap_probe_is_linespec,
> stap_get_probes,
> stap_get_probe_address,
> @@ -1754,6 +1763,7 @@ static const struct probe_ops stap_probe_ops =
> stap_set_semaphore,
> stap_clear_semaphore,
> stap_probe_destroy,
> + stap_type_name,
> stap_gen_info_probes_table_header,
> stap_gen_info_probes_table_values,
> };
> --
> 1.7.10.4
Aside from the comment about putting the "type" inside struct probe, the
patch looks good to me.
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-10-31 18:56 ` Sergio Durigan Junior
@ 2014-11-14 12:38 ` Pedro Alves
2014-11-14 23:08 ` Sergio Durigan Junior
0 siblings, 1 reply; 22+ messages in thread
From: Pedro Alves @ 2014-11-14 12:38 UTC (permalink / raw)
To: Sergio Durigan Junior, Jose E. Marchesi; +Cc: gdb-patches
On 10/31/2014 06:56 PM, Sergio Durigan Junior wrote:
> Also, any particular reason why you did not create a field "type" inside
> "struct probe", instead of making a function that returns the string? I
> consider the field would be simpler (i.e., not pollute the probe_ops
> structure), and it could be set when creating the probes.
Not sure I understood it (and probably doesn't matter much), seems like
that'd waste memory storing the same info over and over?
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-11-14 12:38 ` Pedro Alves
@ 2014-11-14 23:08 ` Sergio Durigan Junior
2014-11-17 16:36 ` Pedro Alves
0 siblings, 1 reply; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-11-14 23:08 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jose E. Marchesi, gdb-patches
On Friday, November 14 2014, Pedro Alves wrote:
> On 10/31/2014 06:56 PM, Sergio Durigan Junior wrote:
>> Also, any particular reason why you did not create a field "type" inside
>> "struct probe", instead of making a function that returns the string? I
>> consider the field would be simpler (i.e., not pollute the probe_ops
>> structure), and it could be set when creating the probes.
>
> Not sure I understood it (and probably doesn't matter much), seems like
> that'd waste memory storing the same info over and over?
We would be wasting sizeof (char *) for each probe created, indeed, but
I think this is clearer (also for debugging purposes) than having all
the necessary machinery to call a function that will return the same
info...
Anyway, I won't oppose the current approach too, I was just curious :-P.
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-11-14 23:08 ` Sergio Durigan Junior
@ 2014-11-17 16:36 ` Pedro Alves
2014-11-17 17:45 ` Sergio Durigan Junior
0 siblings, 1 reply; 22+ messages in thread
From: Pedro Alves @ 2014-11-17 16:36 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: Jose E. Marchesi, gdb-patches
On 11/14/2014 11:08 PM, Sergio Durigan Junior wrote:
> On Friday, November 14 2014, Pedro Alves wrote:
>
>> On 10/31/2014 06:56 PM, Sergio Durigan Junior wrote:
>>> Also, any particular reason why you did not create a field "type" inside
>>> "struct probe", instead of making a function that returns the string? I
>>> consider the field would be simpler (i.e., not pollute the probe_ops
>>> structure), and it could be set when creating the probes.
>>
>> Not sure I understood it (and probably doesn't matter much), seems like
>> that'd waste memory storing the same info over and over?
>
> We would be wasting sizeof (char *) for each probe created, indeed, but
> I think this is clearer (also for debugging purposes) than having all
> the necessary machinery to call a function that will return the same
> info...
IMO, that's not cleaner, because the type name is a property of
the type, not of the instance, so it makes sense to get it from the
type (thus through an ops method). Writing the equivalent C++ may
make it clearer. Something like:
struct probe
{
...
virtual const char *type_name () = 0;
};
struct stap_probe : public probe
{
...
virtual const char *type_name () { return "stap"; }
};
struct dtrace_probe : public probe
{
...
virtual const char *type_name () { return "dtrace"; }
};
And then in info_probes_for_ops:
const char *probe_type = probe->probe->type_name ();
>
> Anyway, I won't oppose the current approach too, I was just curious :-P.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types.
2014-11-17 16:36 ` Pedro Alves
@ 2014-11-17 17:45 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-11-17 17:45 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jose E. Marchesi, gdb-patches
On Monday, November 17 2014, Pedro Alves wrote:
> On 11/14/2014 11:08 PM, Sergio Durigan Junior wrote:
>> On Friday, November 14 2014, Pedro Alves wrote:
>>
>>> On 10/31/2014 06:56 PM, Sergio Durigan Junior wrote:
>>>> Also, any particular reason why you did not create a field "type" inside
>>>> "struct probe", instead of making a function that returns the string? I
>>>> consider the field would be simpler (i.e., not pollute the probe_ops
>>>> structure), and it could be set when creating the probes.
>>>
>>> Not sure I understood it (and probably doesn't matter much), seems like
>>> that'd waste memory storing the same info over and over?
>>
>> We would be wasting sizeof (char *) for each probe created, indeed, but
>> I think this is clearer (also for debugging purposes) than having all
>> the necessary machinery to call a function that will return the same
>> info...
>
> IMO, that's not cleaner, because the type name is a property of
> the type, not of the instance, so it makes sense to get it from the
> type (thus through an ops method). Writing the equivalent C++ may
> make it clearer. Something like:
Fair enough, looking from this perspective I am convinced.
> struct probe
> {
> ...
> virtual const char *type_name () = 0;
> };
>
> struct stap_probe : public probe
> {
> ...
> virtual const char *type_name () { return "stap"; }
> };
>
> struct dtrace_probe : public probe
> {
> ...
> virtual const char *type_name () { return "dtrace"; }
> };
>
>
> And then in info_probes_for_ops:
>
> const char *probe_type = probe->probe->type_name ();
>
>>
>> Anyway, I won't oppose the current approach too, I was just curious :-P.
>
>
> Thanks,
> Pedro Alves
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 7/9] Simple testsuite for DTrace USDT probes.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (3 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 1/9] Adapt `info probes' to support printing probes of different types Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-11-13 23:19 ` Sergio Durigan Junior
2014-11-14 13:03 ` Pedro Alves
2014-10-28 13:45 ` [PATCH V3 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
` (3 subsequent siblings)
8 siblings, 2 replies; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch adds some simple tests testing the support for DTrace USDT
probes. The testsuite will be skipped as unsupported in case the user
does not have DTrace installed on her system. The tests included in the
test suite test breakpointing on DTrace probes, enabling and disabling
probes, printing of probe arguments of several types and also
breakpointing on several probes with the same name.
gdb/testsuite/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* lib/dtrace.exp: New file.
* gdb.base/dtrace-probe.exp: Likewise.
* gdb.base/dtrace-probe.d: Likewise.
* gdb.base/dtrace-probe.c: Likewise.
* lib/pdtrace: Likewise.
---
gdb/testsuite/ChangeLog | 8 +
gdb/testsuite/gdb.base/dtrace-probe.c | 38 ++
gdb/testsuite/gdb.base/dtrace-probe.d | 21 +
gdb/testsuite/gdb.base/dtrace-probe.exp | 106 ++++
gdb/testsuite/lib/dtrace.exp | 71 +++
gdb/testsuite/lib/pdtrace | 1017 +++++++++++++++++++++++++++++++
6 files changed, 1261 insertions(+)
create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
create mode 100644 gdb/testsuite/lib/dtrace.exp
create mode 100755 gdb/testsuite/lib/pdtrace
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.c b/gdb/testsuite/gdb.base/dtrace-probe.c
new file mode 100644
index 0000000..61cd166
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.c
@@ -0,0 +1,38 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014 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/>. */
+
+#include "dtrace-probe.h"
+
+int
+main ()
+{
+ char *name = "application";
+
+ TEST_TWO_LOCATIONS ();
+
+ int i = 0;
+ while (i < 10)
+ {
+ i++;
+ if (TEST_PROGRESS_COUNTER_ENABLED ())
+ TEST_PROGRESS_COUNTER (name, i);
+ else
+ TEST_TWO_LOCATIONS ();
+ }
+
+ return 0; /* last break here */
+}
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.d b/gdb/testsuite/gdb.base/dtrace-probe.d
new file mode 100644
index 0000000..d691d3f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.d
@@ -0,0 +1,21 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2014 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/>. */
+
+provider test {
+ probe progress__counter (char *, int);
+ probe two__locations ();
+};
diff --git a/gdb/testsuite/gdb.base/dtrace-probe.exp b/gdb/testsuite/gdb.base/dtrace-probe.exp
new file mode 100644
index 0000000..cbc6fdb
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dtrace-probe.exp
@@ -0,0 +1,106 @@
+# Copyright (C) 2014 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/>.
+
+load_lib "dtrace.exp"
+
+# Run the tests.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc dtrace_test {} {
+ global testfile hex srcfile binfile
+
+ standard_testfile
+
+ if {[dtrace_build_usdt_test_program] == -1} {
+ untested "could not compile test program"
+ return -1
+ }
+
+ clean_restart ${binfile}
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "print \$_probe_argc" "No probe at PC $hex" \
+ "check argument not at probe point"
+
+ # Test the 'info probes' command.
+ gdb_test "info probes dtrace" \
+ "test *progress-counter *$hex +no.*test *two-locations *$hex +always.*test *two-locations *$hex +always.*" \
+ "info probes dtrace"
+
+ # Disabling the probe test:two-locations shall have no effect,
+ # since no is-enabled probes are defined for it in the object
+ # file.
+
+ gdb_test "disable probe test two-locations" \
+ "Probe test:two-locations cannot be disabled.*" \
+ "disable probe test two-locations"
+
+ # On the other hand, the probe test:progress-counter can be
+ # enabled and then disabled again.
+
+ gdb_test "enable probe test progress-counter" \
+ "Probe test:progress-counter enabled.*" \
+ "enable probe test progress-counter"
+
+ gdb_test "disable probe test progress-counter" \
+ "Probe test:progress-counter disabled.*" \
+ "disable probe test progress-counter"
+
+ # Since test:progress-counter is disabled we can run to the second
+ # instance of the test:two-locations probe.
+
+ if {![runto "-probe-dtrace test:two-locations"]} {
+ fail "run to the first test:two-locations probe point"
+ }
+ if {![runto "-probe-dtrace test:two-locations"]} {
+ fail "run to the second test:two-locations probe point"
+ }
+
+ # Go back to the breakpoint on main() and enable the
+ # test:progress-counter probe. Set a breakpoint on it and see
+ # that it gets reached.
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "enable probe test progress-counter" \
+ "Probe test:progress-counter enabled.*" \
+ "enable probe test progress-counter"
+
+ gdb_test "break -probe-dtrace test:progress-counter" \
+ ".*Breakpoint \[0-9\]+ .*" "set breakpoint in test:progress-counter"
+ gdb_continue_to_breakpoint "test:progress-counter"
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 2" \
+ "print \$_probe_argc for probe progress-counter"
+ gdb_test "print \$_probe_arg0" \
+ " = $hex \"application\"" \
+ "print \$_probe_arg0 for probe progress-counter"
+ gdb_test "print \$_probe_arg1" " = 1" \
+ "print \$_probe_arg1 for probe progress-counter"
+
+ # Set a breakpoint with multiple probe locations.
+ gdb_test "break -pdtrace test:two-locations" \
+ "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
+ "set multi-location probe breakpoint (probe two-locations)"
+
+ return 0
+}
+
+dtrace_test
diff --git a/gdb/testsuite/lib/dtrace.exp b/gdb/testsuite/lib/dtrace.exp
new file mode 100644
index 0000000..dfcdabb
--- /dev/null
+++ b/gdb/testsuite/lib/dtrace.exp
@@ -0,0 +1,71 @@
+# Copyright 2014 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/>.
+
+# Generate a test program containing DTrace USDT probes, whose sources
+# are ${srcfile} and ${testfile}.d. The sequence of commands used to
+# generate the test program is:
+#
+# 1. Generate a header file from ${testfile}.d using dtrace -h.
+# 2. Compile ${srcfile}.c.
+# 3. Generate an object file containing a DOF program using dtrace -G.
+# 4. Link everything together to get the test program.
+#
+# Note that if DTrace is not found in the host system then this
+# function uses the pdtrace implementation, which is located at
+# testsuite/lib/pdtrace.
+#
+# This function requires 'testfile', 'srcfile' and 'binfile' to be
+# properly set.
+#
+# This function returns -1 on failure, 0 otherwise
+proc dtrace_build_usdt_test_program {} {
+ global testfile hex srcdir srcfile subdir binfile
+
+ # Make sure that dtrace is installed, it is the real one (not the
+ # script installed by SystemTap, for example) and of the right
+ # version (>= 0.4.0). If it is not then use pdtrace instead.
+ set dtrace "dtrace"
+ set result [remote_exec host "$dtrace -V"]
+ if {[lindex $result 0] != 0 || ![regexp {^dtrace: Sun D [0-9]\.[0-9]\.[0-9]} [lindex $result 1]]} {
+ set dtrace "${srcdir}/lib/pdtrace"
+ }
+ set dscript_file "${srcdir}/${subdir}/${testfile}.d"
+
+ # 1. Generate a header file from testprogram.d using dtrace -h.
+ set out_header_file [standard_output_file "${testfile}.h"]
+ set result [remote_exec host "$dtrace -h -s $dscript_file -o $out_header_file"]
+ verbose -log [lindex $result 1]
+ if {[lindex $result 0] != 0} {
+ return -1
+ }
+
+ # 2. Compile testprogram.c.
+ set options [list debug additional_flags=-I[file dirname $out_header_file]]
+ if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}.o" object ${options}] != ""} {
+ return -1
+ }
+
+ # 3. Generate an object file containing a DOF program using dtrace -G.
+ set result [remote_exec host "$dtrace -G -s $dscript_file -o ${binfile}-p.o ${binfile}.o"]
+ verbose -log [lindex $result 1]
+ if {[lindex $result 0] != 0} {
+ return -1
+ }
+
+ # 4. Link everything together to get the test program.
+ if {[gdb_compile "${binfile}.o ${binfile}-p.o" ${binfile} executable {debug}] != ""} {
+ return -1
+ }
+}
diff --git a/gdb/testsuite/lib/pdtrace b/gdb/testsuite/lib/pdtrace
new file mode 100755
index 0000000..39fe4d6
--- /dev/null
+++ b/gdb/testsuite/lib/pdtrace
@@ -0,0 +1,1017 @@
+#!/bin/sh
+
+# A Poor(but Free)'s Man dtrace
+#
+# Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# Contributed by Oracle, 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/>.
+
+# DISCLAIMER DISCLAIMER DISCLAIMER
+# This script is a test tool. As such it is in no way intended to
+# replace the "real" dtrace command for any practical purpose, apart
+# from testing the DTrace USDT probes support in GDB.
+
+# that said...
+#
+# pdtrace is a limited dtrace program, implementing a subset of its
+# functionality:
+#
+# - The generation of an ELF file containing an embedded dtrace
+# program. Equivalent to dtrace -G.
+#
+# - The generation of a header file with definitions for static
+# probes. Equivalent to dtrace -h.
+#
+# This allows to generate DTrace static probes without having to use
+# the user-level DTrace components. The generated objects are 100%
+# compatible with DTrace and can be traced by the dtrace kernel module
+# like if they were generated by dtrace.
+#
+# Some of the known limitations of this implementation are:
+# - The input d-script must describe one provider, and only one.
+# - The "probe " directives in the d-file must not include argument
+# names, just the types. Thus something like `char *' is valid, but
+# `char *name' is not.
+# - The command line options must precede other arguments, since the
+# script uses the (more) portable getopts.
+# - Each probe header in the d-script must be contained in
+# a single line.
+# - strip -K removes the debugging information from the input object
+# file.
+# - The supported target platforms are i[3456]86 and x86_64.
+#
+# This script uses the following external programs: tr, nm, egrep,
+# sed, cut, readelf, sort, expr, wc, uniq, head, seq, as, strip, true
+#
+# Please keep this code as portable as possible. Restrict yourself to
+# POSIX sh.
+
+# Sizes for several DOF structures, in bytes.
+#
+# See linux/dtrace/dof.h for the definition of the referred
+# structures.
+
+dof_hdrsize=64 # sizeof(dtrace_dof_hdr)
+dof_secsize=32 # sizeof(dtrace_dof_sect)
+dof_probesize=48 # sizeof(dtrace_dof_probe)
+dof_providersize=44 # sizeof(dtrace_dof_provider)
+
+# Types for the several DOF sections.
+#
+# See linux/dtrace/dof_defines.h for a complete list of section types
+# along with their values.
+
+dof_sect_type_strtab=8
+dof_sect_type_provider=15
+dof_sect_type_probes=16
+dof_sect_type_prargs=17
+dof_sect_type_proffs=18
+dof_sect_type_prenoffs=26
+
+### Functions
+
+# Write a message to the standard error output and exit with an error
+# status.
+#
+# Arguments:
+# $1 error message.
+
+f_panic()
+{
+ echo "error: $1" 1>&2; exit 1
+}
+
+# Write a usage message to the standard output and exit with an error
+# status.
+
+f_usage()
+{
+ printf "Usage: pdtrace [-32|-64] [-GhV] [-o output] [-s script] [ args ... ]\n\n"
+
+ printf "\t-32 generate 32-bit ELF files\n"
+ printf "\t-64 generate 64-bit ELF files\n\n"
+
+ printf "\t-G generate an ELF file containing embedded dtrace program\n"
+ printf "\t-h generate a header file with definitions for static probes\n"
+ printf "\t-o set output file\n"
+ printf "\t-s handle probes according to the specified D script\n"
+ printf "\t-V report the DTrace API version implemented by the tool\n"
+ exit 2
+}
+
+# Write a version message to the standard output and exit with a
+# successful status.
+
+f_version()
+{
+ echo "pdtrace: Sun D 1.6.3"
+ exit
+}
+
+# Add a new record to a list and return it.
+#
+# Arguments:
+# $1 is the list.
+# $2 is the new record
+
+f_add_record()
+{
+ rec=$1
+ test -n "$rec" && \
+ { rec=$(printf %s\\n "$rec"; echo x); rec=${rec%x}; }
+ printf %s "$rec$2"
+}
+
+# Collect the providers and probes information from the input object
+# file.
+#
+# This function sets the values of the following global variables.
+# The values are structured in records, each record in a line. The
+# fields of each record are separated in some cases by white
+# characters and in other cases by colon (:) characters.
+#
+# The type codes in the line format descriptors are:
+# S: string, D: decimal number
+#
+# probes
+# Regular probes and is-enabled probes.
+# TYPE(S) PROVIDER(S) NAME(S) OFFSET(D) BASE(D) BASE_SYM(S)
+# base_probes
+# Base probes, i.e. probes sharing provider, name and container.
+# PROVIDER(S) NAME(S) BASE(D) BASE_SYM(S)
+# providers
+# List of providers.
+# PROVIDER(S)
+# All the offsets are expressed in bytes.
+#
+# Input globals:
+# objfile
+# Output globals:
+# probes, base_probes, providers
+
+probes=
+base_probes=
+providers=
+probes_args=
+
+f_collect_probes()
+{
+ # Probe points are function calls to undefined functions featuring
+ # distinct names for both normal probes and is-enabled probes.
+ PROBE_REGEX="(__dtrace_([a-zA-Z_]+)___([a-zA-Z_]+))"
+ EPROBE_REGEX="(__dtraceenabled_([a-zA-Z_]+)___([a-zA-Z_]+))"
+
+ while read type symbol provider name; do
+ test -z "$type" && f_panic "No probe points found in $objfile"
+
+ provider=$(printf %s $provider | tr -s _)
+ name=$(printf %s $name | tr -s _)
+
+ # Search the object file for relocations defined for the
+ # probe symbols. Then calculate the base address of the
+ # probe (along with the symbol associated with that base
+ # address) and the offset of the probe point.
+ for offset in $(readelf -W -r $objfile | grep $symbol | cut -d' ' -f1)
+ do
+ # Figure out the base address for the probe. This is
+ # done finding the function name in the text section of
+ # the object file located above the probed point. But
+ # note that the relocation is for the address operand of
+ # the call instruction, so we have to subtract 1 to find
+ # the real probed point.
+ offset=$((0x$offset - 1))
+
+ # The addresses of is-enabled probes must point to the
+ # first NOP instruction in their patched instructions
+ # sequences, so modify them (see f_patch_objfile for the
+ # instruction sequences).
+ if test "$type" = "e"; then
+ if test "$objbits" -eq "32"; then
+ offset=$((offset + 2))
+ else # 64 bits
+ offset=$((offset + 3))
+ fi
+ fi
+
+ # Determine the base address of the probe and its
+ # corresponding function name.
+ funcs=$(nm -td $objfile | egrep "^[0-9]+ T " \
+ | cut -d' ' -f1,3 | sort -n -r | tr ' ' :)
+ for fun in $funcs; do
+ func_off=$(printf %s $fun | cut -d: -f1)
+ func_sym=$(printf %s $fun | cut -d: -f2)
+ # Note that `expr' is used to remove leading zeros
+ # to avoid FUNC_OFF to be interpreted as an octal
+ # number in arithmetic contexts.
+ test "$func_off" -le "$offset" && \
+ { base=$(expr $func_off + 0); break; }
+ done
+ test -n "$base" || \
+ f_panic "could not find base address for probe at $objfile($o)"
+
+ # Emit the record for the probe.
+ probes=$(f_add_record "$probes" \
+ "$type $provider $name $(($offset - $base)) $base $func_sym")
+ done
+ done <<EOF
+$(nm $objfile | egrep " U $PROBE_REGEX" \
+ | sed -E -e "s/.*$PROBE_REGEX.*/p \1 \2 \3/";
+ nm $objfile | egrep " U $EPROBE_REGEX" \
+ | sed -E -e "s/.*$EPROBE_REGEX.*/e \1 \2 \3/")
+EOF
+
+ # Build the list of providers and of base probes from the probes.
+ while read type provider name offset base base_sym; do
+ providers=$(f_add_record "$providers" "$provider")
+ base_probes=$(f_add_record "$base_probes" "$provider $name $base $base_sym")
+ done <<EOF
+$probes
+EOF
+ providers=$(printf %s\\n "$providers" | sort | uniq)
+ base_probes=$(printf %s\\n "$base_probes" | sort | uniq)
+}
+
+# Collect the argument counts and type strings for all the probes
+# described in the `probes' global variable. This is done by
+# inspecting the d-script file provided by the user.
+#
+# This function sets the values of the following global variables.
+# The values are structured in records, each record in a line. The
+# fields of each record are separated in some cases by white
+# characters and in other cases by colon (:) characters.
+#
+# The type codes in the line format descriptors are:
+# S: string, D: decimal number
+#
+# probes_args
+# Probes arguments.
+# PROVIDER(S):NAME(S):NARGS(D):ARG1(S):ARG2(S):...:ARGn(S)
+#
+# Input globals:
+# probes
+# Output globals:
+# probes_args
+# Arguments:
+# $1 is the d-script file from which to extract the arguments
+# information.
+
+f_collect_probes_args()
+{
+ dscript=$1
+ while read type provider name offset base base_sym; do
+ # Process normal probes only. Is-enabled probes are not
+ # described in the d-script file and they don't receive any
+ # argument.
+ test "$type" = "p" || continue
+
+ # Names are mangled in d-script files to make it possible to
+ # have underscore characters as part of the provider name and
+ # probe name.
+ m_provider=$(printf %s $provider | sed -e 's/_/__/g')
+ m_name=$(printf %s $name | sed -e 's/_/__/g')
+
+ # Ignore this probe if the d-script file does not describe its
+ # provider.
+ egrep -q "provider +$m_provider" $dscript || continue
+
+ # Look for the line containing the description of the probe.
+ # If we can't find it then ignore this probe.
+ line=$(egrep "^ *probe +$m_name *\(.*\);" $dscript)
+ test -n "$line" || continue
+
+ # Ok, extract the argument types from the probe prototype.
+ # This is fragile as hell as it requires the prototype to be
+ # in a single line.
+ args=""; nargs=0; line=$(printf %s "$line" | sed -e 's/.*(\(.*\)).*/\1/')
+ set -f; IFS=,
+ for arg in $line; do
+ args="$args:$arg"
+ nargs=$((nargs + 1))
+ done
+ set +f; unset IFS
+
+ # Emit the record for the probe arguments.
+ probes_args=$(f_add_record "$probes_args" "$provider:$name:$nargs$args")
+ done <<EOF
+$probes
+EOF
+}
+
+# Functions to manipulate the global BCOUNT.
+
+BCOUNT=0
+
+f_incr_bcount()
+{
+ BCOUNT=$((BCOUNT + $1))
+}
+
+f_align_bcount()
+{
+ test $((BCOUNT % $1)) -eq 0 || BCOUNT=$((BCOUNT + ($1 - (BCOUNT % $1))))
+}
+
+# Generate a line of assembly code and add it to the asmprogram global
+# variable.
+#
+# Arguments:
+# $1 string to generate in a line.
+
+asmprogram=
+
+f_gen_asm()
+{
+ line=$(printf "\t$1")
+ asmprogram=$(f_add_record "$asmprogram" "$line")
+}
+
+# Helper function to generate the assembly code of a DOF section
+# header.
+#
+# This function is used by `f_gen_dof_program'.
+#
+# Arguments:
+# $1 is the name of the described section.
+# $2 is the type of the described section.
+# $3 is the alignment of the described section.
+# $4 is the number of entities stored in the described section.
+# $5 is the offset in the DOF program of the described section.
+# $6 is the size of the described section, in bytes.
+
+f_gen_dof_sect_header()
+{
+ f_gen_asm ""
+ f_gen_asm "/* dtrace_dof_sect for the $1 section. */"
+ f_gen_asm ".balign 8"
+ f_gen_asm ".4byte $2\t/* uint32_t dofs_type */"
+ f_gen_asm ".4byte $3\t/* uint32_t dofs_align */"
+ # The DOF_SECF_LOAD flag is 1 => loadable section.
+ f_gen_asm ".4byte 1\t/* uint32_t dofs_flags */"
+ f_gen_asm ".4byte $4\t/* uint32_t dofs_entsize */"
+ f_gen_asm ".8byte $5\t/* uint64_t dofs_offset */"
+ f_gen_asm ".8byte $6\t/* uint64_t dofs_size */"
+}
+
+# Generate a DOF program and assembly it in the output file.
+#
+# The DOF program generated by this function has the following
+# structure:
+#
+# HEADER
+# STRTAB OFFTAB EOFFTAB [PROBES PROVIDER]...
+# STRTAB_SECT OFFTAB_SECT EOFFTAB_SECT ARGTAB_SECT [PROBES_SECT PROVIDER_SECT]...
+#
+# Input globals:
+# probes, base_probes, providers, probes_args, BCOUNT
+
+f_gen_dof_program()
+{
+ ###### Variables used to cache information needed later.
+
+ # Number of section headers in the generated DOF program.
+ dof_secnum=0
+ # Offset of section headers in the generated DOF program, in bytes.
+ dof_secoff=0
+
+ # Sizes of the STRTAB, OFFTAB and EOFFTAB sections, in bytes.
+ strtab_size=0
+ offtab_size=0
+ eofftab_size=0
+
+ # Offsets of the STRTAB, OFFTAB EOFFTAB and PROBES sections in the
+ # generated DOF program. In bytes.
+ strtab_offset=0
+ offtab_offset=0
+ eofftab_offset=0
+ argtab_offset=0
+ probes_offset=0
+
+ # Indexes of the section headers of the STRTAB, OFFTAB, EOFFTAB and
+ # PROBES sections in the sections array.
+ strtab_sect_index=0
+ offtab_sect_index=0
+ eofftab_sect_index=0
+ argtab_sect_index=0
+ probes_sect_index=0
+
+ # First offsets and eoffsets of the base-probes.
+ # Lines: PROVIDER(S) NAME(S) BASE(D) (DOF_OFFSET(D)|DOF_EOFFSET(D))
+ probes_dof_offsets=
+ probes_dof_eoffsets=
+
+ # Offsets in the STRTAB section for the first type of base probes.
+ # Record per line: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
+ probes_dof_types=
+
+
+ # Offsets of the provider names in the provider's STRTAB section.
+ # Lines: PROVIDER(S) OFFSET(D)
+ providers_dof_names=
+
+ # Offsets of the base-probe names in the provider's STRTAB section.
+ # Lines: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
+ probes_dof_names=
+
+ # Offsets of the provider sections in the DOF program.
+ # Lines: PROVIDER(S) OFFSET(D)
+ providers_offsets=
+
+ ###### Generation phase.
+
+ # The header of the DOF program contains a `struct
+ # dtrace_dof_hdr'. Record its size, but it is written at the end
+ # of the function.
+ f_incr_bcount $dof_hdrsize; f_align_bcount 8
+
+ # The STRTAB section immediately follows the header. It contains
+ # the following set of packed null-terminated strings:
+ #
+ # [PROVIDER [BASE_PROBE_NAME [BASE_PROBE_ARG_TYPE...]]...]...
+ strtab_offset=$BCOUNT
+ strtab_sect_index=$dof_secnum
+ dof_secnum=$((dof_secnum + 1))
+ f_gen_asm ""
+ f_gen_asm "/* The STRTAB section. */"
+ f_gen_asm ".balign 8"
+ # Add the provider names.
+ off=0
+ while read provider; do
+ strtab_size=$(($strtab_size + ${#prov} + 1))
+ # Note the funny mangling...
+ f_gen_asm ".asciz \"$(printf %s $provider | tr _ -)\""
+ providers_dof_names=$(f_add_record "$providers_dof_names" \
+ "$provider $off")
+ off=$(($off + ${#provider} + 1))
+
+ # Add the base-probe names.
+ while read p_provider name base base_sym; do
+ test "$p_provider" = "$provider" || continue
+ # And yes, more funny mangling...
+ f_gen_asm ".asciz \"$(printf %s $name | tr _ -)\""
+ probes_dof_names=$(f_add_record "$probes_dof_names" \
+ "$p_provider $name $base $off")
+ off=$(($off + ${#name} + 1))
+ while read args; do
+ a_provider=$(printf %s "$args" | cut -d: -f1)
+ a_name=$(printf %s "$args" | cut -d: -f2)
+ test "$a_provider" = "$p_provider" \
+ && test "$a_name" = "$name" \
+ || continue
+
+ probes_dof_types=$(f_add_record "$probes_dof_types" \
+ "$a_provider $name $base $off")
+ nargs=$(printf %s "$args" | cut -d: -f3)
+ for n in $(seq $nargs); do
+ arg=$(printf %s "$args" | cut -d: -f$(($n + 3)))
+ f_gen_asm ".asciz \"${arg}\""
+ off=$(($off + ${#arg} + 1))
+ done
+ done <<EOF
+$probes_args
+EOF
+ done <<EOF
+$base_probes
+EOF
+ done <<EOF
+$providers
+EOF
+ strtab_size=$off
+ f_incr_bcount $strtab_size; f_align_bcount 8
+
+ # The OFFTAB section contains a set of 32bit words, one per
+ # defined regular probe.
+ offtab_offset=$BCOUNT
+ offtab_sect_index=$dof_secnum
+ dof_secnum=$((dof_secnum + 1))
+ f_gen_asm ""
+ f_gen_asm "/* The OFFTAB section. */"
+ f_gen_asm ".balign 8"
+ off=0
+ while read type provider name offset base base_sym; do
+ test "$type" = "p" || continue
+ f_gen_asm ".4byte $offset\t/* probe ${provider}:${name} */"
+ probes_dof_offsets=$(f_add_record "$probes_dof_offsets" \
+ "$provider $name $base $off")
+ off=$(($off + 4))
+ done <<EOF
+$probes
+EOF
+ offtab_size=$off
+ f_incr_bcount $offtab_size; f_align_bcount 8
+
+ # The EOFFTAB section contains a set of 32bit words, one per
+ # defined is-enabled probe.
+ eofftab_offset=$BCOUNT
+ eofftab_sect_index=$dof_secnum
+ dof_secnum=$((dof_secnum + 1))
+ f_gen_asm ""
+ f_gen_asm "/* The EOFFTAB section. */"
+ f_gen_asm ".balign 8"
+ off=0
+ while read type provider name offset base base_sym; do
+ test "$type" = "e" || continue
+ f_gen_asm ".4byte $offset\t/* is-enabled probe ${provider}:${name} */"
+ probes_dof_eoffsets=$(f_add_record "$probes_dof_eoffsets" \
+ "$provider $name $base $off")
+ off=$(($off + 4))
+ done <<EOF
+$probes
+EOF
+ eofftab_size=$off
+ f_incr_bcount $eofftab_size; f_align_bcount 8
+
+ # The ARGTAB section is empty, but nonetheless has a section
+ # header, so record its section index here.
+ argtab_offset=0
+ argtab_sect_index=$dof_secnum
+ dof_secnum=$((dof_secnum + 1))
+
+ # Generate a pair of sections PROBES and PROVIDER for each
+ # provider.
+ while read prov; do
+ # The PROBES section contains an array of `struct
+ # dtrace_dof_probe'.
+ #
+ # A `dtrace_dof_probe' entry characterizes the collection of
+ # probes and is-enabled probes sharing the same provider, name and
+ # base address.
+ probes_sect_index=$dof_secnum
+ dof_secnum=$((dof_secnum + 1))
+ probes_offset=$BCOUNT
+ num_base_probes=$(printf %s\\n "$base_probes" | wc -l)
+ while read provider name base base_sym; do
+ name_offset=$(printf %s\\n "$probes_dof_names" \
+ | egrep "^$provider $name " | cut -d' ' -f4)
+
+ num_offsets=$(printf %s\\n "$probes_dof_offsets" \
+ | egrep "^$provider $name [0-9]+ " | wc -l)
+
+ first_offset=0
+ test "$num_offsets" -gt 0 && \
+ first_offset=$(printf %s\\n "$probes_dof_offsets" \
+ | egrep "^$provider $name " | cut -d' ' -f4 | head -1)
+
+ num_eoffsets=$(printf %s\\n "$probes_dof_eoffsets" \
+ | egrep "^$provider $name [0-9]+ " | wc -l)
+ first_eoffset=0
+ test "$num_eoffsets" -gt 0 && \
+ first_eoffset=$(printf %s "$probes_dof_eoffsets" \
+ | egrep "^$provider $name " | cut -d' ' -f4 | head -1)
+
+ num_args=$(printf %s "$probes_args" \
+ | egrep "^$provider:$name:" | cut -d: -f3 | head -1)
+
+ first_type=$(printf %s "$probes_dof_types" \
+ | egrep "^$provider $name $base " | cut -d' ' -f4 | head -1)
+
+ reloctype=R_X86_64_GLOB_DAT
+ test "$objbits" = "32" && reloctype=R_386_32
+
+ f_gen_asm ""
+ f_gen_asm "/* dtrace_dof_probe for ${provider}:${name} at ${base_sym} */"
+ f_gen_asm ".balign 8"
+ f_gen_asm ".reloc ., $reloctype, $base_sym + 0"
+ f_gen_asm ".8byte ${base}\t/* uint64_t dofpr_addr */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpr_func */"
+ f_gen_asm ".4byte $name_offset\t/* uint32_t dofpr_name */"
+ f_gen_asm ".4byte $first_type\t/* uint32_t dofpr_nargv */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpr_xargv */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpr_argidx */"
+ f_gen_asm ".4byte $(($first_offset/4))\t/* uint32_t dofpr_offidx */"
+ f_gen_asm ".byte $num_args\t/* uint8_t dofpr_nargc */"
+ f_gen_asm ".byte 0\t/* uint8_t dofpr_xargc */"
+ f_gen_asm ".2byte $num_offsets\t/* uint16_t dofpr_noffs */"
+ f_gen_asm ".4byte $(($first_eoffset/4))\t/* uint32_t dofpr_enoffidx */"
+ f_gen_asm ".2byte $num_eoffsets\t/* uint16_t dofpr_nenoffs */"
+ f_gen_asm ".2byte 0\t/* uint16_t dofpr_pad1 */"
+ f_gen_asm ".4byte 0\t/* uint16_t dofpr_pad2 */"
+
+ f_incr_bcount "$dof_probesize"
+ done <<EOF
+$base_probes
+EOF
+
+ # The PROVIDER section contains a `struct dtrace_dof_provider'
+ # instance describing the provider for the probes above.
+ dof_secnum=$((dof_secnum + 1))
+ providers_offsets=$(f_add_record "$providers_offsets" \
+ "$prov $BCOUNT")
+ # The dtrace_dof_provider.
+ provider_name_offset=$(printf %s "$providers_dof_names" \
+ | egrep "^$prov " | cut -d' ' -f2)
+
+ f_gen_asm ""
+ f_gen_asm "/* dtrace_dof_provider for $prov */"
+ f_gen_asm ".balign 8"
+ # Links to several DOF sections.
+ f_gen_asm ".4byte $strtab_sect_index\t/* uint32_t dofpv_strtab */"
+ f_gen_asm ".4byte $probes_sect_index\t/* uint32_t dofpv_probes */"
+ f_gen_asm ".4byte $argtab_sect_index\t/* uint32_t dofpv_prargs */"
+ f_gen_asm ".4byte $offtab_sect_index\t/* uint32_t dofpv_proffs */"
+ # Offset of the provider name into the STRTAB section.
+ f_gen_asm ".4byte $provider_name_offset\t/* uint32_t dofpv_name */"
+ # The rest of fields can be 0 for our modest purposes :)
+ f_gen_asm ".4byte 0\t/* uint32_t dofpv_provattr */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpv_modattr */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpv_funcattr */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpv_nameattr */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofpv_argsattr */"
+ # But not this one, of course...
+ f_gen_asm ".4byte $eofftab_sect_index\t/* uint32_t dofpv_prenoffs */"
+
+ f_incr_bcount $dof_providersize
+ done<<EOF
+$providers
+EOF
+ f_align_bcount 8
+
+ # The section headers follow, one per section defined above.
+ dof_secoff=$BCOUNT
+
+ f_gen_dof_sect_header STRTAB \
+ $dof_sect_type_strtab \
+ 1 1 $strtab_offset $strtab_size
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+
+ f_gen_dof_sect_header OFFTAB \
+ $dof_sect_type_proffs \
+ 4 4 $offtab_offset $offtab_size
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+
+ f_gen_dof_sect_header EOFFTAB \
+ $dof_sect_type_prenoffs \
+ 4 4 $eofftab_offset $eofftab_size
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+
+ f_gen_dof_sect_header ARGTAB \
+ $dof_sect_type_prargs \
+ 4 1 $argtab_offset 0
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+
+ while read provider; do
+ provider_offset=$(printf %s "$providers_offsets" \
+ | egrep "^$provider " | cut -d' ' -f2)
+ num_base_probes=$(printf %s\\n "$base_probes" | wc -l)
+
+ f_gen_dof_sect_header "$provider probes" \
+ $dof_sect_type_probes \
+ 8 $dof_probesize $probes_offset \
+ $((num_base_probes * dof_probesize))
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+
+ f_gen_dof_sect_header "$provider provider" \
+ $dof_sect_type_provider \
+ 8 1 $provider_offset $dof_providersize
+ f_incr_bcount $dof_secsize; f_align_bcount 8
+ done <<EOF
+$providers
+EOF
+
+ # Finally, cook the header.
+ asmbody="$asmprogram"
+ asmprogram=""
+ f_gen_asm "/* File generated by pdtrace. */"
+ f_gen_asm ""
+
+ f_gen_asm ".section .SUNW_dof,\"a\",\"progbits\""
+ f_gen_asm ".globl __SUNW_dof"
+ f_gen_asm ".hidden __SUNW_dof"
+ f_gen_asm ".size __SUNW_dof, ${BCOUNT}"
+ f_gen_asm ".type __SUNW_dof, @object"
+ f_gen_asm "__SUNW_dof:"
+
+ f_gen_asm ""
+ f_gen_asm "/* dtrace_dof_hdr */"
+ f_gen_asm ".balign 8"
+ f_gen_asm ".byte 0x7f, 'D, 'O, 'F\t/* dofh_ident[0..3] */"
+ f_gen_asm ".byte 2\t\t/* model: 1=ILP32, 2=LP64 */"
+ f_gen_asm ".byte 1\t\t/* encoding: 1: little-endian, 2: big-endian */"
+ f_gen_asm ".byte 2\t\t/* DOF version: 1 or 2. Latest is 2 */"
+ f_gen_asm ".byte 2\t\t/* DIF version: 1 or 2. Latest is 2 */"
+ f_gen_asm ".byte 8\t\t/* number of DIF integer registers */"
+ f_gen_asm ".byte 8\t\t/* number of DIF tuple registers */"
+ f_gen_asm ".byte 0, 0\t\t/* dofh_ident[10..11] */"
+ f_gen_asm ".4byte 0\t\t/* dofh_ident[12..15] */"
+ f_gen_asm ".4byte 0\t/* uint32_t dofh_flags */" # See Limitations above.
+ f_gen_asm ".4byte ${dof_hdrsize}\t/* uint32_t dofh_hdrsize */"
+ f_gen_asm ".4byte ${dof_secsize}\t/* uint32_t dofh_secsize */"
+ f_gen_asm ".4byte ${dof_secnum}\t/* uint32_t dofh_secnum */"
+ f_gen_asm ".8byte ${dof_secoff}\t/* uint64_t dofh_secoff */"
+ f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_loadsz */"
+ f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_filesz */"
+ f_gen_asm ".8byte 0\t/* uint64_t dofh_pad */"
+ f_gen_asm ""
+
+ # Ok, now assembly the program in OFILE
+ echo "$asmprogram$asmbody" | as -$objbits -o $ofile
+
+ # Next step is to change the sh_type of the ".SUNW_dof" section
+ # headers to 0x6ffffff4 (SHT_SUNW_dof).
+ #
+ # Note that this code relies in the fact that readelf will list
+ # the sections ordered in the same order than the section headers
+ # in the section header table of the file.
+ elfinfo=$(readelf -a $ofile)
+
+ # Mind the endianness.
+ if printf %s "$elfinfo" | egrep -q "little endian"; then
+ sht_sunw_dof=$(printf %s%s%s%s \\364 \\377 \\377 \\157)
+ else
+ sht_sunw_dof=$(printf %s%s%s%s \\157 \\377 \\377 \\364)
+ fi
+
+ shdr_start=$(printf %s "$elfinfo" \
+ | egrep "^[ \t]*Start of section headers:" \
+ | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+ test -n "$shdr_start" \
+ || f_panic "could not extract the start of shdr from $ofile"
+
+ shdr_num_entries=$(printf %s "$elfinfo" \
+ | egrep "^[ \t]*Size of section headers:" \
+ | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+ test -n "$shdr_num_entries" \
+ || f_panic "could not extract the number of shdr entries from $ofile"
+
+ shdr_entry_size=$(printf %s "$elfinfo" \
+ | egrep "^[ \t]*Size of section headers:" \
+ | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
+ test -n "$shdr_entry_size" \
+ || f_panic "could not fetch the size of section headers from $ofile"
+
+ while read line; do
+ data=$(printf %s "$line" \
+ | sed -E -e 's/.*\[(.*)\][ \t]+([a-zA-Z_.]+).*/\1:\2/')
+ num=$(printf %s "$data" | cut -d: -f1)
+ name=$(printf %s "$data" | cut -d: -f2)
+ if test "$name" = ".SUNW_dof"; then
+ # Patch the new sh_type in the proper entry of the section
+ # header table.
+ printf "$sht_sunw_dof" \
+ | dd of=$ofile conv=notrunc count=4 ibs=1 bs=1 \
+ seek=$((shdr_start + (shdr_entry_size * num) + 4)) \
+ 2> /dev/null
+ break
+ fi
+ done <<EOF
+$(printf %s "$elfinfo" | egrep "^[ \t]*\[[0-9 ]+\].*[A-Z]+.*PROGBITS")
+EOF
+
+}
+
+# Patch the probed points in the given object file, replacing the
+# function calls with NOPs.
+#
+# The probed points in the input object files are function calls.
+# This function replaces these function calls by some other
+# instruction sequences. Which replacement to use depends on several
+# factors, as documented below.
+#
+# Arguments:
+# $1 is the object file to patch.
+
+f_patch_objfile()
+{
+ objfile=$1
+
+ # Several x86_64 instruction opcodes, in octal.
+ x86_op_nop=$(printf \\220)
+ x86_op_ret=$(printf \\303)
+ x86_op_call=$(printf \\350)
+ x86_op_jmp32=$(printf \\351)
+ x86_op_rex_rax=$(printf \\110)
+ x86_op_xor_eax_0=$(printf \\063)
+ x86_op_xor_eax_1=$(printf \\300)
+
+ # Figure out the file offset of the text section in the object
+ # file.
+ text_off=0x$(objdump -j .text -h $objfile \
+ | grep \.text | tr -s ' ' | cut -d' ' -f 7)
+
+ while read type provider name offset base base_sym; do
+ # Calculate the offset of the probed point in the object file.
+ # Note that the `offset' of is-enabled probes is tweaked in
+ # `f_collect_probes" to point ahead the patching point.
+ probe_off=$((text_off + base + offset))
+ if test "$type" = "e"; then
+ if test "$objbits" -eq "32"; then
+ probe_off=$((probe_off - 2))
+ else # 64 bits
+ probe_off=$((probe_off - 3))
+ fi
+ fi
+
+ # The probed point can be either a CALL instruction o a JMP
+ # instruction (a tail call). This has an impact on the
+ # patching sequence. Fetch the first byte at the probed point
+ # and do the right thing.
+ nopret="$x86_op_nop"
+ byte=$(dd if=$objfile count=1 ibs=1 bs=1 skip=$probe_off 2> /dev/null)
+ test "$byte" = "$x86_op_jmp32" && nopret="$x86_op_ret"
+
+ # Determine the patching sequence. It depends on the type of
+ # probe at hand (regular or is-enabled) and also if
+ # manipulating a 32bit or 64bit binary.
+ patchseq=
+ case $type in
+ p) patchseq=$(printf %s%s%s%s%s \
+ "$nopret" \
+ "$x86_op_nop" \
+ "$x86_op_nop" \
+ "$x86_op_nop" \
+ "$x86_op_nop")
+ ;;
+ e) test "$objbits" -eq 64 && \
+ patchseq=$(printf %s%s%s%s%s \
+ "$x86_op_rex_rax" \
+ "$x86_op_xor_eax_0" \
+ "$x86_op_xor_eax_1" \
+ "$nopret" \
+ "$x86_op_nop")
+ test "$objbits" -eq 32 && \
+ patchseq=$(printf %s%s%s%s%s \
+ "$x86_op_xor_eax_0" \
+ "$x86_op_xor_eax_1" \
+ "$nopret" \
+ "$x86_op_nop" \
+ "$x86_op_nop")
+ ;;
+ *) f_panic "internal error: wrong probe type $type";;
+ esac
+
+ # Patch!
+ printf %s "$patchseq" \
+ | dd of=$objfile conv=notrunc count=5 ibs=1 bs=1 seek=$probe_off 2> /dev/null
+ done <<EOF
+$probes
+EOF
+
+ # Finally, we have to remove the __dtrace_* and __dtraceenabled_*
+ # symbols from the object file, along with their respective
+ # relocations.
+ #
+ # Note that the most obvious call:
+ # strip -v -N whatever -w foo.o
+ # will not work:
+ # strip: not stripping symbol `whatever' because it is named in a relocation
+ #
+ # Fortunately using `-K !whatever' instead tricks strip to do the
+ # right thing, but this is black magic and may eventually stop
+ # working...
+ strip -K '!__dtrace_*' -w $objfile
+ strip -K '!__dtraceenabled_*' -w $objfile
+}
+
+# Read the input .d file and print a header file with macros to
+# invoke the probes defined in it.
+
+f_gen_header_file()
+{
+ guard=$(basename $ofile | tr - _ | cut -d. -f1 | tr a-z A-Z)
+ printf "/*\n * Generated by pdtrace.\n */\n\n"
+
+ printf "#ifndef _${guard}_H\n"
+ printf "#define _${guard}_H\n\n"
+
+ printf "#include <unistd.h>\n"
+ printf "#include <inttypes.h>\n"
+ printf \\n\\n
+
+ printf "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"
+
+ printf "#define _DTRACE_VERSION 1\n\n"
+
+ provider=$(cat $dfile | egrep "^ *provider +([a-zA-Z_]+)" \
+ | sed -E -e 's/^ *provider +([a-zA-Z]+).*/\1/')
+ test -z "$provider" \
+ && f_panic "unable to parse the provider name from $dfile."
+ u_provider=$(printf %s "$provider" | tr a-z A-Z | tr -s _)
+
+ cat $dfile | egrep "^ *probe +[a-zA-Z_]+ *\(.*\);" | \
+ while read line; do
+ # Extract the probe name.
+ name=$(printf %s "$line" \
+ | sed -E -e 's/^ *probe +([a-zA-Z_]+).*/\1/')
+ u_name=$(printf %s "$name" | tr a-z A-Z | tr -s _)
+
+ # Generate an arg1,arg2,...,argN line for the probe.
+ args=""; nargs=0; aline=$(printf %s "$line" | sed -e 's/.*(\(.*\)).*/\1/')
+ set -f; IFS=,
+ for arg in $aline; do
+ args="${args}arg${nargs},"
+ nargs=$((nargs + 1))
+ done
+ set +f; unset IFS
+ args=${args%,}
+
+ echo "#if _DTRACE_VERSION"
+ echo ""
+
+ # Emit the macros for the probe.
+ echo "#define ${u_provider}_${u_name}($args) \\"
+ echo " __dtrace_${provider}___${name}($args)"
+ echo "#define ${u_provider}_${u_name}_ENABLED() \\"
+ echo " __dtraceenabled_${provider}___${name}()"
+
+ # Emit the extern definitions for the probe dummy
+ # functions.
+ echo ""
+ printf %s\\n "$line" \
+ | sed -E -e "s/^ *probe +/extern void __dtrace_${provider}___/"
+ echo "extern int __dtraceenabled_${provider}___${name}(void);"
+
+
+ printf "\n#else\n"
+
+ # Emit empty macros for the probe
+ echo "#define ${u_provider}_${u_name}($args)"
+ echo "#define ${u_provider}_${u_name}_ENABLED() (0)"
+
+ printf "\n#endif /* _DTRACE_VERSION */\n"
+ done
+
+ printf "#ifdef __cplusplus\n}\n#endif\n\n"
+ printf "#endif /* _${guard}_H */\n"
+}
+
+### Main program.
+
+# Process command line arguments.
+
+test "$#" -eq "0" && f_usage
+
+genelf=0
+genheader=0
+objbits=64
+ofile=
+dfile=
+while getopts VG3264hs:o: name; do
+ case $name in
+ V) f_version;;
+ s) dfile="$OPTARG";
+ test -f "$dfile" || f_panic "cannot read $dfile";;
+ o) ofile="$OPTARG";;
+ G) genelf=1;;
+ h) genheader=1;;
+ # Note the trick to support -32
+ 3) objbits=666;;
+ 2) test "$objbits" -eq 666 || f_usage; objbits=32;;
+ # Likewise for -64
+ 6) objbits=777;;
+ 4) test "$objbits" -eq 777 || f_usage; objbits=64;;
+ ?) f_usage;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+test "$objbits" -eq "32" || test "$objbits" -eq "64" \
+ || f_usage
+
+test $((genelf + genheader)) -gt 1 && \
+ { echo "Please use either -G or -h."; f_usage; }
+
+test -n "$dfile" || { echo "Please specify a .d file with -s."; exit 2; }
+
+if test "$genelf" -gt 0; then
+ # In this mode there must be a remaining argument: the name of the
+ # object file to inspect for probed points.
+ test "$#" -ne "1" && f_usage
+ test -f "$1" || f_panic "cannot read $1"
+ objfile=$1
+
+ # Collect probe information from the input object file and the
+ # d-script.
+ f_collect_probes $objfile
+ f_collect_probes_args $dfile
+
+ # Generate the assembly code and assemble the DOF program in
+ # OFILE. Then patch OBJFILE to remove the dummy probe calls.
+ f_gen_dof_program
+ f_patch_objfile $objfile
+fi
+
+if test "$genheader" -gt 0; then
+ test -n "$ofile" || { echo "Please specify an output file with -o."; exit 2; }
+
+ # In this mode no extra arguments shall be present.
+ test "$#" -ne "0" && f_usage
+
+ f_gen_header_file > $ofile
+fi
+
+# pdtrace ends here.
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 7/9] Simple testsuite for DTrace USDT probes.
2014-10-28 13:45 ` [PATCH V3 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
@ 2014-11-13 23:19 ` Sergio Durigan Junior
2014-11-14 13:03 ` Pedro Alves
1 sibling, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-11-13 23:19 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch adds some simple tests testing the support for DTrace USDT
> probes. The testsuite will be skipped as unsupported in case the user
> does not have DTrace installed on her system. The tests included in the
> test suite test breakpointing on DTrace probes, enabling and disabling
> probes, printing of probe arguments of several types and also
> breakpointing on several probes with the same name.
I would just remove the "simple" from $subject. This is just *amazing*,
Jose. Thank you very much for working on a way to enable the testing of
this feature for everyone. I really appreciate your effort.
I tried running the tests here, and apparently everything works OK. I
also read pdtrace's code specifically, and it looks good to, with decent
documentation.
I think this specific patch is ready to be checked in, unless someone
else has more comments about it.
Thanks,
> gdb/testsuite/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * lib/dtrace.exp: New file.
> * gdb.base/dtrace-probe.exp: Likewise.
> * gdb.base/dtrace-probe.d: Likewise.
> * gdb.base/dtrace-probe.c: Likewise.
> * lib/pdtrace: Likewise.
> ---
> gdb/testsuite/ChangeLog | 8 +
> gdb/testsuite/gdb.base/dtrace-probe.c | 38 ++
> gdb/testsuite/gdb.base/dtrace-probe.d | 21 +
> gdb/testsuite/gdb.base/dtrace-probe.exp | 106 ++++
> gdb/testsuite/lib/dtrace.exp | 71 +++
> gdb/testsuite/lib/pdtrace | 1017 +++++++++++++++++++++++++++++++
> 6 files changed, 1261 insertions(+)
> create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.c
> create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.d
> create mode 100644 gdb/testsuite/gdb.base/dtrace-probe.exp
> create mode 100644 gdb/testsuite/lib/dtrace.exp
> create mode 100755 gdb/testsuite/lib/pdtrace
>
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.c b/gdb/testsuite/gdb.base/dtrace-probe.c
> new file mode 100644
> index 0000000..61cd166
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.c
> @@ -0,0 +1,38 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 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/>. */
> +
> +#include "dtrace-probe.h"
> +
> +int
> +main ()
> +{
> + char *name = "application";
> +
> + TEST_TWO_LOCATIONS ();
> +
> + int i = 0;
> + while (i < 10)
> + {
> + i++;
> + if (TEST_PROGRESS_COUNTER_ENABLED ())
> + TEST_PROGRESS_COUNTER (name, i);
> + else
> + TEST_TWO_LOCATIONS ();
> + }
> +
> + return 0; /* last break here */
> +}
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.d b/gdb/testsuite/gdb.base/dtrace-probe.d
> new file mode 100644
> index 0000000..d691d3f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.d
> @@ -0,0 +1,21 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 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/>. */
> +
> +provider test {
> + probe progress__counter (char *, int);
> + probe two__locations ();
> +};
> diff --git a/gdb/testsuite/gdb.base/dtrace-probe.exp b/gdb/testsuite/gdb.base/dtrace-probe.exp
> new file mode 100644
> index 0000000..cbc6fdb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/dtrace-probe.exp
> @@ -0,0 +1,106 @@
> +# Copyright (C) 2014 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/>.
> +
> +load_lib "dtrace.exp"
> +
> +# Run the tests.
> +# This returns -1 on failure to compile or start, 0 otherwise.
> +proc dtrace_test {} {
> + global testfile hex srcfile binfile
> +
> + standard_testfile
> +
> + if {[dtrace_build_usdt_test_program] == -1} {
> + untested "could not compile test program"
> + return -1
> + }
> +
> + clean_restart ${binfile}
> +
> + if ![runto_main] {
> + return -1
> + }
> +
> + gdb_test "print \$_probe_argc" "No probe at PC $hex" \
> + "check argument not at probe point"
> +
> + # Test the 'info probes' command.
> + gdb_test "info probes dtrace" \
> + "test *progress-counter *$hex +no.*test *two-locations *$hex +always.*test *two-locations *$hex +always.*" \
> + "info probes dtrace"
> +
> + # Disabling the probe test:two-locations shall have no effect,
> + # since no is-enabled probes are defined for it in the object
> + # file.
> +
> + gdb_test "disable probe test two-locations" \
> + "Probe test:two-locations cannot be disabled.*" \
> + "disable probe test two-locations"
> +
> + # On the other hand, the probe test:progress-counter can be
> + # enabled and then disabled again.
> +
> + gdb_test "enable probe test progress-counter" \
> + "Probe test:progress-counter enabled.*" \
> + "enable probe test progress-counter"
> +
> + gdb_test "disable probe test progress-counter" \
> + "Probe test:progress-counter disabled.*" \
> + "disable probe test progress-counter"
> +
> + # Since test:progress-counter is disabled we can run to the second
> + # instance of the test:two-locations probe.
> +
> + if {![runto "-probe-dtrace test:two-locations"]} {
> + fail "run to the first test:two-locations probe point"
> + }
> + if {![runto "-probe-dtrace test:two-locations"]} {
> + fail "run to the second test:two-locations probe point"
> + }
> +
> + # Go back to the breakpoint on main() and enable the
> + # test:progress-counter probe. Set a breakpoint on it and see
> + # that it gets reached.
> +
> + if ![runto_main] {
> + return -1
> + }
> +
> + gdb_test "enable probe test progress-counter" \
> + "Probe test:progress-counter enabled.*" \
> + "enable probe test progress-counter"
> +
> + gdb_test "break -probe-dtrace test:progress-counter" \
> + ".*Breakpoint \[0-9\]+ .*" "set breakpoint in test:progress-counter"
> + gdb_continue_to_breakpoint "test:progress-counter"
> +
> + # Test probe arguments.
> + gdb_test "print \$_probe_argc" " = 2" \
> + "print \$_probe_argc for probe progress-counter"
> + gdb_test "print \$_probe_arg0" \
> + " = $hex \"application\"" \
> + "print \$_probe_arg0 for probe progress-counter"
> + gdb_test "print \$_probe_arg1" " = 1" \
> + "print \$_probe_arg1 for probe progress-counter"
> +
> + # Set a breakpoint with multiple probe locations.
> + gdb_test "break -pdtrace test:two-locations" \
> + "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
> + "set multi-location probe breakpoint (probe two-locations)"
> +
> + return 0
> +}
> +
> +dtrace_test
> diff --git a/gdb/testsuite/lib/dtrace.exp b/gdb/testsuite/lib/dtrace.exp
> new file mode 100644
> index 0000000..dfcdabb
> --- /dev/null
> +++ b/gdb/testsuite/lib/dtrace.exp
> @@ -0,0 +1,71 @@
> +# Copyright 2014 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/>.
> +
> +# Generate a test program containing DTrace USDT probes, whose sources
> +# are ${srcfile} and ${testfile}.d. The sequence of commands used to
> +# generate the test program is:
> +#
> +# 1. Generate a header file from ${testfile}.d using dtrace -h.
> +# 2. Compile ${srcfile}.c.
> +# 3. Generate an object file containing a DOF program using dtrace -G.
> +# 4. Link everything together to get the test program.
> +#
> +# Note that if DTrace is not found in the host system then this
> +# function uses the pdtrace implementation, which is located at
> +# testsuite/lib/pdtrace.
> +#
> +# This function requires 'testfile', 'srcfile' and 'binfile' to be
> +# properly set.
> +#
> +# This function returns -1 on failure, 0 otherwise
> +proc dtrace_build_usdt_test_program {} {
> + global testfile hex srcdir srcfile subdir binfile
> +
> + # Make sure that dtrace is installed, it is the real one (not the
> + # script installed by SystemTap, for example) and of the right
> + # version (>= 0.4.0). If it is not then use pdtrace instead.
> + set dtrace "dtrace"
> + set result [remote_exec host "$dtrace -V"]
> + if {[lindex $result 0] != 0 || ![regexp {^dtrace: Sun D [0-9]\.[0-9]\.[0-9]} [lindex $result 1]]} {
> + set dtrace "${srcdir}/lib/pdtrace"
> + }
> + set dscript_file "${srcdir}/${subdir}/${testfile}.d"
> +
> + # 1. Generate a header file from testprogram.d using dtrace -h.
> + set out_header_file [standard_output_file "${testfile}.h"]
> + set result [remote_exec host "$dtrace -h -s $dscript_file -o $out_header_file"]
> + verbose -log [lindex $result 1]
> + if {[lindex $result 0] != 0} {
> + return -1
> + }
> +
> + # 2. Compile testprogram.c.
> + set options [list debug additional_flags=-I[file dirname $out_header_file]]
> + if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}.o" object ${options}] != ""} {
> + return -1
> + }
> +
> + # 3. Generate an object file containing a DOF program using dtrace -G.
> + set result [remote_exec host "$dtrace -G -s $dscript_file -o ${binfile}-p.o ${binfile}.o"]
> + verbose -log [lindex $result 1]
> + if {[lindex $result 0] != 0} {
> + return -1
> + }
> +
> + # 4. Link everything together to get the test program.
> + if {[gdb_compile "${binfile}.o ${binfile}-p.o" ${binfile} executable {debug}] != ""} {
> + return -1
> + }
> +}
> diff --git a/gdb/testsuite/lib/pdtrace b/gdb/testsuite/lib/pdtrace
> new file mode 100755
> index 0000000..39fe4d6
> --- /dev/null
> +++ b/gdb/testsuite/lib/pdtrace
> @@ -0,0 +1,1017 @@
> +#!/bin/sh
> +
> +# A Poor(but Free)'s Man dtrace
> +#
> +# Copyright (C) 2014 Free Software Foundation, Inc.
> +#
> +# Contributed by Oracle, 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/>.
> +
> +# DISCLAIMER DISCLAIMER DISCLAIMER
> +# This script is a test tool. As such it is in no way intended to
> +# replace the "real" dtrace command for any practical purpose, apart
> +# from testing the DTrace USDT probes support in GDB.
> +
> +# that said...
> +#
> +# pdtrace is a limited dtrace program, implementing a subset of its
> +# functionality:
> +#
> +# - The generation of an ELF file containing an embedded dtrace
> +# program. Equivalent to dtrace -G.
> +#
> +# - The generation of a header file with definitions for static
> +# probes. Equivalent to dtrace -h.
> +#
> +# This allows to generate DTrace static probes without having to use
> +# the user-level DTrace components. The generated objects are 100%
> +# compatible with DTrace and can be traced by the dtrace kernel module
> +# like if they were generated by dtrace.
> +#
> +# Some of the known limitations of this implementation are:
> +# - The input d-script must describe one provider, and only one.
> +# - The "probe " directives in the d-file must not include argument
> +# names, just the types. Thus something like `char *' is valid, but
> +# `char *name' is not.
> +# - The command line options must precede other arguments, since the
> +# script uses the (more) portable getopts.
> +# - Each probe header in the d-script must be contained in
> +# a single line.
> +# - strip -K removes the debugging information from the input object
> +# file.
> +# - The supported target platforms are i[3456]86 and x86_64.
> +#
> +# This script uses the following external programs: tr, nm, egrep,
> +# sed, cut, readelf, sort, expr, wc, uniq, head, seq, as, strip, true
> +#
> +# Please keep this code as portable as possible. Restrict yourself to
> +# POSIX sh.
> +
> +# Sizes for several DOF structures, in bytes.
> +#
> +# See linux/dtrace/dof.h for the definition of the referred
> +# structures.
> +
> +dof_hdrsize=64 # sizeof(dtrace_dof_hdr)
> +dof_secsize=32 # sizeof(dtrace_dof_sect)
> +dof_probesize=48 # sizeof(dtrace_dof_probe)
> +dof_providersize=44 # sizeof(dtrace_dof_provider)
> +
> +# Types for the several DOF sections.
> +#
> +# See linux/dtrace/dof_defines.h for a complete list of section types
> +# along with their values.
> +
> +dof_sect_type_strtab=8
> +dof_sect_type_provider=15
> +dof_sect_type_probes=16
> +dof_sect_type_prargs=17
> +dof_sect_type_proffs=18
> +dof_sect_type_prenoffs=26
> +
> +### Functions
> +
> +# Write a message to the standard error output and exit with an error
> +# status.
> +#
> +# Arguments:
> +# $1 error message.
> +
> +f_panic()
> +{
> + echo "error: $1" 1>&2; exit 1
> +}
> +
> +# Write a usage message to the standard output and exit with an error
> +# status.
> +
> +f_usage()
> +{
> + printf "Usage: pdtrace [-32|-64] [-GhV] [-o output] [-s script] [ args ... ]\n\n"
> +
> + printf "\t-32 generate 32-bit ELF files\n"
> + printf "\t-64 generate 64-bit ELF files\n\n"
> +
> + printf "\t-G generate an ELF file containing embedded dtrace program\n"
> + printf "\t-h generate a header file with definitions for static probes\n"
> + printf "\t-o set output file\n"
> + printf "\t-s handle probes according to the specified D script\n"
> + printf "\t-V report the DTrace API version implemented by the tool\n"
> + exit 2
> +}
> +
> +# Write a version message to the standard output and exit with a
> +# successful status.
> +
> +f_version()
> +{
> + echo "pdtrace: Sun D 1.6.3"
> + exit
> +}
> +
> +# Add a new record to a list and return it.
> +#
> +# Arguments:
> +# $1 is the list.
> +# $2 is the new record
> +
> +f_add_record()
> +{
> + rec=$1
> + test -n "$rec" && \
> + { rec=$(printf %s\\n "$rec"; echo x); rec=${rec%x}; }
> + printf %s "$rec$2"
> +}
> +
> +# Collect the providers and probes information from the input object
> +# file.
> +#
> +# This function sets the values of the following global variables.
> +# The values are structured in records, each record in a line. The
> +# fields of each record are separated in some cases by white
> +# characters and in other cases by colon (:) characters.
> +#
> +# The type codes in the line format descriptors are:
> +# S: string, D: decimal number
> +#
> +# probes
> +# Regular probes and is-enabled probes.
> +# TYPE(S) PROVIDER(S) NAME(S) OFFSET(D) BASE(D) BASE_SYM(S)
> +# base_probes
> +# Base probes, i.e. probes sharing provider, name and container.
> +# PROVIDER(S) NAME(S) BASE(D) BASE_SYM(S)
> +# providers
> +# List of providers.
> +# PROVIDER(S)
> +# All the offsets are expressed in bytes.
> +#
> +# Input globals:
> +# objfile
> +# Output globals:
> +# probes, base_probes, providers
> +
> +probes=
> +base_probes=
> +providers=
> +probes_args=
> +
> +f_collect_probes()
> +{
> + # Probe points are function calls to undefined functions featuring
> + # distinct names for both normal probes and is-enabled probes.
> + PROBE_REGEX="(__dtrace_([a-zA-Z_]+)___([a-zA-Z_]+))"
> + EPROBE_REGEX="(__dtraceenabled_([a-zA-Z_]+)___([a-zA-Z_]+))"
> +
> + while read type symbol provider name; do
> + test -z "$type" && f_panic "No probe points found in $objfile"
> +
> + provider=$(printf %s $provider | tr -s _)
> + name=$(printf %s $name | tr -s _)
> +
> + # Search the object file for relocations defined for the
> + # probe symbols. Then calculate the base address of the
> + # probe (along with the symbol associated with that base
> + # address) and the offset of the probe point.
> + for offset in $(readelf -W -r $objfile | grep $symbol | cut -d' ' -f1)
> + do
> + # Figure out the base address for the probe. This is
> + # done finding the function name in the text section of
> + # the object file located above the probed point. But
> + # note that the relocation is for the address operand of
> + # the call instruction, so we have to subtract 1 to find
> + # the real probed point.
> + offset=$((0x$offset - 1))
> +
> + # The addresses of is-enabled probes must point to the
> + # first NOP instruction in their patched instructions
> + # sequences, so modify them (see f_patch_objfile for the
> + # instruction sequences).
> + if test "$type" = "e"; then
> + if test "$objbits" -eq "32"; then
> + offset=$((offset + 2))
> + else # 64 bits
> + offset=$((offset + 3))
> + fi
> + fi
> +
> + # Determine the base address of the probe and its
> + # corresponding function name.
> + funcs=$(nm -td $objfile | egrep "^[0-9]+ T " \
> + | cut -d' ' -f1,3 | sort -n -r | tr ' ' :)
> + for fun in $funcs; do
> + func_off=$(printf %s $fun | cut -d: -f1)
> + func_sym=$(printf %s $fun | cut -d: -f2)
> + # Note that `expr' is used to remove leading zeros
> + # to avoid FUNC_OFF to be interpreted as an octal
> + # number in arithmetic contexts.
> + test "$func_off" -le "$offset" && \
> + { base=$(expr $func_off + 0); break; }
> + done
> + test -n "$base" || \
> + f_panic "could not find base address for probe at $objfile($o)"
> +
> + # Emit the record for the probe.
> + probes=$(f_add_record "$probes" \
> + "$type $provider $name $(($offset - $base)) $base $func_sym")
> + done
> + done <<EOF
> +$(nm $objfile | egrep " U $PROBE_REGEX" \
> + | sed -E -e "s/.*$PROBE_REGEX.*/p \1 \2 \3/";
> + nm $objfile | egrep " U $EPROBE_REGEX" \
> + | sed -E -e "s/.*$EPROBE_REGEX.*/e \1 \2 \3/")
> +EOF
> +
> + # Build the list of providers and of base probes from the probes.
> + while read type provider name offset base base_sym; do
> + providers=$(f_add_record "$providers" "$provider")
> + base_probes=$(f_add_record "$base_probes" "$provider $name $base $base_sym")
> + done <<EOF
> +$probes
> +EOF
> + providers=$(printf %s\\n "$providers" | sort | uniq)
> + base_probes=$(printf %s\\n "$base_probes" | sort | uniq)
> +}
> +
> +# Collect the argument counts and type strings for all the probes
> +# described in the `probes' global variable. This is done by
> +# inspecting the d-script file provided by the user.
> +#
> +# This function sets the values of the following global variables.
> +# The values are structured in records, each record in a line. The
> +# fields of each record are separated in some cases by white
> +# characters and in other cases by colon (:) characters.
> +#
> +# The type codes in the line format descriptors are:
> +# S: string, D: decimal number
> +#
> +# probes_args
> +# Probes arguments.
> +# PROVIDER(S):NAME(S):NARGS(D):ARG1(S):ARG2(S):...:ARGn(S)
> +#
> +# Input globals:
> +# probes
> +# Output globals:
> +# probes_args
> +# Arguments:
> +# $1 is the d-script file from which to extract the arguments
> +# information.
> +
> +f_collect_probes_args()
> +{
> + dscript=$1
> + while read type provider name offset base base_sym; do
> + # Process normal probes only. Is-enabled probes are not
> + # described in the d-script file and they don't receive any
> + # argument.
> + test "$type" = "p" || continue
> +
> + # Names are mangled in d-script files to make it possible to
> + # have underscore characters as part of the provider name and
> + # probe name.
> + m_provider=$(printf %s $provider | sed -e 's/_/__/g')
> + m_name=$(printf %s $name | sed -e 's/_/__/g')
> +
> + # Ignore this probe if the d-script file does not describe its
> + # provider.
> + egrep -q "provider +$m_provider" $dscript || continue
> +
> + # Look for the line containing the description of the probe.
> + # If we can't find it then ignore this probe.
> + line=$(egrep "^ *probe +$m_name *\(.*\);" $dscript)
> + test -n "$line" || continue
> +
> + # Ok, extract the argument types from the probe prototype.
> + # This is fragile as hell as it requires the prototype to be
> + # in a single line.
> + args=""; nargs=0; line=$(printf %s "$line" | sed -e 's/.*(\(.*\)).*/\1/')
> + set -f; IFS=,
> + for arg in $line; do
> + args="$args:$arg"
> + nargs=$((nargs + 1))
> + done
> + set +f; unset IFS
> +
> + # Emit the record for the probe arguments.
> + probes_args=$(f_add_record "$probes_args" "$provider:$name:$nargs$args")
> + done <<EOF
> +$probes
> +EOF
> +}
> +
> +# Functions to manipulate the global BCOUNT.
> +
> +BCOUNT=0
> +
> +f_incr_bcount()
> +{
> + BCOUNT=$((BCOUNT + $1))
> +}
> +
> +f_align_bcount()
> +{
> + test $((BCOUNT % $1)) -eq 0 || BCOUNT=$((BCOUNT + ($1 - (BCOUNT % $1))))
> +}
> +
> +# Generate a line of assembly code and add it to the asmprogram global
> +# variable.
> +#
> +# Arguments:
> +# $1 string to generate in a line.
> +
> +asmprogram=
> +
> +f_gen_asm()
> +{
> + line=$(printf "\t$1")
> + asmprogram=$(f_add_record "$asmprogram" "$line")
> +}
> +
> +# Helper function to generate the assembly code of a DOF section
> +# header.
> +#
> +# This function is used by `f_gen_dof_program'.
> +#
> +# Arguments:
> +# $1 is the name of the described section.
> +# $2 is the type of the described section.
> +# $3 is the alignment of the described section.
> +# $4 is the number of entities stored in the described section.
> +# $5 is the offset in the DOF program of the described section.
> +# $6 is the size of the described section, in bytes.
> +
> +f_gen_dof_sect_header()
> +{
> + f_gen_asm ""
> + f_gen_asm "/* dtrace_dof_sect for the $1 section. */"
> + f_gen_asm ".balign 8"
> + f_gen_asm ".4byte $2\t/* uint32_t dofs_type */"
> + f_gen_asm ".4byte $3\t/* uint32_t dofs_align */"
> + # The DOF_SECF_LOAD flag is 1 => loadable section.
> + f_gen_asm ".4byte 1\t/* uint32_t dofs_flags */"
> + f_gen_asm ".4byte $4\t/* uint32_t dofs_entsize */"
> + f_gen_asm ".8byte $5\t/* uint64_t dofs_offset */"
> + f_gen_asm ".8byte $6\t/* uint64_t dofs_size */"
> +}
> +
> +# Generate a DOF program and assembly it in the output file.
> +#
> +# The DOF program generated by this function has the following
> +# structure:
> +#
> +# HEADER
> +# STRTAB OFFTAB EOFFTAB [PROBES PROVIDER]...
> +# STRTAB_SECT OFFTAB_SECT EOFFTAB_SECT ARGTAB_SECT [PROBES_SECT PROVIDER_SECT]...
> +#
> +# Input globals:
> +# probes, base_probes, providers, probes_args, BCOUNT
> +
> +f_gen_dof_program()
> +{
> + ###### Variables used to cache information needed later.
> +
> + # Number of section headers in the generated DOF program.
> + dof_secnum=0
> + # Offset of section headers in the generated DOF program, in bytes.
> + dof_secoff=0
> +
> + # Sizes of the STRTAB, OFFTAB and EOFFTAB sections, in bytes.
> + strtab_size=0
> + offtab_size=0
> + eofftab_size=0
> +
> + # Offsets of the STRTAB, OFFTAB EOFFTAB and PROBES sections in the
> + # generated DOF program. In bytes.
> + strtab_offset=0
> + offtab_offset=0
> + eofftab_offset=0
> + argtab_offset=0
> + probes_offset=0
> +
> + # Indexes of the section headers of the STRTAB, OFFTAB, EOFFTAB and
> + # PROBES sections in the sections array.
> + strtab_sect_index=0
> + offtab_sect_index=0
> + eofftab_sect_index=0
> + argtab_sect_index=0
> + probes_sect_index=0
> +
> + # First offsets and eoffsets of the base-probes.
> + # Lines: PROVIDER(S) NAME(S) BASE(D) (DOF_OFFSET(D)|DOF_EOFFSET(D))
> + probes_dof_offsets=
> + probes_dof_eoffsets=
> +
> + # Offsets in the STRTAB section for the first type of base probes.
> + # Record per line: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
> + probes_dof_types=
> +
> +
> + # Offsets of the provider names in the provider's STRTAB section.
> + # Lines: PROVIDER(S) OFFSET(D)
> + providers_dof_names=
> +
> + # Offsets of the base-probe names in the provider's STRTAB section.
> + # Lines: PROVIDER(S) NAME(S) BASE(D) OFFSET(D)
> + probes_dof_names=
> +
> + # Offsets of the provider sections in the DOF program.
> + # Lines: PROVIDER(S) OFFSET(D)
> + providers_offsets=
> +
> + ###### Generation phase.
> +
> + # The header of the DOF program contains a `struct
> + # dtrace_dof_hdr'. Record its size, but it is written at the end
> + # of the function.
> + f_incr_bcount $dof_hdrsize; f_align_bcount 8
> +
> + # The STRTAB section immediately follows the header. It contains
> + # the following set of packed null-terminated strings:
> + #
> + # [PROVIDER [BASE_PROBE_NAME [BASE_PROBE_ARG_TYPE...]]...]...
> + strtab_offset=$BCOUNT
> + strtab_sect_index=$dof_secnum
> + dof_secnum=$((dof_secnum + 1))
> + f_gen_asm ""
> + f_gen_asm "/* The STRTAB section. */"
> + f_gen_asm ".balign 8"
> + # Add the provider names.
> + off=0
> + while read provider; do
> + strtab_size=$(($strtab_size + ${#prov} + 1))
> + # Note the funny mangling...
> + f_gen_asm ".asciz \"$(printf %s $provider | tr _ -)\""
> + providers_dof_names=$(f_add_record "$providers_dof_names" \
> + "$provider $off")
> + off=$(($off + ${#provider} + 1))
> +
> + # Add the base-probe names.
> + while read p_provider name base base_sym; do
> + test "$p_provider" = "$provider" || continue
> + # And yes, more funny mangling...
> + f_gen_asm ".asciz \"$(printf %s $name | tr _ -)\""
> + probes_dof_names=$(f_add_record "$probes_dof_names" \
> + "$p_provider $name $base $off")
> + off=$(($off + ${#name} + 1))
> + while read args; do
> + a_provider=$(printf %s "$args" | cut -d: -f1)
> + a_name=$(printf %s "$args" | cut -d: -f2)
> + test "$a_provider" = "$p_provider" \
> + && test "$a_name" = "$name" \
> + || continue
> +
> + probes_dof_types=$(f_add_record "$probes_dof_types" \
> + "$a_provider $name $base $off")
> + nargs=$(printf %s "$args" | cut -d: -f3)
> + for n in $(seq $nargs); do
> + arg=$(printf %s "$args" | cut -d: -f$(($n + 3)))
> + f_gen_asm ".asciz \"${arg}\""
> + off=$(($off + ${#arg} + 1))
> + done
> + done <<EOF
> +$probes_args
> +EOF
> + done <<EOF
> +$base_probes
> +EOF
> + done <<EOF
> +$providers
> +EOF
> + strtab_size=$off
> + f_incr_bcount $strtab_size; f_align_bcount 8
> +
> + # The OFFTAB section contains a set of 32bit words, one per
> + # defined regular probe.
> + offtab_offset=$BCOUNT
> + offtab_sect_index=$dof_secnum
> + dof_secnum=$((dof_secnum + 1))
> + f_gen_asm ""
> + f_gen_asm "/* The OFFTAB section. */"
> + f_gen_asm ".balign 8"
> + off=0
> + while read type provider name offset base base_sym; do
> + test "$type" = "p" || continue
> + f_gen_asm ".4byte $offset\t/* probe ${provider}:${name} */"
> + probes_dof_offsets=$(f_add_record "$probes_dof_offsets" \
> + "$provider $name $base $off")
> + off=$(($off + 4))
> + done <<EOF
> +$probes
> +EOF
> + offtab_size=$off
> + f_incr_bcount $offtab_size; f_align_bcount 8
> +
> + # The EOFFTAB section contains a set of 32bit words, one per
> + # defined is-enabled probe.
> + eofftab_offset=$BCOUNT
> + eofftab_sect_index=$dof_secnum
> + dof_secnum=$((dof_secnum + 1))
> + f_gen_asm ""
> + f_gen_asm "/* The EOFFTAB section. */"
> + f_gen_asm ".balign 8"
> + off=0
> + while read type provider name offset base base_sym; do
> + test "$type" = "e" || continue
> + f_gen_asm ".4byte $offset\t/* is-enabled probe ${provider}:${name} */"
> + probes_dof_eoffsets=$(f_add_record "$probes_dof_eoffsets" \
> + "$provider $name $base $off")
> + off=$(($off + 4))
> + done <<EOF
> +$probes
> +EOF
> + eofftab_size=$off
> + f_incr_bcount $eofftab_size; f_align_bcount 8
> +
> + # The ARGTAB section is empty, but nonetheless has a section
> + # header, so record its section index here.
> + argtab_offset=0
> + argtab_sect_index=$dof_secnum
> + dof_secnum=$((dof_secnum + 1))
> +
> + # Generate a pair of sections PROBES and PROVIDER for each
> + # provider.
> + while read prov; do
> + # The PROBES section contains an array of `struct
> + # dtrace_dof_probe'.
> + #
> + # A `dtrace_dof_probe' entry characterizes the collection of
> + # probes and is-enabled probes sharing the same provider, name and
> + # base address.
> + probes_sect_index=$dof_secnum
> + dof_secnum=$((dof_secnum + 1))
> + probes_offset=$BCOUNT
> + num_base_probes=$(printf %s\\n "$base_probes" | wc -l)
> + while read provider name base base_sym; do
> + name_offset=$(printf %s\\n "$probes_dof_names" \
> + | egrep "^$provider $name " | cut -d' ' -f4)
> +
> + num_offsets=$(printf %s\\n "$probes_dof_offsets" \
> + | egrep "^$provider $name [0-9]+ " | wc -l)
> +
> + first_offset=0
> + test "$num_offsets" -gt 0 && \
> + first_offset=$(printf %s\\n "$probes_dof_offsets" \
> + | egrep "^$provider $name " | cut -d' ' -f4 | head -1)
> +
> + num_eoffsets=$(printf %s\\n "$probes_dof_eoffsets" \
> + | egrep "^$provider $name [0-9]+ " | wc -l)
> + first_eoffset=0
> + test "$num_eoffsets" -gt 0 && \
> + first_eoffset=$(printf %s "$probes_dof_eoffsets" \
> + | egrep "^$provider $name " | cut -d' ' -f4 | head -1)
> +
> + num_args=$(printf %s "$probes_args" \
> + | egrep "^$provider:$name:" | cut -d: -f3 | head -1)
> +
> + first_type=$(printf %s "$probes_dof_types" \
> + | egrep "^$provider $name $base " | cut -d' ' -f4 | head -1)
> +
> + reloctype=R_X86_64_GLOB_DAT
> + test "$objbits" = "32" && reloctype=R_386_32
> +
> + f_gen_asm ""
> + f_gen_asm "/* dtrace_dof_probe for ${provider}:${name} at ${base_sym} */"
> + f_gen_asm ".balign 8"
> + f_gen_asm ".reloc ., $reloctype, $base_sym + 0"
> + f_gen_asm ".8byte ${base}\t/* uint64_t dofpr_addr */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpr_func */"
> + f_gen_asm ".4byte $name_offset\t/* uint32_t dofpr_name */"
> + f_gen_asm ".4byte $first_type\t/* uint32_t dofpr_nargv */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpr_xargv */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpr_argidx */"
> + f_gen_asm ".4byte $(($first_offset/4))\t/* uint32_t dofpr_offidx */"
> + f_gen_asm ".byte $num_args\t/* uint8_t dofpr_nargc */"
> + f_gen_asm ".byte 0\t/* uint8_t dofpr_xargc */"
> + f_gen_asm ".2byte $num_offsets\t/* uint16_t dofpr_noffs */"
> + f_gen_asm ".4byte $(($first_eoffset/4))\t/* uint32_t dofpr_enoffidx */"
> + f_gen_asm ".2byte $num_eoffsets\t/* uint16_t dofpr_nenoffs */"
> + f_gen_asm ".2byte 0\t/* uint16_t dofpr_pad1 */"
> + f_gen_asm ".4byte 0\t/* uint16_t dofpr_pad2 */"
> +
> + f_incr_bcount "$dof_probesize"
> + done <<EOF
> +$base_probes
> +EOF
> +
> + # The PROVIDER section contains a `struct dtrace_dof_provider'
> + # instance describing the provider for the probes above.
> + dof_secnum=$((dof_secnum + 1))
> + providers_offsets=$(f_add_record "$providers_offsets" \
> + "$prov $BCOUNT")
> + # The dtrace_dof_provider.
> + provider_name_offset=$(printf %s "$providers_dof_names" \
> + | egrep "^$prov " | cut -d' ' -f2)
> +
> + f_gen_asm ""
> + f_gen_asm "/* dtrace_dof_provider for $prov */"
> + f_gen_asm ".balign 8"
> + # Links to several DOF sections.
> + f_gen_asm ".4byte $strtab_sect_index\t/* uint32_t dofpv_strtab */"
> + f_gen_asm ".4byte $probes_sect_index\t/* uint32_t dofpv_probes */"
> + f_gen_asm ".4byte $argtab_sect_index\t/* uint32_t dofpv_prargs */"
> + f_gen_asm ".4byte $offtab_sect_index\t/* uint32_t dofpv_proffs */"
> + # Offset of the provider name into the STRTAB section.
> + f_gen_asm ".4byte $provider_name_offset\t/* uint32_t dofpv_name */"
> + # The rest of fields can be 0 for our modest purposes :)
> + f_gen_asm ".4byte 0\t/* uint32_t dofpv_provattr */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpv_modattr */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpv_funcattr */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpv_nameattr */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofpv_argsattr */"
> + # But not this one, of course...
> + f_gen_asm ".4byte $eofftab_sect_index\t/* uint32_t dofpv_prenoffs */"
> +
> + f_incr_bcount $dof_providersize
> + done<<EOF
> +$providers
> +EOF
> + f_align_bcount 8
> +
> + # The section headers follow, one per section defined above.
> + dof_secoff=$BCOUNT
> +
> + f_gen_dof_sect_header STRTAB \
> + $dof_sect_type_strtab \
> + 1 1 $strtab_offset $strtab_size
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> + f_gen_dof_sect_header OFFTAB \
> + $dof_sect_type_proffs \
> + 4 4 $offtab_offset $offtab_size
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> + f_gen_dof_sect_header EOFFTAB \
> + $dof_sect_type_prenoffs \
> + 4 4 $eofftab_offset $eofftab_size
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> + f_gen_dof_sect_header ARGTAB \
> + $dof_sect_type_prargs \
> + 4 1 $argtab_offset 0
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> + while read provider; do
> + provider_offset=$(printf %s "$providers_offsets" \
> + | egrep "^$provider " | cut -d' ' -f2)
> + num_base_probes=$(printf %s\\n "$base_probes" | wc -l)
> +
> + f_gen_dof_sect_header "$provider probes" \
> + $dof_sect_type_probes \
> + 8 $dof_probesize $probes_offset \
> + $((num_base_probes * dof_probesize))
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> +
> + f_gen_dof_sect_header "$provider provider" \
> + $dof_sect_type_provider \
> + 8 1 $provider_offset $dof_providersize
> + f_incr_bcount $dof_secsize; f_align_bcount 8
> + done <<EOF
> +$providers
> +EOF
> +
> + # Finally, cook the header.
> + asmbody="$asmprogram"
> + asmprogram=""
> + f_gen_asm "/* File generated by pdtrace. */"
> + f_gen_asm ""
> +
> + f_gen_asm ".section .SUNW_dof,\"a\",\"progbits\""
> + f_gen_asm ".globl __SUNW_dof"
> + f_gen_asm ".hidden __SUNW_dof"
> + f_gen_asm ".size __SUNW_dof, ${BCOUNT}"
> + f_gen_asm ".type __SUNW_dof, @object"
> + f_gen_asm "__SUNW_dof:"
> +
> + f_gen_asm ""
> + f_gen_asm "/* dtrace_dof_hdr */"
> + f_gen_asm ".balign 8"
> + f_gen_asm ".byte 0x7f, 'D, 'O, 'F\t/* dofh_ident[0..3] */"
> + f_gen_asm ".byte 2\t\t/* model: 1=ILP32, 2=LP64 */"
> + f_gen_asm ".byte 1\t\t/* encoding: 1: little-endian, 2: big-endian */"
> + f_gen_asm ".byte 2\t\t/* DOF version: 1 or 2. Latest is 2 */"
> + f_gen_asm ".byte 2\t\t/* DIF version: 1 or 2. Latest is 2 */"
> + f_gen_asm ".byte 8\t\t/* number of DIF integer registers */"
> + f_gen_asm ".byte 8\t\t/* number of DIF tuple registers */"
> + f_gen_asm ".byte 0, 0\t\t/* dofh_ident[10..11] */"
> + f_gen_asm ".4byte 0\t\t/* dofh_ident[12..15] */"
> + f_gen_asm ".4byte 0\t/* uint32_t dofh_flags */" # See Limitations above.
> + f_gen_asm ".4byte ${dof_hdrsize}\t/* uint32_t dofh_hdrsize */"
> + f_gen_asm ".4byte ${dof_secsize}\t/* uint32_t dofh_secsize */"
> + f_gen_asm ".4byte ${dof_secnum}\t/* uint32_t dofh_secnum */"
> + f_gen_asm ".8byte ${dof_secoff}\t/* uint64_t dofh_secoff */"
> + f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_loadsz */"
> + f_gen_asm ".8byte ${BCOUNT}\t/* uint64_t dofh_filesz */"
> + f_gen_asm ".8byte 0\t/* uint64_t dofh_pad */"
> + f_gen_asm ""
> +
> + # Ok, now assembly the program in OFILE
> + echo "$asmprogram$asmbody" | as -$objbits -o $ofile
> +
> + # Next step is to change the sh_type of the ".SUNW_dof" section
> + # headers to 0x6ffffff4 (SHT_SUNW_dof).
> + #
> + # Note that this code relies in the fact that readelf will list
> + # the sections ordered in the same order than the section headers
> + # in the section header table of the file.
> + elfinfo=$(readelf -a $ofile)
> +
> + # Mind the endianness.
> + if printf %s "$elfinfo" | egrep -q "little endian"; then
> + sht_sunw_dof=$(printf %s%s%s%s \\364 \\377 \\377 \\157)
> + else
> + sht_sunw_dof=$(printf %s%s%s%s \\157 \\377 \\377 \\364)
> + fi
> +
> + shdr_start=$(printf %s "$elfinfo" \
> + | egrep "^[ \t]*Start of section headers:" \
> + | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> + test -n "$shdr_start" \
> + || f_panic "could not extract the start of shdr from $ofile"
> +
> + shdr_num_entries=$(printf %s "$elfinfo" \
> + | egrep "^[ \t]*Size of section headers:" \
> + | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> + test -n "$shdr_num_entries" \
> + || f_panic "could not extract the number of shdr entries from $ofile"
> +
> + shdr_entry_size=$(printf %s "$elfinfo" \
> + | egrep "^[ \t]*Size of section headers:" \
> + | sed -E -e 's/.*headers:[ \t]*([0-9]+).*/\1/')
> + test -n "$shdr_entry_size" \
> + || f_panic "could not fetch the size of section headers from $ofile"
> +
> + while read line; do
> + data=$(printf %s "$line" \
> + | sed -E -e 's/.*\[(.*)\][ \t]+([a-zA-Z_.]+).*/\1:\2/')
> + num=$(printf %s "$data" | cut -d: -f1)
> + name=$(printf %s "$data" | cut -d: -f2)
> + if test "$name" = ".SUNW_dof"; then
> + # Patch the new sh_type in the proper entry of the section
> + # header table.
> + printf "$sht_sunw_dof" \
> + | dd of=$ofile conv=notrunc count=4 ibs=1 bs=1 \
> + seek=$((shdr_start + (shdr_entry_size * num) + 4)) \
> + 2> /dev/null
> + break
> + fi
> + done <<EOF
> +$(printf %s "$elfinfo" | egrep "^[ \t]*\[[0-9 ]+\].*[A-Z]+.*PROGBITS")
> +EOF
> +
> +}
> +
> +# Patch the probed points in the given object file, replacing the
> +# function calls with NOPs.
> +#
> +# The probed points in the input object files are function calls.
> +# This function replaces these function calls by some other
> +# instruction sequences. Which replacement to use depends on several
> +# factors, as documented below.
> +#
> +# Arguments:
> +# $1 is the object file to patch.
> +
> +f_patch_objfile()
> +{
> + objfile=$1
> +
> + # Several x86_64 instruction opcodes, in octal.
> + x86_op_nop=$(printf \\220)
> + x86_op_ret=$(printf \\303)
> + x86_op_call=$(printf \\350)
> + x86_op_jmp32=$(printf \\351)
> + x86_op_rex_rax=$(printf \\110)
> + x86_op_xor_eax_0=$(printf \\063)
> + x86_op_xor_eax_1=$(printf \\300)
> +
> + # Figure out the file offset of the text section in the object
> + # file.
> + text_off=0x$(objdump -j .text -h $objfile \
> + | grep \.text | tr -s ' ' | cut -d' ' -f 7)
> +
> + while read type provider name offset base base_sym; do
> + # Calculate the offset of the probed point in the object file.
> + # Note that the `offset' of is-enabled probes is tweaked in
> + # `f_collect_probes" to point ahead the patching point.
> + probe_off=$((text_off + base + offset))
> + if test "$type" = "e"; then
> + if test "$objbits" -eq "32"; then
> + probe_off=$((probe_off - 2))
> + else # 64 bits
> + probe_off=$((probe_off - 3))
> + fi
> + fi
> +
> + # The probed point can be either a CALL instruction o a JMP
> + # instruction (a tail call). This has an impact on the
> + # patching sequence. Fetch the first byte at the probed point
> + # and do the right thing.
> + nopret="$x86_op_nop"
> + byte=$(dd if=$objfile count=1 ibs=1 bs=1 skip=$probe_off 2> /dev/null)
> + test "$byte" = "$x86_op_jmp32" && nopret="$x86_op_ret"
> +
> + # Determine the patching sequence. It depends on the type of
> + # probe at hand (regular or is-enabled) and also if
> + # manipulating a 32bit or 64bit binary.
> + patchseq=
> + case $type in
> + p) patchseq=$(printf %s%s%s%s%s \
> + "$nopret" \
> + "$x86_op_nop" \
> + "$x86_op_nop" \
> + "$x86_op_nop" \
> + "$x86_op_nop")
> + ;;
> + e) test "$objbits" -eq 64 && \
> + patchseq=$(printf %s%s%s%s%s \
> + "$x86_op_rex_rax" \
> + "$x86_op_xor_eax_0" \
> + "$x86_op_xor_eax_1" \
> + "$nopret" \
> + "$x86_op_nop")
> + test "$objbits" -eq 32 && \
> + patchseq=$(printf %s%s%s%s%s \
> + "$x86_op_xor_eax_0" \
> + "$x86_op_xor_eax_1" \
> + "$nopret" \
> + "$x86_op_nop" \
> + "$x86_op_nop")
> + ;;
> + *) f_panic "internal error: wrong probe type $type";;
> + esac
> +
> + # Patch!
> + printf %s "$patchseq" \
> + | dd of=$objfile conv=notrunc count=5 ibs=1 bs=1 seek=$probe_off 2> /dev/null
> + done <<EOF
> +$probes
> +EOF
> +
> + # Finally, we have to remove the __dtrace_* and __dtraceenabled_*
> + # symbols from the object file, along with their respective
> + # relocations.
> + #
> + # Note that the most obvious call:
> + # strip -v -N whatever -w foo.o
> + # will not work:
> + # strip: not stripping symbol `whatever' because it is named in a relocation
> + #
> + # Fortunately using `-K !whatever' instead tricks strip to do the
> + # right thing, but this is black magic and may eventually stop
> + # working...
> + strip -K '!__dtrace_*' -w $objfile
> + strip -K '!__dtraceenabled_*' -w $objfile
> +}
> +
> +# Read the input .d file and print a header file with macros to
> +# invoke the probes defined in it.
> +
> +f_gen_header_file()
> +{
> + guard=$(basename $ofile | tr - _ | cut -d. -f1 | tr a-z A-Z)
> + printf "/*\n * Generated by pdtrace.\n */\n\n"
> +
> + printf "#ifndef _${guard}_H\n"
> + printf "#define _${guard}_H\n\n"
> +
> + printf "#include <unistd.h>\n"
> + printf "#include <inttypes.h>\n"
> + printf \\n\\n
> +
> + printf "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"
> +
> + printf "#define _DTRACE_VERSION 1\n\n"
> +
> + provider=$(cat $dfile | egrep "^ *provider +([a-zA-Z_]+)" \
> + | sed -E -e 's/^ *provider +([a-zA-Z]+).*/\1/')
> + test -z "$provider" \
> + && f_panic "unable to parse the provider name from $dfile."
> + u_provider=$(printf %s "$provider" | tr a-z A-Z | tr -s _)
> +
> + cat $dfile | egrep "^ *probe +[a-zA-Z_]+ *\(.*\);" | \
> + while read line; do
> + # Extract the probe name.
> + name=$(printf %s "$line" \
> + | sed -E -e 's/^ *probe +([a-zA-Z_]+).*/\1/')
> + u_name=$(printf %s "$name" | tr a-z A-Z | tr -s _)
> +
> + # Generate an arg1,arg2,...,argN line for the probe.
> + args=""; nargs=0; aline=$(printf %s "$line" | sed -e 's/.*(\(.*\)).*/\1/')
> + set -f; IFS=,
> + for arg in $aline; do
> + args="${args}arg${nargs},"
> + nargs=$((nargs + 1))
> + done
> + set +f; unset IFS
> + args=${args%,}
> +
> + echo "#if _DTRACE_VERSION"
> + echo ""
> +
> + # Emit the macros for the probe.
> + echo "#define ${u_provider}_${u_name}($args) \\"
> + echo " __dtrace_${provider}___${name}($args)"
> + echo "#define ${u_provider}_${u_name}_ENABLED() \\"
> + echo " __dtraceenabled_${provider}___${name}()"
> +
> + # Emit the extern definitions for the probe dummy
> + # functions.
> + echo ""
> + printf %s\\n "$line" \
> + | sed -E -e "s/^ *probe +/extern void __dtrace_${provider}___/"
> + echo "extern int __dtraceenabled_${provider}___${name}(void);"
> +
> +
> + printf "\n#else\n"
> +
> + # Emit empty macros for the probe
> + echo "#define ${u_provider}_${u_name}($args)"
> + echo "#define ${u_provider}_${u_name}_ENABLED() (0)"
> +
> + printf "\n#endif /* _DTRACE_VERSION */\n"
> + done
> +
> + printf "#ifdef __cplusplus\n}\n#endif\n\n"
> + printf "#endif /* _${guard}_H */\n"
> +}
> +
> +### Main program.
> +
> +# Process command line arguments.
> +
> +test "$#" -eq "0" && f_usage
> +
> +genelf=0
> +genheader=0
> +objbits=64
> +ofile=
> +dfile=
> +while getopts VG3264hs:o: name; do
> + case $name in
> + V) f_version;;
> + s) dfile="$OPTARG";
> + test -f "$dfile" || f_panic "cannot read $dfile";;
> + o) ofile="$OPTARG";;
> + G) genelf=1;;
> + h) genheader=1;;
> + # Note the trick to support -32
> + 3) objbits=666;;
> + 2) test "$objbits" -eq 666 || f_usage; objbits=32;;
> + # Likewise for -64
> + 6) objbits=777;;
> + 4) test "$objbits" -eq 777 || f_usage; objbits=64;;
> + ?) f_usage;;
> + esac
> +done
> +shift $(($OPTIND - 1))
> +
> +test "$objbits" -eq "32" || test "$objbits" -eq "64" \
> + || f_usage
> +
> +test $((genelf + genheader)) -gt 1 && \
> + { echo "Please use either -G or -h."; f_usage; }
> +
> +test -n "$dfile" || { echo "Please specify a .d file with -s."; exit 2; }
> +
> +if test "$genelf" -gt 0; then
> + # In this mode there must be a remaining argument: the name of the
> + # object file to inspect for probed points.
> + test "$#" -ne "1" && f_usage
> + test -f "$1" || f_panic "cannot read $1"
> + objfile=$1
> +
> + # Collect probe information from the input object file and the
> + # d-script.
> + f_collect_probes $objfile
> + f_collect_probes_args $dfile
> +
> + # Generate the assembly code and assemble the DOF program in
> + # OFILE. Then patch OBJFILE to remove the dummy probe calls.
> + f_gen_dof_program
> + f_patch_objfile $objfile
> +fi
> +
> +if test "$genheader" -gt 0; then
> + test -n "$ofile" || { echo "Please specify an output file with -o."; exit 2; }
> +
> + # In this mode no extra arguments shall be present.
> + test "$#" -ne "0" && f_usage
> +
> + f_gen_header_file > $ofile
> +fi
> +
> +# pdtrace ends here.
> --
> 1.7.10.4
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 7/9] Simple testsuite for DTrace USDT probes.
2014-10-28 13:45 ` [PATCH V3 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
2014-11-13 23:19 ` Sergio Durigan Junior
@ 2014-11-14 13:03 ` Pedro Alves
1 sibling, 0 replies; 22+ messages in thread
From: Pedro Alves @ 2014-11-14 13:03 UTC (permalink / raw)
To: Jose E. Marchesi, gdb-patches
Man, huge script! I'm not going to pretend I read it. :-P
On 10/28/2014 01:50 PM, Jose E. Marchesi wrote:
> +# This script uses the following external programs: tr, nm, egrep,
> +# sed, cut, readelf, sort, expr, wc, uniq, head, seq, as, strip, true
Hmm, looks like this invokes the system's readelf and strip.
I think we should be running the "transformed" tool name,
like e.g. x86_64-unknown-linux-gnu-strip, etc. ?
In configure.ac we do:
`echo strip | sed -e "$transform"`
In tcl, we do
set strip_to_file_program [transform strip]
Maybe we can make the script pick STRIP and READELF from the
environment, though I don't think that'd work for remote host
testing. Otherwise, what is usually done is run the script
through configure. That is, name it lib/pdtrace.in, and make
the testsuite's configure.ac generate the final pdtrace from that,
substituting @STRIP@ and @READELF@. Like gdb/gcore.in.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 3/9] New commands `enable probe' and `disable probe'.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (4 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 7/9] Simple testsuite for DTrace USDT probes Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 19:04 ` Sergio Durigan Junior
2014-10-28 13:45 ` [PATCH V3 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
` (2 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch adds the above-mentioned commands to the generic probe
abstraction implemented in probe.[ch]. The effects associated to
enabling or disabling a probe depend on the type of probe being
handled, and is triggered by invoking two back-end hooks in
`probe_ops'.
In case some particular probe type does not support the notion of
enabling and/or disabling, the corresponding fields on `probe_ops' can
be initialized to NULL. This is the case of SystemTap probes.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* stap-probe.c (stap_probe_ops): Add NULLs in the static
stap_probe_ops for `enable_probe' and `disable_probe'.
* probe.c (enable_probes_command): New function.
(disable_probes_command): Likewise.
(_initialize_probe): Define the cli commands `enable probe' and
`disable probe'.
(parse_probe_linespec): New function.
(info_probes_for_ops): Use parse_probe_linespec.
* probe.h (probe_ops): New hooks `enable_probe' and
`disable_probe'.
gdb/doc/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* gdb.texinfo (Static Probe Points): Cover the `enable probe' and
`disable probe' commands.
---
gdb/ChangeLog | 13 +++++
gdb/doc/ChangeLog | 5 ++
gdb/doc/gdb.texinfo | 29 ++++++++++
gdb/probe.c | 161 ++++++++++++++++++++++++++++++++++++++++++++-------
gdb/probe.h | 12 ++++
gdb/stap-probe.c | 2 +
6 files changed, 202 insertions(+), 20 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 15c2908..cfdc506 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4976,6 +4976,35 @@ given, all object files are considered.
List the available static probes, from all types.
@end table
+@cindex enabling and disabling probes
+Some probe points can be enabled and/or disabled. The effect of
+enabling or disabling a probe depends on the type of probe being
+handled. @code{SystemTap} probes cannot be disabled.
+
+You can enable (or disable) one or more probes using the following
+commands, with optional arguments:
+
+@table @code
+@kindex enable probes
+@item enable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+If given, @var{provider} is a regular expression used to match against
+provider names when selecting which probes to enable. If omitted,
+all probes from all providers are enabled.
+
+If given, @var{name} is a regular expression to match against probe
+names when selecting which probes to enable. If omitted, probe names
+are not considered when deciding whether to enable them.
+
+If given, @var{objfile} is a regular expression used to select which
+object files (executable or shared libraries) to examine. If not
+given, all object files are considered.
+
+@kindex disable probes
+@item disable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+See the @code{enable probes} command above for a description of the
+optional arguments accepted by this command.
+@end table
+
@vindex $_probe_arg@r{, convenience variable}
A probe may specify up to twelve arguments. These are available at the
point at which the probe is defined---that is, when the current PC is
diff --git a/gdb/probe.c b/gdb/probe.c
index 102c2e1..b96c8ac 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -423,18 +423,18 @@ print_ui_out_not_applicables (const struct probe_ops *pops)
VEC (info_probe_column_s) *headings = NULL;
info_probe_column_s *column;
int ix;
-
+
if (pops->gen_info_probes_table_header == NULL)
return;
c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
pops->gen_info_probes_table_header (&headings);
-
+
for (ix = 0;
VEC_iterate (info_probe_column_s, headings, ix, column);
++ix)
ui_out_field_string (current_uiout, column->field_name, _("n/a"));
-
+
do_cleanups (c);
}
@@ -527,6 +527,24 @@ exists_probe_with_pops (VEC (bound_probe_s) *probes,
return 0;
}
+/* Helper function that parses a probe linespec of the form [PROVIDER
+ [PROBE [OBJNAME]]] from the provided string STR. */
+
+static void
+parse_probe_linespec (const char *str, char **provider,
+ char **probe_name, char **objname)
+{
+ *probe_name = *objname = NULL;
+
+ *provider = extract_arg_const (&str);
+ if (*provider != NULL)
+ {
+ *probe_name = extract_arg_const (&str);
+ if (*probe_name != NULL)
+ *objname = extract_arg_const (&str);
+ }
+}
+
/* See comment in probe.h. */
void
@@ -546,26 +564,14 @@ info_probes_for_ops (const char *arg, int from_tty,
struct bound_probe *probe;
struct gdbarch *gdbarch = get_current_arch ();
- /* Do we have a `provider:probe:objfile' style of linespec? */
- provider = extract_arg_const (&arg);
- if (provider)
- {
- make_cleanup (xfree, provider);
-
- probe_name = extract_arg_const (&arg);
- if (probe_name)
- {
- make_cleanup (xfree, probe_name);
-
- objname = extract_arg_const (&arg);
- if (objname)
- make_cleanup (xfree, objname);
- }
- }
+ parse_probe_linespec (arg, &provider, &probe_name, &objname);
+ make_cleanup (xfree, provider);
+ make_cleanup (xfree, probe_name);
+ make_cleanup (xfree, objname);
probes = collect_probes (objname, provider, probe_name, pops);
make_cleanup (VEC_cleanup (probe_p), &probes);
-
+
if (pops == NULL)
{
const struct probe_ops *po;
@@ -689,6 +695,98 @@ info_probes_command (char *arg, int from_tty)
info_probes_for_ops (arg, from_tty, NULL);
}
+/* Implementation of the `enable probes' command. */
+
+static void
+enable_probes_command (char *arg, int from_tty)
+{
+ char *provider, *probe_name = NULL, *objname = NULL;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ VEC (bound_probe_s) *probes;
+ struct bound_probe *probe;
+ int i;
+
+ parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+ make_cleanup (xfree, provider);
+ make_cleanup (xfree, probe_name);
+ make_cleanup (xfree, objname);
+
+ probes = collect_probes (objname, provider, probe_name, NULL);
+ if (VEC_empty (bound_probe_s, probes))
+ {
+ ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* Enable the selected probes, provided their backends support the
+ notion of enabling a probe. */
+ for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
+ {
+ const struct probe_ops *pops = probe->probe->pops;
+
+ if (pops->enable_probe != NULL)
+ {
+ pops->enable_probe (probe->probe);
+ ui_out_message (current_uiout, 0,
+ _("Probe %s:%s enabled.\n"),
+ probe->probe->provider, probe->probe->name);
+ }
+ else
+ ui_out_message (current_uiout, 0,
+ _("Probe %s:%s cannot be enabled.\n"),
+ probe->probe->provider, probe->probe->name);
+ }
+
+ do_cleanups (cleanup);
+}
+
+/* Implementation of the `disable probes' command. */
+
+static void
+disable_probes_command (char *arg, int from_tty)
+{
+ char *provider, *probe_name = NULL, *objname = NULL;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ VEC (bound_probe_s) *probes;
+ struct bound_probe *probe;
+ int i;
+
+ parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
+ make_cleanup (xfree, provider);
+ make_cleanup (xfree, probe_name);
+ make_cleanup (xfree, objname);
+
+ probes = collect_probes (objname, provider, probe_name, NULL /* pops */);
+ if (VEC_empty (bound_probe_s, probes))
+ {
+ ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+ do_cleanups (cleanup);
+ return;
+ }
+
+ /* Disable the selected probes, provided their backends support the
+ notion of enabling a probe. */
+ for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
+ {
+ const struct probe_ops *pops = probe->probe->pops;
+
+ if (pops->disable_probe != NULL)
+ {
+ pops->disable_probe (probe->probe);
+ ui_out_message (current_uiout, 0,
+ _("Probe %s:%s disabled.\n"),
+ probe->probe->provider, probe->probe->name);
+ }
+ else
+ ui_out_message (current_uiout, 0,
+ _("Probe %s:%s cannot be disabled.\n"),
+ probe->probe->provider, probe->probe->name);
+ }
+
+ do_cleanups (cleanup);
+}
+
/* See comments in probe.h. */
CORE_ADDR
@@ -950,4 +1048,27 @@ _initialize_probe (void)
_("\
Show information about all type of probes."),
info_probes_cmdlist_get ());
+
+ add_cmd ("probes", class_breakpoint, enable_probes_command, _("\
+Enable probes.\n\
+Usage: enable probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name.\n\
+If you do not specify any argument then the command will enable\n\
+all defined probes."),
+ &enablelist);
+
+ add_cmd ("probes", class_breakpoint, disable_probes_command, _("\
+Disable probes.\n\
+Usage: disable probes [PROVIDER [NAME [OBJECT]]]\n\
+Each argument is a regular expression, used to select probes.\n\
+PROVIDER matches probe provider names.\n\
+NAME matches the probe names.\n\
+OBJECT matches the executable or shared library name.\n\
+If you do not specify any argument then the command will disable\n\
+all defined probes."),
+ &disablelist);
+
}
diff --git a/gdb/probe.h b/gdb/probe.h
index 66c8c53..c244a21 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -138,6 +138,18 @@ struct probe_ops
void (*gen_info_probes_table_values) (struct probe *probe,
VEC (const_char_ptr) **values);
+
+ /* Enable a probe. The semantics of "enabling" a probe depend on
+ the specific backend and the field can be NULL in case enabling
+ probes is not supported. */
+
+ void (*enable_probe) (struct probe *probe);
+
+ /* Disable a probe. The semantics of "disabling" a probe depend
+ on the specific backend and the field can be NULL in case
+ disabling probes is not supported. */
+
+ void (*disable_probe) (struct probe *probe);
};
/* Definition of a vector of probe_ops. */
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index ed4ce69..8366ce2 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1684,6 +1684,8 @@ static const struct probe_ops stap_probe_ops =
stap_type_name,
stap_gen_info_probes_table_header,
stap_gen_info_probes_table_values,
+ NULL, /* enable_probe */
+ NULL /* disable_probe */
};
/* Implementation of the `info probes stap' command. */
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 3/9] New commands `enable probe' and `disable probe'.
2014-10-28 13:45 ` [PATCH V3 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
@ 2014-10-31 19:04 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 19:04 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch adds the above-mentioned commands to the generic probe
> abstraction implemented in probe.[ch]. The effects associated to
> enabling or disabling a probe depend on the type of probe being
> handled, and is triggered by invoking two back-end hooks in
> `probe_ops'.
>
> In case some particular probe type does not support the notion of
> enabling and/or disabling, the corresponding fields on `probe_ops' can
> be initialized to NULL. This is the case of SystemTap probes.
Thanks for the patch.
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * stap-probe.c (stap_probe_ops): Add NULLs in the static
> stap_probe_ops for `enable_probe' and `disable_probe'.
> * probe.c (enable_probes_command): New function.
> (disable_probes_command): Likewise.
> (_initialize_probe): Define the cli commands `enable probe' and
> `disable probe'.
> (parse_probe_linespec): New function.
> (info_probes_for_ops): Use parse_probe_linespec.
> * probe.h (probe_ops): New hooks `enable_probe' and
> `disable_probe'.
>
> gdb/doc/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * gdb.texinfo (Static Probe Points): Cover the `enable probe' and
> `disable probe' commands.
> ---
> gdb/ChangeLog | 13 +++++
> gdb/doc/ChangeLog | 5 ++
> gdb/doc/gdb.texinfo | 29 ++++++++++
> gdb/probe.c | 161 ++++++++++++++++++++++++++++++++++++++++++++-------
> gdb/probe.h | 12 ++++
> gdb/stap-probe.c | 2 +
> 6 files changed, 202 insertions(+), 20 deletions(-)
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 15c2908..cfdc506 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4976,6 +4976,35 @@ given, all object files are considered.
> List the available static probes, from all types.
> @end table
>
> +@cindex enabling and disabling probes
> +Some probe points can be enabled and/or disabled. The effect of
> +enabling or disabling a probe depends on the type of probe being
> +handled. @code{SystemTap} probes cannot be disabled.
> +
> +You can enable (or disable) one or more probes using the following
> +commands, with optional arguments:
> +
> +@table @code
> +@kindex enable probes
> +@item enable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
> +If given, @var{provider} is a regular expression used to match against
> +provider names when selecting which probes to enable. If omitted,
> +all probes from all providers are enabled.
> +
> +If given, @var{name} is a regular expression to match against probe
> +names when selecting which probes to enable. If omitted, probe names
> +are not considered when deciding whether to enable them.
> +
> +If given, @var{objfile} is a regular expression used to select which
> +object files (executable or shared libraries) to examine. If not
> +given, all object files are considered.
> +
> +@kindex disable probes
> +@item disable probes @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
> +See the @code{enable probes} command above for a description of the
> +optional arguments accepted by this command.
> +@end table
> +
> @vindex $_probe_arg@r{, convenience variable}
> A probe may specify up to twelve arguments. These are available at the
> point at which the probe is defined---that is, when the current PC is
> diff --git a/gdb/probe.c b/gdb/probe.c
> index 102c2e1..b96c8ac 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -423,18 +423,18 @@ print_ui_out_not_applicables (const struct probe_ops *pops)
> VEC (info_probe_column_s) *headings = NULL;
> info_probe_column_s *column;
> int ix;
> -
> +
> if (pops->gen_info_probes_table_header == NULL)
> return;
>
> c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
> pops->gen_info_probes_table_header (&headings);
> -
> +
> for (ix = 0;
> VEC_iterate (info_probe_column_s, headings, ix, column);
> ++ix)
> ui_out_field_string (current_uiout, column->field_name, _("n/a"));
> -
> +
> do_cleanups (c);
> }
>
This whole hunk should not be in this patch, because it is just removing
extraneous whitespaces. Please fix them in patch #1 instead :-).
> @@ -527,6 +527,24 @@ exists_probe_with_pops (VEC (bound_probe_s) *probes,
> return 0;
> }
>
> +/* Helper function that parses a probe linespec of the form [PROVIDER
> + [PROBE [OBJNAME]]] from the provided string STR. */
> +
> +static void
> +parse_probe_linespec (const char *str, char **provider,
> + char **probe_name, char **objname)
> +{
> + *probe_name = *objname = NULL;
> +
> + *provider = extract_arg_const (&str);
> + if (*provider != NULL)
> + {
> + *probe_name = extract_arg_const (&str);
> + if (*probe_name != NULL)
> + *objname = extract_arg_const (&str);
> + }
> +}
> +
> /* See comment in probe.h. */
>
> void
> @@ -546,26 +564,14 @@ info_probes_for_ops (const char *arg, int from_tty,
> struct bound_probe *probe;
> struct gdbarch *gdbarch = get_current_arch ();
>
> - /* Do we have a `provider:probe:objfile' style of linespec? */
> - provider = extract_arg_const (&arg);
> - if (provider)
> - {
> - make_cleanup (xfree, provider);
> -
> - probe_name = extract_arg_const (&arg);
> - if (probe_name)
> - {
> - make_cleanup (xfree, probe_name);
> -
> - objname = extract_arg_const (&arg);
> - if (objname)
> - make_cleanup (xfree, objname);
> - }
> - }
> + parse_probe_linespec (arg, &provider, &probe_name, &objname);
> + make_cleanup (xfree, provider);
> + make_cleanup (xfree, probe_name);
> + make_cleanup (xfree, objname);
>
> probes = collect_probes (objname, provider, probe_name, pops);
> make_cleanup (VEC_cleanup (probe_p), &probes);
> -
> +
This is fixing extraneous whitespaces added in patch #1. Fix them there
:-).
> if (pops == NULL)
> {
> const struct probe_ops *po;
> @@ -689,6 +695,98 @@ info_probes_command (char *arg, int from_tty)
> info_probes_for_ops (arg, from_tty, NULL);
> }
>
> +/* Implementation of the `enable probes' command. */
> +
> +static void
> +enable_probes_command (char *arg, int from_tty)
> +{
> + char *provider, *probe_name = NULL, *objname = NULL;
> + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
> + VEC (bound_probe_s) *probes;
> + struct bound_probe *probe;
> + int i;
> +
> + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
> + make_cleanup (xfree, provider);
> + make_cleanup (xfree, probe_name);
> + make_cleanup (xfree, objname);
> +
> + probes = collect_probes (objname, provider, probe_name, NULL);
> + if (VEC_empty (bound_probe_s, probes))
> + {
> + ui_out_message (current_uiout, 0, _("No probes matched.\n"));
> + do_cleanups (cleanup);
> + return;
> + }
> +
> + /* Enable the selected probes, provided their backends support the
> + notion of enabling a probe. */
> + for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> + {
> + const struct probe_ops *pops = probe->probe->pops;
> +
> + if (pops->enable_probe != NULL)
> + {
> + pops->enable_probe (probe->probe);
> + ui_out_message (current_uiout, 0,
> + _("Probe %s:%s enabled.\n"),
> + probe->probe->provider, probe->probe->name);
> + }
> + else
> + ui_out_message (current_uiout, 0,
> + _("Probe %s:%s cannot be enabled.\n"),
> + probe->probe->provider, probe->probe->name);
> + }
> +
> + do_cleanups (cleanup);
> +}
> +
> +/* Implementation of the `disable probes' command. */
> +
> +static void
> +disable_probes_command (char *arg, int from_tty)
> +{
> + char *provider, *probe_name = NULL, *objname = NULL;
> + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
> + VEC (bound_probe_s) *probes;
> + struct bound_probe *probe;
> + int i;
> +
> + parse_probe_linespec ((const char *) arg, &provider, &probe_name, &objname);
> + make_cleanup (xfree, provider);
> + make_cleanup (xfree, probe_name);
> + make_cleanup (xfree, objname);
> +
> + probes = collect_probes (objname, provider, probe_name, NULL /* pops */);
> + if (VEC_empty (bound_probe_s, probes))
> + {
> + ui_out_message (current_uiout, 0, _("No probes matched.\n"));
> + do_cleanups (cleanup);
> + return;
> + }
> +
> + /* Disable the selected probes, provided their backends support the
> + notion of enabling a probe. */
> + for (i = 0; VEC_iterate (bound_probe_s, probes, i, probe); ++i)
> + {
> + const struct probe_ops *pops = probe->probe->pops;
> +
> + if (pops->disable_probe != NULL)
> + {
> + pops->disable_probe (probe->probe);
> + ui_out_message (current_uiout, 0,
> + _("Probe %s:%s disabled.\n"),
> + probe->probe->provider, probe->probe->name);
> + }
> + else
> + ui_out_message (current_uiout, 0,
> + _("Probe %s:%s cannot be disabled.\n"),
> + probe->probe->provider, probe->probe->name);
> + }
> +
> + do_cleanups (cleanup);
> +}
> +
> /* See comments in probe.h. */
>
> CORE_ADDR
> @@ -950,4 +1048,27 @@ _initialize_probe (void)
> _("\
> Show information about all type of probes."),
> info_probes_cmdlist_get ());
> +
> + add_cmd ("probes", class_breakpoint, enable_probes_command, _("\
> +Enable probes.\n\
> +Usage: enable probes [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name.\n\
> +If you do not specify any argument then the command will enable\n\
> +all defined probes."),
> + &enablelist);
> +
> + add_cmd ("probes", class_breakpoint, disable_probes_command, _("\
> +Disable probes.\n\
> +Usage: disable probes [PROVIDER [NAME [OBJECT]]]\n\
> +Each argument is a regular expression, used to select probes.\n\
> +PROVIDER matches probe provider names.\n\
> +NAME matches the probe names.\n\
> +OBJECT matches the executable or shared library name.\n\
> +If you do not specify any argument then the command will disable\n\
> +all defined probes."),
> + &disablelist);
> +
> }
> diff --git a/gdb/probe.h b/gdb/probe.h
> index 66c8c53..c244a21 100644
> --- a/gdb/probe.h
> +++ b/gdb/probe.h
> @@ -138,6 +138,18 @@ struct probe_ops
>
> void (*gen_info_probes_table_values) (struct probe *probe,
> VEC (const_char_ptr) **values);
> +
> + /* Enable a probe. The semantics of "enabling" a probe depend on
> + the specific backend and the field can be NULL in case enabling
> + probes is not supported. */
> +
> + void (*enable_probe) (struct probe *probe);
> +
> + /* Disable a probe. The semantics of "disabling" a probe depend
> + on the specific backend and the field can be NULL in case
> + disabling probes is not supported. */
> +
> + void (*disable_probe) (struct probe *probe);
> };
>
> /* Definition of a vector of probe_ops. */
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index ed4ce69..8366ce2 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1684,6 +1684,8 @@ static const struct probe_ops stap_probe_ops =
> stap_type_name,
> stap_gen_info_probes_table_header,
> stap_gen_info_probes_table_values,
> + NULL, /* enable_probe */
> + NULL /* disable_probe */
> };
>
> /* Implementation of the `info probes stap' command. */
> --
> 1.7.10.4
Otherwise, the patch looks good.
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 8/9] Documentation for DTrace USDT probes.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (5 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 3/9] New commands `enable probe' and `disable probe' Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
8 siblings, 0 replies; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch modifies the `Static Probe Points' section on the GDB
manual in order to cover the support for DTrace USDT probes, in
addition to SystemTap SDT probes.
gdb/doc/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* gdb.texinfo (Static Probe Points): Add cindex `static probe
point, DTrace'.
(Static Probe Points): Modified to cover DTrace probes in addition
to SystemTap probes. Also modified to cover the `enable probe'
and `disable probe' commands.
---
gdb/doc/ChangeLog | 8 +++++++
gdb/doc/gdb.texinfo | 58 ++++++++++++++++++++++++++++++++++-----------------
2 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index cfdc506..c7f1bf5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4932,34 +4932,50 @@ that can no longer be recreated.
@subsection Static Probe Points
@cindex static probe point, SystemTap
+@cindex static probe point, DTrace
@value{GDBN} supports @dfn{SDT} probes in the code. @acronym{SDT} stands
for Statically Defined Tracing, and the probes are designed to have a tiny
-runtime code and data footprint, and no dynamic relocations. They are
-usable from assembly, C and C@t{++} languages. See
-@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
-for a good reference on how the @acronym{SDT} probes are implemented.
+runtime code and data footprint, and no dynamic relocations.
+
+Currently, the following types of probes are supported on
+ELF-compatible systems:
+
+@itemize @bullet
-Currently, @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
-@acronym{SDT} probes are supported on ELF-compatible systems. See
+@item @code{SystemTap} (@uref{http://sourceware.org/systemtap/})
+@acronym{SDT} probes@footnote{See
@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
-for more information on how to add @code{SystemTap} @acronym{SDT} probes
-in your applications.
+for more information on how to add @code{SystemTap} @acronym{SDT}
+probes in your applications.}. @code{SystemTap} probes are usable
+from assembly, C and C@t{++} languages@footnote{See
+@uref{http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation}
+for a good reference on how the @acronym{SDT} probes are implemented.}.
+
+@item @code{DTrace} (@uref{http://oss.oracle.com/projects/DTrace})
+@acronym{USDT} probes. @code{DTrace} probes are usable from C and
+C@t{++} languages.
+@end itemize
@cindex semaphores on static probe points
-Some probes have an associated semaphore variable; for instance, this
-happens automatically if you defined your probe using a DTrace-style
-@file{.d} file. If your probe has a semaphore, @value{GDBN} will
-automatically enable it when you specify a breakpoint using the
-@samp{-probe-stap} notation. But, if you put a breakpoint at a probe's
-location by some other method (e.g., @code{break file:line}), then
-@value{GDBN} will not automatically set the semaphore.
+Some @code{SystemTap} probes have an associated semaphore variable;
+for instance, this happens automatically if you defined your probe
+using a DTrace-style @file{.d} file. If your probe has a semaphore,
+@value{GDBN} will automatically enable it when you specify a
+breakpoint using the @samp{-probe-stap} notation. But, if you put a
+breakpoint at a probe's location by some other method (e.g.,
+@code{break file:line}), then @value{GDBN} will not automatically set
+the semaphore. @code{DTrace} probes do not support semaphores.
You can examine the available static static probes using @code{info
probes}, with optional arguments:
@table @code
@kindex info probes
-@item info probes stap @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+@item info probes @r{[}@var{type}@r{]} @r{[}@var{provider} @r{[}@var{name} @r{[}@var{objfile}@r{]}@r{]}@r{]}
+If given, @var{type} is either @code{stap} for listing
+@code{SystemTap} probes or @code{dtrace} for listing @code{DTrace}
+probes. If omitted all probes are listed regardless of their types.
+
If given, @var{provider} is a regular expression used to match against provider
names when selecting which probes to list. If omitted, probes by all
probes from all providers are listed.
@@ -4979,7 +4995,8 @@ List the available static probes, from all types.
@cindex enabling and disabling probes
Some probe points can be enabled and/or disabled. The effect of
enabling or disabling a probe depends on the type of probe being
-handled. @code{SystemTap} probes cannot be disabled.
+handled. Some @code{DTrace} probes can be enabled or
+disabled,but @code{SystemTap} probes cannot be disabled.
You can enable (or disable) one or more probes using the following
commands, with optional arguments:
@@ -5010,8 +5027,11 @@ A probe may specify up to twelve arguments. These are available at the
point at which the probe is defined---that is, when the current PC is
at the probe's location. The arguments are available using the
convenience variables (@pxref{Convenience Vars})
-@code{$_probe_arg0}@dots{}@code{$_probe_arg11}. Each probe argument is
-an integer of the appropriate size; types are not preserved. The
+@code{$_probe_arg0}@dots{}@code{$_probe_arg11}. In @code{SystemTap}
+probes each probe argument is an integer of the appropriate size;
+types are not preserved. In @code{DTrace} probes types are preserved
+provided that they are recognized as such by @value{GDBN}; otherwise
+the value of the probe argument will be a long integer. The
convenience variable @code{$_probe_argc} holds the number of arguments
at the current probe point.
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 9/9] Announce the DTrace USDT probes support in NEWS.
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (6 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 8/9] Documentation for DTrace USDT probes Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-28 13:45 ` [PATCH V3 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
8 siblings, 0 replies; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch simply adds a small entry to `Changes since GDB 7.8' announcing the
support for dtrace probes.
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* NEWS: Announce the support for DTrace SDT probes.
---
gdb/ChangeLog | 4 ++++
gdb/NEWS | 3 +++
2 files changed, 7 insertions(+)
diff --git a/gdb/NEWS b/gdb/NEWS
index 01cdc36..e7c57d8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -49,6 +49,9 @@ queue-signal signal-name-or-number
** The -list-thread-groups command outputs an exit-code field for
inferiors that have exited.
+* GDB now has support for DTrace USDT (Userland Static Defined
+ Tracing) probes. The supported targets are x86_64-*-linux-gnu.
+
* Removed targets
Support for these obsolete configurations has been removed.
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V3 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c
2014-10-28 13:45 [PATCH V3 0/9] Add support for DTrace USDT probes to gdb Jose E. Marchesi
` (7 preceding siblings ...)
2014-10-28 13:45 ` [PATCH V3 9/9] Announce the DTrace USDT probes support in NEWS Jose E. Marchesi
@ 2014-10-28 13:45 ` Jose E. Marchesi
2014-10-31 19:46 ` Sergio Durigan Junior
8 siblings, 1 reply; 22+ messages in thread
From: Jose E. Marchesi @ 2014-10-28 13:45 UTC (permalink / raw)
To: gdb-patches
This patch moves the `compute_probe_arg' and `compile_probe_arg' functions
from stap-probe.c to probe.c. The rationale is that it is reasonable to
assume that all backends will provide the `$_probe_argN' convenience
variables, and that the user must be placed on the PC of the probe when
requesting that information. The value and type of the argument can still be
determined by the probe backend via the `pops->evaluate_probe_argument' and
`pops->compile_to_ax' handlers.
Note that a test in gdb.base/stap-probe.exp had to be adjusted because the "No
SystemTap probe at PC" messages are now "No probe at PC".
gdb/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* probe.c (compute_probe_arg): Moved from stap-probe.c
(compile_probe_arg): Likewise.
(probe_funcs): Likewise.
* stap-probe.c (compute_probe_arg): Moved to probe.c.
(compile_probe_arg): Likewise.
(probe_funcs): Likewise.
gdb/testsuite/ChangeLog:
2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
* gdb.base/stap-probe.exp (stap_test): Remove "SystemTap" from
expected message when trying to access $_probe_* convenience
variables while not on a probe.
---
gdb/ChangeLog | 9 +++
gdb/probe.c | 111 +++++++++++++++++++++++++++++++++
gdb/stap-probe.c | 109 --------------------------------
gdb/testsuite/ChangeLog | 6 ++
gdb/testsuite/gdb.base/stap-probe.exp | 2 +-
5 files changed, 127 insertions(+), 110 deletions(-)
diff --git a/gdb/probe.c b/gdb/probe.c
index 3151ada..102c2e1 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -30,6 +30,9 @@
#include "gdb_regex.h"
#include "frame.h"
#include "arch-utils.h"
+#include "value.h"
+#include "ax.h"
+#include "ax-gdb.h"
#include <ctype.h>
typedef struct bound_probe bound_probe_s;
@@ -826,6 +829,87 @@ will show information about all types of probes."),
return &info_probes_cmdlist;
}
+\f
+
+/* This is called to compute the value of one of the $_probe_arg*
+ convenience variables. */
+
+static struct value *
+compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
+ void *data)
+{
+ struct frame_info *frame = get_selected_frame (_("No frame selected"));
+ CORE_ADDR pc = get_frame_pc (frame);
+ int sel = (int) (uintptr_t) data;
+ struct bound_probe pc_probe;
+ const struct sym_probe_fns *pc_probe_fns;
+ unsigned n_args;
+
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc);
+ if (pc_probe.probe == NULL)
+ error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+ n_args = get_probe_argument_count (pc_probe.probe, frame);
+ if (sel == -1)
+ return value_from_longest (builtin_type (arch)->builtin_int, n_args);
+
+ if (sel >= n_args)
+ error (_("Invalid probe argument %d -- probe has %u arguments available"),
+ sel, n_args);
+
+ return evaluate_probe_argument (pc_probe.probe, sel, frame);
+}
+
+/* This is called to compile one of the $_probe_arg* convenience
+ variables into an agent expression. */
+
+static void
+compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
+ struct axs_value *value, void *data)
+{
+ CORE_ADDR pc = expr->scope;
+ int sel = (int) (uintptr_t) data;
+ struct bound_probe pc_probe;
+ const struct sym_probe_fns *pc_probe_fns;
+ int n_args;
+ struct frame_info *frame = get_selected_frame (NULL);
+
+ /* SEL == -1 means "_probe_argc". */
+ gdb_assert (sel >= -1);
+
+ pc_probe = find_probe_by_pc (pc);
+ if (pc_probe.probe == NULL)
+ error (_("No probe at PC %s"), core_addr_to_string (pc));
+
+ n_args = get_probe_argument_count (pc_probe.probe, frame);
+
+ if (sel == -1)
+ {
+ value->kind = axs_rvalue;
+ value->type = builtin_type (expr->gdbarch)->builtin_int;
+ ax_const_l (expr, n_args);
+ return;
+ }
+
+ gdb_assert (sel >= 0);
+ if (sel >= n_args)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_args);
+
+ pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
+}
+
+static const struct internalvar_funcs probe_funcs =
+{
+ compute_probe_arg,
+ compile_probe_arg,
+ NULL
+};
+
+
VEC (probe_ops_cp) *all_probe_ops;
void _initialize_probe (void);
@@ -835,6 +919,33 @@ _initialize_probe (void)
{
VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
+ create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
+ (void *) (uintptr_t) -1);
+ create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
+ (void *) (uintptr_t) 0);
+ create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
+ (void *) (uintptr_t) 1);
+ create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
+ (void *) (uintptr_t) 2);
+ create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
+ (void *) (uintptr_t) 3);
+ create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
+ (void *) (uintptr_t) 4);
+ create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
+ (void *) (uintptr_t) 5);
+ create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
+ (void *) (uintptr_t) 6);
+ create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
+ (void *) (uintptr_t) 7);
+ create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
+ (void *) (uintptr_t) 8);
+ create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
+ (void *) (uintptr_t) 9);
+ create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
+ (void *) (uintptr_t) 10);
+ create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
+ (void *) (uintptr_t) 11);
+
add_cmd ("all", class_info, info_probes_command,
_("\
Show information about all type of probes."),
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index 061f6d3..ed4ce69 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1365,79 +1365,6 @@ stap_probe_destroy (struct probe *probe_generic)
\f
-/* This is called to compute the value of one of the $_probe_arg*
- convenience variables. */
-
-static struct value *
-compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
- void *data)
-{
- struct frame_info *frame = get_selected_frame (_("No frame selected"));
- CORE_ADDR pc = get_frame_pc (frame);
- int sel = (int) (uintptr_t) data;
- struct bound_probe pc_probe;
- const struct sym_probe_fns *pc_probe_fns;
- unsigned n_args;
-
- /* SEL == -1 means "_probe_argc". */
- gdb_assert (sel >= -1);
-
- pc_probe = find_probe_by_pc (pc);
- if (pc_probe.probe == NULL)
- error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
-
- n_args = get_probe_argument_count (pc_probe.probe, frame);
- if (sel == -1)
- return value_from_longest (builtin_type (arch)->builtin_int, n_args);
-
- if (sel >= n_args)
- error (_("Invalid probe argument %d -- probe has %u arguments available"),
- sel, n_args);
-
- return evaluate_probe_argument (pc_probe.probe, sel, frame);
-}
-
-/* This is called to compile one of the $_probe_arg* convenience
- variables into an agent expression. */
-
-static void
-compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
- struct axs_value *value, void *data)
-{
- CORE_ADDR pc = expr->scope;
- int sel = (int) (uintptr_t) data;
- struct bound_probe pc_probe;
- const struct sym_probe_fns *pc_probe_fns;
- int n_args;
- struct frame_info *frame = get_selected_frame (NULL);
-
- /* SEL == -1 means "_probe_argc". */
- gdb_assert (sel >= -1);
-
- pc_probe = find_probe_by_pc (pc);
- if (pc_probe.probe == NULL)
- error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
-
- n_args = get_probe_argument_count (pc_probe.probe, frame);
-
- if (sel == -1)
- {
- value->kind = axs_rvalue;
- value->type = builtin_type (expr->gdbarch)->builtin_int;
- ax_const_l (expr, n_args);
- return;
- }
-
- gdb_assert (sel >= 0);
- if (sel >= n_args)
- error (_("Invalid probe argument %d -- probe has %d arguments available"),
- sel, n_args);
-
- pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
-}
-
-\f
-
/* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's
address. SET is zero if the semaphore should be cleared, or one
if it should be set. This is a helper function for `stap_semaphore_down'
@@ -1514,15 +1441,6 @@ stap_clear_semaphore (struct probe *probe_generic, struct objfile *objfile,
stap_modify_semaphore (addr, 0, gdbarch);
}
-/* Implementation of `$_probe_arg*' set of variables. */
-
-static const struct internalvar_funcs probe_funcs =
-{
- compute_probe_arg,
- compile_probe_arg,
- NULL
-};
-
/* Helper function that parses the information contained in a
SystemTap's probe. Basically, the information consists in:
@@ -1793,33 +1711,6 @@ _initialize_stap_probe (void)
show_stapexpressiondebug,
&setdebuglist, &showdebuglist);
- create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
- (void *) (uintptr_t) -1);
- create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
- (void *) (uintptr_t) 0);
- create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
- (void *) (uintptr_t) 1);
- create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
- (void *) (uintptr_t) 2);
- create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
- (void *) (uintptr_t) 3);
- create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
- (void *) (uintptr_t) 4);
- create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
- (void *) (uintptr_t) 5);
- create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
- (void *) (uintptr_t) 6);
- create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
- (void *) (uintptr_t) 7);
- create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
- (void *) (uintptr_t) 8);
- create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
- (void *) (uintptr_t) 9);
- create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
- (void *) (uintptr_t) 10);
- create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
- (void *) (uintptr_t) 11);
-
add_cmd ("stap", class_info, info_probes_stap_command,
_("\
Show information about SystemTap static probes.\n\
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
index 7710bc3..9f71d1d 100644
--- a/gdb/testsuite/gdb.base/stap-probe.exp
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -30,7 +30,7 @@ proc stap_test {exec_name {arg ""}} {
return -1
}
- gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+ gdb_test "print \$_probe_argc" "No probe at PC $hex" \
"check argument not at probe point"
gdb_test "info probes stap" \
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH V3 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c
2014-10-28 13:45 ` [PATCH V3 2/9] Move `compute_probe_arg' and `compile_probe_arg' to probe.c Jose E. Marchesi
@ 2014-10-31 19:46 ` Sergio Durigan Junior
0 siblings, 0 replies; 22+ messages in thread
From: Sergio Durigan Junior @ 2014-10-31 19:46 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
On Tuesday, October 28 2014, Jose E. Marchesi wrote:
> This patch moves the `compute_probe_arg' and `compile_probe_arg' functions
> from stap-probe.c to probe.c. The rationale is that it is reasonable to
> assume that all backends will provide the `$_probe_argN' convenience
> variables, and that the user must be placed on the PC of the probe when
> requesting that information. The value and type of the argument can still be
> determined by the probe backend via the `pops->evaluate_probe_argument' and
> `pops->compile_to_ax' handlers.
>
> Note that a test in gdb.base/stap-probe.exp had to be adjusted because the "No
> SystemTap probe at PC" messages are now "No probe at PC".
Thanks for the patch. I guess it was already approved in the last
iteration, so I have no further comments for it.
> gdb/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * probe.c (compute_probe_arg): Moved from stap-probe.c
> (compile_probe_arg): Likewise.
> (probe_funcs): Likewise.
> * stap-probe.c (compute_probe_arg): Moved to probe.c.
> (compile_probe_arg): Likewise.
> (probe_funcs): Likewise.
>
> gdb/testsuite/ChangeLog:
>
> 2014-10-28 Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * gdb.base/stap-probe.exp (stap_test): Remove "SystemTap" from
> expected message when trying to access $_probe_* convenience
> variables while not on a probe.
> ---
> gdb/ChangeLog | 9 +++
> gdb/probe.c | 111 +++++++++++++++++++++++++++++++++
> gdb/stap-probe.c | 109 --------------------------------
> gdb/testsuite/ChangeLog | 6 ++
> gdb/testsuite/gdb.base/stap-probe.exp | 2 +-
> 5 files changed, 127 insertions(+), 110 deletions(-)
>
> diff --git a/gdb/probe.c b/gdb/probe.c
> index 3151ada..102c2e1 100644
> --- a/gdb/probe.c
> +++ b/gdb/probe.c
> @@ -30,6 +30,9 @@
> #include "gdb_regex.h"
> #include "frame.h"
> #include "arch-utils.h"
> +#include "value.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
> #include <ctype.h>
>
> typedef struct bound_probe bound_probe_s;
> @@ -826,6 +829,87 @@ will show information about all types of probes."),
> return &info_probes_cmdlist;
> }
>
> +\f
> +
> +/* This is called to compute the value of one of the $_probe_arg*
> + convenience variables. */
> +
> +static struct value *
> +compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
> + void *data)
> +{
> + struct frame_info *frame = get_selected_frame (_("No frame selected"));
> + CORE_ADDR pc = get_frame_pc (frame);
> + int sel = (int) (uintptr_t) data;
> + struct bound_probe pc_probe;
> + const struct sym_probe_fns *pc_probe_fns;
> + unsigned n_args;
> +
> + /* SEL == -1 means "_probe_argc". */
> + gdb_assert (sel >= -1);
> +
> + pc_probe = find_probe_by_pc (pc);
> + if (pc_probe.probe == NULL)
> + error (_("No probe at PC %s"), core_addr_to_string (pc));
> +
> + n_args = get_probe_argument_count (pc_probe.probe, frame);
> + if (sel == -1)
> + return value_from_longest (builtin_type (arch)->builtin_int, n_args);
> +
> + if (sel >= n_args)
> + error (_("Invalid probe argument %d -- probe has %u arguments available"),
> + sel, n_args);
> +
> + return evaluate_probe_argument (pc_probe.probe, sel, frame);
> +}
> +
> +/* This is called to compile one of the $_probe_arg* convenience
> + variables into an agent expression. */
> +
> +static void
> +compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
> + struct axs_value *value, void *data)
> +{
> + CORE_ADDR pc = expr->scope;
> + int sel = (int) (uintptr_t) data;
> + struct bound_probe pc_probe;
> + const struct sym_probe_fns *pc_probe_fns;
> + int n_args;
> + struct frame_info *frame = get_selected_frame (NULL);
> +
> + /* SEL == -1 means "_probe_argc". */
> + gdb_assert (sel >= -1);
> +
> + pc_probe = find_probe_by_pc (pc);
> + if (pc_probe.probe == NULL)
> + error (_("No probe at PC %s"), core_addr_to_string (pc));
> +
> + n_args = get_probe_argument_count (pc_probe.probe, frame);
> +
> + if (sel == -1)
> + {
> + value->kind = axs_rvalue;
> + value->type = builtin_type (expr->gdbarch)->builtin_int;
> + ax_const_l (expr, n_args);
> + return;
> + }
> +
> + gdb_assert (sel >= 0);
> + if (sel >= n_args)
> + error (_("Invalid probe argument %d -- probe has %d arguments available"),
> + sel, n_args);
> +
> + pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
> +}
> +
> +static const struct internalvar_funcs probe_funcs =
> +{
> + compute_probe_arg,
> + compile_probe_arg,
> + NULL
> +};
> +
> +
> VEC (probe_ops_cp) *all_probe_ops;
>
> void _initialize_probe (void);
> @@ -835,6 +919,33 @@ _initialize_probe (void)
> {
> VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
>
> + create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
> + (void *) (uintptr_t) -1);
> + create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
> + (void *) (uintptr_t) 0);
> + create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
> + (void *) (uintptr_t) 1);
> + create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
> + (void *) (uintptr_t) 2);
> + create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
> + (void *) (uintptr_t) 3);
> + create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
> + (void *) (uintptr_t) 4);
> + create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
> + (void *) (uintptr_t) 5);
> + create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
> + (void *) (uintptr_t) 6);
> + create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
> + (void *) (uintptr_t) 7);
> + create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
> + (void *) (uintptr_t) 8);
> + create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
> + (void *) (uintptr_t) 9);
> + create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
> + (void *) (uintptr_t) 10);
> + create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
> + (void *) (uintptr_t) 11);
> +
> add_cmd ("all", class_info, info_probes_command,
> _("\
> Show information about all type of probes."),
> diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
> index 061f6d3..ed4ce69 100644
> --- a/gdb/stap-probe.c
> +++ b/gdb/stap-probe.c
> @@ -1365,79 +1365,6 @@ stap_probe_destroy (struct probe *probe_generic)
>
> \f
>
> -/* This is called to compute the value of one of the $_probe_arg*
> - convenience variables. */
> -
> -static struct value *
> -compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
> - void *data)
> -{
> - struct frame_info *frame = get_selected_frame (_("No frame selected"));
> - CORE_ADDR pc = get_frame_pc (frame);
> - int sel = (int) (uintptr_t) data;
> - struct bound_probe pc_probe;
> - const struct sym_probe_fns *pc_probe_fns;
> - unsigned n_args;
> -
> - /* SEL == -1 means "_probe_argc". */
> - gdb_assert (sel >= -1);
> -
> - pc_probe = find_probe_by_pc (pc);
> - if (pc_probe.probe == NULL)
> - error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> -
> - n_args = get_probe_argument_count (pc_probe.probe, frame);
> - if (sel == -1)
> - return value_from_longest (builtin_type (arch)->builtin_int, n_args);
> -
> - if (sel >= n_args)
> - error (_("Invalid probe argument %d -- probe has %u arguments available"),
> - sel, n_args);
> -
> - return evaluate_probe_argument (pc_probe.probe, sel, frame);
> -}
> -
> -/* This is called to compile one of the $_probe_arg* convenience
> - variables into an agent expression. */
> -
> -static void
> -compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
> - struct axs_value *value, void *data)
> -{
> - CORE_ADDR pc = expr->scope;
> - int sel = (int) (uintptr_t) data;
> - struct bound_probe pc_probe;
> - const struct sym_probe_fns *pc_probe_fns;
> - int n_args;
> - struct frame_info *frame = get_selected_frame (NULL);
> -
> - /* SEL == -1 means "_probe_argc". */
> - gdb_assert (sel >= -1);
> -
> - pc_probe = find_probe_by_pc (pc);
> - if (pc_probe.probe == NULL)
> - error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> -
> - n_args = get_probe_argument_count (pc_probe.probe, frame);
> -
> - if (sel == -1)
> - {
> - value->kind = axs_rvalue;
> - value->type = builtin_type (expr->gdbarch)->builtin_int;
> - ax_const_l (expr, n_args);
> - return;
> - }
> -
> - gdb_assert (sel >= 0);
> - if (sel >= n_args)
> - error (_("Invalid probe argument %d -- probe has %d arguments available"),
> - sel, n_args);
> -
> - pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
> -}
> -
> -\f
> -
> /* Set or clear a SystemTap semaphore. ADDRESS is the semaphore's
> address. SET is zero if the semaphore should be cleared, or one
> if it should be set. This is a helper function for `stap_semaphore_down'
> @@ -1514,15 +1441,6 @@ stap_clear_semaphore (struct probe *probe_generic, struct objfile *objfile,
> stap_modify_semaphore (addr, 0, gdbarch);
> }
>
> -/* Implementation of `$_probe_arg*' set of variables. */
> -
> -static const struct internalvar_funcs probe_funcs =
> -{
> - compute_probe_arg,
> - compile_probe_arg,
> - NULL
> -};
> -
> /* Helper function that parses the information contained in a
> SystemTap's probe. Basically, the information consists in:
>
> @@ -1793,33 +1711,6 @@ _initialize_stap_probe (void)
> show_stapexpressiondebug,
> &setdebuglist, &showdebuglist);
>
> - create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
> - (void *) (uintptr_t) -1);
> - create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
> - (void *) (uintptr_t) 0);
> - create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
> - (void *) (uintptr_t) 1);
> - create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
> - (void *) (uintptr_t) 2);
> - create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
> - (void *) (uintptr_t) 3);
> - create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
> - (void *) (uintptr_t) 4);
> - create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
> - (void *) (uintptr_t) 5);
> - create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
> - (void *) (uintptr_t) 6);
> - create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
> - (void *) (uintptr_t) 7);
> - create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
> - (void *) (uintptr_t) 8);
> - create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
> - (void *) (uintptr_t) 9);
> - create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
> - (void *) (uintptr_t) 10);
> - create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
> - (void *) (uintptr_t) 11);
> -
> add_cmd ("stap", class_info, info_probes_stap_command,
> _("\
> Show information about SystemTap static probes.\n\
> diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
> index 7710bc3..9f71d1d 100644
> --- a/gdb/testsuite/gdb.base/stap-probe.exp
> +++ b/gdb/testsuite/gdb.base/stap-probe.exp
> @@ -30,7 +30,7 @@ proc stap_test {exec_name {arg ""}} {
> return -1
> }
>
> - gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
> + gdb_test "print \$_probe_argc" "No probe at PC $hex" \
> "check argument not at probe point"
>
> gdb_test "info probes stap" \
> --
> 1.7.10.4
--
Sergio
GPG key ID: 0x65FC5E36
Please send encrypted e-mail if possible
http://sergiodj.net/
^ permalink raw reply [flat|nested] 22+ messages in thread