decode.c 10 KB

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