]> granicus.if.org Git - strace/blob - bpf.c
rtnl_link: use ARRSZ_PAIR where appropriate
[strace] / bpf.c
1 /*
2  * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2017 Quentin Monnet <quentin.monnet@6wind.com>
4  * Copyright (c) 2015-2018 The strace developers.
5  * 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"
31 #include "print_fields.h"
32
33 #ifdef HAVE_LINUX_BPF_H
34 # include <linux/bpf.h>
35 #endif
36 #include <linux/filter.h>
37
38 #include "bpf_attr.h"
39
40 #include "xlat/bpf_commands.h"
41 #include "xlat/bpf_file_mode_flags.h"
42 #include "xlat/bpf_map_types.h"
43 #include "xlat/bpf_map_flags.h"
44 #include "xlat/bpf_prog_types.h"
45 #include "xlat/bpf_prog_flags.h"
46 #include "xlat/bpf_map_update_elem_flags.h"
47 #include "xlat/bpf_attach_type.h"
48 #include "xlat/bpf_attach_flags.h"
49 #include "xlat/bpf_query_flags.h"
50 #include "xlat/ebpf_regs.h"
51 #include "xlat/numa_node.h"
52
53 #define DECL_BPF_CMD_DECODER(bpf_cmd_decoder)                           \
54 int                                                                     \
55 bpf_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
61 #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. */
78
79 #define BPF_CMD_ENTRY(bpf_cmd)                                          \
80         [bpf_cmd] = decode_ ## bpf_cmd
81
82 typedef DECL_BPF_CMD_DECODER((*bpf_cmd_decoder_t));
83
84 /*
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
93 static int
94 decode_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(", ");
109                         if (abbrev(tcp)) {
110                                 tprints("...");
111                         } else {
112                                 tprintf("/* bytes %zu..%zu */ ",
113                                         attr_size, attr_size + size - 1);
114                                 print_quoted_string(data, size,
115                                                     QUOTE_FORCE_HEX);
116                         }
117                         return RVAL_DECODED;
118                 }
119         }
120
121         return 0;
122 }
123
124 struct 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
132 struct ebpf_insns_data {
133         unsigned int count;
134 };
135
136 static bool
137 print_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
164 static void
165 print_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
179 BEGIN_BPF_CMD_DECODER(BPF_MAP_CREATE)
180 {
181         PRINT_FIELD_XVAL_INDEX("{", attr, map_type, bpf_map_types,
182                                "BPF_MAP_TYPE_???");
183         PRINT_FIELD_U(", ", attr, key_size);
184         PRINT_FIELD_U(", ", attr, value_size);
185         PRINT_FIELD_U(", ", attr, max_entries);
186
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;
190         PRINT_FIELD_FLAGS(", ", attr, map_flags, bpf_map_flags, "BPF_F_???");
191
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;
198         PRINT_FIELD_FD(", ", attr, inner_map_fd, tcp);
199
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);
235 }
236 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
237
238 BEGIN_BPF_CMD_DECODER(BPF_MAP_LOOKUP_ELEM)
239 {
240         PRINT_FIELD_FD("{", attr, map_fd, tcp);
241         PRINT_FIELD_ADDR64(", ", attr, key);
242         PRINT_FIELD_ADDR64(", ", attr, value);
243 }
244 END_BPF_CMD_DECODER(RVAL_DECODED)
245
246 BEGIN_BPF_CMD_DECODER(BPF_MAP_UPDATE_ELEM)
247 {
248         PRINT_FIELD_FD("{", attr, map_fd, tcp);
249         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_???");
253 }
254 END_BPF_CMD_DECODER(RVAL_DECODED)
255
256 BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_ELEM)
257 {
258         PRINT_FIELD_FD("{", attr, map_fd, tcp);
259         PRINT_FIELD_ADDR64(", ", attr, key);
260 }
261 END_BPF_CMD_DECODER(RVAL_DECODED)
262
263 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_NEXT_KEY)
264 {
265         PRINT_FIELD_FD("{", attr, map_fd, tcp);
266         PRINT_FIELD_ADDR64(", ", attr, key);
267         PRINT_FIELD_ADDR64(", ", attr, next_key);
268 }
269 END_BPF_CMD_DECODER(RVAL_DECODED)
270
271 BEGIN_BPF_CMD_DECODER(BPF_PROG_LOAD)
272 {
273         PRINT_FIELD_XVAL_INDEX("{", attr, prog_type, bpf_prog_types,
274                                "BPF_PROG_TYPE_???");
275         PRINT_FIELD_U(", ", attr, insn_cnt);
276         tprints(", insns=");
277         print_ebpf_prog(tcp, attr.insns, attr.insn_cnt);
278
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;
286         PRINT_FIELD_U(", ", attr, log_level);
287         PRINT_FIELD_U(", ", attr, log_size);
288         tprintf(", log_buf=");
289         print_big_u64_addr(attr.log_buf);
290         printstr_ex(tcp, attr.log_buf, attr.log_size, QUOTE_0_TERMINATED);
291
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;
303         PRINT_FIELD_FLAGS(", ", attr, prog_flags, bpf_prog_flags, "BPF_F_???");
304
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_???");
330 }
331 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
332
333 BEGIN_BPF_CMD_DECODER(BPF_OBJ_PIN)
334 {
335         tprintf("{pathname=");
336         print_big_u64_addr(attr.pathname);
337         printpath(tcp, attr.pathname);
338
339         PRINT_FIELD_FD(", ", attr, bpf_fd, tcp);
340
341         /* file_flags field was added in Linux v4.15-rc1~84^2~384^2~4 */
342         if (len <= offsetof(struct BPF_OBJ_PIN_struct, file_flags))
343                 break;
344         PRINT_FIELD_FLAGS(", ", attr, file_flags, bpf_file_mode_flags,
345                           "BPF_F_???");
346 }
347 END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD)
348
349 #define decode_BPF_OBJ_GET decode_BPF_OBJ_PIN
350
351 BEGIN_BPF_CMD_DECODER(BPF_PROG_ATTACH)
352 {
353         PRINT_FIELD_FD("{", attr, target_fd, tcp);
354         PRINT_FIELD_FD(", ", attr, attach_bpf_fd, tcp);
355         PRINT_FIELD_XVAL_INDEX(", ", attr, attach_type, bpf_attach_type,
356                                "BPF_???");
357         PRINT_FIELD_FLAGS(", ", attr, attach_flags, bpf_attach_flags,
358                           "BPF_F_???");
359 }
360 END_BPF_CMD_DECODER(RVAL_DECODED)
361
362 BEGIN_BPF_CMD_DECODER(BPF_PROG_DETACH)
363 {
364         PRINT_FIELD_FD("{", attr, target_fd, tcp);
365         PRINT_FIELD_XVAL_INDEX(", ", attr, attach_type, bpf_attach_type,
366                                "BPF_???");
367 }
368 END_BPF_CMD_DECODER(RVAL_DECODED)
369
370 BEGIN_BPF_CMD_DECODER(BPF_PROG_TEST_RUN)
371 {
372         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);
376         PRINT_FIELD_ADDR64(", ", attr, data_in);
377         PRINT_FIELD_ADDR64(", ", attr, data_out);
378         PRINT_FIELD_U(", ", attr, repeat);
379         PRINT_FIELD_U(", ", attr, duration);
380         tprints("}");
381 }
382 END_BPF_CMD_DECODER(RVAL_DECODED)
383
384 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_NEXT_ID)
385 {
386         PRINT_FIELD_U("{", attr, start_id);
387         PRINT_FIELD_U(", ", attr, next_id);
388
389         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
390         if (len <= offsetof(struct BPF_PROG_GET_NEXT_ID_struct, open_flags))
391                 break;
392         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
393                           "BPF_F_???");
394 }
395 END_BPF_CMD_DECODER(RVAL_DECODED)
396
397 #define decode_BPF_MAP_GET_NEXT_ID decode_BPF_PROG_GET_NEXT_ID
398
399 BEGIN_BPF_CMD_DECODER(BPF_PROG_GET_FD_BY_ID)
400 {
401         PRINT_FIELD_U("{", attr, prog_id);
402         PRINT_FIELD_U(", ", attr, next_id);
403
404         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
405         if (len <= offsetof(struct BPF_PROG_GET_FD_BY_ID_struct, open_flags))
406                 break;
407         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
408                           "BPF_F_???");
409 }
410 END_BPF_CMD_DECODER(RVAL_DECODED)
411
412 BEGIN_BPF_CMD_DECODER(BPF_MAP_GET_FD_BY_ID)
413 {
414         PRINT_FIELD_U("{", attr, map_id);
415         PRINT_FIELD_U(", ", attr, next_id);
416
417         /* open_flags field has been added in Linux v4.15-rc1~84^2~384^2~4 */
418         if (len <= offsetof(struct BPF_MAP_GET_FD_BY_ID_struct, open_flags))
419                 break;
420         PRINT_FIELD_FLAGS(", ", attr, open_flags, bpf_file_mode_flags,
421                           "BPF_F_???");
422 }
423 END_BPF_CMD_DECODER(RVAL_DECODED)
424
425 struct obj_get_info_saved;
426 typedef 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
432 struct 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
442 static void
443 print_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)
446 {
447         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
481 print_bpf_map_info_end:
482         tprints("}");
483 }
484
485 static void
486 print_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
561 print_bpf_prog_info_end:
562         tprints("}");
563 }
564
565 static const char *
566 fetch_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
582 static void
583 print_bpf_obj_info_addr(struct tcb * const tcp, uint64_t addr)
584 {
585         if (exiting(tcp))
586                 printaddr64(addr);
587 }
588
589 static void
590 print_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
633 BEGIN_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 }
660 END_BPF_CMD_DECODER(RVAL_DECODED)
661
662 BEGIN_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 }
694 END_BPF_CMD_DECODER(RVAL_DECODED)
695
696 BEGIN_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 }
708 END_BPF_CMD_DECODER(RVAL_DECODED)
709
710 SYS_FUNC(bpf)
711 {
712         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),
723                 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),
729                 BPF_CMD_ENTRY(BPF_PROG_QUERY),
730                 BPF_CMD_ENTRY(BPF_RAW_TRACEPOINT_OPEN),
731         };
732
733         const unsigned int cmd = tcp->u_arg[0];
734         const kernel_ulong_t addr = tcp->u_arg[1];
735         const unsigned int size = tcp->u_arg[2];
736         int rc = RVAL_DECODED;
737
738         if (entering(tcp)) {
739                 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]) {
747                 static char *buf;
748
749                 if (!buf)
750                         buf = xmalloc(get_pagesize());
751
752                 if (!umoven_or_printaddr_ignore_syserror(tcp, addr, size, buf))
753                         rc = bpf_cmd_decoders[cmd](tcp, addr, size, buf);
754         } else {
755                 printaddr(addr);
756         }
757
758         if (exiting(tcp) || (rc & RVAL_DECODED))
759                 tprintf(", %u", size);
760
761         return rc;
762 }