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