/* * Perf only supports OP which is in +/-NUM(REG) form. * Here plus-minus sign, NUM and parenthesis are optional, * only REG is mandatory. * * SDT events also supports indirect addressing mode with a * symbol as offset, scaled mode and constants in OP. But * perf does not support them yet. Below are few examples. * * OP with scaled mode: * (%rax,%rsi,8) * 10(%ras,%rsi,8) * * OP with indirect addressing mode: * check_action(%rip) * mp_+52(%rip) * 44+mp_(%rip) * * OP with constant values: * $0 * $123 * $-1
*/ #define SDT_OP_REGEX "^([+\\-]?)([0-9]*)(\\(?)(%[a-z][a-z0-9]+)(\\)?)$"
static regex_t sdt_op_regex;
staticint sdt_init_op_regex(void)
{ staticint 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;
}
/* * Max x86 register name length is 5(ex: %r15d). So, 6th char * should always contain NULL. This helps to find register name * length using strlen, instead of maintaining one more variable.
*/ #define SDT_REG_NAME_SIZE 6
/* * The uprobe parser does not support all gas register names; * so, we have to replace them (ex. for x86_64: %rax -> %ax). * Note: If register does not require renaming, just copy * paste as it is, but don't leave it empty.
*/ staticvoid sdt_rename_register(char *sdt_reg, int sdt_len, char *uprobe_reg)
{ int i = 0;
for (i = 0; sdt_reg_tbl[i].sdt_name != NULL; i++) { if (!strncmp(sdt_reg_tbl[i].sdt_name, sdt_reg, sdt_len)) {
strcpy(uprobe_reg, sdt_reg_tbl[i].uprobe_name); return;
}
}
strncpy(uprobe_reg, sdt_reg, sdt_len);
}
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 maintaining 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); elseif (rm[2].rm_so != rm[2].rm_eo)
prefix[0] = '+'; else
scnprintf(prefix, sizeof(prefix), "+0");
}
uint64_t arch__intr_reg_mask(void)
{ struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR,
.sample_regs_intr = PERF_REG_EXTENDED_MASK,
.precise_ip = 1,
.disabled = 1,
.exclude_kernel = 1,
}; int fd; /* * In an unnamed union, init it here to build on older gcc versions
*/
attr.sample_period = 1;
if (perf_pmus__num_core_pmus() > 1) { struct perf_pmu *pmu = NULL;
__u64 type = PERF_TYPE_RAW;
/* * The same register set is supported among different hybrid PMUs. * Only check the first available one.
*/ while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
type = pmu->type; break;
}
attr.config |= type << PERF_PMU_TYPE_SHIFT;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.