Skip to content

Commit 3a0c26e

Browse files
namhyungacmel
authored andcommitted
perf annotate: Add annotate_get_insn_location()
The annotate_get_insn_location() is to get the detailed information of instruction locations like registers and offset. It has source and target operands locations in an array. Each operand can have a register and an offset. The offset is meaningful when mem_ref flag is set. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: linux-toolchains@vger.kernel.org Cc: linux-trace-devel@vger.kernel.org Link: https://lore.kernel.org/r/20231213001323.718046-7-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 0669729 commit 3a0c26e

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

tools/perf/util/annotate.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "bpf-utils.h"
3232
#include "block-range.h"
3333
#include "string2.h"
34+
#include "dwarf-regs.h"
3435
#include "util/event.h"
3536
#include "util/sharded_mutex.h"
3637
#include "arch/common.h"
@@ -3518,3 +3519,109 @@ int annotate_check_args(void)
35183519
}
35193520
return 0;
35203521
}
3522+
3523+
/*
3524+
* Get register number and access offset from the given instruction.
3525+
* It assumes AT&T x86 asm format like OFFSET(REG). Maybe it needs
3526+
* to revisit the format when it handles different architecture.
3527+
* Fills @reg and @offset when return 0.
3528+
*/
3529+
static int extract_reg_offset(struct arch *arch, const char *str,
3530+
struct annotated_op_loc *op_loc)
3531+
{
3532+
char *p;
3533+
char *regname;
3534+
3535+
if (arch->objdump.register_char == 0)
3536+
return -1;
3537+
3538+
/*
3539+
* It should start from offset, but it's possible to skip 0
3540+
* in the asm. So 0(%rax) should be same as (%rax).
3541+
*
3542+
* However, it also start with a segment select register like
3543+
* %gs:0x18(%rbx). In that case it should skip the part.
3544+
*/
3545+
if (*str == arch->objdump.register_char) {
3546+
while (*str && !isdigit(*str) &&
3547+
*str != arch->objdump.memory_ref_char)
3548+
str++;
3549+
}
3550+
3551+
op_loc->offset = strtol(str, &p, 0);
3552+
3553+
p = strchr(p, arch->objdump.register_char);
3554+
if (p == NULL)
3555+
return -1;
3556+
3557+
regname = strdup(p);
3558+
if (regname == NULL)
3559+
return -1;
3560+
3561+
op_loc->reg = get_dwarf_regnum(regname, 0);
3562+
free(regname);
3563+
return 0;
3564+
}
3565+
3566+
/**
3567+
* annotate_get_insn_location - Get location of instruction
3568+
* @arch: the architecture info
3569+
* @dl: the target instruction
3570+
* @loc: a buffer to save the data
3571+
*
3572+
* Get detailed location info (register and offset) in the instruction.
3573+
* It needs both source and target operand and whether it accesses a
3574+
* memory location. The offset field is meaningful only when the
3575+
* corresponding mem flag is set.
3576+
*
3577+
* Some examples on x86:
3578+
*
3579+
* mov (%rax), %rcx # src_reg = rax, src_mem = 1, src_offset = 0
3580+
* # dst_reg = rcx, dst_mem = 0
3581+
*
3582+
* mov 0x18, %r8 # src_reg = -1, dst_reg = r8
3583+
*/
3584+
int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
3585+
struct annotated_insn_loc *loc)
3586+
{
3587+
struct ins_operands *ops;
3588+
struct annotated_op_loc *op_loc;
3589+
int i;
3590+
3591+
if (!strcmp(dl->ins.name, "lock"))
3592+
ops = dl->ops.locked.ops;
3593+
else
3594+
ops = &dl->ops;
3595+
3596+
if (ops == NULL)
3597+
return -1;
3598+
3599+
memset(loc, 0, sizeof(*loc));
3600+
3601+
for_each_insn_op_loc(loc, i, op_loc) {
3602+
const char *insn_str = ops->source.raw;
3603+
3604+
if (i == INSN_OP_TARGET)
3605+
insn_str = ops->target.raw;
3606+
3607+
/* Invalidate the register by default */
3608+
op_loc->reg = -1;
3609+
3610+
if (insn_str == NULL)
3611+
continue;
3612+
3613+
if (strchr(insn_str, arch->objdump.memory_ref_char)) {
3614+
op_loc->mem_ref = true;
3615+
extract_reg_offset(arch, insn_str, op_loc);
3616+
} else {
3617+
char *s = strdup(insn_str);
3618+
3619+
if (s) {
3620+
op_loc->reg = get_dwarf_regnum(s, 0);
3621+
free(s);
3622+
}
3623+
}
3624+
}
3625+
3626+
return 0;
3627+
}

tools/perf/util/annotate.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,4 +439,40 @@ int annotate_parse_percent_type(const struct option *opt, const char *_str,
439439

440440
int annotate_check_args(void);
441441

442+
/**
443+
* struct annotated_op_loc - Location info of instruction operand
444+
* @reg: Register in the operand
445+
* @offset: Memory access offset in the operand
446+
* @mem_ref: Whether the operand accesses memory
447+
*/
448+
struct annotated_op_loc {
449+
int reg;
450+
int offset;
451+
bool mem_ref;
452+
};
453+
454+
enum annotated_insn_ops {
455+
INSN_OP_SOURCE = 0,
456+
INSN_OP_TARGET = 1,
457+
458+
INSN_OP_MAX,
459+
};
460+
461+
/**
462+
* struct annotated_insn_loc - Location info of instruction
463+
* @ops: Array of location info for source and target operands
464+
*/
465+
struct annotated_insn_loc {
466+
struct annotated_op_loc ops[INSN_OP_MAX];
467+
};
468+
469+
#define for_each_insn_op_loc(insn_loc, i, op_loc) \
470+
for (i = INSN_OP_SOURCE, op_loc = &(insn_loc)->ops[i]; \
471+
i < INSN_OP_MAX; \
472+
i++, op_loc++)
473+
474+
/* Get detailed location info in the instruction */
475+
int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
476+
struct annotated_insn_loc *loc);
477+
442478
#endif /* __PERF_ANNOTATE_H */

0 commit comments

Comments
 (0)