162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2018 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#ifndef _GNU_SOURCE 562306a36Sopenharmony_ci#define _GNU_SOURCE 662306a36Sopenharmony_ci#endif 762306a36Sopenharmony_ci#include <stdarg.h> 862306a36Sopenharmony_ci#include <stdio.h> 962306a36Sopenharmony_ci#include <stdlib.h> 1062306a36Sopenharmony_ci#include <string.h> 1162306a36Sopenharmony_ci#include <sys/types.h> 1262306a36Sopenharmony_ci#include <bpf/libbpf.h> 1362306a36Sopenharmony_ci#include <bpf/libbpf_internal.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "disasm.h" 1662306a36Sopenharmony_ci#include "json_writer.h" 1762306a36Sopenharmony_ci#include "main.h" 1862306a36Sopenharmony_ci#include "xlated_dumper.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int kernel_syms_cmp(const void *sym_a, const void *sym_b) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return ((struct kernel_sym *)sym_a)->address - 2362306a36Sopenharmony_ci ((struct kernel_sym *)sym_b)->address; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid kernel_syms_load(struct dump_data *dd) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct kernel_sym *sym; 2962306a36Sopenharmony_ci char buff[256]; 3062306a36Sopenharmony_ci void *tmp, *address; 3162306a36Sopenharmony_ci FILE *fp; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci fp = fopen("/proc/kallsyms", "r"); 3462306a36Sopenharmony_ci if (!fp) 3562306a36Sopenharmony_ci return; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci while (fgets(buff, sizeof(buff), fp)) { 3862306a36Sopenharmony_ci tmp = libbpf_reallocarray(dd->sym_mapping, dd->sym_count + 1, 3962306a36Sopenharmony_ci sizeof(*dd->sym_mapping)); 4062306a36Sopenharmony_ci if (!tmp) { 4162306a36Sopenharmony_ciout: 4262306a36Sopenharmony_ci free(dd->sym_mapping); 4362306a36Sopenharmony_ci dd->sym_mapping = NULL; 4462306a36Sopenharmony_ci fclose(fp); 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci dd->sym_mapping = tmp; 4862306a36Sopenharmony_ci sym = &dd->sym_mapping[dd->sym_count]; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* module is optional */ 5162306a36Sopenharmony_ci sym->module[0] = '\0'; 5262306a36Sopenharmony_ci /* trim the square brackets around the module name */ 5362306a36Sopenharmony_ci if (sscanf(buff, "%p %*c %s [%[^]]s", &address, sym->name, sym->module) < 2) 5462306a36Sopenharmony_ci continue; 5562306a36Sopenharmony_ci sym->address = (unsigned long)address; 5662306a36Sopenharmony_ci if (!strcmp(sym->name, "__bpf_call_base")) { 5762306a36Sopenharmony_ci dd->address_call_base = sym->address; 5862306a36Sopenharmony_ci /* sysctl kernel.kptr_restrict was set */ 5962306a36Sopenharmony_ci if (!sym->address) 6062306a36Sopenharmony_ci goto out; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci if (sym->address) 6362306a36Sopenharmony_ci dd->sym_count++; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci fclose(fp); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci qsort(dd->sym_mapping, dd->sym_count, 6962306a36Sopenharmony_ci sizeof(*dd->sym_mapping), kernel_syms_cmp); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid kernel_syms_destroy(struct dump_data *dd) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci free(dd->sym_mapping); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct kernel_sym *kernel_syms_search(struct dump_data *dd, 7862306a36Sopenharmony_ci unsigned long key) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct kernel_sym sym = { 8162306a36Sopenharmony_ci .address = key, 8262306a36Sopenharmony_ci }; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return dd->sym_mapping ? 8562306a36Sopenharmony_ci bsearch(&sym, dd->sym_mapping, dd->sym_count, 8662306a36Sopenharmony_ci sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void __printf(2, 3) print_insn(void *private_data, const char *fmt, ...) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci va_list args; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci va_start(args, fmt); 9462306a36Sopenharmony_ci vprintf(fmt, args); 9562306a36Sopenharmony_ci va_end(args); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void __printf(2, 3) 9962306a36Sopenharmony_ciprint_insn_for_graph(void *private_data, const char *fmt, ...) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci char buf[64], *p; 10262306a36Sopenharmony_ci va_list args; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci va_start(args, fmt); 10562306a36Sopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, args); 10662306a36Sopenharmony_ci va_end(args); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci p = buf; 10962306a36Sopenharmony_ci while (*p != '\0') { 11062306a36Sopenharmony_ci if (*p == '\n') { 11162306a36Sopenharmony_ci memmove(p + 3, p, strlen(buf) + 1 - (p - buf)); 11262306a36Sopenharmony_ci /* Align each instruction dump row left. */ 11362306a36Sopenharmony_ci *p++ = '\\'; 11462306a36Sopenharmony_ci *p++ = 'l'; 11562306a36Sopenharmony_ci /* Output multiline concatenation. */ 11662306a36Sopenharmony_ci *p++ = '\\'; 11762306a36Sopenharmony_ci } else if (*p == '<' || *p == '>' || *p == '|' || *p == '&') { 11862306a36Sopenharmony_ci memmove(p + 1, p, strlen(buf) + 1 - (p - buf)); 11962306a36Sopenharmony_ci /* Escape special character. */ 12062306a36Sopenharmony_ci *p++ = '\\'; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci p++; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci printf("%s", buf); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void __printf(2, 3) 13062306a36Sopenharmony_ciprint_insn_json(void *private_data, const char *fmt, ...) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci unsigned int l = strlen(fmt); 13362306a36Sopenharmony_ci char chomped_fmt[l]; 13462306a36Sopenharmony_ci va_list args; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci va_start(args, fmt); 13762306a36Sopenharmony_ci if (l > 0) { 13862306a36Sopenharmony_ci strncpy(chomped_fmt, fmt, l - 1); 13962306a36Sopenharmony_ci chomped_fmt[l - 1] = '\0'; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); 14262306a36Sopenharmony_ci va_end(args); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic const char *print_call_pcrel(struct dump_data *dd, 14662306a36Sopenharmony_ci struct kernel_sym *sym, 14762306a36Sopenharmony_ci unsigned long address, 14862306a36Sopenharmony_ci const struct bpf_insn *insn) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci if (!dd->nr_jited_ksyms) 15162306a36Sopenharmony_ci /* Do not show address for interpreted programs */ 15262306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 15362306a36Sopenharmony_ci "%+d", insn->off); 15462306a36Sopenharmony_ci else if (sym) 15562306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 15662306a36Sopenharmony_ci "%+d#%s", insn->off, sym->name); 15762306a36Sopenharmony_ci else 15862306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 15962306a36Sopenharmony_ci "%+d#0x%lx", insn->off, address); 16062306a36Sopenharmony_ci return dd->scratch_buff; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic const char *print_call_helper(struct dump_data *dd, 16462306a36Sopenharmony_ci struct kernel_sym *sym, 16562306a36Sopenharmony_ci unsigned long address) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci if (sym) 16862306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 16962306a36Sopenharmony_ci "%s", sym->name); 17062306a36Sopenharmony_ci else 17162306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 17262306a36Sopenharmony_ci "0x%lx", address); 17362306a36Sopenharmony_ci return dd->scratch_buff; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const char *print_call(void *private_data, 17762306a36Sopenharmony_ci const struct bpf_insn *insn) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct dump_data *dd = private_data; 18062306a36Sopenharmony_ci unsigned long address = dd->address_call_base + insn->imm; 18162306a36Sopenharmony_ci struct kernel_sym *sym; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (insn->src_reg == BPF_PSEUDO_CALL && 18462306a36Sopenharmony_ci (__u32) insn->imm < dd->nr_jited_ksyms && dd->jited_ksyms) 18562306a36Sopenharmony_ci address = dd->jited_ksyms[insn->imm]; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci sym = kernel_syms_search(dd, address); 18862306a36Sopenharmony_ci if (insn->src_reg == BPF_PSEUDO_CALL) 18962306a36Sopenharmony_ci return print_call_pcrel(dd, sym, address, insn); 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci return print_call_helper(dd, sym, address); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic const char *print_imm(void *private_data, 19562306a36Sopenharmony_ci const struct bpf_insn *insn, 19662306a36Sopenharmony_ci __u64 full_imm) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct dump_data *dd = private_data; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (insn->src_reg == BPF_PSEUDO_MAP_FD) 20162306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 20262306a36Sopenharmony_ci "map[id:%u]", insn->imm); 20362306a36Sopenharmony_ci else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) 20462306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 20562306a36Sopenharmony_ci "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm); 20662306a36Sopenharmony_ci else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE) 20762306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 20862306a36Sopenharmony_ci "map[idx:%u]+%u", insn->imm, (insn + 1)->imm); 20962306a36Sopenharmony_ci else if (insn->src_reg == BPF_PSEUDO_FUNC) 21062306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 21162306a36Sopenharmony_ci "subprog[%+d]", insn->imm); 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 21462306a36Sopenharmony_ci "0x%llx", (unsigned long long)full_imm); 21562306a36Sopenharmony_ci return dd->scratch_buff; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_civoid dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, 21962306a36Sopenharmony_ci bool opcodes, bool linum) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; 22262306a36Sopenharmony_ci const struct bpf_insn_cbs cbs = { 22362306a36Sopenharmony_ci .cb_print = print_insn_json, 22462306a36Sopenharmony_ci .cb_call = print_call, 22562306a36Sopenharmony_ci .cb_imm = print_imm, 22662306a36Sopenharmony_ci .private_data = dd, 22762306a36Sopenharmony_ci }; 22862306a36Sopenharmony_ci struct bpf_func_info *record; 22962306a36Sopenharmony_ci struct bpf_insn *insn = buf; 23062306a36Sopenharmony_ci struct btf *btf = dd->btf; 23162306a36Sopenharmony_ci bool double_insn = false; 23262306a36Sopenharmony_ci unsigned int nr_skip = 0; 23362306a36Sopenharmony_ci char func_sig[1024]; 23462306a36Sopenharmony_ci unsigned int i; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci jsonw_start_array(json_wtr); 23762306a36Sopenharmony_ci record = dd->func_info; 23862306a36Sopenharmony_ci for (i = 0; i < len / sizeof(*insn); i++) { 23962306a36Sopenharmony_ci if (double_insn) { 24062306a36Sopenharmony_ci double_insn = false; 24162306a36Sopenharmony_ci continue; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci jsonw_start_object(json_wtr); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (btf && record) { 24862306a36Sopenharmony_ci if (record->insn_off == i) { 24962306a36Sopenharmony_ci btf_dumper_type_only(btf, record->type_id, 25062306a36Sopenharmony_ci func_sig, 25162306a36Sopenharmony_ci sizeof(func_sig)); 25262306a36Sopenharmony_ci if (func_sig[0] != '\0') { 25362306a36Sopenharmony_ci jsonw_name(json_wtr, "proto"); 25462306a36Sopenharmony_ci jsonw_string(json_wtr, func_sig); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci record = (void *)record + dd->finfo_rec_size; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (prog_linfo) { 26162306a36Sopenharmony_ci const struct bpf_line_info *linfo; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); 26462306a36Sopenharmony_ci if (linfo) { 26562306a36Sopenharmony_ci btf_dump_linfo_json(btf, linfo, linum); 26662306a36Sopenharmony_ci nr_skip++; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci jsonw_name(json_wtr, "disasm"); 27162306a36Sopenharmony_ci print_bpf_insn(&cbs, insn + i, true); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (opcodes) { 27462306a36Sopenharmony_ci jsonw_name(json_wtr, "opcodes"); 27562306a36Sopenharmony_ci jsonw_start_object(json_wtr); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci jsonw_name(json_wtr, "code"); 27862306a36Sopenharmony_ci jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci jsonw_name(json_wtr, "src_reg"); 28162306a36Sopenharmony_ci jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci jsonw_name(json_wtr, "dst_reg"); 28462306a36Sopenharmony_ci jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci jsonw_name(json_wtr, "off"); 28762306a36Sopenharmony_ci print_hex_data_json((uint8_t *)(&insn[i].off), 2); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci jsonw_name(json_wtr, "imm"); 29062306a36Sopenharmony_ci if (double_insn && i < len - 1) 29162306a36Sopenharmony_ci print_hex_data_json((uint8_t *)(&insn[i].imm), 29262306a36Sopenharmony_ci 12); 29362306a36Sopenharmony_ci else 29462306a36Sopenharmony_ci print_hex_data_json((uint8_t *)(&insn[i].imm), 29562306a36Sopenharmony_ci 4); 29662306a36Sopenharmony_ci jsonw_end_object(json_wtr); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci jsonw_end_object(json_wtr); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci jsonw_end_array(json_wtr); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_civoid dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, 30462306a36Sopenharmony_ci bool opcodes, bool linum) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; 30762306a36Sopenharmony_ci const struct bpf_insn_cbs cbs = { 30862306a36Sopenharmony_ci .cb_print = print_insn, 30962306a36Sopenharmony_ci .cb_call = print_call, 31062306a36Sopenharmony_ci .cb_imm = print_imm, 31162306a36Sopenharmony_ci .private_data = dd, 31262306a36Sopenharmony_ci }; 31362306a36Sopenharmony_ci struct bpf_func_info *record; 31462306a36Sopenharmony_ci struct bpf_insn *insn = buf; 31562306a36Sopenharmony_ci struct btf *btf = dd->btf; 31662306a36Sopenharmony_ci unsigned int nr_skip = 0; 31762306a36Sopenharmony_ci bool double_insn = false; 31862306a36Sopenharmony_ci char func_sig[1024]; 31962306a36Sopenharmony_ci unsigned int i; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci record = dd->func_info; 32262306a36Sopenharmony_ci for (i = 0; i < len / sizeof(*insn); i++) { 32362306a36Sopenharmony_ci if (double_insn) { 32462306a36Sopenharmony_ci double_insn = false; 32562306a36Sopenharmony_ci continue; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (btf && record) { 32962306a36Sopenharmony_ci if (record->insn_off == i) { 33062306a36Sopenharmony_ci btf_dumper_type_only(btf, record->type_id, 33162306a36Sopenharmony_ci func_sig, 33262306a36Sopenharmony_ci sizeof(func_sig)); 33362306a36Sopenharmony_ci if (func_sig[0] != '\0') 33462306a36Sopenharmony_ci printf("%s:\n", func_sig); 33562306a36Sopenharmony_ci record = (void *)record + dd->finfo_rec_size; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (prog_linfo) { 34062306a36Sopenharmony_ci const struct bpf_line_info *linfo; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); 34362306a36Sopenharmony_ci if (linfo) { 34462306a36Sopenharmony_ci btf_dump_linfo_plain(btf, linfo, "; ", 34562306a36Sopenharmony_ci linum); 34662306a36Sopenharmony_ci nr_skip++; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci printf("% 4d: ", i); 35362306a36Sopenharmony_ci print_bpf_insn(&cbs, insn + i, true); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (opcodes) { 35662306a36Sopenharmony_ci printf(" "); 35762306a36Sopenharmony_ci fprint_hex(stdout, insn + i, 8, " "); 35862306a36Sopenharmony_ci if (double_insn && i < len - 1) { 35962306a36Sopenharmony_ci printf(" "); 36062306a36Sopenharmony_ci fprint_hex(stdout, insn + i + 1, 8, " "); 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci printf("\n"); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_civoid dump_xlated_for_graph(struct dump_data *dd, void *buf_start, void *buf_end, 36862306a36Sopenharmony_ci unsigned int start_idx, 36962306a36Sopenharmony_ci bool opcodes, bool linum) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci const struct bpf_insn_cbs cbs = { 37262306a36Sopenharmony_ci .cb_print = print_insn_for_graph, 37362306a36Sopenharmony_ci .cb_call = print_call, 37462306a36Sopenharmony_ci .cb_imm = print_imm, 37562306a36Sopenharmony_ci .private_data = dd, 37662306a36Sopenharmony_ci }; 37762306a36Sopenharmony_ci const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; 37862306a36Sopenharmony_ci const struct bpf_line_info *last_linfo = NULL; 37962306a36Sopenharmony_ci struct bpf_func_info *record = dd->func_info; 38062306a36Sopenharmony_ci struct bpf_insn *insn_start = buf_start; 38162306a36Sopenharmony_ci struct bpf_insn *insn_end = buf_end; 38262306a36Sopenharmony_ci struct bpf_insn *cur = insn_start; 38362306a36Sopenharmony_ci struct btf *btf = dd->btf; 38462306a36Sopenharmony_ci bool double_insn = false; 38562306a36Sopenharmony_ci char func_sig[1024]; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci for (; cur <= insn_end; cur++) { 38862306a36Sopenharmony_ci unsigned int insn_off; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (double_insn) { 39162306a36Sopenharmony_ci double_insn = false; 39262306a36Sopenharmony_ci continue; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci double_insn = cur->code == (BPF_LD | BPF_IMM | BPF_DW); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci insn_off = (unsigned int)(cur - insn_start + start_idx); 39762306a36Sopenharmony_ci if (btf && record) { 39862306a36Sopenharmony_ci if (record->insn_off == insn_off) { 39962306a36Sopenharmony_ci btf_dumper_type_only(btf, record->type_id, 40062306a36Sopenharmony_ci func_sig, 40162306a36Sopenharmony_ci sizeof(func_sig)); 40262306a36Sopenharmony_ci if (func_sig[0] != '\0') 40362306a36Sopenharmony_ci printf("; %s:\\l\\\n", func_sig); 40462306a36Sopenharmony_ci record = (void *)record + dd->finfo_rec_size; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (prog_linfo) { 40962306a36Sopenharmony_ci const struct bpf_line_info *linfo; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci linfo = bpf_prog_linfo__lfind(prog_linfo, insn_off, 0); 41262306a36Sopenharmony_ci if (linfo && linfo != last_linfo) { 41362306a36Sopenharmony_ci btf_dump_linfo_dotlabel(btf, linfo, linum); 41462306a36Sopenharmony_ci last_linfo = linfo; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci printf("%d: ", insn_off); 41962306a36Sopenharmony_ci print_bpf_insn(&cbs, cur, true); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (opcodes) { 42262306a36Sopenharmony_ci printf("\\ \\ \\ \\ "); 42362306a36Sopenharmony_ci fprint_hex(stdout, cur, 8, " "); 42462306a36Sopenharmony_ci if (double_insn && cur <= insn_end - 1) { 42562306a36Sopenharmony_ci printf(" "); 42662306a36Sopenharmony_ci fprint_hex(stdout, cur + 1, 8, " "); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci printf("\\l\\\n"); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (cur != insn_end) 43262306a36Sopenharmony_ci printf("| "); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci} 435