xref: /linux/tools/perf/util/sample.c (revision 473f6c8f437b049f8ec015d57cd59bb983b1d85c)
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 
22 void 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 
35 void 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 
47 struct 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 
58 struct 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 
68 static 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 
104 void 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 }
135