disasm.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. const char *func_id_name(int id)
  21. {
  22. BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
  23. if (id >= 0 && id < __BPF_FUNC_MAX_ID && func_id_str[id])
  24. return func_id_str[id];
  25. else
  26. return "unknown";
  27. }
  28. const char *const bpf_class_string[8] = {
  29. [BPF_LD] = "ld",
  30. [BPF_LDX] = "ldx",
  31. [BPF_ST] = "st",
  32. [BPF_STX] = "stx",
  33. [BPF_ALU] = "alu",
  34. [BPF_JMP] = "jmp",
  35. [BPF_RET] = "BUG",
  36. [BPF_ALU64] = "alu64",
  37. };
  38. const char *const bpf_alu_string[16] = {
  39. [BPF_ADD >> 4] = "+=",
  40. [BPF_SUB >> 4] = "-=",
  41. [BPF_MUL >> 4] = "*=",
  42. [BPF_DIV >> 4] = "/=",
  43. [BPF_OR >> 4] = "|=",
  44. [BPF_AND >> 4] = "&=",
  45. [BPF_LSH >> 4] = "<<=",
  46. [BPF_RSH >> 4] = ">>=",
  47. [BPF_NEG >> 4] = "neg",
  48. [BPF_MOD >> 4] = "%=",
  49. [BPF_XOR >> 4] = "^=",
  50. [BPF_MOV >> 4] = "=",
  51. [BPF_ARSH >> 4] = "s>>=",
  52. [BPF_END >> 4] = "endian",
  53. };
  54. static const char *const bpf_ldst_string[] = {
  55. [BPF_W >> 3] = "u32",
  56. [BPF_H >> 3] = "u16",
  57. [BPF_B >> 3] = "u8",
  58. [BPF_DW >> 3] = "u64",
  59. };
  60. static const char *const bpf_jmp_string[16] = {
  61. [BPF_JA >> 4] = "jmp",
  62. [BPF_JEQ >> 4] = "==",
  63. [BPF_JGT >> 4] = ">",
  64. [BPF_JLT >> 4] = "<",
  65. [BPF_JGE >> 4] = ">=",
  66. [BPF_JLE >> 4] = "<=",
  67. [BPF_JSET >> 4] = "&",
  68. [BPF_JNE >> 4] = "!=",
  69. [BPF_JSGT >> 4] = "s>",
  70. [BPF_JSLT >> 4] = "s<",
  71. [BPF_JSGE >> 4] = "s>=",
  72. [BPF_JSLE >> 4] = "s<=",
  73. [BPF_CALL >> 4] = "call",
  74. [BPF_EXIT >> 4] = "exit",
  75. };
  76. static void print_bpf_end_insn(bpf_insn_print_cb verbose,
  77. struct bpf_verifier_env *env,
  78. const struct bpf_insn *insn)
  79. {
  80. verbose(env, "(%02x) r%d = %s%d r%d\n", insn->code, insn->dst_reg,
  81. BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le",
  82. insn->imm, insn->dst_reg);
  83. }
  84. void print_bpf_insn(bpf_insn_print_cb verbose, struct bpf_verifier_env *env,
  85. const struct bpf_insn *insn, bool allow_ptr_leaks)
  86. {
  87. u8 class = BPF_CLASS(insn->code);
  88. if (class == BPF_ALU || class == BPF_ALU64) {
  89. if (BPF_OP(insn->code) == BPF_END) {
  90. if (class == BPF_ALU64)
  91. verbose(env, "BUG_alu64_%02x\n", insn->code);
  92. else
  93. print_bpf_end_insn(verbose, env, insn);
  94. } else if (BPF_OP(insn->code) == BPF_NEG) {
  95. verbose(env, "(%02x) r%d = %s-r%d\n",
  96. insn->code, insn->dst_reg,
  97. class == BPF_ALU ? "(u32) " : "",
  98. insn->dst_reg);
  99. } else if (BPF_SRC(insn->code) == BPF_X) {
  100. verbose(env, "(%02x) %sr%d %s %sr%d\n",
  101. insn->code, class == BPF_ALU ? "(u32) " : "",
  102. insn->dst_reg,
  103. bpf_alu_string[BPF_OP(insn->code) >> 4],
  104. class == BPF_ALU ? "(u32) " : "",
  105. insn->src_reg);
  106. } else {
  107. verbose(env, "(%02x) %sr%d %s %s%d\n",
  108. insn->code, class == BPF_ALU ? "(u32) " : "",
  109. insn->dst_reg,
  110. bpf_alu_string[BPF_OP(insn->code) >> 4],
  111. class == BPF_ALU ? "(u32) " : "",
  112. insn->imm);
  113. }
  114. } else if (class == BPF_STX) {
  115. if (BPF_MODE(insn->code) == BPF_MEM)
  116. verbose(env, "(%02x) *(%s *)(r%d %+d) = r%d\n",
  117. insn->code,
  118. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  119. insn->dst_reg,
  120. insn->off, insn->src_reg);
  121. else if (BPF_MODE(insn->code) == BPF_XADD)
  122. verbose(env, "(%02x) lock *(%s *)(r%d %+d) += r%d\n",
  123. insn->code,
  124. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  125. insn->dst_reg, insn->off,
  126. insn->src_reg);
  127. else
  128. verbose(env, "BUG_%02x\n", insn->code);
  129. } else if (class == BPF_ST) {
  130. if (BPF_MODE(insn->code) != BPF_MEM) {
  131. verbose(env, "BUG_st_%02x\n", insn->code);
  132. return;
  133. }
  134. verbose(env, "(%02x) *(%s *)(r%d %+d) = %d\n",
  135. insn->code,
  136. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  137. insn->dst_reg,
  138. insn->off, insn->imm);
  139. } else if (class == BPF_LDX) {
  140. if (BPF_MODE(insn->code) != BPF_MEM) {
  141. verbose(env, "BUG_ldx_%02x\n", insn->code);
  142. return;
  143. }
  144. verbose(env, "(%02x) r%d = *(%s *)(r%d %+d)\n",
  145. insn->code, insn->dst_reg,
  146. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  147. insn->src_reg, insn->off);
  148. } else if (class == BPF_LD) {
  149. if (BPF_MODE(insn->code) == BPF_ABS) {
  150. verbose(env, "(%02x) r0 = *(%s *)skb[%d]\n",
  151. insn->code,
  152. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  153. insn->imm);
  154. } else if (BPF_MODE(insn->code) == BPF_IND) {
  155. verbose(env, "(%02x) r0 = *(%s *)skb[r%d + %d]\n",
  156. insn->code,
  157. bpf_ldst_string[BPF_SIZE(insn->code) >> 3],
  158. insn->src_reg, insn->imm);
  159. } else if (BPF_MODE(insn->code) == BPF_IMM &&
  160. BPF_SIZE(insn->code) == BPF_DW) {
  161. /* At this point, we already made sure that the second
  162. * part of the ldimm64 insn is accessible.
  163. */
  164. u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
  165. bool map_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD;
  166. if (map_ptr && !allow_ptr_leaks)
  167. imm = 0;
  168. verbose(env, "(%02x) r%d = 0x%llx\n", insn->code,
  169. insn->dst_reg, (unsigned long long)imm);
  170. } else {
  171. verbose(env, "BUG_ld_%02x\n", insn->code);
  172. return;
  173. }
  174. } else if (class == BPF_JMP) {
  175. u8 opcode = BPF_OP(insn->code);
  176. if (opcode == BPF_CALL) {
  177. verbose(env, "(%02x) call %s#%d\n", insn->code,
  178. func_id_name(insn->imm), insn->imm);
  179. } else if (insn->code == (BPF_JMP | BPF_JA)) {
  180. verbose(env, "(%02x) goto pc%+d\n",
  181. insn->code, insn->off);
  182. } else if (insn->code == (BPF_JMP | BPF_EXIT)) {
  183. verbose(env, "(%02x) exit\n", insn->code);
  184. } else if (BPF_SRC(insn->code) == BPF_X) {
  185. verbose(env, "(%02x) if r%d %s r%d goto pc%+d\n",
  186. insn->code, insn->dst_reg,
  187. bpf_jmp_string[BPF_OP(insn->code) >> 4],
  188. insn->src_reg, insn->off);
  189. } else {
  190. verbose(env, "(%02x) if r%d %s 0x%x goto pc%+d\n",
  191. insn->code, insn->dst_reg,
  192. bpf_jmp_string[BPF_OP(insn->code) >> 4],
  193. insn->imm, insn->off);
  194. }
  195. } else {
  196. verbose(env, "(%02x) %s\n",
  197. insn->code, bpf_class_string[class]);
  198. }
  199. }