• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Facebook, 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  */
16 #include <ctype.h>
17 #include <errno.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "bcc_perf_map.h"
24 
bcc_is_perf_map(const char * path)25 bool bcc_is_perf_map(const char *path) {
26   char* pos = strstr(path, ".map");
27   // Path ends with ".map"
28   return (pos != NULL) && (*(pos + 4)== 0);
29 }
30 
bcc_is_valid_perf_map(const char * path)31 bool bcc_is_valid_perf_map(const char *path) {
32   return bcc_is_perf_map(path) && (access(path, R_OK) == 0);
33 }
34 
bcc_perf_map_nstgid(int pid)35 int bcc_perf_map_nstgid(int pid) {
36   char status_path[64];
37   FILE *status;
38 
39   snprintf(status_path, sizeof(status_path), "/proc/%d/status", pid);
40   status = fopen(status_path, "r");
41 
42   if (!status)
43     return -1;
44 
45   // return the original PID if we fail to work out the TGID
46   int nstgid = pid;
47 
48   size_t size = 0;
49   char *line = NULL;
50   while (getline(&line, &size, status) != -1) {
51     // check Tgid line first in case CONFIG_PID_NS is off
52     if (strstr(line, "Tgid:") != NULL)
53       nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10);
54     if (strstr(line, "NStgid:") != NULL)
55       // PID namespaces can be nested -- last number is innermost PID
56       nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10);
57   }
58   free(line);
59   fclose(status);
60 
61   return nstgid;
62 }
63 
bcc_perf_map_path(char * map_path,size_t map_len,int pid)64 bool bcc_perf_map_path(char *map_path, size_t map_len, int pid) {
65   char source[64];
66   snprintf(source, sizeof(source), "/proc/%d/root", pid);
67 
68   char target[4096];
69   ssize_t target_len = readlink(source, target, sizeof(target) - 1);
70   if (target_len == -1)
71     return false;
72 
73   target[target_len] = '\0';
74   if (strcmp(target, "/") == 0)
75     target[0] = '\0';
76 
77   int nstgid = bcc_perf_map_nstgid(pid);
78 
79   snprintf(map_path, map_len, "%s/tmp/perf-%d.map", target, nstgid);
80   return true;
81 }
82 
bcc_perf_map_foreach_sym(const char * path,bcc_perf_map_symcb callback,void * payload)83 int bcc_perf_map_foreach_sym(const char *path, bcc_perf_map_symcb callback,
84                              void* payload) {
85   FILE* file = fopen(path, "r");
86   if (!file)
87     return -1;
88 
89   char *line = NULL;
90   size_t size = 0;
91   long long begin, len;
92   while (getline(&line, &size, file) != -1) {
93     char *cursor = line;
94     char *newline, *sep;
95 
96     begin = strtoull(cursor, &sep, 16);
97     if (begin == 0 || *sep != ' ' || (begin == ULLONG_MAX && errno == ERANGE))
98       continue;
99     cursor = sep;
100     while (*cursor && isspace(*cursor)) cursor++;
101 
102     len = strtoull(cursor, &sep, 16);
103     if (*sep != ' ' ||
104         (sep == cursor && len == 0) ||
105         (len == ULLONG_MAX && errno == ERANGE))
106       continue;
107     cursor = sep;
108     while (*cursor && isspace(*cursor)) cursor++;
109 
110     newline = strchr(cursor, '\n');
111     if (newline)
112         newline[0] = '\0';
113 
114     callback(cursor, begin, len, payload);
115   }
116 
117   free(line);
118   fclose(file);
119 
120   return 0;
121 }
122