projects/linux·blob master · refs

134 lines · 3.0 KiB

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