jit_disasm.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 <[email protected]>
  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 <stdlib.h>
  18. #include <assert.h>
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include <bfd.h>
  22. #include <dis-asm.h>
  23. #include <sys/stat.h>
  24. #include <limits.h>
  25. #include <bpf/libbpf.h>
  26. #include <tools/dis-asm-compat.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 printf_json(void *out, const char *fmt, va_list ap)
  39. {
  40. char *s;
  41. int err;
  42. err = vasprintf(&s, fmt, ap);
  43. if (err < 0)
  44. return -1;
  45. if (!oper_count) {
  46. int i;
  47. /* Strip trailing spaces */
  48. i = strlen(s) - 1;
  49. while (s[i] == ' ')
  50. s[i--] = '\0';
  51. jsonw_string_field(json_wtr, "operation", s);
  52. jsonw_name(json_wtr, "operands");
  53. jsonw_start_array(json_wtr);
  54. oper_count++;
  55. } else if (!strcmp(fmt, ",")) {
  56. /* Skip */
  57. } else {
  58. jsonw_string(json_wtr, s);
  59. oper_count++;
  60. }
  61. free(s);
  62. return 0;
  63. }
  64. static int fprintf_json(void *out, const char *fmt, ...)
  65. {
  66. va_list ap;
  67. int r;
  68. va_start(ap, fmt);
  69. r = printf_json(out, fmt, ap);
  70. va_end(ap);
  71. return r;
  72. }
  73. static int fprintf_json_styled(void *out,
  74. enum disassembler_style style __maybe_unused,
  75. const char *fmt, ...)
  76. {
  77. va_list ap;
  78. int r;
  79. va_start(ap, fmt);
  80. r = printf_json(out, fmt, ap);
  81. va_end(ap);
  82. return r;
  83. }
  84. void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
  85. const char *arch, const char *disassembler_options,
  86. const struct btf *btf,
  87. const struct bpf_prog_linfo *prog_linfo,
  88. __u64 func_ksym, unsigned int func_idx,
  89. bool linum)
  90. {
  91. const struct bpf_line_info *linfo = NULL;
  92. disassembler_ftype disassemble;
  93. struct disassemble_info info;
  94. unsigned int nr_skip = 0;
  95. int count, i, pc = 0;
  96. char tpath[PATH_MAX];
  97. bfd *bfdf;
  98. if (!len)
  99. return;
  100. memset(tpath, 0, sizeof(tpath));
  101. get_exec_path(tpath, sizeof(tpath));
  102. bfdf = bfd_openr(tpath, NULL);
  103. assert(bfdf);
  104. assert(bfd_check_format(bfdf, bfd_object));
  105. if (json_output)
  106. init_disassemble_info_compat(&info, stdout,
  107. (fprintf_ftype) fprintf_json,
  108. fprintf_json_styled);
  109. else
  110. init_disassemble_info_compat(&info, stdout,
  111. (fprintf_ftype) fprintf,
  112. fprintf_styled);
  113. /* Update architecture info for offload. */
  114. if (arch) {
  115. const bfd_arch_info_type *inf = bfd_scan_arch(arch);
  116. if (inf) {
  117. bfdf->arch_info = inf;
  118. } else {
  119. p_err("No libbfd support for %s", arch);
  120. return;
  121. }
  122. }
  123. info.arch = bfd_get_arch(bfdf);
  124. info.mach = bfd_get_mach(bfdf);
  125. if (disassembler_options)
  126. info.disassembler_options = disassembler_options;
  127. info.buffer = image;
  128. info.buffer_length = len;
  129. disassemble_init_for_target(&info);
  130. #ifdef DISASM_FOUR_ARGS_SIGNATURE
  131. disassemble = disassembler(info.arch,
  132. bfd_big_endian(bfdf),
  133. info.mach,
  134. bfdf);
  135. #else
  136. disassemble = disassembler(bfdf);
  137. #endif
  138. assert(disassemble);
  139. if (json_output)
  140. jsonw_start_array(json_wtr);
  141. do {
  142. if (prog_linfo) {
  143. linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
  144. func_ksym + pc,
  145. func_idx,
  146. nr_skip);
  147. if (linfo)
  148. nr_skip++;
  149. }
  150. if (json_output) {
  151. jsonw_start_object(json_wtr);
  152. oper_count = 0;
  153. if (linfo)
  154. btf_dump_linfo_json(btf, linfo, linum);
  155. jsonw_name(json_wtr, "pc");
  156. jsonw_printf(json_wtr, "\"0x%x\"", pc);
  157. } else {
  158. if (linfo)
  159. btf_dump_linfo_plain(btf, linfo, "; ",
  160. linum);
  161. printf("%4x:\t", pc);
  162. }
  163. count = disassemble(pc, &info);
  164. if (json_output) {
  165. /* Operand array, was started in fprintf_json. Before
  166. * that, make sure we have a _null_ value if no operand
  167. * other than operation code was present.
  168. */
  169. if (oper_count == 1)
  170. jsonw_null(json_wtr);
  171. jsonw_end_array(json_wtr);
  172. }
  173. if (opcodes) {
  174. if (json_output) {
  175. jsonw_name(json_wtr, "opcodes");
  176. jsonw_start_array(json_wtr);
  177. for (i = 0; i < count; ++i)
  178. jsonw_printf(json_wtr, "\"0x%02hhx\"",
  179. (uint8_t)image[pc + i]);
  180. jsonw_end_array(json_wtr);
  181. } else {
  182. printf("\n\t");
  183. for (i = 0; i < count; ++i)
  184. printf("%02x ",
  185. (uint8_t)image[pc + i]);
  186. }
  187. }
  188. if (json_output)
  189. jsonw_end_object(json_wtr);
  190. else
  191. printf("\n");
  192. pc += count;
  193. } while (count > 0 && pc < len);
  194. if (json_output)
  195. jsonw_end_array(json_wtr);
  196. bfd_close(bfdf);
  197. }
  198. int disasm_init(void)
  199. {
  200. bfd_init();
  201. return 0;
  202. }