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