From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4624 invoked by alias); 14 Mar 2011 05:26:18 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 4590 invoked by uid 9813); 14 Mar 2011 05:26:16 -0000 Date: Mon, 14 Mar 2011 05:26:00 -0000 Message-ID: <20110314052616.4571.qmail@sourceware.org> From: sergiodj@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] archer-sergiodj-stap: Initial implementation of the argument evaluation for probes. X-Git-Refname: refs/heads/archer-sergiodj-stap X-Git-Reftype: branch X-Git-Oldrev: a62f1cbf34669576a356a7559cc33a4479483255 X-Git-Newrev: fe14f2b3be3b8360e7aa4a566f764c84747021b4 X-SW-Source: 2011-q1/txt/msg00189.txt.bz2 List-Id: The branch, archer-sergiodj-stap has been updated via fe14f2b3be3b8360e7aa4a566f764c84747021b4 (commit) from a62f1cbf34669576a356a7559cc33a4479483255 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit fe14f2b3be3b8360e7aa4a566f764c84747021b4 Author: Sergio Durigan Junior Date: Mon Mar 14 02:23:40 2011 -0300 Initial implementation of the argument evaluation for probes. This is *not* the final implementation, and this commit contains a lot of trash that will be cleaned ASAP. It already works for simple expressions like `%eax', or simple integer expressions. I will certainly have to work more in order to make it work as desired, but this commit already implements lots of features. ----------------------------------------------------------------------- Summary of changes: gdb/elfread.c | 13 +- gdb/stap-probe.c | 802 +++++++++++++++++++++++++++++++++++++++++++++++++++++- gdb/stap-probe.h | 6 + 3 files changed, 813 insertions(+), 8 deletions(-) First 500 lines of diff: diff --git a/gdb/elfread.c b/gdb/elfread.c index b86073a..ec4ba9f 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -1085,7 +1085,7 @@ handle_probe (struct objfile *objfile, struct sdt_note *el, { bfd *abfd = objfile->obfd; int size = bfd_get_arch_size (abfd) / 8; - struct gdbarch *gdbarch = get_current_arch (); + struct gdbarch *gdbarch = get_objfile_arch (objfile); struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; CORE_ADDR base_ref; @@ -1240,6 +1240,15 @@ elf_get_probe_argument_count (struct objfile *objfile, return stap_get_probe_argument_count (probe); } +static struct value * +elf_evaluate_probe_argument (struct objfile *objfile, + const struct stap_probe *probe, + struct frame_info *frame, + int n) +{ + return stap_evaluate_probe_argument (objfile, probe, frame, n); +} + static void elf_symfile_relocate_probe (struct objfile *objfile, struct section_offsets *new_offsets, @@ -1279,7 +1288,7 @@ 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 */ - NULL, /* sym_evaluate_probe_argument */ + elf_evaluate_probe_argument, /* sym_evaluate_probe_argument */ NULL, /* sym_compile_to_ax */ elf_symfile_relocate_probe, /* sym_relocate_probe */ }; diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c index c23cb96..2e54d79 100644 --- a/gdb/stap-probe.c +++ b/gdb/stap-probe.c @@ -30,6 +30,7 @@ #include "exceptions.h" #include "ax.h" #include "ax-gdb.h" +#include "user-regs.h" #include @@ -49,6 +50,9 @@ struct stap_probe_arg /* The string representing this argument. */ char *arg_str; + + /* The evaluated value of this argument. */ + struct value *val; }; #define STAP_MAX_ARGS 10 @@ -124,7 +128,7 @@ stap_parse_arg (const char **p) case '+': case '-': // break; - + case '*': case '/': case '>': case '<': case '|': case '&': case '^': case '!': @@ -183,8 +187,7 @@ stap_parse_arg (const char **p) if (*cur >= 'a' && *cur <= 'z') { /* We're dealing with a register name. */ - while ((*cur >= 'a' && *cur <= 'z') - || (*cur >= '0' && *cur <= '9')) + while (isalnum (*cur)) ++cur; stap_skip_whitespace_cond (&cur, paren_open); @@ -199,7 +202,7 @@ stap_parse_arg (const char **p) { ++cur; stap_skip_whitespace_cond (&cur, paren_open); - if (*cur < '0' || *cur > '9') + if (!isdigit (*cur)) /* This is an error, since we only expect numbers inside this parenthesis. */ return 0; @@ -223,18 +226,52 @@ stap_parse_arg (const char **p) while (isdigit (*cur)) ++cur; + + stap_skip_whitespace_cond (&cur, paren_open); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { + char *old = cur; + /* Number. */ while (isdigit (*cur)) ++cur; - stap_skip_whitespace_cond (&cur, paren_open); + /* We have to do a lookahead here, because the user may + input `2 + 2' (with spaces), and this is not an error. */ + ep_skip_leading_whitespace (&cur); + + switch (*cur) + { + case '+': case '-': + /* We may find the `@' sign, and it means that the + argument has finished, so we shouldn't advance the + pointer. */ + if (cur[1] && (cur[1] == '4' || cur[1] == '8') + && cur[2] && cur[2] == '@') + { + cur = old; + goto fin; + } + break; + + case '*': case '/': case '>': case '<': + case '|': case '&': case '^': case '!': + /* This is a binary operation, which means we'll + have to find another number after the operator. */ + break; + + case '(': + /* We may also have sentences in the form: + + `4 (%rax)' */ + break; + } } +fin: break; } } @@ -251,8 +288,10 @@ stap_free_args_info (void *args_info_ptr) int i; for (i = 0; i < STAP_MAX_ARGS; i++) - if (a->arg->arg_str) + { xfree (a->arg->arg_str); + xfree (a->arg->val); + } xfree (a->arg); xfree (a); @@ -406,6 +445,757 @@ stap_get_probe_argument_count (const struct stap_probe *probe) return probe->parsed_args->n_args; } +#define REG_NAME_MAX_SIZE 20 + +#if 0 + +static struct value * +stap_get_register_value (char **s) +{ +} + +static struct value * +stap_evaluate_unary_op (char **unary_ptr) +{ + struct value *tmp_res = NULL; + char *s = *unary_ptr; + char sign = *s; + + gdb_assert (*s == '+' || *s == '-'); + ++s; + ep_skip_leading_whitespace (&s); + + if (isdigit (*s)) + { + int number = (int) strtol (s, &s, 0); + + tmp_res + = value_from_longest (builtin_type (gdbarch)->builtin_int, + number); + } + else if (*s == '%') + tmp_res = stap_get_register_value (&s); + + if (tmp_res && sign == '-') + tmp_res = value_neg (tmp_res); + + ep_skip_leading_whitespace (&s); + + *unary_ptr = s; + + return tmp_res; +} + +static enum exp_opcode +stap_binary_expr_opcode (char **s) +{ + switch (**s) + { + case '+': + *s += 1; + return BINOP_ADD; + + case '-': + *s += 1; + return BINOP_SUB; + + case '*': + *s += 1; + return BINOP_MUL; + + case '/': + *s += 1; + return BINOP_DIV; + + case '%': + *s += 1; + return BINOP_REM; + + case '&': + *s += 1; + if (**s == '&') + return BINOP_LOGICAL_AND; + return BINOP_BITWISE_AND; + + case '|': + *s += 1; + if (**s == '|') + return BINOP_LOGICAL_OR; + return BINOP_BITWISE_IOR; + + default: + /*ERROR*/ + return 0; + } +} + +static void +stap_evaluate_probe_argument_1 (struct objfile *objfile, + const struct stap_probe *probe, + struct frame_info *frame, + int n) +{ + struct gdbarch *gdbarch = get_objfile_arch (objfile); + char *s = (char *) probe->parsed_args->arg[n].arg_str; + struct value *final_res = NULL; + enum + { + EVAL_INIT, + EVAL_INDIRECT_REG, + EVAL_REGISTER, + EVAL_PAREN, + EVAL_UNOP, + EVAL_BINOP, + } eval_arg_state; + + eval_arg_state = EVAL_INIT; + + probe->parsed_args->arg[n].val = NULL; + + while (*s) + { + switch (eval_arg_state) + { + /* Ideia: Fazer um parser que dê conta de exprs. + + Por ex: -2+(4-(23+3)) + + a ideia eh pegar primeiro o -, ver que eh unario, + criar um value pro -2, depois ver o + (sem consumir), + chamar uma fcao pra avaliar a segunda parte do binario, + depois chamar uma fcao pra avaliar + parenteses, depois pegar o 4, ver que eh binario e salvar + esse value, chamar fcao pra avaliar parent, ver que eh bin, avaliar + e retornar o value, e ir retornando em cascata. */ + + case EVAL_INIT: + { + switch (*s) + { + case '+': case '-': + eval_arg_state = EVAL_UNOP; + break; + + case '(': + if (s[1] == '%') + eval_arg_state = EVAL_REGISTER; + else + eval_arg_state = EVAL_PAREN; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + eval_arg_state = EVAL_BINOP; + break; + } + } + break; + + case EVAL_UNOP: + { + final_res = stap_evaluate_unary_op (&s); + + if (!final_res) + ; /* ERROR */ + + if (stap_is_binary_op (*s)) + eval_arg_state = EVAL_BINOP; +// else if (*s == '(') +// eval_arg_state = EVAL_PAREN; + else if (*s) + ; /* ERROR */ + } + break; + + case EVAL_BINOP: + { + struct value *tmp_res = NULL; + enum exp_opcode opcode; + + gdb_assert (stap_is_binary_op (s)); + + opcode = stap_binary_expr_opcode (&s); + + ++s; + ep_skip_leading_whitespace (&s); + + switch (*s) + { + case '+': case '-': + { + tmp_res = stap_evaluate_unary_op (&s); + + if (!tmp_res) + ; /*ERROR*/ + } + break; + + case '(': + { + tmp_res = stap_evaluate_paren (&s); + + if (!tmp_res) + ; /*ERROR*/ + } + break; + } + + final_res = value_binop (final_res, tmp_res, opcode); + + ep_skip_leading_whitespace (&s); + } + break; +#if 0 + case '+': case '-': + { + /* This is the beginning of an unary operator. */ + struct value *unary_res; + char c = *s; + + ++s; + ep_skip_leading_whitespace (&s); + if (isdigit (*s)) + { + int number = (int) strtol (s, &s, 0); + struct value *tmp_res; + + if (c == '-') + number *= -1; + + tmp_res + = value_from_longest (builtin_type (gdbarch)->builtin_int, + number); + + ep_skip_leading_whitespace (&s); + + if (*s == '(' && s[1] == '%') + { + struct value *regval; + + ++s; + regval = stap_get_register_value (&s); + + /* Now indirect the register's value. */ + } + } + else if (*s == '(') + { + char *start = s; + + ep_skip_leading_whitespace (&s); + + if (*s == '%') + stap_get_register_value (s); + } + } + break; + + case '(': + { + ++s; + + if (*s == '%') + { + char regname[REG_NAME_MAX_SIZE + 1]; + const char *start; + int len, regnum; + + /* This is a register name. */ + ++s; + start = s; + while (isalnum (*s)) + ++s; + + if (*s != ')') + return; + + len = s - start; + + if (len >= REG_NAME_MAX_SIZE) + return; + + strncpy (regname, start, len); + regname[len] = '\0'; + + regnum = user_reg_map_name_to_regnum (gdbarch, regname, len); + } + } + break; +#endif + } + } +} +#endif + +static int +stap_get_operator_prec (enum exp_opcode op) +{ + switch (op) + { + case BINOP_LOGICAL_OR: + return 1; + + case BINOP_LOGICAL_AND: + return 2; + + 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 3; + + case BINOP_BITWISE_IOR: case BINOP_BITWISE_AND: + case BINOP_BITWISE_XOR: case UNOP_LOGICAL_NOT: + return 4; + + case BINOP_MUL: case BINOP_DIV: case BINOP_REM: + case BINOP_LSH: case BINOP_RSH: + return 5; + + default: + return 0; + } +} + +static int +stap_get_opcode (char **s, enum exp_opcode *op) +{ + char c = **s; + + *s += 1; + + switch (c) + { + case '*': + *op = BINOP_MUL; + break; + + case '/': + *op = BINOP_DIV; + break; + + case '%': + { + if (isalpha (**s)) + /* Dealing with a register name. */ + break; + + *op = BINOP_REM; + } + break; + + case '<': + *op = BINOP_LESS; + if (**s == '<') hooks/post-receive -- Repository for Project Archer.