2012-04-27 Sergio Durigan Junior <sergiodj@redhat.com>

Tom Tromey  <tromey@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	* Makefile.in (SFILES): Add `probe' and `stap-probe'.
	(COMMON_OBS): Likewise.
	(HFILES_NO_SRCDIR): Add `probe'.
	* NEWS: Mention support for static and SystemTap probes.
	* amd64-tdep.c (amd64_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 `probe.h'.
	(bkpt_probe_breakpoint_ops): New variable.
	(momentary_breakpoint_from_master): Set the `probe' value.
	(add_location_to_breakpoint): Likewise.
	(break_command_1): Using proper breakpoint_ops according to the
	argument passed by the user in the command line.
	(bkpt_probe_insert_location): New function.
	(bkpt_probe_remove_location): Likewise.
	(bkpt_probe_create_sals_from_address): Likewise.
	(bkpt_probe_decode_linespec): Likewise.
	(tracepoint_probe_create_sals_from_address): Likewise.
	(tracepoint_probe_decode_linespec): Likewise.
	(tracepoint_probe_breakpoint_ops): New variable.
	(trace_command): Using proper breakpoint_ops according to the
	argument passed by the user in the command line.
	(initialize_breakpoint_ops): Initializing breakpoint_ops for
	static probes on breakpoints and tracepoints.
	* breakpoint.h (struct bp_location) <probe>: New field.
	* 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.
	* configure.ac: Append `stap-probe.o' to be generated when ELF
	support is present.
	* configure: Regenerate.
	* dbxread.c (aout_sym_fns): Add `sym_probe_fns' value.
	* elfread.c: Include `probe.h' and `arch-utils.h'.
	(probe_key): New variable.
	(elf_get_probes): New function.
	(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 static
	probes.
	* gdb_vecs.h (struct probe): New forward declaration.
	(probe_p): New VEC declaration.
	* 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-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_elf_init_abi): Initializing proper fields used by SystemTap
	probes' arguments parser.
	* i386-tdep.h (i386_stap_is_single_operand): New function.
	(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 static
	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.
	* probe.c: New file, for generic statically defined probe support.
	* probe.h: Likewise.
	* 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: Include `gdb_vecs.h'.
	(struct sym_probe_fns): New struct.
	(struct sym_fns) <sym_probe_fns>: New field.
	* symtab.c (init_sal): Initialize `probe' field.
	* symtab.h (struct probe): Forward declaration.
	(struct symtab_and_line) <probe>: New field.
	* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
	locations.
	(stop_tracing): Likewise.
	* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
This commit is contained in:
Sergio Durigan Junior 2012-04-27 20:47:57 +00:00
parent 2755f698e1
commit 55aa24fb2e
39 changed files with 4254 additions and 35 deletions

View File

@ -1,3 +1,124 @@
2012-04-27 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* Makefile.in (SFILES): Add `probe' and `stap-probe'.
(COMMON_OBS): Likewise.
(HFILES_NO_SRCDIR): Add `probe'.
* NEWS: Mention support for static and SystemTap probes.
* amd64-tdep.c (amd64_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 `probe.h'.
(bkpt_probe_breakpoint_ops): New variable.
(momentary_breakpoint_from_master): Set the `probe' value.
(add_location_to_breakpoint): Likewise.
(break_command_1): Using proper breakpoint_ops according to the
argument passed by the user in the command line.
(bkpt_probe_insert_location): New function.
(bkpt_probe_remove_location): Likewise.
(bkpt_probe_create_sals_from_address): Likewise.
(bkpt_probe_decode_linespec): Likewise.
(tracepoint_probe_create_sals_from_address): Likewise.
(tracepoint_probe_decode_linespec): Likewise.
(tracepoint_probe_breakpoint_ops): New variable.
(trace_command): Using proper breakpoint_ops according to the
argument passed by the user in the command line.
(initialize_breakpoint_ops): Initializing breakpoint_ops for
static probes on breakpoints and tracepoints.
* breakpoint.h (struct bp_location) <probe>: New field.
* 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.
* configure.ac: Append `stap-probe.o' to be generated when ELF
support is present.
* configure: Regenerate.
* dbxread.c (aout_sym_fns): Add `sym_probe_fns' value.
* elfread.c: Include `probe.h' and `arch-utils.h'.
(probe_key): New variable.
(elf_get_probes): New function.
(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 static
probes.
* gdb_vecs.h (struct probe): New forward declaration.
(probe_p): New VEC declaration.
* 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-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_elf_init_abi): Initializing proper fields used by SystemTap
probes' arguments parser.
* i386-tdep.h (i386_stap_is_single_operand): New function.
(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 static
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.
* probe.c: New file, for generic statically defined probe support.
* probe.h: Likewise.
* 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: Include `gdb_vecs.h'.
(struct sym_probe_fns): New struct.
(struct sym_fns) <sym_probe_fns>: New field.
* symtab.c (init_sal): Initialize `probe' field.
* symtab.h (struct probe): Forward declaration.
(struct symtab_and_line) <probe>: New field.
* tracepoint.c (start_tracing): Adjust semaphore on breakpoints
locations.
(stop_tracing): Likewise.
* xcoffread.c (xcoff_sym_fns): Add `sym_probe_fns' value.
2012-04-27 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>

View File

@ -726,8 +726,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 probe.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 \
@ -826,7 +826,7 @@ gnulib/import/extra/snippet/arg-nonnull.h gnulib/import/extra/snippet/c++defs.h
gnulib/import/extra/snippet/warn-on-use.h \
gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
common/linux-osdata.h gdb-dlfcn.h auto-load.h
common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h
# Header files that already have srcdir in them, or which are in objdir.
@ -914,7 +914,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 probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o
TSOBS = inflow.o

View File

@ -3,6 +3,13 @@
*** Changes since GDB 7.4
* GDB now has support for SDT (Static Defined Tracing) probes. Currently,
the only implemented backend is for SystemTap probes (<sys/sdt.h>). You
can set a breakpoint using the new "-probe, "-pstap" or "-probe-stap"
options and inspect the probe arguments using the new $_probe_arg family
of convenience variables. You can obtain more information about SystemTap
in <http://sourceware.org/systemtap/>.
* GDB now supports reversible debugging on ARM, it allows you to
debug basic ARM and THUMB instructions, and provides
record/replay support.

View File

@ -2691,6 +2691,16 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address);
/* 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. */

View File

@ -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)
@ -1158,6 +1280,16 @@ arm_linux_init_abi (struct gdbarch_info info,
/* Reversible debugging, process record. */
set_gdbarch_process_record (gdbarch, arm_process_record);
/* 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;
/* Syscall record. */

View File

@ -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,
@ -791,7 +787,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
@ -1803,7 +1799,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)
{

View File

@ -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;

View File

@ -60,6 +60,8 @@
#include "jit.h"
#include "xml-syscall.h"
#include "parser-defs.h"
#include "gdb_regex.h"
#include "probe.h"
#include "cli/cli-utils.h"
#include "continuations.h"
#include "stack.h"
@ -289,6 +291,9 @@ static struct breakpoint_ops momentary_breakpoint_ops;
breakpoints. */
struct breakpoint_ops bkpt_breakpoint_ops;
/* Breakpoints set on probes. */
static struct breakpoint_ops bkpt_probe_breakpoint_ops;
/* A reference-counted struct command_line. This lets multiple
breakpoints share a single command list. */
struct counted_command_line
@ -8149,6 +8154,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->probe = orig->loc->probe;
if (orig->loc->source_file != NULL)
copy->loc->source_file = xstrdup (orig->loc->source_file);
@ -8234,6 +8240,7 @@ add_location_to_breakpoint (struct breakpoint *b,
loc->requested_address = sal->pc;
loc->address = adjusted_address;
loc->pspace = sal->pspace;
loc->probe = sal->probe;
gdb_assert (loc->pspace != NULL);
loc->section = sal->section;
loc->gdbarch = loc_gdbarch;
@ -8973,6 +8980,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;
const char *arg_cp = arg;
/* Matching breakpoints on probes. */
if (arg && probe_linespec_to_ops (&arg_cp) != NULL)
ops = &bkpt_probe_breakpoint_ops;
else
ops = &bkpt_breakpoint_ops;
create_breakpoint (get_current_arch (),
arg,
@ -8980,7 +8995,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 */,
@ -12454,6 +12469,57 @@ momentary_bkpt_print_mention (struct breakpoint *b)
/* Nothing to mention. These breakpoints are internal. */
}
/* Specific methods for probe breakpoints. */
static int
bkpt_probe_insert_location (struct bp_location *bl)
{
int v = bkpt_insert_location (bl);
if (v == 0)
{
/* The insertion was successful, now let's set the probe's semaphore
if needed. */
bl->probe->pops->set_semaphore (bl->probe, bl->gdbarch);
}
return v;
}
static int
bkpt_probe_remove_location (struct bp_location *bl)
{
/* Let's clear the semaphore before removing the location. */
bl->probe->pops->clear_semaphore (bl->probe, bl->gdbarch);
return bkpt_remove_location (bl);
}
static void
bkpt_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_probes (arg, canonical);
*copy_arg = xstrdup (canonical->addr_string);
lsal.canonical = xstrdup (*copy_arg);
VEC_safe_push (linespec_sals, canonical->sals, &lsal);
}
static void
bkpt_probe_decode_linespec (struct breakpoint *b, char **s,
struct symtabs_and_lines *sals)
{
*sals = parse_probes (s, NULL);
if (!sals->sals)
error (_("probe not found"));
}
/* The breakpoint_ops structure to be used in tracepoints. */
static void
@ -12577,6 +12643,30 @@ tracepoint_decode_linespec (struct breakpoint *b, char **s,
struct breakpoint_ops tracepoint_breakpoint_ops;
/* The breakpoint_ops structure to be use on tracepoints placed in a
static probe. */
static void
tracepoint_probe_create_sals_from_address (char **arg,
struct linespec_result *canonical,
enum bptype type_wanted,
char *addr_start, char **copy_arg)
{
/* We use the same method for breakpoint on probes. */
bkpt_probe_create_sals_from_address (arg, canonical, type_wanted,
addr_start, copy_arg);
}
static void
tracepoint_probe_decode_linespec (struct breakpoint *b, char **s,
struct symtabs_and_lines *sals)
{
/* We use the same method for breakpoint on probes. */
bkpt_probe_decode_linespec (b, s, sals);
}
static struct breakpoint_ops tracepoint_probe_breakpoint_ops;
/* The breakpoint_ops structure to be used on static tracepoints with
markers (`-m'). */
@ -14208,6 +14298,14 @@ set_tracepoint_count (int num)
static void
trace_command (char *arg, int from_tty)
{
struct breakpoint_ops *ops;
const char *arg_cp = arg;
if (arg && probe_linespec_to_ops (&arg_cp))
ops = &tracepoint_probe_breakpoint_ops;
else
ops = &tracepoint_breakpoint_ops;
if (create_breakpoint (get_current_arch (),
arg,
NULL, 0, 1 /* parse arg */,
@ -14215,7 +14313,7 @@ trace_command (char *arg, int from_tty)
bp_tracepoint /* type_wanted */,
0 /* Ignore count */,
pending_break_support,
&tracepoint_breakpoint_ops,
ops,
from_tty,
1 /* enabled */,
0 /* internal */, 0))
@ -14950,6 +15048,14 @@ initialize_breakpoint_ops (void)
ops->print_it = momentary_bkpt_print_it;
ops->print_mention = momentary_bkpt_print_mention;
/* Probe breakpoints. */
ops = &bkpt_probe_breakpoint_ops;
*ops = bkpt_breakpoint_ops;
ops->insert_location = bkpt_probe_insert_location;
ops->remove_location = bkpt_probe_remove_location;
ops->create_sals_from_address = bkpt_probe_create_sals_from_address;
ops->decode_linespec = bkpt_probe_decode_linespec;
/* GNU v3 exception catchpoints. */
ops = &gnu_v3_exception_catchpoint_ops;
*ops = bkpt_breakpoint_ops;
@ -14997,6 +15103,12 @@ initialize_breakpoint_ops (void)
ops->create_breakpoints_sal = tracepoint_create_breakpoints_sal;
ops->decode_linespec = tracepoint_decode_linespec;
/* Probe tracepoints. */
ops = &tracepoint_probe_breakpoint_ops;
*ops = tracepoint_breakpoint_ops;
ops->create_sals_from_address = tracepoint_probe_create_sals_from_address;
ops->decode_linespec = tracepoint_probe_decode_linespec;
/* Static tracepoints with marker (`-m'). */
ops = &strace_marker_breakpoint_ops;
*ops = tracepoint_breakpoint_ops;
@ -15075,7 +15187,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);
catch_syscall_inferior_data
= register_inferior_data_with_cleanup (catch_syscall_inferior_data_cleanup);

View File

@ -418,6 +418,10 @@ struct bp_location
processor's architectual constraints. */
CORE_ADDR requested_address;
/* If the location comes from a probe point, this is the probe associated
with it. */
struct probe *probe;
char *function_name;
/* Details of the placed breakpoint, when inserted. */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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
};

2
gdb/configure vendored
View File

@ -12462,7 +12462,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_var_elf" >&5
$as_echo "$gdb_cv_var_elf" >&6; }
if test $gdb_cv_var_elf = yes; then
CONFIG_OBS="$CONFIG_OBS elfread.o"
CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
$as_echo "#define HAVE_ELF 1" >>confdefs.h

View File

@ -1948,7 +1948,7 @@ AC_CACHE_CHECK([for ELF support in BFD], gdb_cv_var_elf,
[bfd *abfd = NULL; bfd_get_elf_phdr_upper_bound (abfd); ],
gdb_cv_var_elf=yes, gdb_cv_var_elf=no)])
if test $gdb_cv_var_elf = yes; then
CONFIG_OBS="$CONFIG_OBS elfread.o"
CONFIG_OBS="$CONFIG_OBS elfread.o stap-probe.o"
AC_DEFINE(HAVE_ELF, 1,
[Define if ELF support should be included.])
# -ldl is provided by bfd/Makfile.am (LIBDL) <PLUGINS>.

View File

@ -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
};

View File

@ -36,6 +36,8 @@
#include "demangle.h"
#include "psympriv.h"
#include "filenames.h"
#include "probe.h"
#include "arch-utils.h"
#include "gdbtypes.h"
#include "value.h"
#include "infcall.h"
@ -60,6 +62,10 @@ struct elfinfo
asection *mdebugsect; /* Section pointer for .mdebug section */
};
/* Per-objfile data for probe info. */
static const struct objfile_data *probe_key = NULL;
static void free_elfinfo (void *);
/* Minimal symbols located at the GOT entries for .plt - that is the real
@ -1576,7 +1582,117 @@ elfstab_offset_sections (struct objfile *objfile, struct partial_symtab *pst)
complaint (&symfile_complaints,
_("elf/stab section information missing for %s"), filename);
}
/* Implementation of `sym_get_probes', as documented in symfile.h. */
static VEC (probe_p) *
elf_get_probes (struct objfile *objfile)
{
VEC (probe_p) *probes_per_objfile;
/* Have we parsed this objfile's probes already? */
probes_per_objfile = objfile_data (objfile, probe_key);
if (!probes_per_objfile)
{
int ix;
const struct probe_ops *probe_ops;
/* Here we try to gather information about all types of probes from the
objfile. */
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops);
ix++)
probe_ops->get_probes (&probes_per_objfile, objfile);
if (probes_per_objfile == NULL)
{
VEC_reserve (probe_p, probes_per_objfile, 1);
gdb_assert (probes_per_objfile != NULL);
}
set_objfile_data (objfile, probe_key, probes_per_objfile);
}
return probes_per_objfile;
}
/* Implementation of `sym_get_probe_argument_count', as documented in
symfile.h. */
static unsigned
elf_get_probe_argument_count (struct objfile *objfile,
struct probe *probe)
{
return probe->pops->get_probe_argument_count (probe, objfile);
}
/* Implementation of `sym_evaluate_probe_argument', as documented in
symfile.h. */
static struct value *
elf_evaluate_probe_argument (struct objfile *objfile,
struct probe *probe,
unsigned n)
{
return probe->pops->evaluate_probe_argument (probe, objfile, n);
}
/* Implementation of `sym_compile_to_ax', as documented in symfile.h. */
static void
elf_compile_to_ax (struct objfile *objfile,
struct probe *probe,
struct agent_expr *expr,
struct axs_value *value,
unsigned n)
{
probe->pops->compile_to_ax (probe, objfile, 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 ix;
VEC (probe_p) *probes = objfile_data (objfile, probe_key);
struct probe *probe;
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
probe->pops->relocate (probe, ANOFFSET (delta, SECT_OFF_TEXT (objfile)));
}
/* Helper function used to free the space allocated for storing SystemTap
probe information. */
static void
probe_key_free (struct objfile *objfile, void *d)
{
int ix;
VEC (probe_p) *probes = d;
struct probe *probe;
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
probe->pops->destroy (probe);
VEC_free (probe_p, probes);
}
/* 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 =
@ -1591,6 +1707,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
};
@ -1609,6 +1726,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
};
@ -1626,6 +1744,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
};
@ -1642,6 +1761,7 @@ static const struct gnu_ifunc_fns elf_gnu_ifunc_fns =
void
_initialize_elfread (void)
{
probe_key = register_objfile_data_with_cleanup (NULL, probe_key_free);
add_symtab_fns (&elf_sym_fns);
elf_objfile_gnu_ifunc_cache_data = register_objfile_data ();

View File

@ -23,6 +23,8 @@
#include "vec.h"
struct probe;
DEF_VEC_P (char_ptr);
DEF_VEC_P (const_char_ptr);
@ -39,4 +41,7 @@ extern void dirnames_to_char_ptr_vec_append (VEC (char_ptr) **vecp,
extern VEC (char_ptr) *dirnames_to_char_ptr_vec (const char *dirnames);
typedef struct probe *probe_p;
DEF_VEC_P (probe_p);
#endif /* GDB_VECS_H */

View File

@ -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 */
@ -1266,6 +1296,42 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (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));
@ -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)
{

View File

@ -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

View File

@ -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.

View File

@ -61,6 +61,13 @@
#include "ax.h"
#include "ax-gdb.h"
#include "stap-probe.h"
#include "user-regs.h"
#include "cli/cli-utils.h"
#include "expression.h"
#include "parser-defs.h"
#include <ctype.h>
/* Register names. */
static const char *i386_register_names[] =
@ -3363,6 +3370,325 @@ i386_svr4_sigcontext_addr (struct frame_info *this_frame)
return read_memory_unsigned_integer (sp + 8, 4, byte_order);
}
/* Implementation of `gdbarch_stap_is_single_operand', as defined in
gdbarch.h. */
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. */
}
/* Implementation of `gdbarch_stap_parse_special_token', as defined in
gdbarch.h. */
int
i386_stap_parse_special_token (struct gdbarch *gdbarch,
struct stap_parse_info *p)
{
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;
}
/* Generic ELF. */
@ -3372,6 +3698,16 @@ i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
/* We typically use stabs-in-ELF with the SVR4 register numbering. */
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
/* Registering SystemTap handlers. */
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);
}
/* System V Release 4 (SVR4). */

View File

@ -379,6 +379,7 @@ 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);
/* Functions and variables exported from i386bsd-tdep.c. */
@ -394,4 +395,12 @@ extern int i386nbsd_sc_reg_offset[];
extern int i386obsd_sc_reg_offset[];
extern int i386bsd_sc_reg_offset[];
/* 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);
#endif /* i386-tdep.h */

View File

@ -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
};

View File

@ -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
};

View File

@ -795,6 +795,11 @@ objfile_relocate1 (struct objfile *objfile,
obj_section_addr (s));
}
/* Relocating 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;
}

View File

@ -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
@ -804,14 +796,10 @@ copy_name (struct stoken token)
return namecopy;
}
/* Reverse an expression from suffix form (in which it is constructed)
to prefix form (in which we can conveniently print or execute it).
Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT
is not -1 (i.e., we are trying to complete a field name), it will
return the index of the subexpression which is the left-hand-side
of the struct operation at EXPOUT_LAST_STRUCT. */
static int
/* See comments on parser-defs.h. */
int
prefixify_expression (struct expression *expr)
{
int len = sizeof (struct expression) + EXP_ELEM_TO_BYTES (expr->nelts);

View File

@ -130,6 +130,30 @@ 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);
/* Reverse an expression from suffix form (in which it is constructed)
to prefix form (in which we can conveniently print or execute it).
Ordinarily this always returns -1. However, if EXPOUT_LAST_STRUCT
is not -1 (i.e., we are trying to complete a field name), it will
return the index of the subexpression which is the left-hand-side
of the struct operation at EXPOUT_LAST_STRUCT. */
extern int prefixify_expression (struct expression *expr);
extern void write_exp_elt_opcode (enum exp_opcode);
extern void write_exp_elt_sym (struct symbol *);

View File

@ -50,6 +50,14 @@
#include "xml-syscall.h"
#include "linux-tdep.h"
#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>
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
#include "features/rs6000/powerpc-cell32l.c"
@ -1276,6 +1284,75 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch,
}
}
/* Implementation of `gdbarch_stap_is_single_operand', as defined in
gdbarch.h. */
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. */
}
/* Implementation of `gdbarch_stap_parse_special_token', as defined in
gdbarch.h. */
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 +1670,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

788
gdb/probe.c Normal file
View File

@ -0,0 +1,788 @@
/* Generic static probe support for GDB.
Copyright (C) 2012 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 "probe.h"
#include "command.h"
#include "cli/cli-cmds.h"
#include "cli/cli-utils.h"
#include "objfiles.h"
#include "symtab.h"
#include "progspace.h"
#include "filenames.h"
#include "exceptions.h"
#include "linespec.h"
#include "gdb_regex.h"
#include "frame.h"
#include "arch-utils.h"
#include <ctype.h>
/* See definition in probe.h. */
struct symtabs_and_lines
parse_probes (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;
const struct probe_ops *probe_ops;
const char *cs;
result.sals = NULL;
result.nelts = 0;
arg_start = *argptr;
cs = *argptr;
probe_ops = probe_linespec_to_ops (&cs);
gdb_assert (probe_ops != NULL);
arg = (char *) cs;
arg = skip_spaces (arg);
if (!*arg)
error (_("argument to `%s' missing"), arg_start);
arg_end = skip_to_space (arg);
/* 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)
{
VEC (probe_p) *probes;
struct probe *probe;
int ix;
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;
if (objfile->separate_debug_objfile_backlink != NULL)
continue;
probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
{
struct symtab_and_line *sal;
if (probe_ops != &probe_ops_any && probe->pops != probe_ops)
continue;
if (provider && strcmp (probe->provider, provider) != 0)
continue;
if (strcmp (probe->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 = probe->address;
sal->explicit_pc = 1;
sal->section = find_pc_overlay (sal->pc);
sal->pspace = pspace;
sal->probe = probe;
}
}
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;
}
/* See definition in probe.h. */
VEC (probe_p) *
find_probes_in_objfile (struct objfile *objfile, const char *provider,
const char *name)
{
VEC (probe_p) *probes, *result = NULL;
int ix;
struct probe *probe;
if (!objfile->sf || !objfile->sf->sym_probe_fns)
return NULL;
probes = objfile->sf->sym_probe_fns->sym_get_probes (objfile);
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
{
if (strcmp (probe->provider, provider) != 0)
continue;
if (strcmp (probe->name, name) != 0)
continue;
VEC_safe_push (probe_p, result, probe);
}
return result;
}
/* See definition in probe.h. */
struct probe *
find_probe_by_pc (CORE_ADDR pc, struct objfile **objfile_out)
{
struct objfile *objfile;
ALL_OBJFILES (objfile)
{
VEC (probe_p) *probes;
int ix;
struct probe *probe;
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);
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
if (probe->address == pc)
{
*objfile_out = objfile;
return probe;
}
}
return NULL;
}
/* A utility structure. A VEC of these is built when handling "info
probes". */
struct probe_and_objfile
{
/* The probe. */
struct probe *probe;
/* The probe's objfile. */
struct objfile *objfile;
};
typedef struct probe_and_objfile probe_and_objfile_s;
DEF_VEC_O (probe_and_objfile_s);
/* 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_NAME.
If POPS is not NULL, only probes of this certain probe_ops will match.
Each argument is a regexp, or NULL, which matches anything. */
static VEC (probe_and_objfile_s) *
collect_probes (char *objname, char *provider, char *probe_name,
const struct probe_ops *pops)
{
struct objfile *objfile;
VEC (probe_and_objfile_s) *result = NULL;
struct cleanup *cleanup, *cleanup_temps;
regex_t obj_pat, prov_pat, probe_pat;
cleanup = make_cleanup (VEC_cleanup (probe_and_objfile_s), &result);
cleanup_temps = make_cleanup (null_cleanup, NULL);
compile_rx_or_error (&prov_pat, provider, _("Invalid provider regexp"));
compile_rx_or_error (&probe_pat, probe_name, _("Invalid probe regexp"));
compile_rx_or_error (&obj_pat, objname, _("Invalid object file regexp"));
ALL_OBJFILES (objfile)
{
VEC (probe_p) *probes;
struct probe *probe;
int ix;
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);
for (ix = 0; VEC_iterate (probe_p, probes, ix, probe); ix++)
{
probe_and_objfile_s entry;
if (pops != NULL && probe->pops != pops)
continue;
if (provider
&& regexec (&prov_pat, probe->provider, 0, NULL, 0) != 0)
continue;
if (probe_name
&& regexec (&probe_pat, probe->name, 0, NULL, 0) != 0)
continue;
entry.probe = probe;
entry.objfile = objfile;
VEC_safe_push (probe_and_objfile_s, result, &entry);
}
}
do_cleanups (cleanup_temps);
discard_cleanups (cleanup);
return result;
}
/* A qsort comparison function for probe_and_objfile_s objects. */
static int
compare_entries (const void *a, const void *b)
{
const probe_and_objfile_s *ea = a;
const probe_and_objfile_s *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);
}
/* Helper function that generate entries in the ui_out table being
crafted by `info_probes_for_ops'. */
static void
gen_ui_out_table_header_info (VEC (probe_and_objfile_s) *probes,
const struct probe_ops *p)
{
/* `headings' refers to the names of the columns when printing `info
probes'. */
VEC (info_probe_column_s) *headings = NULL;
struct cleanup *c;
info_probe_column_s *column;
size_t headings_size;
int ix;
gdb_assert (p != NULL);
if (p->gen_info_probes_table_header == NULL
&& p->gen_info_probes_table_values == NULL)
return;
gdb_assert (p->gen_info_probes_table_header != NULL
&& p->gen_info_probes_table_values != NULL);
c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
p->gen_info_probes_table_header (&headings);
headings_size = VEC_length (info_probe_column_s, headings);
for (ix = 0;
VEC_iterate (info_probe_column_s, headings, ix, column);
++ix)
{
probe_and_objfile_s *entry;
int jx;
size_t size_max = strlen (column->print_name);
for (jx = 0; VEC_iterate (probe_and_objfile_s, probes, jx, entry); ++jx)
{
/* `probe_fields' refers to the values of each new field that this
probe will display. */
VEC (const_char_ptr) *probe_fields = NULL;
struct cleanup *c2;
const char *val;
int kx;
if (entry->probe->pops != p)
continue;
c2 = make_cleanup (VEC_cleanup (const_char_ptr), &probe_fields);
p->gen_info_probes_table_values (entry->probe, entry->objfile,
&probe_fields);
gdb_assert (VEC_length (const_char_ptr, probe_fields)
== headings_size);
for (kx = 0; VEC_iterate (const_char_ptr, probe_fields, kx, val);
++kx)
{
/* It is valid to have a NULL value here, which means that the
backend does not have something to write and this particular
field should be skipped. */
if (val == NULL)
continue;
size_max = max (strlen (val), size_max);
}
do_cleanups (c2);
}
ui_out_table_header (current_uiout, size_max, ui_left,
column->field_name, column->print_name);
}
do_cleanups (c);
}
/* Helper function to print extra information about a probe and an objfile
represented by ENTRY. */
static void
print_ui_out_info (probe_and_objfile_s *entry)
{
int ix;
int j = 0;
/* `values' refers to the actual values of each new field in the output
of `info probe'. `headings' refers to the names of each new field. */
VEC (const_char_ptr) *values = NULL;
VEC (info_probe_column_s) *headings = NULL;
info_probe_column_s *column;
struct cleanup *c;
gdb_assert (entry != NULL);
gdb_assert (entry->probe != NULL);
gdb_assert (entry->probe->pops != NULL);
if (entry->probe->pops->gen_info_probes_table_header == NULL
&& entry->probe->pops->gen_info_probes_table_values == NULL)
return;
gdb_assert (entry->probe->pops->gen_info_probes_table_header != NULL
&& entry->probe->pops->gen_info_probes_table_values != NULL);
c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
make_cleanup (VEC_cleanup (const_char_ptr), &values);
entry->probe->pops->gen_info_probes_table_header (&headings);
entry->probe->pops->gen_info_probes_table_values (entry->probe,
entry->objfile, &values);
gdb_assert (VEC_length (info_probe_column_s, headings)
== VEC_length (const_char_ptr, values));
for (ix = 0;
VEC_iterate (info_probe_column_s, headings, ix, column);
++ix)
{
const char *val = VEC_index (const_char_ptr, values, j++);
if (val == NULL)
ui_out_field_skip (current_uiout, column->field_name);
else
ui_out_field_string (current_uiout, column->field_name, val);
}
do_cleanups (c);
}
/* Helper function that returns the number of extra fields which POPS will
need. */
static int
get_number_extra_fields (const struct probe_ops *pops)
{
VEC (info_probe_column_s) *headings = NULL;
struct cleanup *c;
int n;
if (pops->gen_info_probes_table_header == NULL)
return 0;
c = make_cleanup (VEC_cleanup (info_probe_column_s), &headings);
pops->gen_info_probes_table_header (&headings);
n = VEC_length (info_probe_column_s, headings);
do_cleanups (c);
return n;
}
/* See comment in probe.h. */
void
info_probes_for_ops (char *arg, int from_tty, const struct probe_ops *pops)
{
char *provider, *probe = NULL, *objname = NULL;
struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
VEC (probe_and_objfile_s) *items;
int i, any_found;
int ui_out_extra_fields = 0;
size_t size_addr;
size_t size_name = strlen ("Name");
size_t size_objname = strlen ("Object");
size_t size_provider = strlen ("Provider");
probe_and_objfile_s *entry;
struct gdbarch *gdbarch = get_current_arch ();
/* Do we have a `provider:probe:objfile' style of linespec? */
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);
}
}
if (pops == NULL)
{
const struct probe_ops *po;
int ix;
/* If the probe_ops is NULL, it means the user has requested a "simple"
`info probes', i.e., she wants to print all information about all
probes. For that, we have to identify how many extra fields we will
need to add in the ui_out table.
To do that, we iterate over all probe_ops, querying each one about
its extra fields, and incrementing `ui_out_extra_fields' to reflect
that number. */
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
ui_out_extra_fields += get_number_extra_fields (po);
}
else
ui_out_extra_fields = get_number_extra_fields (pops);
items = collect_probes (objname, provider, probe, pops);
make_cleanup (VEC_cleanup (probe_and_objfile_s), &items);
make_cleanup_ui_out_table_begin_end (current_uiout,
4 + ui_out_extra_fields,
VEC_length (probe_and_objfile_s, items),
"StaticProbes");
if (!VEC_empty (probe_and_objfile_s, items))
qsort (VEC_address (probe_and_objfile_s, items),
VEC_length (probe_and_objfile_s, items),
sizeof (probe_and_objfile_s), compare_entries);
/* What's the size of an address in our architecture? */
size_addr = gdbarch_addr_bit (gdbarch) == 64 ? 18 : 10;
/* Determining the maximum size of each field (`provider', `name' and
`objname'). */
for (i = 0; VEC_iterate (probe_and_objfile_s, items, i, entry); ++i)
{
size_name = max (strlen (entry->probe->name), size_name);
size_provider = max (strlen (entry->probe->provider), size_provider);
size_objname = max (strlen (entry->objfile->name), size_objname);
}
ui_out_table_header (current_uiout, size_provider, ui_left, "provider",
_("Provider"));
ui_out_table_header (current_uiout, size_name, ui_left, "name", _("Name"));
ui_out_table_header (current_uiout, size_addr, ui_left, "addr", _("Where"));
if (pops == NULL)
{
const struct probe_ops *po;
int ix;
/* We have to generate the table header for each new probe type that we
will print. */
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po); ++ix)
gen_ui_out_table_header_info (items, po);
}
else
gen_ui_out_table_header_info (items, pops);
ui_out_table_header (current_uiout, size_objname, ui_left, "object",
_("Object"));
ui_out_table_body (current_uiout);
for (i = 0; VEC_iterate (probe_and_objfile_s, 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_objfile_arch (entry->objfile),
entry->probe->address);
if (pops == NULL)
{
const struct probe_ops *po;
int ix;
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, po);
++ix)
if (entry->probe->pops == po)
print_ui_out_info (entry);
}
else
print_ui_out_info (entry);
ui_out_field_string (current_uiout, "object", entry->objfile->name);
ui_out_text (current_uiout, "\n");
do_cleanups (inner);
}
any_found = !VEC_empty (probe_and_objfile_s, items);
do_cleanups (cleanup);
if (!any_found)
ui_out_message (current_uiout, 0, _("No probes matched.\n"));
}
/* Implementation of the `info probes' command. */
static void
info_probes_command (char *arg, int from_tty)
{
info_probes_for_ops (arg, from_tty, NULL);
}
/* See comments in probe.h. */
struct value *
probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n)
{
struct probe *probe;
struct objfile *objfile;
unsigned 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,
n);
}
/* See comment in probe.h. */
const struct probe_ops *
probe_linespec_to_ops (const char **linespecp)
{
int ix;
const struct probe_ops *probe_ops;
for (ix = 0; VEC_iterate (probe_ops_cp, all_probe_ops, ix, probe_ops); ix++)
if (probe_ops->is_linespec (linespecp))
return probe_ops;
return NULL;
}
/* See comment in probe.h. */
int
probe_is_linespec_by_keyword (const char **linespecp, const char *const *keywords)
{
const char *s = *linespecp;
const char *const *csp;
for (csp = keywords; *csp; csp++)
{
const char *keyword = *csp;
size_t len = strlen (keyword);
if (strncmp (s, keyword, len) == 0 && isspace (s[len]))
{
*linespecp += len + 1;
return 1;
}
}
return 0;
}
/* Implementation of `is_linespec' method for `struct probe_ops'. */
static int
probe_any_is_linespec (const char **linespecp)
{
static const char *const keywords[] = { "-p", "-probe", NULL };
return probe_is_linespec_by_keyword (linespecp, keywords);
}
/* Dummy method used for `probe_ops_any'. */
static void
probe_any_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
{
/* No probes can be provided by this dummy backend. */
}
/* Operations associated with a generic probe. */
const struct probe_ops probe_ops_any =
{
probe_any_is_linespec,
probe_any_get_probes,
};
/* See comments in probe.h. */
struct cmd_list_element **
info_probes_cmdlist_get (void)
{
static struct cmd_list_element *info_probes_cmdlist;
if (info_probes_cmdlist == NULL)
add_prefix_cmd ("probes", class_info, info_probes_command,
_("\
Show available static probes.\n\
Usage: info probes [all|TYPE [ARGS]]\n\
TYPE specifies the type of the probe, and can be one of the following:\n\
- stap\n\
If you specify TYPE, there may be additional arguments needed by the\n\
subcommand.\n\
If you do not specify any argument, or specify `all', then the command\n\
will show information about all types of probes."),
&info_probes_cmdlist, "info probes ",
0/*allow-unknown*/, &infolist);
return &info_probes_cmdlist;
}
VEC (probe_ops_cp) *all_probe_ops;
void _initialize_probe (void);
void
_initialize_probe (void)
{
VEC_safe_push (probe_ops_cp, all_probe_ops, &probe_ops_any);
add_cmd ("all", class_info, info_probes_command,
_("\
Show information about all type of probes."),
info_probes_cmdlist_get ());
}

221
gdb/probe.h Normal file
View File

@ -0,0 +1,221 @@
/* Generic SDT probe support for GDB.
Copyright (C) 2012 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 (PROBE_H)
#define PROBE_H 1
#include "gdb_vecs.h"
struct linespec_result;
/* Structure useful for passing the header names in the method
`gen_ui_out_table_header'. */
struct info_probe_column
{
/* The internal name of the field. This string cannot be capitalized nor
localized, e.g., "extra_field". */
const char *field_name;
/* The field name to be printed in the `info probes' command. This
string can be capitalized and localized, e.g., _("Extra Field"). */
const char *print_name;
};
typedef struct info_probe_column info_probe_column_s;
DEF_VEC_O (info_probe_column_s);
/* Operations associated with a probe. */
struct probe_ops
{
/* Method responsible for verifying if LINESPECP is a valid linespec for
a probe breakpoint. It should return 1 if it is, or zero if it is not.
It also should update LINESPECP in order to discard the breakpoint
option associated with this linespec. For example, if the option is
`-probe', and the LINESPECP is `-probe abc', the function should
return 1 and set LINESPECP to `abc'. */
int (*is_linespec) (const char **linespecp);
/* Function that should fill PROBES with known probes from OBJFILE. */
void (*get_probes) (VEC (probe_p) **probes, struct objfile *objfile);
/* Function used to relocate addresses from PROBE according to some DELTA
provided. */
void (*relocate) (struct probe *probe, CORE_ADDR delta);
/* Return the number of arguments of PROBE. */
unsigned (*get_probe_argument_count) (struct probe *probe,
struct objfile *objfile);
/* Evaluate the Nth argument from the PROBE, returning a value
corresponding to it. The argument number is represented N. */
struct value *(*evaluate_probe_argument) (struct probe *probe,
struct objfile *objfile,
unsigned n);
/* Compile the Nth argument of the PROBE to an agent expression.
The argument number is represented by N. */
void (*compile_to_ax) (struct probe *probe, struct objfile *objfile,
struct agent_expr *aexpr,
struct axs_value *axs_value, unsigned n);
/* Set the semaphore associated with the PROBE. This function only makes
sense if the probe has a concept of semaphore associated to a
probe. */
void (*set_semaphore) (struct probe *probe, struct gdbarch *gdbarch);
/* Clear the semaphore associated with the PROBE. This function only
makes sense if the probe has a concept of semaphore associated to
a probe. */
void (*clear_semaphore) (struct probe *probe, struct gdbarch *gdbarch);
/* Function called to destroy PROBE's specific data. This function
shall not free PROBE itself. */
void (*destroy) (struct probe *probe);
/* Function responsible for providing the extra fields that will be
printed in the `info probes' command. It should fill HEADS
with whatever extra fields it needs. If the backend doesn't need
to print extra fields, it can set this method to NULL. */
void (*gen_info_probes_table_header) (VEC (info_probe_column_s) **heads);
/* Function that will fill VALUES with the values of the extra fields
to be printed for PROBE and OBJFILE. If the backend implements
the `gen_ui_out_table_header' method, then it should implement
this method as well. The backend should also guarantee that the
order and the number of values in the vector is exactly the same
as the order of the extra fields provided in the method
`gen_ui_out_table_header'. If a certain field is to be skipped
when printing the information, you can push a NULL value in that
position in the vector. */
void (*gen_info_probes_table_values) (struct probe *probe,
struct objfile *objfile,
VEC (const_char_ptr) **values);
};
/* Definition of a vector of probe_ops. */
typedef const struct probe_ops *probe_ops_cp;
DEF_VEC_P (probe_ops_cp);
extern VEC (probe_ops_cp) *all_probe_ops;
/* The probe_ops associated with the generic probe. */
extern const struct probe_ops probe_ops_any;
/* Helper function that, given KEYWORDS, iterate over it trying to match
each keyword with LINESPECP. If it succeeds, it updates the LINESPECP
pointer and returns 1. Otherwise, nothing is done to LINESPECP and zero
is returned. */
extern int probe_is_linespec_by_keyword (const char **linespecp,
const char *const *keywords);
/* Return specific PROBE_OPS * matching *LINESPECP and possibly updating
*LINESPECP to skip its "-probe-type " prefix. Return &probe_ops_any if
*LINESPECP matches "-probe ", that is any unspecific probe. Return NULL if
*LINESPECP is not identified as any known probe type, *LINESPECP is not
modified in such case. */
extern const struct probe_ops *probe_linespec_to_ops (const char **linespecp);
/* The probe itself. The struct contains generic information about the
probe, and then some specific information which should be stored in
the `probe_info' field. */
struct probe
{
/* The operations associated with this probe. */
const struct probe_ops *pops;
/* The name of the probe. */
const char *name;
/* The provider of the probe. It generally defaults to the name of
the objfile which contains the probe. */
const char *provider;
/* The address where the probe is inserted. */
CORE_ADDR address;
};
/* A helper for linespec that decodes a probe specification. It returns a
symtabs_and_lines object and updates *ARGPTR or throws an error. The
argument PTYPE specifies the type of the probe(s) to be parsed. */
extern struct symtabs_and_lines parse_probes (char **argptr,
struct linespec_result *canon);
/* Helper function to register the proper probe_ops to a newly created probe.
This function is mainly called from `sym_get_probes'. */
extern void register_probe_ops (struct probe *probe);
/* Given a PC, find an associated probe with type PTYPE. 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 probe *find_probe_by_pc (CORE_ADDR pc,
struct objfile **objfile_out);
/* Search OBJFILE for a probe with the given PROVIDER, NAME and PTYPE.
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 (probe_p) *find_probes_in_objfile (struct objfile *objfile,
const char *provider,
const char *name);
/* Generate a `info probes' command output for probe_ops represented by
POPS. If POPS is NULL it considers any probes types. It is a helper
function that can be used by the probe backends to print their
`info probe TYPE'. */
extern void info_probes_for_ops (char *arg, int from_tty,
const struct probe_ops *pops);
/* Return the `cmd_list_element' associated with the `info probes' command,
or create a new one if it doesn't exist. Helper function that serves the
purpose of avoiding the case of a backend using the `cmd_list_element'
associated with `info probes', without having it registered yet. */
extern struct cmd_list_element **info_probes_cmdlist_get (void);
/* A convenience function that finds a probe at the PC in FRAME and
evaluates argument N, with 0 <= N < number_of_args. If there is no
probe at that location, or if the probe does not have enough arguments,
this returns NULL. */
extern struct value *probe_safe_evaluate_at_pc (struct frame_info *frame,
unsigned n);
#endif /* !defined (PROBE_H) */

View File

@ -45,6 +45,13 @@
#include "linux-tdep.h"
#include "s390-tdep.h"
#include "stap-probe.h"
#include "ax.h"
#include "ax-gdb.h"
#include "user-regs.h"
#include "cli/cli-utils.h"
#include <ctype.h>
#include "features/s390-linux32.c"
#include "features/s390-linux32v1.c"
#include "features/s390-linux32v2.c"
@ -55,7 +62,6 @@
#include "features/s390x-linux64v1.c"
#include "features/s390x-linux64v2.c"
/* The tdep structure. */
struct gdbarch_tdep
@ -2953,6 +2959,18 @@ s390_address_class_name_to_type_flags (struct gdbarch *gdbarch,
return 0;
}
/* Implementation of `gdbarch_stap_is_single_operand', as defined in
gdbarch.h. */
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 +3301,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;
}

View File

@ -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
};

1558
gdb/stap-probe.c Normal file

File diff suppressed because it is too large Load Diff

52
gdb/stap-probe.h Normal file
View File

@ -0,0 +1,52 @@
/* SystemTap probe support for GDB.
Copyright (C) 2012 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 "probe.h"
/* 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;
};
#endif /* !defined (STAP_PROBE_H) */

View File

@ -22,6 +22,7 @@
/* This file requires that you first include "bfd.h". */
#include "symtab.h"
#include "gdb_vecs.h"
/* Opaque declarations. */
struct target_section;
@ -29,6 +30,11 @@ struct objfile;
struct obj_section;
struct obstack;
struct block;
struct probe;
struct value;
struct frame_info;
struct agent_expr;
struct axs_value;
/* Comparison function for symbol look ups. */
@ -297,6 +303,52 @@ struct quick_symbol_functions
int need_fullname);
};
/* Structure of functions used for probe support. If one of these functions
is provided, all must be. */
struct sym_probe_fns
{
/* If non-NULL, return an array of probe objects.
The returned value does not have to be freed and it has lifetime of the
OBJFILE. */
VEC (probe_p) *(*sym_get_probes) (struct objfile *);
/* 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. */
unsigned (*sym_get_probe_argument_count) (struct objfile *objfile,
struct 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 probe *probe,
unsigned 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 probe *probe,
struct agent_expr *expr,
struct axs_value *value,
unsigned 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 +419,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;

View File

@ -901,6 +901,7 @@ init_sal (struct symtab_and_line *sal)
sal->end = 0;
sal->explicit_pc = 0;
sal->explicit_line = 0;
sal->probe = NULL;
}

View File

@ -35,6 +35,7 @@ struct axs_value;
struct agent_expr;
struct program_space;
struct language_defn;
struct probe;
/* Some of the structures in this file are space critical.
The space-critical structures are:
@ -1042,6 +1043,9 @@ struct symtab_and_line
CORE_ADDR end;
int explicit_pc;
int explicit_line;
/* The probe associated with this symtab_and_line. */
struct probe *probe;
};
extern void init_sal (struct symtab_and_line *sal);

View File

@ -52,6 +52,7 @@
#include "memrange.h"
#include "exceptions.h"
#include "cli/cli-utils.h"
#include "probe.h"
/* readline include files */
#include "readline/readline.h"
@ -1717,6 +1718,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 +1781,9 @@ start_tracing (char *notes)
}
t->number_on_target = b->number;
for (loc = b->loc; loc; loc = loc->next)
loc->probe->pops->set_semaphore (loc->probe, loc->gdbarch);
}
VEC_free (breakpoint_p, tp_vec);
@ -1851,9 +1856,34 @@ 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)
{
/* GDB can be totally absent in some disconnected trace scenarios,
but we don't really care if this semaphore goes out of sync.
That's why we are decrementing it here, but not taking care
in other places. */
loc->probe->pops->clear_semaphore (loc->probe, loc->gdbarch);
}
}
VEC_free (breakpoint_p, tp_vec);
if (!note)
note = trace_stop_notes;
ret = target_set_trace_notes (NULL, NULL, note);

View File

@ -3136,6 +3136,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
};