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