jit_disasm.c 3.8 KB

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