jit_disasm.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /*
  3. * Based on:
  4. *
  5. * Minimal BPF JIT image disassembler
  6. *
  7. * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
  8. * debugging or verification purposes.
  9. *
  10. * Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
  11. * Licensed under the GNU General Public License, version 2.0 (GPLv2)
  12. */
  13. #define _GNU_SOURCE
  14. #include <stdio.h>
  15. #include <stdarg.h>
  16. #include <stdint.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <assert.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <bfd.h>
  23. #include <dis-asm.h>
  24. #include <sys/stat.h>
  25. #include <limits.h>
  26. #include <libbpf.h>
  27. #include "json_writer.h"
  28. #include "main.h"
  29. static void get_exec_path(char *tpath, size_t size)
  30. {
  31. const char *path = "/proc/self/exe";
  32. ssize_t len;
  33. len = readlink(path, tpath, size - 1);
  34. assert(len > 0);
  35. tpath[len] = 0;
  36. }
  37. static int oper_count;
  38. static int fprintf_json(void *out, const char *fmt, ...)
  39. {
  40. va_list ap;
  41. char *s;
  42. int err;
  43. va_start(ap, fmt);
  44. err = vasprintf(&s, fmt, ap);
  45. va_end(ap);
  46. if (err < 0)
  47. return -1;
  48. if (!oper_count) {
  49. int i;
  50. /* Strip trailing spaces */
  51. i = strlen(s) - 1;
  52. while (s[i] == ' ')
  53. s[i--] = '\0';
  54. jsonw_string_field(json_wtr, "operation", s);
  55. jsonw_name(json_wtr, "operands");
  56. jsonw_start_array(json_wtr);
  57. oper_count++;
  58. } else if (!strcmp(fmt, ",")) {
  59. /* Skip */
  60. } else {
  61. jsonw_string(json_wtr, s);
  62. oper_count++;
  63. }
  64. free(s);
  65. return 0;
  66. }
  67. void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
  68. const char *arch, const char *disassembler_options,
  69. const struct btf *btf,
  70. const struct bpf_prog_linfo *prog_linfo,
  71. __u64 func_ksym, unsigned int func_idx,
  72. bool linum)
  73. {
  74. const struct bpf_line_info *linfo = NULL;
  75. disassembler_ftype disassemble;
  76. struct disassemble_info info;
  77. unsigned int nr_skip = 0;
  78. int count, i, pc = 0;
  79. char tpath[PATH_MAX];
  80. bfd *bfdf;
  81. if (!len)
  82. return;
  83. memset(tpath, 0, sizeof(tpath));
  84. get_exec_path(tpath, sizeof(tpath));
  85. bfdf = bfd_openr(tpath, NULL);
  86. assert(bfdf);
  87. assert(bfd_check_format(bfdf, bfd_object));
  88. if (json_output)
  89. init_disassemble_info(&info, stdout,
  90. (fprintf_ftype) fprintf_json);
  91. else
  92. init_disassemble_info(&info, stdout,
  93. (fprintf_ftype) fprintf);
  94. /* Update architecture info for offload. */
  95. if (arch) {
  96. const bfd_arch_info_type *inf = bfd_scan_arch(arch);
  97. if (inf) {
  98. bfdf->arch_info = inf;
  99. } else {
  100. p_err("No libbfd support for %s", arch);
  101. return;
  102. }
  103. }
  104. info.arch = bfd_get_arch(bfdf);
  105. info.mach = bfd_get_mach(bfdf);
  106. if (disassembler_options)
  107. info.disassembler_options = disassembler_options;
  108. info.buffer = image;
  109. info.buffer_length = len;
  110. disassemble_init_for_target(&info);
  111. #ifdef DISASM_FOUR_ARGS_SIGNATURE
  112. disassemble = disassembler(info.arch,
  113. bfd_big_endian(bfdf),
  114. info.mach,
  115. bfdf);
  116. #else
  117. disassemble = disassembler(bfdf);
  118. #endif
  119. assert(disassemble);
  120. if (json_output)
  121. jsonw_start_array(json_wtr);
  122. do {
  123. if (prog_linfo) {
  124. linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
  125. func_ksym + pc,
  126. func_idx,
  127. nr_skip);
  128. if (linfo)
  129. nr_skip++;
  130. }
  131. if (json_output) {
  132. jsonw_start_object(json_wtr);
  133. oper_count = 0;
  134. if (linfo)
  135. btf_dump_linfo_json(btf, linfo, linum);
  136. jsonw_name(json_wtr, "pc");
  137. jsonw_printf(json_wtr, "\"0x%x\"", pc);
  138. } else {
  139. if (linfo)
  140. btf_dump_linfo_plain(btf, linfo, "; ",
  141. linum);
  142. printf("%4x:\t", pc);
  143. }
  144. count = disassemble(pc, &info);
  145. if (json_output) {
  146. /* Operand array, was started in fprintf_json. Before
  147. * that, make sure we have a _null_ value if no operand
  148. * other than operation code was present.
  149. */
  150. if (oper_count == 1)
  151. jsonw_null(json_wtr);
  152. jsonw_end_array(json_wtr);
  153. }
  154. if (opcodes) {
  155. if (json_output) {
  156. jsonw_name(json_wtr, "opcodes");
  157. jsonw_start_array(json_wtr);
  158. for (i = 0; i < count; ++i)
  159. jsonw_printf(json_wtr, "\"0x%02hhx\"",
  160. (uint8_t)image[pc + i]);
  161. jsonw_end_array(json_wtr);
  162. } else {
  163. printf("\n\t");
  164. for (i = 0; i < count; ++i)
  165. printf("%02x ",
  166. (uint8_t)image[pc + i]);
  167. }
  168. }
  169. if (json_output)
  170. jsonw_end_object(json_wtr);
  171. else
  172. printf("\n");
  173. pc += count;
  174. } while (count > 0 && pc < len);
  175. if (json_output)
  176. jsonw_end_array(json_wtr);
  177. bfd_close(bfdf);
  178. }
  179. int disasm_init(void)
  180. {
  181. bfd_init();
  182. return 0;
  183. }