blob: 6fe11a02738c60bb3df115385a764380233a7e71 [file] [log] [blame]
Vicent Marti411f6982016-04-20 13:24:54 +02001/*
2 * Copyright (c) 2016 GitHub, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Teng Qin5440af32017-04-07 10:57:14 -070016
Vicent Martib366ede2016-04-20 13:24:54 +020017#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/mman.h>
Vicent Martib366ede2016-04-20 13:24:54 +020020#include <ctype.h>
Teng Qin8cc8fc32017-10-05 14:04:33 -070021#include <fcntl.h>
22#include <limits.h>
Paul Chaignon690b7e62016-12-25 19:43:41 +010023#include <math.h>
Teng Qin8cc8fc32017-10-05 14:04:33 -070024#include <stdbool.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
Vicent Martib366ede2016-04-20 13:24:54 +020030
Mark Drayton769edf92016-06-15 11:53:24 +010031#include "bcc_perf_map.h"
Vicent Martic1c23732016-04-20 13:24:54 +020032#include "bcc_proc.h"
33#include "bcc_elf.h"
Vicent Martib366ede2016-04-20 13:24:54 +020034
Teng Qin8cc8fc32017-10-05 14:04:33 -070035#ifdef __x86_64__
36// https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
37const unsigned long long kernelAddrSpace = 0x00ffffffffffffff;
38#else
39const unsigned long long kernelAddrSpace = 0x0;
40#endif
41
Vicent Martic1c23732016-04-20 13:24:54 +020042char *bcc_procutils_which(const char *binpath) {
43 char buffer[4096];
44 const char *PATH;
Vicent Martib366ede2016-04-20 13:24:54 +020045
Vicent Martic1c23732016-04-20 13:24:54 +020046 if (strchr(binpath, '/'))
Teng Qind82e8132017-05-04 12:09:14 -070047 return bcc_elf_is_exe(binpath) ? strdup(binpath) : 0;
Vicent Martib366ede2016-04-20 13:24:54 +020048
Vicent Martic1c23732016-04-20 13:24:54 +020049 if (!(PATH = getenv("PATH")))
50 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +020051
Vicent Martic1c23732016-04-20 13:24:54 +020052 while (PATH) {
53 const char *next = strchr(PATH, ':') ?: strchr(PATH, '\0');
54 const size_t path_len = next - PATH;
Vicent Martib366ede2016-04-20 13:24:54 +020055
Vicent Martic1c23732016-04-20 13:24:54 +020056 if (path_len) {
Christian Resell5a7882e2017-05-26 21:44:07 +020057 int ret = snprintf(buffer, sizeof(buffer), "%.*s/%s",
58 (int)path_len, PATH, binpath);
59 if (ret < 0 || ret >= sizeof(buffer))
60 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +020061
Teng Qind82e8132017-05-04 12:09:14 -070062 if (bcc_elf_is_exe(buffer))
Vicent Martic1c23732016-04-20 13:24:54 +020063 return strdup(buffer);
64 }
Vicent Martib366ede2016-04-20 13:24:54 +020065
Vicent Martic1c23732016-04-20 13:24:54 +020066 PATH = *next ? (next + 1) : 0;
67 }
Vicent Martib366ede2016-04-20 13:24:54 +020068
Vicent Martic1c23732016-04-20 13:24:54 +020069 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +020070}
71
Vicent Marti8600ffc2017-06-27 15:22:38 +020072#define STARTS_WITH(mapname, prefix) (!strncmp(mapname, prefix, sizeof(prefix)-1))
73
Mark Drayton13685082017-02-22 02:05:10 +000074int bcc_mapping_is_file_backed(const char *mapname) {
Vicent Marti8600ffc2017-06-27 15:22:38 +020075 return mapname[0] && !(
76 STARTS_WITH(mapname, "//anon") ||
77 STARTS_WITH(mapname, "/dev/zero") ||
78 STARTS_WITH(mapname, "/anon_hugepage") ||
79 STARTS_WITH(mapname, "[stack") ||
80 STARTS_WITH(mapname, "/SYSV") ||
81 STARTS_WITH(mapname, "[heap]") ||
Teng Qin1670d332017-10-06 18:08:33 -070082 STARTS_WITH(mapname, "[vsyscall]"));
Mark Drayton13685082017-02-22 02:05:10 +000083}
84
Vicent Martic1c23732016-04-20 13:24:54 +020085int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
86 void *payload) {
87 char procmap_filename[128];
88 FILE *procmap;
Teng Qina0c5de12017-09-25 15:13:23 -070089 snprintf(procmap_filename, sizeof(procmap_filename), "/proc/%ld/maps",
90 (long)pid);
Vicent Martic1c23732016-04-20 13:24:54 +020091 procmap = fopen(procmap_filename, "r");
Vicent Martic1c23732016-04-20 13:24:54 +020092 if (!procmap)
93 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +020094
Teng Qina9e5f532017-10-06 17:11:11 -070095 char buf[PATH_MAX + 1], perm[5], dev[8];
96 char *name;
97 uint64_t begin, end, inode;
98 unsigned long long offset;
99 while (true) {
100 buf[0] = '\0';
101 // From fs/proc/task_mmu.c:show_map_vma
102 if (fscanf(procmap, "%lx-%lx %s %llx %s %lu%[^\n]", &begin, &end, perm,
103 &offset, dev, &inode, buf) != 7)
Vicent Martic1c23732016-04-20 13:24:54 +0200104 break;
Vicent Martib366ede2016-04-20 13:24:54 +0200105
Teng Qina9e5f532017-10-06 17:11:11 -0700106 if (perm[2] != 'x')
107 continue;
Vicent Martib366ede2016-04-20 13:24:54 +0200108
Teng Qina9e5f532017-10-06 17:11:11 -0700109 name = buf;
110 while (isspace(*name))
111 name++;
112 if (!bcc_mapping_is_file_backed(name))
113 continue;
Vicent Martib366ede2016-04-20 13:24:54 +0200114
Teng Qina9e5f532017-10-06 17:11:11 -0700115 if (callback(name, begin, end, (uint64_t)offset, true, payload) < 0)
116 break;
117 }
Vicent Martib366ede2016-04-20 13:24:54 +0200118
Vicent Martic1c23732016-04-20 13:24:54 +0200119 fclose(procmap);
Mark Drayton769edf92016-06-15 11:53:24 +0100120
Teng Qin3bfc8772017-05-04 12:09:19 -0700121 // Address mapping for the entire address space maybe in /tmp/perf-<PID>.map
122 // This will be used if symbols aren't resolved in an earlier mapping.
Mark Drayton769edf92016-06-15 11:53:24 +0100123 char map_path[4096];
Teng Qin3bfc8772017-05-04 12:09:19 -0700124 // Try perf-<PID>.map path with process's mount namespace, chroot and NSPID,
125 // in case it is generated by the process itself.
Mark Drayton769edf92016-06-15 11:53:24 +0100126 if (bcc_perf_map_path(map_path, sizeof(map_path), pid))
Teng Qina0c5de12017-09-25 15:13:23 -0700127 if (callback(map_path, 0, -1, 0, true, payload) < 0)
128 return 0;
Teng Qin3bfc8772017-05-04 12:09:19 -0700129 // Try perf-<PID>.map path with global root and PID, in case it is generated
130 // by other Process. Avoid checking mount namespace for this.
131 int res = snprintf(map_path, 4096, "/tmp/perf-%d.map", pid);
132 if (res > 0 && res < 4096)
Teng Qina0c5de12017-09-25 15:13:23 -0700133 if (callback(map_path, 0, -1, 0, false, payload) < 0)
134 return 0;
135
Vicent Martic1c23732016-04-20 13:24:54 +0200136 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200137}
138
Vicent Martic1c23732016-04-20 13:24:54 +0200139int bcc_procutils_each_ksym(bcc_procutils_ksymcb callback, void *payload) {
140 char line[2048];
Teng Qin8cc8fc32017-10-05 14:04:33 -0700141 char *symname, *endsym;
Vicent Marti6b59b2c2016-04-20 13:24:54 +0200142 FILE *kallsyms;
Teng Qin8cc8fc32017-10-05 14:04:33 -0700143 unsigned long long addr;
Vicent Martib366ede2016-04-20 13:24:54 +0200144
Vicent Marti6b59b2c2016-04-20 13:24:54 +0200145 /* root is needed to list ksym addresses */
146 if (geteuid() != 0)
147 return -1;
148
149 kallsyms = fopen("/proc/kallsyms", "r");
Vicent Martic1c23732016-04-20 13:24:54 +0200150 if (!kallsyms)
151 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200152
Vicent Martic1c23732016-04-20 13:24:54 +0200153 while (fgets(line, sizeof(line), kallsyms)) {
Vicent Martic1c23732016-04-20 13:24:54 +0200154 addr = strtoull(line, &symname, 16);
Teng Qin8cc8fc32017-10-05 14:04:33 -0700155 if (addr == 0 || addr == ULLONG_MAX)
156 continue;
157 if (addr < kernelAddrSpace)
158 continue;
Vicent Martib366ede2016-04-20 13:24:54 +0200159
Teng Qin8cc8fc32017-10-05 14:04:33 -0700160 symname++;
161 // Ignore data symbols
162 if (*symname == 'b' || *symname == 'B' || *symname == 'd' ||
163 *symname == 'D' || *symname == 'r' || *symname =='R')
164 continue;
165
166 endsym = (symname = symname + 2);
Vicent Martic1c23732016-04-20 13:24:54 +0200167 while (*endsym && !isspace(*endsym)) endsym++;
Vicent Martic1c23732016-04-20 13:24:54 +0200168 *endsym = '\0';
Teng Qin8cc8fc32017-10-05 14:04:33 -0700169
Vicent Martic1c23732016-04-20 13:24:54 +0200170 callback(symname, addr, payload);
171 }
Vicent Martib366ede2016-04-20 13:24:54 +0200172
Vicent Martic1c23732016-04-20 13:24:54 +0200173 fclose(kallsyms);
174 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200175}
176
177#define CACHE1_HEADER "ld.so-1.7.0"
178#define CACHE1_HEADER_LEN (sizeof(CACHE1_HEADER) - 1)
179
180#define CACHE2_HEADER "glibc-ld.so.cache"
181#define CACHE2_HEADER_LEN (sizeof(CACHE2_HEADER) - 1)
182#define CACHE2_VERSION "1.1"
183
184struct ld_cache1_entry {
Vicent Martic1c23732016-04-20 13:24:54 +0200185 int32_t flags;
186 uint32_t key;
187 uint32_t value;
Vicent Martib366ede2016-04-20 13:24:54 +0200188};
189
190struct ld_cache1 {
Vicent Martic1c23732016-04-20 13:24:54 +0200191 char header[CACHE1_HEADER_LEN];
192 uint32_t entry_count;
193 struct ld_cache1_entry entries[0];
Vicent Martib366ede2016-04-20 13:24:54 +0200194};
195
196struct ld_cache2_entry {
Vicent Martic1c23732016-04-20 13:24:54 +0200197 int32_t flags;
198 uint32_t key;
199 uint32_t value;
200 uint32_t pad1_;
201 uint64_t pad2_;
Vicent Martib366ede2016-04-20 13:24:54 +0200202};
203
204struct ld_cache2 {
Vicent Martic1c23732016-04-20 13:24:54 +0200205 char header[CACHE2_HEADER_LEN];
206 char version[3];
207 uint32_t entry_count;
208 uint32_t string_table_len;
209 uint32_t pad_[5];
210 struct ld_cache2_entry entries[0];
Vicent Martib366ede2016-04-20 13:24:54 +0200211};
212
213static int lib_cache_count;
214static struct ld_lib {
Vicent Martic1c23732016-04-20 13:24:54 +0200215 char *libname;
216 char *path;
217 int flags;
218} * lib_cache;
Vicent Martib366ede2016-04-20 13:24:54 +0200219
Vicent Martic1c23732016-04-20 13:24:54 +0200220static int read_cache1(const char *ld_map) {
221 struct ld_cache1 *ldcache = (struct ld_cache1 *)ld_map;
222 const char *ldstrings =
223 (const char *)(ldcache->entries + ldcache->entry_count);
224 uint32_t i;
Vicent Martib366ede2016-04-20 13:24:54 +0200225
Vicent Martic1c23732016-04-20 13:24:54 +0200226 lib_cache =
227 (struct ld_lib *)malloc(ldcache->entry_count * sizeof(struct ld_lib));
228 lib_cache_count = (int)ldcache->entry_count;
Vicent Martib366ede2016-04-20 13:24:54 +0200229
Vicent Martic1c23732016-04-20 13:24:54 +0200230 for (i = 0; i < ldcache->entry_count; ++i) {
231 const char *key = ldstrings + ldcache->entries[i].key;
232 const char *val = ldstrings + ldcache->entries[i].value;
233 const int flags = ldcache->entries[i].flags;
Vicent Martib366ede2016-04-20 13:24:54 +0200234
Vicent Martic1c23732016-04-20 13:24:54 +0200235 lib_cache[i].libname = strdup(key);
236 lib_cache[i].path = strdup(val);
237 lib_cache[i].flags = flags;
238 }
239 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200240}
241
Vicent Martic1c23732016-04-20 13:24:54 +0200242static int read_cache2(const char *ld_map) {
243 struct ld_cache2 *ldcache = (struct ld_cache2 *)ld_map;
244 uint32_t i;
Vicent Martib366ede2016-04-20 13:24:54 +0200245
Vicent Martic1c23732016-04-20 13:24:54 +0200246 if (memcmp(ld_map, CACHE2_HEADER, CACHE2_HEADER_LEN))
247 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200248
Vicent Martic1c23732016-04-20 13:24:54 +0200249 lib_cache =
250 (struct ld_lib *)malloc(ldcache->entry_count * sizeof(struct ld_lib));
251 lib_cache_count = (int)ldcache->entry_count;
Vicent Martib366ede2016-04-20 13:24:54 +0200252
Vicent Martic1c23732016-04-20 13:24:54 +0200253 for (i = 0; i < ldcache->entry_count; ++i) {
254 const char *key = ld_map + ldcache->entries[i].key;
255 const char *val = ld_map + ldcache->entries[i].value;
256 const int flags = ldcache->entries[i].flags;
Vicent Martib366ede2016-04-20 13:24:54 +0200257
Vicent Martic1c23732016-04-20 13:24:54 +0200258 lib_cache[i].libname = strdup(key);
259 lib_cache[i].path = strdup(val);
260 lib_cache[i].flags = flags;
261 }
262 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200263}
264
Vicent Martic1c23732016-04-20 13:24:54 +0200265static int load_ld_cache(const char *cache_path) {
266 struct stat st;
267 size_t ld_size;
268 const char *ld_map;
269 int ret, fd = open(cache_path, O_RDONLY);
Vicent Martib366ede2016-04-20 13:24:54 +0200270
Vicent Martic1c23732016-04-20 13:24:54 +0200271 if (fd < 0)
272 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200273
Vicent Martic1c23732016-04-20 13:24:54 +0200274 if (fstat(fd, &st) < 0 || st.st_size < sizeof(struct ld_cache1)) {
275 close(fd);
276 return -1;
277 }
Vicent Martib366ede2016-04-20 13:24:54 +0200278
Vicent Martic1c23732016-04-20 13:24:54 +0200279 ld_size = st.st_size;
280 ld_map = (const char *)mmap(NULL, ld_size, PROT_READ, MAP_PRIVATE, fd, 0);
281 if (ld_map == MAP_FAILED) {
282 close(fd);
283 return -1;
284 }
Vicent Martib366ede2016-04-20 13:24:54 +0200285
Vicent Martic1c23732016-04-20 13:24:54 +0200286 if (memcmp(ld_map, CACHE1_HEADER, CACHE1_HEADER_LEN) == 0) {
287 const struct ld_cache1 *cache1 = (struct ld_cache1 *)ld_map;
288 size_t cache1_len = sizeof(struct ld_cache1) +
289 (cache1->entry_count * sizeof(struct ld_cache1_entry));
290 cache1_len = (cache1_len + 0x7) & ~0x7ULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200291
Vicent Martic1c23732016-04-20 13:24:54 +0200292 if (ld_size > (cache1_len + sizeof(struct ld_cache2)))
293 ret = read_cache2(ld_map + cache1_len);
294 else
295 ret = read_cache1(ld_map);
296 } else {
297 ret = read_cache2(ld_map);
298 }
Vicent Martib366ede2016-04-20 13:24:54 +0200299
Vicent Martic1c23732016-04-20 13:24:54 +0200300 munmap((void *)ld_map, ld_size);
301 close(fd);
302 return ret;
Vicent Martib366ede2016-04-20 13:24:54 +0200303}
304
305#define LD_SO_CACHE "/etc/ld.so.cache"
306#define FLAG_TYPE_MASK 0x00ff
307#define TYPE_ELF_LIBC6 0x0003
308#define FLAG_ABI_MASK 0xff00
309#define ABI_SPARC_LIB64 0x0100
310#define ABI_IA64_LIB64 0x0200
311#define ABI_X8664_LIB64 0x0300
312#define ABI_S390_LIB64 0x0400
313#define ABI_POWERPC_LIB64 0x0500
Yonghong Song7abe63a2017-10-24 09:50:55 -0700314#define ABI_AARCH64_LIB64 0x0a00
Vicent Martib366ede2016-04-20 13:24:54 +0200315
Vicent Martic1c23732016-04-20 13:24:54 +0200316static bool match_so_flags(int flags) {
317 if ((flags & FLAG_TYPE_MASK) != TYPE_ELF_LIBC6)
318 return false;
Vicent Martib366ede2016-04-20 13:24:54 +0200319
Vicent Martic1c23732016-04-20 13:24:54 +0200320 switch (flags & FLAG_ABI_MASK) {
Vicent Marti21536732016-04-20 13:37:55 +0200321 case ABI_SPARC_LIB64:
322 case ABI_IA64_LIB64:
323 case ABI_X8664_LIB64:
324 case ABI_S390_LIB64:
325 case ABI_POWERPC_LIB64:
Yonghong Song7abe63a2017-10-24 09:50:55 -0700326 case ABI_AARCH64_LIB64:
Vicent Marti21536732016-04-20 13:37:55 +0200327 return (sizeof(void *) == 8);
Vicent Martic1c23732016-04-20 13:24:54 +0200328 }
Vicent Martib366ede2016-04-20 13:24:54 +0200329
Ulrich Drepperce0981b2017-05-04 17:09:51 +0200330 return sizeof(void *) == 4;
Vicent Martib366ede2016-04-20 13:24:54 +0200331}
332
Paul Chaignon81654bf2017-01-15 10:11:42 +0100333static bool which_so_in_process(const char* libname, int pid, char* libpath) {
Paul Chaignon690b7e62016-12-25 19:43:41 +0100334 int ret, found = false;
335 char endline[4096], *mapname = NULL, *newline;
336 char mappings_file[128];
337 const size_t search_len = strlen(libname) + strlen("/lib.");
338 char search1[search_len + 1];
339 char search2[search_len + 1];
340
Nan Xiao03797792017-07-29 10:47:24 +0800341 snprintf(mappings_file, sizeof(mappings_file), "/proc/%ld/maps", (long)pid);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100342 FILE *fp = fopen(mappings_file, "r");
343 if (!fp)
344 return NULL;
345
346 snprintf(search1, search_len + 1, "/lib%s.", libname);
347 snprintf(search2, search_len + 1, "/lib%s-", libname);
348
349 do {
350 ret = fscanf(fp, "%*x-%*x %*s %*x %*s %*d");
351 if (!fgets(endline, sizeof(endline), fp))
352 break;
353
354 mapname = endline;
355 newline = strchr(endline, '\n');
356 if (newline)
357 newline[0] = '\0';
358
359 while (isspace(mapname[0])) mapname++;
360
361 if (strstr(mapname, ".so") && (strstr(mapname, search1) ||
362 strstr(mapname, search2))) {
363 found = true;
Paul Chaignon81654bf2017-01-15 10:11:42 +0100364 memcpy(libpath, mapname, strlen(mapname) + 1);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100365 break;
366 }
367 } while (ret != EOF);
368
369 fclose(fp);
370 return found;
371}
372
Paul Chaignon81654bf2017-01-15 10:11:42 +0100373char *bcc_procutils_which_so(const char *libname, int pid) {
Vicent Martic1c23732016-04-20 13:24:54 +0200374 const size_t soname_len = strlen(libname) + strlen("lib.so");
375 char soname[soname_len + 1];
Paul Chaignon81654bf2017-01-15 10:11:42 +0100376 char libpath[4096];
Vicent Martic1c23732016-04-20 13:24:54 +0200377 int i;
Vicent Martib366ede2016-04-20 13:24:54 +0200378
Vicent Martic1c23732016-04-20 13:24:54 +0200379 if (strchr(libname, '/'))
Paul Chaignon81654bf2017-01-15 10:11:42 +0100380 return strdup(libname);
Vicent Martib366ede2016-04-20 13:24:54 +0200381
Paul Chaignon81654bf2017-01-15 10:11:42 +0100382 if (pid && which_so_in_process(libname, pid, libpath))
383 return strdup(libpath);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100384
Vicent Martic1c23732016-04-20 13:24:54 +0200385 if (lib_cache_count < 0)
386 return NULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200387
Vicent Martic1c23732016-04-20 13:24:54 +0200388 if (!lib_cache_count && load_ld_cache(LD_SO_CACHE) < 0) {
389 lib_cache_count = -1;
390 return NULL;
391 }
Vicent Martib366ede2016-04-20 13:24:54 +0200392
Vicent Martic1c23732016-04-20 13:24:54 +0200393 snprintf(soname, soname_len + 1, "lib%s.so", libname);
Vicent Martib366ede2016-04-20 13:24:54 +0200394
Vicent Martic1c23732016-04-20 13:24:54 +0200395 for (i = 0; i < lib_cache_count; ++i) {
396 if (!strncmp(lib_cache[i].libname, soname, soname_len) &&
Paul Chaignon690b7e62016-12-25 19:43:41 +0100397 match_so_flags(lib_cache[i].flags)) {
Paul Chaignon81654bf2017-01-15 10:11:42 +0100398 return strdup(lib_cache[i].path);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100399 }
Vicent Martic1c23732016-04-20 13:24:54 +0200400 }
401 return NULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200402}
Paul Chaignon81654bf2017-01-15 10:11:42 +0100403
404void bcc_procutils_free(const char *ptr) {
405 free((void *)ptr);
406}
kmjohansen4b87af02017-03-30 00:58:31 -0700407
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200408/* Detects the following languages + C. */
409const char *languages[] = {"java", "python", "ruby", "php", "node"};
410const char *language_c = "c";
411const int nb_languages = 5;
412
413const char *bcc_procutils_language(int pid) {
Nan Xiao03797792017-07-29 10:47:24 +0800414 char procfilename[24], line[4096], pathname[32], *str;
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200415 FILE *procfile;
416 int i, ret;
417
418 /* Look for clues in the absolute path to the executable. */
Nan Xiao03797792017-07-29 10:47:24 +0800419 snprintf(procfilename, sizeof(procfilename), "/proc/%ld/exe", (long)pid);
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200420 if (realpath(procfilename, line)) {
421 for (i = 0; i < nb_languages; i++)
422 if (strstr(line, languages[i]))
423 return languages[i];
424 }
425
426
Nan Xiao03797792017-07-29 10:47:24 +0800427 snprintf(procfilename, sizeof(procfilename), "/proc/%ld/maps", (long)pid);
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200428 procfile = fopen(procfilename, "r");
429 if (!procfile)
430 return NULL;
431
432 /* Look for clues in memory mappings. */
433 bool libc = false;
434 do {
435 char perm[8], dev[8];
436 long long begin, end, size, inode;
437 ret = fscanf(procfile, "%llx-%llx %s %llx %s %lld", &begin, &end, perm,
438 &size, dev, &inode);
439 if (!fgets(line, sizeof(line), procfile))
440 break;
441 if (ret == 6) {
442 char *mapname = line;
443 char *newline = strchr(line, '\n');
444 if (newline)
445 newline[0] = '\0';
446 while (isspace(mapname[0])) mapname++;
447 for (i = 0; i < nb_languages; i++) {
Nan Xiao03797792017-07-29 10:47:24 +0800448 snprintf(pathname, sizeof(pathname), "/lib%s", languages[i]);
jeromemarchandb84714a2018-08-08 18:09:44 +0200449 if (strstr(mapname, pathname)) {
450 fclose(procfile);
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200451 return languages[i];
jeromemarchandb84714a2018-08-08 18:09:44 +0200452 }
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200453 if ((str = strstr(mapname, "libc")) &&
454 (str[4] == '-' || str[4] == '.'))
455 libc = true;
456 }
457 }
458 } while (ret && ret != EOF);
459
460 fclose(procfile);
461
462 /* Return C as the language if libc was found and nothing else. */
463 return libc ? language_c : NULL;
464}