perf annotate: Parse x86 segment register location
authorNamhyung Kim <namhyung@kernel.org>
Tue, 19 Mar 2024 05:51:08 +0000 (22:51 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 21 Mar 2024 13:41:29 +0000 (10:41 -0300)
Add a segment field in the struct annotated_insn_loc and save it for the
segment based addressing like %gs:0x28.  For simplicity it now handles
%gs register only.

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>
Link: https://lore.kernel.org/r/20240319055115.4063940-17-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/annotate.c
tools/perf/util/annotate.h

index abb641aa8ec0601a6639aa63594e7dedd6e1a443..3aa3a3b987ad84145757b5ea2790f3f566b808ff 100644 (file)
@@ -94,6 +94,7 @@ struct arch {
                char skip_functions_char;
                char register_char;
                char memory_ref_char;
+               char imm_char;
        } objdump;
 };
 
@@ -211,6 +212,7 @@ static struct arch architectures[] = {
                        .comment_char = '#',
                        .register_char = '%',
                        .memory_ref_char = '(',
+                       .imm_char = '$',
                },
        },
        {
@@ -3585,6 +3587,12 @@ static int extract_reg_offset(struct arch *arch, const char *str,
         * %gs:0x18(%rbx).  In that case it should skip the part.
         */
        if (*str == arch->objdump.register_char) {
+               if (arch__is(arch, "x86")) {
+                       /* FIXME: Handle other segment registers */
+                       if (!strncmp(str, "%gs:", 4))
+                               op_loc->segment = INSN_SEG_X86_GS;
+               }
+
                while (*str && !isdigit(*str) &&
                       *str != arch->objdump.memory_ref_char)
                        str++;
@@ -3681,12 +3689,32 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
                        op_loc->multi_regs = multi_regs;
                        extract_reg_offset(arch, insn_str, op_loc);
                } else {
-                       char *s = strdup(insn_str);
+                       char *s, *p = NULL;
+
+                       if (arch__is(arch, "x86")) {
+                               /* FIXME: Handle other segment registers */
+                               if (!strncmp(insn_str, "%gs:", 4)) {
+                                       op_loc->segment = INSN_SEG_X86_GS;
+                                       op_loc->offset = strtol(insn_str + 4,
+                                                               &p, 0);
+                                       if (p && p != insn_str + 4)
+                                               op_loc->imm = true;
+                                       continue;
+                               }
+                       }
+
+                       s = strdup(insn_str);
+                       if (s == NULL)
+                               return -1;
 
-                       if (s) {
+                       if (*s == arch->objdump.register_char)
                                op_loc->reg1 = get_dwarf_regnum(s, 0);
-                               free(s);
+                       else if (*s == arch->objdump.imm_char) {
+                               op_loc->offset = strtol(s + 1, &p, 0);
+                               if (p && p != s + 1)
+                                       op_loc->imm = true;
                        }
+                       free(s);
                }
        }
 
@@ -3881,7 +3909,7 @@ retry:
                        .op = op_loc,
                };
 
-               if (!op_loc->mem_ref)
+               if (!op_loc->mem_ref && op_loc->segment == INSN_SEG_NONE)
                        continue;
 
                /* Recalculate IP because of LOCK prefix or insn fusion */
index 0928663fddeeca3a780a1b43ddf672b5657c9bd3..14980b65f812d08ae225f482bb3cca8b0313b56c 100644 (file)
@@ -511,15 +511,19 @@ int annotate_check_args(void);
  * @reg1: First register in the operand
  * @reg2: Second register in the operand
  * @offset: Memory access offset in the operand
+ * @segment: Segment selector register
  * @mem_ref: Whether the operand accesses memory
  * @multi_regs: Whether the second register is used
+ * @imm: Whether the operand is an immediate value (in offset)
  */
 struct annotated_op_loc {
        int reg1;
        int reg2;
        int offset;
+       u8 segment;
        bool mem_ref;
        bool multi_regs;
+       bool imm;
 };
 
 enum annotated_insn_ops {
@@ -529,6 +533,17 @@ enum annotated_insn_ops {
        INSN_OP_MAX,
 };
 
+enum annotated_x86_segment {
+       INSN_SEG_NONE = 0,
+
+       INSN_SEG_X86_CS,
+       INSN_SEG_X86_DS,
+       INSN_SEG_X86_ES,
+       INSN_SEG_X86_FS,
+       INSN_SEG_X86_GS,
+       INSN_SEG_X86_SS,
+};
+
 /**
  * struct annotated_insn_loc - Location info of instruction
  * @ops: Array of location info for source and target operands