blob: e5dc4eeb1bd037aeebd96b62e8cb3fc5c78d656a [file] [log] [blame]
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +00001/*
Elliott Hughes77c3ff82017-09-08 17:11:00 -07002 * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
Elliott Hughesd35df492017-02-15 15:19:05 -08003 * Copyright (c) 2017 Quentin Monnet <quentin.monnet@6wind.com>
Elliott Hughes28e98bc2018-06-14 16:59:04 -07004 * Copyright (c) 2015-2018 The strace developers.
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +00005 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "defs.h"
Elliott Hughes77c3ff82017-09-08 17:11:00 -070031#include "print_fields.h"
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000032
33#ifdef HAVE_LINUX_BPF_H
34# include <linux/bpf.h>
35#endif
Elliott Hughes03a418e2018-06-15 13:11:40 -070036#include <linux/filter.h>
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000037
Elliott Hughes28e98bc2018-06-14 16:59:04 -070038#include "bpf_attr.h"
39
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000040#include "xlat/bpf_commands.h"
Elliott Hughes28e98bc2018-06-14 16:59:04 -070041#include "xlat/bpf_file_mode_flags.h"
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000042#include "xlat/bpf_map_types.h"
Elliott Hughes77c3ff82017-09-08 17:11:00 -070043#include "xlat/bpf_map_flags.h"
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000044#include "xlat/bpf_prog_types.h"
Elliott Hughes77c3ff82017-09-08 17:11:00 -070045#include "xlat/bpf_prog_flags.h"
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000046#include "xlat/bpf_map_update_elem_flags.h"
Elliott Hughesd35df492017-02-15 15:19:05 -080047#include "xlat/bpf_attach_type.h"
Elliott Hughes39bac052017-05-25 16:56:11 -070048#include "xlat/bpf_attach_flags.h"
Elliott Hughes03a418e2018-06-15 13:11:40 -070049#include "xlat/bpf_query_flags.h"
50#include "xlat/ebpf_regs.h"
51#include "xlat/numa_node.h"
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000052
Elliott Hughes77c3ff82017-09-08 17:11:00 -070053#define DECL_BPF_CMD_DECODER(bpf_cmd_decoder) \
54int \
55bpf_cmd_decoder(struct tcb *const tcp, \
56 const kernel_ulong_t addr, \
57 const unsigned int size, \
58 void *const data) \
59/* End of DECL_BPF_CMD_DECODER definition. */
60
Elliott Hughes28e98bc2018-06-14 16:59:04 -070061#define BEGIN_BPF_CMD_DECODER(bpf_cmd) \
62 static DECL_BPF_CMD_DECODER(decode_ ## bpf_cmd) \
63 { \
64 struct bpf_cmd ## _struct attr = {}; \
65 const size_t attr_size = bpf_cmd ## _struct_size; \
66 const unsigned int len = MIN(size, attr_size); \
67 memcpy(&attr, data, len); \
68 do { \
69/* End of BEGIN_BPF_CMD_DECODER definition. */
70
71#define END_BPF_CMD_DECODER(rval) \
72 decode_attr_extra_data(tcp, data, size, attr_size); \
73 } while (0); \
74 tprints("}"); \
75 return (rval); \
76 } \
77/* End of END_BPF_CMD_DECODER definition. */
Elliott Hughes77c3ff82017-09-08 17:11:00 -070078
79#define BPF_CMD_ENTRY(bpf_cmd) \
80 [bpf_cmd] = decode_ ## bpf_cmd
81
82typedef DECL_BPF_CMD_DECODER((*bpf_cmd_decoder_t));
83
Elliott Hughes28e98bc2018-06-14 16:59:04 -070084/*
85 * A note about bpf syscall decoder: it doesn't perform any size sanity checks,
86 * so even if it leads to partial copying of one of the fields, the command
87 * handler will still use the (partially-copied-from-userspace, partially
88 * zeroed) field value. That's why we stop decoding and check for known sizes
89 * that correspond to released versions of the structure used by the specific
90 * command - it looks like the most sensible way to parse this insanity.
91 */
92
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +000093static int
Elliott Hughes77c3ff82017-09-08 17:11:00 -070094decode_attr_extra_data(struct tcb *const tcp,
95 const char *data,
96 unsigned int size,
97 const size_t attr_size)
98{
99 if (size <= attr_size)
100 return 0;
101
102 data += attr_size;
103 size -= attr_size;
104
105 unsigned int i;
106 for (i = 0; i < size; ++i) {
107 if (data[i]) {
108 tprints(", ");
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700109 if (abbrev(tcp)) {
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700110 tprints("...");
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700111 } else {
112 tprintf("/* bytes %zu..%zu */ ",
113 attr_size, attr_size + size - 1);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700114 print_quoted_string(data, size,
115 QUOTE_FORCE_HEX);
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700116 }
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700117 return RVAL_DECODED;
118 }
119 }
120
121 return 0;
122}
123
Elliott Hughes03a418e2018-06-15 13:11:40 -0700124struct ebpf_insn {
125 uint8_t code;
126 uint8_t dst_reg:4;
127 uint8_t src_reg:4;
128 int16_t off;
129 int32_t imm;
130};
131
132struct ebpf_insns_data {
133 unsigned int count;
134};
135
136static bool
137print_ebpf_insn(struct tcb * const tcp, void * const elem_buf,
138 const size_t elem_size, void * const data)
139{
140 struct ebpf_insns_data *eid = data;
141 struct ebpf_insn *insn = elem_buf;
142
143 if (eid->count++ >= BPF_MAXINSNS) {
144 tprints("...");
145 return false;
146 }
147
148 tprints("{code=");
149 print_bpf_filter_code(insn->code, true);
150
151 /* We can't use PRINT_FIELD_XVAL on bit fields */
152 tprints(", dst_reg=");
153 printxval_index(ebpf_regs, insn->dst_reg, "BPF_REG_???");
154 tprints(", src_reg=");
155 printxval_index(ebpf_regs, insn->src_reg, "BPF_REG_???");
156
157 PRINT_FIELD_D(", ", *insn, off);
158 PRINT_FIELD_X(", ", *insn, imm);
159 tprints("}");
160
161 return true;
162}
163
164static void
165print_ebpf_prog(struct tcb *const tcp, const uint64_t addr, const uint32_t len)
166{
167 print_big_u64_addr(addr);
168 if (abbrev(tcp)) {
169 printaddr(addr);
170 } else {
171 struct ebpf_insns_data eid = {};
172 struct ebpf_insn insn;
173
174 print_array(tcp, addr, len, &insn, sizeof(insn),
175 tfetch_mem, print_ebpf_insn, &eid);
176 }
177}
178
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700179BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000180{
Elliott Hughes03a418e2018-06-15 13:11:40 -0700181 PRINT_FIELD_XVAL_INDEX("{", attr, map_type, bpf_map_types,
182 "BPF_MAP_TYPE_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700183 PRINT_FIELD_U(", ", attr, key_size);
184 PRINT_FIELD_U(", ", attr, value_size);
185 PRINT_FIELD_U(", ", attr, max_entries);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700186
187 /* map_flags field was added in Linux commit v4.6-rc1~91^2~108^2~6. */
188 if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_flags))
189 break;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700190 PRINT_FIELD_FLAGS(", ", attr, map_flags, bpf_map_flags, "BPF_F_???");
Elliott Hughes03a418e2018-06-15 13:11:40 -0700191
192 /*
193 * inner_map_fd field was added in Linux commit
194 * v4.12-rc1~64^3~373^2~2.
195 */
196 if (len <= offsetof(struct BPF_MAP_CREATE_struct, inner_map_fd))
197 break;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700198 PRINT_FIELD_FD(", ", attr, inner_map_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700199
200 /* numa_node field was added in Linux commit v4.14-rc1~130^2~196^2~1. */
201 if (len <= offsetof(struct BPF_MAP_CREATE_struct, numa_node))
202 break;
203 if (attr.map_flags & BPF_F_NUMA_NODE) {
204 /*
205 * Kernel uses the value of -1 as a designation for "no NUMA
206 * node specified", and even uses NUMA_NO_NODE constant;
207 * however, the constant definition is not a part of UAPI
208 * headers, thus we can't simply print this named constant
209 * instead of the value. Let's force verbose xlat style instead
210 * in order to provide the information for the user while
211 * not hampering the availability to derive the actual value
212 * without the access to the kernel headers.
213 */
214 tprints(", numa_node=");
215 printxvals_ex(attr.numa_node, NULL,
216 XLAT_STYLE_FMT_U | XLAT_STYLE_VERBOSE,
217 numa_node, NULL);
218 }
219
220 /* map_name field was added in Linux commit v4.15-rc1~84^2~605^2~3. */
221 if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_name))
222 break;
223 PRINT_FIELD_CSTRING_SZ(", ", attr, map_name,
224 MIN(sizeof(attr.map_name),
225 len - offsetof(struct BPF_MAP_CREATE_struct,
226 map_name)));
227
228 /*
229 * map_ifindex field was added in Linux commit
230 * v4.16-rc1~123^2~145^2~5^2~8.
231 */
232 if (len <= offsetof(struct BPF_MAP_CREATE_struct, map_ifindex))
233 break;
234 PRINT_FIELD_IFINDEX(", ", attr, map_ifindex);
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000235}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700236END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000237
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700238BEGIN_BPF_CMD_DECODER(BPF_MAP_LOOKUP_ELEM)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700239{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700240 PRINT_FIELD_FD("{", attr, map_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700241 PRINT_FIELD_ADDR64(", ", attr, key);
242 PRINT_FIELD_ADDR64(", ", attr, value);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700243}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700244END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700245
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700246BEGIN_BPF_CMD_DECODER(BPF_MAP_UPDATE_ELEM)
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000247{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700248 PRINT_FIELD_FD("{", attr, map_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700249 PRINT_FIELD_ADDR64(", ", attr, key);
250 PRINT_FIELD_ADDR64(", ", attr, value);
251 PRINT_FIELD_XVAL_INDEX(", ", attr, flags, bpf_map_update_elem_flags,
252 "BPF_???");
Elliott Hughesd35df492017-02-15 15:19:05 -0800253}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700254END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesd35df492017-02-15 15:19:05 -0800255
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700256BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_ELEM)
Elliott Hughesd35df492017-02-15 15:19:05 -0800257{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700258 PRINT_FIELD_FD("{", attr, map_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700259 PRINT_FIELD_ADDR64(", ", attr, key);
Elliott Hughesd35df492017-02-15 15:19:05 -0800260}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700261END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesd35df492017-02-15 15:19:05 -0800262
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700263BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_NEXT_KEY)
Elliott Hughesd35df492017-02-15 15:19:05 -0800264{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700265 PRINT_FIELD_FD("{", attr, map_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700266 PRINT_FIELD_ADDR64(", ", attr, key);
267 PRINT_FIELD_ADDR64(", ", attr, next_key);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700268}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700269END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700270
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700271BEGIN_BPF_CMD_DECODER(BPF_PROG_LOAD)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700272{
Elliott Hughes03a418e2018-06-15 13:11:40 -0700273 PRINT_FIELD_XVAL_INDEX("{", attr, prog_type, bpf_prog_types,
274 "BPF_PROG_TYPE_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700275 PRINT_FIELD_U(", ", attr, insn_cnt);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700276 tprints(", insns=");
277 print_ebpf_prog(tcp, attr.insns, attr.insn_cnt);
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700278
279 tprintf(", license=");
280 print_big_u64_addr(attr.license);
281 printstr(tcp, attr.license);
282
283 /* log_* fields were added in Linux commit v3.18-rc1~52^2~1^2~4. */
284 if (len <= offsetof(struct BPF_PROG_LOAD_struct, log_level))
285 break;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700286 PRINT_FIELD_U(", ", attr, log_level);
287 PRINT_FIELD_U(", ", attr, log_size);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700288 tprintf(", log_buf=");
289 print_big_u64_addr(attr.log_buf);
290 printstr_ex(tcp, attr.log_buf, attr.log_size, QUOTE_0_TERMINATED);
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700291
292 /* kern_version field was added in Linux commit v4.1-rc1~84^2~50. */
293 if (len <= offsetof(struct BPF_PROG_LOAD_struct, kern_version))
294 break;
295 tprintf(", kern_version=KERNEL_VERSION(%u, %u, %u)",
296 attr.kern_version >> 16,
297 (attr.kern_version >> 8) & 0xFF,
298 attr.kern_version & 0xFF);
299
300 /* prog_flags field was added in Linux commit v4.12-rc2~34^2~29^2~2. */
301 if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_flags))
302 break;
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700303 PRINT_FIELD_FLAGS(", ", attr, prog_flags, bpf_prog_flags, "BPF_F_???");
Elliott Hughes03a418e2018-06-15 13:11:40 -0700304
305 /* prog_name field was added in Linux commit v4.15-rc1~84^2~605^2~4. */
306 if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_name))
307 break;
308 PRINT_FIELD_CSTRING_SZ(", ", attr, prog_name,
309 MIN(sizeof(attr.prog_name),
310 len - offsetof(struct BPF_PROG_LOAD_struct,
311 prog_name)));
312
313 /*
314 * prog_ifindex field was added as prog_target_ifindex in Linux commit
315 * v4.15-rc1~84^2~127^2~13 and renamed to its current name in
316 * v4.15-rc1~15^2~5^2~3^2~7.
317 */
318 if (len <= offsetof(struct BPF_PROG_LOAD_struct, prog_ifindex))
319 break;
320 PRINT_FIELD_IFINDEX(", ", attr, prog_ifindex);
321
322 /*
323 * expected_attach_type was added in Linux commit
324 * v4.17-rc1~148^2~19^2^2~8.
325 */
326 if (len <= offsetof(struct BPF_PROG_LOAD_struct, expected_attach_type))
327 break;
328 PRINT_FIELD_XVAL(", ", attr, expected_attach_type, bpf_attach_type,
329 "BPF_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700330}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700331END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700332
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700333BEGIN_BPF_CMD_DECODER(BPF_OBJ_PIN)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700334{
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700335 tprintf("{pathname=");
336 print_big_u64_addr(attr.pathname);
337 printpath(tcp, attr.pathname);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700338
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700339 PRINT_FIELD_FD(", ", attr, bpf_fd, tcp);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700340
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700341 /* file_flags field was added in Linux v4.15-rc1~84^2~384^2~4 */
Elliott Hughes03a418e2018-06-15 13:11:40 -0700342 if (len <= offsetof(struct BPF_OBJ_PIN_struct, file_flags))
343 break;
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700344 PRINT_FIELD_FLAGS(", ", attr, file_flags, bpf_file_mode_flags,
345 "BPF_F_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700346}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700347END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700348
349#define decode_BPF_OBJ_GET decode_BPF_OBJ_PIN
350
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700351BEGIN_BPF_CMD_DECODER(BPF_PROG_ATTACH)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700352{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700353 PRINT_FIELD_FD("{", attr, target_fd, tcp);
354 PRINT_FIELD_FD(", ", attr, attach_bpf_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700355 PRINT_FIELD_XVAL_INDEX(", ", attr, attach_type, bpf_attach_type,
356 "BPF_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700357 PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
358 "BPF_F_???");
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700359}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700360END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700361
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700362BEGIN_BPF_CMD_DECODER(BPF_PROG_DETACH)
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700363{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700364 PRINT_FIELD_FD("{", attr, target_fd, tcp);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700365 PRINT_FIELD_XVAL_INDEX(", ", attr, attach_type, bpf_attach_type,
366 "BPF_???");
Elliott Hughesd35df492017-02-15 15:19:05 -0800367}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700368END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesd35df492017-02-15 15:19:05 -0800369
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700370BEGIN_BPF_CMD_DECODER(BPF_PROG_TEST_RUN)
Elliott Hughesb7556142018-02-20 17:03:16 -0800371{
Elliott Hughesb7556142018-02-20 17:03:16 -0800372 PRINT_FIELD_FD("{test={", attr, prog_fd, tcp);
373 PRINT_FIELD_U(", ", attr, retval);
374 PRINT_FIELD_U(", ", attr, data_size_in);
375 PRINT_FIELD_U(", ", attr, data_size_out);
Elliott Hughes03a418e2018-06-15 13:11:40 -0700376 PRINT_FIELD_ADDR64(", ", attr, data_in);
377 PRINT_FIELD_ADDR64(", ", attr, data_out);
Elliott Hughesb7556142018-02-20 17:03:16 -0800378 PRINT_FIELD_U(", ", attr, repeat);
379 PRINT_FIELD_U(", ", attr, duration);
380 tprints("}");
Elliott Hughesb7556142018-02-20 17:03:16 -0800381}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700382END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesb7556142018-02-20 17:03:16 -0800383
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700384BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_NEXT_ID)
Elliott Hughesb7556142018-02-20 17:03:16 -0800385{
Elliott Hughesb7556142018-02-20 17:03:16 -0800386 PRINT_FIELD_U("{", attr, start_id);
387 PRINT_FIELD_U(", ", attr, next_id);
Elliott Hughesb7556142018-02-20 17:03:16 -0800388
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700389 /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
Elliott Hughes03a418e2018-06-15 13:11:40 -0700390 if (len <= offsetof(struct BPF_PROG_GET_NEXT_ID_struct, open_flags))
391 break;
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700392 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
393 "BPF_F_???");
Elliott Hughesb7556142018-02-20 17:03:16 -0800394}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700395END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesb7556142018-02-20 17:03:16 -0800396
397#define decode_BPF_MAP_GET_NEXT_ID decode_BPF_PROG_GET_NEXT_ID
398
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700399BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_FD_BY_ID)
Elliott Hughesb7556142018-02-20 17:03:16 -0800400{
Elliott Hughesb7556142018-02-20 17:03:16 -0800401 PRINT_FIELD_U("{", attr, prog_id);
402 PRINT_FIELD_U(", ", attr, next_id);
Elliott Hughesb7556142018-02-20 17:03:16 -0800403
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700404 /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
Elliott Hughes03a418e2018-06-15 13:11:40 -0700405 if (len <= offsetof(struct BPF_PROG_GET_FD_BY_ID_struct, open_flags))
406 break;
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700407 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
408 "BPF_F_???");
Elliott Hughesb7556142018-02-20 17:03:16 -0800409}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700410END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesb7556142018-02-20 17:03:16 -0800411
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700412BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_FD_BY_ID)
Elliott Hughesb7556142018-02-20 17:03:16 -0800413{
Elliott Hughesb7556142018-02-20 17:03:16 -0800414 PRINT_FIELD_U("{", attr, map_id);
415 PRINT_FIELD_U(", ", attr, next_id);
Elliott Hughesb7556142018-02-20 17:03:16 -0800416
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700417 /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
Elliott Hughes03a418e2018-06-15 13:11:40 -0700418 if (len <= offsetof(struct BPF_MAP_GET_FD_BY_ID_struct, open_flags))
419 break;
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700420 PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
421 "BPF_F_???");
Elliott Hughesb7556142018-02-20 17:03:16 -0800422}
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700423END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesb7556142018-02-20 17:03:16 -0800424
Elliott Hughes03a418e2018-06-15 13:11:40 -0700425struct obj_get_info_saved;
426typedef void (*print_bpf_obj_info_fn)(struct tcb *,
427 uint32_t bpf_fd,
428 const char *info_buf,
429 uint32_t size,
430 struct obj_get_info_saved *saved);
431
432struct obj_get_info_saved {
433 print_bpf_obj_info_fn print_fn;
434
435 uint32_t info_len;
436
437 uint32_t jited_prog_len;
438 uint32_t xlated_prog_len;
439 uint32_t nr_map_ids;
440};
441
442static void
443print_bpf_map_info(struct tcb * const tcp, uint32_t bpf_fd,
444 const char *info_buf, uint32_t size,
445 struct obj_get_info_saved *saved)
Elliott Hughesb7556142018-02-20 17:03:16 -0800446{
Elliott Hughes03a418e2018-06-15 13:11:40 -0700447 if (entering(tcp))
448 return;
449
450 struct bpf_map_info_struct info = { 0 };
451 const unsigned int len = MIN(size, bpf_map_info_struct_size);
452
453 memcpy(&info, info_buf, len);
454
455 PRINT_FIELD_XVAL("{", info, type, bpf_map_types, "BPF_MAP_TYPE_???");
456 PRINT_FIELD_U(", ", info, id);
457 PRINT_FIELD_U(", ", info, key_size);
458 PRINT_FIELD_U(", ", info, value_size);
459 PRINT_FIELD_U(", ", info, max_entries);
460 PRINT_FIELD_FLAGS(", ", info, map_flags, bpf_map_flags, "BPF_F_???");
461
462 /*
463 * "name" field was introduced by Linux commit v4.15-rc1~84^2~605^2~3.
464 */
465 if (len <= offsetof(struct bpf_map_info_struct, name))
466 goto print_bpf_map_info_end;
467 PRINT_FIELD_CSTRING(", ", info, name);
468
469 /*
470 * ifindex, netns_dev, and netns_ino fields were introduced
471 * by Linux commit v4.16-rc1~123^2~109^2~5^2~4.
472 */
473 if (len <= offsetof(struct bpf_map_info_struct, ifindex))
474 goto print_bpf_map_info_end;
475 PRINT_FIELD_IFINDEX(", ", info, ifindex);
476 PRINT_FIELD_DEV(", ", info, netns_dev);
477 PRINT_FIELD_U(", ", info, netns_ino);
478
479 decode_attr_extra_data(tcp, info_buf, size, bpf_map_info_struct_size);
480
481print_bpf_map_info_end:
Elliott Hughesb7556142018-02-20 17:03:16 -0800482 tprints("}");
Elliott Hughesb7556142018-02-20 17:03:16 -0800483}
Elliott Hughes03a418e2018-06-15 13:11:40 -0700484
485static void
486print_bpf_prog_info(struct tcb * const tcp, uint32_t bpf_fd,
487 const char *info_buf, uint32_t size,
488 struct obj_get_info_saved *saved)
489{
490 struct bpf_prog_info_struct info = { 0 };
491 const unsigned int len = MIN(size, bpf_prog_info_struct_size);
492 uint64_t map_id_buf;
493
494 memcpy(&info, info_buf, len);
495
496 if (entering(tcp)) {
497 saved->jited_prog_len = info.jited_prog_len;
498 saved->xlated_prog_len = info.xlated_prog_len;
499 saved->nr_map_ids = info.nr_map_ids;
500
501 return;
502 }
503
504 PRINT_FIELD_XVAL("{", info, type, bpf_prog_types, "BPF_PROG_TYPE_???");
505 PRINT_FIELD_U(", ", info, id);
506 PRINT_FIELD_HEX_ARRAY(", ", info, tag);
507
508 tprints(", jited_prog_len=");
509 if (saved->jited_prog_len != info.jited_prog_len)
510 tprintf("%" PRIu32 " => ", saved->jited_prog_len);
511 tprintf("%" PRIu32, info.jited_prog_len);
512
513 tprints(", jited_prog_insns=");
514 print_big_u64_addr(info.jited_prog_insns);
515 printstr_ex(tcp, info.jited_prog_insns, info.jited_prog_len,
516 QUOTE_FORCE_HEX);
517
518 tprints(", xlated_prog_len=");
519 if (saved->xlated_prog_len != info.xlated_prog_len)
520 tprintf("%" PRIu32 " => ", saved->xlated_prog_len);
521 tprintf("%" PRIu32, info.xlated_prog_len);
522
523 tprints(", xlated_prog_insns=");
524 print_ebpf_prog(tcp, info.xlated_prog_insns,
525 MIN(saved->xlated_prog_len, info.xlated_prog_len) / 8);
526
527 /*
528 * load_time, created_by_uid, nr_map_ids, map_ids, and name fields
529 * were introduced by Linux commit v4.15-rc1~84^2~605^2~4.
530 */
531 if (len <= offsetof(struct bpf_prog_info_struct, load_time))
532 goto print_bpf_prog_info_end;
533 PRINT_FIELD_U(", ", info, load_time);
534 PRINT_FIELD_UID(", ", info, created_by_uid);
535
536 tprints(", nr_map_ids=");
537 if (saved->nr_map_ids != info.nr_map_ids)
538 tprintf("%" PRIu32 " => ", saved->nr_map_ids);
539 tprintf("%" PRIu32, info.nr_map_ids);
540
541 tprints(", map_ids=");
542 print_big_u64_addr(info.map_ids);
543 print_array(tcp, info.map_ids, MIN(saved->nr_map_ids, info.nr_map_ids),
544 &map_id_buf, sizeof(map_id_buf),
545 tfetch_mem, print_uint32_array_member, 0);
546
547 PRINT_FIELD_CSTRING(", ", info, name);
548
549 /*
550 * ifindex, netns_dev, and netns_ino fields were introduced
551 * by Linux commit v4.16-rc1~123^2~227^2~5^2~2.
552 */
553 if (len <= offsetof(struct bpf_prog_info_struct, ifindex))
554 goto print_bpf_prog_info_end;
555 PRINT_FIELD_IFINDEX(", ", info, ifindex);
556 PRINT_FIELD_DEV(", ", info, netns_dev);
557 PRINT_FIELD_U(", ", info, netns_ino);
558
559 decode_attr_extra_data(tcp, info_buf, size, bpf_prog_info_struct_size);
560
561print_bpf_prog_info_end:
562 tprints("}");
563}
564
565static const char *
566fetch_bpf_obj_info(struct tcb * const tcp, uint64_t info, uint32_t size)
567{
568 static char *info_buf;
569
570 if (!info_buf)
571 info_buf = xmalloc(get_pagesize());
572
573 memset(info_buf, 0, get_pagesize());
574
575 if (size > 0 && size <= get_pagesize()
576 && !umoven(tcp, info, size, info_buf))
577 return info_buf;
578
579 return NULL;
580}
581
582static void
583print_bpf_obj_info_addr(struct tcb * const tcp, uint64_t addr)
584{
585 if (exiting(tcp))
586 printaddr64(addr);
587}
588
589static void
590print_bpf_obj_info(struct tcb * const tcp, uint32_t bpf_fd, uint64_t info,
591 uint32_t size, struct obj_get_info_saved *saved)
592{
593 if (abbrev(tcp)) {
594 print_bpf_obj_info_addr(tcp, info);
595 return;
596 }
597
598 static struct {
599 const char *id;
600 print_bpf_obj_info_fn print_fn;
601 } obj_printers[] = {
602 { "anon_inode:bpf-map", print_bpf_map_info },
603 { "anon_inode:bpf-prog", print_bpf_prog_info }
604 };
605
606 if (entering(tcp)) {
607 char path[PATH_MAX + 1];
608
609 if (getfdpath(tcp, bpf_fd, path, sizeof(path)) > 0) {
610 for (size_t i = 0; i < ARRAY_SIZE(obj_printers); ++i) {
611 if (!strcmp(path, obj_printers[i].id)) {
612 saved->print_fn =
613 obj_printers[i].print_fn;
614 break;
615 }
616 }
617 }
618 }
619
620 if (!saved || !saved->print_fn) {
621 print_bpf_obj_info_addr(tcp, info);
622 return;
623 }
624
625 const char *info_buf = fetch_bpf_obj_info(tcp, info, size);
626
627 if (info_buf)
628 saved->print_fn(tcp, bpf_fd, info_buf, size, saved);
629 else
630 print_bpf_obj_info_addr(tcp, info);
631}
632
633BEGIN_BPF_CMD_DECODER(BPF_OBJ_GET_INFO_BY_FD)
634{
635 struct obj_get_info_saved *saved;
636
637 if (entering(tcp)) {
638 saved = xcalloc(1, sizeof(*saved));
639 saved->info_len = attr.info_len;
640 set_tcb_priv_data(tcp, saved, free);
641
642 PRINT_FIELD_FD("{info={", attr, bpf_fd, tcp);
643 PRINT_FIELD_U(", ", attr, info_len);
644 } else {
645 saved = get_tcb_priv_data(tcp);
646
647 if (saved && (saved->info_len != attr.info_len))
648 tprintf(" => %u", attr.info_len);
649
650 tprintf(", info=");
651 }
652
653 print_bpf_obj_info(tcp, attr.bpf_fd, attr.info, attr.info_len, saved);
654
655 if (entering(tcp))
656 return 0;
657
658 tprints("}");
659}
660END_BPF_CMD_DECODER(RVAL_DECODED)
661
662BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)
663{
664 uint32_t prog_id_buf;
665
666 if (entering(tcp)) {
667 PRINT_FIELD_FD("{query={", attr, target_fd, tcp);
668 PRINT_FIELD_XVAL_INDEX(", ", attr, attach_type, bpf_attach_type,
669 "BPF_???");
670 PRINT_FIELD_FLAGS(", ", attr, query_flags, bpf_query_flags,
671 "BPF_F_QUERY_???");
672 PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
673 "BPF_F_???");
674
675 tprints(", prog_ids=");
676
677 set_tcb_priv_ulong(tcp, attr.prog_cnt);
678
679 return 0;
680 }
681
682 print_big_u64_addr(attr.prog_ids);
683 print_array(tcp, attr.prog_ids, attr.prog_cnt, &prog_id_buf,
684 sizeof(prog_id_buf), tfetch_mem,
685 print_uint32_array_member, 0);
686
687 tprints(", prog_cnt=");
688 const uint32_t prog_cnt_entering = get_tcb_priv_ulong(tcp);
689 if (prog_cnt_entering != attr.prog_cnt)
690 tprintf("%" PRIu32 " => ", prog_cnt_entering);
691 tprintf("%" PRIu32, attr.prog_cnt);
692 tprints("}");
693}
694END_BPF_CMD_DECODER(RVAL_DECODED)
695
696BEGIN_BPF_CMD_DECODER(BPF_RAW_TRACEPOINT_OPEN)
697{
698 enum { TP_NAME_SIZE = 128 };
699
700 tprintf("{raw_tracepoint={name=");
701 print_big_u64_addr(attr.name);
702 printstr_ex(tcp, attr.name, TP_NAME_SIZE, QUOTE_0_TERMINATED);
703
704 PRINT_FIELD_FD(", ", attr, prog_fd, tcp);
705
706 tprints("}");
707}
708END_BPF_CMD_DECODER(RVAL_DECODED)
Elliott Hughesb7556142018-02-20 17:03:16 -0800709
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000710SYS_FUNC(bpf)
711{
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700712 static const bpf_cmd_decoder_t bpf_cmd_decoders[] = {
713 BPF_CMD_ENTRY(BPF_MAP_CREATE),
714 BPF_CMD_ENTRY(BPF_MAP_LOOKUP_ELEM),
715 BPF_CMD_ENTRY(BPF_MAP_UPDATE_ELEM),
716 BPF_CMD_ENTRY(BPF_MAP_DELETE_ELEM),
717 BPF_CMD_ENTRY(BPF_MAP_GET_NEXT_KEY),
718 BPF_CMD_ENTRY(BPF_PROG_LOAD),
719 BPF_CMD_ENTRY(BPF_OBJ_PIN),
720 BPF_CMD_ENTRY(BPF_OBJ_GET),
721 BPF_CMD_ENTRY(BPF_PROG_ATTACH),
722 BPF_CMD_ENTRY(BPF_PROG_DETACH),
Elliott Hughesb7556142018-02-20 17:03:16 -0800723 BPF_CMD_ENTRY(BPF_PROG_TEST_RUN),
724 BPF_CMD_ENTRY(BPF_PROG_GET_NEXT_ID),
725 BPF_CMD_ENTRY(BPF_MAP_GET_NEXT_ID),
726 BPF_CMD_ENTRY(BPF_PROG_GET_FD_BY_ID),
727 BPF_CMD_ENTRY(BPF_MAP_GET_FD_BY_ID),
728 BPF_CMD_ENTRY(BPF_OBJ_GET_INFO_BY_FD),
Elliott Hughes03a418e2018-06-15 13:11:40 -0700729 BPF_CMD_ENTRY(BPF_PROG_QUERY),
730 BPF_CMD_ENTRY(BPF_RAW_TRACEPOINT_OPEN),
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700731 };
732
Elliott Hughesd35df492017-02-15 15:19:05 -0800733 const unsigned int cmd = tcp->u_arg[0];
734 const kernel_ulong_t addr = tcp->u_arg[1];
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000735 const unsigned int size = tcp->u_arg[2];
Elliott Hughes03a418e2018-06-15 13:11:40 -0700736 int rc = RVAL_DECODED;
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000737
738 if (entering(tcp)) {
Elliott Hughes03a418e2018-06-15 13:11:40 -0700739 printxval_index(bpf_commands, cmd, "BPF_???");
740 tprints(", ");
741 }
742
743 if (size > 0
744 && size <= get_pagesize()
745 && cmd < ARRAY_SIZE(bpf_cmd_decoders)
746 && bpf_cmd_decoders[cmd]) {
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700747 static char *buf;
748
Elliott Hughes28e98bc2018-06-14 16:59:04 -0700749 if (!buf)
750 buf = xmalloc(get_pagesize());
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700751
Elliott Hughes03a418e2018-06-15 13:11:40 -0700752 if (!umoven_or_printaddr_ignore_syserror(tcp, addr, size, buf))
753 rc = bpf_cmd_decoders[cmd](tcp, addr, size, buf);
Elliott Hughes77c3ff82017-09-08 17:11:00 -0700754 } else {
Elliott Hughes03a418e2018-06-15 13:11:40 -0700755 printaddr(addr);
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000756 }
757
Elliott Hughes03a418e2018-06-15 13:11:40 -0700758 if (exiting(tcp) || (rc & RVAL_DECODED))
Dmitry V. Levinddb53dd2015-07-25 23:55:51 +0000759 tprintf(", %u", size);
760
761 return rc;
762}