disasm_helpers.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2. #include <bpf/bpf.h>
  3. #include "disasm.h"
  4. struct print_insn_context {
  5. char scratch[16];
  6. char *buf;
  7. size_t sz;
  8. };
  9. static void print_insn_cb(void *private_data, const char *fmt, ...)
  10. {
  11. struct print_insn_context *ctx = private_data;
  12. va_list args;
  13. va_start(args, fmt);
  14. vsnprintf(ctx->buf, ctx->sz, fmt, args);
  15. va_end(args);
  16. }
  17. static const char *print_call_cb(void *private_data, const struct bpf_insn *insn)
  18. {
  19. struct print_insn_context *ctx = private_data;
  20. /* For pseudo calls verifier.c:jit_subprogs() hides original
  21. * imm to insn->off and changes insn->imm to be an index of
  22. * the subprog instead.
  23. */
  24. if (insn->src_reg == BPF_PSEUDO_CALL) {
  25. snprintf(ctx->scratch, sizeof(ctx->scratch), "%+d", insn->off);
  26. return ctx->scratch;
  27. }
  28. return NULL;
  29. }
  30. struct bpf_insn *disasm_insn(struct bpf_insn *insn, char *buf, size_t buf_sz)
  31. {
  32. struct print_insn_context ctx = {
  33. .buf = buf,
  34. .sz = buf_sz,
  35. };
  36. struct bpf_insn_cbs cbs = {
  37. .cb_print = print_insn_cb,
  38. .cb_call = print_call_cb,
  39. .private_data = &ctx,
  40. };
  41. char *tmp, *pfx_end, *sfx_start;
  42. bool double_insn;
  43. int len;
  44. print_bpf_insn(&cbs, insn, true);
  45. /* We share code with kernel BPF disassembler, it adds '(FF) ' prefix
  46. * for each instruction (FF stands for instruction `code` byte).
  47. * Remove the prefix inplace, and also simplify call instructions.
  48. * E.g.: "(85) call foo#10" -> "call foo".
  49. * Also remove newline in the end (the 'max(strlen(buf) - 1, 0)' thing).
  50. */
  51. pfx_end = buf + 5;
  52. sfx_start = buf + max((int)strlen(buf) - 1, 0);
  53. if (strncmp(pfx_end, "call ", 5) == 0 && (tmp = strrchr(buf, '#')))
  54. sfx_start = tmp;
  55. len = sfx_start - pfx_end;
  56. memmove(buf, pfx_end, len);
  57. buf[len] = 0;
  58. double_insn = insn->code == (BPF_LD | BPF_IMM | BPF_DW);
  59. return insn + (double_insn ? 2 : 1);
  60. }