projects/linux·blob master · refs

289 lines · 5.9 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include "common.h"
3
4#include <limits.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include <linux/zalloc.h>
10#include <unistd.h>
11
12#include <dwarf-regs.h>
13
14#include "../util/debug.h"
15#include "../util/env.h"
16
17static const char *const arc_triplets[] = {
18 "arc-linux-",
19 "arc-snps-linux-uclibc-",
20 "arc-snps-linux-gnu-",
21 NULL
22};
23
24static const char *const arm_triplets[] = {
25 "arm-eabi-",
26 "arm-linux-androideabi-",
27 "arm-unknown-linux-",
28 "arm-unknown-linux-gnu-",
29 "arm-unknown-linux-gnueabi-",
30 "arm-linux-gnu-",
31 "arm-linux-gnueabihf-",
32 "arm-none-eabi-",
33 NULL
34};
35
36static const char *const arm64_triplets[] = {
37 "aarch64-linux-android-",
38 "aarch64-linux-gnu-",
39 NULL
40};
41
42static const char *const powerpc_triplets[] = {
43 "powerpc-unknown-linux-gnu-",
44 "powerpc-linux-gnu-",
45 "powerpc64-unknown-linux-gnu-",
46 "powerpc64-linux-gnu-",
47 "powerpc64le-linux-gnu-",
48 NULL
49};
50
51static const char *const riscv32_triplets[] = {
52 "riscv32-unknown-linux-gnu-",
53 "riscv32-linux-android-",
54 "riscv32-linux-gnu-",
55 NULL
56};
57
58static const char *const riscv64_triplets[] = {
59 "riscv64-unknown-linux-gnu-",
60 "riscv64-linux-android-",
61 "riscv64-linux-gnu-",
62 NULL
63};
64
65static const char *const s390_triplets[] = {
66 "s390-ibm-linux-",
67 "s390x-linux-gnu-",
68 NULL
69};
70
71static const char *const sh_triplets[] = {
72 "sh-unknown-linux-gnu-",
73 "sh-linux-gnu-",
74 NULL
75};
76
77static const char *const sparc_triplets[] = {
78 "sparc-unknown-linux-gnu-",
79 "sparc64-unknown-linux-gnu-",
80 "sparc64-linux-gnu-",
81 NULL
82};
83
84static const char *const x86_triplets[] = {
85 "x86_64-pc-linux-gnu-",
86 "x86_64-unknown-linux-gnu-",
87 "i686-pc-linux-gnu-",
88 "i586-pc-linux-gnu-",
89 "i486-pc-linux-gnu-",
90 "i386-pc-linux-gnu-",
91 "i686-linux-android-",
92 "i686-android-linux-",
93 "x86_64-linux-gnu-",
94 "i586-linux-gnu-",
95 NULL
96};
97
98static const char *const mips_triplets[] = {
99 "mips-unknown-linux-gnu-",
100 "mipsel-linux-android-",
101 "mips-linux-gnu-",
102 "mips64-linux-gnu-",
103 "mips64el-linux-gnuabi64-",
104 "mips64-linux-gnuabi64-",
105 "mipsel-linux-gnu-",
106 NULL
107};
108
109static bool lookup_path(char *name)
110{
111 bool found = false;
112 char *path, *tmp = NULL;
113 char buf[PATH_MAX];
114 char *env = getenv("PATH");
115
116 if (!env)
117 return false;
118
119 env = strdup(env);
120 if (!env)
121 return false;
122
123 path = strtok_r(env, ":", &tmp);
124 while (path) {
125 scnprintf(buf, sizeof(buf), "%s/%s", path, name);
126 if (access(buf, F_OK) == 0) {
127 found = true;
128 break;
129 }
130 path = strtok_r(NULL, ":", &tmp);
131 }
132 free(env);
133 return found;
134}
135
136static int lookup_triplets(const char *const *triplets, const char *name)
137{
138 int i;
139 char buf[PATH_MAX];
140
141 for (i = 0; triplets[i] != NULL; i++) {
142 scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name);
143 if (lookup_path(buf))
144 return i;
145 }
146 return -1;
147}
148
149static bool is_native_compatible(struct perf_env *env, uint16_t target, uint16_t host)
150{
151 if (target != host) {
152 /* A 64-bit host can natively disassemble its 32-bit compat architecture */
153 if (host == EM_X86_64 && target == EM_386)
154 return true;
155 if (host == EM_AARCH64 && target == EM_ARM)
156 return true;
157 if (host == EM_PPC64 && target == EM_PPC)
158 return true;
159 if (host == EM_SPARCV9 && target == EM_SPARC)
160 return true;
161 return false;
162 }
163
164 /* target == host case */
165 if (target == EM_RISCV) {
166 bool target_is_64 = perf_env__kernel_is_64_bit(env);
167 bool host_is_64 = (sizeof(void *) == 8);
168
169 /* 32-bit host cannot natively disassemble 64-bit target */
170 if (!host_is_64 && target_is_64)
171 return false;
172 }
173
174 return true;
175}
176
177static int perf_env__lookup_binutils_path(struct perf_env *env,
178 const char *name, char **path)
179{
180 int idx;
181 uint16_t e_machine = perf_env__e_machine(env, /*e_flags=*/NULL);
182 const char *cross_env;
183 const char *const *path_list;
184 char *buf = NULL;
185
186 /*
187 * We don't need to try to find objdump path for native system.
188 * Just use default binutils path (e.g.: "objdump").
189 */
190 if (is_native_compatible(env, e_machine, EM_HOST))
191 goto out;
192
193 cross_env = getenv("CROSS_COMPILE");
194 if (cross_env) {
195 if (asprintf(&buf, "%s%s", cross_env, name) < 0)
196 goto out_error;
197 if (buf[0] == '/') {
198 if (access(buf, F_OK) == 0)
199 goto out;
200 goto out_error;
201 }
202 if (lookup_path(buf))
203 goto out;
204 zfree(&buf);
205 }
206
207 switch (e_machine) {
208 case EM_ARC:
209 path_list = arc_triplets;
210 break;
211 case EM_ARM:
212 path_list = arm_triplets;
213 break;
214 case EM_AARCH64:
215 path_list = arm64_triplets;
216 break;
217 case EM_PPC:
218 case EM_PPC64:
219 path_list = powerpc_triplets;
220 break;
221 case EM_RISCV:
222 path_list = perf_env__kernel_is_64_bit(env) ? riscv64_triplets : riscv32_triplets;
223 break;
224 case EM_SH:
225 path_list = sh_triplets;
226 break;
227 case EM_S390:
228 path_list = s390_triplets;
229 break;
230 case EM_SPARC:
231 case EM_SPARCV9:
232 path_list = sparc_triplets;
233 break;
234 case EM_X86_64:
235 case EM_386:
236 path_list = x86_triplets;
237 break;
238 case EM_MIPS:
239 path_list = mips_triplets;
240 break;
241 default:
242 ui__error("binutils for %s not supported.\n", perf_env__arch(env));
243 goto out_error;
244 }
245
246 idx = lookup_triplets(path_list, name);
247 if (idx < 0) {
248 ui__error("Please install %s for %s.\n"
249 "You can add it to PATH, set CROSS_COMPILE or "
250 "override the default using --%s.\n",
251 name, perf_env__arch(env), name);
252 goto out_error;
253 }
254
255 if (asprintf(&buf, "%s%s", path_list[idx], name) < 0)
256 goto out_error;
257
258out:
259 *path = buf;
260 return 0;
261out_error:
262 free(buf);
263 *path = NULL;
264 return -1;
265}
266
267int perf_env__lookup_objdump(struct perf_env *env, char **path)
268{
269 /*
270 * For live mode, env->arch will be NULL and we can use
271 * the native objdump tool.
272 */
273 if (env->arch == NULL)
274 return 0;
275
276 return perf_env__lookup_binutils_path(env, "objdump", path);
277}
278
279/*
280 * Some architectures have a single address space for kernel and user addresses,
281 * which makes it possible to determine if an address is in kernel space or user
282 * space.
283 */
284bool perf_env__single_address_space(struct perf_env *env)
285{
286 uint16_t e_machine = perf_env__e_machine(env, /*e_flags=*/NULL);
287
288 return e_machine != EM_SPARC && e_machine != EM_SPARCV9 && e_machine != EM_S390;
289}