1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2016 Facebook, Inc.
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker #include <ctype.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <limits.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
22*387f9dfdSAndroid Build Coastguard Worker
23*387f9dfdSAndroid Build Coastguard Worker #include "bcc_perf_map.h"
24*387f9dfdSAndroid Build Coastguard Worker
bcc_is_perf_map(const char * path)25*387f9dfdSAndroid Build Coastguard Worker bool bcc_is_perf_map(const char *path) {
26*387f9dfdSAndroid Build Coastguard Worker char* pos = strstr(path, ".map");
27*387f9dfdSAndroid Build Coastguard Worker // Path ends with ".map"
28*387f9dfdSAndroid Build Coastguard Worker return (pos != NULL) && (*(pos + 4)== 0);
29*387f9dfdSAndroid Build Coastguard Worker }
30*387f9dfdSAndroid Build Coastguard Worker
bcc_is_valid_perf_map(const char * path)31*387f9dfdSAndroid Build Coastguard Worker bool bcc_is_valid_perf_map(const char *path) {
32*387f9dfdSAndroid Build Coastguard Worker return bcc_is_perf_map(path) && (access(path, R_OK) == 0);
33*387f9dfdSAndroid Build Coastguard Worker }
34*387f9dfdSAndroid Build Coastguard Worker
bcc_perf_map_nstgid(int pid)35*387f9dfdSAndroid Build Coastguard Worker int bcc_perf_map_nstgid(int pid) {
36*387f9dfdSAndroid Build Coastguard Worker char status_path[64];
37*387f9dfdSAndroid Build Coastguard Worker FILE *status;
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker snprintf(status_path, sizeof(status_path), "/proc/%d/status", pid);
40*387f9dfdSAndroid Build Coastguard Worker status = fopen(status_path, "r");
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Worker if (!status)
43*387f9dfdSAndroid Build Coastguard Worker return -1;
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Worker // return the original PID if we fail to work out the TGID
46*387f9dfdSAndroid Build Coastguard Worker int nstgid = pid;
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard Worker size_t size = 0;
49*387f9dfdSAndroid Build Coastguard Worker char *line = NULL;
50*387f9dfdSAndroid Build Coastguard Worker while (getline(&line, &size, status) != -1) {
51*387f9dfdSAndroid Build Coastguard Worker // check Tgid line first in case CONFIG_PID_NS is off
52*387f9dfdSAndroid Build Coastguard Worker if (strstr(line, "Tgid:") != NULL)
53*387f9dfdSAndroid Build Coastguard Worker nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10);
54*387f9dfdSAndroid Build Coastguard Worker if (strstr(line, "NStgid:") != NULL)
55*387f9dfdSAndroid Build Coastguard Worker // PID namespaces can be nested -- last number is innermost PID
56*387f9dfdSAndroid Build Coastguard Worker nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10);
57*387f9dfdSAndroid Build Coastguard Worker }
58*387f9dfdSAndroid Build Coastguard Worker free(line);
59*387f9dfdSAndroid Build Coastguard Worker fclose(status);
60*387f9dfdSAndroid Build Coastguard Worker
61*387f9dfdSAndroid Build Coastguard Worker return nstgid;
62*387f9dfdSAndroid Build Coastguard Worker }
63*387f9dfdSAndroid Build Coastguard Worker
bcc_perf_map_path(char * map_path,size_t map_len,int pid)64*387f9dfdSAndroid Build Coastguard Worker bool bcc_perf_map_path(char *map_path, size_t map_len, int pid) {
65*387f9dfdSAndroid Build Coastguard Worker char source[64];
66*387f9dfdSAndroid Build Coastguard Worker snprintf(source, sizeof(source), "/proc/%d/root", pid);
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Worker char target[4096];
69*387f9dfdSAndroid Build Coastguard Worker ssize_t target_len = readlink(source, target, sizeof(target) - 1);
70*387f9dfdSAndroid Build Coastguard Worker if (target_len == -1)
71*387f9dfdSAndroid Build Coastguard Worker return false;
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker target[target_len] = '\0';
74*387f9dfdSAndroid Build Coastguard Worker if (strcmp(target, "/") == 0)
75*387f9dfdSAndroid Build Coastguard Worker target[0] = '\0';
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker int nstgid = bcc_perf_map_nstgid(pid);
78*387f9dfdSAndroid Build Coastguard Worker
79*387f9dfdSAndroid Build Coastguard Worker snprintf(map_path, map_len, "%s/tmp/perf-%d.map", target, nstgid);
80*387f9dfdSAndroid Build Coastguard Worker return true;
81*387f9dfdSAndroid Build Coastguard Worker }
82*387f9dfdSAndroid Build Coastguard Worker
bcc_perf_map_foreach_sym(const char * path,bcc_perf_map_symcb callback,void * payload)83*387f9dfdSAndroid Build Coastguard Worker int bcc_perf_map_foreach_sym(const char *path, bcc_perf_map_symcb callback,
84*387f9dfdSAndroid Build Coastguard Worker void* payload) {
85*387f9dfdSAndroid Build Coastguard Worker FILE* file = fopen(path, "r");
86*387f9dfdSAndroid Build Coastguard Worker if (!file)
87*387f9dfdSAndroid Build Coastguard Worker return -1;
88*387f9dfdSAndroid Build Coastguard Worker
89*387f9dfdSAndroid Build Coastguard Worker char *line = NULL;
90*387f9dfdSAndroid Build Coastguard Worker size_t size = 0;
91*387f9dfdSAndroid Build Coastguard Worker long long begin, len;
92*387f9dfdSAndroid Build Coastguard Worker while (getline(&line, &size, file) != -1) {
93*387f9dfdSAndroid Build Coastguard Worker char *cursor = line;
94*387f9dfdSAndroid Build Coastguard Worker char *newline, *sep;
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker begin = strtoull(cursor, &sep, 16);
97*387f9dfdSAndroid Build Coastguard Worker if (begin == 0 || *sep != ' ' || (begin == ULLONG_MAX && errno == ERANGE))
98*387f9dfdSAndroid Build Coastguard Worker continue;
99*387f9dfdSAndroid Build Coastguard Worker cursor = sep;
100*387f9dfdSAndroid Build Coastguard Worker while (*cursor && isspace(*cursor)) cursor++;
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker len = strtoull(cursor, &sep, 16);
103*387f9dfdSAndroid Build Coastguard Worker if (*sep != ' ' ||
104*387f9dfdSAndroid Build Coastguard Worker (sep == cursor && len == 0) ||
105*387f9dfdSAndroid Build Coastguard Worker (len == ULLONG_MAX && errno == ERANGE))
106*387f9dfdSAndroid Build Coastguard Worker continue;
107*387f9dfdSAndroid Build Coastguard Worker cursor = sep;
108*387f9dfdSAndroid Build Coastguard Worker while (*cursor && isspace(*cursor)) cursor++;
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Worker newline = strchr(cursor, '\n');
111*387f9dfdSAndroid Build Coastguard Worker if (newline)
112*387f9dfdSAndroid Build Coastguard Worker newline[0] = '\0';
113*387f9dfdSAndroid Build Coastguard Worker
114*387f9dfdSAndroid Build Coastguard Worker callback(cursor, begin, len, payload);
115*387f9dfdSAndroid Build Coastguard Worker }
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Worker free(line);
118*387f9dfdSAndroid Build Coastguard Worker fclose(file);
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker return 0;
121*387f9dfdSAndroid Build Coastguard Worker }
122