perf annotate: Update parameters for reg extract functions to use raw instruction on powerpc
Use the raw instruction code and macros to identify memory instructions, extract register fields and also offset. The implementation addresses the D-form, X-form, DS-form instructions. Adds "mem_ref" field to check whether source/target has memory reference. Add function "get_powerpc_regs" which will set these fields: reg1, reg2, offset depending of where it is source or target ops. Update "parse" callback for "struct ins_ops" to also pass "struct disasm_line" as argument. This is needed in parse functions where opcode is used to determine whether to set multi_regs and other fields Reviewed-by: Kajol Jain <kjain@linux.ibm.com> Reviewed-by: Namhyung Kim <namhyung@kernel.org> Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Tested-by: Kajol Jain <kjain@linux.ibm.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Akanksha J N <akanksha@linux.ibm.com> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> Cc: Disha Goel <disgoel@linux.vnet.ibm.com> Cc: Hari Bathini <hbathini@linux.ibm.com> Cc: Ian Rogers <irogers@google.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Madhavan Srinivasan <maddy@linux.ibm.com> Cc: Segher Boessenkool <segher@kernel.crashing.org> Link: https://lore.kernel.org/lkml/20240718084358.72242-7-atrajeev@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
0b971e6bf1
commit
1b4406d2a8
@ -11,7 +11,8 @@ struct arm64_annotate {
|
||||
|
||||
static int arm64_mov__parse(struct arch *arch __maybe_unused,
|
||||
struct ins_operands *ops,
|
||||
struct map_symbol *ms __maybe_unused)
|
||||
struct map_symbol *ms __maybe_unused,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *s = strchr(ops->raw, ','), *target, *endptr;
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
* Copyright (C) 2020-2023 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
|
||||
static int loongarch_call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *c, *endptr, *tok, *name;
|
||||
struct map *map = ms->map;
|
||||
@ -51,7 +52,8 @@ static struct ins_ops loongarch_call_ops = {
|
||||
.scnprintf = call__scnprintf,
|
||||
};
|
||||
|
||||
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
|
||||
static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
struct map *map = ms->map;
|
||||
struct symbol *sym = ms->sym;
|
||||
|
@ -107,3 +107,47 @@ int regs_query_register_offset(const char *name)
|
||||
#define PPC_DS(DS) ((DS) & 0xfffc)
|
||||
#define OP_LD 58
|
||||
#define OP_STD 62
|
||||
|
||||
static int get_source_reg(u32 raw_insn)
|
||||
{
|
||||
return PPC_RA(raw_insn);
|
||||
}
|
||||
|
||||
static int get_target_reg(u32 raw_insn)
|
||||
{
|
||||
return PPC_RT(raw_insn);
|
||||
}
|
||||
|
||||
static int get_offset_opcode(u32 raw_insn)
|
||||
{
|
||||
int opcode = PPC_OP(raw_insn);
|
||||
|
||||
/* DS- form */
|
||||
if ((opcode == OP_LD) || (opcode == OP_STD))
|
||||
return PPC_DS(raw_insn);
|
||||
else
|
||||
return PPC_D(raw_insn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills the required fields for op_loc depending on if it
|
||||
* is a source or target.
|
||||
* D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT
|
||||
* DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT
|
||||
* X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT
|
||||
*/
|
||||
void get_powerpc_regs(u32 raw_insn, int is_source,
|
||||
struct annotated_op_loc *op_loc)
|
||||
{
|
||||
if (is_source)
|
||||
op_loc->reg1 = get_source_reg(raw_insn);
|
||||
else
|
||||
op_loc->reg1 = get_target_reg(raw_insn);
|
||||
|
||||
if (op_loc->multi_regs)
|
||||
op_loc->reg2 = PPC_RB(raw_insn);
|
||||
|
||||
/* TODO: Implement offset handling for X Form */
|
||||
if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31))
|
||||
op_loc->offset = get_offset_opcode(raw_insn);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <linux/compiler.h>
|
||||
|
||||
static int s390_call__parse(struct arch *arch, struct ins_operands *ops,
|
||||
struct map_symbol *ms)
|
||||
struct map_symbol *ms, struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *endptr, *tok, *name;
|
||||
struct map *map = ms->map;
|
||||
@ -52,7 +52,8 @@ static struct ins_ops s390_call_ops = {
|
||||
|
||||
static int s390_mov__parse(struct arch *arch __maybe_unused,
|
||||
struct ins_operands *ops,
|
||||
struct map_symbol *ms __maybe_unused)
|
||||
struct map_symbol *ms __maybe_unused,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *s = strchr(ops->raw, ','), *target, *endptr;
|
||||
|
||||
|
@ -2123,20 +2123,33 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
|
||||
for_each_insn_op_loc(loc, i, op_loc) {
|
||||
const char *insn_str = ops->source.raw;
|
||||
bool multi_regs = ops->source.multi_regs;
|
||||
bool mem_ref = ops->source.mem_ref;
|
||||
|
||||
if (i == INSN_OP_TARGET) {
|
||||
insn_str = ops->target.raw;
|
||||
multi_regs = ops->target.multi_regs;
|
||||
mem_ref = ops->target.mem_ref;
|
||||
}
|
||||
|
||||
/* Invalidate the register by default */
|
||||
op_loc->reg1 = -1;
|
||||
op_loc->reg2 = -1;
|
||||
|
||||
if (insn_str == NULL)
|
||||
continue;
|
||||
if (insn_str == NULL) {
|
||||
if (!arch__is(arch, "powerpc"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strchr(insn_str, arch->objdump.memory_ref_char)) {
|
||||
/*
|
||||
* For powerpc, call get_powerpc_regs function which extracts the
|
||||
* required fields for op_loc, ie reg1, reg2, offset from the
|
||||
* raw instruction.
|
||||
*/
|
||||
if (arch__is(arch, "powerpc")) {
|
||||
op_loc->mem_ref = mem_ref;
|
||||
op_loc->multi_regs = multi_regs;
|
||||
get_powerpc_regs(dl->raw.raw_insn, !i, op_loc);
|
||||
} else if (strchr(insn_str, arch->objdump.memory_ref_char)) {
|
||||
op_loc->mem_ref = true;
|
||||
op_loc->multi_regs = multi_regs;
|
||||
extract_reg_offset(arch, insn_str, op_loc);
|
||||
|
@ -255,7 +255,8 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2)
|
||||
return arch->ins_is_fused(arch, ins1, ins2);
|
||||
}
|
||||
|
||||
static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
|
||||
static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *endptr, *tok, *name;
|
||||
struct map *map = ms->map;
|
||||
@ -350,7 +351,8 @@ static inline const char *validate_comma(const char *c, struct ins_operands *ops
|
||||
return c;
|
||||
}
|
||||
|
||||
static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
|
||||
static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
struct map *map = ms->map;
|
||||
struct symbol *sym = ms->sym;
|
||||
@ -509,7 +511,8 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
|
||||
static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
|
||||
if (ops->locked.ops == NULL)
|
||||
@ -524,7 +527,7 @@ static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_s
|
||||
goto out_free_ops;
|
||||
|
||||
if (ops->locked.ins.ops->parse &&
|
||||
ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0)
|
||||
ops->locked.ins.ops->parse(arch, ops->locked.ops, ms, NULL) < 0)
|
||||
goto out_free_ops;
|
||||
|
||||
return 0;
|
||||
@ -595,7 +598,8 @@ static bool check_multi_regs(struct arch *arch, const char *op)
|
||||
return count > 1;
|
||||
}
|
||||
|
||||
static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
|
||||
static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *s = strchr(ops->raw, ','), *target, *comment, prev;
|
||||
|
||||
@ -673,7 +677,8 @@ static struct ins_ops mov_ops = {
|
||||
.scnprintf = mov__scnprintf,
|
||||
};
|
||||
|
||||
static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
|
||||
static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused,
|
||||
struct disasm_line *dl __maybe_unused)
|
||||
{
|
||||
char *target, *comment, *s, prev;
|
||||
|
||||
@ -814,7 +819,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, str
|
||||
if (!dl->ins.ops)
|
||||
return;
|
||||
|
||||
if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0)
|
||||
if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms, dl) < 0)
|
||||
dl->ins.ops = NULL;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,7 @@ struct ins_operands {
|
||||
bool offset_avail;
|
||||
bool outside;
|
||||
bool multi_regs;
|
||||
bool mem_ref;
|
||||
} target;
|
||||
union {
|
||||
struct {
|
||||
@ -69,6 +70,7 @@ struct ins_operands {
|
||||
char *name;
|
||||
u64 addr;
|
||||
bool multi_regs;
|
||||
bool mem_ref;
|
||||
} source;
|
||||
struct {
|
||||
struct ins ins;
|
||||
@ -83,7 +85,8 @@ struct ins_operands {
|
||||
|
||||
struct ins_ops {
|
||||
void (*free)(struct ins_operands *ops);
|
||||
int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);
|
||||
int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms,
|
||||
struct disasm_line *dl);
|
||||
int (*scnprintf)(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops, int max_ins_name);
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _PERF_DWARF_REGS_H_
|
||||
#define _PERF_DWARF_REGS_H_
|
||||
#include "annotate.h"
|
||||
|
||||
#define DWARF_REG_PC 0xd3af9c /* random number */
|
||||
#define DWARF_REG_FB 0xd3affb /* random number */
|
||||
@ -31,6 +32,16 @@ static inline int get_dwarf_regnum(const char *name __maybe_unused,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(__powerpc__) || !defined(HAVE_DWARF_SUPPORT)
|
||||
static inline void get_powerpc_regs(u32 raw_insn __maybe_unused, int is_source __maybe_unused,
|
||||
struct annotated_op_loc *op_loc __maybe_unused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
void get_powerpc_regs(u32 raw_insn, int is_source, struct annotated_op_loc *op_loc);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
|
||||
/*
|
||||
* Arch should support fetching the offset of a register in pt_regs
|
||||
|
Loading…
Reference in New Issue
Block a user