perf script: Consolidate capstone print functions
authorAdrian Hunter <adrian.hunter@intel.com>
Mon, 1 Apr 2024 21:08:05 +0000 (14:08 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 8 Apr 2024 20:42:27 +0000 (17:42 -0300)
Consolidate capstone print functions, to reduce duplication. Amend call
sites to use a file pointer for output, which is consistent with most
perf tools print functions. Add print_opts with an option to print also
the hex value of a resolved symbol+offset.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/20240401210925.209671-4-ak@linux.intel.com
Signed-off-by: Andi Kleen <ak@linux.intel.com>
[ Added missing inttypes.h include to use PRIx64 in util/print_insn.c ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-script.c
tools/perf/util/print_insn.c
tools/perf/util/print_insn.h

index dd10f158ed0cde58bb41f6b484514392708645f3..647cb31a47c8f114404f623e2656f565e59537df 100644 (file)
@@ -1165,18 +1165,29 @@ out:
        return ret;
 }
 
-static const char *any_dump_insn(struct perf_event_attr *attr __maybe_unused,
-                       struct perf_insn *x, uint64_t ip,
-                       u8 *inbuf, int inlen, int *lenp)
+static int any_dump_insn(struct perf_event_attr *attr __maybe_unused,
+                        struct perf_insn *x, uint64_t ip,
+                        u8 *inbuf, int inlen, int *lenp,
+                        FILE *fp)
 {
 #ifdef HAVE_LIBCAPSTONE_SUPPORT
        if (PRINT_FIELD(BRSTACKDISASM)) {
-               const char *p = cs_dump_insn(x, ip, inbuf, inlen, lenp);
-               if (p)
-                       return p;
+               int printed = fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->is64bit,
+                                              (uint8_t *)inbuf, inlen, ip, lenp,
+                                              PRINT_INSN_IMM_HEX, fp);
+
+               if (printed > 0)
+                       return printed;
        }
 #endif
-       return dump_insn(x, ip, inbuf, inlen, lenp);
+       return fprintf(fp, "%s", dump_insn(x, ip, inbuf, inlen, lenp));
+}
+
+static int add_padding(FILE *fp, int printed, int padding)
+{
+       if (printed >= 0 && printed < padding)
+               printed += fprintf(fp, "%*s", padding - printed, "");
+       return printed;
 }
 
 static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
@@ -1186,8 +1197,10 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
                            struct thread *thread)
 {
        int ilen = 0;
-       int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t", ip,
-                             any_dump_insn(attr, x, ip, inbuf, len, &ilen));
+       int printed = fprintf(fp, "\t%016" PRIx64 "\t", ip);
+
+       printed += add_padding(fp, any_dump_insn(attr, x, ip, inbuf, len, &ilen, fp), 30);
+       printed += fprintf(fp, "\t");
 
        if (PRINT_FIELD(BRSTACKINSNLEN))
                printed += fprintf(fp, "ilen: %d\t", ilen);
@@ -1330,8 +1343,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                                break;
                        } else {
                                ilen = 0;
-                               printed += fprintf(fp, "\t%016" PRIx64 "\t%s", ip,
-                                                  any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen));
+                               printed += fprintf(fp, "\t%016" PRIx64 "\t", ip);
+                               printed += any_dump_insn(attr, &x, ip, buffer + off, len - off, &ilen, fp);
                                if (PRINT_FIELD(BRSTACKINSNLEN))
                                        printed += fprintf(fp, "\tilen: %d", ilen);
                                printed += fprintf(fp, "\n");
@@ -1378,8 +1391,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                if (len <= 0)
                        goto out;
                ilen = 0;
-               printed += fprintf(fp, "\t%016" PRIx64 "\t%s", sample->ip,
-                       any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen));
+               printed += fprintf(fp, "\t%016" PRIx64 "\t", sample->ip);
+               printed += any_dump_insn(attr, &x, sample->ip, buffer, len, &ilen, fp);
                if (PRINT_FIELD(BRSTACKINSNLEN))
                        printed += fprintf(fp, "\tilen: %d", ilen);
                printed += fprintf(fp, "\n");
@@ -1389,8 +1402,8 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
        }
        for (off = 0; off <= end - start; off += ilen) {
                ilen = 0;
-               printed += fprintf(fp, "\t%016" PRIx64 "\t%s", start + off,
-                                  any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen));
+               printed += fprintf(fp, "\t%016" PRIx64 "\t", start + off);
+               printed += any_dump_insn(attr, &x, start + off, buffer + off, len - off, &ilen, fp);
                if (PRINT_FIELD(BRSTACKINSNLEN))
                        printed += fprintf(fp, "\tilen: %d", ilen);
                printed += fprintf(fp, "\n");
index 8825330d435f918b864505f4d82afad2c486dd7a..aab11d8e1b1d2a0399cef8e4baf631ec83a5ba45 100644 (file)
@@ -4,6 +4,7 @@
  *
  * Author(s): Changbin Du <changbin.du@huawei.com>
  */
+#include <inttypes.h>
 #include <string.h>
 #include <stdbool.h>
 #include "debug.h"
@@ -72,59 +73,8 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64)
        return 0;
 }
 
-static void dump_insn_x86(struct thread *thread, cs_insn *insn, struct perf_insn *x)
-{
-       struct addr_location al;
-       bool printed = false;
-
-       if (insn->detail && insn->detail->x86.op_count == 1) {
-               cs_x86_op *op = &insn->detail->x86.operands[0];
-
-               addr_location__init(&al);
-               if (op->type == X86_OP_IMM &&
-                   thread__find_symbol(thread, x->cpumode, op->imm, &al) &&
-                   al.sym &&
-                   al.addr < al.sym->end) {
-                       snprintf(x->out, sizeof(x->out), "%s %s+%#" PRIx64 " [%#" PRIx64 "]", insn[0].mnemonic,
-                                       al.sym->name, al.addr - al.sym->start, op->imm);
-                       printed = true;
-               }
-               addr_location__exit(&al);
-       }
-
-       if (!printed)
-               snprintf(x->out, sizeof(x->out), "%s %s", insn[0].mnemonic, insn[0].op_str);
-}
-
-const char *cs_dump_insn(struct perf_insn *x, uint64_t ip,
-                        u8 *inbuf, int inlen, int *lenp)
-{
-       int ret;
-       int count;
-       cs_insn *insn;
-       csh cs_handle;
-
-       ret = capstone_init(x->machine, &cs_handle, x->is64bit);
-       if (ret < 0)
-               return NULL;
-
-       count = cs_disasm(cs_handle, (uint8_t *)inbuf, inlen, ip, 1, &insn);
-       if (count > 0) {
-               if (machine__normalized_is(x->machine, "x86"))
-                       dump_insn_x86(x->thread, &insn[0], x);
-               else
-                       snprintf(x->out, sizeof(x->out), "%s %s",
-                                       insn[0].mnemonic, insn[0].op_str);
-               *lenp = insn->size;
-               cs_free(insn, count);
-       } else {
-               return NULL;
-       }
-       return x->out;
-}
-
-static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread,
-                            cs_insn *insn, FILE *fp)
+static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
+                            int print_opts, FILE *fp)
 {
        struct addr_location al;
        size_t printed = 0;
@@ -134,9 +84,11 @@ static size_t print_insn_x86(struct perf_sample *sample, struct thread *thread,
 
                addr_location__init(&al);
                if (op->type == X86_OP_IMM &&
-                   thread__find_symbol(thread, sample->cpumode, op->imm, &al)) {
+                   thread__find_symbol(thread, cpumode, op->imm, &al)) {
                        printed += fprintf(fp, "%s ", insn[0].mnemonic);
                        printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
+                       if (print_opts & PRINT_INSN_IMM_HEX)
+                               printed += fprintf(fp, " [%#" PRIx64 "]", op->imm);
                        addr_location__exit(&al);
                        return printed;
                }
@@ -159,39 +111,53 @@ static bool is64bitip(struct machine *machine, struct addr_location *al)
                machine__normalized_is(machine, "s390");
 }
 
-size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread,
-                               struct machine *machine, FILE *fp,
-                               struct addr_location *al)
+ssize_t fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode,
+                        bool is64bit, const uint8_t *code, size_t code_size,
+                        uint64_t ip, int *lenp, int print_opts, FILE *fp)
 {
-       csh cs_handle;
+       size_t printed;
        cs_insn *insn;
+       csh cs_handle;
        size_t count;
-       size_t printed = 0;
        int ret;
-       bool is64bit = is64bitip(machine, al);
 
        /* TODO: Try to initiate capstone only once but need a proper place. */
        ret = capstone_init(machine, &cs_handle, is64bit);
-       if (ret < 0) {
-               /* fallback */
-               return sample__fprintf_insn_raw(sample, fp);
-       }
+       if (ret < 0)
+               return ret;
 
-       count = cs_disasm(cs_handle, (uint8_t *)sample->insn, sample->insn_len,
-                         sample->ip, 1, &insn);
+       count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
        if (count > 0) {
                if (machine__normalized_is(machine, "x86"))
-                       printed += print_insn_x86(sample, thread, &insn[0], fp);
+                       printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
                else
-                       printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
+                       printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
+               if (lenp)
+                       *lenp = insn->size;
                cs_free(insn, count);
        } else {
-               printed += fprintf(fp, "illegal instruction");
+               printed = -1;
        }
 
        cs_close(&cs_handle);
        return printed;
 }
+
+size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread,
+                               struct machine *machine, FILE *fp,
+                               struct addr_location *al)
+{
+       bool is64bit = is64bitip(machine, al);
+       ssize_t printed;
+
+       printed = fprintf_insn_asm(machine, thread, sample->cpumode, is64bit,
+                                  (uint8_t *)sample->insn, sample->insn_len,
+                                  sample->ip, NULL, 0, fp);
+       if (printed < 0)
+               return sample__fprintf_insn_raw(sample, fp);
+
+       return printed;
+}
 #else
 size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused,
                                struct thread *thread __maybe_unused,
index c2a6391a45cea97034a2b766b6fbd3f42bb2bb59..07d11af3fc1cbe7da44ce50066d3126952dd2530 100644 (file)
@@ -10,10 +10,13 @@ struct thread;
 struct machine;
 struct perf_insn;
 
+#define PRINT_INSN_IMM_HEX             (1<<0)
+
 size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread,
                                struct machine *machine, FILE *fp, struct addr_location *al);
 size_t sample__fprintf_insn_raw(struct perf_sample *sample, FILE *fp);
-const char *cs_dump_insn(struct perf_insn *x, uint64_t ip,
-                         u8 *inbuf, int inlen, int *lenp);
+ssize_t fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode,
+                        bool is64bit, const uint8_t *code, size_t code_size,
+                        uint64_t ip, int *lenp, int print_opts, FILE *fp);
 
 #endif /* PERF_PRINT_INSN_H */