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