decode.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <string.h>
  3. #include <objtool/check.h>
  4. #include <objtool/warn.h>
  5. #include <asm/inst.h>
  6. #include <asm/orc_types.h>
  7. #include <linux/objtool_types.h>
  8. #ifndef EM_LOONGARCH
  9. #define EM_LOONGARCH 258
  10. #endif
  11. int arch_ftrace_match(char *name)
  12. {
  13. return !strcmp(name, "_mcount");
  14. }
  15. unsigned long arch_jump_destination(struct instruction *insn)
  16. {
  17. return insn->offset + (insn->immediate << 2);
  18. }
  19. unsigned long arch_dest_reloc_offset(int addend)
  20. {
  21. return addend;
  22. }
  23. bool arch_pc_relative_reloc(struct reloc *reloc)
  24. {
  25. return false;
  26. }
  27. bool arch_callee_saved_reg(unsigned char reg)
  28. {
  29. switch (reg) {
  30. case CFI_RA:
  31. case CFI_FP:
  32. case CFI_S0 ... CFI_S8:
  33. return true;
  34. default:
  35. return false;
  36. }
  37. }
  38. int arch_decode_hint_reg(u8 sp_reg, int *base)
  39. {
  40. switch (sp_reg) {
  41. case ORC_REG_UNDEFINED:
  42. *base = CFI_UNDEFINED;
  43. break;
  44. case ORC_REG_SP:
  45. *base = CFI_SP;
  46. break;
  47. case ORC_REG_FP:
  48. *base = CFI_FP;
  49. break;
  50. default:
  51. return -1;
  52. }
  53. return 0;
  54. }
  55. static bool is_loongarch(const struct elf *elf)
  56. {
  57. if (elf->ehdr.e_machine == EM_LOONGARCH)
  58. return true;
  59. WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
  60. return false;
  61. }
  62. #define ADD_OP(op) \
  63. if (!(op = calloc(1, sizeof(*op)))) \
  64. return -1; \
  65. else for (*ops_list = op, ops_list = &op->next; op; op = NULL)
  66. static bool decode_insn_reg0i26_fomat(union loongarch_instruction inst,
  67. struct instruction *insn)
  68. {
  69. switch (inst.reg0i26_format.opcode) {
  70. case b_op:
  71. insn->type = INSN_JUMP_UNCONDITIONAL;
  72. insn->immediate = sign_extend64(inst.reg0i26_format.immediate_h << 16 |
  73. inst.reg0i26_format.immediate_l, 25);
  74. break;
  75. case bl_op:
  76. insn->type = INSN_CALL;
  77. insn->immediate = sign_extend64(inst.reg0i26_format.immediate_h << 16 |
  78. inst.reg0i26_format.immediate_l, 25);
  79. break;
  80. default:
  81. return false;
  82. }
  83. return true;
  84. }
  85. static bool decode_insn_reg1i21_fomat(union loongarch_instruction inst,
  86. struct instruction *insn)
  87. {
  88. switch (inst.reg1i21_format.opcode) {
  89. case beqz_op:
  90. case bnez_op:
  91. case bceqz_op:
  92. insn->type = INSN_JUMP_CONDITIONAL;
  93. insn->immediate = sign_extend64(inst.reg1i21_format.immediate_h << 16 |
  94. inst.reg1i21_format.immediate_l, 20);
  95. break;
  96. default:
  97. return false;
  98. }
  99. return true;
  100. }
  101. static bool decode_insn_reg2i12_fomat(union loongarch_instruction inst,
  102. struct instruction *insn,
  103. struct stack_op **ops_list,
  104. struct stack_op *op)
  105. {
  106. switch (inst.reg2i12_format.opcode) {
  107. case addid_op:
  108. if ((inst.reg2i12_format.rd == CFI_SP) || (inst.reg2i12_format.rj == CFI_SP)) {
  109. /* addi.d sp,sp,si12 or addi.d fp,sp,si12 or addi.d sp,fp,si12 */
  110. insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
  111. ADD_OP(op) {
  112. op->src.type = OP_SRC_ADD;
  113. op->src.reg = inst.reg2i12_format.rj;
  114. op->src.offset = insn->immediate;
  115. op->dest.type = OP_DEST_REG;
  116. op->dest.reg = inst.reg2i12_format.rd;
  117. }
  118. }
  119. if ((inst.reg2i12_format.rd == CFI_SP) && (inst.reg2i12_format.rj == CFI_FP)) {
  120. /* addi.d sp,fp,si12 */
  121. struct symbol *func = find_func_containing(insn->sec, insn->offset);
  122. if (!func)
  123. return false;
  124. func->frame_pointer = true;
  125. }
  126. break;
  127. case ldd_op:
  128. if (inst.reg2i12_format.rj == CFI_SP) {
  129. /* ld.d rd,sp,si12 */
  130. insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
  131. ADD_OP(op) {
  132. op->src.type = OP_SRC_REG_INDIRECT;
  133. op->src.reg = CFI_SP;
  134. op->src.offset = insn->immediate;
  135. op->dest.type = OP_DEST_REG;
  136. op->dest.reg = inst.reg2i12_format.rd;
  137. }
  138. }
  139. break;
  140. case std_op:
  141. if (inst.reg2i12_format.rj == CFI_SP) {
  142. /* st.d rd,sp,si12 */
  143. insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11);
  144. ADD_OP(op) {
  145. op->src.type = OP_SRC_REG;
  146. op->src.reg = inst.reg2i12_format.rd;
  147. op->dest.type = OP_DEST_REG_INDIRECT;
  148. op->dest.reg = CFI_SP;
  149. op->dest.offset = insn->immediate;
  150. }
  151. }
  152. break;
  153. case andi_op:
  154. if (inst.reg2i12_format.rd == 0 &&
  155. inst.reg2i12_format.rj == 0 &&
  156. inst.reg2i12_format.immediate == 0)
  157. /* andi r0,r0,0 */
  158. insn->type = INSN_NOP;
  159. break;
  160. default:
  161. return false;
  162. }
  163. return true;
  164. }
  165. static bool decode_insn_reg2i14_fomat(union loongarch_instruction inst,
  166. struct instruction *insn,
  167. struct stack_op **ops_list,
  168. struct stack_op *op)
  169. {
  170. switch (inst.reg2i14_format.opcode) {
  171. case ldptrd_op:
  172. if (inst.reg2i14_format.rj == CFI_SP) {
  173. /* ldptr.d rd,sp,si14 */
  174. insn->immediate = sign_extend64(inst.reg2i14_format.immediate, 13);
  175. ADD_OP(op) {
  176. op->src.type = OP_SRC_REG_INDIRECT;
  177. op->src.reg = CFI_SP;
  178. op->src.offset = insn->immediate;
  179. op->dest.type = OP_DEST_REG;
  180. op->dest.reg = inst.reg2i14_format.rd;
  181. }
  182. }
  183. break;
  184. case stptrd_op:
  185. if (inst.reg2i14_format.rj == CFI_SP) {
  186. /* stptr.d ra,sp,0 */
  187. if (inst.reg2i14_format.rd == LOONGARCH_GPR_RA &&
  188. inst.reg2i14_format.immediate == 0)
  189. break;
  190. /* stptr.d rd,sp,si14 */
  191. insn->immediate = sign_extend64(inst.reg2i14_format.immediate, 13);
  192. ADD_OP(op) {
  193. op->src.type = OP_SRC_REG;
  194. op->src.reg = inst.reg2i14_format.rd;
  195. op->dest.type = OP_DEST_REG_INDIRECT;
  196. op->dest.reg = CFI_SP;
  197. op->dest.offset = insn->immediate;
  198. }
  199. }
  200. break;
  201. default:
  202. return false;
  203. }
  204. return true;
  205. }
  206. static bool decode_insn_reg2i16_fomat(union loongarch_instruction inst,
  207. struct instruction *insn)
  208. {
  209. switch (inst.reg2i16_format.opcode) {
  210. case jirl_op:
  211. if (inst.reg2i16_format.rd == 0 &&
  212. inst.reg2i16_format.rj == CFI_RA &&
  213. inst.reg2i16_format.immediate == 0) {
  214. /* jirl r0,ra,0 */
  215. insn->type = INSN_RETURN;
  216. } else if (inst.reg2i16_format.rd == CFI_RA) {
  217. /* jirl ra,rj,offs16 */
  218. insn->type = INSN_CALL_DYNAMIC;
  219. } else if (inst.reg2i16_format.rd == CFI_A0 &&
  220. inst.reg2i16_format.immediate == 0) {
  221. /*
  222. * jirl a0,t0,0
  223. * this is a special case in loongarch_suspend_enter,
  224. * just treat it as a call instruction.
  225. */
  226. insn->type = INSN_CALL_DYNAMIC;
  227. } else if (inst.reg2i16_format.rd == 0 &&
  228. inst.reg2i16_format.immediate == 0) {
  229. /* jirl r0,rj,0 */
  230. insn->type = INSN_JUMP_DYNAMIC;
  231. } else if (inst.reg2i16_format.rd == 0 &&
  232. inst.reg2i16_format.immediate != 0) {
  233. /*
  234. * jirl r0,t0,12
  235. * this is a rare case in JUMP_VIRT_ADDR,
  236. * just ignore it due to it is harmless for tracing.
  237. */
  238. break;
  239. } else {
  240. /* jirl rd,rj,offs16 */
  241. insn->type = INSN_JUMP_UNCONDITIONAL;
  242. insn->immediate = sign_extend64(inst.reg2i16_format.immediate, 15);
  243. }
  244. break;
  245. case beq_op:
  246. case bne_op:
  247. case blt_op:
  248. case bge_op:
  249. case bltu_op:
  250. case bgeu_op:
  251. insn->type = INSN_JUMP_CONDITIONAL;
  252. insn->immediate = sign_extend64(inst.reg2i16_format.immediate, 15);
  253. break;
  254. default:
  255. return false;
  256. }
  257. return true;
  258. }
  259. static bool decode_insn_reg3_fomat(union loongarch_instruction inst,
  260. struct instruction *insn)
  261. {
  262. switch (inst.reg3_format.opcode) {
  263. case amswapw_op:
  264. if (inst.reg3_format.rd == LOONGARCH_GPR_ZERO &&
  265. inst.reg3_format.rk == LOONGARCH_GPR_RA &&
  266. inst.reg3_format.rj == LOONGARCH_GPR_ZERO) {
  267. /* amswap.w $zero, $ra, $zero */
  268. insn->type = INSN_BUG;
  269. }
  270. break;
  271. default:
  272. return false;
  273. }
  274. return true;
  275. }
  276. int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
  277. unsigned long offset, unsigned int maxlen,
  278. struct instruction *insn)
  279. {
  280. struct stack_op **ops_list = &insn->stack_ops;
  281. const struct elf *elf = file->elf;
  282. struct stack_op *op = NULL;
  283. union loongarch_instruction inst;
  284. if (!is_loongarch(elf))
  285. return -1;
  286. if (maxlen < LOONGARCH_INSN_SIZE)
  287. return 0;
  288. insn->len = LOONGARCH_INSN_SIZE;
  289. insn->type = INSN_OTHER;
  290. insn->immediate = 0;
  291. inst = *(union loongarch_instruction *)(sec->data->d_buf + offset);
  292. if (decode_insn_reg0i26_fomat(inst, insn))
  293. return 0;
  294. if (decode_insn_reg1i21_fomat(inst, insn))
  295. return 0;
  296. if (decode_insn_reg2i12_fomat(inst, insn, ops_list, op))
  297. return 0;
  298. if (decode_insn_reg2i14_fomat(inst, insn, ops_list, op))
  299. return 0;
  300. if (decode_insn_reg2i16_fomat(inst, insn))
  301. return 0;
  302. if (decode_insn_reg3_fomat(inst, insn))
  303. return 0;
  304. if (inst.word == 0) {
  305. /* andi $zero, $zero, 0x0 */
  306. insn->type = INSN_NOP;
  307. } else if (inst.reg0i15_format.opcode == break_op &&
  308. inst.reg0i15_format.immediate == 0x0) {
  309. /* break 0x0 */
  310. insn->type = INSN_TRAP;
  311. } else if (inst.reg0i15_format.opcode == break_op &&
  312. inst.reg0i15_format.immediate == 0x1) {
  313. /* break 0x1 */
  314. insn->type = INSN_BUG;
  315. } else if (inst.reg2_format.opcode == ertn_op) {
  316. /* ertn */
  317. insn->type = INSN_RETURN;
  318. }
  319. return 0;
  320. }
  321. const char *arch_nop_insn(int len)
  322. {
  323. static u32 nop;
  324. if (len != LOONGARCH_INSN_SIZE)
  325. WARN("invalid NOP size: %d\n", len);
  326. nop = LOONGARCH_INSN_NOP;
  327. return (const char *)&nop;
  328. }
  329. const char *arch_ret_insn(int len)
  330. {
  331. static u32 ret;
  332. if (len != LOONGARCH_INSN_SIZE)
  333. WARN("invalid RET size: %d\n", len);
  334. emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
  335. return (const char *)&ret;
  336. }
  337. void arch_initial_func_cfi_state(struct cfi_init_state *state)
  338. {
  339. int i;
  340. for (i = 0; i < CFI_NUM_REGS; i++) {
  341. state->regs[i].base = CFI_UNDEFINED;
  342. state->regs[i].offset = 0;
  343. }
  344. /* initial CFA (call frame address) */
  345. state->cfa.base = CFI_SP;
  346. state->cfa.offset = 0;
  347. }