| .. | .. |
|---|
| 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) |
|---|