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:
parent
2755f698e1
commit
55aa24fb2e
121
gdb/ChangeLog
121
gdb/ChangeLog
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
7
gdb/NEWS
7
gdb/NEWS
@ -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.
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
119
gdb/breakpoint.c
119
gdb/breakpoint.c
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
2
gdb/configure
vendored
@ -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
|
||||
|
||||
|
@ -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>.
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
120
gdb/elfread.c
120
gdb/elfread.c
@ -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 ();
|
||||
|
@ -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 */
|
||||
|
250
gdb/gdbarch.c
250
gdb/gdbarch.c
@ -265,6 +265,16 @@ struct gdbarch
|
||||
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
|
||||
gdbarch_record_special_symbol_ftype *record_special_symbol;
|
||||
gdbarch_get_syscall_number_ftype *get_syscall_number;
|
||||
const char * stap_integer_prefix;
|
||||
const char * stap_integer_suffix;
|
||||
const char * stap_register_prefix;
|
||||
const char * stap_register_suffix;
|
||||
const char * stap_register_indirection_prefix;
|
||||
const char * stap_register_indirection_suffix;
|
||||
const char * stap_gdb_register_prefix;
|
||||
const char * stap_gdb_register_suffix;
|
||||
gdbarch_stap_is_single_operand_ftype *stap_is_single_operand;
|
||||
gdbarch_stap_parse_special_token_ftype *stap_parse_special_token;
|
||||
int has_global_solist;
|
||||
int has_global_breakpoints;
|
||||
gdbarch_has_shared_address_space_ftype *has_shared_address_space;
|
||||
@ -423,6 +433,16 @@ struct gdbarch startup_gdbarch =
|
||||
0, /* get_siginfo_type */
|
||||
0, /* record_special_symbol */
|
||||
0, /* get_syscall_number */
|
||||
0, /* stap_integer_prefix */
|
||||
0, /* stap_integer_suffix */
|
||||
0, /* stap_register_prefix */
|
||||
0, /* stap_register_suffix */
|
||||
0, /* stap_register_indirection_prefix */
|
||||
0, /* stap_register_indirection_suffix */
|
||||
0, /* stap_gdb_register_prefix */
|
||||
0, /* stap_gdb_register_suffix */
|
||||
0, /* stap_is_single_operand */
|
||||
0, /* stap_parse_special_token */
|
||||
0, /* has_global_solist */
|
||||
0, /* has_global_breakpoints */
|
||||
default_has_shared_address_space, /* has_shared_address_space */
|
||||
@ -715,6 +735,16 @@ verify_gdbarch (struct gdbarch *gdbarch)
|
||||
/* Skip verify of get_siginfo_type, has predicate. */
|
||||
/* Skip verify of record_special_symbol, has predicate. */
|
||||
/* Skip verify of get_syscall_number, has predicate. */
|
||||
/* Skip verify of stap_integer_prefix, invalid_p == 0 */
|
||||
/* Skip verify of stap_integer_suffix, invalid_p == 0 */
|
||||
/* Skip verify of stap_register_prefix, invalid_p == 0 */
|
||||
/* Skip verify of stap_register_suffix, invalid_p == 0 */
|
||||
/* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */
|
||||
/* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */
|
||||
/* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */
|
||||
/* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */
|
||||
/* Skip verify of stap_is_single_operand, has predicate. */
|
||||
/* Skip verify of stap_parse_special_token, has predicate. */
|
||||
/* Skip verify of has_global_solist, invalid_p == 0 */
|
||||
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
|
||||
/* Skip verify of has_shared_address_space, invalid_p == 0 */
|
||||
@ -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)
|
||||
{
|
||||
|
120
gdb/gdbarch.h
120
gdb/gdbarch.h
@ -55,6 +55,7 @@ struct core_regset_section;
|
||||
struct syscall;
|
||||
struct agent_expr;
|
||||
struct axs_value;
|
||||
struct stap_parse_info;
|
||||
|
||||
/* The architecture associated with the connection to the target.
|
||||
|
||||
@ -979,6 +980,125 @@ typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, pti
|
||||
extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
|
||||
extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
|
||||
|
||||
/* SystemTap related fields and functions.
|
||||
Prefix used to mark an integer constant on the architecture's assembly
|
||||
For example, on x86 integer constants are written as:
|
||||
|
||||
$10 ;; integer constant 10
|
||||
|
||||
in this case, this prefix would be the character `$'. */
|
||||
|
||||
extern const char * gdbarch_stap_integer_prefix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch, const char * stap_integer_prefix);
|
||||
|
||||
/* Suffix used to mark an integer constant on the architecture's assembly. */
|
||||
|
||||
extern const char * gdbarch_stap_integer_suffix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch, const char * stap_integer_suffix);
|
||||
|
||||
/* Prefix used to mark a register name on the architecture's assembly.
|
||||
For example, on x86 the register name is written as:
|
||||
|
||||
%eax ;; register eax
|
||||
|
||||
in this case, this prefix would be the character `%'. */
|
||||
|
||||
extern const char * gdbarch_stap_register_prefix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch, const char * stap_register_prefix);
|
||||
|
||||
/* Suffix used to mark a register name on the architecture's assembly */
|
||||
|
||||
extern const char * gdbarch_stap_register_suffix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch, const char * stap_register_suffix);
|
||||
|
||||
/* Prefix used to mark a register indirection on the architecture's assembly.
|
||||
For example, on x86 the register indirection is written as:
|
||||
|
||||
(%eax) ;; indirecting eax
|
||||
|
||||
in this case, this prefix would be the charater `('.
|
||||
|
||||
Please note that we use the indirection prefix also for register
|
||||
displacement, e.g., `4(%eax)' on x86. */
|
||||
|
||||
extern const char * gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch, const char * stap_register_indirection_prefix);
|
||||
|
||||
/* Suffix used to mark a register indirection on the architecture's assembly.
|
||||
For example, on x86 the register indirection is written as:
|
||||
|
||||
(%eax) ;; indirecting eax
|
||||
|
||||
in this case, this prefix would be the charater `)'.
|
||||
|
||||
Please note that we use the indirection suffix also for register
|
||||
displacement, e.g., `4(%eax)' on x86. */
|
||||
|
||||
extern const char * gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch, const char * stap_register_indirection_suffix);
|
||||
|
||||
/* Prefix used to name a register using GDB's nomenclature.
|
||||
|
||||
For example, on PPC a register is represented by a number in the assembly
|
||||
language (e.g., `10' is the 10th general-purpose register). However,
|
||||
inside GDB this same register has an `r' appended to its name, so the 10th
|
||||
register would be represented as `r10' internally. */
|
||||
|
||||
extern const char * gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_gdb_register_prefix (struct gdbarch *gdbarch, const char * stap_gdb_register_prefix);
|
||||
|
||||
/* Suffix used to name a register using GDB's nomenclature. */
|
||||
|
||||
extern const char * gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch);
|
||||
extern void set_gdbarch_stap_gdb_register_suffix (struct gdbarch *gdbarch, const char * stap_gdb_register_suffix);
|
||||
|
||||
/* Check if S is a single operand.
|
||||
|
||||
Single operands can be:
|
||||
- Literal integers, e.g. `$10' on x86
|
||||
- Register access, e.g. `%eax' on x86
|
||||
- Register indirection, e.g. `(%eax)' on x86
|
||||
- Register displacement, e.g. `4(%eax)' on x86
|
||||
|
||||
This function should check for these patterns on the string
|
||||
and return 1 if some were found, or zero otherwise. Please try to match
|
||||
as much info as you can from the string, i.e., if you have to match
|
||||
something like `(%', do not match just the `('. */
|
||||
|
||||
extern int gdbarch_stap_is_single_operand_p (struct gdbarch *gdbarch);
|
||||
|
||||
typedef int (gdbarch_stap_is_single_operand_ftype) (struct gdbarch *gdbarch, const char *s);
|
||||
extern int gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, const char *s);
|
||||
extern void set_gdbarch_stap_is_single_operand (struct gdbarch *gdbarch, gdbarch_stap_is_single_operand_ftype *stap_is_single_operand);
|
||||
|
||||
/* Function used to handle a "special case" in the parser.
|
||||
|
||||
A "special case" is considered to be an unknown token, i.e., a token
|
||||
that the parser does not know how to parse. A good example of special
|
||||
case would be ARM's register displacement syntax:
|
||||
|
||||
[R0, #4] ;; displacing R0 by 4
|
||||
|
||||
Since the parser assumes that a register displacement is of the form:
|
||||
|
||||
<number> <indirection_prefix> <register_name> <indirection_suffix>
|
||||
|
||||
it means that it will not be able to recognize and parse this odd syntax.
|
||||
Therefore, we should add a special case function that will handle this token.
|
||||
|
||||
This function should generate the proper expression form of the expression
|
||||
using GDB's internal expression mechanism (e.g., `write_exp_elt_opcode'
|
||||
and so on). It should also return 1 if the parsing was successful, or zero
|
||||
if the token was not recognized as a special token (in this case, returning
|
||||
zero means that the special parser is deferring the parsing to the generic
|
||||
parser), and should advance the buffer pointer (p->arg). */
|
||||
|
||||
extern int gdbarch_stap_parse_special_token_p (struct gdbarch *gdbarch);
|
||||
|
||||
typedef int (gdbarch_stap_parse_special_token_ftype) (struct gdbarch *gdbarch, struct stap_parse_info *p);
|
||||
extern int gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, struct stap_parse_info *p);
|
||||
extern void set_gdbarch_stap_parse_special_token (struct gdbarch *gdbarch, gdbarch_stap_parse_special_token_ftype *stap_parse_special_token);
|
||||
|
||||
/* True if the list of shared libraries is one and only for all
|
||||
processes, as opposed to a list of shared libraries per inferior.
|
||||
This usually means that all processes, although may or may not share
|
||||
|
@ -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.
|
||||
|
||||
|
336
gdb/i386-tdep.c
336
gdb/i386-tdep.c
@ -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). */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
26
gdb/parse.c
26
gdb/parse.c
@ -113,8 +113,6 @@ show_parserdebug (struct ui_file *file, int from_tty,
|
||||
|
||||
static void free_funcalls (void *ignore);
|
||||
|
||||
static int prefixify_expression (struct expression *);
|
||||
|
||||
static int prefixify_subexp (struct expression *, struct expression *, int,
|
||||
int);
|
||||
|
||||
@ -182,13 +180,9 @@ free_funcalls (void *ignore)
|
||||
/* This page contains the functions for adding data to the struct expression
|
||||
being constructed. */
|
||||
|
||||
/* Helper function to initialize the expout, expout_size, expout_ptr
|
||||
trio before it is used to store expression elements created during
|
||||
the parsing of an expression. INITIAL_SIZE is the initial size of
|
||||
the expout array. LANG is the language used to parse the expression.
|
||||
And GDBARCH is the gdbarch to use during parsing. */
|
||||
/* See definition in parser-defs.h. */
|
||||
|
||||
static void
|
||||
void
|
||||
initialize_expout (int initial_size, const struct language_defn *lang,
|
||||
struct gdbarch *gdbarch)
|
||||
{
|
||||
@ -200,11 +194,9 @@ initialize_expout (int initial_size, const struct language_defn *lang,
|
||||
expout->gdbarch = gdbarch;
|
||||
}
|
||||
|
||||
/* Helper function that frees any unsed space in the expout array.
|
||||
It is generally used when the parser has just been parsed and
|
||||
created. */
|
||||
/* See definition in parser-defs.h. */
|
||||
|
||||
static void
|
||||
void
|
||||
reallocate_expout (void)
|
||||
{
|
||||
/* Record the actual number of expression elements, and then
|
||||
@ -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);
|
||||
|
@ -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 *);
|
||||
|
@ -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
788
gdb/probe.c
Normal 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
221
gdb/probe.h
Normal 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) */
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
1558
gdb/stap-probe.c
Normal file
File diff suppressed because it is too large
Load Diff
52
gdb/stap-probe.h
Normal file
52
gdb/stap-probe.h
Normal 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) */
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user