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