xref: /linux/tools/perf/util/sample.c (revision c7decec2f2d2ab0366567f9e30c0e1418cece43f)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include "sample.h"
3 #include "debug.h"
4 #include "thread.h"
5 #include <elf.h>
6 #ifndef EM_CSKY
7 #define EM_CSKY		252
8 #endif
9 #ifndef EM_LOONGARCH
10 #define EM_LOONGARCH	258
11 #endif
12 #include <linux/zalloc.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "../../arch/x86/include/asm/insn.h"
16 
perf_sample__init(struct perf_sample * sample,bool all)17 void perf_sample__init(struct perf_sample *sample, bool all)
18 {
19 	if (all) {
20 		memset(sample, 0, sizeof(*sample));
21 	} else {
22 		sample->user_regs = NULL;
23 		sample->intr_regs = NULL;
24 	}
25 }
26 
perf_sample__exit(struct perf_sample * sample)27 void perf_sample__exit(struct perf_sample *sample)
28 {
29 	free(sample->user_regs);
30 	free(sample->intr_regs);
31 }
32 
perf_sample__user_regs(struct perf_sample * sample)33 struct regs_dump *perf_sample__user_regs(struct perf_sample *sample)
34 {
35 	if (!sample->user_regs) {
36 		sample->user_regs = zalloc(sizeof(*sample->user_regs));
37 		if (!sample->user_regs)
38 			pr_err("Failure to allocate sample user_regs");
39 	}
40 	return sample->user_regs;
41 }
42 
43 
perf_sample__intr_regs(struct perf_sample * sample)44 struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample)
45 {
46 	if (!sample->intr_regs) {
47 		sample->intr_regs = zalloc(sizeof(*sample->intr_regs));
48 		if (!sample->intr_regs)
49 			pr_err("Failure to allocate sample intr_regs");
50 	}
51 	return sample->intr_regs;
52 }
53 
elf_machine_max_instruction_length(uint16_t e_machine)54 static int elf_machine_max_instruction_length(uint16_t e_machine)
55 {
56 	switch (e_machine) {
57 	/* Fixed 4-byte (32-bit) architectures */
58 	case EM_AARCH64:
59 	case EM_PPC:
60 	case EM_PPC64:
61 	case EM_MIPS:
62 	case EM_SPARC:
63 	case EM_SPARCV9:
64 	case EM_ALPHA:
65 	case EM_LOONGARCH:
66 	case EM_PARISC:
67 	case EM_SH:
68 		return 4;
69 
70 	/* Variable length or mixed-mode architectures */
71 	case EM_ARM:    /* Variable due to Thumb/Thumb-2 */
72 	case EM_RISCV:  /* Variable due to Compressed (C) extension */
73 	case EM_CSKY:   /* Variable (16 or 32 bit) */
74 	case EM_ARC:    /* Variable (ARCompact) */
75 		return 4;
76 	case EM_S390:   /* Variable (2, 4, or 6 bytes) */
77 		return 6;
78 	case EM_68K:
79 		return 10;
80 	case EM_386:
81 	case EM_X86_64:
82 		return 15;
83 	case EM_XTENSA: /* Variable (FLIX) */
84 		return 16;
85 	default:
86 		return MAX_INSN;
87 	}
88 }
89 
perf_sample__fetch_insn(struct perf_sample * sample,struct thread * thread,struct machine * machine)90 void perf_sample__fetch_insn(struct perf_sample *sample,
91 			     struct thread *thread,
92 			     struct machine *machine)
93 {
94 	int ret, len;
95 	bool is64bit = false;
96 	uint16_t e_machine;
97 
98 	if (!sample->ip || sample->insn_len != 0)
99 		return;
100 
101 	e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL);
102 	len = elf_machine_max_instruction_length(e_machine);
103 	len = thread__memcpy(thread, machine, sample->insn,
104 			     sample->ip, len,
105 			     &is64bit);
106 	if (len <= 0)
107 		return;
108 
109 	sample->insn_len = len;
110 
111 	if (e_machine == EM_386 || e_machine == EM_X86_64) {
112 		/* Refine the x86 instruction length with the decoder. */
113 		struct insn insn;
114 
115 		ret = insn_decode(&insn, sample->insn, len,
116 				  is64bit ? INSN_MODE_64 : INSN_MODE_32);
117 		if (ret >= 0 && insn.length <= len)
118 			sample->insn_len = insn.length;
119 	}
120 }
121