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