disasm.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
  2. * Copyright (c) 2016 Facebook
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of version 2 of the GNU General Public
  6. * License as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * General Public License for more details.
  12. */
  13. #include <linux/bpf.h>
  14. #include "disasm.h"
  15. #define __BPF_FUNC_STR_FN(x) [BPF_FUNC_ ## x] = __stringify(bpf_ ## x)
  16. static const char * const func_id_str[] = {
  17. __BPF_FUNC_MAPPER(__BPF_FUNC_STR_FN)
  18. };
  19. #undef __BPF_FUNC_STR_FN
  20. static const char *__func_get_name(const struct bpf_insn_cbs *cbs,
  21. const struct bpf_insn *insn,
  22. char *buff, size_t len)
  23. {
  24. BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
  25. if (insn->src_reg != BPF_PSEUDO_CALL &&
  26. insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
  27. func_id_str[insn->imm])
  28. return func_id_str[insn->imm];
  29. if (cbs && cbs->cb_call)
  30. return cbs->cb_call(cbs->private_data, insn);
  31. if (insn->src_reg == BPF_PSEUDO_CALL)
  32. snprintf(buff, len, "%+d", insn->imm);
  33. return buff;
  34. }
  35. static const char *__func_imm_name(const struct bpf_insn_cbs *cbs,
  36. const struct bpf_insn *insn,
  37. u64 full_imm, char *buff, size_t len)
  38. {
  39. if (cbs && cbs->cb_imm)
  40. return cbs->cb_imm(cbs->private_data, insn, full_imm);
  41. snprintf(buff, len, "0x%llx", (unsigned long long)full_imm);
  42. return buff;
  43. }
  44. const char *func_id_name(int id)
  45. {
  46. if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
  47. return func_id_str[id];
  48. else
  49. return "unknown";
  50. }
  51. const char *const bpf_class_string[8] = {
  52. [BPF_LD] = "ld",
  53. [BPF_LDX] = "ldx",
  54. [BPF_ST] = "st",
  55. [BPF_STX] = "stx",
  56. [BPF_ALU] = "alu",
  57. [BPF_JMP] = "jmp",
  58. [BPF_RET] = "BUG",
  59. [BPF_ALU64] = "alu64",
  60. };
  61. const char *const bpf_alu_string[16] = {
  62. [BPF_ADD >> 4] = "+=",
  63. [BPF_SUB >> 4] = "-=",
  64. [BPF_MUL >> 4] = "*=",
  65. [BPF_DIV >> 4] = "/=",
  66. [BPF_OR >> 4] = "|=",
  67. [BPF_AND >> 4] = "&=",
  68. [BPF_LSH >> 4] = "<<=",
  69. [BPF_RSH >> 4] = ">>=",
  70. [BPF_NEG >> 4] = "neg",
  71. [BPF_MOD >> 4] = "%=",
  72. [BPF_XOR >> 4] = "^=",
  73. [BPF_MOV >> 4] = "=",
  74. [BPF_ARSH >> 4] = "s>>=",
  75. [BPF_END >> 4] = "endian",
  76. };
  77. static const char *const bpf_ldst_string[] = {
  78. [BPF_W >> 3] = "u32",
  79. [BPF_H >> 3] = "u16",
  80. [BPF_B >> 3] = "u8",
  81. [BPF_DW >> 3] = "u64",
  82. };
  83. static const char *const bpf_jmp_string[16] = {
  84. [BPF_JA >> 4] = "jmp",
  85. [BPF_JEQ >> 4] = "==",
  86. [BPF_JGT >> 4] = ">",
  87. [BPF_JLT >> 4] = "<",
  88. [BPF_JGE >> 4] = ">=",
  89. [BPF_JLE >> 4] = "<=",
  90. [BPF_JSET >> 4] = "&",
  91. [BPF_JNE >> 4] = "!=",
  92. [BPF_JSGT >> 4] = "s>",
  93. [BPF_JSLT >> 4] = "s<",
  94. [BPF_JSGE >> 4] = "s>=",
  95. [BPF_JSLE >> 4] = "s<=",
  96. [BPF_CALL >> 4] = "call",
  97. [BPF_EXIT >> 4] = "exit",
  98. };
  99. static void print_bpf_end_insn(bpf_insn_print_t verbose,
  100. void *private_data,
  101. const struct bpf_insn *insn)
  102. {
  103. verbose(private_data, "(%02x) r%d = %s%d r%d\n",
  104. insn->code, insn->dst_reg,
  105. BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
  106. insn->imm, insn->dst_reg);
  107. }
  108. void print_bpf_insn(const struct bpf_insn_cbs *cbs,
  109. const struct bpf_insn *insn,
  110. bool allow_ptr_leaks)
  111. {
  112. const bpf_insn_print_t verbose = cbs->cb_print;
  113. u8 class = BPF_CLASS(insn->code);
  114. if (class == BPF_ALU || class == BPF_ALU64) {
  115. if (BPF_OP(insn->code) == BPF_END) {
  116. if (class == BPF_ALU64)
  117. verbose(cbs->private_data, "BUG_alu64_%02x\n", insn->code);
  118. else
  119. print_bpf_end_insn(verbose, cbs->private_data, insn);
  120. } else if (BPF_OP(insn->code) == BPF_NEG) {
  121. verbose(cbs->private_data, "(%02x) r%d = %s-r%d\n",
  122. insn->code, insn->dst_reg,
  123. class == BPF_ALU ? "(u32) " : "",
  124. insn->dst_reg);
  125. } else if (BPF_SRC(insn->code) == BPF_X) {
  126. verbose(cbs->private_data, "(%02x) %sr%d %s %sr%d\n",
  127. insn->code, class == BPF_ALU ? "(u32) " : "",
  128. insn->dst_reg,
  129. bpf_alu_string[BPF_OP(insn->code) >> 4],
  130. class == BPF_ALU ? "(u32) " : "",
  131. insn->src_reg);
  132. } else {
  133. verbose(cbs->private_data, "(%02x) %sr%d %s %s%d\n",
  134. insn->code, class == BPF_ALU ? "(u32) " : "",
  135. insn->dst_reg,
  136. bpf_alu_string[BPF_OP(insn->code) >> 4],
  137. class == BPF_ALU ? "(u32) " : "",
  138. insn->imm);
  139. }
  140. } else if (class == BPF_STX) {
  141. if (BPF_MODE(insn->code) == BPF_MEM)
  142. verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n",
  143. insn->code,
  144. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  145. insn->dst_reg,
  146. insn->off, insn->src_reg);
  147. else if (BPF_MODE(insn->code) == BPF_XADD)
  148. verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
  149. insn->code,
  150. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  151. insn->dst_reg, insn->off,
  152. insn->src_reg);
  153. else
  154. verbose(cbs->private_data, "BUG_%02x\n", insn->code);
  155. } else if (class == BPF_ST) {
  156. if (BPF_MODE(insn->code) != BPF_MEM) {
  157. verbose(cbs->private_data, "BUG_st_%02x\n", insn->code);
  158. return;
  159. }
  160. verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n",
  161. insn->code,
  162. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  163. insn->dst_reg,
  164. insn->off, insn->imm);
  165. } else if (class == BPF_LDX) {
  166. if (BPF_MODE(insn->code) != BPF_MEM) {
  167. verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code);
  168. return;
  169. }
  170. verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n",
  171. insn->code, insn->dst_reg,
  172. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  173. insn->src_reg, insn->off);
  174. } else if (class == BPF_LD) {
  175. if (BPF_MODE(insn->code) == BPF_ABS) {
  176. verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n",
  177. insn->code,
  178. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  179. insn->imm);
  180. } else if (BPF_MODE(insn->code) == BPF_IND) {
  181. verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
  182. insn->code,
  183. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  184. insn->src_reg, insn->imm);
  185. } else if (BPF_MODE(insn->code) == BPF_IMM &&
  186. BPF_SIZE(insn->code) == BPF_DW) {
  187. /* At this point, we already made sure that the second
  188. * part of the ldimm64 insn is accessible.
  189. */
  190. u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
  191. bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD;
  192. char tmp[64];
  193. if (map_ptr && !allow_ptr_leaks)
  194. imm = 0;
  195. verbose(cbs->private_data, "(%02x) r%d = %s\n",
  196. insn->code, insn->dst_reg,
  197. __func_imm_name(cbs, insn, imm,
  198. tmp, sizeof(tmp)));
  199. } else {
  200. verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code);
  201. return;
  202. }
  203. } else if (class == BPF_JMP) {
  204. u8 opcode = BPF_OP(insn->code);
  205. if (opcode == BPF_CALL) {
  206. char tmp[64];
  207. if (insn->src_reg == BPF_PSEUDO_CALL) {
  208. verbose(cbs->private_data, "(%02x) call pc%s\n",
  209. insn->code,
  210. __func_get_name(cbs, insn,
  211. tmp, sizeof(tmp)));
  212. } else {
  213. strcpy(tmp, "unknown");
  214. verbose(cbs->private_data, "(%02x) call %s#%d\n", insn->code,
  215. __func_get_name(cbs, insn,
  216. tmp, sizeof(tmp)),
  217. insn->imm);
  218. }
  219. } else if (insn->code == (BPF_JMP | BPF_JA)) {
  220. verbose(cbs->private_data, "(%02x) goto pc%+d\n",
  221. insn->code, insn->off);
  222. } else if (insn->code == (BPF_JMP | BPF_EXIT)) {
  223. verbose(cbs->private_data, "(%02x) exit\n", insn->code);
  224. } else if (BPF_SRC(insn->code) == BPF_X) {
  225. verbose(cbs->private_data, "(%02x) if r%d %s r%d goto pc%+d\n",
  226. insn->code, insn->dst_reg,
  227. bpf_jmp_string[BPF_OP(insn->code) >> 4],
  228. insn->src_reg, insn->off);
  229. } else {
  230. verbose(cbs->private_data, "(%02x) if r%d %s 0x%x goto pc%+d\n",
  231. insn->code, insn->dst_reg,
  232. bpf_jmp_string[BPF_OP(insn->code) >> 4],
  233. insn->imm, insn->off);
  234. }
  235. } else {
  236. verbose(cbs->private_data, "(%02x) %s\n",
  237. insn->code, bpf_class_string[class]);
  238. }
  239. }