Commit 1acdad68 authored by Athira Rajeev's avatar Athira Rajeev Committed by Arnaldo Carvalho de Melo

perf annotate: Add parse function for memory instructions in 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.
Two main functions are added.

New parse function "load_store__parse" as instruction ops parser for
memory instructions.

Unlike other parsers (like mov__parse), this one fills in the
"multi_regs" field for source/target and new added "mem_ref" field. No
other fields are set because, here there is no need to parse the
disassembled code and arch specific macros will take care of extracting
offset and regs which is easier and will be precise.

In powerpc, all instructions with a primary opcode from 32 to 63
are memory instructions. Update "ins__find" function to have "raw_insn"
also as a parameter.
Reviewed-by: default avatarKajol Jain <kjain@linux.ibm.com>
Reviewed-by: default avatarNamhyung Kim <namhyung@kernel.org>
Signed-off-by: default avatarAthira Rajeev <atrajeev@linux.vnet.ibm.com>
Tested-by: default avatarKajol 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-8-atrajeev@linux.vnet.ibm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1b4406d2
......@@ -49,6 +49,22 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
return ops;
}
#define PPC_OP(op) (((op) >> 26) & 0x3F)
static struct ins_ops *check_ppc_insn(u32 raw_insn)
{
int opcode = PPC_OP(raw_insn);
/*
* Instructions with opcode 32 to 63 are memory
* instructions in powerpc
*/
if ((opcode & 0x20))
return &load_store_ops;
return NULL;
}
static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
if (!arch->initialized) {
......
......@@ -36,6 +36,7 @@ static struct ins_ops mov_ops;
static struct ins_ops nop_ops;
static struct ins_ops lock_ops;
static struct ins_ops ret_ops;
static struct ins_ops load_store_ops;
static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
struct ins_operands *ops, int max_ins_name);
......@@ -521,7 +522,7 @@ static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_s
if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
goto out_free_ops;
ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name, 0);
if (ops->locked.ins.ops == NULL)
goto out_free_ops;
......@@ -677,6 +678,37 @@ static struct ins_ops mov_ops = {
.scnprintf = mov__scnprintf,
};
static int load_store__scnprintf(struct ins *ins, char *bf, size_t size,
struct ins_operands *ops, int max_ins_name)
{
return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
ops->raw);
}
/*
* Sets the fields: multi_regs and "mem_ref".
* "mem_ref" is set for ops->source which is later used to
* fill the objdump->memory_ref-char field. This ops is currently
* used by powerpc and since binary instruction code is used to
* extract opcode, regs and offset, no other parsing is needed here
*/
static int load_store__parse(struct arch *arch __maybe_unused, struct ins_operands *ops,
struct map_symbol *ms __maybe_unused, struct disasm_line *dl __maybe_unused)
{
ops->source.mem_ref = true;
ops->source.multi_regs = false;
ops->target.mem_ref = false;
ops->target.multi_regs = false;
return 0;
}
static struct ins_ops load_store_ops = {
.parse = load_store__parse,
.scnprintf = load_store__scnprintf,
};
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)
{
......@@ -768,11 +800,23 @@ static void ins__sort(struct arch *arch)
qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
}
static struct ins_ops *__ins__find(struct arch *arch, const char *name)
static struct ins_ops *__ins__find(struct arch *arch, const char *name, u32 raw_insn)
{
struct ins *ins;
const int nmemb = arch->nr_instructions;
if (arch__is(arch, "powerpc")) {
/*
* For powerpc, identify the instruction ops
* from the opcode using raw_insn.
*/
struct ins_ops *ops;
ops = check_ppc_insn(raw_insn);
if (ops)
return ops;
}
if (!arch->sorted_instructions) {
ins__sort(arch);
arch->sorted_instructions = true;
......@@ -802,9 +846,9 @@ static struct ins_ops *__ins__find(struct arch *arch, const char *name)
return ins ? ins->ops : NULL;
}
struct ins_ops *ins__find(struct arch *arch, const char *name)
struct ins_ops *ins__find(struct arch *arch, const char *name, u32 raw_insn)
{
struct ins_ops *ops = __ins__find(arch, name);
struct ins_ops *ops = __ins__find(arch, name, raw_insn);
if (!ops && arch->associate_instruction_ops)
ops = arch->associate_instruction_ops(arch, name);
......@@ -814,7 +858,7 @@ struct ins_ops *ins__find(struct arch *arch, const char *name)
static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms)
{
dl->ins.ops = ins__find(arch, dl->ins.name);
dl->ins.ops = ins__find(arch, dl->ins.name, dl->raw.raw_insn);
if (!dl->ins.ops)
return;
......
......@@ -105,7 +105,7 @@ struct annotate_args {
struct arch *arch__find(const char *name);
bool arch__is(struct arch *arch, const char *name);
struct ins_ops *ins__find(struct arch *arch, const char *name);
struct ins_ops *ins__find(struct arch *arch, const char *name, u32 raw_insn);
int ins__scnprintf(struct ins *ins, char *bf, size_t size,
struct ins_operands *ops, int max_ins_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment