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