gdb/stap-probe.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "stap-probe.h"
- #include "probe.h"
- #include "vec.h"
- #include "ui-out.h"
- #include "objfiles.h"
- #include "arch-utils.h"
- #include "command.h"
- #include "gdbcmd.h"
- #include "filenames.h"
- #include "value.h"
- #include "ax.h"
- #include "ax-gdb.h"
- #include "complaints.h"
- #include "cli/cli-utils.h"
- #include "linespec.h"
- #include "user-regs.h"
- #include "parser-defs.h"
- #include "language.h"
- #include "elf-bfd.h"
- #include <ctype.h>
- #define STAP_BASE_SECTION_NAME ".stapsdt.base"
- static const struct probe_ops stap_probe_ops;
- static unsigned int stap_expression_debug = 0;
- enum stap_arg_bitness
- {
- STAP_ARG_BITNESS_UNDEFINED,
- STAP_ARG_BITNESS_8BIT_UNSIGNED,
- STAP_ARG_BITNESS_8BIT_SIGNED,
- STAP_ARG_BITNESS_16BIT_UNSIGNED,
- STAP_ARG_BITNESS_16BIT_SIGNED,
- STAP_ARG_BITNESS_32BIT_UNSIGNED,
- STAP_ARG_BITNESS_32BIT_SIGNED,
- STAP_ARG_BITNESS_64BIT_UNSIGNED,
- STAP_ARG_BITNESS_64BIT_SIGNED,
- };
- struct stap_probe_arg
- {
-
- enum stap_arg_bitness bitness;
-
- struct type *atype;
-
- struct expression *aexpr;
- };
- typedef struct stap_probe_arg stap_probe_arg_s;
- DEF_VEC_O (stap_probe_arg_s);
- struct stap_probe
- {
-
- struct probe p;
-
- CORE_ADDR sem_addr;
-
- unsigned int args_parsed : 1;
- union
- {
- const char *text;
-
- VEC (stap_probe_arg_s) *vec;
- }
- args_u;
- };
- enum stap_operand_prec
- {
-
- STAP_OPERAND_PREC_NONE = 0,
-
- STAP_OPERAND_PREC_LOGICAL_OR,
-
- STAP_OPERAND_PREC_LOGICAL_AND,
-
- STAP_OPERAND_PREC_ADD_CMP,
-
- STAP_OPERAND_PREC_BITWISE,
-
- STAP_OPERAND_PREC_MUL
- };
- static void stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
- enum stap_operand_prec prec);
- static void stap_parse_argument_conditionally (struct stap_parse_info *p);
- static int stap_is_operator (const char *op);
- static void
- show_stapexpressiondebug (struct ui_file *file, int from_tty,
- struct cmd_list_element *c, const char *value)
- {
- fprintf_filtered (file, _("SystemTap Probe expression debugging is %s.\n"),
- value);
- }
- static enum stap_operand_prec
- stap_get_operator_prec (enum exp_opcode op)
- {
- switch (op)
- {
- case BINOP_LOGICAL_OR:
- return STAP_OPERAND_PREC_LOGICAL_OR;
- case BINOP_LOGICAL_AND:
- return STAP_OPERAND_PREC_LOGICAL_AND;
- case BINOP_ADD:
- case BINOP_SUB:
- case BINOP_EQUAL:
- case BINOP_NOTEQUAL:
- case BINOP_LESS:
- case BINOP_LEQ:
- case BINOP_GTR:
- case BINOP_GEQ:
- return STAP_OPERAND_PREC_ADD_CMP;
- case BINOP_BITWISE_IOR:
- case BINOP_BITWISE_AND:
- case BINOP_BITWISE_XOR:
- case UNOP_LOGICAL_NOT:
- return STAP_OPERAND_PREC_BITWISE;
- case BINOP_MUL:
- case BINOP_DIV:
- case BINOP_REM:
- case BINOP_LSH:
- case BINOP_RSH:
- return STAP_OPERAND_PREC_MUL;
- default:
- return STAP_OPERAND_PREC_NONE;
- }
- }
- static enum exp_opcode
- stap_get_opcode (const char **s)
- {
- const char c = **s;
- enum exp_opcode op;
- *s += 1;
- switch (c)
- {
- case '*':
- op = BINOP_MUL;
- break;
- case '/':
- op = BINOP_DIV;
- break;
- case '%':
- op = BINOP_REM;
- break;
- case '<':
- op = BINOP_LESS;
- if (**s == '<')
- {
- *s += 1;
- op = BINOP_LSH;
- }
- else if (**s == '=')
- {
- *s += 1;
- op = BINOP_LEQ;
- }
- else if (**s == '>')
- {
- *s += 1;
- op = BINOP_NOTEQUAL;
- }
- break;
- case '>':
- op = BINOP_GTR;
- if (**s == '>')
- {
- *s += 1;
- op = BINOP_RSH;
- }
- else if (**s == '=')
- {
- *s += 1;
- op = BINOP_GEQ;
- }
- break;
- case '|':
- op = BINOP_BITWISE_IOR;
- if (**s == '|')
- {
- *s += 1;
- op = BINOP_LOGICAL_OR;
- }
- break;
- case '&':
- op = BINOP_BITWISE_AND;
- if (**s == '&')
- {
- *s += 1;
- op = BINOP_LOGICAL_AND;
- }
- break;
- case '^':
- op = BINOP_BITWISE_XOR;
- break;
- case '!':
- op = UNOP_LOGICAL_NOT;
- break;
- case '+':
- op = BINOP_ADD;
- break;
- case '-':
- op = BINOP_SUB;
- break;
- case '=':
- gdb_assert (**s == '=');
- op = BINOP_EQUAL;
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("Invalid opcode in expression `%s' for SystemTap"
- "probe"), *s);
- }
- return op;
- }
- static struct type *
- stap_get_expected_argument_type (struct gdbarch *gdbarch,
- enum stap_arg_bitness b)
- {
- switch (b)
- {
- case STAP_ARG_BITNESS_UNDEFINED:
- if (gdbarch_addr_bit (gdbarch) == 32)
- return builtin_type (gdbarch)->builtin_uint32;
- else
- return builtin_type (gdbarch)->builtin_uint64;
- case STAP_ARG_BITNESS_8BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint8;
- case STAP_ARG_BITNESS_8BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int8;
- case STAP_ARG_BITNESS_16BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint16;
- case STAP_ARG_BITNESS_16BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int16;
- case STAP_ARG_BITNESS_32BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int32;
- case STAP_ARG_BITNESS_32BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint32;
- case STAP_ARG_BITNESS_64BIT_SIGNED:
- return builtin_type (gdbarch)->builtin_int64;
- case STAP_ARG_BITNESS_64BIT_UNSIGNED:
- return builtin_type (gdbarch)->builtin_uint64;
- default:
- internal_error (__FILE__, __LINE__,
- _("Undefined bitness for probe."));
- break;
- }
- }
- static int
- stap_is_generic_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r, const char *const *prefixes)
- {
- const char *const *p;
- if (prefixes == NULL)
- {
- if (r != NULL)
- *r = "";
- return 1;
- }
- for (p = prefixes; *p != NULL; ++p)
- if (strncasecmp (s, *p, strlen (*p)) == 0)
- {
- if (r != NULL)
- *r = *p;
- return 1;
- }
- return 0;
- }
- static int
- stap_is_register_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_register_prefixes (gdbarch);
- return stap_is_generic_prefix (gdbarch, s, r, t);
- }
- static int
- stap_is_register_indirection_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_register_indirection_prefixes (gdbarch);
- return stap_is_generic_prefix (gdbarch, s, r, t);
- }
- static int
- stap_is_integer_prefix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *t = gdbarch_stap_integer_prefixes (gdbarch);
- const char *const *p;
- if (t == NULL)
- {
-
- if (r != NULL)
- *r = "";
- return isdigit (*s);
- }
- for (p = t; *p != NULL; ++p)
- {
- size_t len = strlen (*p);
- if ((len == 0 && isdigit (*s))
- || (len > 0 && strncasecmp (s, *p, len) == 0))
- {
-
- if (r != NULL)
- *r = *p;
- return 1;
- }
- }
- return 0;
- }
- static int
- stap_generic_check_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r, const char *const *suffixes)
- {
- const char *const *p;
- int found = 0;
- if (suffixes == NULL)
- {
- if (r != NULL)
- *r = "";
- return 1;
- }
- for (p = suffixes; *p != NULL; ++p)
- if (strncasecmp (s, *p, strlen (*p)) == 0)
- {
- if (r != NULL)
- *r = *p;
- found = 1;
- break;
- }
- return found;
- }
- static int
- stap_check_integer_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_integer_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- static int
- stap_check_register_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_register_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- static int
- stap_check_register_indirection_suffix (struct gdbarch *gdbarch, const char *s,
- const char **r)
- {
- const char *const *p = gdbarch_stap_register_indirection_suffixes (gdbarch);
- return stap_generic_check_suffix (gdbarch, s, r, p);
- }
- static void
- stap_parse_register_operand (struct stap_parse_info *p)
- {
-
- int got_minus = 0;
-
- int disp_p = 0, indirect_p = 0;
- struct gdbarch *gdbarch = p->gdbarch;
-
- struct stoken str;
-
- const char *start;
- char *regname;
- int len;
- const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch);
- int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0;
- const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch);
- int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0;
- const char *reg_prefix;
- const char *reg_ind_prefix;
- const char *reg_suffix;
- const char *reg_ind_suffix;
-
- if (*p->arg == '+')
- {
-
- ++p->arg;
- }
- if (*p->arg == '-')
- {
- got_minus = 1;
- ++p->arg;
- }
- if (isdigit (*p->arg))
- {
-
- long displacement;
- char *endp;
- disp_p = 1;
- displacement = strtol (p->arg, &endp, 10);
- p->arg = endp;
-
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (&p->pstate, displacement);
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- if (got_minus)
- write_exp_elt_opcode (&p->pstate, UNOP_NEG);
- }
-
- if (stap_is_register_indirection_prefix (gdbarch, p->arg, ®_ind_prefix))
- {
- indirect_p = 1;
- p->arg += strlen (reg_ind_prefix);
- }
- if (disp_p && !indirect_p)
- error (_("Invalid register displacement syntax on expression `%s'."),
- p->saved_arg);
-
- if (stap_is_register_prefix (gdbarch, p->arg, ®_prefix))
- p->arg += strlen (reg_prefix);
-
- start = p->arg;
-
- while (isalnum (*p->arg))
- ++p->arg;
- len = p->arg - start;
- regname = alloca (len + gdb_reg_prefix_len + gdb_reg_suffix_len + 1);
- regname[0] = '\0';
-
- if (gdb_reg_prefix && isdigit (*start))
- {
- strncpy (regname, gdb_reg_prefix, gdb_reg_prefix_len);
- strncpy (regname + gdb_reg_prefix_len, start, len);
- if (gdb_reg_suffix)
- strncpy (regname + gdb_reg_prefix_len + len,
- gdb_reg_suffix, gdb_reg_suffix_len);
- len += gdb_reg_prefix_len + gdb_reg_suffix_len;
- }
- else
- strncpy (regname, start, len);
- regname[len] = '\0';
-
- 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 (&p->pstate, OP_REGISTER);
- str.ptr = regname;
- str.length = len;
- write_exp_string (&p->pstate, str);
- write_exp_elt_opcode (&p->pstate, OP_REGISTER);
- if (indirect_p)
- {
- if (disp_p)
- write_exp_elt_opcode (&p->pstate, BINOP_ADD);
-
- write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
- write_exp_elt_opcode (&p->pstate, UNOP_CAST);
- write_exp_elt_opcode (&p->pstate, UNOP_IND);
- }
-
- if (stap_check_register_suffix (gdbarch, p->arg, ®_suffix))
- p->arg += strlen (reg_suffix);
- else
- error (_("Missing register name suffix on expression `%s'."),
- p->saved_arg);
-
- if (indirect_p)
- {
- if (stap_check_register_indirection_suffix (gdbarch, p->arg,
- ®_ind_suffix))
- p->arg += strlen (reg_ind_suffix);
- else
- error (_("Missing indirection suffix on expression `%s'."),
- p->saved_arg);
- }
- }
- static void
- stap_parse_single_operand (struct stap_parse_info *p)
- {
- struct gdbarch *gdbarch = p->gdbarch;
- const char *int_prefix = NULL;
-
- if (gdbarch_stap_parse_special_token_p (gdbarch))
- if (gdbarch_stap_parse_special_token (gdbarch, p) != 0)
- {
-
- return;
- }
- if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+')
- {
- char c = *p->arg;
-
- const char *tmp = p->arg;
- int has_digit = 0;
-
- ++tmp;
-
- if (p->inside_paren_p)
- tmp = skip_spaces_const (tmp);
- while (isdigit (*tmp))
- {
-
- ++tmp;
- has_digit = 1;
- }
- if (has_digit && stap_is_register_indirection_prefix (gdbarch, tmp,
- NULL))
- {
-
- if (c == '~')
- error (_("Invalid operator `%c' for register displacement "
- "on expression `%s'."), c, p->saved_arg);
- stap_parse_register_operand (p);
- }
- else
- {
-
- ++p->arg;
- stap_parse_argument_conditionally (p);
- if (c == '-')
- write_exp_elt_opcode (&p->pstate, UNOP_NEG);
- else if (c == '~')
- write_exp_elt_opcode (&p->pstate, UNOP_COMPLEMENT);
- }
- }
- else if (isdigit (*p->arg))
- {
-
- const char *tmp = p->arg;
- char *endp;
- long number;
-
- number = strtol (tmp, &endp, 10);
- tmp = endp;
- if (p->inside_paren_p)
- tmp = skip_spaces_const (tmp);
-
- if (stap_is_integer_prefix (gdbarch, p->arg, NULL)
- && !stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
- {
- const char *int_suffix;
-
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- write_exp_elt_type (&p->pstate,
- builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (&p->pstate, number);
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- p->arg = tmp;
- if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
- p->arg += strlen (int_suffix);
- else
- error (_("Invalid constant suffix on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_register_indirection_prefix (gdbarch, tmp, NULL))
- stap_parse_register_operand (p);
- else
- error (_("Unknown numeric token on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_integer_prefix (gdbarch, p->arg, &int_prefix))
- {
-
- long number;
- char *endp;
- const char *int_suffix;
- p->arg += strlen (int_prefix);
- number = strtol (p->arg, &endp, 10);
- p->arg = endp;
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
- write_exp_elt_longcst (&p->pstate, number);
- write_exp_elt_opcode (&p->pstate, OP_LONG);
- if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix))
- p->arg += strlen (int_suffix);
- else
- error (_("Invalid constant suffix on expression `%s'."),
- p->saved_arg);
- }
- else if (stap_is_register_prefix (gdbarch, p->arg, NULL)
- || stap_is_register_indirection_prefix (gdbarch, p->arg, NULL))
- stap_parse_register_operand (p);
- else
- error (_("Operator `%c' not recognized on expression `%s'."),
- *p->arg, p->saved_arg);
- }
- static void
- stap_parse_argument_conditionally (struct stap_parse_info *p)
- {
- gdb_assert (gdbarch_stap_is_single_operand_p (p->gdbarch));
- if (*p->arg == '-' || *p->arg == '~' || *p->arg == '+'
- || isdigit (*p->arg)
- || gdbarch_stap_is_single_operand (p->gdbarch, p->arg))
- stap_parse_single_operand (p);
- else if (*p->arg == '(')
- {
-
- ++p->arg;
- p->arg = skip_spaces_const (p->arg);
- ++p->inside_paren_p;
- stap_parse_argument_1 (p, 0, STAP_OPERAND_PREC_NONE);
- --p->inside_paren_p;
- if (*p->arg != ')')
- error (_("Missign close-paren on expression `%s'."),
- p->saved_arg);
- ++p->arg;
- if (p->inside_paren_p)
- p->arg = skip_spaces_const (p->arg);
- }
- else
- error (_("Cannot parse expression `%s'."), p->saved_arg);
- }
- static void
- stap_parse_argument_1 (struct stap_parse_info *p, int has_lhs,
- enum stap_operand_prec prec)
- {
-
- gdb_assert (p->arg != NULL);
- if (p->inside_paren_p)
- p->arg = skip_spaces_const (p->arg);
- if (!has_lhs)
- {
-
- stap_parse_argument_conditionally (p);
- }
-
- while (*p->arg != '\0' && *p->arg != ')' && !isspace (*p->arg))
- {
- const char *tmp_exp_buf;
- enum exp_opcode opcode;
- enum stap_operand_prec cur_prec;
- if (!stap_is_operator (p->arg))
- error (_("Invalid operator `%c' on expression `%s'."), *p->arg,
- p->saved_arg);
-
- tmp_exp_buf = p->arg;
- opcode = stap_get_opcode (&tmp_exp_buf);
- cur_prec = stap_get_operator_prec (opcode);
- if (cur_prec < prec)
- {
-
- break;
- }
- p->arg = tmp_exp_buf;
- if (p->inside_paren_p)
- p->arg = skip_spaces_const (p->arg);
-
- stap_parse_argument_conditionally (p);
-
- while (*p->arg != '\0' && stap_is_operator (p->arg))
- {
- enum exp_opcode lookahead_opcode;
- enum stap_operand_prec lookahead_prec;
-
- tmp_exp_buf = p->arg;
- lookahead_opcode = stap_get_opcode (&tmp_exp_buf);
- lookahead_prec = stap_get_operator_prec (lookahead_opcode);
- if (lookahead_prec <= prec)
- {
-
- break;
- }
-
- stap_parse_argument_1 (p, 1, lookahead_prec);
- }
- write_exp_elt_opcode (&p->pstate, opcode);
- }
- }
- static struct expression *
- stap_parse_argument (const char **arg, struct type *atype,
- struct gdbarch *gdbarch)
- {
- struct stap_parse_info p;
- struct cleanup *back_to;
-
- initialize_expout (&p.pstate, 10, language_def (language_c), gdbarch);
- back_to = make_cleanup (free_current_contents, &p.pstate.expout);
- p.saved_arg = *arg;
- p.arg = *arg;
- p.arg_type = atype;
- p.gdbarch = gdbarch;
- p.inside_paren_p = 0;
- stap_parse_argument_1 (&p, 0, STAP_OPERAND_PREC_NONE);
- discard_cleanups (back_to);
- gdb_assert (p.inside_paren_p == 0);
-
- write_exp_elt_opcode (&p.pstate, UNOP_CAST);
- write_exp_elt_type (&p.pstate, atype);
- write_exp_elt_opcode (&p.pstate, UNOP_CAST);
- reallocate_expout (&p.pstate);
- p.arg = skip_spaces_const (p.arg);
- *arg = p.arg;
-
- return p.pstate.expout;
- }
- static void
- stap_parse_probe_arguments (struct stap_probe *probe, struct gdbarch *gdbarch)
- {
- const char *cur;
- gdb_assert (!probe->args_parsed);
- cur = probe->args_u.text;
- probe->args_parsed = 1;
- probe->args_u.vec = NULL;
- if (cur == NULL || *cur == '\0' || *cur == ':')
- return;
- while (*cur != '\0')
- {
- struct stap_probe_arg arg;
- enum stap_arg_bitness b;
- int got_minus = 0;
- struct expression *expr;
- memset (&arg, 0, sizeof (arg));
-
- if ((cur[0] == '-' && isdigit (cur[1]) && cur[2] == '@')
- || (isdigit (cur[0]) && cur[1] == '@'))
- {
- if (*cur == '-')
- {
-
- ++cur;
- got_minus = 1;
- }
-
- switch (*cur)
- {
- case '1':
- b = (got_minus ? STAP_ARG_BITNESS_8BIT_SIGNED
- : STAP_ARG_BITNESS_8BIT_UNSIGNED);
- break;
- case '2':
- b = (got_minus ? STAP_ARG_BITNESS_16BIT_SIGNED
- : STAP_ARG_BITNESS_16BIT_UNSIGNED);
- break;
- case '4':
- b = (got_minus ? STAP_ARG_BITNESS_32BIT_SIGNED
- : STAP_ARG_BITNESS_32BIT_UNSIGNED);
- break;
- case '8':
- b = (got_minus ? STAP_ARG_BITNESS_64BIT_SIGNED
- : STAP_ARG_BITNESS_64BIT_UNSIGNED);
- break;
- default:
- {
-
- warning (_("unrecognized bitness %s%c' for probe `%s'"),
- got_minus ? "`-" : "`", *cur, probe->p.name);
- return;
- }
- }
- arg.bitness = b;
-
- cur += 2;
- }
- else
- arg.bitness = STAP_ARG_BITNESS_UNDEFINED;
- arg.atype = stap_get_expected_argument_type (gdbarch, arg.bitness);
- expr = stap_parse_argument (&cur, arg.atype, gdbarch);
- if (stap_expression_debug)
- dump_raw_expression (expr, gdb_stdlog,
- "before conversion to prefix form");
- prefixify_expression (expr);
- if (stap_expression_debug)
- dump_prefix_expression (expr, gdb_stdlog);
- arg.aexpr = expr;
-
- cur = skip_spaces_const (cur);
- VEC_safe_push (stap_probe_arg_s, probe->args_u.vec, &arg);
- }
- }
- static CORE_ADDR
- stap_get_probe_address (struct probe *probe, struct objfile *objfile)
- {
- return probe->address + ANOFFSET (objfile->section_offsets,
- SECT_OFF_DATA (objfile));
- }
- static unsigned
- stap_get_probe_argument_count (struct probe *probe_generic,
- struct frame_info *frame)
- {
- struct stap_probe *probe = (struct stap_probe *) probe_generic;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- if (!probe->args_parsed)
- {
- if (can_evaluate_probe_arguments (probe_generic))
- stap_parse_probe_arguments (probe, gdbarch);
- else
- {
- static int have_warned_stap_incomplete = 0;
- if (!have_warned_stap_incomplete)
- {
- warning (_(
- "The SystemTap SDT probe support is not fully implemented on this target;\n"
- "you will not be able to inspect the arguments of the probes.\n"
- "Please report a bug against GDB requesting a port to this target."));
- have_warned_stap_incomplete = 1;
- }
-
- probe->args_u.vec = NULL;
- probe->args_parsed = 1;
- }
- }
- gdb_assert (probe->args_parsed);
- return VEC_length (stap_probe_arg_s, probe->args_u.vec);
- }
- static int
- stap_is_operator (const char *op)
- {
- int ret = 1;
- switch (*op)
- {
- case '*':
- case '/':
- case '%':
- case '^':
- case '!':
- case '+':
- case '-':
- case '<':
- case '>':
- case '|':
- case '&':
- break;
- case '=':
- if (op[1] != '=')
- ret = 0;
- break;
- default:
-
- ret = 0;
- }
- return ret;
- }
- static struct stap_probe_arg *
- stap_get_arg (struct stap_probe *probe, unsigned n, struct gdbarch *gdbarch)
- {
- if (!probe->args_parsed)
- stap_parse_probe_arguments (probe, gdbarch);
- return VEC_index (stap_probe_arg_s, probe->args_u.vec, n);
- }
- static int
- stap_can_evaluate_probe_arguments (struct probe *probe_generic)
- {
- struct stap_probe *stap_probe = (struct stap_probe *) probe_generic;
- struct gdbarch *gdbarch = stap_probe->p.arch;
-
- return gdbarch_stap_is_single_operand_p (gdbarch);
- }
- static struct value *
- stap_evaluate_probe_argument (struct probe *probe_generic, unsigned n,
- struct frame_info *frame)
- {
- struct stap_probe *stap_probe = (struct stap_probe *) probe_generic;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct stap_probe_arg *arg;
- int pos = 0;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- arg = stap_get_arg (stap_probe, n, gdbarch);
- return evaluate_subexp_standard (arg->atype, arg->aexpr, &pos, EVAL_NORMAL);
- }
- static void
- stap_compile_to_ax (struct probe *probe_generic, struct agent_expr *expr,
- struct axs_value *value, unsigned n)
- {
- struct stap_probe *stap_probe = (struct stap_probe *) probe_generic;
- struct stap_probe_arg *arg;
- union exp_element *pc;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- arg = stap_get_arg (stap_probe, n, expr->gdbarch);
- pc = arg->aexpr->elts;
- gen_expr (arg->aexpr, &pc, expr, value);
- require_rvalue (expr, value);
- value->type = arg->atype;
- }
- static void
- stap_probe_destroy (struct probe *probe_generic)
- {
- struct stap_probe *probe = (struct stap_probe *) probe_generic;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- if (probe->args_parsed)
- {
- struct stap_probe_arg *arg;
- int ix;
- for (ix = 0; VEC_iterate (stap_probe_arg_s, probe->args_u.vec, ix, arg);
- ++ix)
- xfree (arg->aexpr);
- VEC_free (stap_probe_arg_s, probe->args_u.vec);
- }
- }
- static struct value *
- compute_probe_arg (struct gdbarch *arch, struct internalvar *ivar,
- void *data)
- {
- struct frame_info *frame = get_selected_frame (_("No frame selected"));
- CORE_ADDR pc = get_frame_pc (frame);
- int sel = (int) (uintptr_t) data;
- struct bound_probe pc_probe;
- const struct sym_probe_fns *pc_probe_fns;
- unsigned n_args;
-
- gdb_assert (sel >= -1);
- pc_probe = find_probe_by_pc (pc);
- if (pc_probe.probe == NULL)
- error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
- n_args = get_probe_argument_count (pc_probe.probe, frame);
- if (sel == -1)
- return value_from_longest (builtin_type (arch)->builtin_int, n_args);
- if (sel >= n_args)
- error (_("Invalid probe argument %d -- probe has %u arguments available"),
- sel, n_args);
- return evaluate_probe_argument (pc_probe.probe, sel, frame);
- }
- static void
- compile_probe_arg (struct internalvar *ivar, struct agent_expr *expr,
- struct axs_value *value, void *data)
- {
- CORE_ADDR pc = expr->scope;
- int sel = (int) (uintptr_t) data;
- struct bound_probe pc_probe;
- const struct sym_probe_fns *pc_probe_fns;
- int n_args;
- struct frame_info *frame = get_selected_frame (NULL);
-
- gdb_assert (sel >= -1);
- pc_probe = find_probe_by_pc (pc);
- if (pc_probe.probe == NULL)
- error (_("No SystemTap probe at PC %s"), core_addr_to_string (pc));
- n_args = get_probe_argument_count (pc_probe.probe, frame);
- if (sel == -1)
- {
- value->kind = axs_rvalue;
- value->type = builtin_type (expr->gdbarch)->builtin_int;
- ax_const_l (expr, n_args);
- return;
- }
- gdb_assert (sel >= 0);
- if (sel >= n_args)
- error (_("Invalid probe argument %d -- probe has %d arguments available"),
- sel, n_args);
- pc_probe.probe->pops->compile_to_ax (pc_probe.probe, expr, value, sel);
- }
- static void
- stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
- {
- gdb_byte bytes[sizeof (LONGEST)];
-
- struct type *type = builtin_type (gdbarch)->builtin_unsigned_short;
- ULONGEST value;
- if (address == 0)
- return;
-
- if (target_read_memory (address, bytes, TYPE_LENGTH (type)) != 0)
- {
- warning (_("Could not read the value of a SystemTap semaphore."));
- return;
- }
- value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
- gdbarch_byte_order (gdbarch));
-
- if (set)
- ++value;
- else
- --value;
- store_unsigned_integer (bytes, TYPE_LENGTH (type),
- gdbarch_byte_order (gdbarch), value);
- if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0)
- warning (_("Could not write the value of a SystemTap semaphore."));
- }
- static void
- stap_set_semaphore (struct probe *probe_generic, struct objfile *objfile,
- struct gdbarch *gdbarch)
- {
- struct stap_probe *probe = (struct stap_probe *) probe_generic;
- CORE_ADDR addr;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- addr = (probe->sem_addr
- + ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)));
- stap_modify_semaphore (addr, 1, gdbarch);
- }
- static void
- stap_clear_semaphore (struct probe *probe_generic, struct objfile *objfile,
- struct gdbarch *gdbarch)
- {
- struct stap_probe *probe = (struct stap_probe *) probe_generic;
- CORE_ADDR addr;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- addr = (probe->sem_addr
- + ANOFFSET (objfile->section_offsets, SECT_OFF_DATA (objfile)));
- stap_modify_semaphore (addr, 0, gdbarch);
- }
- static const struct internalvar_funcs probe_funcs =
- {
- compute_probe_arg,
- compile_probe_arg,
- NULL
- };
- static void
- handle_stap_probe (struct objfile *objfile, struct sdt_note *el,
- VEC (probe_p) **probesp, CORE_ADDR base)
- {
- bfd *abfd = objfile->obfd;
- int size = bfd_get_arch_size (abfd) / 8;
- struct gdbarch *gdbarch = get_objfile_arch (objfile);
- struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
- CORE_ADDR base_ref;
- const char *probe_args = NULL;
- struct stap_probe *ret;
- ret = obstack_alloc (&objfile->per_bfd->storage_obstack, sizeof (*ret));
- ret->p.pops = &stap_probe_ops;
- ret->p.arch = gdbarch;
-
- ret->p.provider = (char *) &el->data[3 * size];
- ret->p.name = memchr (ret->p.provider, '\0',
- (char *) el->data + el->size - ret->p.provider);
-
- if (ret->p.name == NULL)
- {
- complaint (&symfile_complaints, _("corrupt probe name when "
- "reading `%s'"),
- objfile_name (objfile));
-
- return;
- }
- else
- ++ret->p.name;
-
- ret->p.address = extract_typed_address (&el->data[0], ptr_type);
-
- base_ref = extract_typed_address (&el->data[size], ptr_type);
-
- ret->sem_addr = extract_typed_address (&el->data[2 * size], ptr_type);
- ret->p.address += base - base_ref;
- if (ret->sem_addr != 0)
- ret->sem_addr += base - base_ref;
-
- probe_args = memchr (ret->p.name, '\0',
- (char *) el->data + el->size - ret->p.name);
- if (probe_args != NULL)
- ++probe_args;
- if (probe_args == NULL
- || (memchr (probe_args, '\0', (char *) el->data + el->size - ret->p.name)
- != el->data + el->size - 1))
- {
- complaint (&symfile_complaints, _("corrupt probe argument when "
- "reading `%s'"),
- objfile_name (objfile));
-
- return;
- }
- ret->args_parsed = 0;
- ret->args_u.text = (void *) probe_args;
-
- VEC_safe_push (probe_p, *probesp, (struct probe *) ret);
- }
- static void
- get_stap_base_address_1 (bfd *abfd, asection *sect, void *obj)
- {
- asection **ret = obj;
- if ((sect->flags & (SEC_DATA | SEC_ALLOC | SEC_HAS_CONTENTS))
- && sect->name && !strcmp (sect->name, STAP_BASE_SECTION_NAME))
- *ret = sect;
- }
- static int
- get_stap_base_address (bfd *obfd, bfd_vma *base)
- {
- asection *ret = NULL;
- bfd_map_over_sections (obfd, get_stap_base_address_1, (void *) &ret);
- if (ret == NULL)
- {
- complaint (&symfile_complaints, _("could not obtain base address for "
- "SystemTap section on objfile `%s'."),
- obfd->filename);
- return 0;
- }
- if (base != NULL)
- *base = ret->vma;
- return 1;
- }
- static void
- stap_get_probes (VEC (probe_p) **probesp, struct objfile *objfile)
- {
-
- bfd *obfd = objfile->obfd;
- bfd_vma base;
- struct sdt_note *iter;
- unsigned save_probesp_len = VEC_length (probe_p, *probesp);
- if (objfile->separate_debug_objfile_backlink != NULL)
- {
-
- return;
- }
- if (elf_tdata (obfd)->sdt_note_head == NULL)
- {
-
- return;
- }
- if (!get_stap_base_address (obfd, &base))
- {
-
- return;
- }
-
- for (iter = elf_tdata (obfd)->sdt_note_head;
- iter != NULL;
- iter = iter->next)
- {
-
- handle_stap_probe (objfile, iter, probesp, base);
- }
- if (save_probesp_len == VEC_length (probe_p, *probesp))
- {
-
- complaint (&symfile_complaints, _("could not parse SystemTap probe(s) "
- "from inferior"));
- return;
- }
- }
- static int
- stap_probe_is_linespec (const char **linespecp)
- {
- static const char *const keywords[] = { "-pstap", "-probe-stap", NULL };
- return probe_is_linespec_by_keyword (linespecp, keywords);
- }
- static void
- stap_gen_info_probes_table_header (VEC (info_probe_column_s) **heads)
- {
- info_probe_column_s stap_probe_column;
- stap_probe_column.field_name = "semaphore";
- stap_probe_column.print_name = _("Semaphore");
- VEC_safe_push (info_probe_column_s, *heads, &stap_probe_column);
- }
- static void
- stap_gen_info_probes_table_values (struct probe *probe_generic,
- VEC (const_char_ptr) **ret)
- {
- struct stap_probe *probe = (struct stap_probe *) probe_generic;
- struct gdbarch *gdbarch;
- const char *val = NULL;
- gdb_assert (probe_generic->pops == &stap_probe_ops);
- gdbarch = probe->p.arch;
- if (probe->sem_addr != 0)
- val = print_core_address (gdbarch, probe->sem_addr);
- VEC_safe_push (const_char_ptr, *ret, val);
- }
- static const struct probe_ops stap_probe_ops =
- {
- stap_probe_is_linespec,
- stap_get_probes,
- stap_get_probe_address,
- stap_get_probe_argument_count,
- stap_can_evaluate_probe_arguments,
- stap_evaluate_probe_argument,
- stap_compile_to_ax,
- stap_set_semaphore,
- stap_clear_semaphore,
- stap_probe_destroy,
- stap_gen_info_probes_table_header,
- stap_gen_info_probes_table_values,
- };
- static void
- info_probes_stap_command (char *arg, int from_tty)
- {
- info_probes_for_ops (arg, from_tty, &stap_probe_ops);
- }
- void _initialize_stap_probe (void);
- void
- _initialize_stap_probe (void)
- {
- VEC_safe_push (probe_ops_cp, all_probe_ops, &stap_probe_ops);
- add_setshow_zuinteger_cmd ("stap-expression", class_maintenance,
- &stap_expression_debug,
- _("Set SystemTap expression debugging."),
- _("Show SystemTap expression debugging."),
- _("When non-zero, the internal representation "
- "of SystemTap expressions will be printed."),
- NULL,
- show_stapexpressiondebug,
- &setdebuglist, &showdebuglist);
- create_internalvar_type_lazy ("_probe_argc", &probe_funcs,
- (void *) (uintptr_t) -1);
- create_internalvar_type_lazy ("_probe_arg0", &probe_funcs,
- (void *) (uintptr_t) 0);
- create_internalvar_type_lazy ("_probe_arg1", &probe_funcs,
- (void *) (uintptr_t) 1);
- create_internalvar_type_lazy ("_probe_arg2", &probe_funcs,
- (void *) (uintptr_t) 2);
- create_internalvar_type_lazy ("_probe_arg3", &probe_funcs,
- (void *) (uintptr_t) 3);
- create_internalvar_type_lazy ("_probe_arg4", &probe_funcs,
- (void *) (uintptr_t) 4);
- create_internalvar_type_lazy ("_probe_arg5", &probe_funcs,
- (void *) (uintptr_t) 5);
- create_internalvar_type_lazy ("_probe_arg6", &probe_funcs,
- (void *) (uintptr_t) 6);
- create_internalvar_type_lazy ("_probe_arg7", &probe_funcs,
- (void *) (uintptr_t) 7);
- create_internalvar_type_lazy ("_probe_arg8", &probe_funcs,
- (void *) (uintptr_t) 8);
- create_internalvar_type_lazy ("_probe_arg9", &probe_funcs,
- (void *) (uintptr_t) 9);
- create_internalvar_type_lazy ("_probe_arg10", &probe_funcs,
- (void *) (uintptr_t) 10);
- create_internalvar_type_lazy ("_probe_arg11", &probe_funcs,
- (void *) (uintptr_t) 11);
- add_cmd ("stap", class_info, info_probes_stap_command,
- _("\
- Show information about SystemTap static probes.\n\
- Usage: info probes stap [PROVIDER [NAME [OBJECT]]]\n\
- Each argument is a regular expression, used to select probes.\n\
- PROVIDER matches probe provider names.\n\
- NAME matches the probe names.\n\
- OBJECT matches the executable or shared library name."),
- info_probes_cmdlist_get ());
- }