xref: /aosp_15_r20/external/bcc/src/cc/common.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker  * Copyright (c) 2016 Catalysts GmbH
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 <fstream>
17*387f9dfdSAndroid Build Coastguard Worker #include <sstream>
18*387f9dfdSAndroid Build Coastguard Worker 
19*387f9dfdSAndroid Build Coastguard Worker #include "common.h"
20*387f9dfdSAndroid Build Coastguard Worker #include "bcc_libbpf_inc.h"
21*387f9dfdSAndroid Build Coastguard Worker #include "vendor/optional.hpp"
22*387f9dfdSAndroid Build Coastguard Worker #include "vendor/tinyformat.hpp"
23*387f9dfdSAndroid Build Coastguard Worker 
24*387f9dfdSAndroid Build Coastguard Worker namespace ebpf {
25*387f9dfdSAndroid Build Coastguard Worker 
26*387f9dfdSAndroid Build Coastguard Worker using std::experimental::optional;
27*387f9dfdSAndroid Build Coastguard Worker 
28*387f9dfdSAndroid Build Coastguard Worker // Get enum value from BTF, since the enum may be anonymous, like:
29*387f9dfdSAndroid Build Coastguard Worker //   [608] ENUM '(anon)' size=4 vlen=1
30*387f9dfdSAndroid Build Coastguard Worker //   	'TASK_COMM_LEN' val=16
31*387f9dfdSAndroid Build Coastguard Worker // we have to traverse the whole BTF.
32*387f9dfdSAndroid Build Coastguard Worker // Though there is a BTF_KIND_ENUM64, but it is unlikely that it will
33*387f9dfdSAndroid Build Coastguard Worker // be used as array size, we don't handle it here.
get_enum_val_from_btf(const char * name)34*387f9dfdSAndroid Build Coastguard Worker static optional<int32_t> get_enum_val_from_btf(const char *name) {
35*387f9dfdSAndroid Build Coastguard Worker   optional<int32_t> val;
36*387f9dfdSAndroid Build Coastguard Worker 
37*387f9dfdSAndroid Build Coastguard Worker   auto btf = btf__load_vmlinux_btf();
38*387f9dfdSAndroid Build Coastguard Worker   if (libbpf_get_error(btf))
39*387f9dfdSAndroid Build Coastguard Worker     return {};
40*387f9dfdSAndroid Build Coastguard Worker 
41*387f9dfdSAndroid Build Coastguard Worker   for (size_t i = 1; i < btf__type_cnt(btf); i++) {
42*387f9dfdSAndroid Build Coastguard Worker     auto t = btf__type_by_id(btf, i);
43*387f9dfdSAndroid Build Coastguard Worker     if (btf_kind(t) != BTF_KIND_ENUM)
44*387f9dfdSAndroid Build Coastguard Worker       continue;
45*387f9dfdSAndroid Build Coastguard Worker 
46*387f9dfdSAndroid Build Coastguard Worker     auto m = btf_enum(t);
47*387f9dfdSAndroid Build Coastguard Worker     for (int j = 0, n = btf_vlen(t); j < n; j++, m++) {
48*387f9dfdSAndroid Build Coastguard Worker       if (!strcmp(btf__name_by_offset(btf, m->name_off), name)) {
49*387f9dfdSAndroid Build Coastguard Worker         val = m->val;
50*387f9dfdSAndroid Build Coastguard Worker         break;
51*387f9dfdSAndroid Build Coastguard Worker       }
52*387f9dfdSAndroid Build Coastguard Worker     }
53*387f9dfdSAndroid Build Coastguard Worker 
54*387f9dfdSAndroid Build Coastguard Worker     if (val)
55*387f9dfdSAndroid Build Coastguard Worker       break;
56*387f9dfdSAndroid Build Coastguard Worker   }
57*387f9dfdSAndroid Build Coastguard Worker 
58*387f9dfdSAndroid Build Coastguard Worker   btf__free(btf);
59*387f9dfdSAndroid Build Coastguard Worker   return val;
60*387f9dfdSAndroid Build Coastguard Worker }
61*387f9dfdSAndroid Build Coastguard Worker 
read_cpu_range(std::string path)62*387f9dfdSAndroid Build Coastguard Worker std::vector<int> read_cpu_range(std::string path) {
63*387f9dfdSAndroid Build Coastguard Worker   std::ifstream cpus_range_stream { path };
64*387f9dfdSAndroid Build Coastguard Worker   std::vector<int> cpus;
65*387f9dfdSAndroid Build Coastguard Worker   std::string cpu_range;
66*387f9dfdSAndroid Build Coastguard Worker 
67*387f9dfdSAndroid Build Coastguard Worker   while (std::getline(cpus_range_stream, cpu_range, ',')) {
68*387f9dfdSAndroid Build Coastguard Worker     std::size_t rangeop = cpu_range.find('-');
69*387f9dfdSAndroid Build Coastguard Worker     if (rangeop == std::string::npos) {
70*387f9dfdSAndroid Build Coastguard Worker       cpus.push_back(std::stoi(cpu_range));
71*387f9dfdSAndroid Build Coastguard Worker     }
72*387f9dfdSAndroid Build Coastguard Worker     else {
73*387f9dfdSAndroid Build Coastguard Worker       int start = std::stoi(cpu_range.substr(0, rangeop));
74*387f9dfdSAndroid Build Coastguard Worker       int end = std::stoi(cpu_range.substr(rangeop + 1));
75*387f9dfdSAndroid Build Coastguard Worker       for (int i = start; i <= end; i++)
76*387f9dfdSAndroid Build Coastguard Worker         cpus.push_back(i);
77*387f9dfdSAndroid Build Coastguard Worker     }
78*387f9dfdSAndroid Build Coastguard Worker   }
79*387f9dfdSAndroid Build Coastguard Worker   return cpus;
80*387f9dfdSAndroid Build Coastguard Worker }
81*387f9dfdSAndroid Build Coastguard Worker 
get_online_cpus()82*387f9dfdSAndroid Build Coastguard Worker std::vector<int> get_online_cpus() {
83*387f9dfdSAndroid Build Coastguard Worker   return read_cpu_range("/sys/devices/system/cpu/online");
84*387f9dfdSAndroid Build Coastguard Worker }
85*387f9dfdSAndroid Build Coastguard Worker 
get_possible_cpus()86*387f9dfdSAndroid Build Coastguard Worker std::vector<int> get_possible_cpus() {
87*387f9dfdSAndroid Build Coastguard Worker   return read_cpu_range("/sys/devices/system/cpu/possible");
88*387f9dfdSAndroid Build Coastguard Worker }
89*387f9dfdSAndroid Build Coastguard Worker 
get_pid_exe(pid_t pid)90*387f9dfdSAndroid Build Coastguard Worker std::string get_pid_exe(pid_t pid) {
91*387f9dfdSAndroid Build Coastguard Worker   char exe_path[4096];
92*387f9dfdSAndroid Build Coastguard Worker   int res;
93*387f9dfdSAndroid Build Coastguard Worker 
94*387f9dfdSAndroid Build Coastguard Worker   std::string exe_link = tfm::format("/proc/%d/exe", pid);
95*387f9dfdSAndroid Build Coastguard Worker   res = readlink(exe_link.c_str(), exe_path, sizeof(exe_path));
96*387f9dfdSAndroid Build Coastguard Worker   if (res == -1)
97*387f9dfdSAndroid Build Coastguard Worker     return "";
98*387f9dfdSAndroid Build Coastguard Worker   if (res >= static_cast<int>(sizeof(exe_path)))
99*387f9dfdSAndroid Build Coastguard Worker     res = sizeof(exe_path) - 1;
100*387f9dfdSAndroid Build Coastguard Worker   exe_path[res] = '\0';
101*387f9dfdSAndroid Build Coastguard Worker   return std::string(exe_path);
102*387f9dfdSAndroid Build Coastguard Worker }
103*387f9dfdSAndroid Build Coastguard Worker 
104*387f9dfdSAndroid Build Coastguard Worker enum class field_kind_t {
105*387f9dfdSAndroid Build Coastguard Worker     common,
106*387f9dfdSAndroid Build Coastguard Worker     data_loc,
107*387f9dfdSAndroid Build Coastguard Worker     regular,
108*387f9dfdSAndroid Build Coastguard Worker     invalid,
109*387f9dfdSAndroid Build Coastguard Worker     pad,
110*387f9dfdSAndroid Build Coastguard Worker };
111*387f9dfdSAndroid Build Coastguard Worker 
_get_field_kind(std::string const & line,std::string & field_type,std::string & field_name,int * last_offset)112*387f9dfdSAndroid Build Coastguard Worker static inline field_kind_t _get_field_kind(std::string const& line,
113*387f9dfdSAndroid Build Coastguard Worker                                            std::string& field_type,
114*387f9dfdSAndroid Build Coastguard Worker                                            std::string& field_name,
115*387f9dfdSAndroid Build Coastguard Worker                                            int *last_offset) {
116*387f9dfdSAndroid Build Coastguard Worker   auto field_pos = line.find("field:");
117*387f9dfdSAndroid Build Coastguard Worker   if (field_pos == std::string::npos)
118*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
119*387f9dfdSAndroid Build Coastguard Worker 
120*387f9dfdSAndroid Build Coastguard Worker   auto field_semi_pos = line.find(';', field_pos);
121*387f9dfdSAndroid Build Coastguard Worker   if (field_semi_pos == std::string::npos)
122*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
123*387f9dfdSAndroid Build Coastguard Worker 
124*387f9dfdSAndroid Build Coastguard Worker   auto offset_pos = line.find("offset:", field_semi_pos);
125*387f9dfdSAndroid Build Coastguard Worker   if (offset_pos == std::string::npos)
126*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
127*387f9dfdSAndroid Build Coastguard Worker 
128*387f9dfdSAndroid Build Coastguard Worker   auto semi_pos = line.find(';', offset_pos);
129*387f9dfdSAndroid Build Coastguard Worker   if (semi_pos == std::string::npos)
130*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
131*387f9dfdSAndroid Build Coastguard Worker 
132*387f9dfdSAndroid Build Coastguard Worker   auto offset_str = line.substr(offset_pos + 7,
133*387f9dfdSAndroid Build Coastguard Worker                               semi_pos - offset_pos - 7);
134*387f9dfdSAndroid Build Coastguard Worker   int offset = std::stoi(offset_str, nullptr);
135*387f9dfdSAndroid Build Coastguard Worker 
136*387f9dfdSAndroid Build Coastguard Worker   auto size_pos = line.find("size:", semi_pos);
137*387f9dfdSAndroid Build Coastguard Worker   if (size_pos == std::string::npos)
138*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
139*387f9dfdSAndroid Build Coastguard Worker 
140*387f9dfdSAndroid Build Coastguard Worker   semi_pos = line.find(';', size_pos);
141*387f9dfdSAndroid Build Coastguard Worker   if (semi_pos == std::string::npos)
142*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
143*387f9dfdSAndroid Build Coastguard Worker 
144*387f9dfdSAndroid Build Coastguard Worker   auto size_str = line.substr(size_pos + 5,
145*387f9dfdSAndroid Build Coastguard Worker                               semi_pos - size_pos - 5);
146*387f9dfdSAndroid Build Coastguard Worker   int size = std::stoi(size_str, nullptr);
147*387f9dfdSAndroid Build Coastguard Worker 
148*387f9dfdSAndroid Build Coastguard Worker   if (*last_offset < offset) {
149*387f9dfdSAndroid Build Coastguard Worker     *last_offset += 1;
150*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::pad;
151*387f9dfdSAndroid Build Coastguard Worker   }
152*387f9dfdSAndroid Build Coastguard Worker 
153*387f9dfdSAndroid Build Coastguard Worker   *last_offset = offset + size;
154*387f9dfdSAndroid Build Coastguard Worker 
155*387f9dfdSAndroid Build Coastguard Worker   auto field = line.substr(field_pos + 6/*"field:"*/,
156*387f9dfdSAndroid Build Coastguard Worker                            field_semi_pos - field_pos - 6);
157*387f9dfdSAndroid Build Coastguard Worker   auto pos = field.find_last_of("\t ");
158*387f9dfdSAndroid Build Coastguard Worker   if (pos == std::string::npos)
159*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::invalid;
160*387f9dfdSAndroid Build Coastguard Worker 
161*387f9dfdSAndroid Build Coastguard Worker   field_type = field.substr(0, pos);
162*387f9dfdSAndroid Build Coastguard Worker   field_name = field.substr(pos + 1);
163*387f9dfdSAndroid Build Coastguard Worker   if (field_type.find("__data_loc") != std::string::npos)
164*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::data_loc;
165*387f9dfdSAndroid Build Coastguard Worker   if (field_name.find("common_") == 0)
166*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::common;
167*387f9dfdSAndroid Build Coastguard Worker 
168*387f9dfdSAndroid Build Coastguard Worker   // We may have `char comm[TASK_COMM_LEN];` on kernel v5.18+
169*387f9dfdSAndroid Build Coastguard Worker   // Let's replace `TASK_COMM_LEN` with value extracted from BTF
170*387f9dfdSAndroid Build Coastguard Worker   if (field_name.find("[") != std::string::npos) {
171*387f9dfdSAndroid Build Coastguard Worker     auto pos1 = field_name.find("[");
172*387f9dfdSAndroid Build Coastguard Worker     auto pos2 = field_name.find("]");
173*387f9dfdSAndroid Build Coastguard Worker     auto dim = field_name.substr(pos1 + 1, pos2 - pos1 - 1);
174*387f9dfdSAndroid Build Coastguard Worker     if (!dim.empty() && !isdigit(dim[0])) {
175*387f9dfdSAndroid Build Coastguard Worker       auto v = get_enum_val_from_btf(dim.c_str());
176*387f9dfdSAndroid Build Coastguard Worker       if (v)
177*387f9dfdSAndroid Build Coastguard Worker         dim = std::to_string(*v);
178*387f9dfdSAndroid Build Coastguard Worker       field_name.replace(pos1 + 1, pos2 - pos1 - 1, dim, 0);
179*387f9dfdSAndroid Build Coastguard Worker     }
180*387f9dfdSAndroid Build Coastguard Worker     return field_kind_t::regular;
181*387f9dfdSAndroid Build Coastguard Worker   }
182*387f9dfdSAndroid Build Coastguard Worker 
183*387f9dfdSAndroid Build Coastguard Worker   // adjust the field_type based on the size of field
184*387f9dfdSAndroid Build Coastguard Worker   // otherwise, incorrect value may be retrieved for big endian
185*387f9dfdSAndroid Build Coastguard Worker   // and the field may have incorrect structure offset.
186*387f9dfdSAndroid Build Coastguard Worker   if (size == 2) {
187*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "char" || field_type == "int8_t")
188*387f9dfdSAndroid Build Coastguard Worker       field_type = "s16";
189*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "unsigned char" || field_type == "uint8_t")
190*387f9dfdSAndroid Build Coastguard Worker       field_type = "u16";
191*387f9dfdSAndroid Build Coastguard Worker   } else if (size == 4) {
192*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "char" || field_type == "short" ||
193*387f9dfdSAndroid Build Coastguard Worker         field_type == "int8_t" || field_type == "int16_t")
194*387f9dfdSAndroid Build Coastguard Worker       field_type = "s32";
195*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "unsigned char" || field_type == "unsigned short" ||
196*387f9dfdSAndroid Build Coastguard Worker         field_type == "uint8_t" || field_type == "uint16_t")
197*387f9dfdSAndroid Build Coastguard Worker       field_type = "u32";
198*387f9dfdSAndroid Build Coastguard Worker   } else if (size == 8) {
199*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "char" || field_type == "short" || field_type == "int" ||
200*387f9dfdSAndroid Build Coastguard Worker         field_type == "int8_t" || field_type == "int16_t" ||
201*387f9dfdSAndroid Build Coastguard Worker         field_type == "int32_t" || field_type == "pid_t")
202*387f9dfdSAndroid Build Coastguard Worker       field_type = "s64";
203*387f9dfdSAndroid Build Coastguard Worker     if (field_type == "unsigned char" || field_type == "unsigned short" ||
204*387f9dfdSAndroid Build Coastguard Worker         field_type == "unsigned int" || field_type == "uint8_t" ||
205*387f9dfdSAndroid Build Coastguard Worker         field_type == "uint16_t" || field_type == "uint32_t" ||
206*387f9dfdSAndroid Build Coastguard Worker         field_type == "unsigned" || field_type == "u32" ||
207*387f9dfdSAndroid Build Coastguard Worker         field_type == "uid_t" || field_type == "gid_t")
208*387f9dfdSAndroid Build Coastguard Worker       field_type = "u64";
209*387f9dfdSAndroid Build Coastguard Worker   }
210*387f9dfdSAndroid Build Coastguard Worker 
211*387f9dfdSAndroid Build Coastguard Worker   return field_kind_t::regular;
212*387f9dfdSAndroid Build Coastguard Worker }
213*387f9dfdSAndroid Build Coastguard Worker 
214*387f9dfdSAndroid Build Coastguard Worker #define DEBUGFS_TRACEFS "/sys/kernel/debug/tracing"
215*387f9dfdSAndroid Build Coastguard Worker #define TRACEFS "/sys/kernel/tracing"
216*387f9dfdSAndroid Build Coastguard Worker 
tracefs_path()217*387f9dfdSAndroid Build Coastguard Worker std::string tracefs_path() {
218*387f9dfdSAndroid Build Coastguard Worker   static bool use_debugfs = access(DEBUGFS_TRACEFS, F_OK) == 0;
219*387f9dfdSAndroid Build Coastguard Worker   return use_debugfs ? DEBUGFS_TRACEFS : TRACEFS;
220*387f9dfdSAndroid Build Coastguard Worker }
221*387f9dfdSAndroid Build Coastguard Worker 
tracepoint_format_file(std::string const & category,std::string const & event)222*387f9dfdSAndroid Build Coastguard Worker std::string tracepoint_format_file(std::string const& category,
223*387f9dfdSAndroid Build Coastguard Worker                                    std::string const& event) {
224*387f9dfdSAndroid Build Coastguard Worker   return tracefs_path() + "/events/" + category + "/" + event + "/format";
225*387f9dfdSAndroid Build Coastguard Worker }
226*387f9dfdSAndroid Build Coastguard Worker 
parse_tracepoint(std::istream & input,std::string const & category,std::string const & event)227*387f9dfdSAndroid Build Coastguard Worker std::string parse_tracepoint(std::istream &input, std::string const& category,
228*387f9dfdSAndroid Build Coastguard Worker                              std::string const& event) {
229*387f9dfdSAndroid Build Coastguard Worker   std::string tp_struct = "struct tracepoint__" + category + "__" + event + " {\n";
230*387f9dfdSAndroid Build Coastguard Worker   tp_struct += "\tu64 __do_not_use__;\n";
231*387f9dfdSAndroid Build Coastguard Worker   int last_offset = 0, common_offset = 8;
232*387f9dfdSAndroid Build Coastguard Worker   for (std::string line; getline(input, line); ) {
233*387f9dfdSAndroid Build Coastguard Worker     std::string field_type, field_name;
234*387f9dfdSAndroid Build Coastguard Worker     field_kind_t kind;
235*387f9dfdSAndroid Build Coastguard Worker 
236*387f9dfdSAndroid Build Coastguard Worker     do {
237*387f9dfdSAndroid Build Coastguard Worker       kind = _get_field_kind(line, field_type, field_name, &last_offset);
238*387f9dfdSAndroid Build Coastguard Worker 
239*387f9dfdSAndroid Build Coastguard Worker       switch (kind) {
240*387f9dfdSAndroid Build Coastguard Worker       case field_kind_t::invalid:
241*387f9dfdSAndroid Build Coastguard Worker           continue;
242*387f9dfdSAndroid Build Coastguard Worker       case field_kind_t::common:
243*387f9dfdSAndroid Build Coastguard Worker             for (;common_offset < last_offset; common_offset++)
244*387f9dfdSAndroid Build Coastguard Worker             {
245*387f9dfdSAndroid Build Coastguard Worker               tp_struct += "\tchar __do_not_use__" + std::to_string(common_offset) + ";\n";
246*387f9dfdSAndroid Build Coastguard Worker             }
247*387f9dfdSAndroid Build Coastguard Worker           continue;
248*387f9dfdSAndroid Build Coastguard Worker       case field_kind_t::data_loc:
249*387f9dfdSAndroid Build Coastguard Worker           tp_struct += "\tint data_loc_" + field_name + ";\n";
250*387f9dfdSAndroid Build Coastguard Worker           break;
251*387f9dfdSAndroid Build Coastguard Worker       case field_kind_t::regular:
252*387f9dfdSAndroid Build Coastguard Worker           tp_struct += "\t" + field_type + " " + field_name + ";\n";
253*387f9dfdSAndroid Build Coastguard Worker           break;
254*387f9dfdSAndroid Build Coastguard Worker       case field_kind_t::pad:
255*387f9dfdSAndroid Build Coastguard Worker           tp_struct += "\tchar __pad_" + std::to_string(last_offset - 1) + ";\n";
256*387f9dfdSAndroid Build Coastguard Worker           break;
257*387f9dfdSAndroid Build Coastguard Worker       }
258*387f9dfdSAndroid Build Coastguard Worker     } while (kind == field_kind_t::pad);
259*387f9dfdSAndroid Build Coastguard Worker   }
260*387f9dfdSAndroid Build Coastguard Worker 
261*387f9dfdSAndroid Build Coastguard Worker   tp_struct += "};\n";
262*387f9dfdSAndroid Build Coastguard Worker   return tp_struct;
263*387f9dfdSAndroid Build Coastguard Worker }
264*387f9dfdSAndroid Build Coastguard Worker } // namespace ebpf
265