Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jiong Wang | 1476 | 61.50% | 2 | 6.45% |
Yonghong Song | 263 | 10.96% | 2 | 6.45% |
Quentin Monnet | 159 | 6.62% | 8 | 25.81% |
Martin KaFai Lau | 157 | 6.54% | 2 | 6.45% |
Daniel Borkmann | 151 | 6.29% | 2 | 6.45% |
Jakub Kiciński | 78 | 3.25% | 4 | 12.90% |
Alexei Starovoitov | 43 | 1.79% | 3 | 9.68% |
Sandipan Das | 38 | 1.58% | 1 | 3.23% |
Yafang Shao | 17 | 0.71% | 1 | 3.23% |
Jiri Olsa | 6 | 0.25% | 1 | 3.23% |
Toke Höiland-Jörgensen | 5 | 0.21% | 2 | 6.45% |
Mauricio Vásquez | 4 | 0.17% | 1 | 3.23% |
zhujun2 | 2 | 0.08% | 1 | 3.23% |
Chang-Hsien Tsai | 1 | 0.04% | 1 | 3.23% |
Total | 2400 | 31 |
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (C) 2018 Netronome Systems, Inc. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <bpf/libbpf.h> #include <bpf/libbpf_internal.h> #include "disasm.h" #include "json_writer.h" #include "main.h" #include "xlated_dumper.h" static int kernel_syms_cmp(const void *sym_a, const void *sym_b) { return ((struct kernel_sym *)sym_a)->address - ((struct kernel_sym *)sym_b)->address; } void kernel_syms_load(struct dump_data *dd) { struct kernel_sym *sym; char buff[256]; void *tmp, *address; FILE *fp; fp = fopen("/proc/kallsyms", "r"); if (!fp) return; while (fgets(buff, sizeof(buff), fp)) { tmp = libbpf_reallocarray(dd->sym_mapping, dd->sym_count + 1, sizeof(*dd->sym_mapping)); if (!tmp) { out: free(dd->sym_mapping); dd->sym_mapping = NULL; fclose(fp); return; } dd->sym_mapping = tmp; sym = &dd->sym_mapping[dd->sym_count]; /* module is optional */ sym->module[0] = '\0'; /* trim the square brackets around the module name */ if (sscanf(buff, "%p %*c %s [%[^]]s", &address, sym->name, sym->module) < 2) continue; sym->address = (unsigned long)address; if (!strcmp(sym->name, "__bpf_call_base")) { dd->address_call_base = sym->address; /* sysctl kernel.kptr_restrict was set */ if (!sym->address) goto out; } if (sym->address) dd->sym_count++; } fclose(fp); qsort(dd->sym_mapping, dd->sym_count, sizeof(*dd->sym_mapping), kernel_syms_cmp); } void kernel_syms_destroy(struct dump_data *dd) { free(dd->sym_mapping); } struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key) { struct kernel_sym sym = { .address = key, }; return dd->sym_mapping ? bsearch(&sym, dd->sym_mapping, dd->sym_count, sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL; } static void __printf(2, 3) print_insn(void *private_data, const char *fmt, ...) { va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); } static void __printf(2, 3) print_insn_for_graph(void *private_data, const char *fmt, ...) { char buf[64], *p; va_list args; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); p = buf; while (*p != '\0') { if (*p == '\n') { memmove(p + 3, p, strlen(buf) + 1 - (p - buf)); /* Align each instruction dump row left. */ *p++ = '\\'; *p++ = 'l'; /* Output multiline concatenation. */ *p++ = '\\'; } else if (*p == '<' || *p == '>' || *p == '|' || *p == '&') { memmove(p + 1, p, strlen(buf) + 1 - (p - buf)); /* Escape special character. */ *p++ = '\\'; } p++; } printf("%s", buf); } static void __printf(2, 3) print_insn_json(void *private_data, const char *fmt, ...) { unsigned int l = strlen(fmt); char chomped_fmt[l]; va_list args; va_start(args, fmt); if (l > 0) { strncpy(chomped_fmt, fmt, l - 1); chomped_fmt[l - 1] = '\0'; } jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); va_end(args); } static const char *print_call_pcrel(struct dump_data *dd, struct kernel_sym *sym, unsigned long address, const struct bpf_insn *insn) { if (!dd->nr_jited_ksyms) /* Do not show address for interpreted programs */ snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "%+d", insn->off); else if (sym) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "%+d#%s", insn->off, sym->name); else snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "%+d#0x%lx", insn->off, address); return dd->scratch_buff; } static const char *print_call_helper(struct dump_data *dd, struct kernel_sym *sym, unsigned long address) { if (sym) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "%s", sym->name); else snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "0x%lx", address); return dd->scratch_buff; } static const char *print_call(void *private_data, const struct bpf_insn *insn) { struct dump_data *dd = private_data; unsigned long address = dd->address_call_base + insn->imm; struct kernel_sym *sym; if (insn->src_reg == BPF_PSEUDO_CALL && (__u32) insn->imm < dd->nr_jited_ksyms && dd->jited_ksyms) address = dd->jited_ksyms[insn->imm]; sym = kernel_syms_search(dd, address); if (insn->src_reg == BPF_PSEUDO_CALL) return print_call_pcrel(dd, sym, address, insn); else return print_call_helper(dd, sym, address); } static const char *print_imm(void *private_data, const struct bpf_insn *insn, __u64 full_imm) { struct dump_data *dd = private_data; if (insn->src_reg == BPF_PSEUDO_MAP_FD) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "map[id:%u]", insn->imm); else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm); else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "map[idx:%u]+%u", insn->imm, (insn + 1)->imm); else if (insn->src_reg == BPF_PSEUDO_FUNC) snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "subprog[%+d]", insn->imm); else snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), "0x%llx", (unsigned long long)full_imm); return dd->scratch_buff; } void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, bool opcodes, bool linum) { const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; const struct bpf_insn_cbs cbs = { .cb_print = print_insn_json, .cb_call = print_call, .cb_imm = print_imm, .private_data = dd, }; struct bpf_func_info *record; struct bpf_insn *insn = buf; struct btf *btf = dd->btf; bool double_insn = false; unsigned int nr_skip = 0; char func_sig[1024]; unsigned int i; jsonw_start_array(json_wtr); record = dd->func_info; for (i = 0; i < len / sizeof(*insn); i++) { if (double_insn) { double_insn = false; continue; } double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); jsonw_start_object(json_wtr); if (btf && record) { if (record->insn_off == i) { btf_dumper_type_only(btf, record->type_id, func_sig, sizeof(func_sig)); if (func_sig[0] != '\0') { jsonw_name(json_wtr, "proto"); jsonw_string(json_wtr, func_sig); } record = (void *)record + dd->finfo_rec_size; } } if (prog_linfo) { const struct bpf_line_info *linfo; linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); if (linfo) { btf_dump_linfo_json(btf, linfo, linum); nr_skip++; } } jsonw_name(json_wtr, "disasm"); print_bpf_insn(&cbs, insn + i, true); if (opcodes) { jsonw_name(json_wtr, "opcodes"); jsonw_start_object(json_wtr); jsonw_name(json_wtr, "code"); jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); jsonw_name(json_wtr, "src_reg"); jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); jsonw_name(json_wtr, "dst_reg"); jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); jsonw_name(json_wtr, "off"); print_hex_data_json((uint8_t *)(&insn[i].off), 2); jsonw_name(json_wtr, "imm"); if (double_insn && i < len - 1) print_hex_data_json((uint8_t *)(&insn[i].imm), 12); else print_hex_data_json((uint8_t *)(&insn[i].imm), 4); jsonw_end_object(json_wtr); } jsonw_end_object(json_wtr); } jsonw_end_array(json_wtr); } void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, bool opcodes, bool linum) { const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; const struct bpf_insn_cbs cbs = { .cb_print = print_insn, .cb_call = print_call, .cb_imm = print_imm, .private_data = dd, }; struct bpf_func_info *record; struct bpf_insn *insn = buf; struct btf *btf = dd->btf; unsigned int nr_skip = 0; bool double_insn = false; char func_sig[1024]; unsigned int i; record = dd->func_info; for (i = 0; i < len / sizeof(*insn); i++) { if (double_insn) { double_insn = false; continue; } if (btf && record) { if (record->insn_off == i) { btf_dumper_type_only(btf, record->type_id, func_sig, sizeof(func_sig)); if (func_sig[0] != '\0') printf("%s:\n", func_sig); record = (void *)record + dd->finfo_rec_size; } } if (prog_linfo) { const struct bpf_line_info *linfo; linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); if (linfo) { btf_dump_linfo_plain(btf, linfo, "; ", linum); nr_skip++; } } double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); printf("%4u: ", i); print_bpf_insn(&cbs, insn + i, true); if (opcodes) { printf(" "); fprint_hex(stdout, insn + i, 8, " "); if (double_insn && i < len - 1) { printf(" "); fprint_hex(stdout, insn + i + 1, 8, " "); } printf("\n"); } } } void dump_xlated_for_graph(struct dump_data *dd, void *buf_start, void *buf_end, unsigned int start_idx, bool opcodes, bool linum) { const struct bpf_insn_cbs cbs = { .cb_print = print_insn_for_graph, .cb_call = print_call, .cb_imm = print_imm, .private_data = dd, }; const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; const struct bpf_line_info *last_linfo = NULL; struct bpf_func_info *record = dd->func_info; struct bpf_insn *insn_start = buf_start; struct bpf_insn *insn_end = buf_end; struct bpf_insn *cur = insn_start; struct btf *btf = dd->btf; bool double_insn = false; char func_sig[1024]; for (; cur <= insn_end; cur++) { unsigned int insn_off; if (double_insn) { double_insn = false; continue; } double_insn = cur->code == (BPF_LD | BPF_IMM | BPF_DW); insn_off = (unsigned int)(cur - insn_start + start_idx); if (btf && record) { if (record->insn_off == insn_off) { btf_dumper_type_only(btf, record->type_id, func_sig, sizeof(func_sig)); if (func_sig[0] != '\0') printf("; %s:\\l\\\n", func_sig); record = (void *)record + dd->finfo_rec_size; } } if (prog_linfo) { const struct bpf_line_info *linfo; linfo = bpf_prog_linfo__lfind(prog_linfo, insn_off, 0); if (linfo && linfo != last_linfo) { btf_dump_linfo_dotlabel(btf, linfo, linum); last_linfo = linfo; } } printf("%u: ", insn_off); print_bpf_insn(&cbs, cur, true); if (opcodes) { printf("\\ \\ \\ \\ "); fprint_hex(stdout, cur, 8, " "); if (double_insn && cur <= insn_end - 1) { printf(" "); fprint_hex(stdout, cur + 1, 8, " "); } printf("\\l\\\n"); } if (cur != insn_end) printf("| "); } }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1