jit_disasm.c 3.7 KB

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