Commit cbaf89a8 authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo
Browse files

perf annotate: Parse x86 segment register location



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: default avatarNamhyung 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent bdc80ace
Loading
Loading
Loading
Loading
+32 −4
Original line number Diff line number Diff line
@@ -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 (s) {
			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 == 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 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
			.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 */
+15 −0
Original line number Diff line number Diff line
@@ -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