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 17 static const char *const arc_triplets[] = { 18 "arc-linux-", 19 "arc-snps-linux-uclibc-", 20 "arc-snps-linux-gnu-", 21 NULL 22 }; 23 24 static 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 36 static const char *const arm64_triplets[] = { 37 "aarch64-linux-android-", 38 "aarch64-linux-gnu-", 39 NULL 40 }; 41 42 static 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 51 static const char *const riscv32_triplets[] = { 52 "riscv32-unknown-linux-gnu-", 53 "riscv32-linux-android-", 54 "riscv32-linux-gnu-", 55 NULL 56 }; 57 58 static const char *const riscv64_triplets[] = { 59 "riscv64-unknown-linux-gnu-", 60 "riscv64-linux-android-", 61 "riscv64-linux-gnu-", 62 NULL 63 }; 64 65 static const char *const s390_triplets[] = { 66 "s390-ibm-linux-", 67 "s390x-linux-gnu-", 68 NULL 69 }; 70 71 static const char *const sh_triplets[] = { 72 "sh-unknown-linux-gnu-", 73 "sh-linux-gnu-", 74 NULL 75 }; 76 77 static const char *const sparc_triplets[] = { 78 "sparc-unknown-linux-gnu-", 79 "sparc64-unknown-linux-gnu-", 80 "sparc64-linux-gnu-", 81 NULL 82 }; 83 84 static 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 98 static 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 109 static 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 136 static 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 149 static 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 177 static 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 258 out: 259 *path = buf; 260 return 0; 261 out_error: 262 free(buf); 263 *path = NULL; 264 return -1; 265 } 266 267 int 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 */ 284 bool 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 } 290