.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
---|
2 | | -/* |
---|
3 | | - * Copyright (C) 2018 Netronome Systems, Inc. |
---|
4 | | - * |
---|
5 | | - * This software is dual licensed under the GNU General License Version 2, |
---|
6 | | - * June 1991 as shown in the file COPYING in the top-level directory of this |
---|
7 | | - * source tree or the BSD 2-Clause License provided below. You have the |
---|
8 | | - * option to license this software under the complete terms of either license. |
---|
9 | | - * |
---|
10 | | - * The BSD 2-Clause License: |
---|
11 | | - * |
---|
12 | | - * Redistribution and use in source and binary forms, with or |
---|
13 | | - * without modification, are permitted provided that the following |
---|
14 | | - * conditions are met: |
---|
15 | | - * |
---|
16 | | - * 1. Redistributions of source code must retain the above |
---|
17 | | - * copyright notice, this list of conditions and the following |
---|
18 | | - * disclaimer. |
---|
19 | | - * |
---|
20 | | - * 2. Redistributions in binary form must reproduce the above |
---|
21 | | - * copyright notice, this list of conditions and the following |
---|
22 | | - * disclaimer in the documentation and/or other materials |
---|
23 | | - * provided with the distribution. |
---|
24 | | - * |
---|
25 | | - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
26 | | - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
27 | | - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
28 | | - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
---|
29 | | - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
30 | | - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
31 | | - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
32 | | - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
33 | | - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
34 | | - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
35 | | - * POSSIBILITY OF SUCH DAMAGE. |
---|
36 | | - */ |
---|
| 2 | +/* Copyright (C) 2018 Netronome Systems, Inc. */ |
---|
37 | 3 | |
---|
38 | 4 | #define _GNU_SOURCE |
---|
39 | 5 | #include <stdarg.h> |
---|
.. | .. |
---|
41 | 7 | #include <stdlib.h> |
---|
42 | 8 | #include <string.h> |
---|
43 | 9 | #include <sys/types.h> |
---|
| 10 | +#include <bpf/libbpf.h> |
---|
44 | 11 | |
---|
45 | 12 | #include "disasm.h" |
---|
46 | 13 | #include "json_writer.h" |
---|
.. | .. |
---|
64 | 31 | if (!fp) |
---|
65 | 32 | return; |
---|
66 | 33 | |
---|
67 | | - while (!feof(fp)) { |
---|
68 | | - if (!fgets(buff, sizeof(buff), fp)) |
---|
69 | | - break; |
---|
| 34 | + while (fgets(buff, sizeof(buff), fp)) { |
---|
70 | 35 | tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1, |
---|
71 | 36 | sizeof(*dd->sym_mapping)); |
---|
72 | 37 | if (!tmp) { |
---|
.. | .. |
---|
114 | 79 | sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL; |
---|
115 | 80 | } |
---|
116 | 81 | |
---|
117 | | -static void print_insn(void *private_data, const char *fmt, ...) |
---|
| 82 | +static void __printf(2, 3) print_insn(void *private_data, const char *fmt, ...) |
---|
118 | 83 | { |
---|
119 | 84 | va_list args; |
---|
120 | 85 | |
---|
.. | .. |
---|
123 | 88 | va_end(args); |
---|
124 | 89 | } |
---|
125 | 90 | |
---|
126 | | -static void |
---|
| 91 | +static void __printf(2, 3) |
---|
127 | 92 | print_insn_for_graph(void *private_data, const char *fmt, ...) |
---|
128 | 93 | { |
---|
129 | 94 | char buf[64], *p; |
---|
.. | .. |
---|
154 | 119 | printf("%s", buf); |
---|
155 | 120 | } |
---|
156 | 121 | |
---|
157 | | -static void print_insn_json(void *private_data, const char *fmt, ...) |
---|
| 122 | +static void __printf(2, 3) |
---|
| 123 | +print_insn_json(void *private_data, const char *fmt, ...) |
---|
158 | 124 | { |
---|
159 | 125 | unsigned int l = strlen(fmt); |
---|
160 | 126 | char chomped_fmt[l]; |
---|
.. | .. |
---|
208 | 174 | struct kernel_sym *sym; |
---|
209 | 175 | |
---|
210 | 176 | if (insn->src_reg == BPF_PSEUDO_CALL && |
---|
211 | | - (__u32) insn->imm < dd->nr_jited_ksyms) |
---|
| 177 | + (__u32) insn->imm < dd->nr_jited_ksyms && dd->jited_ksyms) |
---|
212 | 178 | address = dd->jited_ksyms[insn->imm]; |
---|
213 | 179 | |
---|
214 | 180 | sym = kernel_syms_search(dd, address); |
---|
.. | .. |
---|
227 | 193 | if (insn->src_reg == BPF_PSEUDO_MAP_FD) |
---|
228 | 194 | snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), |
---|
229 | 195 | "map[id:%u]", insn->imm); |
---|
| 196 | + else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) |
---|
| 197 | + snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), |
---|
| 198 | + "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm); |
---|
230 | 199 | else |
---|
231 | 200 | snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), |
---|
232 | 201 | "0x%llx", (unsigned long long)full_imm); |
---|
.. | .. |
---|
234 | 203 | } |
---|
235 | 204 | |
---|
236 | 205 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, |
---|
237 | | - bool opcodes) |
---|
| 206 | + bool opcodes, bool linum) |
---|
238 | 207 | { |
---|
| 208 | + const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; |
---|
239 | 209 | const struct bpf_insn_cbs cbs = { |
---|
240 | 210 | .cb_print = print_insn_json, |
---|
241 | 211 | .cb_call = print_call, |
---|
242 | 212 | .cb_imm = print_imm, |
---|
243 | 213 | .private_data = dd, |
---|
244 | 214 | }; |
---|
| 215 | + struct bpf_func_info *record; |
---|
245 | 216 | struct bpf_insn *insn = buf; |
---|
| 217 | + struct btf *btf = dd->btf; |
---|
246 | 218 | bool double_insn = false; |
---|
| 219 | + unsigned int nr_skip = 0; |
---|
| 220 | + char func_sig[1024]; |
---|
247 | 221 | unsigned int i; |
---|
248 | 222 | |
---|
249 | 223 | jsonw_start_array(json_wtr); |
---|
| 224 | + record = dd->func_info; |
---|
250 | 225 | for (i = 0; i < len / sizeof(*insn); i++) { |
---|
251 | 226 | if (double_insn) { |
---|
252 | 227 | double_insn = false; |
---|
.. | .. |
---|
255 | 230 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); |
---|
256 | 231 | |
---|
257 | 232 | jsonw_start_object(json_wtr); |
---|
| 233 | + |
---|
| 234 | + if (btf && record) { |
---|
| 235 | + if (record->insn_off == i) { |
---|
| 236 | + btf_dumper_type_only(btf, record->type_id, |
---|
| 237 | + func_sig, |
---|
| 238 | + sizeof(func_sig)); |
---|
| 239 | + if (func_sig[0] != '\0') { |
---|
| 240 | + jsonw_name(json_wtr, "proto"); |
---|
| 241 | + jsonw_string(json_wtr, func_sig); |
---|
| 242 | + } |
---|
| 243 | + record = (void *)record + dd->finfo_rec_size; |
---|
| 244 | + } |
---|
| 245 | + } |
---|
| 246 | + |
---|
| 247 | + if (prog_linfo) { |
---|
| 248 | + const struct bpf_line_info *linfo; |
---|
| 249 | + |
---|
| 250 | + linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); |
---|
| 251 | + if (linfo) { |
---|
| 252 | + btf_dump_linfo_json(btf, linfo, linum); |
---|
| 253 | + nr_skip++; |
---|
| 254 | + } |
---|
| 255 | + } |
---|
| 256 | + |
---|
258 | 257 | jsonw_name(json_wtr, "disasm"); |
---|
259 | 258 | print_bpf_insn(&cbs, insn + i, true); |
---|
260 | 259 | |
---|
.. | .. |
---|
289 | 288 | } |
---|
290 | 289 | |
---|
291 | 290 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, |
---|
292 | | - bool opcodes) |
---|
| 291 | + bool opcodes, bool linum) |
---|
293 | 292 | { |
---|
| 293 | + const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; |
---|
294 | 294 | const struct bpf_insn_cbs cbs = { |
---|
295 | 295 | .cb_print = print_insn, |
---|
296 | 296 | .cb_call = print_call, |
---|
297 | 297 | .cb_imm = print_imm, |
---|
298 | 298 | .private_data = dd, |
---|
299 | 299 | }; |
---|
| 300 | + struct bpf_func_info *record; |
---|
300 | 301 | struct bpf_insn *insn = buf; |
---|
| 302 | + struct btf *btf = dd->btf; |
---|
| 303 | + unsigned int nr_skip = 0; |
---|
301 | 304 | bool double_insn = false; |
---|
| 305 | + char func_sig[1024]; |
---|
302 | 306 | unsigned int i; |
---|
303 | 307 | |
---|
| 308 | + record = dd->func_info; |
---|
304 | 309 | for (i = 0; i < len / sizeof(*insn); i++) { |
---|
305 | 310 | if (double_insn) { |
---|
306 | 311 | double_insn = false; |
---|
307 | 312 | continue; |
---|
| 313 | + } |
---|
| 314 | + |
---|
| 315 | + if (btf && record) { |
---|
| 316 | + if (record->insn_off == i) { |
---|
| 317 | + btf_dumper_type_only(btf, record->type_id, |
---|
| 318 | + func_sig, |
---|
| 319 | + sizeof(func_sig)); |
---|
| 320 | + if (func_sig[0] != '\0') |
---|
| 321 | + printf("%s:\n", func_sig); |
---|
| 322 | + record = (void *)record + dd->finfo_rec_size; |
---|
| 323 | + } |
---|
| 324 | + } |
---|
| 325 | + |
---|
| 326 | + if (prog_linfo) { |
---|
| 327 | + const struct bpf_line_info *linfo; |
---|
| 328 | + |
---|
| 329 | + linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); |
---|
| 330 | + if (linfo) { |
---|
| 331 | + btf_dump_linfo_plain(btf, linfo, "; ", |
---|
| 332 | + linum); |
---|
| 333 | + nr_skip++; |
---|
| 334 | + } |
---|
308 | 335 | } |
---|
309 | 336 | |
---|
310 | 337 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); |
---|
.. | .. |
---|
336 | 363 | struct bpf_insn *insn_start = buf_start; |
---|
337 | 364 | struct bpf_insn *insn_end = buf_end; |
---|
338 | 365 | struct bpf_insn *cur = insn_start; |
---|
| 366 | + bool double_insn = false; |
---|
339 | 367 | |
---|
340 | 368 | for (; cur <= insn_end; cur++) { |
---|
| 369 | + if (double_insn) { |
---|
| 370 | + double_insn = false; |
---|
| 371 | + continue; |
---|
| 372 | + } |
---|
| 373 | + double_insn = cur->code == (BPF_LD | BPF_IMM | BPF_DW); |
---|
| 374 | + |
---|
341 | 375 | printf("% 4d: ", (int)(cur - insn_start + start_idx)); |
---|
342 | 376 | print_bpf_insn(&cbs, cur, true); |
---|
343 | 377 | if (cur != insn_end) |
---|