/* * Parse OP and convert it into uprobe format, which is, +/-NUM(%gprREG). * Possible variants of OP are: * Format Example * ------------------------- * NUM(REG) 48(18) * -NUM(REG) -48(18) * NUM(%rREG) 48(%r18) * -NUM(%rREG) -48(%r18) * REG 18 * %rREG %r18 * iNUM i0 * i-NUM i-1 * * SDT marker arguments on Powerpc uses %rREG form with -mregnames flag * and REG form with -mno-regnames. Here REG is general purpose register, * which is in 0 to 31 range. */ int arch_sdt_arg_parse_op(char *old_op, char **new_op) { int ret, new_len; regmatch_t rm[5]; char prefix; /* Constant argument. Uprobe does not support it */ if (old_op[0] == 'i') { pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); return SDT_ARG_SKIP; } ret = sdt_init_op_regex(); if (ret < 0) return ret; if (!regexec(&sdt_op_regex1, old_op, 3, rm, 0)) { /* REG or %rREG --> %gprREG */ new_len = 5; /* % g p r NULL */ new_len += (int)(rm[2].rm_eo - rm[2].rm_so); *new_op = zalloc(new_len); if (!*new_op) return -ENOMEM; scnprintf(*new_op, new_len, "%%gpr%.*s", (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so); } else if (!regexec(&sdt_op_regex2, old_op, 5, rm, 0)) { /* * -NUM(REG) or NUM(REG) or -NUM(%rREG) or NUM(%rREG) --> * +/-NUM(%gprREG) */ prefix = (rm[1].rm_so == -1) ? '+' : '-'; new_len = 8; /* +/- ( % g p r ) NULL */ new_len += (int)(rm[2].rm_eo - rm[2].rm_so); new_len += (int)(rm[4].rm_eo - rm[4].rm_so); *new_op = zalloc(new_len); if (!*new_op) return -ENOMEM; scnprintf(*new_op, new_len, "%c%.*s(%%gpr%.*s)", prefix, (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, (int)(rm[4].rm_eo - rm[4].rm_so), old_op + rm[4].rm_so); } else { pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); return SDT_ARG_SKIP; } return SDT_ARG_VALID; }
static int sdt_init_op_regex(void) { static int initialized; int ret = 0; if (initialized) return 0; ret = regcomp(&sdt_op_regex1, SDT_OP_REGEX1, REG_EXTENDED); if (ret) goto error; ret = regcomp(&sdt_op_regex2, SDT_OP_REGEX2, REG_EXTENDED); if (ret) goto free_regex1; initialized = 1; return 0; free_regex1: regfree(&sdt_op_regex1); error: pr_debug4("Regex compilation error.\n"); return ret; }
static int sdt_init_op_regex(void) { static int initialized; int ret = 0; if (initialized) return 0; ret = regcomp(&sdt_op_regex, SDT_OP_REGEX, REG_EXTENDED); if (ret < 0) { pr_debug4("Regex compilation error.\n"); return ret; } initialized = 1; return 0; }
static struct symbol *symbol__new(u64 start, u64 len, const char *name) { size_t namelen = strlen(name) + 1; struct symbol *self = zalloc(symbol_conf.priv_size + sizeof(*self) + namelen); if (self == NULL) return NULL; if (symbol_conf.priv_size) self = ((void *)self) + symbol_conf.priv_size; self->start = start; self->end = len ? start + len - 1 : start; pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); memcpy(self->name, name, namelen); return self; }
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) { size_t namelen = strlen(name) + 1; struct symbol *sym = calloc(1, (symbol_conf.priv_size + sizeof(*sym) + namelen)); if (sym == NULL) return NULL; if (symbol_conf.priv_size) sym = ((void *)sym) + symbol_conf.priv_size; sym->start = start; sym->end = len ? start + len - 1 : start; sym->binding = binding; sym->namelen = namelen - 1; pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, sym->end); memcpy(sym->name, name, namelen); return sym; }
int arch_sdt_arg_parse_op(char *old_op, char **new_op) { char new_reg[SDT_REG_NAME_SIZE] = {0}; int new_len = 0, ret; /* * rm[0]: +/-NUM(REG) * rm[1]: +/- * rm[2]: NUM * rm[3]: ( * rm[4]: REG * rm[5]: ) */ regmatch_t rm[6]; /* * Max prefix length is 2 as it may contains sign(+/-) * and displacement 0 (Both sign and displacement 0 are * optional so it may be empty). Use one more character * to hold last NULL so that strlen can be used to find * prefix length, instead of maintaing one more variable. */ char prefix[3] = {0}; ret = sdt_init_op_regex(); if (ret < 0) return ret; /* * If unsupported OR does not match with regex OR * register name too long, skip it. */ if (strchr(old_op, ',') || strchr(old_op, '$') || regexec(&sdt_op_regex, old_op, 6, rm, 0) || rm[4].rm_eo - rm[4].rm_so > SDT_REG_NAME_SIZE) { pr_debug4("Skipping unsupported SDT argument: %s\n", old_op); return SDT_ARG_SKIP; } /* * Prepare prefix. * If SDT OP has parenthesis but does not provide * displacement, add 0 for displacement. * SDT Uprobe Prefix * ----------------------------- * +24(%rdi) +24(%di) + * 24(%rdi) +24(%di) + * %rdi %di * (%rdi) +0(%di) +0 * -80(%rbx) -80(%bx) - */ if (rm[3].rm_so != rm[3].rm_eo) { if (rm[1].rm_so != rm[1].rm_eo) prefix[0] = *(old_op + rm[1].rm_so); else if (rm[2].rm_so != rm[2].rm_eo) prefix[0] = '+'; else scnprintf(prefix, sizeof(prefix), "+0"); } /* Rename register */ sdt_rename_register(old_op + rm[4].rm_so, rm[4].rm_eo - rm[4].rm_so, new_reg); /* Prepare final OP which should be valid for uprobe_events */ new_len = strlen(prefix) + (rm[2].rm_eo - rm[2].rm_so) + (rm[3].rm_eo - rm[3].rm_so) + strlen(new_reg) + (rm[5].rm_eo - rm[5].rm_so) + 1; /* NULL */ *new_op = zalloc(new_len); if (!*new_op) return -ENOMEM; scnprintf(*new_op, new_len, "%.*s%.*s%.*s%.*s%.*s", strlen(prefix), prefix, (int)(rm[2].rm_eo - rm[2].rm_so), old_op + rm[2].rm_so, (int)(rm[3].rm_eo - rm[3].rm_so), old_op + rm[3].rm_so, strlen(new_reg), new_reg, (int)(rm[5].rm_eo - rm[5].rm_so), old_op + rm[5].rm_so); return SDT_ARG_VALID; }