Skip to content

Commit 06dd4c5

Browse files
athira-rajeevacmel
authored andcommitted
perf annotate: Add disasm_line__parse() to parse raw instruction for powerpc
Currently, the perf tool infrastructure uses the disasm_line__parse function to parse disassembled line. Example snippet from objdump: objdump --start-address=<address> --stop-address=<address> -d --no-show-raw-insn -C <vmlinux> c0000000010224b4: lwz r10,0(r9) This line "lwz r10,0(r9)" is parsed to extract instruction name, registers names and offset. In powerpc, the approach for data type profiling uses raw instruction instead of result from objdump to identify the instruction category and extract the source/target registers. Example: 38 01 81 e8 ld r4,312(r1) Here "38 01 81 e8" is the raw instruction representation. Add function "disasm_line__parse_powerpc" to handle parsing of raw instruction. Also update "struct disasm_line" to save the binary code/ With the change, function captures: line -> "38 01 81 e8 ld r4,312(r1)" raw instruction "38 01 81 e8" Raw instruction is used later to extract the reg/offset fields. Macros are added to extract opcode and register fields. "struct disasm_line" is updated to carry union of "bytes" and "raw_insn" of 32 bit to carry raw code (raw). Function "disasm_line__parse_powerpc fills the raw instruction hex value and can use macros to get opcode. There is no changes in existing code paths, which parses the disassembled code. The size of raw instruction depends on architecture. In case of powerpc, the parsing the disasm line needs to handle cases for reading binary code directly from DSO as well as parsing the objdump result. Hence adding the logic into separate function instead of updating "disasm_line__parse". The architecture using the instruction name and present approach is not altered. Since this approach targets powerpc, the macro implementation is added for powerpc as of now. Since the disasm_line__parse is used in other cases (perf annotate) and not only data tye profiling, the powerpc callback includes changes to work with binary code as well as mnemonic representation. Also in case if the DSO read fails and libcapstone is not supported, the approach fallback to use objdump as option. Hence as option, patch has changes to ensure objdump option also works well. Reviewed-by: Kajol Jain <[email protected]> Reviewed-by: Namhyung Kim <[email protected]> Signed-off-by: Athira Rajeev <[email protected]> Tested-by: Kajol Jain <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Akanksha J N <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Disha Goel <[email protected]> Cc: Hari Bathini <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Madhavan Srinivasan <[email protected]> Cc: Segher Boessenkool <[email protected]> Link: https://lore.kernel.org/lkml/[email protected] [ Add check for strndup() result ] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent b1d8d96 commit 06dd4c5

File tree

6 files changed

+79
-2
lines changed

6 files changed

+79
-2
lines changed

tools/include/linux/string.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ extern char * __must_check skip_spaces(const char *);
4646

4747
extern char *strim(char *);
4848

49+
extern void remove_spaces(char *s);
50+
4951
extern void *memchr_inv(const void *start, int c, size_t bytes);
5052
#endif /* _TOOLS_LINUX_STRING_H_ */

tools/lib/string.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@ char *strim(char *s)
153153
return skip_spaces(s);
154154
}
155155

156+
/*
157+
* remove_spaces - Removes whitespaces from @s
158+
*/
159+
void remove_spaces(char *s)
160+
{
161+
char *d = s;
162+
163+
do {
164+
while (*d == ' ')
165+
++d;
166+
} while ((*s++ = *d++));
167+
}
168+
156169
/**
157170
* strreplace - Replace all occurrences of character in string.
158171
* @s: The string to operate on.

tools/perf/arch/powerpc/annotate/instructions.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
5555
arch->initialized = true;
5656
arch->associate_instruction_ops = powerpc__associate_instruction_ops;
5757
arch->objdump.comment_char = '#';
58+
annotate_opts.show_asm_raw = true;
5859
}
5960

6061
return 0;

tools/perf/arch/powerpc/util/dwarf-regs.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,12 @@ int regs_query_register_offset(const char *name)
9898
return roff->ptregs_offset;
9999
return -EINVAL;
100100
}
101+
102+
#define PPC_OP(op) (((op) >> 26) & 0x3F)
103+
#define PPC_RA(a) (((a) >> 16) & 0x1f)
104+
#define PPC_RT(t) (((t) >> 21) & 0x1f)
105+
#define PPC_RB(b) (((b) >> 11) & 0x1f)
106+
#define PPC_D(D) ((D) & 0xfffe)
107+
#define PPC_DS(DS) ((DS) & 0xfffc)
108+
#define OP_LD 58
109+
#define OP_STD 62

tools/perf/util/annotate.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ struct annotation_line {
113113
struct disasm_line {
114114
struct ins ins;
115115
struct ins_operands ops;
116-
116+
union {
117+
u8 bytes[4];
118+
u32 raw_insn;
119+
} raw;
117120
/* This needs to be at the end. */
118121
struct annotation_line al;
119122
};

tools/perf/util/disasm.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size,
4444

4545
static void ins__sort(struct arch *arch);
4646
static int disasm_line__parse(char *line, const char **namep, char **rawp);
47+
static int disasm_line__parse_powerpc(struct disasm_line *dl);
4748

4849
static __attribute__((constructor)) void symbol__init_regexpr(void)
4950
{
@@ -845,6 +846,51 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
845846
return -1;
846847
}
847848

849+
/*
850+
* Parses the result captured from symbol__disassemble_*
851+
* Example, line read from DSO file in powerpc:
852+
* line: 38 01 81 e8
853+
* opcode: fetched from arch specific get_opcode_insn
854+
* rawp_insn: e8810138
855+
*
856+
* rawp_insn is used later to extract the reg/offset fields
857+
*/
858+
#define PPC_OP(op) (((op) >> 26) & 0x3F)
859+
#define RAW_BYTES 11
860+
861+
static int disasm_line__parse_powerpc(struct disasm_line *dl)
862+
{
863+
char *line = dl->al.line;
864+
const char **namep = &dl->ins.name;
865+
char **rawp = &dl->ops.raw;
866+
char *tmp_raw_insn, *name_raw_insn = skip_spaces(line);
867+
char *name = skip_spaces(name_raw_insn + RAW_BYTES);
868+
int objdump = 0;
869+
870+
if (strlen(line) > RAW_BYTES)
871+
objdump = 1;
872+
873+
if (name_raw_insn[0] == '\0')
874+
return -1;
875+
876+
if (objdump) {
877+
disasm_line__parse(name, namep, rawp);
878+
} else
879+
*namep = "";
880+
881+
tmp_raw_insn = strndup(name_raw_insn, 11);
882+
if (tmp_raw_insn == NULL)
883+
return -1;
884+
885+
remove_spaces(tmp_raw_insn);
886+
887+
sscanf(tmp_raw_insn, "%x", &dl->raw.raw_insn);
888+
if (objdump)
889+
dl->raw.raw_insn = be32_to_cpu(dl->raw.raw_insn);
890+
891+
return 0;
892+
}
893+
848894
static void annotation_line__init(struct annotation_line *al,
849895
struct annotate_args *args,
850896
int nr)
@@ -898,7 +944,10 @@ struct disasm_line *disasm_line__new(struct annotate_args *args)
898944
goto out_delete;
899945

900946
if (args->offset != -1) {
901-
if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
947+
if (arch__is(args->arch, "powerpc")) {
948+
if (disasm_line__parse_powerpc(dl) < 0)
949+
goto out_free_line;
950+
} else if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
902951
goto out_free_line;
903952

904953
disasm_line__init_ins(dl, args->arch, &args->ms);

0 commit comments

Comments
 (0)