blob: 5b2641dfeaa1607d23731ab34de68140edccb0dd [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 */
kmjohansen4b87af02017-03-30 00:58:31 -070016#define _GNU_SOURCE
Vicent Martib366ede2016-04-20 13:24:54 +020017#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/mman.h>
20#include <fcntl.h>
kmjohansen4b87af02017-03-30 00:58:31 -070021#include <sched.h>
Vicent Martib366ede2016-04-20 13:24:54 +020022#include <unistd.h>
23#include <stdlib.h>
24#include <stdbool.h>
25#include <string.h>
26#include <stdint.h>
27#include <ctype.h>
28#include <stdio.h>
Paul Chaignon690b7e62016-12-25 19:43:41 +010029#include <math.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
Vicent Martic1c23732016-04-20 13:24:54 +020035static bool is_exe(const char *path) {
36 struct stat s;
37 if (access(path, X_OK) < 0)
38 return false;
Vicent Martib366ede2016-04-20 13:24:54 +020039
Vicent Martic1c23732016-04-20 13:24:54 +020040 if (stat(path, &s) < 0)
41 return false;
Vicent Martib366ede2016-04-20 13:24:54 +020042
Vicent Martic1c23732016-04-20 13:24:54 +020043 return S_ISREG(s.st_mode);
Vicent Martib366ede2016-04-20 13:24:54 +020044}
45
Vicent Martic1c23732016-04-20 13:24:54 +020046char *bcc_procutils_which(const char *binpath) {
47 char buffer[4096];
48 const char *PATH;
Vicent Martib366ede2016-04-20 13:24:54 +020049
Vicent Martic1c23732016-04-20 13:24:54 +020050 if (strchr(binpath, '/'))
51 return is_exe(binpath) ? strdup(binpath) : 0;
Vicent Martib366ede2016-04-20 13:24:54 +020052
Vicent Martic1c23732016-04-20 13:24:54 +020053 if (!(PATH = getenv("PATH")))
54 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +020055
Vicent Martic1c23732016-04-20 13:24:54 +020056 while (PATH) {
57 const char *next = strchr(PATH, ':') ?: strchr(PATH, '\0');
58 const size_t path_len = next - PATH;
Vicent Martib366ede2016-04-20 13:24:54 +020059
Vicent Martic1c23732016-04-20 13:24:54 +020060 if (path_len) {
61 memcpy(buffer, PATH, path_len);
62 buffer[path_len] = '/';
63 strcpy(buffer + path_len + 1, binpath);
Vicent Martib366ede2016-04-20 13:24:54 +020064
Vicent Martic1c23732016-04-20 13:24:54 +020065 if (is_exe(buffer))
66 return strdup(buffer);
67 }
Vicent Martib366ede2016-04-20 13:24:54 +020068
Vicent Martic1c23732016-04-20 13:24:54 +020069 PATH = *next ? (next + 1) : 0;
70 }
Vicent Martib366ede2016-04-20 13:24:54 +020071
Vicent Martic1c23732016-04-20 13:24:54 +020072 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +020073}
74
Mark Drayton13685082017-02-22 02:05:10 +000075int bcc_mapping_is_file_backed(const char *mapname) {
76 return mapname[0] &&
77 strncmp(mapname, "//anon", sizeof("//anon") - 1) &&
78 strncmp(mapname, "/dev/zero", sizeof("/dev/zero") - 1) &&
79 strncmp(mapname, "/anon_hugepage", sizeof("/anon_hugepage") - 1) &&
80 strncmp(mapname, "[stack", sizeof("[stack") - 1) &&
81 strncmp(mapname, "/SYSV", sizeof("/SYSV") - 1) &&
82 strncmp(mapname, "[heap]", sizeof("[heap]") - 1);
83}
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;
89 int ret;
Vicent Martib366ede2016-04-20 13:24:54 +020090
Vicent Martic1c23732016-04-20 13:24:54 +020091 sprintf(procmap_filename, "/proc/%ld/maps", (long)pid);
92 procmap = fopen(procmap_filename, "r");
Vicent Martib366ede2016-04-20 13:24:54 +020093
Vicent Martic1c23732016-04-20 13:24:54 +020094 if (!procmap)
95 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +020096
Vicent Martic1c23732016-04-20 13:24:54 +020097 do {
98 char endline[4096];
99 char perm[8], dev[8];
100 long long begin, end, size, inode;
Vicent Martib366ede2016-04-20 13:24:54 +0200101
Mark Drayton769edf92016-06-15 11:53:24 +0100102 ret = fscanf(procmap, "%llx-%llx %s %llx %s %lld", &begin, &end, perm,
Vicent Martic1c23732016-04-20 13:24:54 +0200103 &size, dev, &inode);
Vicent Martib366ede2016-04-20 13:24:54 +0200104
Vicent Martic1c23732016-04-20 13:24:54 +0200105 if (!fgets(endline, sizeof(endline), procmap))
106 break;
Vicent Martib366ede2016-04-20 13:24:54 +0200107
Vicent Martic1c23732016-04-20 13:24:54 +0200108 if (ret == 6) {
109 char *mapname = endline;
110 char *newline = strchr(endline, '\n');
Vicent Martib366ede2016-04-20 13:24:54 +0200111
Vicent Martic1c23732016-04-20 13:24:54 +0200112 if (newline)
113 newline[0] = '\0';
Vicent Martib366ede2016-04-20 13:24:54 +0200114
Vicent Martic1c23732016-04-20 13:24:54 +0200115 while (isspace(mapname[0])) mapname++;
Vicent Martib366ede2016-04-20 13:24:54 +0200116
Mark Drayton13685082017-02-22 02:05:10 +0000117 if (strchr(perm, 'x') && bcc_mapping_is_file_backed(mapname)) {
Vicent Marti2ff8e572016-04-28 12:20:57 +0200118 if (callback(mapname, (uint64_t)begin, (uint64_t)end, payload) < 0)
119 break;
120 }
Vicent Martic1c23732016-04-20 13:24:54 +0200121 }
122 } while (ret && ret != EOF);
Vicent Martib366ede2016-04-20 13:24:54 +0200123
Vicent Martic1c23732016-04-20 13:24:54 +0200124 fclose(procmap);
Mark Drayton769edf92016-06-15 11:53:24 +0100125
126 // Add a mapping to /tmp/perf-pid.map for the entire address space. This will
127 // be used if symbols aren't resolved in an earlier mapping.
128 char map_path[4096];
129 if (bcc_perf_map_path(map_path, sizeof(map_path), pid))
130 callback(map_path, 0, -1, payload);
131
Vicent Martic1c23732016-04-20 13:24:54 +0200132 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200133}
134
Vicent Martic1c23732016-04-20 13:24:54 +0200135int bcc_procutils_each_ksym(bcc_procutils_ksymcb callback, void *payload) {
136 char line[2048];
Vicent Marti6b59b2c2016-04-20 13:24:54 +0200137 FILE *kallsyms;
Vicent Martib366ede2016-04-20 13:24:54 +0200138
Vicent Marti6b59b2c2016-04-20 13:24:54 +0200139 /* root is needed to list ksym addresses */
140 if (geteuid() != 0)
141 return -1;
142
143 kallsyms = fopen("/proc/kallsyms", "r");
Vicent Martic1c23732016-04-20 13:24:54 +0200144 if (!kallsyms)
145 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200146
Vicent Martic1c23732016-04-20 13:24:54 +0200147 if (!fgets(line, sizeof(line), kallsyms)) {
148 fclose(kallsyms);
149 return -1;
150 }
Vicent Martib366ede2016-04-20 13:24:54 +0200151
Vicent Martic1c23732016-04-20 13:24:54 +0200152 while (fgets(line, sizeof(line), kallsyms)) {
153 char *symname, *endsym;
154 unsigned long long addr;
Vicent Martib366ede2016-04-20 13:24:54 +0200155
Vicent Martic1c23732016-04-20 13:24:54 +0200156 addr = strtoull(line, &symname, 16);
157 endsym = symname = symname + 3;
Vicent Martib366ede2016-04-20 13:24:54 +0200158
Vicent Martic1c23732016-04-20 13:24:54 +0200159 while (*endsym && !isspace(*endsym)) endsym++;
Vicent Martib366ede2016-04-20 13:24:54 +0200160
Vicent Martic1c23732016-04-20 13:24:54 +0200161 *endsym = '\0';
162 callback(symname, addr, payload);
163 }
Vicent Martib366ede2016-04-20 13:24:54 +0200164
Vicent Martic1c23732016-04-20 13:24:54 +0200165 fclose(kallsyms);
166 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200167}
168
169#define CACHE1_HEADER "ld.so-1.7.0"
170#define CACHE1_HEADER_LEN (sizeof(CACHE1_HEADER) - 1)
171
172#define CACHE2_HEADER "glibc-ld.so.cache"
173#define CACHE2_HEADER_LEN (sizeof(CACHE2_HEADER) - 1)
174#define CACHE2_VERSION "1.1"
175
176struct ld_cache1_entry {
Vicent Martic1c23732016-04-20 13:24:54 +0200177 int32_t flags;
178 uint32_t key;
179 uint32_t value;
Vicent Martib366ede2016-04-20 13:24:54 +0200180};
181
182struct ld_cache1 {
Vicent Martic1c23732016-04-20 13:24:54 +0200183 char header[CACHE1_HEADER_LEN];
184 uint32_t entry_count;
185 struct ld_cache1_entry entries[0];
Vicent Martib366ede2016-04-20 13:24:54 +0200186};
187
188struct ld_cache2_entry {
Vicent Martic1c23732016-04-20 13:24:54 +0200189 int32_t flags;
190 uint32_t key;
191 uint32_t value;
192 uint32_t pad1_;
193 uint64_t pad2_;
Vicent Martib366ede2016-04-20 13:24:54 +0200194};
195
196struct ld_cache2 {
Vicent Martic1c23732016-04-20 13:24:54 +0200197 char header[CACHE2_HEADER_LEN];
198 char version[3];
199 uint32_t entry_count;
200 uint32_t string_table_len;
201 uint32_t pad_[5];
202 struct ld_cache2_entry entries[0];
Vicent Martib366ede2016-04-20 13:24:54 +0200203};
204
205static int lib_cache_count;
206static struct ld_lib {
Vicent Martic1c23732016-04-20 13:24:54 +0200207 char *libname;
208 char *path;
209 int flags;
210} * lib_cache;
Vicent Martib366ede2016-04-20 13:24:54 +0200211
Vicent Martic1c23732016-04-20 13:24:54 +0200212static int read_cache1(const char *ld_map) {
213 struct ld_cache1 *ldcache = (struct ld_cache1 *)ld_map;
214 const char *ldstrings =
215 (const char *)(ldcache->entries + ldcache->entry_count);
216 uint32_t i;
Vicent Martib366ede2016-04-20 13:24:54 +0200217
Vicent Martic1c23732016-04-20 13:24:54 +0200218 lib_cache =
219 (struct ld_lib *)malloc(ldcache->entry_count * sizeof(struct ld_lib));
220 lib_cache_count = (int)ldcache->entry_count;
Vicent Martib366ede2016-04-20 13:24:54 +0200221
Vicent Martic1c23732016-04-20 13:24:54 +0200222 for (i = 0; i < ldcache->entry_count; ++i) {
223 const char *key = ldstrings + ldcache->entries[i].key;
224 const char *val = ldstrings + ldcache->entries[i].value;
225 const int flags = ldcache->entries[i].flags;
Vicent Martib366ede2016-04-20 13:24:54 +0200226
Vicent Martic1c23732016-04-20 13:24:54 +0200227 lib_cache[i].libname = strdup(key);
228 lib_cache[i].path = strdup(val);
229 lib_cache[i].flags = flags;
230 }
231 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200232}
233
Vicent Martic1c23732016-04-20 13:24:54 +0200234static int read_cache2(const char *ld_map) {
235 struct ld_cache2 *ldcache = (struct ld_cache2 *)ld_map;
236 uint32_t i;
Vicent Martib366ede2016-04-20 13:24:54 +0200237
Vicent Martic1c23732016-04-20 13:24:54 +0200238 if (memcmp(ld_map, CACHE2_HEADER, CACHE2_HEADER_LEN))
239 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200240
Vicent Martic1c23732016-04-20 13:24:54 +0200241 lib_cache =
242 (struct ld_lib *)malloc(ldcache->entry_count * sizeof(struct ld_lib));
243 lib_cache_count = (int)ldcache->entry_count;
Vicent Martib366ede2016-04-20 13:24:54 +0200244
Vicent Martic1c23732016-04-20 13:24:54 +0200245 for (i = 0; i < ldcache->entry_count; ++i) {
246 const char *key = ld_map + ldcache->entries[i].key;
247 const char *val = ld_map + ldcache->entries[i].value;
248 const int flags = ldcache->entries[i].flags;
Vicent Martib366ede2016-04-20 13:24:54 +0200249
Vicent Martic1c23732016-04-20 13:24:54 +0200250 lib_cache[i].libname = strdup(key);
251 lib_cache[i].path = strdup(val);
252 lib_cache[i].flags = flags;
253 }
254 return 0;
Vicent Martib366ede2016-04-20 13:24:54 +0200255}
256
Vicent Martic1c23732016-04-20 13:24:54 +0200257static int load_ld_cache(const char *cache_path) {
258 struct stat st;
259 size_t ld_size;
260 const char *ld_map;
261 int ret, fd = open(cache_path, O_RDONLY);
Vicent Martib366ede2016-04-20 13:24:54 +0200262
Vicent Martic1c23732016-04-20 13:24:54 +0200263 if (fd < 0)
264 return -1;
Vicent Martib366ede2016-04-20 13:24:54 +0200265
Vicent Martic1c23732016-04-20 13:24:54 +0200266 if (fstat(fd, &st) < 0 || st.st_size < sizeof(struct ld_cache1)) {
267 close(fd);
268 return -1;
269 }
Vicent Martib366ede2016-04-20 13:24:54 +0200270
Vicent Martic1c23732016-04-20 13:24:54 +0200271 ld_size = st.st_size;
272 ld_map = (const char *)mmap(NULL, ld_size, PROT_READ, MAP_PRIVATE, fd, 0);
273 if (ld_map == MAP_FAILED) {
274 close(fd);
275 return -1;
276 }
Vicent Martib366ede2016-04-20 13:24:54 +0200277
Vicent Martic1c23732016-04-20 13:24:54 +0200278 if (memcmp(ld_map, CACHE1_HEADER, CACHE1_HEADER_LEN) == 0) {
279 const struct ld_cache1 *cache1 = (struct ld_cache1 *)ld_map;
280 size_t cache1_len = sizeof(struct ld_cache1) +
281 (cache1->entry_count * sizeof(struct ld_cache1_entry));
282 cache1_len = (cache1_len + 0x7) & ~0x7ULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200283
Vicent Martic1c23732016-04-20 13:24:54 +0200284 if (ld_size > (cache1_len + sizeof(struct ld_cache2)))
285 ret = read_cache2(ld_map + cache1_len);
286 else
287 ret = read_cache1(ld_map);
288 } else {
289 ret = read_cache2(ld_map);
290 }
Vicent Martib366ede2016-04-20 13:24:54 +0200291
Vicent Martic1c23732016-04-20 13:24:54 +0200292 munmap((void *)ld_map, ld_size);
293 close(fd);
294 return ret;
Vicent Martib366ede2016-04-20 13:24:54 +0200295}
296
297#define LD_SO_CACHE "/etc/ld.so.cache"
298#define FLAG_TYPE_MASK 0x00ff
299#define TYPE_ELF_LIBC6 0x0003
300#define FLAG_ABI_MASK 0xff00
301#define ABI_SPARC_LIB64 0x0100
302#define ABI_IA64_LIB64 0x0200
303#define ABI_X8664_LIB64 0x0300
304#define ABI_S390_LIB64 0x0400
305#define ABI_POWERPC_LIB64 0x0500
306
Vicent Martic1c23732016-04-20 13:24:54 +0200307static bool match_so_flags(int flags) {
308 if ((flags & FLAG_TYPE_MASK) != TYPE_ELF_LIBC6)
309 return false;
Vicent Martib366ede2016-04-20 13:24:54 +0200310
Vicent Martic1c23732016-04-20 13:24:54 +0200311 switch (flags & FLAG_ABI_MASK) {
Vicent Marti21536732016-04-20 13:37:55 +0200312 case ABI_SPARC_LIB64:
313 case ABI_IA64_LIB64:
314 case ABI_X8664_LIB64:
315 case ABI_S390_LIB64:
316 case ABI_POWERPC_LIB64:
317 return (sizeof(void *) == 8);
Vicent Martic1c23732016-04-20 13:24:54 +0200318 }
Vicent Martib366ede2016-04-20 13:24:54 +0200319
Vicent Martic1c23732016-04-20 13:24:54 +0200320 return true;
Vicent Martib366ede2016-04-20 13:24:54 +0200321}
322
Paul Chaignon81654bf2017-01-15 10:11:42 +0100323static bool which_so_in_process(const char* libname, int pid, char* libpath) {
Paul Chaignon690b7e62016-12-25 19:43:41 +0100324 int ret, found = false;
325 char endline[4096], *mapname = NULL, *newline;
326 char mappings_file[128];
327 const size_t search_len = strlen(libname) + strlen("/lib.");
328 char search1[search_len + 1];
329 char search2[search_len + 1];
330
331 sprintf(mappings_file, "/proc/%ld/maps", (long)pid);
332 FILE *fp = fopen(mappings_file, "r");
333 if (!fp)
334 return NULL;
335
336 snprintf(search1, search_len + 1, "/lib%s.", libname);
337 snprintf(search2, search_len + 1, "/lib%s-", libname);
338
339 do {
340 ret = fscanf(fp, "%*x-%*x %*s %*x %*s %*d");
341 if (!fgets(endline, sizeof(endline), fp))
342 break;
343
344 mapname = endline;
345 newline = strchr(endline, '\n');
346 if (newline)
347 newline[0] = '\0';
348
349 while (isspace(mapname[0])) mapname++;
350
351 if (strstr(mapname, ".so") && (strstr(mapname, search1) ||
352 strstr(mapname, search2))) {
353 found = true;
Paul Chaignon81654bf2017-01-15 10:11:42 +0100354 memcpy(libpath, mapname, strlen(mapname) + 1);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100355 break;
356 }
357 } while (ret != EOF);
358
359 fclose(fp);
360 return found;
361}
362
Paul Chaignon81654bf2017-01-15 10:11:42 +0100363char *bcc_procutils_which_so(const char *libname, int pid) {
Vicent Martic1c23732016-04-20 13:24:54 +0200364 const size_t soname_len = strlen(libname) + strlen("lib.so");
365 char soname[soname_len + 1];
Paul Chaignon81654bf2017-01-15 10:11:42 +0100366 char libpath[4096];
Vicent Martic1c23732016-04-20 13:24:54 +0200367 int i;
Vicent Martib366ede2016-04-20 13:24:54 +0200368
Vicent Martic1c23732016-04-20 13:24:54 +0200369 if (strchr(libname, '/'))
Paul Chaignon81654bf2017-01-15 10:11:42 +0100370 return strdup(libname);
Vicent Martib366ede2016-04-20 13:24:54 +0200371
Paul Chaignon81654bf2017-01-15 10:11:42 +0100372 if (pid && which_so_in_process(libname, pid, libpath))
373 return strdup(libpath);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100374
Vicent Martic1c23732016-04-20 13:24:54 +0200375 if (lib_cache_count < 0)
376 return NULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200377
Vicent Martic1c23732016-04-20 13:24:54 +0200378 if (!lib_cache_count && load_ld_cache(LD_SO_CACHE) < 0) {
379 lib_cache_count = -1;
380 return NULL;
381 }
Vicent Martib366ede2016-04-20 13:24:54 +0200382
Vicent Martic1c23732016-04-20 13:24:54 +0200383 snprintf(soname, soname_len + 1, "lib%s.so", libname);
Vicent Martib366ede2016-04-20 13:24:54 +0200384
Vicent Martic1c23732016-04-20 13:24:54 +0200385 for (i = 0; i < lib_cache_count; ++i) {
386 if (!strncmp(lib_cache[i].libname, soname, soname_len) &&
Paul Chaignon690b7e62016-12-25 19:43:41 +0100387 match_so_flags(lib_cache[i].flags)) {
Paul Chaignon81654bf2017-01-15 10:11:42 +0100388 return strdup(lib_cache[i].path);
Paul Chaignon690b7e62016-12-25 19:43:41 +0100389 }
Vicent Martic1c23732016-04-20 13:24:54 +0200390 }
391 return NULL;
Vicent Martib366ede2016-04-20 13:24:54 +0200392}
Paul Chaignon81654bf2017-01-15 10:11:42 +0100393
394void bcc_procutils_free(const char *ptr) {
395 free((void *)ptr);
396}
kmjohansen4b87af02017-03-30 00:58:31 -0700397
398bool bcc_procutils_enter_mountns(int pid, struct ns_cookie *nc) {
399 char curnspath[4096];
400 char newnspath[4096];
401 int oldns = -1;
402 int newns = -1;
403 struct stat ons_stat;
404 struct stat nns_stat;
405
406 if (nc == NULL)
407 return false;
408
409 nc->nsc_oldns = -1;
410 nc->nsc_newns = -1;
411
412 if (snprintf(curnspath, 4096, "/proc/self/ns/mnt") == 4096) {
413 return false;
414 }
415
416 if (snprintf(newnspath, 4096, "/proc/%d/ns/mnt", pid) == 4096) {
417 return false;
418 }
419
420 if ((oldns = open(curnspath, O_RDONLY)) < 0) {
421 return false;
422 }
423
424 if ((newns = open(newnspath, O_RDONLY)) < 0) {
425 goto errout;
426 }
427
428 if (fstat(oldns, &ons_stat) < 0) {
429 goto errout;
430 }
431
432 if (fstat(newns, &nns_stat) < 0) {
433 goto errout;
434 }
435
436 /*
437 * Only switch to the new namespace if it doesn't match the existing
438 * namespace. This prevents us from getting an EPERM when trying to enter an
439 * identical namespace.
440 */
441 if (ons_stat.st_ino == nns_stat.st_ino) {
442 goto errout;
443 }
444
445 if (setns(newns, CLONE_NEWNS) < 0) {
446 goto errout;
447 }
448
449 nc->nsc_oldns = oldns;
450 nc->nsc_newns = newns;
451
452 return true;
453
454errout:
455 if (oldns > -1) {
456 (void) close(oldns);
457 }
458 if (newns > -1) {
459 (void) close(newns);
460 }
461 return false;
462}
463
464bool bcc_procutils_exit_mountns(struct ns_cookie *nc) {
465 bool rc = false;
466
467 if (nc == NULL)
468 return rc;
469
470 if (nc->nsc_oldns == -1 || nc->nsc_newns == -1)
471 return rc;
472
473 if (setns(nc->nsc_oldns, CLONE_NEWNS) == 0) {
474 rc = true;
475 }
476
477 if (nc->nsc_oldns > -1) {
478 (void) close(nc->nsc_oldns);
479 nc->nsc_oldns = -1;
480 }
481 if (nc->nsc_newns > -1) {
482 (void) close(nc->nsc_newns);
483 nc->nsc_newns = -1;
484 }
485
486 return rc;
487}
Paul Chaignon4bb6d7f2017-03-30 19:05:40 +0200488
489/* Detects the following languages + C. */
490const char *languages[] = {"java", "python", "ruby", "php", "node"};
491const char *language_c = "c";
492const int nb_languages = 5;
493
494const char *bcc_procutils_language(int pid) {
495 char procfilename[22], line[4096], pathname[32], *str;
496 FILE *procfile;
497 int i, ret;
498
499 /* Look for clues in the absolute path to the executable. */
500 sprintf(procfilename, "/proc/%ld/exe", (long)pid);
501 if (realpath(procfilename, line)) {
502 for (i = 0; i < nb_languages; i++)
503 if (strstr(line, languages[i]))
504 return languages[i];
505 }
506
507
508 sprintf(procfilename, "/proc/%ld/maps", (long)pid);
509 procfile = fopen(procfilename, "r");
510 if (!procfile)
511 return NULL;
512
513 /* Look for clues in memory mappings. */
514 bool libc = false;
515 do {
516 char perm[8], dev[8];
517 long long begin, end, size, inode;
518 ret = fscanf(procfile, "%llx-%llx %s %llx %s %lld", &begin, &end, perm,
519 &size, dev, &inode);
520 if (!fgets(line, sizeof(line), procfile))
521 break;
522 if (ret == 6) {
523 char *mapname = line;
524 char *newline = strchr(line, '\n');
525 if (newline)
526 newline[0] = '\0';
527 while (isspace(mapname[0])) mapname++;
528 for (i = 0; i < nb_languages; i++) {
529 sprintf(pathname, "/lib%s", languages[i]);
530 if (strstr(mapname, pathname))
531 return languages[i];
532 if ((str = strstr(mapname, "libc")) &&
533 (str[4] == '-' || str[4] == '.'))
534 libc = true;
535 }
536 }
537 } while (ret && ret != EOF);
538
539 fclose(procfile);
540
541 /* Return C as the language if libc was found and nothing else. */
542 return libc ? language_c : NULL;
543}