* [PATCH 0/3] Implement support for SystemTap probes on userspace
@ 2012-03-09 20:29 Sergio Durigan Junior
2012-03-09 20:32 ` [PATCH 1/3] Refactor internal variable mechanism Sergio Durigan Junior
` (4 more replies)
0 siblings, 5 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-09 20:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Hello,
After a long time reworking the patches, I am finally resubmitting them
for review and, hopefully, inclusion.
This series of patches implement the support for SystemTap probes in
userspace on GDB. Not many people know, but SystemTap can be used to
insert and inspect probes on userspace applications as well (most people
use it in the kernel space), and those probes are simple markers on the
code which can be parsed by other programs. So this patch makes GDB
aware of those probes (and their arguments, when available) in a way
that the user will be able to inspect them while running the program.
The easiest way to insert a probe in your application is to include
<sys/sdt.h> (with systemtap-sdt-devel >= 1.4 on Fedora systems), and use
the STAP_PROBE* macros, e.g.:
#include <sys/sdt.h>
int
main ()
{
int a = 10;
STAP_PROBE1 (myprogram, myprobe, a);
exit (0);
}
After that, you can normally compile your code without the need of
special flags.
As you can see in the code above, the STAP_PROBE1 macro takes three
arguments: the first one is the provider (which in this case is just the
name of the program), the second is the probe name, and the third is the
first probe argument. If your probe doesn't need to have arguments, you
can use STAP_PROBE (which will take only the first two arguments), or if
your probe has more than one argument, you can use STAP_PROBE{1..12} and
specify up to twelve arguments. More information about probes on
userspace applications can be found at:
http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps
Now, with the following patch, GDB will be able to recognize probes in
an objfile, and also evaluate the probe's argument(s). We have also
implemented the possibility put a tracepoint on a probe and collect its
argument(s).
When you start a patched GDB debugging a binary which contains probes in
it, you can get a list of the probes by using the new `info probes'
command:
sergio@psique ~/work/src/git/stap-patches/build-64/gdb $ ./gdb -q /tmp/stap-example
(gdb) info probes
Provider Name Where Semaphore Object
teste m4 0x0000000000400505 0x00000000006009f8 /tmp/stap-example
teste ps 0x00000000004004cd 0x00000000006009fc /tmp/stap-example
teste two 0x0000000000400484 0x00000000006009f6 /tmp/stap-example
teste two 0x0000000000400497 0x00000000006009f6 /tmp/stap-example
teste user 0x00000000004004ad 0x00000000006009f4 /tmp/stap-example
As you can see above, there are 5 probes in the binary. We can now ask
GDB to put a breakpoint in a probe, by using the new option `-p' or
`-probe' in the `break' command:
(gdb) b -probe m4
Breakpoint 1 at 0x400505
(gdb) run
Starting program: /tmp/stap-example
Breakpoint 1,
0x0000000000400505 in m4 (fs=0x7fffffffe300, v=0) at stap-probe.c:89
89 STAP_PROBE3 (teste, m4, fs->val, fs->ps (v), v);
This probe has 3 arguments, as we can see. But if we didn't have access
to the source code, we could inspect the number of arguments by printing
the new convenience variable `$_probe_argc':
(gdb) print $_probe_argc
$1 = 3
Now, suppose we want to evaluate the second argument, we would then
print the convenience variable `$_probe_arg1' (there are convenience
variables for $_probe_arg{0,..,11}):
(gdb) print $_probe_arg1
$2 = 4195944
And that's the main idea of the patch. Below, I will try to explain
what we did to achieve this.
The first patch of the series contains code to refactor the internal
variable mechanism, making it more OO and including new functions needed
to (for example) compile the internal variable to an agent expression.
The second patch contains the biggest part of the new work, with the
inclusion of new files such as stap-probe.[ch], responsible for parsing
and evaluating probes' arguments, and also for interfacing with external
requests from elfread.c and breakpoint.c. As mentioned above, I had to
write a parser for probe arguments, and I decided to use GDB's own
evaluation mechanism (using struct expression et al). We have also
included a couple of tests, documentation and new commands (like `break
[-p|-probe]'), and lots of code to support arch-dependent argument
parsing (please, review that for me). If you want to narrow your
review, I'd suggest starting here...
The third patch contains code to make use of the existing longjmp and
exception probes in glibc and libgcc, respectively. I believe Tom can
give more information about this patch, but the idea is that if we have
those probes available, GDB should use them because we don't need
debuginfo to access them.
This whole patch has been regtested on x86/x86_64 (no regressions), and
it has been tested on PPC/PPC64, ARM and S390.
Reviews are not just appreciated, but really wanted!
Thank you,
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 1/3] Refactor internal variable mechanism
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
@ 2012-03-09 20:32 ` Sergio Durigan Junior
2012-03-09 21:03 ` Tom Tromey
2012-03-09 20:34 ` [PATCH 3/3] Use longjmp and exception probes when available Sergio Durigan Junior
` (3 subsequent siblings)
4 siblings, 1 reply; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-09 20:32 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Hello,
This is the first patch, which refactors the internal variable
mechanism. It creates new methods, for example to compile an internal
variable into agent expression.
Is this OK to check-in?
gdb/ChangeLog
2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* ax-gdb.c (gen_expr): Clean up code to handle internal variables
and to compile agent expressions.
* infrun.c (siginfo_make_value): New argument `ignore'.
(siginfo_funcs): New struct.
(_initialize_infrun): New argument when calling
`create_internalvar_type_lazy'.
* thread.c (thread_id_make_value): New argument `ignore'.
(thread_funcs): New struct.
(_initialize_thread): New argument when calling
`create_internalvar_type_lazy'.
* tracepoint.c (sdata_make_value): New argument `ignore'.
(sdata_funcs): New struct.
(_initialize_tracepoint): New argument when calling
`create_internalvar_type_lazy'.
* value.c (make_value): New struct.
(create_internalvar_type_lazy): New argument `data'.
(compile_internalvar_to_ax): New function.
(value_of_internalvar): Properly handling `make_value' case.
(clear_internalvar): Likewise.
(show_convenience): Adding `TRY_CATCH' block.
* value.h (internalvar_make_value): Delete, replace by...
(struct internalvar_funcs): ... this.
(create_internalvar_type_lazy) <fun>: Delete argument.
(create_internalvar_type_lazy) <funcs>, <data>: New arguments.
(compile_internalvar_to_ax): New function.
* windows-tdep.c (tlb_make_value): New argument `ignore'.
(tlb_funcs): New struct.
(_initialize_windows_tdep): New argument when calling
`create_internalvar_type_lazy'.
---
gdb/ax-gdb.c | 5 +++--
gdb/infrun.c | 14 ++++++++++++--
gdb/thread.c | 14 ++++++++++++--
gdb/tracepoint.c | 14 ++++++++++++--
gdb/value.c | 44 +++++++++++++++++++++++++++++++++++++++-----
gdb/value.h | 48 +++++++++++++++++++++++++++++++++++++++++++++---
gdb/windows-tdep.c | 13 +++++++++++--
7 files changed, 134 insertions(+), 18 deletions(-)
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index bd81338..b163681 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2041,7 +2041,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;
(*pc) += 3;
@@ -2055,7 +2056,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 103ef30..54e39ef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6589,7 +6589,8 @@ static const struct lval_funcs siginfo_value_funcs =
if there's no object available. */
static struct value *
-siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
if (target_has_stack
&& !ptid_equal (inferior_ptid, null_ptid)
@@ -7011,6 +7012,15 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
"of all processes is %s.\n"), value);
}
+/* Implementation of `siginfo' variable. */
+
+static const struct internalvar_funcs siginfo_funcs =
+{
+ siginfo_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_infrun (void)
{
@@ -7299,7 +7309,7 @@ enabled by default on some platforms."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+ create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
add_setshow_boolean_cmd ("observer", no_class,
&observer_mode_1, _("\
diff --git a/gdb/thread.c b/gdb/thread.c
index 97f283c..aaa7380 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1439,7 +1439,8 @@ update_thread_list (void)
no thread is selected, or no threads exist. */
static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);
@@ -1450,6 +1451,15 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
/* Commands with a prefix of `thread'. */
struct cmd_list_element *thread_cmd_list = NULL;
+/* Implementation of `thread' variable. */
+
+static struct internalvar_funcs thread_funcs =
+{
+ thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1495,5 +1505,5 @@ Show printing of thread events (such as thread start and exit)."), NULL,
show_print_thread_events,
&setprintlist, &showprintlist);
- create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 89f75b6..ac8fade 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4946,7 +4946,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
available. */
static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
@@ -5125,6 +5126,15 @@ traceframe_available_memory (VEC(mem_range_s) **result,
return 0;
}
+/* Implementation of `sdata' variable. */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
@@ -5135,7 +5145,7 @@ _initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
traceframe_number = -1;
tracepoint_number = -1;
diff --git a/gdb/value.c b/gdb/value.c
index e8eb33f..9a384a5 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1577,7 +1577,14 @@ struct internalvar
struct value *value;
/* The call-back routine used with INTERNALVAR_MAKE_VALUE. */
- internalvar_make_value make_value;
+ struct
+ {
+ /* The functions to call. */
+ const struct internalvar_funcs *functions;
+
+ /* The function's user-data. */
+ void *data;
+ } make_value;
/* The internal function used with INTERNALVAR_FUNCTION. */
struct
@@ -1676,18 +1683,39 @@ create_internalvar (const char *name)
/* Create an internal variable with name NAME and register FUN as the
function that value_of_internalvar uses to create a value whenever
this variable is referenced. NAME should not normally include a
- dollar sign. */
+ dollar sign. DATA is passed uninterpreted to FUN when it is
+ called. CLEANUP, if not NULL, is called when the internal variable
+ is destroyed. It is passed DATA as its only argument. */
struct internalvar *
-create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data)
{
struct internalvar *var = create_internalvar (name);
var->kind = INTERNALVAR_MAKE_VALUE;
- var->u.make_value = fun;
+ var->u.make_value.functions = funcs;
+ var->u.make_value.data = data;
return var;
}
+/* See documentation in value.h. */
+
+int
+compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value)
+{
+ if (var->kind != INTERNALVAR_MAKE_VALUE
+ || var->u.make_value.functions->compile_to_ax == NULL)
+ return 0;
+
+ var->u.make_value.functions->compile_to_ax (var, expr, value,
+ var->u.make_value.data);
+ return 1;
+}
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
@@ -1760,7 +1788,8 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;
case INTERNALVAR_MAKE_VALUE:
- val = (*var->u.make_value) (gdbarch, var);
+ val = (*var->u.make_value.functions->make_value) (gdbarch, var,
+ var->u.make_value.data);
break;
default:
@@ -1956,6 +1985,11 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;
+ case INTERNALVAR_MAKE_VALUE:
+ if (var->u.make_value.functions->destroy != NULL)
+ var->u.make_value.functions->destroy (var->u.make_value.data);
+ break;
+
default:
break;
}
diff --git a/gdb/value.h b/gdb/value.h
index 3ce0f88..3e4e57f 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -733,10 +733,52 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
extern struct internalvar *create_internalvar (const char *name);
-typedef struct value * (*internalvar_make_value) (struct gdbarch *,
- struct internalvar *);
+/* An internalvar can be dynamically computed by supplying a vector of
+ function pointers to perform various operations. */
+
+struct internalvar_funcs
+{
+ /* Compute the value of the variable. The DATA argument passed to
+ the function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ struct value *(*make_value) (struct gdbarch *arch,
+ struct internalvar *var,
+ void *data);
+
+ /* Update the agent expression EXPR with bytecode to compute the
+ value. VALUE is the agent value we are updating. The DATA
+ argument passed to this function is the same argument that was
+ passed to `create_internalvar_type_lazy'. If this pointer is
+ NULL, then the internalvar cannot be compiled to an agent
+ expression. */
+
+ void (*compile_to_ax) (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ void *data);
+
+ /* If non-NULL, this is called to destroy DATA. The DATA argument
+ passed to this function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ void (*destroy) (void *data);
+};
+
extern struct internalvar *
- create_internalvar_type_lazy (char *name, internalvar_make_value fun);
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data);
+
+/* Compile an internal variable to an agent expression. VAR is the
+ variable to compile; EXPR and VALUE are the agent expression we are
+ updating. This will return 0 if there is no known way to compile
+ VAR, and 1 if VAR was successfully compiled. It may also throw an
+ exception on error. */
+
+extern int compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value);
extern struct internalvar *lookup_internalvar (const char *name);
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6b84eff..a704599 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -268,7 +268,7 @@ static const struct lval_funcs tlb_value_funcs =
if there's no object available. */
static struct value *
-tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore)
{
if (target_has_stack && !ptid_equal (inferior_ptid, null_ptid))
{
@@ -428,6 +428,15 @@ init_w32_command_list (void)
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_windows_tdep;
+/* Implementation of `tlb' variable. */
+
+static const struct internalvar_funcs tlb_funcs =
+{
+ tlb_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_windows_tdep (void)
{
@@ -454,5 +463,5 @@ even if their meaning is unknown."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_tlb", tlb_make_value);
+ create_internalvar_type_lazy ("_tlb", &tlb_funcs, NULL);
}
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
2012-03-09 20:32 ` [PATCH 1/3] Refactor internal variable mechanism Sergio Durigan Junior
2012-03-09 20:34 ` [PATCH 3/3] Use longjmp and exception probes when available Sergio Durigan Junior
@ 2012-03-09 20:34 ` Sergio Durigan Junior
2012-03-10 8:38 ` Eli Zaretskii
` (3 more replies)
2012-03-09 21:15 ` [PATCH 0/3] Implement support for SystemTap probes on userspace Tom Tromey
2012-03-10 7:55 ` Eli Zaretskii
4 siblings, 4 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-09 20:34 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Hello,
This is the second patch. It implements a bunch of new things needed to
support SystemTap probes, for both arch-dependent and independent bits.
There are new variables and methods for gdbarch, new files
(stap-probe.[ch]), new methods for reading and handling SystemTap probes
on elfread.c, adaptations on breakpoint.c to make the `break' command
understand the `-p' and `-probe' arguments, and so on. It also includes
documentation and testcases inclusions.
Is this OK?
gdb/ChangeLog
2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* Makefile.in (SFILES): Add `stap-probe'.
(COMMON_OBS): Likewise.
(HFILES_NO_SRCDIR): Likewise.
* NEWS: Mention support for SystemTap probes.
* amd64-linux-tdep.c (amd64_linux_init_abi): Initializing proper
fields used by SystemTap probes' arguments parser.
* arm-linux-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(arm_stap_is_single_operand): New function.
(arm_stap_parse_special_token): Likewise.
(arm_linux_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* ax-gdb.c (require_rvalue): Removing static declaration.
(gen_expr): Likewise.
* ax-gdb.h (gen_expr): Declaring function.
(require_rvalue): Likewise.
* breakpoint.c: Include `gdb_regex.h' and `stap-probe.h'.
(bkpt_stap_probe_breakpoint_ops): New variable.
(modify_semaphore): New function.
(insert_bp_location): Call `modify_semaphore'.
(remove_breakpoint_1): Likewise.
(momentary_breakpoint_from_master): Use the `semaphore' value.
(add_location_to_breakpoint): Likewise.
(break_command_1): Using proper breakpoint_ops according to the
argument passed by user in the command line.
(bkpt_stap_probe_create_sals_from_address): New function.
(bkpt_stap_probe_decode_linespec): Likewise.
(initialize_breakpoint_ops): Initializing breakpoint_ops from
SystemTap probes.
* breakpoint.h (struct bp_location) <semaphore>: New field.
(modify_semaphore): New function.
* cli-utils.c (skip_spaces_const): New function.
(extract_arg): Likewise.
* cli-utils.h (skip_spaces_const): Likewise.
(extract_arg): Likewise.
* coffread.c (coff_sym_fns): Add `sym_probe_fns' value.
* dbxread.c (aout_sym_fns): Likewise.
* elfread.c: Include `stap-probe.h' and `arch-utils.h'.
(stap_probe_key): New variable.
(struct stap_probe_per_objfile): New struct.
(handle_probe): New function.
(STAP_BASE_SECTION_NAME): New define.
(get_base_address_1): New function.
(get_base_address): Likewise.
(elf_get_probes): Likewise.
(elf_get_probe_argument_count): Likewise.
(elf_evaluate_probe_argument): Likewise.
(elf_compile_to_ax): Likewise.
(elf_symfile_relocate_probe): Likewise.
(stap_probe_key_free): Likewise.
(elf_probe_fns): New variable.
(elf_sym_fns): Add `sym_probe_fns' value.
(elf_sym_fns_lazy_psyms): Likewise.
(elf_sym_fns_gdb_index): Likewise.
(_initialize_elfread): Initialize objfile cache for SystemTap
probes.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh (stap_integer_prefix): New variable.
(stap_integer_suffix): Likewise.
(stap_register_prefix): Likewise.
(stap_register_suffix): Likewise.
(stap_register_indirection_prefix): Likewise.
(stap_register_indirection_suffix): Likewise.
(stap_gdb_register_prefix): Likewise.
(stap_gdb_register_suffix): Likewise.
(stap_is_single_operand): New function.
(stap_parse_special_token): Likewise.
(struct stap_parse_info): Forward declaration.
* i386-linux-tdep.c (i386_linux_init_abi): Initializing proper
fields used by SystemTap probes' arguments parser.
* i386-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(i386_stap_is_single_operand): New function.
(i386_stap_parse_special_token): Likewise.
* i386-tdep.h (i386_stap_is_single_operand): Likewise.
(i386_stap_parse_special_token): Likewise.
* machoread.c (macho_sym_fns): Add `sym_probe_fns' value.
* mipsread.c (ecoff_sym_fns): Likewise.
* objfiles.c (objfile_relocate1): Support relocation for SystemTap
probes.
* parse.c (prefixify_expression): Remove static declaration.
(initialize_expout): Likewise.
(reallocate_expout): Likewise.
* parser-defs.h (initialize_expout): Declare function.
(reallocate_expout): Likewise.
(prefixify_expression): Likewise.
* ppc-linux-tdep.c: Including headers needed to perform the parsing
of SystemTap probes' arguments.
(ppc_stap_is_single_operand): New function.
(ppc_stap_parse_special_token): Likewise.
(ppc_linux_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* s390-tdep.c: Including headers needed to perform the parsing of
SystemTap probes' arguments.
(s390_stap_is_single_operand): New function.
(s390_gdbarch_init): Initializing proper fields used by SystemTap
probes' arguments parser.
* somread.c (som_sym_fns): Add `sym_probe_fns' value.
* stap-probe.c: New file, for SystemTap probe support.
* stap-probe.h: Likewise.
* symfile.h (struct sym_probe_fns): New struct.
(struct sym_fns) <sym_probe_fns>: New field.
* symtab.c (init_sal): Initialize `semaphore' field.
* symtab.h (struct symtab_and_line) <semaphore>: New field.
* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
locations.
(stop_tracing): Likewise.
* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
gdb/doc/ChangeLog
2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Static Probe Points): New entry, explaining SystemTap
probe support on GDB.
gdb/testsuite/ChangeLog
2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* gdb.base/default.exp: Add `$_probe_arg*' convenience
variables.
* gdb.base/stap-probe.c: New file.
* gdb.base/stap-probe.exp: New file.
* gdb.cp/nextoverthrow.exp: Add check for SystemTap probe in
libgcc's unwinder.
* gdb.trace/stap-trace.c: New file.
* gdb.trace/stap-trace.exp: New file.
---
gdb/Makefile.in | 8 +-
gdb/NEWS | 4 +
gdb/amd64-linux-tdep.c | 9 +
gdb/arm-linux-tdep.c | 131 +++
gdb/ax-gdb.c | 8 +-
gdb/ax-gdb.h | 5 +
gdb/breakpoint.c | 88 ++-
gdb/breakpoint.h | 12 +
gdb/cli/cli-utils.c | 41 +
gdb/cli/cli-utils.h | 11 +
gdb/coffread.c | 1 +
gdb/dbxread.c | 1 +
gdb/doc/gdb.texinfo | 82 ++
gdb/elfread.c | 288 ++++++
gdb/gdbarch.c | 250 +++++
gdb/gdbarch.h | 120 +++
gdb/gdbarch.sh | 96 ++
gdb/i386-linux-tdep.c | 9 +
gdb/i386-tdep.c | 312 ++++++
gdb/i386-tdep.h | 9 +
gdb/machoread.c | 1 +
gdb/mipsread.c | 1 +
gdb/objfiles.c | 5 +
gdb/parse.c | 18 +-
gdb/parser-defs.h | 17 +
gdb/ppc-linux-tdep.c | 76 ++
gdb/s390-tdep.c | 21 +
gdb/somread.c | 1 +
gdb/stap-probe.c | 1689 ++++++++++++++++++++++++++++++++
gdb/stap-probe.h | 144 +++
gdb/symfile.h | 55 +
gdb/symtab.c | 1 +
gdb/symtab.h | 4 +
gdb/testsuite/gdb.base/default.exp | 13 +
gdb/testsuite/gdb.base/stap-probe.c | 108 ++
gdb/testsuite/gdb.base/stap-probe.exp | 187 ++++
gdb/testsuite/gdb.cp/nextoverthrow.exp | 11 +
gdb/testsuite/gdb.trace/stap-trace.c | 71 ++
gdb/testsuite/gdb.trace/stap-trace.exp | 129 +++
gdb/tracepoint.c | 23 +
gdb/xcoffread.c | 1 +
41 files changed, 4037 insertions(+), 24 deletions(-)
create mode 100644 gdb/stap-probe.c
create mode 100644 gdb/stap-probe.h
create mode 100644 gdb/testsuite/gdb.base/stap-probe.c
create mode 100644 gdb/testsuite/gdb.base/stap-probe.exp
create mode 100644 gdb/testsuite/gdb.trace/stap-trace.c
create mode 100644 gdb/testsuite/gdb.trace/stap-trace.exp
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 84eda7d..050aacd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -723,8 +723,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
sentinel-frame.c \
serial.c ser-base.c ser-unix.c skip.c \
solib.c solib-target.c source.c \
- stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
- symtab.c \
+ stabsread.c stack.c stap-probe.c std-regs.c \
+ symfile.c symfile-mem.c symmisc.c symtab.c \
target.c target-descriptions.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
@@ -820,7 +820,7 @@ osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
python/python-internal.h python/python.h ravenscar-thread.h record.h \
solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
-gnulib/stddef.in.h inline-frame.h skip.h \
+gnulib/stddef.in.h inline-frame.h skip.h stap-probe.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
common/linux-osdata.h gdb-dlfcn.h
@@ -909,7 +909,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
xml-support.o xml-syscall.o xml-utils.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
- jit.o progspace.o skip.o \
+ jit.o progspace.o skip.o stap-probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o
TSOBS = inflow.o
diff --git a/gdb/NEWS b/gdb/NEWS
index 9c89346..1439945 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
*** Changes since GDB 7.4
+* GDB now has support for SystemTap <sys/sdt.h> probes. You can set a
+ breakpoint using the new "-p" or "-probe" options and inspect the probe
+ arguments using the new $_probe_arg family of convenience variables.
+
* Python scripting
** GDB commands implemented in Python can now be put in command class
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index da22c1c..05f7f5d 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1362,6 +1362,15 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);
+ /* SystemTap variables and functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "$");
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch, i386_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ i386_stap_parse_special_token);
+
/* Initialize the amd64_linux_record_tdep. */
/* These values are the size of the type that will be used in a system
call. They are obtained from Linux Kernel source. */
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index e41205b..f49c0cf 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -43,6 +43,12 @@
#include "gdbthread.h"
#include "symfile.h"
+#include "cli/cli-utils.h"
+#include "stap-probe.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
#include "gdb_string.h"
/* This is defined in <elf.h> on ARM GNU/Linux systems. */
@@ -1056,6 +1062,122 @@ arm_linux_displaced_step_copy_insn (struct gdbarch *gdbarch,
return dsc;
}
+static int
+arm_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == '#' /* Literal number. */
+ || *s == '[' /* Register indirection or
+ displacement. */
+ || isalpha (*s)); /* Register value. */
+}
+
+/* This routine is used to parse a special token in ARM's assembly.
+
+ The special tokens parsed by it are:
+
+ - Register displacement (e.g, [fp, #-8])
+
+ It returns one if the special token has been parsed successfully,
+ or zero if the current token is not considered special. */
+
+static int
+arm_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ if (*p->arg == '[')
+ {
+ /* Temporary holder for lookahead. */
+ const char *tmp = p->arg;
+ /* Used to save the register name. */
+ const char *start;
+ char *regname;
+ int len, offset;
+ int got_minus = 0;
+ long displacement;
+ struct stoken str;
+
+ ++tmp;
+ start = tmp;
+
+ /* Register name. */
+ while (isalnum (*tmp))
+ ++tmp;
+
+ if (*tmp != ',')
+ return 0;
+
+ len = tmp - start;
+ regname = alloca (len + 2);
+
+ offset = 0;
+ if (isdigit (*start))
+ {
+ /* If we are dealing with a register whose name begins with a
+ digit, it means we should prefix the name with the letter
+ `r', because GDB expects this name pattern. Otherwise (e.g.,
+ we are dealing with the register `fp'), we don't need to
+ add such a prefix. */
+ regname[0] = 'r';
+ offset = 1;
+ }
+
+ strncpy (regname + offset, start, len);
+ len += offset;
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ ++tmp;
+ tmp = skip_spaces_const (tmp);
+ if (*tmp++ != '#')
+ return 0;
+
+ if (*tmp == '-')
+ {
+ ++tmp;
+ got_minus = 1;
+ }
+
+ displacement = strtol (tmp, (char **) &tmp, 10);
+
+ /* Skipping last `]'. */
+ if (*tmp++ != ']')
+ return 0;
+
+ /* The displacement. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacement);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+
+ /* The register name. */
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ write_exp_elt_opcode (BINOP_ADD);
+
+ /* Casting to the expected type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = tmp;
+ }
+ else
+ return 0;
+
+ return 1;
+}
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
@@ -1155,6 +1277,15 @@ arm_linux_init_abi (struct gdbarch_info info,
simple_displaced_step_free_closure);
set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point);
+ /* SystemTap functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "#");
+ set_gdbarch_stap_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "[");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, "]");
+ set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_is_single_operand (gdbarch, arm_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ arm_stap_parse_special_token);
tdep->syscall_next_pc = arm_linux_syscall_next_pc;
}
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index b163681..0d796ac 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -95,8 +95,6 @@ static void gen_int_literal (struct agent_expr *ax,
struct axs_value *value,
LONGEST k, struct type *type);
-
-static void require_rvalue (struct agent_expr *ax, struct axs_value *value);
static void gen_usual_unary (struct expression *exp, struct agent_expr *ax,
struct axs_value *value);
static int type_wider_than (struct type *type1, struct type *type2);
@@ -157,8 +155,6 @@ static void gen_repeat (struct expression *exp, union exp_element **pc,
static void gen_sizeof (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value,
struct type *size_type);
-static void gen_expr (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
static void gen_expr_binop_rest (struct expression *exp,
enum exp_opcode op, union exp_element **pc,
struct agent_expr *ax,
@@ -788,7 +784,7 @@ gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k,
/* Take what's on the top of the stack (as described by VALUE), and
try to make an rvalue out of it. Signal an error if we can't do
that. */
-static void
+void
require_rvalue (struct agent_expr *ax, struct axs_value *value)
{
/* Only deal with scalars, structs and such may be too large
@@ -1806,7 +1802,7 @@ gen_sizeof (struct expression *exp, union exp_element **pc,
/* XXX: i18n */
/* A gen_expr function written by a Gen-X'er guy.
Append code for the subexpression of EXPR starting at *POS_P to AX. */
-static void
+void
gen_expr (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value)
{
diff --git a/gdb/ax-gdb.h b/gdb/ax-gdb.h
index 48c35a4..09f6889 100644
--- a/gdb/ax-gdb.h
+++ b/gdb/ax-gdb.h
@@ -110,6 +110,11 @@ extern struct agent_expr *gen_trace_for_return_address (CORE_ADDR,
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
+extern void gen_expr (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value);
+
+extern void require_rvalue (struct agent_expr *ax, struct axs_value *value);
+
extern int trace_kludge;
extern int trace_string_kludge;
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1158f0e..a8f3a42 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -60,6 +60,8 @@
#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
+#include "gdb_regex.h"
+#include "stap-probe.h"
#include "cli/cli-utils.h"
#include "continuations.h"
#include "stack.h"
@@ -290,6 +292,9 @@ static struct breakpoint_ops momentary_breakpoint_ops;
breakpoints. */
struct breakpoint_ops bkpt_breakpoint_ops;
+/* Breakpoints set on SystemTap probes. */
+static struct breakpoint_ops bkpt_stap_probe_breakpoint_ops;
+
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
struct counted_command_line
@@ -1926,6 +1931,40 @@ unduplicated_should_be_inserted (struct bp_location *bl)
return result;
}
+/* See the comment in breakpoint.h. */
+
+void
+modify_semaphore (struct bp_location *loc, int set)
+{
+ struct gdbarch *arch = loc->gdbarch;
+ gdb_byte bytes[sizeof (LONGEST)];
+ /* The ABI specifies "unsigned short". */
+ struct type *type = builtin_type (arch)->builtin_unsigned_short;
+ CORE_ADDR address = loc->semaphore;
+ ULONGEST value;
+
+ if (address == 0)
+ return;
+
+ /* Swallow errors. */
+ if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
+ return;
+
+ value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
+ gdbarch_byte_order (arch));
+ /* Note that we explicitly don't worry about overflow or
+ underflow. */
+ if (set)
+ ++value;
+ else
+ --value;
+
+ store_unsigned_integer (bytes, TYPE_LENGTH (type),
+ gdbarch_byte_order (arch), value);
+
+ target_write_memory (address, bytes, TYPE_LENGTH (type));
+}
+
/* Parses a conditional described by an expression COND into an
agent expression bytecode suitable for evaluation
by the bytecode interpreter. Return NULL if there was
@@ -2168,6 +2207,8 @@ insert_bp_location (struct bp_location *bl,
/* No overlay handling: just set the breakpoint. */
val = bl->owner->ops->insert_location (bl);
+
+ modify_semaphore (bl, 1);
}
else
{
@@ -3153,6 +3194,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
{
/* No overlay handling: just remove the breakpoint. */
val = bl->owner->ops->remove_location (bl);
+
+ modify_semaphore (bl, 0);
}
else
{
@@ -8070,6 +8113,7 @@ momentary_breakpoint_from_master (struct breakpoint *orig,
copy->loc->address = orig->loc->address;
copy->loc->section = orig->loc->section;
copy->loc->pspace = orig->loc->pspace;
+ copy->loc->semaphore = orig->loc->semaphore;
if (orig->loc->source_file != NULL)
copy->loc->source_file = xstrdup (orig->loc->source_file);
@@ -8155,6 +8199,7 @@ add_location_to_breakpoint (struct breakpoint *b,
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
+ loc->semaphore = sal->semaphore;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
@@ -8885,6 +8930,14 @@ break_command_1 (char *arg, int flag, int from_tty)
enum bptype type_wanted = (flag & BP_HARDWAREFLAG
? bp_hardware_breakpoint
: bp_breakpoint);
+ struct breakpoint_ops *ops;
+
+ /* Matching breakpoints on SystemTap probes (`-p' or `-probe'). */
+ if (arg && ((strncmp (arg, "-p", 2) == 0 && isspace (arg[2]))
+ || (strncmp (arg, "-probe", 6) == 0 && isspace (arg[6]))))
+ ops = &bkpt_stap_probe_breakpoint_ops;
+ else
+ ops = &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (),
arg,
@@ -8892,7 +8945,7 @@ break_command_1 (char *arg, int flag, int from_tty)
tempflag, type_wanted,
0 /* Ignore count */,
pending_break_support,
- &bkpt_breakpoint_ops,
+ ops,
from_tty,
1 /* enabled */,
0 /* internal */);
@@ -12364,6 +12417,33 @@ momentary_bkpt_print_mention (struct breakpoint *b)
/* Nothing to mention. These breakpoints are internal. */
}
+/* Specific methods for SystemTap probe breakpoints. */
+
+static void
+bkpt_stap_probe_create_sals_from_address (char **arg,
+ struct linespec_result *canonical,
+ enum bptype type_wanted,
+ char *addr_start, char **copy_arg)
+{
+ struct linespec_sals lsal;
+
+ lsal.sals = parse_stap_probe (arg, canonical);
+
+ *copy_arg = xstrdup (canonical->addr_string);
+ lsal.canonical = xstrdup (*copy_arg);
+
+ VEC_safe_push (linespec_sals, canonical->sals, &lsal);
+}
+
+static void
+bkpt_stap_probe_decode_linespec (struct breakpoint *b, char **s,
+ struct symtabs_and_lines *sals)
+{
+ *sals = parse_stap_probe (s, NULL);
+ if (!sals->sals)
+ error (_("probe not found"));
+}
+
/* The breakpoint_ops structure to be used in tracepoints. */
static void
@@ -14855,6 +14935,12 @@ initialize_breakpoint_ops (void)
ops->print_it = momentary_bkpt_print_it;
ops->print_mention = momentary_bkpt_print_mention;
+ /* SystemTap probe breakpoints. */
+ ops = &bkpt_stap_probe_breakpoint_ops;
+ *ops = bkpt_breakpoint_ops;
+ ops->create_sals_from_address = bkpt_stap_probe_create_sals_from_address;
+ ops->decode_linespec = bkpt_stap_probe_decode_linespec;
+
/* GNU v3 exception catchpoints. */
ops = &gnu_v3_exception_catchpoint_ops;
*ops = bkpt_breakpoint_ops;
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 5b5172e..11ea6c8 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -418,6 +418,11 @@ struct bp_location
processor's architectual constraints. */
CORE_ADDR requested_address;
+ /* If the location comes from a SystemTap probe point, and the probe
+ has an associated semaphore variable, then this is the address of
+ the semaphore. Otherwise, this is zero. */
+ CORE_ADDR semaphore;
+
char *function_name;
/* Details of the placed breakpoint, when inserted. */
@@ -1471,6 +1476,13 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
+/* Set or clear a SystemTap semaphore. LOC is the location which may
+ hold a semaphore. SET is non-zero if the semaphore should be set,
+ or zero if the semaphore should be cleared. Semaphores act as
+ reference counters, so calls to this function must be paired. */
+
+extern void modify_semaphore (struct bp_location *location, int set);
+
extern void handle_solib_event (void);
#endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/cli/cli-utils.c b/gdb/cli/cli-utils.c
index a7b2718..a1e5161 100644
--- a/gdb/cli/cli-utils.c
+++ b/gdb/cli/cli-utils.c
@@ -223,6 +223,18 @@ skip_spaces (char *chp)
return chp;
}
+/* A const-correct version of the above. */
+
+const char *
+skip_spaces_const (const char *chp)
+{
+ if (chp == NULL)
+ return NULL;
+ while (*chp && isspace (*chp))
+ chp++;
+ return chp;
+}
+
/* See documentation in cli-utils.h. */
char *
@@ -245,3 +257,32 @@ remove_trailing_whitespace (const char *start, char *s)
return s;
}
+
+/* See documentation in cli-utils.h. */
+
+char *
+extract_arg (char **arg)
+{
+ char *result, *copy;
+
+ if (!*arg)
+ return NULL;
+
+ /* Find the start of the argument. */
+ *arg = skip_spaces (*arg);
+ if (! **arg)
+ return NULL;
+ result = *arg;
+
+ /* Find the end of the argument. */
+ *arg = skip_to_space (*arg + 1);
+
+ if (result == *arg)
+ return NULL;
+
+ copy = xmalloc (*arg - result + 1);
+ memcpy (copy, result, *arg - result);
+ copy[*arg - result] = '\0';
+
+ return copy;
+}
diff --git a/gdb/cli/cli-utils.h b/gdb/cli/cli-utils.h
index e23c7d8..5f8a91d 100644
--- a/gdb/cli/cli-utils.h
+++ b/gdb/cli/cli-utils.h
@@ -94,6 +94,10 @@ extern int number_is_in_list (char *list, int number);
extern char *skip_spaces (char *inp);
+/* A const-correct version of the above. */
+
+extern const char *skip_spaces_const (const char *inp);
+
/* Skip leading non-whitespace characters in INP, returning an updated
pointer. If INP is NULL, return NULL. */
@@ -103,4 +107,11 @@ extern char *skip_to_space (char *inp);
START. */
extern char *remove_trailing_whitespace (const char *start, char *s);
+
+/* A helper function to extract an argument from *ARG. An argument is
+ delimited by whitespace. The return value is either NULL if no
+ argument was found, or an xmalloc'd string. */
+
+extern char *extract_arg (char **arg);
+
#endif /* CLI_UTILS_H */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 30bf3f7..f5b9fe0 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2196,6 +2196,7 @@ static const struct sym_fns coff_sym_fns =
default_symfile_relocate, /* sym_relocate: Relocate a debug
section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 1725112..2d47407 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -3589,6 +3589,7 @@ static const struct sym_fns aout_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e8bbded..16c7a4d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3303,6 +3303,7 @@ all breakpoints in that range are operated on.
* Conditions:: Break conditions
* Break Commands:: Breakpoint command lists
* Save Breakpoints:: How to save breakpoints in a file
+* Static Probe Points:: Listing static probe points
* Error in Breakpoints:: ``Cannot insert breakpoints''
* Breakpoint-related Warnings:: ``Breakpoint address adjusted...''
@end menu
@@ -4613,6 +4614,50 @@ and remove the breakpoint definitions you're not interested in, or
that can no longer be recreated.
@end table
+@node Static Probe Points
+@subsection Static Probe Points
+
+@cindex SystemTap static probe point
+@cindex sdt-probe
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes, using @file{sys/sdt.h}. @value{GDBN}
+can list the available probes, and you can put breakpoints at the
+probe points (@pxref{Specify Location}).
+
+You can examine the available @code{SystemTap} static probes using
+@code{info probes}:
+
+@table @code
+@kindex info probes
+@item info probes [@var{provider} [@var{name} [@var{objfile}]]]
+List the available @code{SystemTap} static probes.
+
+If given, @var{provider} is a regular expression used to select which
+providers to list. If omitted, all providers are listed.
+
+If given, @var{name} is a regular expression used to select which
+probes to list. If omitted, all probes are listed.
+
+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.
+@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
+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
+convenience variable @code{$_probe_argc} holds the number of arguments
+at the current probe point.
+
+These variables are always available, but attempts to access them at
+any location other than a probe point will cause @value{GDBN} to give
+an error.
+
+
@c @ifclear BARETARGET
@node Error in Breakpoints
@subsection ``Cannot insert breakpoints''
@@ -6628,6 +6673,29 @@ specify the function unambiguously, e.g., if there are several
functions with identical names in different source files.
@end table
+@cindex SystemTap static probe point
+@item -p|-probe @r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}
+The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
+applications to embed static probes. This form of linespec specifies
+the location of such a static probe. See
+@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
+for more information on static probes.
+
+If @var{objfile} is given, only probes coming from that shared library
+or executable are considered. If @var{provider} is given, then only
+probes from that provider are considered.
+
+@xref{Static Probe Points}, for more information on finding and using
+static probes.
+
+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{-p} 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.
+
@end table
@@ -8884,6 +8952,10 @@ to match the format in which the data was printed.
The variable @code{$_exitcode} is automatically set to the exit code when
the program being debugged terminates.
+@item $_probe_argc
+@itemx $_probe_arg0@dots{}$_probe_arg11
+Arguments to a SystemTap static probe. @xref{Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, inspect, convenience variable}
The variable @code{$_sdata} contains extra collected static tracepoint
@@ -10836,6 +10908,16 @@ Collect all local variables.
Collect the return address. This is helpful if you want to see more
of a backtrace.
+@item $_probe_argc
+Collects the number of arguments from the @code{SystemTap} probe at
+which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}.
+
+@item $_probe_arg@var{N}
+Where @var{N} varies from 0 to 11. Collects the @var{N}th argument
+from the @code{SystemTap} probe at which the tracepoint is located.
+@xref{Static Probe Points,,Static Probe Points}.
+
@item $_sdata
@vindex $_sdata@r{, collect}
Collect static tracepoint marker specific data. Only available for
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9f8a7e8..5dd4d38 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -36,6 +36,8 @@
#include "demangle.h"
#include "psympriv.h"
#include "filenames.h"
+#include "stap-probe.h"
+#include "arch-utils.h"
#include "gdbtypes.h"
#include "value.h"
#include "infcall.h"
@@ -60,6 +62,21 @@ struct elfinfo
asection *mdebugsect; /* Section pointer for .mdebug section */
};
+/* Per-objfile data for SystemTap probe info. */
+
+static const struct objfile_data *stap_probe_key = NULL;
+
+/* Per-objfile data about SystemTap probes. */
+
+struct stap_probe_per_objfile
+ {
+ /* The number of probes in this objfile. */
+ int stap_num_probes;
+
+ /* The probes themselves. */
+ struct stap_probe *probes;
+ };
+
static void free_elfinfo (void *);
/* Minimal symbols located at the GOT entries for .plt - that is the real
@@ -1579,7 +1596,273 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
complaint (&symfile_complaints,
_("elf/stab section information missing for %s"), filename);
}
+
+/* Helper function that parses the information contained in a
+ SystemTap's probe. Basically, the information consists in:
+
+ - Probe's PC address;
+ - Link-time section address of `.stapsdt.base' section;
+ - Link-time address of the semaphore variable, or ZERO if the
+ probe doesn't have an associated semaphore;
+ - Probe's provider name;
+ - Probe's name;
+ - Probe's argument format. */
+
+static void
+handle_probe (struct objfile *objfile, struct sdt_note *el,
+ struct stap_probe *ret, CORE_ADDR base)
+{
+ bfd *abfd = objfile->obfd;
+ int size = bfd_get_arch_size (abfd) / 8;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ CORE_ADDR base_ref;
+
+ ret->gdbarch = gdbarch;
+
+ /* Provider and the name of the probe. */
+ ret->provider = &el->data[3 * size];
+ ret->name = memchr (ret->provider, '\0',
+ (char *) el->data + el->size - ret->provider);
+ /* Making sure there is a name. */
+ if (!ret->name)
+ {
+ complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+ objfile->name);
+ ret->provider = NULL;
+ ret->name = NULL;
+ }
+ else
+ ++ret->name;
+
+ /* Retrieving the probe's address. */
+ ret->address = extract_typed_address (&el->data[0], ptr_type);
+ /* Link-time sh_addr of `.stapsdt.base' section. */
+ base_ref = extract_typed_address (&el->data[size], ptr_type);
+ /* Semaphore address. */
+ ret->sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
+
+ ret->address += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_TEXT (objfile))
+ + base - base_ref);
+ if (ret->sem_addr)
+ ret->sem_addr += (ANOFFSET (objfile->section_offsets,
+ SECT_OFF_DATA (objfile))
+ + base - base_ref);
+
+ /* Arguments. We can only extract the argument format if there is a valid
+ name for this probe. */
+ if (ret->name)
+ {
+ ret->args = memchr (ret->name, '\0',
+ (char *) el->data + el->size - ret->name);
+
+ if (ret->args != NULL)
+ ++ret->args;
+ if (ret->args == NULL
+ || (memchr (ret->args, '\0',
+ (char *) el->data + el->size - ret->name)
+ != el->data + el->size - 1))
+ {
+ complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
+ objfile->name);
+ ret->args = NULL;
+ }
+ }
+ else
+ ret->args = NULL;
+}
+
+/* The name of the SystemTap section where we will find information about
+ the probes. */
+
+#define STAP_BASE_SECTION_NAME ".stapsdt.base"
+
+/* Helper function which tries to find the base address of the SystemTap
+ base section named STAP_BASE_SECTION_NAME. */
+
+static void
+get_base_address_1 (bfd *abfd, asection *sect, void *obj)
+{
+ bfd_vma *base = (bfd_vma *) obj;
+
+ if (*base == (bfd_vma) -1
+ && (sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
+ && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
+ *base = sect->vma;
+}
+
+/* Helper function which iterates over every section in the BFD file,
+ trying to find the base address of the SystemTap base section.
+ Returns the section address if found, or -1 otherwise. */
+
+static bfd_vma
+get_base_address (bfd *obfd)
+{
+ bfd_vma base = (bfd_vma) -1;
+
+ bfd_map_over_sections (obfd, get_base_address_1, (void *) &base);
+
+ return base;
+}
+
+/* Implementation of `sym_get_probes', as documented in symfile.h. */
+
+static struct stap_probe *
+elf_get_probes (struct objfile *objfile, int *num_probes)
+{
+ struct stap_probe *ret = NULL;
+ struct stap_probe_per_objfile *probes_per_objfile;
+
+ /* Initially, no probes. */
+ *num_probes = 0;
+
+ /* Have we parsed this objfile's probes already? */
+ probes_per_objfile
+ = (struct stap_probe_per_objfile *) objfile_data (objfile,
+ stap_probe_key);
+
+ if (!probes_per_objfile)
+ {
+ /* If we are here, then this is the first time we are parsing the
+ probe's information. We basically have to count how many probes
+ the objfile has, and then fill in the necessary information
+ for each one. */
+
+ bfd *obfd = objfile->obfd;
+ bfd_vma base = get_base_address (obfd);
+ struct sdt_note *iter;
+ int i;
+ int n = 0;
+
+ if (! elf_tdata (obfd)->sdt_note_head)
+ /* There isn't any probe here. */
+ return NULL;
+
+ /* Allocating space for probe info. */
+ for (iter = elf_tdata (obfd)->sdt_note_head;
+ iter;
+ iter = iter->next, ++n);
+
+ ret = xcalloc (n, sizeof (struct stap_probe));
+
+ /* Parsing each probe's information. */
+ for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
+ iter;
+ iter = iter->next, i++)
+ /* We first have to handle all the information about the
+ probe which is present in the section. */
+ handle_probe (objfile, iter, &ret[i], base);
+
+ /* Creating a cache for these probes in the objfile's registry. */
+ probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
+
+ probes_per_objfile->stap_num_probes = n;
+ probes_per_objfile->probes = ret;
+
+ set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
+ }
+ else
+ ret = probes_per_objfile->probes;
+
+ *num_probes = probes_per_objfile->stap_num_probes;
+
+ return ret;
+}
+
+/* Implementation of `sym_get_probe_argument_count', as documented in
+ symfile.h. */
+
+static int
+elf_get_probe_argument_count (struct objfile *objfile,
+ struct stap_probe *probe)
+{
+ const char *pargs = probe->args;
+
+ if (!pargs || !*pargs || *pargs == ':')
+ /* No arguments. */
+ return 0;
+
+ return stap_get_probe_argument_count (probe);
+}
+
+/* Implementation of `sym_evaluate_probe_argument', as documented in
+ symfile.h. */
+
+static struct value *
+elf_evaluate_probe_argument (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct frame_info *frame,
+ int n)
+{
+ return stap_evaluate_probe_argument (objfile, probe, frame, n);
+}
+
+/* Implementation of `sym_compile_to_ax', as documented in symfile.h. */
+
+static void
+elf_compile_to_ax (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n)
+{
+ stap_compile_to_ax (objfile, probe, expr, value, n);
+}
+
+/* Implementation of `sym_relocate_probe', as documented in symfile.h. */
+
+static void
+elf_symfile_relocate_probe (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta)
+{
+ int i;
+ struct stap_probe_per_objfile *p
+ = (struct stap_probe_per_objfile *) objfile_data (objfile,
+ stap_probe_key);
+
+ if (!p)
+ /* No probe to relocate. */
+ return;
+
+ for (i = 0; i < p->stap_num_probes; i++)
+ {
+ p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
+ if (p->probes[i].sem_addr)
+ p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
+ }
+}
+
+/* Helper function used to free the space allocated for storing SystemTap
+ probe information. */
+
+static void
+stap_probe_key_free (struct objfile *objfile, void *d)
+{
+ int i;
+ struct stap_probe_per_objfile *data = (struct stap_probe_per_objfile *) d;
+
+ for (i = 0; i < data->stap_num_probes; i++)
+ stap_free_parsed_args (data->probes[i].parsed_args);
+ xfree (data->probes);
+ xfree (data);
+}
+
\f
+
+/* Implementation `sym_probe_fns', as documented in symfile.h. */
+
+static const struct sym_probe_fns elf_probe_fns =
+{
+ elf_get_probes, /* sym_get_probes */
+ elf_get_probe_argument_count, /* sym_get_probe_argument_count */
+ elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */
+ elf_compile_to_ax, /* sym_compile_to_ax */
+ elf_symfile_relocate_probe, /* sym_relocate_probe */
+};
+
/* Register that we are able to handle ELF object file formats. */
static const struct sym_fns elf_sym_fns =
@@ -1594,6 +1877,7 @@ static const struct sym_fns elf_sym_fns =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1612,6 +1896,7 @@ static const struct sym_fns elf_sym_fns_lazy_psyms =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&psym_functions
};
@@ -1629,6 +1914,7 @@ static const struct sym_fns elf_sym_fns_gdb_index =
elf_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ &elf_probe_fns, /* sym_probe_fns */
&dwarf2_gdb_index_functions
};
@@ -1645,6 +1931,8 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
void
_initialize_elfread (void)
{
+ stap_probe_key
+ = register_objfile_data_with_cleanup (NULL, stap_probe_key_free);
add_symtab_fns (&elf_sym_fns);
elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c079932..056dd5a 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -265,6 +265,16 @@ struct gdbarch
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
gdbarch_record_special_symbol_ftype *record_special_symbol;
gdbarch_get_syscall_number_ftype *get_syscall_number;
+ const char * stap_integer_prefix;
+ const char * stap_integer_suffix;
+ const char * stap_register_prefix;
+ const char * stap_register_suffix;
+ const char * stap_register_indirection_prefix;
+ const char * stap_register_indirection_suffix;
+ const char * stap_gdb_register_prefix;
+ 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;
int has_global_solist;
int has_global_breakpoints;
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
@@ -423,6 +433,16 @@ struct gdbarch startup_gdbarch =
0, /* get_siginfo_type */
0, /* record_special_symbol */
0, /* get_syscall_number */
+ 0, /* stap_integer_prefix */
+ 0, /* stap_integer_suffix */
+ 0, /* stap_register_prefix */
+ 0, /* stap_register_suffix */
+ 0, /* stap_register_indirection_prefix */
+ 0, /* stap_register_indirection_suffix */
+ 0, /* stap_gdb_register_prefix */
+ 0, /* stap_gdb_register_suffix */
+ 0, /* stap_is_single_operand */
+ 0, /* stap_parse_special_token */
0, /* has_global_solist */
0, /* has_global_breakpoints */
default_has_shared_address_space, /* has_shared_address_space */
@@ -715,6 +735,16 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of get_siginfo_type, has predicate. */
/* Skip verify of record_special_symbol, has predicate. */
/* Skip verify of get_syscall_number, has predicate. */
+ /* Skip verify of stap_integer_prefix, invalid_p == 0 */
+ /* Skip verify of stap_integer_suffix, invalid_p == 0 */
+ /* Skip verify of stap_register_prefix, invalid_p == 0 */
+ /* Skip verify of stap_register_suffix, invalid_p == 0 */
+ /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */
+ /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */
+ /* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */
+ /* 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 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 */
@@ -1267,6 +1297,42 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: stabs_argument_has_addr = <%s>\n",
host_address_to_string (gdbarch->stabs_argument_has_addr));
fprintf_unfiltered (file,
+ "gdbarch_dump: stap_gdb_register_prefix = %s\n",
+ gdbarch->stap_gdb_register_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_gdb_register_suffix = %s\n",
+ gdbarch->stap_gdb_register_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_integer_prefix = %s\n",
+ gdbarch->stap_integer_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_integer_suffix = %s\n",
+ gdbarch->stap_integer_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_stap_is_single_operand_p() = %d\n",
+ gdbarch_stap_is_single_operand_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_is_single_operand = <%s>\n",
+ host_address_to_string (gdbarch->stap_is_single_operand));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_stap_parse_special_token_p() = %d\n",
+ gdbarch_stap_parse_special_token_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_parse_special_token = <%s>\n",
+ host_address_to_string (gdbarch->stap_parse_special_token));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_indirection_prefix = %s\n",
+ gdbarch->stap_register_indirection_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_indirection_suffix = %s\n",
+ gdbarch->stap_register_indirection_suffix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_prefix = %s\n",
+ gdbarch->stap_register_prefix);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: stap_register_suffix = %s\n",
+ gdbarch->stap_register_suffix);
+ fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_static_transform_name_p() = %d\n",
gdbarch_static_transform_name_p (gdbarch));
fprintf_unfiltered (file,
@@ -3834,6 +3900,190 @@ set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
gdbarch->get_syscall_number = get_syscall_number;
}
+const char *
+gdbarch_stap_integer_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_integer_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_prefix called\n");
+ return gdbarch->stap_integer_prefix;
+}
+
+void
+set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch,
+ const char * stap_integer_prefix)
+{
+ gdbarch->stap_integer_prefix = stap_integer_prefix;
+}
+
+const char *
+gdbarch_stap_integer_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_integer_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_suffix called\n");
+ return gdbarch->stap_integer_suffix;
+}
+
+void
+set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch,
+ const char * stap_integer_suffix)
+{
+ gdbarch->stap_integer_suffix = stap_integer_suffix;
+}
+
+const char *
+gdbarch_stap_register_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_prefix called\n");
+ return gdbarch->stap_register_prefix;
+}
+
+void
+set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch,
+ const char * stap_register_prefix)
+{
+ gdbarch->stap_register_prefix = stap_register_prefix;
+}
+
+const char *
+gdbarch_stap_register_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_suffix called\n");
+ return gdbarch->stap_register_suffix;
+}
+
+void
+set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch,
+ const char * stap_register_suffix)
+{
+ gdbarch->stap_register_suffix = stap_register_suffix;
+}
+
+const char *
+gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_prefix called\n");
+ return gdbarch->stap_register_indirection_prefix;
+}
+
+void
+set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch,
+ const char * stap_register_indirection_prefix)
+{
+ gdbarch->stap_register_indirection_prefix = stap_register_indirection_prefix;
+}
+
+const char *
+gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_suffix called\n");
+ return gdbarch->stap_register_indirection_suffix;
+}
+
+void
+set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch,
+ const char * stap_register_indirection_suffix)
+{
+ gdbarch->stap_register_indirection_suffix = stap_register_indirection_suffix;
+}
+
+const char *
+gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_gdb_register_prefix called\n");
+ return gdbarch->stap_gdb_register_prefix;
+}
+
+void
+set_gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch,
+ const char * stap_gdb_register_prefix)
+{
+ gdbarch->stap_gdb_register_prefix = stap_gdb_register_prefix;
+}
+
+const char *
+gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_gdb_register_suffix called\n");
+ return gdbarch->stap_gdb_register_suffix;
+}
+
+void
+set_gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch,
+ const char * stap_gdb_register_suffix)
+{
+ gdbarch->stap_gdb_register_suffix = stap_gdb_register_suffix;
+}
+
+int
+gdbarch_stap_is_single_operand_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->stap_is_single_operand != NULL;
+}
+
+int
+gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stap_is_single_operand != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_is_single_operand called\n");
+ return gdbarch->stap_is_single_operand (gdbarch, s);
+}
+
+void
+set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch,
+ gdbarch_stap_is_single_operand_ftype stap_is_single_operand)
+{
+ gdbarch->stap_is_single_operand = stap_is_single_operand;
+}
+
+int
+gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->stap_parse_special_token != NULL;
+}
+
+int
+gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->stap_parse_special_token != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_parse_special_token called\n");
+ return gdbarch->stap_parse_special_token (gdbarch, p);
+}
+
+void
+set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch,
+ gdbarch_stap_parse_special_token_ftype stap_parse_special_token)
+{
+ gdbarch->stap_parse_special_token = stap_parse_special_token;
+}
+
int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 84e6ff8..2d832aa 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -55,6 +55,7 @@ struct core_regset_section;
struct syscall;
struct agent_expr;
struct axs_value;
+struct stap_parse_info;
/* The architecture associated with the connection to the target.
@@ -979,6 +980,125 @@ typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, pti
extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
+/* SystemTap related fields and functions.
+ Prefix used to mark an integer constant on the architecture's assembly
+ For example, on x86 integer constants are written as:
+
+ $10 ;; integer constant 10
+
+ in this case, this prefix would be the character `$'. */
+
+extern const char * gdbarch_stap_integer_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch, const char * stap_integer_prefix);
+
+/* Suffix used to mark an integer constant on the architecture's assembly. */
+
+extern const char * gdbarch_stap_integer_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch, const char * stap_integer_suffix);
+
+/* Prefix used to mark a register name on the architecture's assembly.
+ For example, on x86 the register name is written as:
+
+ %eax ;; register eax
+
+ in this case, this prefix would be the character `%'. */
+
+extern const char * gdbarch_stap_register_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch, const char * stap_register_prefix);
+
+/* Suffix used to mark a register name on the architecture's assembly */
+
+extern const char * gdbarch_stap_register_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch, const char * stap_register_suffix);
+
+/* Prefix used to mark a register indirection on the architecture's assembly.
+ For example, on x86 the register indirection is written as:
+
+ (%eax) ;; indirecting eax
+
+ in this case, this prefix would be the charater `('.
+
+ Please note that we use the indirection prefix also for register
+ displacement, e.g., `4(%eax)' on x86. */
+
+extern const char * gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch, const char * stap_register_indirection_prefix);
+
+/* Suffix used to mark a register indirection on the architecture's assembly.
+ For example, on x86 the register indirection is written as:
+
+ (%eax) ;; indirecting eax
+
+ in this case, this prefix would be the charater `)'.
+
+ Please note that we use the indirection suffix also for register
+ displacement, e.g., `4(%eax)' on x86. */
+
+extern const char * gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch, const char * stap_register_indirection_suffix);
+
+/* Prefix used to name a register using GDB's nomenclature.
+
+ For example, on PPC a register is represented by a number in the assembly
+ language (e.g., `10' is the 10th general-purpose register). However,
+ inside GDB this same register has an `r' appended to its name, so the 10th
+ register would be represented as `r10' internally. */
+
+extern const char * gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch, const char * stap_gdb_register_prefix);
+
+/* Suffix used to name a register using GDB's nomenclature. */
+
+extern const char * gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch);
+extern void set_gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch, const char * stap_gdb_register_suffix);
+
+/* Check if S is a single operand.
+
+ Single operands can be:
+ - Literal integers, e.g. `$10' on x86
+ - Register access, e.g. `%eax' on x86
+ - Register indirection, e.g. `(%eax)' on x86
+ - Register displacement, e.g. `4(%eax)' on x86
+
+ This function should check for these patterns on the string
+ and return 1 if some were found, or zero otherwise. Please try to match
+ as much info as you can from the string, i.e., if you have to match
+ something like `(%', do not match just the `('. */
+
+extern int gdbarch_stap_is_single_operand_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_stap_is_single_operand_ftype) (struct gdbarch *gdbarch, const char *s);
+extern int gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, const char *s);
+extern void set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, gdbarch_stap_is_single_operand_ftype *stap_is_single_operand);
+
+/* Function used to handle a "special case" in the parser.
+
+ A "special case" is considered to be an unknown token, i.e., a token
+ that the parser does not know how to parse. A good example of special
+ case would be ARM's register displacement syntax:
+
+ [R0, #4] ;; displacing R0 by 4
+
+ Since the parser assumes that a register displacement is of the form:
+
+ <number> <indirection_prefix> <register_name> <indirection_suffix>
+
+ it means that it will not be able to recognize and parse this odd syntax.
+ Therefore, we should add a special case function that will handle this token.
+
+ This function should generate the proper expression form of the expression
+ using GDB's internal expression mechanism (e.g., `write_exp_elt_opcode'
+ and so on). It should also return 1 if the parsing was successful, or zero
+ if the token was not recognized as a special token (in this case, returning
+ zero means that the special parser is deferring the parsing to the generic
+ parser), and should advance the buffer pointer (p->arg). */
+
+extern int gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p);
+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);
+
/* 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 5831172..956734a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -792,6 +792,101 @@ M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
# Get architecture-specific system calls information from registers.
M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+# SystemTap related fields and functions.
+
+# Prefix used to mark an integer constant on the architecture's assembly
+# For example, on x86 integer constants are written as:
+#
+# \$10 ;; integer constant 10
+#
+# in this case, this prefix would be the character \`\$\'.
+v:const char *:stap_integer_prefix:::0:0::0:gdbarch->stap_integer_prefix
+
+# Suffix used to mark an integer constant on the architecture's assembly.
+v:const char *:stap_integer_suffix:::0:0::0:gdbarch->stap_integer_suffix
+
+# Prefix used to mark a register name on the architecture's assembly.
+# For example, on x86 the register name is written as:
+#
+# \%eax ;; register eax
+#
+# in this case, this prefix would be the character \`\%\'.
+v:const char *:stap_register_prefix:::0:0::0:gdbarch->stap_register_prefix
+
+# Suffix used to mark a register name on the architecture's assembly
+v:const char *:stap_register_suffix:::0:0::0:gdbarch->stap_register_suffix
+
+# Prefix used to mark a register indirection on the architecture's assembly.
+# For example, on x86 the register indirection is written as:
+#
+# \(\%eax\) ;; indirecting eax
+#
+# in this case, this prefix would be the charater \`\(\'.
+#
+# Please note that we use the indirection prefix also for register
+# displacement, e.g., \`4\(\%eax\)\' on x86.
+v:const char *:stap_register_indirection_prefix:::0:0::0:gdbarch->stap_register_indirection_prefix
+
+# Suffix used to mark a register indirection on the architecture's assembly.
+# For example, on x86 the register indirection is written as:
+#
+# \(\%eax\) ;; indirecting eax
+#
+# in this case, this prefix would be the charater \`\)\'.
+#
+# Please note that we use the indirection suffix also for register
+# displacement, e.g., \`4\(\%eax\)\' on x86.
+v:const char *:stap_register_indirection_suffix:::0:0::0:gdbarch->stap_register_indirection_suffix
+
+# Prefix used to name a register using GDB's nomenclature.
+#
+# For example, on PPC a register is represented by a number in the assembly
+# language (e.g., \`10\' is the 10th general-purpose register). However,
+# inside GDB this same register has an \`r\' appended to its name, so the 10th
+# register would be represented as \`r10\' internally.
+v:const char *:stap_gdb_register_prefix:::0:0::0:gdbarch->stap_gdb_register_prefix
+
+# Suffix used to name a register using GDB's nomenclature.
+v:const char *:stap_gdb_register_suffix:::0:0::0:gdbarch->stap_gdb_register_suffix
+
+# Check if S is a single operand.
+#
+# Single operands can be:
+# \- Literal integers, e.g. \`\$10\' on x86
+# \- Register access, e.g. \`\%eax\' on x86
+# \- Register indirection, e.g. \`\(\%eax\)\' on x86
+# \- Register displacement, e.g. \`4\(\%eax\)\' on x86
+#
+# This function should check for these patterns on the string
+# and return 1 if some were found, or zero otherwise. Please try to match
+# as much info as you can from the string, i.e., if you have to match
+# something like \`\(\%\', do not match just the \`\(\'.
+M:int:stap_is_single_operand:const char *s:s
+
+# Function used to handle a "special case" in the parser.
+#
+# A "special case" is considered to be an unknown token, i.e., a token
+# that the parser does not know how to parse. A good example of special
+# case would be ARM's register displacement syntax:
+#
+# [R0, #4] ;; displacing R0 by 4
+#
+# Since the parser assumes that a register displacement is of the form:
+#
+# <number> <indirection_prefix> <register_name> <indirection_suffix>
+#
+# it means that it will not be able to recognize and parse this odd syntax.
+# Therefore, we should add a special case function that will handle this token.
+#
+# This function should generate the proper expression form of the expression
+# using GDB\'s internal expression mechanism (e.g., \`write_exp_elt_opcode\'
+# and so on). It should also return 1 if the parsing was successful, or zero
+# if the token was not recognized as a special token (in this case, returning
+# zero means that the special parser is deferring the parsing to the generic
+# parser), and should advance the buffer pointer (p->arg).
+M:int:stap_parse_special_token:struct stap_parse_info *p:p
+
+
# 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
@@ -954,6 +1049,7 @@ struct core_regset_section;
struct syscall;
struct agent_expr;
struct axs_value;
+struct stap_parse_info;
/* The architecture associated with the connection to the target.
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index bee4a6d..533b451 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -965,6 +965,15 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
i386_linux_get_syscall_number);
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+
+ /* SystemTap variables and functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "$");
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch, i386_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ i386_stap_parse_special_token);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index d18aa99..9eaa772 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -58,8 +58,14 @@
#include "features/i386/i386-avx.c"
#include "features/i386/i386-mmx.c"
+#include "stap-probe.h"
#include "ax.h"
#include "ax-gdb.h"
+#include "user-regs.h"
+#include "cli/cli-utils.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include <ctype.h>
/* Register names. */
@@ -7251,6 +7257,312 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
return valid_p;
}
+int
+i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == '$' /* Literal number. */
+ || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement. */
+ || (*s == '(' && s[1] == '%') /* Register indirection. */
+ || (*s == '%' && isalpha (s[1]))); /* Register access. */
+}
+
+int
+i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ const char *s = p->arg;
+
+ /* In order to parse special tokens, we use a state-machine that go
+ through every known token and try to get a match. */
+ enum
+ {
+ TRIPLET,
+ THREE_ARG_DISPLACEMENT,
+ DONE
+ } current_state;
+
+ current_state = TRIPLET;
+
+ /* The special tokens to be parsed here are:
+
+ - `register base + (register index * size) + offset', as represented
+ in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
+
+ - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
+ `*(-8 + 3 - 1 + (void *) $eax)'. */
+
+ while (current_state != DONE)
+ {
+ const char *s = p->arg;
+
+ switch (current_state)
+ {
+ case TRIPLET:
+ {
+ if (isdigit (*s) || *s == '-' || *s == '+')
+ {
+ int got_minus[3];
+ int i;
+ long displacements[3];
+ const char *start;
+ char *regname;
+ int len;
+ struct stoken str;
+
+ got_minus[0] = 0;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ got_minus[0] = 1;
+ }
+
+ displacements[0] = strtol (s, (char **) &s, 10);
+
+ if (*s != '+' && *s != '-')
+ /* We are not dealing with a triplet. */
+ break;
+
+ got_minus[1] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[1] = 1;
+ }
+
+ displacements[1] = strtol (s, (char **) &s, 10);
+
+ if (*s != '+' && *s != '-')
+ /* We are not dealing with a triplet. */
+ break;
+
+ got_minus[2] = 0;
+ if (*s == '+')
+ ++s;
+ else
+ {
+ ++s;
+ got_minus[2] = 1;
+ }
+
+ displacements[2] = strtol (s, (char **) &s, 10);
+
+ if (*s != '(' || s[1] != '%')
+ break;
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ if (*s++ != ')')
+ break;
+
+ len = s - start;
+ regname = alloca (len + 1);
+
+ strncpy (regname, start, len);
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ regname, len) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ regname, p->saved_arg);
+
+ for (i = 0; i < 3; i++)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacements[i]);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus[i])
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = s;
+
+ return 1;
+ }
+ break;
+ }
+ case THREE_ARG_DISPLACEMENT:
+ {
+ if (isdigit (*s) || *s == '(' || *s == '-' || *s == '+')
+ {
+ int offset_minus = 0;
+ long offset = 0;
+ int size_minus = 0;
+ long size = 0;
+ const char *start;
+ char *base;
+ int len_base;
+ char *index;
+ int len_index;
+ struct stoken base_token, index_token;
+
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ offset_minus = 1;
+ }
+
+ if (offset_minus && !isdigit (*s))
+ break;
+
+ if (isdigit (*s))
+ offset = strtol (s, (char **) &s, 10);
+
+ if (*s != '(' || s[1] != '%')
+ break;
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ if (*s != ',' || s[1] != '%')
+ break;
+
+ len_base = s - start;
+ base = alloca (len_base + 1);
+ strncpy (base, start, len_base);
+ base[len_base] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ base, len_base) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ base, p->saved_arg);
+
+ s += 2;
+ start = s;
+
+ while (isalnum (*s))
+ ++s;
+
+ len_index = s - start;
+ index = alloca (len_index + 1);
+ strncpy (index, start, len_index);
+ index[len_index] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch,
+ index, len_index) == -1)
+ error (_("Invalid register name `%s' "
+ "on expression `%s'."),
+ index, p->saved_arg);
+
+ if (*s != ',' && *s != ')')
+ break;
+
+ if (*s == ',')
+ {
+ ++s;
+ if (*s == '+')
+ ++s;
+ else if (*s == '-')
+ {
+ ++s;
+ size_minus = 1;
+ }
+
+ size = strtol (s, (char **) &s, 10);
+
+ if (*s != ')')
+ break;
+ }
+
+ ++s;
+
+ if (offset)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (offset);
+ write_exp_elt_opcode (OP_LONG);
+ if (offset_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ write_exp_elt_opcode (OP_REGISTER);
+ base_token.ptr = base;
+ base_token.length = len_base;
+ write_exp_string (base_token);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (offset)
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ index_token.ptr = index;
+ index_token.length = len_index;
+ write_exp_string (index_token);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (size)
+ {
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type
+ (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (size);
+ write_exp_elt_opcode (OP_LONG);
+ if (size_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ write_exp_elt_opcode (BINOP_MUL);
+ }
+
+ write_exp_elt_opcode (BINOP_ADD);
+
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+
+ p->arg = s;
+
+ return 1;
+ }
+ break;
+ }
+ }
+
+ /* Advancing to the next state. */
+ ++current_state;
+ }
+
+ return 0;
+}
+
\f
static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 870054f..9ffbe44 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -379,6 +379,15 @@ extern void i386_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
extern int i386_process_record (struct gdbarch *gdbarch,
struct regcache *regcache, CORE_ADDR addr);
+
+/* SystemTap related functions. */
+
+extern int i386_stap_is_single_operand (struct gdbarch *gdbarch,
+ const char *s);
+
+extern int i386_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p);
+
\f
/* Functions and variables exported from i386bsd-tdep.c. */
diff --git a/gdb/machoread.c b/gdb/machoread.c
index 88ce612..4e83874 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -1032,6 +1032,7 @@ static const struct sym_fns macho_sym_fns = {
default_symfile_segments, /* Get segment information from a file. */
NULL,
macho_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index 5790730..23ceece 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -401,6 +401,7 @@ static const struct sym_fns ecoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index e29b3a7..72deabf 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -795,6 +795,11 @@ objfile_relocate1 (struct objfile *objfile,
obj_section_addr (s));
}
+ /* Relocating SystemTap probes. */
+ if (objfile->sf && objfile->sf->sym_probe_fns)
+ objfile->sf->sym_probe_fns->sym_relocate_probe (objfile,
+ new_offsets, delta);
+
/* Data changed. */
return 1;
}
diff --git a/gdb/parse.c b/gdb/parse.c
index 32a3bd6..1ebfd2e 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -113,8 +113,6 @@ show_parserdebug (struct ui_file *file, int from_tty,
static void free_funcalls (void *ignore);
-static int prefixify_expression (struct expression *);
-
static int prefixify_subexp (struct expression *, struct expression *, int,
int);
@@ -182,13 +180,9 @@ free_funcalls (void *ignore)
/* This page contains the functions for adding data to the struct expression
being constructed. */
-/* Helper function to initialize the expout, expout_size, expout_ptr
- trio before it is used to store expression elements created during
- the parsing of an expression. INITIAL_SIZE is the initial size of
- the expout array. LANG is the language used to parse the expression.
- And GDBARCH is the gdbarch to use during parsing. */
+/* See definition in parser-defs.h. */
-static void
+void
initialize_expout (int initial_size, const struct language_defn *lang,
struct gdbarch *gdbarch)
{
@@ -200,11 +194,9 @@ initialize_expout (int initial_size, const struct language_defn *lang,
expout->gdbarch = gdbarch;
}
-/* Helper function that frees any unsed space in the expout array.
- It is generally used when the parser has just been parsed and
- created. */
+/* See definition in parser-defs.h. */
-static void
+void
reallocate_expout (void)
{
/* Record the actual number of expression elements, and then
@@ -811,7 +803,7 @@ copy_name (struct stoken token)
return the index of the subexpression which is the left-hand-side
of the struct operation at EXPOUT_LAST_STRUCT. */
-static int
+int
prefixify_expression (struct expression *expr)
{
int len = sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);
diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h
index 16b40ac..442ca03 100644
--- a/gdb/parser-defs.h
+++ b/gdb/parser-defs.h
@@ -130,6 +130,23 @@ union type_stack_elt
extern union type_stack_elt *type_stack;
extern int type_stack_depth, type_stack_size;
+/* Helper function to initialize the expout, expout_size, expout_ptr
+ trio before it is used to store expression elements created during
+ the parsing of an expression. INITIAL_SIZE is the initial size of
+ the expout array. LANG is the language used to parse the expression.
+ And GDBARCH is the gdbarch to use during parsing. */
+
+extern void initialize_expout (int, const struct language_defn *,
+ struct gdbarch *);
+
+/* Helper function that frees any unsed space in the expout array.
+ It is generally used when the parser has just been parsed and
+ created. */
+
+extern void reallocate_expout (void);
+
+extern int prefixify_expression (struct expression *expr);
+
extern void write_exp_elt_opcode (enum exp_opcode);
extern void write_exp_elt_sym (struct symbol *);
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index b94dea2..2edc4fd 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -66,6 +66,14 @@
#include "features/rs6000/powerpc-isa205-vsx64l.c"
#include "features/rs6000/powerpc-e500l.c"
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "cli/cli-utils.h"
+#include "parser-defs.h"
+#include "user-regs.h"
+#include <ctype.h>
+
/* Shared library operations for PowerPC-Linux. */
static struct target_so_ops powerpc_so_ops;
@@ -1276,6 +1284,65 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
}
}
+static int
+ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return (*s == 'i' /* Literal number. */
+ || (isdigit (*s) && s[1] == '('
+ && isdigit (s[2])) /* Displacement. */
+ || (*s == '(' && isdigit (s[1])) /* Register indirection. */
+ || isdigit (*s)); /* Register value. */
+}
+
+static int
+ppc_stap_parse_special_token (struct gdbarch *gdbarch,
+ struct stap_parse_info *p)
+{
+ if (isdigit (*p->arg))
+ {
+ /* This temporary pointer is needed because we have to do a lookahead.
+ We could be dealing with a register displacement, and in such case
+ we would not need to do anything. */
+ const char *s = p->arg;
+ char *regname;
+ int len;
+ struct stoken str;
+
+ while (isdigit (*s))
+ ++s;
+
+ if (*s == '(')
+ /* It is a register displacement indeed. Returning 0 means we are
+ deferring the treatment of this case to the generic parser. */
+ return 0;
+
+ len = s - p->arg;
+ regname = alloca (len + 2);
+ regname[0] = 'r';
+
+ strncpy (regname + 1, p->arg, len);
+ ++len;
+ regname[len] = '\0';
+
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ p->arg = s;
+ }
+ else
+ /* All the other tokens should be handled correctly by the generic
+ parser. */
+ return 0;
+
+ return 1;
+}
/* Cell/B.E. active SPE context tracking support. */
@@ -1593,6 +1660,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Get the syscall number from the arch's register. */
set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+ /* SystemTap functions. */
+ set_gdbarch_stap_integer_prefix (gdbarch, "i");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
+ set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand);
+ set_gdbarch_stap_parse_special_token (gdbarch,
+ ppc_stap_parse_special_token);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index ac0c526..661d90c 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -55,6 +55,12 @@
#include "features/s390x-linux64v1.c"
#include "features/s390x-linux64v2.c"
+#include "stap-probe.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "user-regs.h"
+#include "cli/cli-utils.h"
+#include <ctype.h>
/* The tdep structure. */
@@ -2953,6 +2959,15 @@ s390_address_class_name_to_type_flags (struct gdbarch *gdbarch,
return 0;
}
+static int
+s390_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
+{
+ return ((isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement
+ or indirection. */
+ || *s == '%' /* Register access. */
+ || isdigit (*s)); /* Literal number. */
+}
+
/* Set up gdbarch struct. */
static struct gdbarch *
@@ -3283,6 +3298,12 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+ /* SystemTap functions. */
+ set_gdbarch_stap_register_prefix (gdbarch, "%");
+ set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
+ set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
+ set_gdbarch_stap_is_single_operand (gdbarch, s390_stap_is_single_operand);
+
return gdbarch;
}
diff --git a/gdb/somread.c b/gdb/somread.c
index e621cba..19a15e2 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -427,6 +427,7 @@ static const struct sym_fns som_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
NULL,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_get_probes */
&psym_functions
};
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
new file mode 100644
index 0000000..c1e60d0
--- /dev/null
+++ b/gdb/stap-probe.c
@@ -0,0 +1,1689 @@
+/* SystemTap probe support for GDB.
+
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "stap-probe.h"
+#include "vec.h"
+#include "ui-out.h"
+#include "gdb_regex.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "filenames.h"
+#include "value.h"
+#include "exceptions.h"
+#include "ax.h"
+#include "ax-gdb.h"
+#include "complaints.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
+#include "user-regs.h"
+#include "parser-defs.h"
+#include "language.h"
+
+#include <ctype.h>
+
+/* The maximum number of arguments that a probe can have,
+ as defined in <sys/sdt.h>. */
+
+#define STAP_MAX_ARGS 12
+
+/* Should we display debug information for the probe's argument expression
+ parsing? */
+
+static int stap_expression_debug = 0;
+
+/* The various possibilities of bitness defined for a probe's argument.
+
+ The relationship is:
+
+ - STAP_ARG_BITNESS_UNDEFINED: The user hasn't specified the bitness.
+ - STAP_ARG_BITNESS_32BIT_UNSIGNED: argument string starts with `4@'.
+ - STAP_ARG_BITNESS_32BIT_SIGNED: argument string starts with `-4@'.
+ - STAP_ARG_BITNESS_64BIT_UNSIGNED: argument string starts with `8@'.
+ - STAP_ARG_BITNESS_64BIT_SIGNED: argument string starts with `-8@'. */
+
+enum stap_arg_bitness
+{
+ STAP_ARG_BITNESS_UNDEFINED,
+ STAP_ARG_BITNESS_32BIT_UNSIGNED,
+ STAP_ARG_BITNESS_32BIT_SIGNED,
+ STAP_ARG_BITNESS_64BIT_UNSIGNED,
+ STAP_ARG_BITNESS_64BIT_SIGNED,
+};
+
+/* The following structure represents a single argument for the probe. */
+
+struct stap_probe_arg
+{
+ /* The bitness of this argument. */
+ enum stap_arg_bitness bitness;
+
+ /* The corresponding `struct type *' to the bitness. */
+ struct type *atype;
+
+ /* The argument converted to an internal GDB expression. */
+ struct expression *aexpr;
+};
+
+/* Structure that holds information about all arguments of a probe. */
+
+struct stap_args_info
+{
+ /* The number of valid parsed arguments. */
+ int n_args;
+
+ /* The probe to which these arguments belong. */
+ struct stap_probe *probe;
+
+ /* Information about each argument. This is an array of `stap_probe_arg',
+ with each entry representing one argument. */
+ struct stap_probe_arg *args;
+};
+
+/* When parsing the arguments, we have to establish different precedences
+ for the various kinds of asm operators. This enumeration represents those
+ precedences.
+
+ This logic behind this is available at
+ <http://sourceware.org/binutils/docs/as/Infix-Ops.html#Infix-Ops>, or using
+ the command "info '(as)Infix Ops'". */
+
+enum stap_operand_prec
+{
+ /* Lowest precedence, used for non-recognized operands or for the beginning
+ of the parsing process. */
+ STAP_OPERAND_PREC_NONE = 0,
+
+ /* Precedence of logical OR. */
+ STAP_OPERAND_PREC_LOGICAL_OR,
+
+ /* Precedence of logical AND. */
+ STAP_OPERAND_PREC_LOGICAL_AND,
+
+ /* Precedence of additive (plus, minus) and comparative (equal, less,
+ greater-than, etc) operands. */
+ STAP_OPERAND_PREC_ADD_CMP,
+
+ /* Precedence of bitwise operands (bitwise OR, XOR, bitwise AND,
+ logical NOT). */
+ STAP_OPERAND_PREC_BITWISE,
+
+ /* Precedence of multiplicative operands (multiplication, division,
+ remainder, left shift and right shift). */
+ STAP_OPERAND_PREC_MUL
+};
+
+/* This dummy variable is used when parsing a probe's argument fails.
+ In this case, the number of arguments for this probe is zero, so that's
+ why this variable is useful. */
+
+static struct stap_args_info dummy_stap_args_info =
+ { 0, NULL, NULL };
+
+static void stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
+ enum stap_operand_prec prec);
+
+static void stap_parse_argument_conditionally (struct stap_parse_info *p);
+
+/* Returns 1 if *S is an operator, zero otherwise. */
+
+static int stap_is_operator (char op);
+
+static void
+show_stapexpressiondebug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("SystemTap Probe expression debugging is %s.\n"),
+ value);
+}
+
+/* Returns the operator precedence level of OP, or STAP_OPERAND_PREC_NONE
+ if the operator code was not recognized. */
+
+static enum stap_operand_prec
+stap_get_operator_prec (enum exp_opcode op)
+{
+ switch (op)
+ {
+ case BINOP_LOGICAL_OR:
+ return STAP_OPERAND_PREC_LOGICAL_OR;
+
+ case BINOP_LOGICAL_AND:
+ return STAP_OPERAND_PREC_LOGICAL_AND;
+
+ case BINOP_ADD:
+ case BINOP_SUB:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_LEQ:
+ case BINOP_GTR:
+ case BINOP_GEQ:
+ return STAP_OPERAND_PREC_ADD_CMP;
+
+ case BINOP_BITWISE_IOR:
+ case BINOP_BITWISE_AND:
+ case BINOP_BITWISE_XOR:
+ case UNOP_LOGICAL_NOT:
+ return STAP_OPERAND_PREC_BITWISE;
+
+ case BINOP_MUL:
+ case BINOP_DIV:
+ case BINOP_REM:
+ case BINOP_LSH:
+ case BINOP_RSH:
+ return STAP_OPERAND_PREC_MUL;
+
+ default:
+ return STAP_OPERAND_PREC_NONE;
+ }
+}
+
+/* Given S, read the operator in it and fills the OP pointer with its code.
+ Return 1 on success, zero if the operator was not recognized. */
+
+static int
+stap_get_opcode (const char **s, enum exp_opcode *op)
+{
+ const char c = **s;
+ int ret = 1;
+
+ *s += 1;
+
+ switch (c)
+ {
+ case '*':
+ *op = BINOP_MUL;
+ break;
+
+ case '/':
+ *op = BINOP_DIV;
+ break;
+
+ case '%':
+ *op = BINOP_REM;
+ break;
+
+ case '<':
+ *op = BINOP_LESS;
+ if (**s == '<')
+ {
+ *s += 1;
+ *op = BINOP_LSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_LEQ;
+ }
+ else if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_NOTEQUAL;
+ }
+ break;
+
+ case '>':
+ *op = BINOP_GTR;
+ if (**s == '>')
+ {
+ *s += 1;
+ *op = BINOP_RSH;
+ }
+ else if (**s == '=')
+ {
+ *s += 1;
+ *op = BINOP_GEQ;
+ }
+ break;
+
+ case '|':
+ *op = BINOP_BITWISE_IOR;
+ if (**s == '|')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_OR;
+ }
+ break;
+
+ case '&':
+ *op = BINOP_BITWISE_AND;
+ if (**s == '&')
+ {
+ *s += 1;
+ *op = BINOP_LOGICAL_AND;
+ }
+ break;
+
+ case '^':
+ *op = BINOP_BITWISE_XOR;
+ break;
+
+ case '!':
+ *op = UNOP_LOGICAL_NOT;
+ break;
+
+ case '+':
+ *op = BINOP_ADD;
+ break;
+
+ case '-':
+ *op = BINOP_SUB;
+ break;
+
+ case '=':
+ if (**s != '=')
+ {
+ ret = 0;
+ break;
+ }
+ *op = BINOP_EQUAL;
+ break;
+
+ default:
+ /* We didn't find any operator. */
+ *s -= 1;
+ return 0;
+ }
+
+ return ret;
+}
+
+/* Given the bitness of the argument, represented by B, return the
+ corresponding `struct type *'. */
+
+static struct type *
+stap_get_expected_argument_type (struct gdbarch *gdbarch,
+ enum stap_arg_bitness b)
+{
+ switch (b)
+ {
+ case STAP_ARG_BITNESS_UNDEFINED:
+ if (gdbarch_addr_bit (gdbarch) == 32)
+ return builtin_type (gdbarch)->builtin_uint32;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+
+ case STAP_ARG_BITNESS_32BIT_SIGNED:
+ return builtin_type (gdbarch)->builtin_int32;
+
+ case STAP_ARG_BITNESS_32BIT_UNSIGNED:
+ return builtin_type (gdbarch)->builtin_uint32;
+
+ case STAP_ARG_BITNESS_64BIT_SIGNED:
+ return builtin_type (gdbarch)->builtin_int64;
+
+ case STAP_ARG_BITNESS_64BIT_UNSIGNED:
+ return builtin_type (gdbarch)->builtin_uint64;
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Undefined bitness for probe."));
+ break;
+ }
+}
+
+static void
+stap_parse_register_operand (struct stap_parse_info *p)
+{
+ /* Simple flag to indicate whether we have seen a minus signal before
+ certain number. */
+ int got_minus = 0;
+ /* Flags to indicate whether this register access is being displaced and/or
+ indirected. */
+ int disp_p = 0, indirect_p = 0;
+ struct gdbarch *gdbarch = p->gdbarch;
+ /* Needed to generate the register name as a part of an expression. */
+ struct stoken str;
+ /* Variables used to extract the register name from the probe's
+ argument. */
+ const char *start;
+ char *regname;
+ int len;
+
+ /* Prefixes for the parser. */
+ const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
+ const char *reg_ind_prefix
+ = gdbarch_stap_register_indirection_prefix (gdbarch);
+ const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
+ int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
+ int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
+ int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0;
+
+ /* Suffixes for the parser. */
+ const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
+ const char *reg_ind_suffix
+ = gdbarch_stap_register_indirection_suffix (gdbarch);
+ const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
+ int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
+ int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
+ int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0;
+
+ /* Checking for a displacement argument. */
+ if (*p->arg == '+')
+ /* If it's a plus sign, we don't need to do anything, just advance the
+ pointer. */
+ ++p->arg;
+
+ if (*p->arg == '-')
+ {
+ got_minus = 1;
+ ++p->arg;
+ }
+
+ if (isdigit (*p->arg))
+ {
+ /* The value of the displacement. */
+ long displacement;
+
+ disp_p = 1;
+ displacement = strtol (p->arg, (char **) &p->arg, 10);
+
+ /* Generating the expression for the displacement. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (displacement);
+ write_exp_elt_opcode (OP_LONG);
+ if (got_minus)
+ write_exp_elt_opcode (UNOP_NEG);
+ }
+
+ /* Getting rid of register indirection prefix. */
+ if (reg_ind_prefix
+ && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0)
+ {
+ indirect_p = 1;
+ p->arg += reg_ind_prefix_len;
+ }
+
+ if (disp_p && !indirect_p)
+ error (_("Invalid register displacement syntax on expression `%s'."),
+ p->saved_arg);
+
+ /* Getting rid of register prefix. */
+ if (reg_prefix && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
+ p->arg += reg_prefix_len;
+
+ /* Now we should have only the register name. Let's extract it and get
+ the associated number. */
+ start = p->arg;
+
+ /* We assume the register name is composed by letters and numbers. */
+ while (isalnum (*p->arg))
+ ++p->arg;
+
+ len = p->arg - start;
+
+ regname = alloca (len + gdb_reg_prefix_len + gdb_reg_suffix_len + 1);
+ regname[0] = '\0';
+
+ /* We only add the GDB's register prefix/suffix if we are dealing with
+ a numeric register. */
+ if (gdb_reg_prefix && isdigit (*start))
+ {
+ strncpy (regname, gdb_reg_prefix, gdb_reg_prefix_len);
+ strncpy (regname + gdb_reg_prefix_len, start, len);
+
+ if (gdb_reg_suffix)
+ strncpy (regname + gdb_reg_prefix_len + len,
+ gdb_reg_suffix, gdb_reg_suffix_len);
+
+ len += gdb_reg_prefix_len + gdb_reg_suffix_len;
+ }
+ else
+ strncpy (regname, start, len);
+
+ regname[len] = '\0';
+ /* Is this a valid register name? */
+ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
+ error (_("Invalid register name `%s' on expression `%s'."),
+ regname, p->saved_arg);
+
+ write_exp_elt_opcode (OP_REGISTER);
+ str.ptr = regname;
+ str.length = len;
+ write_exp_string (str);
+ write_exp_elt_opcode (OP_REGISTER);
+
+ if (indirect_p)
+ {
+ if (disp_p)
+ write_exp_elt_opcode (BINOP_ADD);
+
+ /* Casting to the expected type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (lookup_pointer_type (p->arg_type));
+ write_exp_elt_opcode (UNOP_CAST);
+
+ write_exp_elt_opcode (UNOP_IND);
+ }
+
+ /* Getting rid of the register name suffix. */
+ if (reg_suffix)
+ {
+ if (strncmp (p->arg, reg_suffix, reg_suffix_len) != 0)
+ error (_("Missing register name suffix `%s' on expression `%s'."),
+ reg_suffix, p->saved_arg);
+
+ p->arg += reg_suffix_len;
+ }
+
+ /* Getting rid of the register indirection suffix. */
+ if (indirect_p && reg_ind_suffix)
+ {
+ if (strncmp (p->arg, reg_ind_suffix, reg_ind_suffix_len) != 0)
+ error (_("Missing indirection suffix `%s' on expression `%s'."),
+ reg_ind_suffix, p->saved_arg);
+
+ p->arg += reg_ind_suffix_len;
+ }
+}
+
+static void
+stap_parse_single_operand (struct stap_parse_info *p)
+{
+ struct gdbarch *gdbarch = p->gdbarch;
+ /* Prefixes for the parser. */
+ const char *const_prefix = gdbarch_stap_integer_prefix (gdbarch);
+ const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
+ const char *reg_ind_prefix
+ = gdbarch_stap_register_indirection_prefix (gdbarch);
+ int const_prefix_len = const_prefix ? strlen (const_prefix) : 0;
+ int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
+ int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
+
+ /* Suffixes for the parser. */
+ const char *const_suffix = gdbarch_stap_integer_suffix (gdbarch);
+ const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
+ const char *reg_ind_suffix
+ = gdbarch_stap_register_indirection_suffix (gdbarch);
+ int const_suffix_len = const_suffix ? strlen (const_suffix) : 0;
+ int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
+ int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
+
+ /* We first try to parse this token as a "special token". */
+ if (gdbarch_stap_parse_special_token_p (gdbarch))
+ {
+ int ret = gdbarch_stap_parse_special_token (gdbarch, p);
+
+ if (ret)
+ /* If the return value of the above function is not zero,
+ it means it successfully parsed the special token.
+
+ If it is NULL, we try to parse it using our method. */
+ return;
+ }
+
+ if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+')
+ {
+ char c = *p->arg;
+ /* We use this variable to do a lookahead. */
+ const char *tmp = p->arg;
+
+ ++tmp;
+
+ /* This is an unary operation. Here is a list of allowed tokens
+ here:
+
+ - numeric literal;
+ - number (from register displacement)
+ - subexpression (beginning with `(')
+
+ We handle the register displacement here, and the other cases
+ recursively. */
+ if (isdigit (*tmp))
+ {
+ int number = strtol (tmp, (char **) &tmp, 10);
+
+ if (p->inside_paren_p)
+ tmp = skip_spaces_const (tmp);
+ if (!reg_ind_prefix
+ || strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
+ goto not_displacement;
+
+ /* If we are here, it means it is a displacement. The only
+ operations allowed here are `-' and `+'. */
+ if (c == '~')
+ error (_("Invalid operator `%c' for register displacement "
+ "on expression `%s'."), c, p->saved_arg);
+
+ stap_parse_register_operand (p);
+ }
+ else
+not_displacement:
+ {
+ p->arg = tmp;
+ stap_parse_argument_conditionally (p);
+ if (c == '-')
+ write_exp_elt_opcode (UNOP_NEG);
+ else if (c == '~')
+ write_exp_elt_opcode (UNOP_COMPLEMENT);
+ }
+ }
+ else if (isdigit (*p->arg))
+ {
+ /* A temporary variable, needed for lookahead. */
+ const char *tmp = p->arg;
+ long number;
+
+ /* We can be dealing with a numeric constant (if `const_prefix' is
+ NULL), or with a register displacement. */
+ number = strtol (tmp, (char **) &tmp, 10);
+
+ if (p->inside_paren_p)
+ tmp = skip_spaces_const (tmp);
+ if (!const_prefix && reg_ind_prefix
+ && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
+ {
+ /* We are dealing with a numeric constant. */
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (number);
+ write_exp_elt_opcode (OP_LONG);
+
+ p->arg = tmp;
+
+ if (const_suffix)
+ {
+ if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
+ p->arg += const_suffix_len;
+ else
+ error (_("Invalid constant suffix on expression `%s'."),
+ p->saved_arg);
+ }
+ }
+ else if (reg_ind_prefix
+ && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) == 0)
+ stap_parse_register_operand (p);
+ else
+ error (_("Unknown numeric token on expression `%s'."),
+ p->saved_arg);
+ }
+ else if (const_prefix
+ && strncmp (p->arg, const_prefix, const_prefix_len) == 0)
+ {
+ /* We are dealing with a numeric constant. */
+ long number;
+
+ p->arg += const_prefix_len;
+ number = strtol (p->arg, (char **) &p->arg, 10);
+
+ write_exp_elt_opcode (OP_LONG);
+ write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
+ write_exp_elt_longcst (number);
+ write_exp_elt_opcode (OP_LONG);
+
+ if (const_suffix)
+ {
+ if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
+ p->arg += const_suffix_len;
+ else
+ error (_("Invalid constant suffix on expression `%s'."),
+ p->saved_arg);
+ }
+ }
+ else if ((reg_prefix
+ && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
+ || (reg_ind_prefix
+ && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0))
+ stap_parse_register_operand (p);
+ else
+ error (_("Operator `%c' not recognized on expression `%s'."),
+ *p->arg, p->saved_arg);
+}
+
+static void
+stap_parse_argument_conditionally (struct stap_parse_info *p)
+{
+ if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */
+ || isdigit (*p->arg)
+ || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
+ stap_parse_single_operand (p);
+ else if (*p->arg == '(')
+ {
+ /* We are dealing with a parenthesized operand. It means we
+ have to parse it as it was a separate expression, without
+ left-side or precedence. */
+ ++p->arg;
+ p->arg = skip_spaces_const (p->arg);
+ ++p->inside_paren_p;
+
+ stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
+
+ --p->inside_paren_p;
+ if (*p->arg != ')')
+ error (_("Missign close-paren on expression `%s'."),
+ p->saved_arg);
+
+ ++p->arg;
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+ }
+ else
+ error (_("Cannot parse expression `%s'."), p->saved_arg);
+}
+
+static void
+stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
+ enum stap_operand_prec prec)
+{
+ /* This is an operator-precedence parser.
+
+ We work with left- and right-sides of expressions, and
+ parse them depending on the precedence of the operators
+ we find. */
+
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+
+ if (!has_lhs)
+ /* We were called without a left-side, either because this is the
+ first call, or because we were called to parse a parenthesized
+ expression. It doesn't really matter; we have to parse the
+ left-side in order to continue the process. */
+ stap_parse_argument_conditionally (p);
+
+ /* Start to parse the right-side, and to "join" left and right sides
+ depending on the operation specified.
+
+ This loop shall continue until we run out of characters in the input,
+ or until we find a close-parenthesis, which means that we've reached
+ the end of a sub-expression. */
+ while (p->arg && *p->arg && *p->arg != ')' && !isspace (*p->arg))
+ {
+ const char *tmp_exp_buf;
+ enum exp_opcode opcode;
+ enum stap_operand_prec cur_prec;
+
+ if (!stap_is_operator (*p->arg))
+ error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
+ p->saved_arg);
+
+ /* We have to save the current value of the expression buffer because
+ the `stap_get_opcode' modifies it in order to get the current
+ operator. If this operator's precedence is lower than PREC, we
+ should return and not advance the expression buffer pointer. */
+ tmp_exp_buf = p->arg;
+ stap_get_opcode (&tmp_exp_buf, &opcode);
+
+ cur_prec = stap_get_operator_prec (opcode);
+ if (cur_prec < prec)
+ /* If the precedence of the operator that we are seeing now is
+ lower than the precedence of the first operator seen before
+ this parsing process began, it means we should stop parsing
+ and return. */
+ break;
+
+ p->arg = tmp_exp_buf;
+ if (p->inside_paren_p)
+ p->arg = skip_spaces_const (p->arg);
+
+ /* Parse the right-side of the expression. */
+ stap_parse_argument_conditionally (p);
+
+ /* While we still have operators, try to parse another
+ right-side, but using the current right-side as a left-side. */
+ while (*p->arg && stap_is_operator (*p->arg))
+ {
+ enum exp_opcode lookahead_opcode;
+ enum stap_operand_prec lookahead_prec;
+
+ /* Saving the current expression buffer position. The explanation
+ is the same as above. */
+ tmp_exp_buf = p->arg;
+ stap_get_opcode (&tmp_exp_buf, &lookahead_opcode);
+ lookahead_prec = stap_get_operator_prec (lookahead_opcode);
+
+ if (lookahead_prec <= prec)
+ /* If we are dealing with an operator whose precedence is lower
+ than the first one, just abandon the attempt. */
+ break;
+
+ /* Parse the right-side of the expression, but since we already
+ have a left-side at this point, set `has_lhs' to 1. */
+ stap_parse_argument_1 (p, 1, lookahead_prec);
+ }
+
+ write_exp_elt_opcode (opcode);
+ }
+}
+
+/* Parse a probe's argument.
+
+ Assuming that:
+
+ LP = literal integer prefix
+ LS = literal integer suffix
+
+ RP = register prefix
+ RS = register suffix
+
+ RIP = register indirection prefix
+ RIS = register indirection suffix
+
+ This routine assumes that arguments' tokens are of the form:
+
+ - [LP] NUMBER [LS]
+ - [RP] REGISTER [RS]
+ - [RIP] [RP] REGISTER [RS] [RIS]
+ - If we find a number without LP, we try to parse it as a literal integer
+ constant (if LP == NULL), or as a register displacement.
+ - We count parenthesis, and only skip whitespaces if we are inside them.
+ - If we find an operator, we skip it.
+
+ This function can also call a special function that will try to match
+ unknown tokens. It will return 1 if the argument has been parsed
+ successfully, or zero otherwise. */
+
+static int
+stap_parse_argument (const char **arg, struct type *atype,
+ struct gdbarch *gdbarch)
+{
+ struct stap_parse_info p;
+ volatile struct gdb_exception e;
+
+ /* We need to initialize the expression buffer, in order to begin
+ our parsing efforts. The language here does not matter, since we
+ are using our own parser. */
+ initialize_expout (10, current_language, gdbarch);
+
+ p.saved_arg = *arg;
+ p.arg = *arg;
+ p.arg_type = atype;
+ p.gdbarch = gdbarch;
+ p.inside_paren_p = 0;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
+ }
+ if (e.reason < 0)
+ {
+ xfree (expout);
+ return 0;
+ }
+
+ gdb_assert (p.inside_paren_p == 0);
+
+ /* Casting the final expression to the appropriate type. */
+ write_exp_elt_opcode (UNOP_CAST);
+ write_exp_elt_type (atype);
+ write_exp_elt_opcode (UNOP_CAST);
+
+ reallocate_expout ();
+
+ p.arg = skip_spaces_const (p.arg);
+ *arg = p.arg;
+
+ return 1;
+}
+
+/* Helper function which is responsible for freeing the space allocated to
+ hold information about a probe's arguments. */
+
+static void
+stap_free_args_info (void *args_info_ptr)
+{
+ struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
+ int i;
+
+ for (i = 0; i < a->n_args; i++)
+ xfree (a->args[i].aexpr);
+
+ xfree (a->args);
+ xfree (a);
+}
+
+/* Function which parses an argument string from PROBE, correctly splitting
+ the arguments and storing their information in properly ways.
+
+ Consider the following argument string (x86 syntax):
+
+ `4@%eax 4@$10'
+
+ We have two arguments, `%eax' and `$10', both with 32-bit unsigned bitness.
+ This function basically handles them, properly filling some structures with
+ this information. */
+
+static void
+stap_parse_probe_arguments (struct stap_probe *probe)
+{
+ struct stap_args_info *args_info;
+ struct cleanup *back_to;
+ const char *cur = probe->args;
+ int current_arg = -1;
+ /* This is a state-machine parser, which means we will always be
+ in a known state when parsing an argument. The state could be
+ either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
+ we are parsing the bitness-definition part (i.e., `4@'), or
+ `PARSE_ARG' if we are actually parsing the argument part. */
+ enum
+ {
+ NEW_ARG,
+ BITNESS,
+ PARSE_ARG,
+ } current_state;
+
+ /* For now, we assume everything is not going to work. */
+ probe->parsed_args = &dummy_stap_args_info;
+
+ if (!cur || !*cur || *cur == ':')
+ return;
+
+ args_info = xmalloc (sizeof (struct stap_args_info));
+ args_info->n_args = 0;
+ back_to = make_cleanup (stap_free_args_info, args_info);
+ args_info->args = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
+
+ /* Ok, let's start. */
+ current_state = NEW_ARG;
+
+ while (*cur)
+ {
+ switch (current_state)
+ {
+ case NEW_ARG:
+ ++current_arg;
+
+ if (current_arg >= STAP_MAX_ARGS)
+ {
+ complaint (&symfile_complaints,
+ _("probe `%s' has more arguments than the maximum "
+ "allowed"), probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+
+ current_state = BITNESS;
+ break;
+
+ case BITNESS:
+ {
+ enum stap_arg_bitness b;
+ int got_minus = 0;
+
+ /* We expect to find something like:
+
+ N@OP
+
+ Where `N' can be [+,-][4,8]. This is not mandatory, so
+ we check it here. If we don't find it, go to the next
+ state. */
+ if ((*cur == '-' && cur[1] && cur[2] != '@')
+ && cur[1] != '@')
+ {
+ current_state = PARSE_ARG;
+ args_info->args[current_arg].bitness
+ = STAP_ARG_BITNESS_UNDEFINED;
+ break;
+ }
+
+ if (*cur == '-')
+ {
+ /* Discard the `-'. */
+ ++cur;
+ got_minus = 1;
+ }
+
+ if (*cur == '4')
+ b = got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
+ : STAP_ARG_BITNESS_32BIT_UNSIGNED;
+ else if (*cur == '8')
+ b = got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
+ : STAP_ARG_BITNESS_64BIT_UNSIGNED;
+ else
+ {
+ /* We have an error, because we don't expect anything
+ except 4 and 8. */
+ complaint (&symfile_complaints,
+ _("unrecognized bitness `%c' for probe `%s'"),
+ *cur, probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+
+ args_info->args[current_arg].bitness = b;
+ args_info->args[current_arg].atype
+ = stap_get_expected_argument_type (probe->gdbarch, b);
+ /* Discard the number and the `@' sign. */
+ cur += 2;
+ /* Move on. */
+ current_state = PARSE_ARG;
+ }
+ break;
+
+ case PARSE_ARG:
+ {
+ if (!stap_parse_argument (&cur,
+ args_info->args[current_arg].atype,
+ probe->gdbarch))
+ {
+ /* We have tried to parse this argument, but it's
+ malformed. This is an error. */
+ complaint (&symfile_complaints,
+ _("malformed argument for probe `%s'"),
+ probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+
+ if (stap_expression_debug)
+ dump_raw_expression (expout, gdb_stdlog,
+ "before conversion to prefix form");
+
+ prefixify_expression (expout);
+
+ if (stap_expression_debug)
+ dump_prefix_expression (expout, gdb_stdlog);
+
+ args_info->args[current_arg].aexpr = expout;
+ expout = NULL;
+
+ ++args_info->n_args;
+ /* Start it over again. */
+ cur = skip_spaces_const (cur);
+ current_state = NEW_ARG;
+ }
+ break;
+ }
+
+ if (!*cur && current_state != NEW_ARG)
+ {
+ /* We reached the end of the argument string, but we're
+ still in the middle of the process of parsing an argument.
+ It means the argument string is malformed. */
+ complaint (&symfile_complaints,
+ _("malformed argument for probe `%s'"),
+ probe->name);
+ do_cleanups (back_to);
+ return;
+ }
+ }
+
+ args_info->args = xrealloc (args_info->args,
+ args_info->n_args
+ * sizeof (struct stap_probe_arg));
+ args_info->probe = probe;
+
+ probe->parsed_args = args_info;
+
+ discard_cleanups (back_to);
+}
+
+/* See definition in stap-probe.h. */
+
+int
+stap_get_probe_argument_count (struct stap_probe *probe)
+{
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments (probe);
+
+ return probe->parsed_args->n_args;
+}
+
+/* Return 1 if OP is a valid operator inside a probe argument, or zero
+ otherwise. */
+
+static int
+stap_is_operator (char op)
+{
+ return (op == '+' || op == '-' || op == '*' || op == '/'
+ || op == '>' || op == '<' || op == '!' || op == '^'
+ || op == '|' || op == '&' || op == '%' || op == '=');
+}
+
+/* See definition in stap-probe.h. */
+
+struct value *
+stap_evaluate_probe_argument (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct frame_info *frame,
+ int n)
+{
+ int pos = 0;
+
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments (probe);
+
+ if (!probe->parsed_args->args
+ || n >= probe->parsed_args->n_args)
+ return NULL;
+
+ /* This is needed because on some architectures (e.g., ARM) we need
+ the frame's gdbarch in order to compute the value of the frame
+ pointer. */
+ probe->parsed_args->args[n].aexpr->gdbarch = get_frame_arch (frame);
+
+ return evaluate_subexp_standard (probe->parsed_args->args[n].atype,
+ probe->parsed_args->args[n].aexpr,
+ &pos, EVAL_NORMAL);
+}
+
+/* See definition in stap-probe.h. */
+
+void
+stap_compile_to_ax (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n)
+{
+ union exp_element *pc;
+
+ if (!probe->parsed_args)
+ stap_parse_probe_arguments (probe);
+
+ if (!probe->parsed_args->args
+ || n >= probe->parsed_args->n_args)
+ return;
+
+ pc = probe->parsed_args->args[n].aexpr->elts;
+ gen_expr (probe->parsed_args->args[n].aexpr, &pc, expr, value);
+
+ require_rvalue (expr, value);
+ value->type = probe->parsed_args->args[n].atype;
+}
+
+struct value *
+stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
+{
+ struct stap_probe *probe;
+ struct objfile *objfile;
+ int n_probes;
+
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (!probe)
+ return NULL;
+ gdb_assert (objfile->sf && objfile->sf->sym_probe_fns);
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ probe);
+ if (n >= n_probes)
+ return NULL;
+
+ return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ probe,
+ frame,
+ n);
+}
+
+/* This function frees the space allocated to hold information about
+ the probe's parsed arguments. */
+
+void
+stap_free_parsed_args (struct stap_args_info *parsed_args)
+{
+ int i;
+
+ if (!parsed_args
+ || parsed_args == &dummy_stap_args_info
+ || parsed_args->n_args == 0)
+ return;
+
+ for (i = 0; i < parsed_args->n_args; i++)
+ xfree (parsed_args->args[i].aexpr);
+
+ xfree (parsed_args->args);
+ xfree (parsed_args);
+}
+
+/* A utility structure. A VEC of these is built when handling "info
+ probes". */
+
+struct stap_probe_and_objfile
+{
+ /* The probe. */
+ struct stap_probe *probe;
+ /* The probe's objfile. */
+ struct objfile *objfile;
+};
+
+typedef struct stap_probe_and_objfile stap_entry;
+DEF_VEC_O (stap_entry);
+
+/* A helper function for collect_probes that compiles a regexp and
+ throws an exception on error. This installs a cleanup to free the
+ resulting pattern on success. If RX is NULL, this does nothing. */
+
+static void
+compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
+{
+ int code;
+
+ if (!rx)
+ return;
+
+ code = regcomp (pattern, rx, REG_NOSUB);
+ if (code == 0)
+ make_regfree_cleanup (pattern);
+ else
+ {
+ char *err = get_regcomp_error (code, pattern);
+
+ make_cleanup (xfree, err);
+ error (_("%s: %s"), message, err);
+ }
+}
+
+/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE.
+ Each argument is a regexp, or NULL, which matches anything. */
+
+static VEC (stap_entry) *
+collect_probes (char *objname, char *provider, char *probe)
+{
+ struct objfile *objfile;
+ VEC (stap_entry) *result = NULL;
+ struct cleanup *cleanup;
+ regex_t obj_pat, prov_pat, probe_pat;
+
+ cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
+
+ compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
+ compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
+ compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
+
+ ALL_OBJFILES (objfile)
+ {
+ struct stap_probe *probes;
+ int i, num_probes;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objname)
+ {
+ if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ stap_entry entry;
+
+ if (provider)
+ {
+ if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ if (probe)
+ {
+ if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
+ continue;
+ }
+
+ entry.probe = &probes[i];
+ entry.objfile = objfile;
+ VEC_safe_push (stap_entry, result, &entry);
+ }
+ }
+
+ discard_cleanups (cleanup);
+ return result;
+}
+
+/* A qsort comparison function for stap_entry objects. */
+
+static int
+compare_entries (const void *a, const void *b)
+{
+ const stap_entry *ea = a;
+ const stap_entry *eb = b;
+ int v;
+
+ v = strcmp (ea->probe->provider, eb->probe->provider);
+ if (v)
+ return v;
+
+ v = strcmp (ea->probe->name, eb->probe->name);
+ if (v)
+ return v;
+
+ if (ea->probe->address < eb->probe->address)
+ return -1;
+ if (ea->probe->address > eb->probe->address)
+ return 1;
+
+ return strcmp (ea->objfile->name, eb->objfile->name);
+}
+
+/* Implementation of the "info probes" command. */
+
+static void
+info_probes_command (char *arg, int from_tty)
+{
+ char *provider, *probe = NULL, *objname = NULL;
+ struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
+ VEC (stap_entry) *items;
+ int i, addr_width, any_found;
+ stap_entry *entry;
+
+ provider = extract_arg (&arg);
+ if (provider)
+ {
+ make_cleanup (xfree, provider);
+
+ probe = extract_arg (&arg);
+ if (probe)
+ {
+ make_cleanup (xfree, probe);
+
+ objname = extract_arg (&arg);
+ if (objname)
+ make_cleanup (xfree, objname);
+ }
+ }
+
+ items = collect_probes (objname, provider, probe);
+ make_cleanup (VEC_cleanup (stap_entry), &items);
+ make_cleanup_ui_out_table_begin_end (current_uiout, 5,
+ VEC_length (stap_entry, items),
+ "SystemTapProbes");
+
+ if (! VEC_empty (stap_entry, items))
+ qsort (VEC_address (stap_entry, items),
+ VEC_length (stap_entry, items),
+ sizeof (stap_entry),
+ compare_entries);
+
+ addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
+
+ ui_out_table_header (current_uiout, 10, ui_left, "provider", _("Provider"));
+ ui_out_table_header (current_uiout, 10, ui_left, "name", _("Name"));
+ ui_out_table_header (current_uiout, addr_width - 1, ui_left, "addr", _("Where"));
+ ui_out_table_header (current_uiout, addr_width - 1, ui_left, "semaphore",
+ _("Semaphore"));
+ ui_out_table_header (current_uiout, 30, ui_left, "object", _("Object"));
+ ui_out_table_body (current_uiout);
+
+ for (i = 0; VEC_iterate (stap_entry, items, i, entry); ++i)
+ {
+ struct cleanup *inner;
+
+ inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
+
+ ui_out_field_string (current_uiout, "provider", entry->probe->provider);
+ ui_out_field_string (current_uiout, "name", entry->probe->name);
+ ui_out_field_core_addr (current_uiout, "addr", get_current_arch (),
+ entry->probe->address);
+ if (entry->probe->sem_addr == 0)
+ ui_out_field_skip (current_uiout, "semaphore");
+ else
+ ui_out_field_core_addr (current_uiout, "semaphore", get_current_arch (),
+ entry->probe->sem_addr);
+ ui_out_field_string (current_uiout, "object", entry->objfile->name);
+ ui_out_text (current_uiout, "\n");
+
+ do_cleanups (inner);
+ }
+
+ any_found = ! VEC_empty (stap_entry, items);
+ do_cleanups (cleanup);
+
+ if (! any_found)
+ ui_out_message (current_uiout, 0, _("No probes matched.\n"));
+}
+
+\f
+
+/* See definition in stap-probe.h. */
+
+VEC (stap_probe_p) *
+find_probes_in_objfile (struct objfile *objfile,
+ const char *provider,
+ const char *name)
+{
+ struct stap_probe *probes;
+ int i, num_probes;
+ VEC (stap_probe_p) *result = NULL;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ return NULL;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ if (strcmp (probes[i].provider, provider) != 0)
+ continue;
+
+ if (strcmp (probes[i].name, name) != 0)
+ continue;
+
+ VEC_safe_push (stap_probe_p, result, &probes[i]);
+ }
+
+ return result;
+}
+
+/* See definition in stap-probe.h. */
+
+struct symtabs_and_lines
+parse_stap_probe (char **argptr, struct linespec_result *canonical)
+{
+ char *arg_start, *arg_end, *arg;
+ char *objfile_name = NULL, *provider = NULL, *name, *p;
+ struct cleanup *cleanup;
+ struct symtabs_and_lines result;
+ struct objfile *objfile;
+ struct program_space *pspace;
+
+ result.sals = NULL;
+ result.nelts = 0;
+
+ arg_start = *argptr;
+ /* The caller ensured that this starts with `-p' or `-probe'. */
+ gdb_assert (arg_start
+ && ((strncmp (arg_start, "-p", 2) == 0
+ && isspace (arg_start[2]))
+ || (strncmp (arg_start, "-probe", 6) == 0
+ && isspace (arg_start[6]))));
+
+ if (strncmp (arg_start, "-probe", 6) == 0)
+ arg_end = arg_start + 6;
+ else
+ arg_end = arg_start + 2;
+ arg_end = skip_spaces (arg_end);
+
+ if (!*arg_end)
+ error (_("argument to `%s' missing"),
+ strncmp (arg_start, "-probe", 6) == 0 ? "-probe" : "-p");
+
+ arg = arg_end;
+ arg_end = skip_to_space (arg_end);
+
+ /* We make a copy here so we can write over parts with impunity. */
+ arg = savestring (arg, arg_end - arg);
+ cleanup = make_cleanup (xfree, arg);
+
+ /* Extract each word from the argument, separated by ":"s. */
+ p = strchr (arg, ':');
+ if (p == NULL)
+ {
+ /* This is `-p name'. */
+ name = arg;
+ }
+ else
+ {
+ char *hold = p + 1;
+
+ *p = '\0';
+ p = strchr (hold, ':');
+ if (p == NULL)
+ {
+ /* This is `-p provider:name'. */
+ provider = arg;
+ name = hold;
+ }
+ else
+ {
+ /* This is `-p objfile:provider:name'. */
+ *p = '\0';
+ objfile_name = arg;
+ provider = hold;
+ name = p + 1;
+ }
+ }
+
+ if (*name == '\0')
+ error (_("no probe name specified"));
+ if (provider && *provider == '\0')
+ error (_("invalid provider name"));
+ if (objfile_name && *objfile_name == '\0')
+ error (_("invalid objfile name"));
+
+ ALL_PSPACES (pspace)
+ {
+ ALL_PSPACE_OBJFILES (pspace, objfile)
+ {
+ struct stap_probe *probes;
+ int i, num_probes;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ if (objfile_name
+ && FILENAME_CMP (objfile->name, objfile_name) != 0
+ && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
+ continue;
+
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile,
+ &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ struct symtab_and_line *sal;
+
+ if (provider && strcmp (probes[i].provider, provider) != 0)
+ continue;
+
+ if (strcmp (probes[i].name, name) != 0)
+ continue;
+
+ ++result.nelts;
+ result.sals = xrealloc (result.sals,
+ result.nelts
+ * sizeof (struct symtab_and_line));
+ sal = &result.sals[result.nelts - 1];
+
+ init_sal (sal);
+
+ sal->pc = probes[i].address;
+ sal->explicit_pc = 1;
+ sal->section = find_pc_overlay (sal->pc);
+ sal->pspace = current_program_space;
+ sal->semaphore = probes[i].sem_addr;
+ }
+ }
+ }
+
+ if (result.nelts == 0)
+ {
+ throw_error (NOT_FOUND_ERROR,
+ _("No probe matching objfile=`%s', provider=`%s', name=`%s'"),
+ objfile_name ? objfile_name : _("<any>"),
+ provider ? provider : _("<any>"),
+ name);
+ }
+
+ if (canonical)
+ {
+ canonical->special_display = 1;
+ canonical->pre_expanded = 1;
+ canonical->addr_string = savestring (*argptr, arg_end - *argptr);
+ }
+
+ *argptr = arg_end;
+ do_cleanups (cleanup);
+
+ return result;
+}
+
+\f
+
+/* See definition in stap-probe.h. */
+
+struct stap_probe *
+find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct stap_probe *probes;
+ int i, num_probes;
+ stap_entry entry;
+
+ if (! objfile->sf || ! objfile->sf->sym_probe_fns)
+ continue;
+
+ /* If this proves too inefficient, we can replace with a hash. */
+ probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
+ for (i = 0; i < num_probes; ++i)
+ {
+ if (probes[i].address == pc)
+ {
+ *objfile_out = objfile;
+ return &probes[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* 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 objfile *objfile;
+ struct stap_probe *pc_probe;
+ int n_probes;
+
+ /* SEL==-1 means "_probe_argc". */
+ gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ if (sel == -1)
+ return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
+
+ if (sel >= n_probes)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_probes);
+
+ return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
+ pc_probe,
+ frame, sel);
+}
+
+/* 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 objfile *objfile;
+ struct stap_probe *pc_probe;
+ int n_probes;
+
+ /* SEL==-1 means "_probe_argc". */
+ gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
+
+ pc_probe = find_probe_by_pc (pc, &objfile);
+ if (pc_probe == NULL)
+ error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
+
+ n_probes
+ = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
+ pc_probe);
+ if (sel == -1)
+ {
+ value->kind = axs_rvalue;
+ value->type = builtin_type (expr->gdbarch)->builtin_int;
+ ax_const_l (expr, n_probes);
+ return;
+ }
+
+ gdb_assert (sel >= 0);
+ if (sel >= n_probes)
+ error (_("Invalid probe argument %d -- probe has %d arguments available"),
+ sel, n_probes);
+
+ objfile->sf->sym_probe_fns->sym_compile_to_ax (objfile, pc_probe,
+ expr, value, sel);
+}
+
+\f
+
+/* Implementation of `$_probe_arg*' set of variables. */
+
+static const struct internalvar_funcs probe_funcs =
+{
+ compute_probe_arg,
+ compile_probe_arg,
+ NULL
+};
+
+void _initialize_stap_probe (void);
+
+void
+_initialize_stap_probe (void)
+{
+ add_info ("probes", info_probes_command, _("\
+Show available static probes.\n\
+Usage: info 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 match the executable or shared library name."));
+
+ add_setshow_zinteger_cmd ("stap-expression", class_maintenance,
+ &stap_expression_debug,
+ _("Set SystemTap expression debugging."),
+ _("Show SystemTap expression debugging."),
+ _("When non-zero, the internal representation "
+ "of SystemTap expressions will be printed."),
+ NULL,
+ 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);
+}
diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
new file mode 100644
index 0000000..9b6dc7a
--- /dev/null
+++ b/gdb/stap-probe.h
@@ -0,0 +1,144 @@
+/* SystemTap probe support for GDB.
+
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#if !defined (STAP_PROBE_H)
+#define STAP_PROBE_H 1
+
+#include "vec.h"
+
+struct stap_args_info;
+struct axs_value;
+struct linespec_result;
+
+/* Main structure which holds information about a SystemTap probe. */
+
+struct stap_probe
+{
+ /* The provider of this probe. */
+ const char *provider;
+
+ /* The name of the probe. */
+ const char *name;
+
+ /* The address where the probe is inserted. */
+ CORE_ADDR address;
+
+ /* The address of the probe's semaphore, or 0 if this probe does not
+ have an associated semaphore. */
+ CORE_ADDR sem_addr;
+
+ /* Probe's arguments. Users should generally not examine this, but
+ should instead extract information about the arguments using the
+ methods provided in sym_probe_fns. */
+ const char *args;
+
+ /* Probe's arguments after parsing. This is an opaque structure that
+ will hold information about the arguments pointed by ARGS. */
+ struct stap_args_info *parsed_args;
+
+ /* gdbarch structure associated with this probe. */
+ struct gdbarch *gdbarch;
+};
+
+/* Structure which holds information about the parsing process of one probe's
+ argument. */
+
+struct stap_parse_info
+{
+ /* The probe's argument in a string format. */
+ const char *arg;
+
+ /* A pointer to the full chain of arguments. This is useful for printing
+ error messages. The parser functions should not modify this argument
+ directly; instead, they should use the ARG pointer above. */
+ const char *saved_arg;
+
+ /* The expected argument type (bitness), as defined in the probe's
+ argument. For instance, if the argument begins with `-8@', it means
+ the bitness is 64-bit signed. In this case, ARG_TYPE would represent
+ the type `int64_t'. */
+ struct type *arg_type;
+
+ /* A pointer to the current gdbarch. */
+ struct gdbarch *gdbarch;
+
+ /* Greater than zero if we are inside a parenthesized expression. Useful
+ for knowing when to skip spaces or not. */
+ int inside_paren_p;
+};
+
+typedef struct stap_probe *stap_probe_p;
+DEF_VEC_P (stap_probe_p);
+
+/* A helper for linespec that decodes a stap probe specification. It
+ returns a symtabs_and_lines object and updates *ARGPTR or throws an
+ error. */
+
+extern struct symtabs_and_lines parse_stap_probe (char **argptr,
+ struct linespec_result *canon);
+
+/* Search OBJFILE for a probe with the given PROVIDER and NAME.
+ Return a VEC of all probes that were found. If no matching probe
+ is found, return NULL. The caller must free the VEC. */
+
+extern VEC (stap_probe_p) *find_probes_in_objfile (struct objfile *objfile,
+ const char *provider,
+ const char *name);
+
+/* Given a PC, find an associated SystemTap probe. If a probe is
+ found, set *OBJFILE_OUT to the probe's objfile, and return the
+ probe. If no probe is found, return NULL. */
+
+extern struct stap_probe *find_probe_by_pc (CORE_ADDR pc,
+ struct objfile **objfile_out);
+
+/* Given PROBE, returns the number of arguments present in that probe's
+ argument string. */
+
+extern int stap_get_probe_argument_count (struct stap_probe *probe);
+
+/* Given PARSED_ARGS, frees the space allocated to hold information about
+ the probe's parsed arguments. */
+
+extern void stap_free_parsed_args (struct stap_args_info *parsed_args);
+
+/* Evaluate the probe's argument N, returning a value corresponding
+ to it. */
+
+extern struct value *stap_evaluate_probe_argument (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct frame_info *frame,
+ int n);
+
+/* Compile the probe's argument N to agent expression. */
+
+extern void stap_compile_to_ax (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n);
+
+/* A convenience function that finds a probe at the PC in FRAME and
+ evaluates argument N. If there is no probe at that location, or if
+ the probe does not have enough arguments, this returns NULL. */
+
+extern struct value *stap_safe_evaluate_at_pc (struct frame_info *frame,
+ int n);
+
+#endif /* !defined (STAP_PROBE_H) */
diff --git a/gdb/symfile.h b/gdb/symfile.h
index d4f3fd9..544d465 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -29,6 +29,11 @@ struct objfile;
struct obj_section;
struct obstack;
struct block;
+struct stap_probe;
+struct value;
+struct frame_info;
+struct agent_expr;
+struct axs_value;
/* Comparison function for symbol look ups. */
@@ -297,6 +302,52 @@ struct quick_symbol_functions
int need_fullname);
};
+/* Structure of functions used for SystemTap probe support. If one of
+ these functions is provided, all must be. */
+
+struct sym_probe_fns
+{
+ /* If non-NULL, return an array of SystemTap probe objects. The
+ number of objects is returned in *NUM_PROBES. */
+ struct stap_probe *(*sym_get_probes) (struct objfile *,
+ int *num_probes);
+
+ /* Return the number of arguments available to PROBE. PROBE will
+ have come from a call to this objfile's sym_get_probes method.
+ If you provide an implementation of sym_get_probes, you must
+ implement this method as well. */
+ int (*sym_get_probe_argument_count) (struct objfile *objfile,
+ struct stap_probe *probe);
+
+ /* Evaluate the Nth argument available to PROBE. PROBE will have
+ come from a call to this objfile's sym_get_probes method. N will
+ be between 0 and the number of arguments available to this probe.
+ FRAME is the frame in which the evaluation is done; the frame's
+ PC will match the address of the probe. If you provide an
+ implementation of sym_get_probes, you must implement this method
+ as well. */
+ struct value *(*sym_evaluate_probe_argument) (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct frame_info *frame,
+ int n);
+
+ /* Compile the Nth probe argument to an agent expression. PROBE
+ will have come from a call to this objfile's sym_get_probes
+ method. N will be between 0 and the number of arguments
+ available to this probe. EXPR and VALUE are the agent expression
+ that is being updated. */
+ void (*sym_compile_to_ax) (struct objfile *objfile,
+ struct stap_probe *probe,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ int n);
+
+ /* Relocate the probe section of OBJFILE. */
+ void (*sym_relocate_probe) (struct objfile *objfile,
+ struct section_offsets *new_offsets,
+ struct section_offsets *delta);
+};
+
/* Structure to keep track of symbol reading functions for various
object file types. */
@@ -367,6 +418,10 @@ struct sym_fns
bfd_byte *(*sym_relocate) (struct objfile *, asection *sectp, bfd_byte *buf);
+ /* If non-NULL, this objfile has probe support, and all the probe
+ functions referred to here will be non-NULL. */
+ const struct sym_probe_fns *sym_probe_fns;
+
/* The "quick" (aka partial) symbol functions for this symbol
reader. */
const struct quick_symbol_functions *qf;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index c2580a1..c83dd96 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -877,6 +877,7 @@ init_sal (struct symtab_and_line *sal)
sal->end = 0;
sal->explicit_pc = 0;
sal->explicit_line = 0;
+ sal->semaphore = 0;
}
\f
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d9e5f4a..cb6206d 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1045,6 +1045,10 @@ struct symtab_and_line
CORE_ADDR end;
int explicit_pc;
int explicit_line;
+
+ /* If non-zero, the semaphore location associated with a SystemTap
+ probe. */
+ CORE_ADDR semaphore;
};
extern void init_sal (struct symtab_and_line *sal);
diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp
index 89426c2..6ec3c80 100644
--- a/gdb/testsuite/gdb.base/default.exp
+++ b/gdb/testsuite/gdb.base/default.exp
@@ -606,6 +606,19 @@ gdb_test_list_exact "show convenience" "show convenience" \
{$_sdata = void} \
{$_siginfo = void} \
{$_thread = 0} \
+ {$_probe_argc = <error: No frame selected>} \
+ {$_probe_arg0 = <error: No frame selected>} \
+ {$_probe_arg1 = <error: No frame selected>} \
+ {$_probe_arg2 = <error: No frame selected>} \
+ {$_probe_arg3 = <error: No frame selected>} \
+ {$_probe_arg4 = <error: No frame selected>} \
+ {$_probe_arg5 = <error: No frame selected>} \
+ {$_probe_arg6 = <error: No frame selected>} \
+ {$_probe_arg7 = <error: No frame selected>} \
+ {$_probe_arg8 = <error: No frame selected>} \
+ {$_probe_arg9 = <error: No frame selected>} \
+ {$_probe_arg10 = <error: No frame selected>} \
+ {$_probe_arg11 = <error: No frame selected>} \
}
#test show directories
diff --git a/gdb/testsuite/gdb.base/stap-probe.c b/gdb/testsuite/gdb.base/stap-probe.c
new file mode 100644
index 0000000..236da96
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.c
@@ -0,0 +1,108 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_two_semaphore
+
+__extension__ unsigned short teste_m4_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short teste_pstr_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+
+__extension__ unsigned short teste_ps_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+struct funcs
+{
+ int val;
+
+ const char *(*ps) (int);
+};
+
+static void
+m1 (void)
+{
+ if (TEST2)
+ STAP_PROBE (teste, two);
+}
+
+static void
+m2 (void)
+{
+ if (TEST2)
+ STAP_PROBE (teste, two);
+}
+
+static int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1 (teste, user, x);
+ return x+5;
+}
+
+static const char *
+pstr (int val)
+{
+ const char *a = "This is a test message.";
+ const char *b = "This is another test message.";
+
+ STAP_PROBE3 (teste, ps, a, b, val);
+
+ return val == 0 ? a : b;
+}
+
+static void
+m4 (const struct funcs *fs, int v)
+{
+ STAP_PROBE3 (teste, m4, fs->val, fs->ps (v), v);
+}
+
+int
+main()
+{
+ struct funcs fs;
+
+ fs.val = 42;
+ fs.ps = pstr;
+
+ f (f (23));
+ m1 ();
+ m2 ();
+
+ m4 (&fs, 0);
+ m4 (&fs, 1);
+
+ return 0; /* last break here */
+}
diff --git a/gdb/testsuite/gdb.base/stap-probe.exp b/gdb/testsuite/gdb.base/stap-probe.exp
new file mode 100644
index 0000000..468efb9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/stap-probe.exp
@@ -0,0 +1,187 @@
+# Copyright (C) 2011 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/>.
+
+set testfile stap-probe
+
+# Run the tests. We run the tests two different ways: once with a
+# plain probe, and once with a probe that has an associated semaphore.
+# This returns -1 on failure to compile or start, 0 otherwise.
+proc stap_test {{arg ""}} {
+ global testfile hex
+
+ if {$arg != ""} {
+ set arg "additional_flags=$arg"
+ set addendum ", with semaphore, not optimized"
+ } else {
+ set addendum ", no semaphore, not optimized"
+ }
+
+ if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
+ [concat $arg debug]]} {
+ return -1
+ }
+
+ if ![runto_main] {
+ return -1
+ }
+
+ gdb_test "print \$_probe_argc" "No SystemTap probe at PC $hex" \
+ "check argument not at probe point$addendum"
+
+ gdb_test "info probes" \
+ "teste *user *$hex .*" \
+ "info probes$addendum"
+
+ if {[runto "-p teste:user"]} {
+ pass "run to -p teste:user$addendum"
+ } else {
+ fail "run to -p teste:user$addendum"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user$addendum"
+ gdb_test "print \$_probe_arg0 == x" " = 1" \
+ "check \$_probe_arg0 for probe user$addendum"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user$addendum"
+
+ # Set a breakpoint with multiple probe locations.
+ gdb_test "break -p teste:two" \
+ "Breakpoint \[0-9\]+ at $hex.*2 locations.*" \
+ "set multi-location probe breakpoint (probe two)$addendum"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-p teste:m4"]} {
+ pass "run to -p teste:m4$addendum"
+ } else {
+ fail "run to -p teste:m4$addendum"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4$addendum"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4$addendum"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4$addendum"
+ gdb_test "print \$_probe_arg2 == v" " = 1" \
+ "check \$_probe_arg2 for probe m4$addendum"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-p teste:ps"]} {
+ pass "run to -p teste:m4$addendum"
+ } else {
+ fail "run to -p teste:m4$addendum"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps$addendum"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps$addendum"
+
+ return 0
+}
+
+proc stap_test_no_debuginfo {{ arg "" }} {
+ global testfile hex
+
+ if {$arg != ""} {
+ set arg "additional_flags=$arg"
+ set addendum ", with semaphore, optimized"
+ } else {
+ set addendum ", no semaphore, optimized"
+ }
+
+ if {[prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c \
+ {$arg nodebug optimize=-O2}]} {
+ return -1
+ }
+
+ if {[runto "-p teste:user"]} {
+ pass "run to -p teste:user$addendum"
+ } else {
+ fail "run to -p teste:user$addendum"
+ }
+
+ # Test probe arguments.
+ gdb_test "print \$_probe_argc" " = 1" \
+ "print \$_probe_argc for probe user$addendum"
+ gdb_test "print \$_probe_arg0 == 23" " = 1" \
+ "check \$_probe_arg0 for probe user$addendum"
+ gdb_test "print \$_probe_arg1" \
+ "Invalid probe argument 1 -- probe has 1 arguments available" \
+ "check \$_probe_arg1 for probe user$addendum"
+
+ # Set a breakpoint with multiple probe locations.
+ # In this scenario, we may expect more than 2 locations because of
+ # the optimizations (inlining, loop unrolling, etc).
+ gdb_test "break -p teste:two" \
+ "Breakpoint .* at $hex.*\[0-9\]+ locations.*" \
+ "set multi-location probe breakpoint (probe two)$addendum"
+
+ # Reinit GDB, set a breakpoint on probe m4.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-p teste:m4"]} {
+ pass "run to -p teste:m4$addendum"
+ } else {
+ fail "run to -p teste:m4$addendum"
+ }
+
+ # Testing probe arguments.
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe m4$addendum"
+ gdb_test "print \$_probe_arg0" " = 42" \
+ "check \$_probe_arg0 for probe m4$addendum"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is a test message.*" \
+ "check \$_probe_arg1 for probe m4$addendum"
+ gdb_test "print \$_probe_arg2 == 0" " = 1" \
+ "check \$_probe_arg2 for probe m4$addendum"
+
+ # Reinit GDB, set a breakpoint on probe ps.
+ delete_breakpoints
+ rerun_to_main
+ if {[runto "-p teste:ps"]} {
+ pass "run to -p teste:m4$addendum"
+ } else {
+ fail "run to -p teste:m4$addendum"
+ }
+
+ gdb_test "print \$_probe_argc" " = 3" \
+ "print \$_probe_argc for probe ps$addendum"
+ gdb_test "print (const char *) \$_probe_arg1" \
+ " = $hex .This is another test message.*" \
+ "print \$_probe_arg1 for probe ps$addendum"
+
+ return 0
+}
+
+if {[stap_test] == -1} {
+ untested stap-probe.exp
+ return -1
+}
+
+stap_test "-DUSE_PROBES"
+stap_test_no_debuginfo
+stap_test_no_debuginfo "-DUSE_PROBES"
diff --git a/gdb/testsuite/gdb.cp/nextoverthrow.exp b/gdb/testsuite/gdb.cp/nextoverthrow.exp
index 7d4a0c5..2dafcab 100644
--- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
+++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
@@ -54,6 +54,17 @@ gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
}
}
if {!$ok} {
+ gdb_test_multiple "info probe" "check for stap probe in unwinder" {
+ -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
+ pass "check for stap probe in unwinder"
+ set ok 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+}
+
+if {!$ok} {
unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
return -1
}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.c b/gdb/testsuite/gdb.trace/stap-trace.c
new file mode 100644
index 0000000..27f317e
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.c
@@ -0,0 +1,71 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#if USE_PROBES
+
+#define _SDT_HAS_SEMAPHORES
+__extension__ unsigned short teste_user_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST teste_user_semaphore
+
+__extension__ unsigned short teste_two_semaphore __attribute__ ((unused)) __attribute__ ((section (".probes")));
+#define TEST2 teste_two_semaphore
+
+#else
+
+#define TEST 1
+#define TEST2 1
+
+#endif /* USE_PROBES */
+
+#include <sys/sdt.h>
+
+/* We only support SystemTap and only the v3 form. */
+#if _SDT_NOTE_TYPE != 3
+#error "not using SystemTap v3 probes"
+#endif
+
+void
+m1 (int x)
+{
+ if (TEST2)
+ STAP_PROBE1 (teste, two, x);
+}
+
+int
+f (int x)
+{
+ if (TEST)
+ STAP_PROBE1(teste, user, x);
+ return x+5;
+}
+
+void
+nothing (void)
+{
+ int a = 1 + 1;
+ return;
+}
+
+int
+main()
+{
+ f (f (23));
+ m1 (46);
+ nothing (); /* end-here */
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.trace/stap-trace.exp b/gdb/testsuite/gdb.trace/stap-trace.exp
new file mode 100644
index 0000000..b0f1d7d
--- /dev/null
+++ b/gdb/testsuite/gdb.trace/stap-trace.exp
@@ -0,0 +1,129 @@
+# Copyright 2011
+# 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 "trace-support.exp"
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile "stap-trace"
+set srcfile ${testfile}.c
+set executable $testfile
+set binfile $objdir/$subdir/$executable
+
+set ws "\[\r\n\t \]+"
+set cr "\[\r\n\]+"
+
+# Only x86 and x86_64 targets are supported for now.
+
+if { ![istarget "x86_64-*"] && ![istarget "i?86-*"] } {
+ continue
+}
+
+proc compile_stap_bin {{ arg "" }} {
+ global srcfile
+ global binfile
+ global srcdir
+ global subdir
+
+ if { $arg != "" } {
+ set arg "additional_flags=$arg"
+ }
+
+ if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
+ executable [concat $arg debug nowarnings]] != "" } {
+ untested "Could not compile ${srcfile}"
+ return -1
+ }
+}
+
+proc prepare_for_trace_test {} {
+ global executable
+
+ clean_restart $executable
+
+ if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+ }
+
+ gdb_breakpoint [gdb_get_line_number "end-here"]
+}
+
+proc run_trace_experiment { test_probe msg } {
+ global gdb_prompt
+
+ set test "collect $msg: start trace experiment"
+ gdb_test_multiple "tstart" "$test" {
+ -re "^tstart\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test "continue" \
+ "Continuing.*Breakpoint \[0-9\]+.*" \
+ "collect $msg: run trace experiment"
+ gdb_test "tstop" \
+ "\[\r\n\]+" \
+ "collect $msg: stop trace experiment"
+ gdb_test "tfind start" \
+ "#0 .*" \
+ "collect $msg: tfind test frame"
+}
+
+proc gdb_collect_probe_arg { msg probe val_arg0 } {
+ global gdb_prompt
+ global cr
+
+ prepare_for_trace_test
+
+ gdb_test "trace $probe" \
+ "Tracepoint \[0-9\]+ at .*" \
+ "collect $msg: set tracepoint"
+ gdb_trace_setactions "collect $msg: define actions" \
+ "" \
+ "collect \$_probe_arg0" "^$"
+
+ # Begin the test.
+ run_trace_experiment $msg $probe
+
+ gdb_test "print \$_probe_arg0" \
+ "\\$\[0-9\]+ = $val_arg0$cr" \
+ "collect $msg: collected probe arg0"
+}
+
+compile_stap_bin ""
+
+clean_restart $executable
+if { ![runto_main] } {
+ perror "Could not run to `main'."
+ continue
+}
+
+if { ![gdb_target_supports_trace] } {
+ # Test cannot run on this target.
+ return 1;
+}
+
+gdb_collect_probe_arg "probe args without semaphore" "-p user" "23"
+gdb_exit
+
+compile_stap_bin "-DUSE_PROBES"
+gdb_collect_probe_arg "probe args with semaphore" "-p two" "46"
+
+# Finished!
+gdb_test "tfind none" ".*" ""
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index ac8fade..a615ef2 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -1717,6 +1717,7 @@ start_tracing (char *notes)
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
{
struct tracepoint *t = (struct tracepoint *) b;
+ struct bp_location *loc;
if (b->enable_state == bp_enabled)
any_enabled = 1;
@@ -1779,6 +1780,9 @@ start_tracing (char *notes)
}
t->number_on_target = b->number;
+
+ for (loc = b->loc; loc; loc = loc->next)
+ modify_semaphore (loc, 1);
}
VEC_free (breakpoint_p, tp_vec);
@@ -1851,9 +1855,28 @@ void
stop_tracing (char *note)
{
int ret;
+ VEC(breakpoint_p) *tp_vec = NULL;
+ int ix;
+ struct breakpoint *t;
target_trace_stop ();
+ tp_vec = all_tracepoints ();
+ for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+ {
+ struct bp_location *loc;
+
+ if ((t->type == bp_fast_tracepoint
+ ? !may_insert_fast_tracepoints
+ : !may_insert_tracepoints))
+ continue;
+
+ for (loc = t->loc; loc; loc = loc->next)
+ modify_semaphore (loc, 0);
+ }
+
+ VEC_free (breakpoint_p, tp_vec);
+
if (!note)
note = trace_stop_notes;
ret = target_set_trace_notes (NULL, NULL, note);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 86ae8fb..288709e 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3112,6 +3112,7 @@ static const struct sym_fns xcoff_sym_fns =
default_symfile_segments, /* Get segment information from a file. */
aix_process_linenos,
default_symfile_relocate, /* Relocate a debug section. */
+ NULL, /* sym_probe_fns */
&psym_functions
};
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH 3/3] Use longjmp and exception probes when available
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
2012-03-09 20:32 ` [PATCH 1/3] Refactor internal variable mechanism Sergio Durigan Junior
@ 2012-03-09 20:34 ` Sergio Durigan Junior
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
` (2 subsequent siblings)
4 siblings, 0 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-09 20:34 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Hello,
This is the third and last patch. It implements the bits necessary for
using longjmp and exception probes on glibc and libgcc, respectively.
Is this OK to check-in?
gdb/ChangeLog
2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* breakpoint.c (struct breakpoint_objfile_data)
<longjmp_searched>,<longjmp_probes>,<exception_searched>,
<exception_probes>: New fields.
(free_breakpoint_probes): New function.
(create_longjmp_master_breakpoint): Prefer SystemTap probe over
`_Unwind_DebugHook'.
(create_exception_master_breakpoint): Likewise.
(_initialize_breakpoint): Registering cleanup for SystemTap probes.
* infrun.c: Including necessary header files for handling SystemTap
probes.
(handle_inferior_event): Handling longjmp breakpoint and exceptions
via SystemTap probes.
(check_exception_resume): Remove `func' argument. Handle exception
unwinding breakpoint set via a SystemTap probe.
(insert_exception_resume_from_probe): New function.
---
gdb/breakpoint.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
gdb/infrun.c | 77 ++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 154 insertions(+), 12 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a8f3a42..7b3f209 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2752,11 +2752,23 @@ struct breakpoint_objfile_data
/* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any). */
struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
+ /* True if we have looked for longjmp probes. */
+ int longjmp_searched;
+
+ /* SystemTap probe points for longjmp (if any). */
+ VEC (stap_probe_p) *longjmp_probes;
+
/* Minimal symbol for "std::terminate()" (if any). */
struct minimal_symbol *terminate_msym;
/* Minimal symbol for "_Unwind_DebugHook" (if any). */
struct minimal_symbol *exception_msym;
+
+ /* True if we have looked for exception probes. */
+ int exception_searched;
+
+ /* SystemTap probe points for unwinding (if any). */
+ VEC (stap_probe_p) *exception_probes;
};
static const struct objfile_data *breakpoint_objfile_key;
@@ -2793,6 +2805,15 @@ get_breakpoint_objfile_data (struct objfile *objfile)
}
static void
+free_breakpoint_probes (struct objfile *obj, void *data)
+{
+ struct breakpoint_objfile_data *bp_objfile_data = data;
+
+ VEC_free (stap_probe_p, bp_objfile_data->longjmp_probes);
+ VEC_free (stap_probe_p, bp_objfile_data->exception_probes);
+}
+
+static void
create_overlay_event_breakpoint (void)
{
struct objfile *objfile;
@@ -2869,6 +2890,37 @@ create_longjmp_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ if (!bp_objfile_data->longjmp_searched)
+ {
+ bp_objfile_data->longjmp_probes
+ = find_probes_in_objfile (objfile, "libc", "longjmp");
+ bp_objfile_data->longjmp_searched = 1;
+ }
+
+ if (bp_objfile_data->longjmp_probes != NULL)
+ {
+ int i;
+ struct stap_probe *probe;
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ for (i = 0;
+ VEC_iterate (stap_probe_p,
+ bp_objfile_data->longjmp_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_longjmp_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-p libc:longjmp");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
@@ -2979,6 +3031,40 @@ create_exception_master_breakpoint (void)
bp_objfile_data = get_breakpoint_objfile_data (objfile);
+ /* We prefer the SystemTap probe point if it exists. */
+ if (!bp_objfile_data->exception_searched)
+ {
+ bp_objfile_data->exception_probes
+ = find_probes_in_objfile (objfile, "libgcc", "unwind");
+ bp_objfile_data->exception_searched = 1;
+ }
+
+ if (bp_objfile_data->exception_probes != NULL)
+ {
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+ int i;
+ struct stap_probe *probe;
+
+ for (i = 0;
+ VEC_iterate (stap_probe_p,
+ bp_objfile_data->exception_probes,
+ i, probe);
+ ++i)
+ {
+ struct breakpoint *b;
+
+ b = create_internal_breakpoint (gdbarch, probe->address,
+ bp_exception_master,
+ &internal_breakpoint_ops);
+ b->addr_string = xstrdup ("-p libgcc:unwind");
+ b->enable_state = bp_disabled;
+ }
+
+ continue;
+ }
+
+ /* Otherwise, try the hook function. */
+
if (msym_not_found_p (bp_objfile_data->exception_msym))
continue;
@@ -15066,7 +15152,8 @@ _initialize_breakpoint (void)
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
- breakpoint_objfile_key = register_objfile_data ();
+ breakpoint_objfile_key
+ = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
breakpoint_chain = 0;
/* Don't bother to call set_breakpoint_count. $bpnum isn't useful
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e39ef..d9bd886 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -55,6 +55,8 @@
#include "continuations.h"
#include "interps.h"
#include "skip.h"
+#include "stap-probe.h"
+#include "objfiles.h"
/* Prototypes for local functions */
@@ -2392,7 +2394,7 @@ static void handle_step_into_function (struct gdbarch *gdbarch,
static void handle_step_into_function_backward (struct gdbarch *gdbarch,
struct execution_control_state *ecs);
static void check_exception_resume (struct execution_control_state *,
- struct frame_info *, struct symbol *);
+ struct frame_info *);
static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
@@ -4427,9 +4429,17 @@ process_event_stop_test:
if (what.is_longjmp)
{
- if (!gdbarch_get_longjmp_target_p (gdbarch)
- || !gdbarch_get_longjmp_target (gdbarch,
- frame, &jmp_buf_pc))
+ struct value *arg_value;
+
+ /* If we set the longjmp breakpoint via a SystemTap probe,
+ then use it to extract the arguments. The destination
+ PC is the third argument to the probe. */
+ arg_value = stap_safe_evaluate_at_pc (frame, 2);
+ if (arg_value)
+ jmp_buf_pc = value_as_address (arg_value);
+ else if (!gdbarch_get_longjmp_target_p (gdbarch)
+ || !gdbarch_get_longjmp_target (gdbarch,
+ frame, &jmp_buf_pc))
{
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog,
@@ -4447,12 +4457,7 @@ process_event_stop_test:
insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
}
else
- {
- struct symbol *func = get_frame_function (frame);
-
- if (func)
- check_exception_resume (ecs, frame, func);
- }
+ check_exception_resume (ecs, frame);
keep_going (ecs);
return;
@@ -5539,15 +5544,65 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
}
}
+/* A helper for check_exception_resume that sets an
+ exception-breakpoint based on a SystemTap probe. */
+
+static void
+insert_exception_resume_from_probe (struct thread_info *tp,
+ const struct stap_probe *probe,
+ struct objfile *objfile,
+ struct frame_info *frame)
+{
+ struct value *arg_value;
+ CORE_ADDR handler;
+ struct breakpoint *bp;
+
+ arg_value = stap_safe_evaluate_at_pc (frame, 1);
+ if (!arg_value)
+ return;
+
+ handler = value_as_address (arg_value);
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: exception resume at %s\n",
+ paddress (get_objfile_arch (objfile),
+ handler));
+
+ bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+ handler, bp_exception_resume);
+ bp->thread = tp->num;
+ inferior_thread ()->control.exception_resume_breakpoint = bp;
+}
+
/* This is called when an exception has been intercepted. Check to
see whether the exception's destination is of interest, and if so,
set an exception resume breakpoint there. */
static void
check_exception_resume (struct execution_control_state *ecs,
- struct frame_info *frame, struct symbol *func)
+ struct frame_info *frame)
{
volatile struct gdb_exception e;
+ struct objfile *objfile;
+ const struct stap_probe *probe;
+ struct symbol *func;
+
+ /* First see if this exception unwinding breakpoint was set via a
+ SystemTap probe point. If so, the probe has two arguments: the
+ CFA and the HANDLER. We ignore the CFA, extract the handler, and
+ set a breakpoint there. */
+ probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+ if (probe)
+ {
+ insert_exception_resume_from_probe (ecs->event_thread, probe,
+ objfile, frame);
+ return;
+ }
+
+ func = get_frame_function (frame);
+ if (!func)
+ return;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/3] Refactor internal variable mechanism
2012-03-09 20:32 ` [PATCH 1/3] Refactor internal variable mechanism Sergio Durigan Junior
@ 2012-03-09 21:03 ` Tom Tromey
2012-03-10 4:02 ` Sergio Durigan Junior
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-03-09 21:03 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> This is the first patch, which refactors the internal variable
Sergio> mechanism. It creates new methods, for example to compile an internal
Sergio> variable into agent expression.
Sergio> Is this OK to check-in?
I intend to approve this one but I would like to wait for other comments
first.
Really I'm replying now to point out a nit :)
Sergio> +/* Implementation of `thread' variable. */
Sergio> +
Sergio> +static struct internalvar_funcs thread_funcs =
This one should be 'const' like the others are.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
` (2 preceding siblings ...)
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
@ 2012-03-09 21:15 ` Tom Tromey
2012-03-10 3:51 ` Sergio Durigan Junior
2012-03-10 7:55 ` Eli Zaretskii
4 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-03-09 21:15 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> The third patch contains code to make use of the existing longjmp and
Sergio> exception probes in glibc and libgcc, respectively. I believe Tom can
Sergio> give more information about this patch, but the idea is that if we have
Sergio> those probes available, GDB should use them because we don't need
Sergio> debuginfo to access them.
That sums it up very well. The probes are preferable for just this
reason.
The libgcc probes are upstream, so distros need only install sdt.h
before building gcc to get the benefit.
The glibc changes are in the Fedora RPM. I think we may try again to
get them upstream.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-09 21:15 ` [PATCH 0/3] Implement support for SystemTap probes on userspace Tom Tromey
@ 2012-03-10 3:51 ` Sergio Durigan Junior
0 siblings, 0 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-10 3:51 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, March 09 2012, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> The third patch contains code to make use of the existing longjmp and
> Sergio> exception probes in glibc and libgcc, respectively. I believe Tom can
> Sergio> give more information about this patch, but the idea is that if we have
> Sergio> those probes available, GDB should use them because we don't need
> Sergio> debuginfo to access them.
>
> The glibc changes are in the Fedora RPM. I think we may try again to
> get them upstream.
Definitely. Let me know if you need any help with that.
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 1/3] Refactor internal variable mechanism
2012-03-09 21:03 ` Tom Tromey
@ 2012-03-10 4:02 ` Sergio Durigan Junior
0 siblings, 0 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-10 4:02 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Friday, March 09 2012, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> This is the first patch, which refactors the internal variable
> Sergio> mechanism. It creates new methods, for example to compile an internal
> Sergio> variable into agent expression.
>
> Sergio> Is this OK to check-in?
>
> I intend to approve this one but I would like to wait for other comments
> first.
Sure :-).
> Really I'm replying now to point out a nit :)
>
> Sergio> +/* Implementation of `thread' variable. */
> Sergio> +
> Sergio> +static struct internalvar_funcs thread_funcs =
>
> This one should be 'const' like the others are.
Right, thanks for that, fixed.
--
Sergio
2012-10-03 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
* ax-gdb.c (gen_expr): Clean up code to handle internal variables
and to compile agent expressions.
* infrun.c (siginfo_make_value): New argument `ignore'.
(siginfo_funcs): New struct.
(_initialize_infrun): New argument when calling
`create_internalvar_type_lazy'.
* thread.c (thread_id_make_value): New argument `ignore'.
(thread_funcs): New struct.
(_initialize_thread): New argument when calling
`create_internalvar_type_lazy'.
* tracepoint.c (sdata_make_value): New argument `ignore'.
(sdata_funcs): New struct.
(_initialize_tracepoint): New argument when calling
`create_internalvar_type_lazy'.
* value.c (make_value): New struct.
(create_internalvar_type_lazy): New argument `data'.
(compile_internalvar_to_ax): New function.
(value_of_internalvar): Properly handling `make_value' case.
(clear_internalvar): Likewise.
(show_convenience): Adding `TRY_CATCH' block.
* value.h (internalvar_make_value): Delete, replace by...
(struct internalvar_funcs): ... this.
(create_internalvar_type_lazy) <fun>: Delete argument.
(create_internalvar_type_lazy) <funcs>, <data>: New arguments.
(compile_internalvar_to_ax): New function.
* windows-tdep.c (tlb_make_value): New argument `ignore'.
(tlb_funcs): New struct.
(_initialize_windows_tdep): New argument when calling
`create_internalvar_type_lazy'.
---
gdb/ax-gdb.c | 5 +++--
gdb/infrun.c | 14 ++++++++++++--
gdb/thread.c | 14 ++++++++++++--
gdb/tracepoint.c | 14 ++++++++++++--
gdb/value.c | 44 +++++++++++++++++++++++++++++++++++++++-----
gdb/value.h | 48 +++++++++++++++++++++++++++++++++++++++++++++---
gdb/windows-tdep.c | 13 +++++++++++--
7 files changed, 134 insertions(+), 18 deletions(-)
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index bd81338..b163681 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2041,7 +2041,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;
(*pc) += 3;
@@ -2055,7 +2056,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 103ef30..54e39ef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6589,7 +6589,8 @@ static const struct lval_funcs siginfo_value_funcs =
if there's no object available. */
static struct value *
-siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
if (target_has_stack
&& !ptid_equal (inferior_ptid, null_ptid)
@@ -7011,6 +7012,15 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
"of all processes is %s.\n"), value);
}
+/* Implementation of `siginfo' variable. */
+
+static const struct internalvar_funcs siginfo_funcs =
+{
+ siginfo_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_infrun (void)
{
@@ -7299,7 +7309,7 @@ enabled by default on some platforms."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+ create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
add_setshow_boolean_cmd ("observer", no_class,
&observer_mode_1, _("\
diff --git a/gdb/thread.c b/gdb/thread.c
index 97f283c..d361dd8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1439,7 +1439,8 @@ update_thread_list (void)
no thread is selected, or no threads exist. */
static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);
@@ -1450,6 +1451,15 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
/* Commands with a prefix of `thread'. */
struct cmd_list_element *thread_cmd_list = NULL;
+/* Implementation of `thread' variable. */
+
+static const struct internalvar_funcs thread_funcs =
+{
+ thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1495,5 +1505,5 @@ Show printing of thread events (such as thread start and exit)."), NULL,
show_print_thread_events,
&setprintlist, &showprintlist);
- create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 89f75b6..ac8fade 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4946,7 +4946,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
available. */
static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
@@ -5125,6 +5126,15 @@ traceframe_available_memory (VEC(mem_range_s) **result,
return 0;
}
+/* Implementation of `sdata' variable. */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
@@ -5135,7 +5145,7 @@ _initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);
traceframe_number = -1;
tracepoint_number = -1;
diff --git a/gdb/value.c b/gdb/value.c
index e8eb33f..9a384a5 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1577,7 +1577,14 @@ struct internalvar
struct value *value;
/* The call-back routine used with INTERNALVAR_MAKE_VALUE. */
- internalvar_make_value make_value;
+ struct
+ {
+ /* The functions to call. */
+ const struct internalvar_funcs *functions;
+
+ /* The function's user-data. */
+ void *data;
+ } make_value;
/* The internal function used with INTERNALVAR_FUNCTION. */
struct
@@ -1676,18 +1683,39 @@ create_internalvar (const char *name)
/* Create an internal variable with name NAME and register FUN as the
function that value_of_internalvar uses to create a value whenever
this variable is referenced. NAME should not normally include a
- dollar sign. */
+ dollar sign. DATA is passed uninterpreted to FUN when it is
+ called. CLEANUP, if not NULL, is called when the internal variable
+ is destroyed. It is passed DATA as its only argument. */
struct internalvar *
-create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data)
{
struct internalvar *var = create_internalvar (name);
var->kind = INTERNALVAR_MAKE_VALUE;
- var->u.make_value = fun;
+ var->u.make_value.functions = funcs;
+ var->u.make_value.data = data;
return var;
}
+/* See documentation in value.h. */
+
+int
+compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value)
+{
+ if (var->kind != INTERNALVAR_MAKE_VALUE
+ || var->u.make_value.functions->compile_to_ax == NULL)
+ return 0;
+
+ var->u.make_value.functions->compile_to_ax (var, expr, value,
+ var->u.make_value.data);
+ return 1;
+}
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
@@ -1760,7 +1788,8 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;
case INTERNALVAR_MAKE_VALUE:
- val = (*var->u.make_value) (gdbarch, var);
+ val = (*var->u.make_value.functions->make_value) (gdbarch, var,
+ var->u.make_value.data);
break;
default:
@@ -1956,6 +1985,11 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;
+ case INTERNALVAR_MAKE_VALUE:
+ if (var->u.make_value.functions->destroy != NULL)
+ var->u.make_value.functions->destroy (var->u.make_value.data);
+ break;
+
default:
break;
}
diff --git a/gdb/value.h b/gdb/value.h
index 3ce0f88..3e4e57f 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -733,10 +733,52 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
extern struct internalvar *create_internalvar (const char *name);
-typedef struct value * (*internalvar_make_value) (struct gdbarch *,
- struct internalvar *);
+/* An internalvar can be dynamically computed by supplying a vector of
+ function pointers to perform various operations. */
+
+struct internalvar_funcs
+{
+ /* Compute the value of the variable. The DATA argument passed to
+ the function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ struct value *(*make_value) (struct gdbarch *arch,
+ struct internalvar *var,
+ void *data);
+
+ /* Update the agent expression EXPR with bytecode to compute the
+ value. VALUE is the agent value we are updating. The DATA
+ argument passed to this function is the same argument that was
+ passed to `create_internalvar_type_lazy'. If this pointer is
+ NULL, then the internalvar cannot be compiled to an agent
+ expression. */
+
+ void (*compile_to_ax) (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ void *data);
+
+ /* If non-NULL, this is called to destroy DATA. The DATA argument
+ passed to this function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ void (*destroy) (void *data);
+};
+
extern struct internalvar *
- create_internalvar_type_lazy (char *name, internalvar_make_value fun);
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data);
+
+/* Compile an internal variable to an agent expression. VAR is the
+ variable to compile; EXPR and VALUE are the agent expression we are
+ updating. This will return 0 if there is no known way to compile
+ VAR, and 1 if VAR was successfully compiled. It may also throw an
+ exception on error. */
+
+extern int compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value);
extern struct internalvar *lookup_internalvar (const char *name);
diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6b84eff..a704599 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -268,7 +268,7 @@ static const struct lval_funcs tlb_value_funcs =
if there's no object available. */
static struct value *
-tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore)
{
if (target_has_stack && !ptid_equal (inferior_ptid, null_ptid))
{
@@ -428,6 +428,15 @@ init_w32_command_list (void)
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_windows_tdep;
+/* Implementation of `tlb' variable. */
+
+static const struct internalvar_funcs tlb_funcs =
+{
+ tlb_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_windows_tdep (void)
{
@@ -454,5 +463,5 @@ even if their meaning is unknown."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_tlb", tlb_make_value);
+ create_internalvar_type_lazy ("_tlb", &tlb_funcs, NULL);
}
--
1.7.6.5
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
` (3 preceding siblings ...)
2012-03-09 21:15 ` [PATCH 0/3] Implement support for SystemTap probes on userspace Tom Tromey
@ 2012-03-10 7:55 ` Eli Zaretskii
2012-03-10 8:55 ` Jan Kratochvil
2012-03-12 19:59 ` Tom Tromey
4 siblings, 2 replies; 27+ messages in thread
From: Eli Zaretskii @ 2012-03-10 7:55 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches, tromey
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Tom Tromey <tromey@redhat.com>
> Date: Fri, 09 Mar 2012 17:28:51 -0300
>
> After a long time reworking the patches, I am finally resubmitting them
> for review and, hopefully, inclusion.
Thanks!
> When you start a patched GDB debugging a binary which contains probes in
> it, you can get a list of the probes by using the new `info probes'
> command:
>
> sergio@psique ~/work/src/git/stap-patches/build-64/gdb $ ./gdb -q /tmp/stap-example
> (gdb) info probes
> Provider Name Where Semaphore Object
> teste m4 0x0000000000400505 0x00000000006009f8 /tmp/stap-example
> teste ps 0x00000000004004cd 0x00000000006009fc /tmp/stap-example
> teste two 0x0000000000400484 0x00000000006009f6 /tmp/stap-example
> teste two 0x0000000000400497 0x00000000006009f6 /tmp/stap-example
> teste user 0x00000000004004ad 0x00000000006009f4 /tmp/stap-example
May I suggest that the new command be called "info stap-probes"
instead? IMO, "probe" is much too general, and may conflict in the
future with some other feature that uses similar facilities or
terminology.
> As you can see above, there are 5 probes in the binary. We can now ask
> GDB to put a breakpoint in a probe, by using the new option `-p' or
> `-probe' in the `break' command:
>
> (gdb) b -probe m4
> Breakpoint 1 at 0x400505
Again, either "break -stap-probe" or even just "break -stap" would be
better, IMO.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
@ 2012-03-10 8:38 ` Eli Zaretskii
2012-03-10 16:56 ` Mark Kettenis
` (2 subsequent siblings)
3 siblings, 0 replies; 27+ messages in thread
From: Eli Zaretskii @ 2012-03-10 8:38 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches, tromey
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Tom Tromey <tromey@redhat.com>
> Date: Fri, 09 Mar 2012 17:33:21 -0300
>
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,10 @@
>
> *** Changes since GDB 7.4
>
> +* GDB now has support for SystemTap <sys/sdt.h> probes. You can set a
> + breakpoint using the new "-p" or "-probe" options and inspect the probe
> + arguments using the new $_probe_arg family of convenience variables.
I'd suggest to add here a URL where SystemTap is described.
> +@cindex sdt-probe
Not sure what this index entry is about. If we want or plan to add to
GDB support for SDT probes, there should be some general text here
explaining what SDT probes are and at least a cursory reference to a
couple of such existing facilities in various development
environments. In contrast, the text in this section is entirely
Linux- and SystemTap-centric. So having an "sdt-probe" index entry
pointing to here would be misleading, I think.
My preference would be to make this section more general, by adding
some minimal text explaining what is an SDT probe, and then mention
SystemTap as the SDT variety we support on GNU/Linux. Something like
"currently, SystemTap (http://....) probes are supported on
GNU/Linux".
> +You can examine the available @code{SystemTap} static probes using
> +@code{info probes}:
See my other mail where I suggest a more specific name for this
command. I could also go with "info sdt-probes", if we include in
this section the general explanation of SDT probes.
> +@table @code
> +@kindex info probes
> +@item info probes [@var{provider} [@var{name} [@var{objfile}]]]
We are using @r{[} and @r{]} in the @item lines that are part of
"@table @code", to have the brackets typeset in the "normal" Roman
typeface, instead of the @code typeface.
Also, the way you wrote this implies that "name" cannot be given
unless "provider" is also given, and similarly with "objfile". Is
this the intent?
> +If given, @var{provider} is a regular expression used to select which
> +providers to list. If omitted, all providers are listed.
Not "all providers", but "probes by all providers". (You don't list
the providers, you list the probes.)
Btw, I suggest to use @var{providers}, in plural here.
> +If given, @var{name} is a regular expression used to select which
> +probes to list. If omitted, all probes are listed.
This doesn't make clear what is tested for matching the regexp. I
suggest
If given, @var{names} is a regular expression to match against probe
names when selecting which probes to list. If omitted, probe names
are not considered when deciding whether to display them.
(I modified the second sentence because it's not really accurate to
say "all probes", due to filtering by "providers".)
> +These variables are always available, but attempts to access them at
> +any location other than a probe point will cause @value{GDBN} to give
> +an error.
"give an error message".
> +@cindex SystemTap static probe point
You already have a literally identical index entry in the section
where you describe "info probes". Here, I would suggest something
different, like
@cindex breakpoint at static probe point
> +@item -p|-probe @r{[}@var{objfile}:@r{]}@r{[}@var{provider}:@r{]}@var{name}
> +The @sc{gnu}/Linux tool @code{SystemTap} provides a way for
> +applications to embed static probes.
A cross-reference to "Static Probe Points" here is essential.
> This form of linespec specifies
> +the location of such a static probe. See
> +@uref{http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps}
> +for more information on static probes.
This URL should be in "Static Probe Points" instead.
In general, when you describe a feature, you should decide which of
the sections will be the main one describing it, and have all the info
there. The other places in the manual should only mention the name of
the feature and provide a cross-reference to that main section.
> +If @var{objfile} is given, only probes coming from that shared library
> +or executable are considered. If @var{provider} is given, then only
> +probes from that provider are considered.
Is this really different from "info probes", where these are regular
expressions?
Also, I think this should tell what happens if several probes match
the spec.
> +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{-p} 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.
This text should have an appropriate @cindex entry. Imagine that you
are a user of this facility, and you want to quickly find in the GDB
manual whether the semaphore is enabled or not. Whatever phrase you'd
think in that situation as something to look for in the index should
be here.
> +@item $_probe_argc
> +@itemx $_probe_arg0@dots{}$_probe_arg11
> +Arguments to a SystemTap static probe. @xref{Static Probe Points}.
If you accept my view to make the description of probe support more
general, this should not specifically mention SystemTap.
Also, you seem to be inconsistent wrt whether you use @code{SystemTap}
or just "SystemTap". Please pick one and stick to it.
> +@item $_probe_argc
> +Collects the number of arguments from the @code{SystemTap} probe at
> +which the tracepoint is located.
Same here.
> +@xref{Static Probe Points,,Static Probe Points}.
Not sure why you need the 3rd arg in this @xref, since it's identical
to the first one.
> +@item $_probe_arg@var{N}
> +Where @var{N} varies from 0 to 11. Collects the @var{N}th argument
The first sentence is not a complete sentence. I would simply drop
the "where" part.
Also, Please use @var{n}, not @var{N}, it looks nicer in print.
> +from the @code{SystemTap} probe at which the tracepoint is located.
> +@xref{Static Probe Points,,Static Probe Points}.
Same comment about this @xref.
> + add_info ("probes", info_probes_command, _("\
> +Show available static probes.\n\
> +Usage: info 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 match the executable or shared library name."));
^^^^^
"mathes", no?
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-10 7:55 ` Eli Zaretskii
@ 2012-03-10 8:55 ` Jan Kratochvil
2012-03-10 9:06 ` Eli Zaretskii
2012-03-12 19:59 ` Tom Tromey
1 sibling, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-03-10 8:55 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Sergio Durigan Junior, gdb-patches, tromey
On Sat, 10 Mar 2012 08:55:05 +0100, Eli Zaretskii wrote:
> > sergio@psique ~/work/src/git/stap-patches/build-64/gdb $ ./gdb -q /tmp/stap-example
> > (gdb) info probes
> > Provider Name Where Semaphore Object
> > teste m4 0x0000000000400505 0x00000000006009f8 /tmp/stap-example
> > teste ps 0x00000000004004cd 0x00000000006009fc /tmp/stap-example
> > teste two 0x0000000000400484 0x00000000006009f6 /tmp/stap-example
> > teste two 0x0000000000400497 0x00000000006009f6 /tmp/stap-example
> > teste user 0x00000000004004ad 0x00000000006009f4 /tmp/stap-example
>
> May I suggest that the new command be called "info stap-probes"
> instead? IMO, "probe" is much too general, and may conflict in the
> future with some other feature that uses similar facilities or
> terminology.
There can be "info probes stap" and "info probes foo" in the future with "info
probes" calling all the existing probe backends. Like "show" shows all
variables. (I have also "info auto-load" in this still but it has not yet been
posted.)
> > As you can see above, there are 5 probes in the binary. We can now ask
> > GDB to put a breakpoint in a probe, by using the new option `-p' or
> > `-probe' in the `break' command:
> >
> > (gdb) b -probe m4
> > Breakpoint 1 at 0x400505
>
> Again, either "break -stap-probe" or even just "break -stap" would be
> better, IMO.
Again -probe may try to find that probe in all the probe backends, later
extensible by -probe-stap and -probe-foo?
Before a real review, so it is a bikeshed.
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-10 8:55 ` Jan Kratochvil
@ 2012-03-10 9:06 ` Eli Zaretskii
2012-03-10 15:52 ` Sergio Durigan Junior
0 siblings, 1 reply; 27+ messages in thread
From: Eli Zaretskii @ 2012-03-10 9:06 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: sergiodj, gdb-patches, tromey
> Date: Sat, 10 Mar 2012 09:54:33 +0100
> From: Jan Kratochvil <jan.kratochvil@redhat.com>
> Cc: Sergio Durigan Junior <sergiodj@redhat.com>, gdb-patches@sourceware.org,
> tromey@redhat.com
>
> > May I suggest that the new command be called "info stap-probes"
> > instead? IMO, "probe" is much too general, and may conflict in the
> > future with some other feature that uses similar facilities or
> > terminology.
>
> There can be "info probes stap" and "info probes foo" in the future with "info
> probes" calling all the existing probe backends.
Works for me. Or maybe "info sdt-probes" that would cover all of the
varieties of this kind of probes, as in my other suggestion.
> > > (gdb) b -probe m4
> > > Breakpoint 1 at 0x400505
> >
> > Again, either "break -stap-probe" or even just "break -stap" would be
> > better, IMO.
>
> Again -probe may try to find that probe in all the probe backends, later
> extensible by -probe-stap and -probe-foo?
Could be. Or "break -std-probe", which is general enough to cover
several varieties, and yet less general than just "-probe".
Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-10 9:06 ` Eli Zaretskii
@ 2012-03-10 15:52 ` Sergio Durigan Junior
0 siblings, 0 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-10 15:52 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Jan Kratochvil, gdb-patches, tromey
On Saturday, March 10 2012, Eli Zaretskii wrote:
>> Date: Sat, 10 Mar 2012 09:54:33 +0100
>> From: Jan Kratochvil <jan.kratochvil@redhat.com>
>> Cc: Sergio Durigan Junior <sergiodj@redhat.com>, gdb-patches@sourceware.org,
>> tromey@redhat.com
>>
>> > May I suggest that the new command be called "info stap-probes"
>> > instead? IMO, "probe" is much too general, and may conflict in the
>> > future with some other feature that uses similar facilities or
>> > terminology.
>>
>> There can be "info probes stap" and "info probes foo" in the future with "info
>> probes" calling all the existing probe backends.
>
> Works for me. Or maybe "info sdt-probes" that would cover all of the
> varieties of this kind of probes, as in my other suggestion.
I don't really have a preference (though I lean towards Jan suggestion
because of how GDB already deals with such cases). So, which one do you
guys prefer?
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
2012-03-10 8:38 ` Eli Zaretskii
@ 2012-03-10 16:56 ` Mark Kettenis
2012-03-12 15:11 ` Tom Tromey
2012-03-10 19:22 ` Jan Kratochvil
2012-03-15 15:36 ` Pedro Alves
3 siblings, 1 reply; 27+ messages in thread
From: Mark Kettenis @ 2012-03-10 16:56 UTC (permalink / raw)
To: sergiodj; +Cc: gdb-patches, tromey
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Fri, 09 Mar 2012 17:33:21 -0300
>
> This is the second patch. It implements a bunch of new things needed to
> support SystemTap probes, for both arch-dependent and independent bits.
> There are new variables and methods for gdbarch, new files
> (stap-probe.[ch]), new methods for reading and handling SystemTap probes
> on elfread.c, adaptations on breakpoint.c to make the `break' command
> understand the `-p' and `-probe' arguments, and so on. It also includes
> documentation and testcases inclusions.
>
> Is this OK?
>
> gdb/ChangeLog
> 2012-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
> Tom Tromey <tromey@redhat.com>
>
> * Makefile.in (SFILES): Add `stap-probe'.
> (COMMON_OBS): Likewise.
> (HFILES_NO_SRCDIR): Likewise.
> * NEWS: Mention support for SystemTap probes.
> * amd64-linux-tdep.c (amd64_linux_init_abi): Initializing proper
> fields used by SystemTap probes' arguments parser.
> * arm-linux-tdep.c: Including headers needed to perform the parsing
> of SystemTap probes' arguments.
> (arm_stap_is_single_operand): New function.
> (arm_stap_parse_special_token): Likewise.
> (arm_linux_init_abi): Initializing proper fields used by SystemTap
> probes' arguments parser.
> * ax-gdb.c (require_rvalue): Removing static declaration.
> (gen_expr): Likewise.
> * ax-gdb.h (gen_expr): Declaring function.
> (require_rvalue): Likewise.
> * breakpoint.c: Include `gdb_regex.h' and `stap-probe.h'.
> (bkpt_stap_probe_breakpoint_ops): New variable.
> (modify_semaphore): New function.
> (insert_bp_location): Call `modify_semaphore'.
> (remove_breakpoint_1): Likewise.
> (momentary_breakpoint_from_master): Use the `semaphore' value.
> (add_location_to_breakpoint): Likewise.
> (break_command_1): Using proper breakpoint_ops according to the
> argument passed by user in the command line.
> (bkpt_stap_probe_create_sals_from_address): New function.
> (bkpt_stap_probe_decode_linespec): Likewise.
> (initialize_breakpoint_ops): Initializing breakpoint_ops from
> SystemTap probes.
> * breakpoint.h (struct bp_location) <semaphore>: New field.
> (modify_semaphore): New function.
> * cli-utils.c (skip_spaces_const): New function.
> (extract_arg): Likewise.
> * cli-utils.h (skip_spaces_const): Likewise.
> (extract_arg): Likewise.
> * coffread.c (coff_sym_fns): Add `sym_probe_fns' value.
> * dbxread.c (aout_sym_fns): Likewise.
> * elfread.c: Include `stap-probe.h' and `arch-utils.h'.
> (stap_probe_key): New variable.
> (struct stap_probe_per_objfile): New struct.
> (handle_probe): New function.
> (STAP_BASE_SECTION_NAME): New define.
> (get_base_address_1): New function.
> (get_base_address): Likewise.
> (elf_get_probes): Likewise.
> (elf_get_probe_argument_count): Likewise.
> (elf_evaluate_probe_argument): Likewise.
> (elf_compile_to_ax): Likewise.
> (elf_symfile_relocate_probe): Likewise.
> (stap_probe_key_free): Likewise.
> (elf_probe_fns): New variable.
> (elf_sym_fns): Add `sym_probe_fns' value.
> (elf_sym_fns_lazy_psyms): Likewise.
> (elf_sym_fns_gdb_index): Likewise.
> (_initialize_elfread): Initialize objfile cache for SystemTap
> probes.
> * gdbarch.c: Regenerate.
> * gdbarch.h: Regenerate.
> * gdbarch.sh (stap_integer_prefix): New variable.
> (stap_integer_suffix): Likewise.
> (stap_register_prefix): Likewise.
> (stap_register_suffix): Likewise.
> (stap_register_indirection_prefix): Likewise.
> (stap_register_indirection_suffix): Likewise.
> (stap_gdb_register_prefix): Likewise.
> (stap_gdb_register_suffix): Likewise.
> (stap_is_single_operand): New function.
> (stap_parse_special_token): Likewise.
> (struct stap_parse_info): Forward declaration.
> * i386-linux-tdep.c (i386_linux_init_abi): Initializing proper
> fields used by SystemTap probes' arguments parser.
> * i386-tdep.c: Including headers needed to perform the parsing
> of SystemTap probes' arguments.
> (i386_stap_is_single_operand): New function.
> (i386_stap_parse_special_token): Likewise.
> * i386-tdep.h (i386_stap_is_single_operand): Likewise.
> (i386_stap_parse_special_token): Likewise.
As far as I can tell SystemTap is Linux-specific. So I'd think its
support should go completely in Linux-specific -tdep.c files.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
2012-03-10 8:38 ` Eli Zaretskii
2012-03-10 16:56 ` Mark Kettenis
@ 2012-03-10 19:22 ` Jan Kratochvil
2012-03-12 20:37 ` Tom Tromey
2012-03-15 15:36 ` Pedro Alves
3 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-03-10 19:22 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey
Hi Sergio,
On Fri, 09 Mar 2012 21:33:21 +0100, Sergio Durigan Junior wrote:
[...]
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -60,6 +60,8 @@
> #include "jit.h"
> #include "xml-syscall.h"
> #include "parser-defs.h"
> +#include "gdb_regex.h"
> +#include "stap-probe.h"
I believe there was intended some abstraction, more talked about it elsewhere,
breakpoint.c should only include some (nonexistent) "probe.h", not
"stap-probe.h".
> #include "cli/cli-utils.h"
> #include "continuations.h"
> #include "stack.h"
> @@ -290,6 +292,9 @@ static struct breakpoint_ops momentary_breakpoint_ops;
> breakpoints. */
> struct breakpoint_ops bkpt_breakpoint_ops;
>
> +/* Breakpoints set on SystemTap probes. */
> +static struct breakpoint_ops bkpt_stap_probe_breakpoint_ops;
> +
> /* A reference-counted struct command_line. This lets multiple
> breakpoints share a single command list. */
> struct counted_command_line
> @@ -1926,6 +1931,40 @@ unduplicated_should_be_inserted (struct bp_location *bl)
> return result;
> }
>
> +/* See the comment in breakpoint.h. */
> +
> +void
> +modify_semaphore (struct bp_location *loc, int set)
> +{
> + struct gdbarch *arch = loc->gdbarch;
> + gdb_byte bytes[sizeof (LONGEST)];
> + /* The ABI specifies "unsigned short". */
> + struct type *type = builtin_type (arch)->builtin_unsigned_short;
> + CORE_ADDR address = loc->semaphore;
> + ULONGEST value;
> +
> + if (address == 0)
> + return;
> +
> + /* Swallow errors. */
Could here be a reason why it is valid?
> + if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
> + return;
> +
> + value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
> + gdbarch_byte_order (arch));
> + /* Note that we explicitly don't worry about overflow or
> + underflow. */
> + if (set)
> + ++value;
> + else
> + --value;
> +
> + store_unsigned_integer (bytes, TYPE_LENGTH (type),
> + gdbarch_byte_order (arch), value);
> +
> + target_write_memory (address, bytes, TYPE_LENGTH (type));
And here again, why not to check errors?
> +}
> +
> /* Parses a conditional described by an expression COND into an
> agent expression bytecode suitable for evaluation
> by the bytecode interpreter. Return NULL if there was
[...]
> --- a/gdb/cli/cli-utils.c
> +++ b/gdb/cli/cli-utils.c
[...]
> @@ -245,3 +257,32 @@ remove_trailing_whitespace (const char *start, char *s)
>
> return s;
> }
> +
> +/* See documentation in cli-utils.h. */
> +
> +char *
> +extract_arg (char **arg)
> +{
> + char *result, *copy;
> +
> + if (!*arg)
> + return NULL;
> +
> + /* Find the start of the argument. */
> + *arg = skip_spaces (*arg);
> + if (! **arg)
Excessive space according to GDB Coding Style.
> + return NULL;
> + result = *arg;
> +
> + /* Find the end of the argument. */
> + *arg = skip_to_space (*arg + 1);
> +
> + if (result == *arg)
> + return NULL;
> +
> + copy = xmalloc (*arg - result + 1);
> + memcpy (copy, result, *arg - result);
> + copy[*arg - result] = '\0';
> +
> + return copy;
> +}
[...]
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -36,6 +36,8 @@
> #include "demangle.h"
> #include "psympriv.h"
> #include "filenames.h"
> +#include "stap-probe.h"
> +#include "arch-utils.h"
> #include "gdbtypes.h"
> #include "value.h"
> #include "infcall.h"
> @@ -60,6 +62,21 @@ struct elfinfo
> asection *mdebugsect; /* Section pointer for .mdebug section */
> };
>
> +/* Per-objfile data for SystemTap probe info. */
> +
> +static const struct objfile_data *stap_probe_key = NULL;
> +
> +/* Per-objfile data about SystemTap probes. */
> +
> +struct stap_probe_per_objfile
> + {
> + /* The number of probes in this objfile. */
> + int stap_num_probes;
> +
> + /* The probes themselves. */
nitpick:
/* Pointer to array of STAP_NUM_PROBES elements with the probes. */
> + struct stap_probe *probes;
> + };
> +
> static void free_elfinfo (void *);
>
> /* Minimal symbols located at the GOT entries for .plt - that is the real
> @@ -1579,7 +1596,273 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
> complaint (&symfile_complaints,
> _("elf/stab section information missing for %s"), filename);
> }
> +
> +/* Helper function that parses the information contained in a
> + SystemTap's probe. Basically, the information consists in:
> +
> + - Probe's PC address;
> + - Link-time section address of `.stapsdt.base' section;
> + - Link-time address of the semaphore variable, or ZERO if the
> + probe doesn't have an associated semaphore;
> + - Probe's provider name;
> + - Probe's name;
> + - Probe's argument format. */
> +
> +static void
> +handle_probe (struct objfile *objfile, struct sdt_note *el,
> + struct stap_probe *ret, CORE_ADDR base)
> +{
> + bfd *abfd = objfile->obfd;
> + int size = bfd_get_arch_size (abfd) / 8;
> + struct gdbarch *gdbarch = get_objfile_arch (objfile);
> + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
> + CORE_ADDR base_ref;
> +
> + ret->gdbarch = gdbarch;
> +
> + /* Provider and the name of the probe. */
> + ret->provider = &el->data[3 * size];
> + ret->name = memchr (ret->provider, '\0',
> + (char *) el->data + el->size - ret->provider);
> + /* Making sure there is a name. */
> + if (!ret->name)
> + {
> + complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
> + objfile->name);
> + ret->provider = NULL;
> + ret->name = NULL;
> + }
> + else
> + ++ret->name;
> +
> + /* Retrieving the probe's address. */
> + ret->address = extract_typed_address (&el->data[0], ptr_type);
Empty line before comment.
> + /* Link-time sh_addr of `.stapsdt.base' section. */
> + base_ref = extract_typed_address (&el->data[size], ptr_type);
Empty line before comment.
> + /* Semaphore address. */
> + ret->sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
> +
> + ret->address += (ANOFFSET (objfile->section_offsets,
> + SECT_OFF_TEXT (objfile))
> + + base - base_ref);
> + if (ret->sem_addr)
> + ret->sem_addr += (ANOFFSET (objfile->section_offsets,
> + SECT_OFF_DATA (objfile))
> + + base - base_ref);
> +
> + /* Arguments. We can only extract the argument format if there is a valid
> + name for this probe. */
> + if (ret->name)
> + {
> + ret->args = memchr (ret->name, '\0',
> + (char *) el->data + el->size - ret->name);
> +
> + if (ret->args != NULL)
> + ++ret->args;
> + if (ret->args == NULL
> + || (memchr (ret->args, '\0',
> + (char *) el->data + el->size - ret->name)
> + != el->data + el->size - 1))
Here would be missing '(char *) ' for el->data. But it is no longer needed as
you made DATA gdb_byte[] now. But in such case please drop the no longer
needed '(char *) ' casts above.
> + {
> + complaint (&symfile_complaints, _("corrupt probe when reading `%s'"),
> + objfile->name);
> + ret->args = NULL;
> + }
> + }
> + else
> + ret->args = NULL;
> +}
> +
> +/* The name of the SystemTap section where we will find information about
> + the probes. */
> +
> +#define STAP_BASE_SECTION_NAME ".stapsdt.base"
Such #defines are usually at the top of file (under #includes).
> +
> +/* Helper function which tries to find the base address of the SystemTap
> + base section named STAP_BASE_SECTION_NAME. */
> +
> +static void
> +get_base_address_1 (bfd *abfd, asection *sect, void *obj)
> +{
> + bfd_vma *base = (bfd_vma *) obj;
> +
> + if (*base == (bfd_vma) -1
> + && (sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
> + && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
> + *base = sect->vma;
> +}
> +
> +/* Helper function which iterates over every section in the BFD file,
> + trying to find the base address of the SystemTap base section.
> + Returns the section address if found, or -1 otherwise. */
> +
> +static bfd_vma
> +get_base_address (bfd *obfd)
> +{
> + bfd_vma base = (bfd_vma) -1;
(1) Special values (such as 0xfff...fff are discouraged).
(2) I do not see a reason here for it, there will be just one
STAP_BASE_SECTION_NAME section anyway, if there are multiple such sections
it is already some undefined state and it does not matter if one chooses
the first one or the last one and finally if the secion is not found the
code mishandles the 0xfff...fff value anyway (which it should not).
I would put some error/warning there and making turning that `void *' into
'asection *' may handle the special not-found value for error/warning even
easy without new parameter struct.
> +
> + bfd_map_over_sections (obfd, get_base_address_1, (void *) &base);
> +
> + return base;
> +}
> +
> +/* Implementation of `sym_get_probes', as documented in symfile.h. */
> +
> +static struct stap_probe *
> +elf_get_probes (struct objfile *objfile, int *num_probes)
> +{
> + struct stap_probe *ret = NULL;
> + struct stap_probe_per_objfile *probes_per_objfile;
> +
> + /* Initially, no probes. */
> + *num_probes = 0;
> +
> + /* Have we parsed this objfile's probes already? */
> + probes_per_objfile
> + = (struct stap_probe_per_objfile *) objfile_data (objfile,
> + stap_probe_key);
Excessive cast.
> +
> + if (!probes_per_objfile)
> + {
> + /* If we are here, then this is the first time we are parsing the
> + probe's information. We basically have to count how many probes
> + the objfile has, and then fill in the necessary information
> + for each one. */
> +
> + bfd *obfd = objfile->obfd;
> + bfd_vma base = get_base_address (obfd);
> + struct sdt_note *iter;
> + int i;
> + int n = 0;
> +
> + if (! elf_tdata (obfd)->sdt_note_head)
> + /* There isn't any probe here. */
> + return NULL;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + /* Allocating space for probe info. */
> + for (iter = elf_tdata (obfd)->sdt_note_head;
> + iter;
> + iter = iter->next, ++n);
> +
> + ret = xcalloc (n, sizeof (struct stap_probe));
> +
> + /* Parsing each probe's information. */
> + for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
> + iter;
> + iter = iter->next, i++)
> + /* We first have to handle all the information about the
> + probe which is present in the section. */
> + handle_probe (objfile, iter, &ret[i], base);
> +
> + /* Creating a cache for these probes in the objfile's registry. */
> + probes_per_objfile = xmalloc (sizeof (struct stap_probe_per_objfile));
> +
> + probes_per_objfile->stap_num_probes = n;
> + probes_per_objfile->probes = ret;
> +
> + set_objfile_data (objfile, stap_probe_key, probes_per_objfile);
> + }
> + else
> + ret = probes_per_objfile->probes;
> +
> + *num_probes = probes_per_objfile->stap_num_probes;
> +
> + return ret;
> +}
> +
> +/* Implementation of `sym_get_probe_argument_count', as documented in
> + symfile.h. */
> +
> +static int
> +elf_get_probe_argument_count (struct objfile *objfile,
> + struct stap_probe *probe)
> +{
> + const char *pargs = probe->args;
> +
> + if (!pargs || !*pargs || *pargs == ':')
> + /* No arguments. */
> + return 0;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + return stap_get_probe_argument_count (probe);
> +}
> +
> +/* Implementation of `sym_evaluate_probe_argument', as documented in
> + symfile.h. */
> +
> +static struct value *
> +elf_evaluate_probe_argument (struct objfile *objfile,
> + struct stap_probe *probe,
> + struct frame_info *frame,
> + int n)
> +{
> + return stap_evaluate_probe_argument (objfile, probe, frame, n);
> +}
> +
> +/* Implementation of `sym_compile_to_ax', as documented in symfile.h. */
> +
> +static void
> +elf_compile_to_ax (struct objfile *objfile,
> + struct stap_probe *probe,
> + struct agent_expr *expr,
> + struct axs_value *value,
> + int n)
> +{
Some comment that current GDB can parse only the SystemTap kind of probes from
ELF, this is why this function is so trivial.
But more about the abstraction I write elsewhere.
> + stap_compile_to_ax (objfile, probe, expr, value, n);
> +}
> +
> +/* Implementation of `sym_relocate_probe', as documented in symfile.h. */
> +
> +static void
> +elf_symfile_relocate_probe (struct objfile *objfile,
> + struct section_offsets *new_offsets,
> + struct section_offsets *delta)
> +{
> + int i;
> + struct stap_probe_per_objfile *p
> + = (struct stap_probe_per_objfile *) objfile_data (objfile,
> + stap_probe_key);
> +
> + if (!p)
> + /* No probe to relocate. */
> + return;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + for (i = 0; i < p->stap_num_probes; i++)
> + {
> + p->probes[i].address += ANOFFSET (delta, SECT_OFF_TEXT (objfile));
> + if (p->probes[i].sem_addr)
> + p->probes[i].sem_addr += ANOFFSET (delta, SECT_OFF_DATA (objfile));
> + }
> +}
> +
> +/* Helper function used to free the space allocated for storing SystemTap
> + probe information. */
> +
> +static void
> +stap_probe_key_free (struct objfile *objfile, void *d)
> +{
> + int i;
> + struct stap_probe_per_objfile *data = (struct stap_probe_per_objfile *) d;
Excessive cast.
> +
> + for (i = 0; i < data->stap_num_probes; i++)
> + stap_free_parsed_args (data->probes[i].parsed_args);
> + xfree (data->probes);
> + xfree (data);
> +}
> +
> \f
> +
> +/* Implementation `sym_probe_fns', as documented in symfile.h. */
> +
> +static const struct sym_probe_fns elf_probe_fns =
> +{
> + elf_get_probes, /* sym_get_probes */
> + elf_get_probe_argument_count, /* sym_get_probe_argument_count */
> + elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */
> + elf_compile_to_ax, /* sym_compile_to_ax */
> + elf_symfile_relocate_probe, /* sym_relocate_probe */
> +};
> +
> /* Register that we are able to handle ELF object file formats. */
>
> static const struct sym_fns elf_sym_fns =
[...]
> --- a/gdb/i386-tdep.c
> +++ b/gdb/i386-tdep.c
> @@ -58,8 +58,14 @@
> #include "features/i386/i386-avx.c"
> #include "features/i386/i386-mmx.c"
>
> +#include "stap-probe.h"
> #include "ax.h"
> #include "ax-gdb.h"
> +#include "user-regs.h"
> +#include "cli/cli-utils.h"
> +#include "expression.h"
> +#include "parser-defs.h"
> +#include <ctype.h>
>
> /* Register names. */
>
> @@ -7251,6 +7257,312 @@ i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
> return valid_p;
> }
>
> +int
> +i386_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
Missing function comment.
> +{
> + return (*s == '$' /* Literal number. */
> + || (isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement. */
> + || (*s == '(' && s[1] == '%') /* Register indirection. */
> + || (*s == '%' && isalpha (s[1]))); /* Register access. */
> +}
> +
> +int
> +i386_stap_parse_special_token (struct gdbarch *gdbarch,
> + struct stap_parse_info *p)
Missing function comment.
> +{
> + const char *s = p->arg;
> +
> + /* In order to parse special tokens, we use a state-machine that go
> + through every known token and try to get a match. */
> + enum
> + {
> + TRIPLET,
> + THREE_ARG_DISPLACEMENT,
> + DONE
> + } current_state;
> +
> + current_state = TRIPLET;
> +
> + /* The special tokens to be parsed here are:
> +
> + - `register base + (register index * size) + offset', as represented
> + in `(%rcx,%rax,8)', or `[OFFSET](BASE_REG,INDEX_REG[,SIZE])'.
> +
> + - Operands of the form `-8+3+1(%rbp)', which must be interpreted as
> + `*(-8 + 3 - 1 + (void *) $eax)'. */
> +
> + while (current_state != DONE)
> + {
> + const char *s = p->arg;
> +
> + switch (current_state)
> + {
> + case TRIPLET:
> + {
> + if (isdigit (*s) || *s == '-' || *s == '+')
> + {
> + int got_minus[3];
> + int i;
> + long displacements[3];
> + const char *start;
> + char *regname;
> + int len;
> + struct stoken str;
> +
> + got_minus[0] = 0;
> + if (*s == '+')
> + ++s;
> + else if (*s == '-')
> + {
> + ++s;
> + got_minus[0] = 1;
> + }
> +
> + displacements[0] = strtol (s, (char **) &s, 10);
> +
> + if (*s != '+' && *s != '-')
> + /* We are not dealing with a triplet. */
> + break;
> +
> + got_minus[1] = 0;
> + if (*s == '+')
> + ++s;
> + else
> + {
> + ++s;
> + got_minus[1] = 1;
> + }
> +
> + displacements[1] = strtol (s, (char **) &s, 10);
> +
> + if (*s != '+' && *s != '-')
> + /* We are not dealing with a triplet. */
> + break;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + got_minus[2] = 0;
> + if (*s == '+')
> + ++s;
> + else
> + {
> + ++s;
> + got_minus[2] = 1;
> + }
> +
> + displacements[2] = strtol (s, (char **) &s, 10);
> +
> + if (*s != '(' || s[1] != '%')
> + break;
> +
> + s += 2;
> + start = s;
> +
> + while (isalnum (*s))
> + ++s;
> +
> + if (*s++ != ')')
> + break;
> +
> + len = s - start;
> + regname = alloca (len + 1);
> +
> + strncpy (regname, start, len);
> + regname[len] = '\0';
> +
> + if (user_reg_map_name_to_regnum (gdbarch,
> + regname, len) == -1)
> + error (_("Invalid register name `%s' "
> + "on expression `%s'."),
> + regname, p->saved_arg);
> +
> + for (i = 0; i < 3; i++)
> + {
> + write_exp_elt_opcode (OP_LONG);
> + write_exp_elt_type
> + (builtin_type (gdbarch)->builtin_long);
> + write_exp_elt_longcst (displacements[i]);
> + write_exp_elt_opcode (OP_LONG);
> + if (got_minus[i])
> + write_exp_elt_opcode (UNOP_NEG);
> + }
> +
> + write_exp_elt_opcode (OP_REGISTER);
> + str.ptr = regname;
> + str.length = len;
> + write_exp_string (str);
> + write_exp_elt_opcode (OP_REGISTER);
> +
> + write_exp_elt_opcode (UNOP_CAST);
> + write_exp_elt_type (builtin_type (gdbarch)->builtin_data_ptr);
> + write_exp_elt_opcode (UNOP_CAST);
> +
> + write_exp_elt_opcode (BINOP_ADD);
> + write_exp_elt_opcode (BINOP_ADD);
> + write_exp_elt_opcode (BINOP_ADD);
> +
> + write_exp_elt_opcode (UNOP_CAST);
> + write_exp_elt_type (lookup_pointer_type (p->arg_type));
> + write_exp_elt_opcode (UNOP_CAST);
> +
> + write_exp_elt_opcode (UNOP_IND);
> +
> + p->arg = s;
> +
> + return 1;
> + }
> + break;
> + }
[...]
> --- a/gdb/ppc-linux-tdep.c
> +++ b/gdb/ppc-linux-tdep.c
[...]
> @@ -1276,6 +1284,65 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
> }
> }
>
> +static int
> +ppc_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
Missing function comment.
> +{
> + return (*s == 'i' /* Literal number. */
> + || (isdigit (*s) && s[1] == '('
> + && isdigit (s[2])) /* Displacement. */
> + || (*s == '(' && isdigit (s[1])) /* Register indirection. */
> + || isdigit (*s)); /* Register value. */
> +}
> +
> +static int
> +ppc_stap_parse_special_token (struct gdbarch *gdbarch,
> + struct stap_parse_info *p)
Missing function comment.
> +{
> + if (isdigit (*p->arg))
> + {
> + /* This temporary pointer is needed because we have to do a lookahead.
> + We could be dealing with a register displacement, and in such case
> + we would not need to do anything. */
> + const char *s = p->arg;
> + char *regname;
> + int len;
> + struct stoken str;
> +
> + while (isdigit (*s))
> + ++s;
> +
> + if (*s == '(')
> + /* It is a register displacement indeed. Returning 0 means we are
> + deferring the treatment of this case to the generic parser. */
> + return 0;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + len = s - p->arg;
> + regname = alloca (len + 2);
> + regname[0] = 'r';
> +
> + strncpy (regname + 1, p->arg, len);
> + ++len;
> + regname[len] = '\0';
> +
> + if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
> + error (_("Invalid register name `%s' on expression `%s'."),
> + regname, p->saved_arg);
> +
> + write_exp_elt_opcode (OP_REGISTER);
> + str.ptr = regname;
> + str.length = len;
> + write_exp_string (str);
> + write_exp_elt_opcode (OP_REGISTER);
> +
> + p->arg = s;
> + }
> + else
> + /* All the other tokens should be handled correctly by the generic
> + parser. */
> + return 0;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + return 1;
> +}
>
> /* Cell/B.E. active SPE context tracking support. */
>
> @@ -1593,6 +1660,15 @@ ppc_linux_init_abi (struct gdbarch_info info,
> /* Get the syscall number from the arch's register. */
> set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
>
> + /* SystemTap functions. */
> + set_gdbarch_stap_integer_prefix (gdbarch, "i");
> + set_gdbarch_stap_register_indirection_prefix (gdbarch, "(");
> + set_gdbarch_stap_register_indirection_suffix (gdbarch, ")");
> + set_gdbarch_stap_gdb_register_prefix (gdbarch, "r");
> + set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand);
> + set_gdbarch_stap_parse_special_token (gdbarch,
> + ppc_stap_parse_special_token);
> +
> if (tdep->wordsize == 4)
> {
> /* Until November 2001, gcc did not comply with the 32 bit SysV
> diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
> index ac0c526..661d90c 100644
> --- a/gdb/s390-tdep.c
> +++ b/gdb/s390-tdep.c
> @@ -55,6 +55,12 @@
> #include "features/s390x-linux64v1.c"
> #include "features/s390x-linux64v2.c"
>
> +#include "stap-probe.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
> +#include "user-regs.h"
> +#include "cli/cli-utils.h"
> +#include <ctype.h>
>
> /* The tdep structure. */
>
> @@ -2953,6 +2959,15 @@ s390_address_class_name_to_type_flags (struct gdbarch *gdbarch,
> return 0;
> }
>
> +static int
> +s390_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
Missing function comment.
> +{
> + return ((isdigit (*s) && s[1] == '(' && s[2] == '%') /* Displacement
> + or indirection. */
> + || *s == '%' /* Register access. */
> + || isdigit (*s)); /* Literal number. */
> +}
> +
> /* Set up gdbarch struct. */
>
> static struct gdbarch *
[...]
> --- /dev/null
> +++ b/gdb/stap-probe.c
> @@ -0,0 +1,1689 @@
> +/* SystemTap probe support for GDB.
> +
> + Copyright (C) 2011 Free Software Foundation, Inc.
Update the year.
> +
> + 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.
[...]
> + default:
> + internal_error (__FILE__, __LINE__,
> + _("Undefined bitness for probe."));
> + break;
> + }
> +}
> +
> +static void
> +stap_parse_register_operand (struct stap_parse_info *p)
Missing function comment.
> +{
> + /* Simple flag to indicate whether we have seen a minus signal before
> + certain number. */
> + int got_minus = 0;
Empty line before comment.
> + /* Flags to indicate whether this register access is being displaced and/or
> + indirected. */
> + int disp_p = 0, indirect_p = 0;
> + struct gdbarch *gdbarch = p->gdbarch;
Empty line before comment.
> + /* Needed to generate the register name as a part of an expression. */
> + struct stoken str;
Empty line before comment.
> + /* Variables used to extract the register name from the probe's
> + argument. */
> + const char *start;
> + char *regname;
> + int len;
> +
> + /* Prefixes for the parser. */
> + const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
> + const char *reg_ind_prefix
> + = gdbarch_stap_register_indirection_prefix (gdbarch);
> + const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
> + int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
> + int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
> + int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0;
> +
> + /* Suffixes for the parser. */
> + const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
> + const char *reg_ind_suffix
> + = gdbarch_stap_register_indirection_suffix (gdbarch);
> + const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
> + int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
> + int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
> + int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0;
> +
> + /* Checking for a displacement argument. */
> + if (*p->arg == '+')
> + /* If it's a plus sign, we don't need to do anything, just advance the
> + pointer. */
> + ++p->arg;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + if (*p->arg == '-')
> + {
> + got_minus = 1;
> + ++p->arg;
> + }
> +
> + if (isdigit (*p->arg))
> + {
> + /* The value of the displacement. */
> + long displacement;
> +
> + disp_p = 1;
> + displacement = strtol (p->arg, (char **) &p->arg, 10);
> +
> + /* Generating the expression for the displacement. */
> + write_exp_elt_opcode (OP_LONG);
> + write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
> + write_exp_elt_longcst (displacement);
> + write_exp_elt_opcode (OP_LONG);
> + if (got_minus)
> + write_exp_elt_opcode (UNOP_NEG);
> + }
> +
> + /* Getting rid of register indirection prefix. */
> + if (reg_ind_prefix
> + && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0)
> + {
> + indirect_p = 1;
> + p->arg += reg_ind_prefix_len;
> + }
> +
> + if (disp_p && !indirect_p)
> + error (_("Invalid register displacement syntax on expression `%s'."),
> + p->saved_arg);
> +
> + /* Getting rid of register prefix. */
> + if (reg_prefix && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
> + p->arg += reg_prefix_len;
> +
> + /* Now we should have only the register name. Let's extract it and get
> + the associated number. */
> + start = p->arg;
> +
> + /* We assume the register name is composed by letters and numbers. */
> + while (isalnum (*p->arg))
> + ++p->arg;
> +
> + len = p->arg - start;
> +
> + regname = alloca (len + gdb_reg_prefix_len + gdb_reg_suffix_len + 1);
> + regname[0] = '\0';
> +
> + /* We only add the GDB's register prefix/suffix if we are dealing with
> + a numeric register. */
> + if (gdb_reg_prefix && isdigit (*start))
> + {
> + strncpy (regname, gdb_reg_prefix, gdb_reg_prefix_len);
> + strncpy (regname + gdb_reg_prefix_len, start, len);
> +
> + if (gdb_reg_suffix)
> + strncpy (regname + gdb_reg_prefix_len + len,
> + gdb_reg_suffix, gdb_reg_suffix_len);
> +
> + len += gdb_reg_prefix_len + gdb_reg_suffix_len;
> + }
> + else
> + strncpy (regname, start, len);
> +
> + regname[len] = '\0';
Empty line before comment.
> + /* Is this a valid register name? */
> + if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
> + error (_("Invalid register name `%s' on expression `%s'."),
> + regname, p->saved_arg);
> +
> + write_exp_elt_opcode (OP_REGISTER);
> + str.ptr = regname;
> + str.length = len;
> + write_exp_string (str);
> + write_exp_elt_opcode (OP_REGISTER);
> +
> + if (indirect_p)
> + {
> + if (disp_p)
> + write_exp_elt_opcode (BINOP_ADD);
> +
> + /* Casting to the expected type. */
> + write_exp_elt_opcode (UNOP_CAST);
> + write_exp_elt_type (lookup_pointer_type (p->arg_type));
> + write_exp_elt_opcode (UNOP_CAST);
> +
> + write_exp_elt_opcode (UNOP_IND);
> + }
> +
> + /* Getting rid of the register name suffix. */
> + if (reg_suffix)
> + {
> + if (strncmp (p->arg, reg_suffix, reg_suffix_len) != 0)
> + error (_("Missing register name suffix `%s' on expression `%s'."),
> + reg_suffix, p->saved_arg);
> +
> + p->arg += reg_suffix_len;
> + }
> +
> + /* Getting rid of the register indirection suffix. */
> + if (indirect_p && reg_ind_suffix)
> + {
> + if (strncmp (p->arg, reg_ind_suffix, reg_ind_suffix_len) != 0)
> + error (_("Missing indirection suffix `%s' on expression `%s'."),
> + reg_ind_suffix, p->saved_arg);
> +
> + p->arg += reg_ind_suffix_len;
> + }
> +}
> +
> +static void
> +stap_parse_single_operand (struct stap_parse_info *p)
Missing function comment.
> +{
> + struct gdbarch *gdbarch = p->gdbarch;
Empty line before comment.
> + /* Prefixes for the parser. */
> + const char *const_prefix = gdbarch_stap_integer_prefix (gdbarch);
> + const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch);
> + const char *reg_ind_prefix
> + = gdbarch_stap_register_indirection_prefix (gdbarch);
> + int const_prefix_len = const_prefix ? strlen (const_prefix) : 0;
> + int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0;
> + int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0;
> +
> + /* Suffixes for the parser. */
> + const char *const_suffix = gdbarch_stap_integer_suffix (gdbarch);
> + const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch);
> + const char *reg_ind_suffix
> + = gdbarch_stap_register_indirection_suffix (gdbarch);
> + int const_suffix_len = const_suffix ? strlen (const_suffix) : 0;
> + int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0;
> + int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0;
> +
> + /* We first try to parse this token as a "special token". */
> + if (gdbarch_stap_parse_special_token_p (gdbarch))
> + {
> + int ret = gdbarch_stap_parse_special_token (gdbarch, p);
> +
> + if (ret)
> + /* If the return value of the above function is not zero,
> + it means it successfully parsed the special token.
> +
> + If it is NULL, we try to parse it using our method. */
> + return;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> + }
> +
> + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+')
> + {
> + char c = *p->arg;
Empty line before comment.
> + /* We use this variable to do a lookahead. */
> + const char *tmp = p->arg;
> +
> + ++tmp;
> +
> + /* This is an unary operation. Here is a list of allowed tokens
> + here:
> +
> + - numeric literal;
> + - number (from register displacement)
> + - subexpression (beginning with `(')
> +
> + We handle the register displacement here, and the other cases
> + recursively. */
> + if (isdigit (*tmp))
> + {
> + int number = strtol (tmp, (char **) &tmp, 10);
> +
> + if (p->inside_paren_p)
> + tmp = skip_spaces_const (tmp);
> + if (!reg_ind_prefix
> + || strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
> + goto not_displacement;
Please no goto. You can invert the condition and change 'else' below into new
'if' with some check for 'tmp == p->arg + 1' or even a new helper variable,
but no goto.
> +
> + /* If we are here, it means it is a displacement. The only
> + operations allowed here are `-' and `+'. */
> + if (c == '~')
> + error (_("Invalid operator `%c' for register displacement "
> + "on expression `%s'."), c, p->saved_arg);
> +
> + stap_parse_register_operand (p);
> + }
> + else
> +not_displacement:
> + {
> + p->arg = tmp;
> + stap_parse_argument_conditionally (p);
> + if (c == '-')
> + write_exp_elt_opcode (UNOP_NEG);
> + else if (c == '~')
> + write_exp_elt_opcode (UNOP_COMPLEMENT);
> + }
> + }
> + else if (isdigit (*p->arg))
> + {
> + /* A temporary variable, needed for lookahead. */
> + const char *tmp = p->arg;
> + long number;
> +
> + /* We can be dealing with a numeric constant (if `const_prefix' is
> + NULL), or with a register displacement. */
> + number = strtol (tmp, (char **) &tmp, 10);
> +
> + if (p->inside_paren_p)
> + tmp = skip_spaces_const (tmp);
> + if (!const_prefix && reg_ind_prefix
> + && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0)
> + {
> + /* We are dealing with a numeric constant. */
> + write_exp_elt_opcode (OP_LONG);
> + write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
> + write_exp_elt_longcst (number);
> + write_exp_elt_opcode (OP_LONG);
> +
> + p->arg = tmp;
> +
> + if (const_suffix)
> + {
> + if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
> + p->arg += const_suffix_len;
> + else
> + error (_("Invalid constant suffix on expression `%s'."),
> + p->saved_arg);
> + }
> + }
> + else if (reg_ind_prefix
> + && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) == 0)
> + stap_parse_register_operand (p);
> + else
> + error (_("Unknown numeric token on expression `%s'."),
> + p->saved_arg);
> + }
> + else if (const_prefix
> + && strncmp (p->arg, const_prefix, const_prefix_len) == 0)
> + {
> + /* We are dealing with a numeric constant. */
> + long number;
> +
> + p->arg += const_prefix_len;
> + number = strtol (p->arg, (char **) &p->arg, 10);
> +
> + write_exp_elt_opcode (OP_LONG);
> + write_exp_elt_type (builtin_type (gdbarch)->builtin_long);
> + write_exp_elt_longcst (number);
> + write_exp_elt_opcode (OP_LONG);
> +
> + if (const_suffix)
> + {
> + if (strncmp (p->arg, const_suffix, const_suffix_len) == 0)
> + p->arg += const_suffix_len;
> + else
> + error (_("Invalid constant suffix on expression `%s'."),
> + p->saved_arg);
> + }
> + }
> + else if ((reg_prefix
> + && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0)
> + || (reg_ind_prefix
> + && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0))
> + stap_parse_register_operand (p);
> + else
> + error (_("Operator `%c' not recognized on expression `%s'."),
> + *p->arg, p->saved_arg);
> +}
> +
> +static void
> +stap_parse_argument_conditionally (struct stap_parse_info *p)
Missing function comment.
> +{
> + if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+' /* Unary. */
> + || isdigit (*p->arg)
> + || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
> + stap_parse_single_operand (p);
> + else if (*p->arg == '(')
> + {
> + /* We are dealing with a parenthesized operand. It means we
> + have to parse it as it was a separate expression, without
> + left-side or precedence. */
> + ++p->arg;
> + p->arg = skip_spaces_const (p->arg);
> + ++p->inside_paren_p;
> +
> + stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
> +
> + --p->inside_paren_p;
> + if (*p->arg != ')')
> + error (_("Missign close-paren on expression `%s'."),
> + p->saved_arg);
> +
> + ++p->arg;
> + if (p->inside_paren_p)
> + p->arg = skip_spaces_const (p->arg);
> + }
> + else
> + error (_("Cannot parse expression `%s'."), p->saved_arg);
> +}
> +
> +static void
> +stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
> + enum stap_operand_prec prec)
Missing function comment.
> +{
> + /* This is an operator-precedence parser.
> +
> + We work with left- and right-sides of expressions, and
> + parse them depending on the precedence of the operators
> + we find. */
> +
> + if (p->inside_paren_p)
> + p->arg = skip_spaces_const (p->arg);
> +
> + if (!has_lhs)
> + /* We were called without a left-side, either because this is the
> + first call, or because we were called to parse a parenthesized
> + expression. It doesn't really matter; we have to parse the
> + left-side in order to continue the process. */
> + stap_parse_argument_conditionally (p);
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + /* Start to parse the right-side, and to "join" left and right sides
> + depending on the operation specified.
> +
> + This loop shall continue until we run out of characters in the input,
> + or until we find a close-parenthesis, which means that we've reached
> + the end of a sub-expression. */
> + while (p->arg && *p->arg && *p->arg != ')' && !isspace (*p->arg))
> + {
> + const char *tmp_exp_buf;
> + enum exp_opcode opcode;
> + enum stap_operand_prec cur_prec;
> +
> + if (!stap_is_operator (*p->arg))
> + error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
> + p->saved_arg);
> +
> + /* We have to save the current value of the expression buffer because
> + the `stap_get_opcode' modifies it in order to get the current
> + operator. If this operator's precedence is lower than PREC, we
> + should return and not advance the expression buffer pointer. */
> + tmp_exp_buf = p->arg;
> + stap_get_opcode (&tmp_exp_buf, &opcode);
> +
> + cur_prec = stap_get_operator_prec (opcode);
> + if (cur_prec < prec)
> + /* If the precedence of the operator that we are seeing now is
> + lower than the precedence of the first operator seen before
> + this parsing process began, it means we should stop parsing
> + and return. */
> + break;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + p->arg = tmp_exp_buf;
> + if (p->inside_paren_p)
> + p->arg = skip_spaces_const (p->arg);
> +
> + /* Parse the right-side of the expression. */
> + stap_parse_argument_conditionally (p);
> +
> + /* While we still have operators, try to parse another
> + right-side, but using the current right-side as a left-side. */
> + while (*p->arg && stap_is_operator (*p->arg))
> + {
> + enum exp_opcode lookahead_opcode;
> + enum stap_operand_prec lookahead_prec;
> +
> + /* Saving the current expression buffer position. The explanation
> + is the same as above. */
> + tmp_exp_buf = p->arg;
> + stap_get_opcode (&tmp_exp_buf, &lookahead_opcode);
> + lookahead_prec = stap_get_operator_prec (lookahead_opcode);
> +
> + if (lookahead_prec <= prec)
> + /* If we are dealing with an operator whose precedence is lower
> + than the first one, just abandon the attempt. */
> + break;
These multiple lines should be in { block } according to new GDB Coding Style rule.
> +
> + /* Parse the right-side of the expression, but since we already
> + have a left-side at this point, set `has_lhs' to 1. */
> + stap_parse_argument_1 (p, 1, lookahead_prec);
> + }
> +
> + write_exp_elt_opcode (opcode);
> + }
> +}
> +
> +/* Parse a probe's argument.
> +
> + Assuming that:
> +
> + LP = literal integer prefix
> + LS = literal integer suffix
> +
> + RP = register prefix
> + RS = register suffix
> +
> + RIP = register indirection prefix
> + RIS = register indirection suffix
> +
> + This routine assumes that arguments' tokens are of the form:
> +
> + - [LP] NUMBER [LS]
> + - [RP] REGISTER [RS]
> + - [RIP] [RP] REGISTER [RS] [RIS]
> + - If we find a number without LP, we try to parse it as a literal integer
> + constant (if LP == NULL), or as a register displacement.
> + - We count parenthesis, and only skip whitespaces if we are inside them.
> + - If we find an operator, we skip it.
> +
> + This function can also call a special function that will try to match
> + unknown tokens. It will return 1 if the argument has been parsed
> + successfully, or zero otherwise. */
> +
> +static int
> +stap_parse_argument (const char **arg, struct type *atype,
> + struct gdbarch *gdbarch)
> +{
> + struct stap_parse_info p;
> + volatile struct gdb_exception e;
> +
> + /* We need to initialize the expression buffer, in order to begin
> + our parsing efforts. The language here does not matter, since we
> + are using our own parser. */
> + initialize_expout (10, current_language, gdbarch);
Put back_to = make_cleanup (free_current_contents, &expout); here.
> +
> + p.saved_arg = *arg;
> + p.arg = *arg;
> + p.arg_type = atype;
> + p.gdbarch = gdbarch;
> + p.inside_paren_p = 0;
> +
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
> + }
> + if (e.reason < 0)
> + {
> + xfree (expout);
> + return 0;
> + }
And drop TRY_CATCH magic here with just discard_cleanups (back_to);
here (therefore if stap_parse_argument_1 does not throw).
Make possible this function throws. Make the function return always
non-NULL 'struct expression *' so that the callers no longer have to deal with
the global variable mess underneath.
Then the caller will have TRY_CATCH and it can display by complaint that
e.message which happened. In general if we have exceptions they are fine to
use IMO. Hopefully the exception system will be more sane in the future.
Maybe this is more a personal preference of this function redesign, feel free
to discuss it more.
> +
> + gdb_assert (p.inside_paren_p == 0);
> +
> + /* Casting the final expression to the appropriate type. */
> + write_exp_elt_opcode (UNOP_CAST);
> + write_exp_elt_type (atype);
> + write_exp_elt_opcode (UNOP_CAST);
> +
> + reallocate_expout ();
> +
> + p.arg = skip_spaces_const (p.arg);
> + *arg = p.arg;
> +
> + return 1;
> +}
> +
> +/* Helper function which is responsible for freeing the space allocated to
> + hold information about a probe's arguments. */
> +
> +static void
> +stap_free_args_info (void *args_info_ptr)
> +{
> + struct stap_args_info *a = (struct stap_args_info *) args_info_ptr;
> + int i;
> +
> + for (i = 0; i < a->n_args; i++)
> + xfree (a->args[i].aexpr);
> +
> + xfree (a->args);
> + xfree (a);
> +}
> +
> +/* Function which parses an argument string from PROBE, correctly splitting
> + the arguments and storing their information in properly ways.
> +
> + Consider the following argument string (x86 syntax):
> +
> + `4@%eax 4@$10'
> +
> + We have two arguments, `%eax' and `$10', both with 32-bit unsigned bitness.
> + This function basically handles them, properly filling some structures with
> + this information. */
> +
> +static void
> +stap_parse_probe_arguments (struct stap_probe *probe)
> +{
> + struct stap_args_info *args_info;
> + struct cleanup *back_to;
> + const char *cur = probe->args;
> + int current_arg = -1;
Empty line before comment.
> + /* This is a state-machine parser, which means we will always be
> + in a known state when parsing an argument. The state could be
> + either `NEW_ARG' if we are parsing a new argument, `BITNESS' if
> + we are parsing the bitness-definition part (i.e., `4@'), or
> + `PARSE_ARG' if we are actually parsing the argument part. */
> + enum
> + {
> + NEW_ARG,
> + BITNESS,
> + PARSE_ARG,
> + } current_state;
> +
> + /* For now, we assume everything is not going to work. */
> + probe->parsed_args = &dummy_stap_args_info;
> +
> + if (!cur || !*cur || *cur == ':')
> + return;
> +
> + args_info = xmalloc (sizeof (struct stap_args_info));
> + args_info->n_args = 0;
> + back_to = make_cleanup (stap_free_args_info, args_info);
> + args_info->args = xcalloc (STAP_MAX_ARGS, sizeof (struct stap_probe_arg));
> +
> + /* Ok, let's start. */
Excessive comment.
> + current_state = NEW_ARG;
> +
> + while (*cur)
> + {
> + switch (current_state)
> + {
> + case NEW_ARG:
> + ++current_arg;
> +
> + if (current_arg >= STAP_MAX_ARGS)
> + {
> + complaint (&symfile_complaints,
> + _("probe `%s' has more arguments than the maximum "
> + "allowed"), probe->name);
> + do_cleanups (back_to);
> + return;
> + }
> +
> + current_state = BITNESS;
> + break;
> +
> + case BITNESS:
> + {
> + enum stap_arg_bitness b;
> + int got_minus = 0;
> +
> + /* We expect to find something like:
> +
> + N@OP
> +
> + Where `N' can be [+,-][4,8]. This is not mandatory, so
> + we check it here. If we don't find it, go to the next
> + state. */
> + if ((*cur == '-' && cur[1] && cur[2] != '@')
> + && cur[1] != '@')
> + {
> + current_state = PARSE_ARG;
> + args_info->args[current_arg].bitness
> + = STAP_ARG_BITNESS_UNDEFINED;
> + break;
> + }
> +
> + if (*cur == '-')
> + {
> + /* Discard the `-'. */
> + ++cur;
> + got_minus = 1;
> + }
> +
> + if (*cur == '4')
> + b = got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
> + : STAP_ARG_BITNESS_32BIT_UNSIGNED;
Here should be parentheses according to GNU Coding Style.
> + else if (*cur == '8')
> + b = got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
> + : STAP_ARG_BITNESS_64BIT_UNSIGNED;
Here should be parentheses according to GNU Coding Style.
> + else
> + {
> + /* We have an error, because we don't expect anything
> + except 4 and 8. */
> + complaint (&symfile_complaints,
> + _("unrecognized bitness `%c' for probe `%s'"),
> + *cur, probe->name);
> + do_cleanups (back_to);
> + return;
> + }
> +
> + args_info->args[current_arg].bitness = b;
> + args_info->args[current_arg].atype
> + = stap_get_expected_argument_type (probe->gdbarch, b);
Empty line before comment.
> + /* Discard the number and the `@' sign. */
> + cur += 2;
Empty line before comment.
> + /* Move on. */
> + current_state = PARSE_ARG;
> + }
> + break;
> +
> + case PARSE_ARG:
> + {
> + if (!stap_parse_argument (&cur,
> + args_info->args[current_arg].atype,
> + probe->gdbarch))
> + {
> + /* We have tried to parse this argument, but it's
> + malformed. This is an error. */
> + complaint (&symfile_complaints,
> + _("malformed argument for probe `%s'"),
> + probe->name);
> + do_cleanups (back_to);
> + return;
> + }
> +
> + if (stap_expression_debug)
> + dump_raw_expression (expout, gdb_stdlog,
> + "before conversion to prefix form");
> +
> + prefixify_expression (expout);
> +
> + if (stap_expression_debug)
> + dump_prefix_expression (expout, gdb_stdlog);
> +
> + args_info->args[current_arg].aexpr = expout;
> + expout = NULL;
> +
> + ++args_info->n_args;
Empty line before comment.
> + /* Start it over again. */
> + cur = skip_spaces_const (cur);
> + current_state = NEW_ARG;
> + }
> + break;
> + }
> +
> + if (!*cur && current_state != NEW_ARG)
> + {
> + /* We reached the end of the argument string, but we're
> + still in the middle of the process of parsing an argument.
> + It means the argument string is malformed. */
> + complaint (&symfile_complaints,
> + _("malformed argument for probe `%s'"),
> + probe->name);
> + do_cleanups (back_to);
> + return;
> + }
> + }
> +
> + args_info->args = xrealloc (args_info->args,
> + args_info->n_args
> + * sizeof (struct stap_probe_arg));
> + args_info->probe = probe;
> +
> + probe->parsed_args = args_info;
> +
> + discard_cleanups (back_to);
> +}
[...]
> +}
> +
> +struct value *
> +stap_safe_evaluate_at_pc (struct frame_info *frame, int n)
Missing function comment.
> +{
> + struct stap_probe *probe;
> + struct objfile *objfile;
> + int n_probes;
> +
> + probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
> + if (!probe)
> + return NULL;
> + gdb_assert (objfile->sf && objfile->sf->sym_probe_fns);
> +
> + n_probes
> + = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
> + probe);
> + if (n >= n_probes)
> + return NULL;
> +
> + return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
> + probe,
> + frame,
> + n);
> +}
> +
> +/* This function frees the space allocated to hold information about
> + the probe's parsed arguments. */
> +
> +void
> +stap_free_parsed_args (struct stap_args_info *parsed_args)
> +{
> + int i;
> +
> + if (!parsed_args
> + || parsed_args == &dummy_stap_args_info
> + || parsed_args->n_args == 0)
> + return;
> +
> + for (i = 0; i < parsed_args->n_args; i++)
> + xfree (parsed_args->args[i].aexpr);
> +
> + xfree (parsed_args->args);
> + xfree (parsed_args);
> +}
> +
> +/* A utility structure. A VEC of these is built when handling "info
> + probes". */
> +
> +struct stap_probe_and_objfile
> +{
> + /* The probe. */
> + struct stap_probe *probe;
Empty line before comment.
> + /* The probe's objfile. */
> + struct objfile *objfile;
> +};
> +
> +typedef struct stap_probe_and_objfile stap_entry;
> +DEF_VEC_O (stap_entry);
> +
> +/* A helper function for collect_probes that compiles a regexp and
> + throws an exception on error. This installs a cleanup to free the
> + resulting pattern on success. If RX is NULL, this does nothing. */
> +
> +static void
> +compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
> +{
> + int code;
> +
> + if (!rx)
> + return;
> +
> + code = regcomp (pattern, rx, REG_NOSUB);
> + if (code == 0)
> + make_regfree_cleanup (pattern);
> + else
> + {
> + char *err = get_regcomp_error (code, pattern);
> +
> + make_cleanup (xfree, err);
> + error (_("%s: %s"), message, err);
Excessive localization _().
> + }
> +}
> +
> +/* Make a vector of probes matching OBJNAME, PROVIDER, and PROBE.
> + Each argument is a regexp, or NULL, which matches anything. */
> +
> +static VEC (stap_entry) *
> +collect_probes (char *objname, char *provider, char *probe)
> +{
> + struct objfile *objfile;
> + VEC (stap_entry) *result = NULL;
> + struct cleanup *cleanup;
> + regex_t obj_pat, prov_pat, probe_pat;
> +
> + cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
> +
> + compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
> + compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
> + compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
> +
> + ALL_OBJFILES (objfile)
> + {
> + struct stap_probe *probes;
> + int i, num_probes;
> +
> + if (! objfile->sf || ! objfile->sf->sym_probe_fns)
> + continue;
> +
> + if (objname)
> + {
> + if (regexec (&obj_pat, objfile->name, 0, NULL, 0) != 0)
> + continue;
> + }
> +
> + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
> + for (i = 0; i < num_probes; ++i)
> + {
> + stap_entry entry;
> +
> + if (provider)
> + {
> + if (regexec (&prov_pat, probes[i].provider, 0, NULL, 0) != 0)
> + continue;
> + }
> +
> + if (probe)
> + {
> + if (regexec (&probe_pat, probes[i].name, 0, NULL, 0) != 0)
> + continue;
> + }
> +
> + entry.probe = &probes[i];
> + entry.objfile = objfile;
> + VEC_safe_push (stap_entry, result, &entry);
> + }
> + }
> +
> + discard_cleanups (cleanup);
Here you leak PROV_PAT, PROBE_PAT and OBJ_PAT.
> + return result;
> +}
> +
> +/* A qsort comparison function for stap_entry objects. */
> +
> +static int
> +compare_entries (const void *a, const void *b)
> +{
> + const stap_entry *ea = a;
> + const stap_entry *eb = b;
> + int v;
> +
> + v = strcmp (ea->probe->provider, eb->probe->provider);
handle_probe can create NULL probe->provider or NULL probe->name etc. But
other code like this one will crash on it.
I believe such non-valid probes rather should be dropped during parsing.
Sorry if I missed it is already handled somehow?
> + if (v)
> + return v;
> +
> + v = strcmp (ea->probe->name, eb->probe->name);
> + if (v)
> + return v;
> +
> + if (ea->probe->address < eb->probe->address)
> + return -1;
> + if (ea->probe->address > eb->probe->address)
> + return 1;
> +
> + return strcmp (ea->objfile->name, eb->objfile->name);
> +}
> +
> +/* Implementation of the "info probes" command. */
> +
> +static void
> +info_probes_command (char *arg, int from_tty)
> +{
> + char *provider, *probe = NULL, *objname = NULL;
> + struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
> + VEC (stap_entry) *items;
> + int i, addr_width, any_found;
> + stap_entry *entry;
> +
> + provider = extract_arg (&arg);
> + if (provider)
> + {
> + make_cleanup (xfree, provider);
> +
> + probe = extract_arg (&arg);
> + if (probe)
> + {
> + make_cleanup (xfree, probe);
> +
> + objname = extract_arg (&arg);
> + if (objname)
> + make_cleanup (xfree, objname);
> + }
> + }
> +
> + items = collect_probes (objname, provider, probe);
> + make_cleanup (VEC_cleanup (stap_entry), &items);
> + make_cleanup_ui_out_table_begin_end (current_uiout, 5,
> + VEC_length (stap_entry, items),
> + "SystemTapProbes");
> +
> + if (! VEC_empty (stap_entry, items))
> + qsort (VEC_address (stap_entry, items),
> + VEC_length (stap_entry, items),
> + sizeof (stap_entry),
> + compare_entries);
> +
> + addr_width = 4 + (gdbarch_ptr_bit (get_current_arch ()) / 4);
> +
> + ui_out_table_header (current_uiout, 10, ui_left, "provider", _("Provider"));
> + ui_out_table_header (current_uiout, 10, ui_left, "name", _("Name"));
> + ui_out_table_header (current_uiout, addr_width - 1, ui_left, "addr", _("Where"));
> + ui_out_table_header (current_uiout, addr_width - 1, ui_left, "semaphore",
> + _("Semaphore"));
> + ui_out_table_header (current_uiout, 30, ui_left, "object", _("Object"));
> + ui_out_table_body (current_uiout);
> +
> + for (i = 0; VEC_iterate (stap_entry, items, i, entry); ++i)
> + {
> + struct cleanup *inner;
> +
> + inner = make_cleanup_ui_out_tuple_begin_end (current_uiout, "probe");
> +
> + ui_out_field_string (current_uiout, "provider", entry->probe->provider);
> + ui_out_field_string (current_uiout, "name", entry->probe->name);
> + ui_out_field_core_addr (current_uiout, "addr", get_current_arch (),
> + entry->probe->address);
> + if (entry->probe->sem_addr == 0)
> + ui_out_field_skip (current_uiout, "semaphore");
> + else
> + ui_out_field_core_addr (current_uiout, "semaphore", get_current_arch (),
> + entry->probe->sem_addr);
> + ui_out_field_string (current_uiout, "object", entry->objfile->name);
> + ui_out_text (current_uiout, "\n");
> +
> + do_cleanups (inner);
> + }
> +
> + any_found = ! VEC_empty (stap_entry, items);
Excessive space after ! according to GDB Coding Style.
> + do_cleanups (cleanup);
> +
> + if (! any_found)
> + ui_out_message (current_uiout, 0, _("No probes matched.\n"));
> +}
> +
> +\f
> +
> +/* See definition in stap-probe.h. */
> +
> +VEC (stap_probe_p) *
> +find_probes_in_objfile (struct objfile *objfile,
> + const char *provider,
> + const char *name)
> +{
> + struct stap_probe *probes;
> + int i, num_probes;
> + VEC (stap_probe_p) *result = NULL;
> +
> + if (! objfile->sf || ! objfile->sf->sym_probe_fns)
> + return NULL;
> +
> + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
> + for (i = 0; i < num_probes; ++i)
> + {
> + if (strcmp (probes[i].provider, provider) != 0)
> + continue;
> +
> + if (strcmp (probes[i].name, name) != 0)
> + continue;
> +
> + VEC_safe_push (stap_probe_p, result, &probes[i]);
> + }
> +
> + return result;
> +}
> +
> +/* See definition in stap-probe.h. */
> +
> +struct symtabs_and_lines
> +parse_stap_probe (char **argptr, struct linespec_result *canonical)
> +{
> + char *arg_start, *arg_end, *arg;
> + char *objfile_name = NULL, *provider = NULL, *name, *p;
> + struct cleanup *cleanup;
> + struct symtabs_and_lines result;
> + struct objfile *objfile;
> + struct program_space *pspace;
> +
> + result.sals = NULL;
> + result.nelts = 0;
> +
> + arg_start = *argptr;
Empty line before comment.
> + /* The caller ensured that this starts with `-p' or `-probe'. */
> + gdb_assert (arg_start
> + && ((strncmp (arg_start, "-p", 2) == 0
> + && isspace (arg_start[2]))
> + || (strncmp (arg_start, "-probe", 6) == 0
> + && isspace (arg_start[6]))));
> +
> + if (strncmp (arg_start, "-probe", 6) == 0)
> + arg_end = arg_start + 6;
> + else
> + arg_end = arg_start + 2;
> + arg_end = skip_spaces (arg_end);
> +
> + if (!*arg_end)
> + error (_("argument to `%s' missing"),
> + strncmp (arg_start, "-probe", 6) == 0 ? "-probe" : "-p");
> +
> + arg = arg_end;
> + arg_end = skip_to_space (arg_end);
> +
> + /* We make a copy here so we can write over parts with impunity. */
> + arg = savestring (arg, arg_end - arg);
> + cleanup = make_cleanup (xfree, arg);
> +
> + /* Extract each word from the argument, separated by ":"s. */
> + p = strchr (arg, ':');
> + if (p == NULL)
> + {
> + /* This is `-p name'. */
> + name = arg;
> + }
> + else
> + {
> + char *hold = p + 1;
> +
> + *p = '\0';
> + p = strchr (hold, ':');
> + if (p == NULL)
> + {
> + /* This is `-p provider:name'. */
> + provider = arg;
> + name = hold;
> + }
> + else
> + {
> + /* This is `-p objfile:provider:name'. */
> + *p = '\0';
> + objfile_name = arg;
> + provider = hold;
> + name = p + 1;
> + }
> + }
> +
> + if (*name == '\0')
> + error (_("no probe name specified"));
> + if (provider && *provider == '\0')
> + error (_("invalid provider name"));
> + if (objfile_name && *objfile_name == '\0')
> + error (_("invalid objfile name"));
> +
> + ALL_PSPACES (pspace)
> + {
I would find this { block } and its 2 space indentation excessive.
> + ALL_PSPACE_OBJFILES (pspace, objfile)
> + {
> + struct stap_probe *probes;
> + int i, num_probes;
> +
> + if (! objfile->sf || ! objfile->sf->sym_probe_fns)
> + continue;
> +
> + if (objfile_name
> + && FILENAME_CMP (objfile->name, objfile_name) != 0
> + && FILENAME_CMP (lbasename (objfile->name), objfile_name) != 0)
> + continue;
> +
> + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile,
> + &num_probes);
> + for (i = 0; i < num_probes; ++i)
> + {
> + struct symtab_and_line *sal;
> +
> + if (provider && strcmp (probes[i].provider, provider) != 0)
> + continue;
> +
> + if (strcmp (probes[i].name, name) != 0)
> + continue;
> +
> + ++result.nelts;
> + result.sals = xrealloc (result.sals,
> + result.nelts
> + * sizeof (struct symtab_and_line));
> + sal = &result.sals[result.nelts - 1];
> +
> + init_sal (sal);
> +
> + sal->pc = probes[i].address;
> + sal->explicit_pc = 1;
> + sal->section = find_pc_overlay (sal->pc);
> + sal->pspace = current_program_space;
Here should be pspace;
> + sal->semaphore = probes[i].sem_addr;
> + }
> + }
> + }
> +
> + if (result.nelts == 0)
> + {
> + throw_error (NOT_FOUND_ERROR,
> + _("No probe matching objfile=`%s', provider=`%s', name=`%s'"),
> + objfile_name ? objfile_name : _("<any>"),
> + provider ? provider : _("<any>"),
> + name);
> + }
> +
> + if (canonical)
> + {
> + canonical->special_display = 1;
> + canonical->pre_expanded = 1;
> + canonical->addr_string = savestring (*argptr, arg_end - *argptr);
> + }
> +
> + *argptr = arg_end;
> + do_cleanups (cleanup);
> +
> + return result;
> +}
> +
> +\f
> +
> +/* See definition in stap-probe.h. */
> +
> +struct stap_probe *
> +find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
> +{
> + struct objfile *objfile;
> +
> + ALL_OBJFILES (objfile)
> + {
> + struct stap_probe *probes;
> + int i, num_probes;
> + stap_entry entry;
> +
> + if (! objfile->sf || ! objfile->sf->sym_probe_fns)
Excessive space after ! according to GDB Coding Style.
> + continue;
> +
> + /* If this proves too inefficient, we can replace with a hash. */
> + probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile, &num_probes);
> + for (i = 0; i < num_probes; ++i)
> + {
> + if (probes[i].address == pc)
> + {
> + *objfile_out = objfile;
> + return &probes[i];
> + }
> + }
> + }
> +
> + return NULL;
> +}
> +
> +/* 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 objfile *objfile;
> + struct stap_probe *pc_probe;
> + int n_probes;
> +
> + /* SEL==-1 means "_probe_argc". */
/* SEL == -1 ... */
> + gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
> +
> + pc_probe = find_probe_by_pc (pc, &objfile);
> + if (pc_probe == NULL)
> + error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> +
> + n_probes
> + = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
> + pc_probe);
> + if (sel == -1)
> + return value_from_longest (builtin_type (arch)->builtin_int, n_probes);
> +
> + if (sel >= n_probes)
> + error (_("Invalid probe argument %d -- probe has %d arguments available"),
> + sel, n_probes);
> +
> + return objfile->sf->sym_probe_fns->sym_evaluate_probe_argument (objfile,
> + pc_probe,
> + frame, sel);
> +}
> +
> +/* 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 objfile *objfile;
> + struct stap_probe *pc_probe;
> + int n_probes;
> +
> + /* SEL==-1 means "_probe_argc". */
> + gdb_assert (sel >= -1 && sel <= STAP_MAX_ARGS);
> +
> + pc_probe = find_probe_by_pc (pc, &objfile);
> + if (pc_probe == NULL)
> + error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
> +
> + n_probes
> + = objfile->sf->sym_probe_fns->sym_get_probe_argument_count (objfile,
> + pc_probe);
> + if (sel == -1)
> + {
> + value->kind = axs_rvalue;
> + value->type = builtin_type (expr->gdbarch)->builtin_int;
> + ax_const_l (expr, n_probes);
> + return;
> + }
> +
> + gdb_assert (sel >= 0);
> + if (sel >= n_probes)
> + error (_("Invalid probe argument %d -- probe has %d arguments available"),
> + sel, n_probes);
> +
> + objfile->sf->sym_probe_fns->sym_compile_to_ax (objfile, pc_probe,
> + expr, value, sel);
> +}
> +
> +\f
> +
> +/* Implementation of `$_probe_arg*' set of variables. */
> +
> +static const struct internalvar_funcs probe_funcs =
> +{
> + compute_probe_arg,
> + compile_probe_arg,
> + NULL
> +};
My only serious concern about this patch is some missing abstraction. These
PROBE_FUNCS seem to be SystemTap-indepdent but the backeng-independent
compile_probe_arg already deals with 'struct stap_probe'. Any reference to
'struct stap_probe' should have been only in elf_compile_to_ax.
Moreover I would still more see to drop [patch 1/3], call just
compute_probe_arg which returns lazy lval_computed struct value * which
provides new struct lval_funcs member which can return `struct expression *'
and generic code can call gen_expr on its own. There is no need for special
internalvar_funcs->compile_to_ax member.
internalvar_funcs->destroy can be also replaced by lval_funcs->free_closure.
> +
> +void _initialize_stap_probe (void);
> +
> +void
> +_initialize_stap_probe (void)
> +{
> + add_info ("probes", info_probes_command, _("\
> +Show available static probes.\n\
> +Usage: info 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 match the executable or shared library name."));
> +
> + add_setshow_zinteger_cmd ("stap-expression", class_maintenance,
> + &stap_expression_debug,
> + _("Set SystemTap expression debugging."),
> + _("Show SystemTap expression debugging."),
> + _("When non-zero, the internal representation "
> + "of SystemTap expressions will be printed."),
> + NULL,
> + 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);
> +}
> diff --git a/gdb/stap-probe.h b/gdb/stap-probe.h
> new file mode 100644
> index 0000000..9b6dc7a
> --- /dev/null
> +++ b/gdb/stap-probe.h
> @@ -0,0 +1,144 @@
> +/* SystemTap probe support for GDB.
> +
> + Copyright (C) 2011 Free Software Foundation, Inc.
Update the year.
> +
> + 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.
[...]
> --- a/gdb/symfile.h
> +++ b/gdb/symfile.h
> @@ -29,6 +29,11 @@ struct objfile;
> struct obj_section;
> struct obstack;
> struct block;
> +struct stap_probe;
> +struct value;
> +struct frame_info;
> +struct agent_expr;
> +struct axs_value;
>
> /* Comparison function for symbol look ups. */
>
> @@ -297,6 +302,52 @@ struct quick_symbol_functions
> int need_fullname);
> };
>
> +/* Structure of functions used for SystemTap probe support. If one of
> + these functions is provided, all must be. */
> +
> +struct sym_probe_fns
> +{
> + /* If non-NULL, return an array of SystemTap probe objects. The
> + number of objects is returned in *NUM_PROBES. */
I would also say explicitly:
The returned value does not have to be freed and it has lifetime of
the OBJFILE.
> + struct stap_probe *(*sym_get_probes) (struct objfile *,
> + int *num_probes);
> +
> + /* Return the number of arguments available to PROBE. PROBE will
> + have come from a call to this objfile's sym_get_probes method.
> + If you provide an implementation of sym_get_probes, you must
> + implement this method as well. */
> + int (*sym_get_probe_argument_count) (struct objfile *objfile,
> + struct stap_probe *probe);
> +
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/stap-probe.c
> @@ -0,0 +1,108 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2011 Free Software Foundation, Inc.
Update the year.
> +
> + 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.
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/stap-probe.exp
> @@ -0,0 +1,187 @@
> +# Copyright (C) 2011 Free Software Foundation, Inc.
Update the year.
> +
> +# 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.
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.trace/stap-trace.c
> @@ -0,0 +1,71 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2011 Free Software Foundation, Inc.
Update the year.
> +
> + 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.
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.trace/stap-trace.exp
> @@ -0,0 +1,129 @@
> +# Copyright 2011
> +# Free Software Foundation, Inc.
Update the year. Join the lines.
> +
> +# 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.
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-10 16:56 ` Mark Kettenis
@ 2012-03-12 15:11 ` Tom Tromey
2012-03-13 8:58 ` Mark Kettenis
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-03-12 15:11 UTC (permalink / raw)
To: Mark Kettenis; +Cc: sergiodj, gdb-patches
>>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
Mark> As far as I can tell SystemTap is Linux-specific. So I'd think its
Mark> support should go completely in Linux-specific -tdep.c files.
sdt.h is really more like an ELF feature.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 0/3] Implement support for SystemTap probes on userspace
2012-03-10 7:55 ` Eli Zaretskii
2012-03-10 8:55 ` Jan Kratochvil
@ 2012-03-12 19:59 ` Tom Tromey
1 sibling, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2012-03-12 19:59 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: Sergio Durigan Junior, gdb-patches
>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
Eli> May I suggest that the new command be called "info stap-probes"
Eli> instead? IMO, "probe" is much too general, and may conflict in the
Eli> future with some other feature that uses similar facilities or
Eli> terminology.
I think this change would make it seem like these probe points are
somehow less generic than UST static markers from the gdb point of view
-- but they are not, in fact they are more generic because they aren't
restricted to just being used in tracepoints.
We did look at unifying the support between UST and sdt.h probes, but
this seemed not very doable.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-10 19:22 ` Jan Kratochvil
@ 2012-03-12 20:37 ` Tom Tromey
2012-03-12 23:15 ` Jan Kratochvil
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-03-12 20:37 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Sergio Durigan Junior, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Thanks for the thorough and detailed review. I have a few comments.
Jan> I believe there was intended some abstraction, more talked about it
Jan> elsewhere, breakpoint.c should only include some (nonexistent)
Jan> "probe.h", not "stap-probe.h".
What did you have in mind?
In the abstract, my concern about adding abstraction is that we aren't
sure it would be good for anything. Then we can wind up with an
over-engineered solution.
But, this is an abstract concern; perhaps your idea is not susceptible
to this.
>> + /* Swallow errors. */
Jan> Could here be a reason why it is valid?
>> + target_write_memory (address, bytes, TYPE_LENGTH (type));
Jan> And here again, why not to check errors?
I think we should warn.
Originally I thought there was just nothing sensible to do if we got an
error, but warning is better than silently ignoring it.
Jan> Here you leak PROV_PAT, PROBE_PAT and OBJ_PAT.
No, compile_rx_or_error makes a cleanup.
>> + return result;
>> +}
>> +
>> +/* A qsort comparison function for stap_entry objects. */
>> +
>> +static int
>> +compare_entries (const void *a, const void *b)
>> +{
>> + const stap_entry *ea = a;
>> + const stap_entry *eb = b;
>> + int v;
>> +
>> + v = strcmp (ea->probe->provider, eb->probe->provider);
Jan> handle_probe can create NULL probe->provider or NULL probe->name etc. But
Jan> other code like this one will crash on it.
Jan> I believe such non-valid probes rather should be dropped during parsing.
I agree.
Jan> Moreover I would still more see to drop [patch 1/3], call just
Jan> compute_probe_arg which returns lazy lval_computed struct value *
Jan> which provides new struct lval_funcs member which can return
Jan> `struct expression *' and generic code can call gen_expr on its
Jan> own. There is no need for special
Jan> internalvar_funcs-> compile_to_ax member.
This is a relic of an earlier implementation, which had two different
code paths.
Putting this into lval_funcs seems very roundabout to me. First, it
means computing a value in the middle of compiling to AX. But, when
compiling to AX we are not generally computing values. The probe
argument might not even be valid at the time at which AX compilation is
done. And, this means that we must always return a special computed
value for all probe arguments, just to make compilation work. All these
gyrations provide no extra benefit, though. Simply asking the
internalvar for an expression is simpler all around.
We could change the new method to return an expression; this doesn't
seem vital to me since it isn't used anywhere else, but I find it a
valid aesthetic choice.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-12 20:37 ` Tom Tromey
@ 2012-03-12 23:15 ` Jan Kratochvil
2012-03-15 15:40 ` Pedro Alves
0 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-03-12 23:15 UTC (permalink / raw)
To: Tom Tromey; +Cc: Sergio Durigan Junior, gdb-patches
On Mon, 12 Mar 2012 21:37:37 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
[...]
> Jan> I believe there was intended some abstraction, more talked about it
> Jan> elsewhere, breakpoint.c should only include some (nonexistent)
> Jan> "probe.h", not "stap-probe.h".
>
> What did you have in mind?
>
> In the abstract, my concern about adding abstraction is that we aren't
> sure it would be good for anything. Then we can wind up with an
> over-engineered solution.
>
> But, this is an abstract concern; perhaps your idea is not susceptible
> to this.
I find important that user interface gets established in a way needing no
changes in the future, as discussed with Eli.
Including probe.h vs. stap-probe.h also seems more easier for readability of
the generic GDB code. So called code encapsulation - not to complicate
unrelated code with the specific stap backend details visibility.
It would also make it more easy to implement breakpoints on UST addresses;
although I do not have ust.h available here to examine that possibility more.
> Jan> Here you leak PROV_PAT, PROBE_PAT and OBJ_PAT.
>
> No, compile_rx_or_error makes a cleanup.
Yes but there is:
discard_cleanups (cleanup);
which discards those cleanups.
IMO that discard_cleanups was meant for RESULT but not for PROV_PAT, PROBE_PAT
and OBJ_PAT - or I really still miss it? There should be two cleanup trackers:
cleanup = make_cleanup (VEC_cleanup (stap_entry), &result);
cleanup_temps = compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
compile_rx_or_error (&probe_pat, probe, _("Invalid probe regexp"));
compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
[...]
do_cleanups (cleanup_temps);
discard_cleanups (cleanup);
> Jan> Moreover I would still more see to drop [patch 1/3], call just
> Jan> compute_probe_arg which returns lazy lval_computed struct value *
> Jan> which provides new struct lval_funcs member which can return
> Jan> `struct expression *' and generic code can call gen_expr on its
> Jan> own. There is no need for special
> Jan> internalvar_funcs-> compile_to_ax member.
[...]
> Putting this into lval_funcs seems very roundabout to me. First, it
> means computing a value in the middle of compiling to AX. But, when
> compiling to AX we are not generally computing values.
+
> Simply asking the internalvar for an expression is simpler all around.
lval_computed value is not a real value, it is just a way how to implement the
needed functionality on top of existing API, without needing making that API
more rich.
I do not mind if you have considered the lval_computed way.
> We could change the new method to return an expression; this doesn't
> seem vital to me since it isn't used anywhere else, but I find it a
> valid aesthetic choice.
That's already detail, I was objecting more the whole [patch 1/3].
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-12 15:11 ` Tom Tromey
@ 2012-03-13 8:58 ` Mark Kettenis
2012-03-13 16:06 ` Sergio Durigan Junior
2012-03-15 20:44 ` Tom Tromey
0 siblings, 2 replies; 27+ messages in thread
From: Mark Kettenis @ 2012-03-13 8:58 UTC (permalink / raw)
To: tromey; +Cc: sergiodj, gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Mon, 12 Mar 2012 08:21:00 -0600
>
> >>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
>
> Mark> As far as I can tell SystemTap is Linux-specific. So I'd think its
> Mark> support should go completely in Linux-specific -tdep.c files.
>
> sdt.h is really more like an ELF feature.
Can you elaborate on that? I've googled around a bit but didn't
really find anything that describes how SystemTap works; only stuff
that describes how great it is and how it can be used. I did notice
that DTrace uses a header file with that name as well, but it seems
that the interfaces defined in the DTrace sdt.h are completely
different from the SystemTap one.
All evidence I have points towards the functions in i386-tdep.c being
SystemTap-specific; that's probably why they have "stap" in their name
;). They're only used from i386-linux-tdep.c, so it makes much more
sense to put them there. If somebody ever ports (or reimplements)
SystemTap for another OS, we can always move them. The same thing
holds for arm-tdep.c vs. arm-linux-tdep.c of course.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-13 8:58 ` Mark Kettenis
@ 2012-03-13 16:06 ` Sergio Durigan Junior
2012-03-15 20:44 ` Tom Tromey
1 sibling, 0 replies; 27+ messages in thread
From: Sergio Durigan Junior @ 2012-03-13 16:06 UTC (permalink / raw)
To: Mark Kettenis; +Cc: tromey, sergiodj, gdb-patches
On Tuesday, March 13 2012, Mark Kettenis wrote:
>> From: Tom Tromey <tromey@redhat.com>
>> Date: Mon, 12 Mar 2012 08:21:00 -0600
>>
>> >>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
>>
>> Mark> As far as I can tell SystemTap is Linux-specific. So I'd think its
>> Mark> support should go completely in Linux-specific -tdep.c files.
>>
>> sdt.h is really more like an ELF feature.
>
> All evidence I have points towards the functions in i386-tdep.c being
> SystemTap-specific; that's probably why they have "stap" in their name
> ;). They're only used from i386-linux-tdep.c, so it makes much more
> sense to put them there. If somebody ever ports (or reimplements)
> SystemTap for another OS, we can always move them. The same thing
> holds for arm-tdep.c vs. arm-linux-tdep.c of course.
I actually chose to put those functions on i386-tdep.c because they are
used by both {i386,amd64}-linux-tdep.c, and so I thought it would be a
good way to export them. However, I can put them in i386-linux-tdep.c
and export via a new i386-linux-tdep.h, if that's OK.
--
Sergio
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
` (2 preceding siblings ...)
2012-03-10 19:22 ` Jan Kratochvil
@ 2012-03-15 15:36 ` Pedro Alves
2012-03-15 20:50 ` Tom Tromey
3 siblings, 1 reply; 27+ messages in thread
From: Pedro Alves @ 2012-03-15 15:36 UTC (permalink / raw)
To: Sergio Durigan Junior; +Cc: gdb-patches, Tom Tromey
I've looked this one over. See my by comments below. I've tried to skip issues
already pointed out.
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> +/* See the comment in breakpoint.h. */
> +
> +void
> +modify_semaphore (struct bp_location *loc, int set)
> +{
Starting with a nit... This function name is a bit too generic for an
extern function. Can we make it a bit more specific, like
breakpoint_modify_stap_semaphore, or modify_stap_semaphore, or
perhaps even clearer, (bp_)stap_semaphore_up/(bp_)stap_semaphore_down?
I'd even suggest changing the function's prototype to take the semaphore
address as argument instead, and move it elsewhere most stap things
are (stap-probe.c?).
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> +{
> + struct gdbarch *arch = loc->gdbarch;
> + gdb_byte bytes[sizeof (LONGEST)];
> + /* The ABI specifies "unsigned short". */
> + struct type *type = builtin_type (arch)->builtin_unsigned_short;
> + CORE_ADDR address = loc->semaphore;
> + ULONGEST value;
> +
> + if (address == 0)
> + return;
> +
> + /* Swallow errors. */
> + if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
> + return;
> +
> + value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
> + gdbarch_byte_order (arch));
> + /* Note that we explicitly don't worry about overflow or
> + underflow. */
> + if (set)
> + ++value;
> + else
> + --value;
> +
> + store_unsigned_integer (bytes, TYPE_LENGTH (type),
> + gdbarch_byte_order (arch), value);
> +
> + target_write_memory (address, bytes, TYPE_LENGTH (type));
> +}
Is this racing with threads in the inferior, in non-stop mode? If
so, we should find a way to fix, but a comment about it here
meanwhile would be quite worth it.
> val = bl->owner->ops->insert_location (bl);
> +
> + modify_semaphore (bl, 1);
This is modifying the semaphore even if the insertion failed. Please make sure
we can't reach this with the breakpoint already inserted, due to the recent
target side breakpoint conditions work, in which case you should
not increment the semaphore. And I think we do.
> }
> else
> {
> @@ -3153,6 +3194,8 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
> {
> /* No overlay handling: just remove the breakpoint. */
> val = bl->owner->ops->remove_location (bl);
> +
> + modify_semaphore (bl, 0);
This is modifying the semaphore even if removal failed. Not so clear what to do in this
case; things are bonkers already anyway. But, in any case, at insertion time you have:
- insert breakpoint
- increment semaphore
so at removal, the obvious code that doesn't raise suspicions is the reverse sequence:
- decrement semaphore
- remove breakpoint
but you didn't do that. You should, to avoid raising eyebrows :-).
And this makes me wonder about non-stop. If the inferior is running, does is make a
different if you increment the semaphore before, or after you insert the breakpoint?
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> + /* Arguments. We can only extract the argument format if there is a valid
> + name for this probe. */
> + if (ret->name)
Am I the only one who's eyes sore with implicit pointer->bool conversions? :-)
> + {
> + ret->args = memchr (ret->name, '\0',
> + (char *) el->data + el->size - ret->name);
> +
> + if (ret->args != NULL)
> + ++ret->args;
> + if (ret->args == NULL
Mixbag of styles in the same function is what hurts the most. :-)
> + if (! elf_tdata (obfd)->sdt_note_head)
No space after ! please. Several instances of this.
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> + /* Parsing each probe's information. */
> + for (iter = elf_tdata (obfd)->sdt_note_head, i = 0;
> + iter;
> + iter = iter->next, i++)
> + /* We first have to handle all the information about the
> + probe which is present in the section. */
> + handle_probe (objfile, iter, &ret[i], base);
GDB's coding convention now requires {}'s around the
multi-line comment + statement, even though there's only a
single-line statement. More instances of this throughout.
> -/* Helper function that frees any unsed space in the expout array.
> - It is generally used when the parser has just been parsed and
> - created. */
> +/* See definition in parser-defs.h. */
>
> -static void
> +void
> reallocate_expout (void)
> {
> /* Record the actual number of expression elements, and then
> @@ -811,7 +803,7 @@ copy_name (struct stoken token)
> return the index of the subexpression which is the left-hand-side
> of the struct operation at EXPOUT_LAST_STRUCT. */
>
> -static int
> +int
> prefixify_expression (struct expression *expr)
> {
Seems like you move some comments to the headers, and others not. Other
examples elsewhere.
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> --- a/gdb/ppc-linux-tdep.c
> +++ b/gdb/ppc-linux-tdep.c
> @@ -66,6 +66,14 @@
> #include "features/rs6000/powerpc-isa205-vsx64l.c"
> #include "features/rs6000/powerpc-e500l.c"
>
> +#include "stap-probe.h"
> +#include "ax.h"
> +#include "ax-gdb.h"
> +#include "cli/cli-utils.h"
> +#include "parser-defs.h"
> +#include "user-regs.h"
> +#include <ctype.h>
Please put these above the .c includes, along with the other .h includes.
More cases of this elsewhere.
> + STAP_PROBE (teste, two);
Aha, a little PT sneaked in. :-)
> +proc stap_test {{arg ""}} {
> + global testfile hex
> +
> + if {$arg != ""} {
> + set arg "additional_flags=$arg"
> + set addendum ", with semaphore, not optimized"
> + } else {
> + set addendum ", no semaphore, not optimized"
> + }
> +
Instead of appending $addendum to all test messages (and missing
those that are emitted from within gdb.exp and friends), you should
now use with_test_prefix instead.
> --- a/gdb/testsuite/gdb.cp/nextoverthrow.exp
> +++ b/gdb/testsuite/gdb.cp/nextoverthrow.exp
> @@ -54,6 +54,17 @@ gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
> }
> }
> if {!$ok} {
> + gdb_test_multiple "info probe" "check for stap probe in unwinder" {
> + -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
> + pass "check for stap probe in unwinder"
> + set ok 1
> + }
> + -re "\r\n$gdb_prompt $" {
> + }
> + }
> +}
> +
> +if {!$ok} {
> unsupported "nextoverthrow.exp could not find _Unwind_DebugHook"
> return -1
> }
I don't understand why we'd now skip the test when we don't have the unwinder
stap probe, but in any case, this should not be in this patch, GDB only learns to
use the unwind probe in the next patch.
> +
> +if $tracelevel then {
> + strace $tracelevel
> +}
Please remove all traces of this. All existing instances have already been
removed from the testsuite throughout.
On 03/09/2012 08:33 PM, Sergio Durigan Junior wrote:
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -1717,6 +1717,7 @@ start_tracing (char *notes)
> for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, b); ix++)
> {
> struct tracepoint *t = (struct tracepoint *) b;
> + struct bp_location *loc;
>
> if (b->enable_state == bp_enabled)
> any_enabled = 1;
> @@ -1779,6 +1780,9 @@ start_tracing (char *notes)
> }
>
> t->number_on_target = b->number;
> +
> + for (loc = b->loc; loc; loc = loc->next)
> + modify_semaphore (loc, 1);
> }
> VEC_free (breakpoint_p, tp_vec);
>
> @@ -1851,9 +1855,28 @@ void
> stop_tracing (char *note)
> {
> int ret;
> + VEC(breakpoint_p) *tp_vec = NULL;
> + int ix;
> + struct breakpoint *t;
>
> target_trace_stop ();
>
> + tp_vec = all_tracepoints ();
> + for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
> + {
> + struct bp_location *loc;
> +
> + if ((t->type == bp_fast_tracepoint
> + ? !may_insert_fast_tracepoints
> + : !may_insert_tracepoints))
> + continue;
> +
> + for (loc = t->loc; loc; loc = loc->next)
> + modify_semaphore (loc, 0);
> + }
> +
> + VEC_free (breakpoint_p, tp_vec);
This made me wonder about something else with this semaphore
handling: the target can itself stop tracing, without GDB requesting
it. E.g., if the trace buffer is full. If so, then you'll miss
decrementing the semaphore count... Even worse with disconnected
tracing; GDB might not even be connected when the tracing stops,
and when you reconnect, you have no clue whether to decrement
the counts or not...
--
Pedro Alves
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-12 23:15 ` Jan Kratochvil
@ 2012-03-15 15:40 ` Pedro Alves
0 siblings, 0 replies; 27+ messages in thread
From: Pedro Alves @ 2012-03-15 15:40 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Tom Tromey, Sergio Durigan Junior, gdb-patches
On 03/12/2012 11:15 PM, Jan Kratochvil wrote:
> It would also make it more easy to implement breakpoints on UST addresses;
> although I do not have ust.h available here to examine that possibility more.
It's quite possible. We just need to use target_static_tracepoint_markers_by_strid
to get the address of a marker.
--
Pedro Alves
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-13 8:58 ` Mark Kettenis
2012-03-13 16:06 ` Sergio Durigan Junior
@ 2012-03-15 20:44 ` Tom Tromey
2012-03-16 14:52 ` Mark Kettenis
1 sibling, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-03-15 20:44 UTC (permalink / raw)
To: Mark Kettenis; +Cc: sergiodj, gdb-patches
>>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
Tom> sdt.h is really more like an ELF feature.
Mark> Can you elaborate on that? I've googled around a bit but didn't
Mark> really find anything that describes how SystemTap works; only stuff
Mark> that describes how great it is and how it can be used. I did notice
Mark> that DTrace uses a header file with that name as well, but it seems
Mark> that the interfaces defined in the DTrace sdt.h are completely
Mark> different from the SystemTap one.
Yeah, sorry. That was too brief.
The static probes in this case are intended to be source- (but not
binary-) compatible with DTrace. They are implemented entirely in a
header file (technically two headers but one is of the "config.h"
variety) and assume ELF and GCC.
The header is independent of SystemTap proper; it just came from the
SystemTap project and so it is maintained in that source repository.
There's been some talk that it will be used as the basis for UST markers
as well, but AFAIK this work hasn't happened yet.
I don't know of any barrier to this header working as-is on other
ELF+GCC platforms. I haven't tried it myself.
If you still want this in the Linux tdep files, I suppose it can be
done.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-15 15:36 ` Pedro Alves
@ 2012-03-15 20:50 ` Tom Tromey
0 siblings, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2012-03-15 20:50 UTC (permalink / raw)
To: Pedro Alves; +Cc: Sergio Durigan Junior, gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> I don't understand why we'd now skip the test when we don't have
Pedro> the unwinder stap probe,
I think the patch checks for the probe and for the unwinder debug hook,
and bails if they are both missing.
If either one exists then the test should work.
Pedro> This made me wonder about something else with this semaphore
Pedro> handling: the target can itself stop tracing, without GDB requesting
Pedro> it. E.g., if the trace buffer is full. If so, then you'll miss
Pedro> decrementing the semaphore count... Even worse with disconnected
Pedro> tracing; GDB might not even be connected when the tracing stops,
Pedro> and when you reconnect, you have no clue whether to decrement
Pedro> the counts or not...
Leaving the semaphore enabled in corner cases is not terrible.
It may affect performance a little, but that is all.
Anyone affected will already be doing reasonably sophisticated
debugging -- running disconnected trace experiments. If it is important
they could also just reset the semaphore to 0 manually.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-15 20:44 ` Tom Tromey
@ 2012-03-16 14:52 ` Mark Kettenis
2012-03-16 18:17 ` Tom Tromey
0 siblings, 1 reply; 27+ messages in thread
From: Mark Kettenis @ 2012-03-16 14:52 UTC (permalink / raw)
To: tromey; +Cc: mark.kettenis, sergiodj, gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Thu, 15 Mar 2012 14:43:38 -0600
>
> >>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
>
> Tom> sdt.h is really more like an ELF feature.
>
> Mark> Can you elaborate on that? I've googled around a bit but didn't
> Mark> really find anything that describes how SystemTap works; only stuff
> Mark> that describes how great it is and how it can be used. I did notice
> Mark> that DTrace uses a header file with that name as well, but it seems
> Mark> that the interfaces defined in the DTrace sdt.h are completely
> Mark> different from the SystemTap one.
>
> Yeah, sorry. That was too brief.
>
> The static probes in this case are intended to be source- (but not
> binary-) compatible with DTrace.
Don't you mean the other way around? As far as I can tell the
SystemTap macros have different names than their DTrace counterparts.
And I'd say that for GDB it's only binary compatibility that really
matters here.
> They are implemented entirely in a header file (technically two
> headers but one is of the "config.h" variety) and assume ELF and
> GCC.
>
> The header is independent of SystemTap proper; it just came from the
> SystemTap project and so it is maintained in that source repository.
> There's been some talk that it will be used as the basis for UST markers
> as well, but AFAIK this work hasn't happened yet.
>
> I don't know of any barrier to this header working as-is on other
> ELF+GCC platforms. I haven't tried it myself.
So you are saying that, at least in principle, it should be possible
to use the SystemTap toolchain on any ELF-based system to do
user-space tracing without needing any kernel support? That'd be cool.
> If you still want this in the Linux tdep files, I suppose it can be
> done.
And if that's the case, I think having them where they are currently
should be fine. But perhaps in that case setting the gdbarch hooks
needs to be moved from the Linux tdep files into i386_elf_init_abi().
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH 2/3] Implement new features needed for handling SystemTap probes
2012-03-16 14:52 ` Mark Kettenis
@ 2012-03-16 18:17 ` Tom Tromey
0 siblings, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2012-03-16 18:17 UTC (permalink / raw)
To: Mark Kettenis; +Cc: sergiodj, gdb-patches
>>>>> "Mark" == Mark Kettenis <mark.kettenis@xs4all.nl> writes:
Tom> The static probes in this case are intended to be source- (but not
Tom> binary-) compatible with DTrace.
Mark> Don't you mean the other way around? As far as I can tell the
Mark> SystemTap macros have different names than their DTrace counterparts.
Mark> And I'd say that for GDB it's only binary compatibility that really
Mark> matters here.
No, the SystemTap-provided <sdt.h> has compatibility macros with the
same names as the DTrace macros.
It doesn't try to be binary-compatible. I don't know how the DTrace
<sdt.h> works at all...
Mark> So you are saying that, at least in principle, it should be possible
Mark> to use the SystemTap toolchain on any ELF-based system to do
Mark> user-space tracing without needing any kernel support? That'd be cool.
Nope, just the static markers coming from <sdt.h>. The rest of
SystemTap is Linux-specific, dynamically creating and loading kernel
modules.
The probes still have some value outside of SystemTap. With patch #3 in
this series, you can use them to better implement "next-over-throw", for
C++ debugging. This is because GCC's unwinder has a probe in it that is
used by GDB.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2012-03-16 18:17 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-09 20:29 [PATCH 0/3] Implement support for SystemTap probes on userspace Sergio Durigan Junior
2012-03-09 20:32 ` [PATCH 1/3] Refactor internal variable mechanism Sergio Durigan Junior
2012-03-09 21:03 ` Tom Tromey
2012-03-10 4:02 ` Sergio Durigan Junior
2012-03-09 20:34 ` [PATCH 3/3] Use longjmp and exception probes when available Sergio Durigan Junior
2012-03-09 20:34 ` [PATCH 2/3] Implement new features needed for handling SystemTap probes Sergio Durigan Junior
2012-03-10 8:38 ` Eli Zaretskii
2012-03-10 16:56 ` Mark Kettenis
2012-03-12 15:11 ` Tom Tromey
2012-03-13 8:58 ` Mark Kettenis
2012-03-13 16:06 ` Sergio Durigan Junior
2012-03-15 20:44 ` Tom Tromey
2012-03-16 14:52 ` Mark Kettenis
2012-03-16 18:17 ` Tom Tromey
2012-03-10 19:22 ` Jan Kratochvil
2012-03-12 20:37 ` Tom Tromey
2012-03-12 23:15 ` Jan Kratochvil
2012-03-15 15:40 ` Pedro Alves
2012-03-15 15:36 ` Pedro Alves
2012-03-15 20:50 ` Tom Tromey
2012-03-09 21:15 ` [PATCH 0/3] Implement support for SystemTap probes on userspace Tom Tromey
2012-03-10 3:51 ` Sergio Durigan Junior
2012-03-10 7:55 ` Eli Zaretskii
2012-03-10 8:55 ` Jan Kratochvil
2012-03-10 9:06 ` Eli Zaretskii
2012-03-10 15:52 ` Sergio Durigan Junior
2012-03-12 19:59 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox