Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#define unlikely(cond) (cond)
10#include <asm/insn.h>
11#include "../../../arch/x86/lib/inat.c"
12#include "../../../arch/x86/lib/insn.c"
13
14#define CONFIG_64BIT 1
15#include <asm/nops.h>
16
17#include <asm/orc_types.h>
18#include <objtool/check.h>
19#include <objtool/disas.h>
20#include <objtool/elf.h>
21#include <objtool/arch.h>
22#include <objtool/warn.h>
23#include <objtool/builtin.h>
24#include <arch/elf.h>
25
26const char *arch_reg_name[CFI_NUM_REGS] = {
27 "rax", "rcx", "rdx", "rbx",
28 "rsp", "rbp", "rsi", "rdi",
29 "r8", "r9", "r10", "r11",
30 "r12", "r13", "r14", "r15",
31 "ra"
32};
33
34int arch_ftrace_match(const char *name)
35{
36 return !strcmp(name, "__fentry__");
37}
38
39static int is_x86_64(const struct elf *elf)
40{
41 switch (elf->ehdr.e_machine) {
42 case EM_X86_64:
43 return 1;
44 case EM_386:
45 return 0;
46 default:
47 ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
48 return -1;
49 }
50}
51
52bool arch_callee_saved_reg(unsigned char reg)
53{
54 switch (reg) {
55 case CFI_BP:
56 case CFI_BX:
57 case CFI_R12:
58 case CFI_R13:
59 case CFI_R14:
60 case CFI_R15:
61 return true;
62
63 case CFI_AX:
64 case CFI_CX:
65 case CFI_DX:
66 case CFI_SI:
67 case CFI_DI:
68 case CFI_SP:
69 case CFI_R8:
70 case CFI_R9:
71 case CFI_R10:
72 case CFI_R11:
73 case CFI_RA:
74 default:
75 return false;
76 }
77}
78
79/* Undo the effects of __pa_symbol() if necessary */
80static unsigned long phys_to_virt(unsigned long pa)
81{
82 s64 va = pa;
83
84 if (va > 0)
85 va &= ~(0x80000000);
86
87 return va;
88}
89
90s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc)
91{
92 s64 addend = reloc_addend(reloc);
93
94 if (arch_pc_relative_reloc(reloc))
95 addend += insn->offset + insn->len - reloc_offset(reloc);
96
97 return phys_to_virt(addend);
98}
99
100static void scan_for_insn(struct section *sec, unsigned long offset,
101 unsigned long *insn_off, unsigned int *insn_len)
102{
103 unsigned long o = 0;
104 struct insn insn;
105
106 while (1) {
107
108 insn_decode(&insn, sec->data->d_buf + o, sec_size(sec) - o,
109 INSN_MODE_64);
110
111 if (o + insn.length > offset) {
112 *insn_off = o;
113 *insn_len = insn.length;
114 return;
115 }
116
117 o += insn.length;
118 }
119}
120
121u64 arch_adjusted_addend(struct reloc *reloc)
122{
123 unsigned int type = reloc_type(reloc);
124 s64 addend = reloc_addend(reloc);
125 unsigned long insn_off;
126 unsigned int insn_len;
127
128 if (type == R_X86_64_PLT32)
129 return addend + 4;
130
131 if (type != R_X86_64_PC32 || !is_text_sec(reloc->sec->base))
132 return addend;
133
134 scan_for_insn(reloc->sec->base, reloc_offset(reloc),
135 &insn_off, &insn_len);
136
137 return addend + insn_off + insn_len - reloc_offset(reloc);
138}
139
140unsigned long arch_jump_destination(struct instruction *insn)
141{
142 return insn->offset + insn->len + insn->immediate;
143}
144
145bool arch_pc_relative_reloc(struct reloc *reloc)
146{
147 /*
148 * All relocation types where P (the address of the target)
149 * is included in the computation.
150 */
151 switch (reloc_type(reloc)) {
152 case R_X86_64_PC8:
153 case R_X86_64_PC16:
154 case R_X86_64_PC32:
155 case R_X86_64_PC64:
156
157 case R_X86_64_PLT32:
158 case R_X86_64_GOTPC32:
159 case R_X86_64_GOTPCREL:
160 return true;
161
162 default:
163 break;
164 }
165
166 return false;
167}
168
169#define ADD_OP(op) \
170 if (!(op = calloc(1, sizeof(*op)))) \
171 return -1; \
172 else for (*ops_list = op, ops_list = &op->next; op; op = NULL)
173
174/*
175 * Helpers to decode ModRM/SIB:
176 *
177 * r/m| AX CX DX BX | SP | BP | SI DI |
178 * | R8 R9 R10 R11 | R12 | R13 | R14 R15 |
179 * Mod+----------------+-----+-----+---------+
180 * 00 | [r/m] |[SIB]|[IP+]| [r/m] |
181 * 01 | [r/m + d8] |[S+d]| [r/m + d8] |
182 * 10 | [r/m + d32] |[S+D]| [r/m + d32] |
183 * 11 | r/ m |
184 */
185
186#define mod_is_mem() (modrm_mod != 3)
187#define mod_is_reg() (modrm_mod == 3)
188
189#define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0)
190#define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem())
191
192/*
193 * Check the ModRM register. If there is a SIB byte then check with
194 * the SIB base register. But if the SIB base is 5 (i.e. CFI_BP) and
195 * ModRM mod is 0 then there is no base register.
196 */
197#define rm_is(reg) (have_SIB() ? \
198 sib_base == (reg) && sib_index == CFI_SP && \
199 (sib_base != CFI_BP || modrm_mod != 0) : \
200 modrm_rm == (reg))
201
202#define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg))
203#define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg))
204
205static bool has_notrack_prefix(struct insn *insn)
206{
207 int i;
208
209 for (i = 0; i < insn->prefixes.nbytes; i++) {
210 if (insn->prefixes.bytes[i] == 0x3e)
211 return true;
212 }
213
214 return false;
215}
216
217int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
218 unsigned long offset, unsigned int maxlen,
219 struct instruction *insn)
220{
221 struct stack_op **ops_list = &insn->stack_ops;
222 const struct elf *elf = file->elf;
223 struct insn ins;
224 int x86_64, ret;
225 unsigned char op1, op2, op3, prefix,
226 rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
227 modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
228 sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0;
229 struct stack_op *op = NULL;
230 struct symbol *sym;
231 u64 imm;
232
233 x86_64 = is_x86_64(elf);
234 if (x86_64 == -1)
235 return -1;
236
237 ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen,
238 x86_64 ? INSN_MODE_64 : INSN_MODE_32);
239 if (ret < 0) {
240 ERROR("can't decode instruction at %s:0x%lx", sec->name, offset);
241 return -1;
242 }
243
244 insn->len = ins.length;
245 insn->type = INSN_OTHER;
246
247 if (ins.vex_prefix.nbytes)
248 return 0;
249
250 prefix = ins.prefixes.bytes[0];
251
252 op1 = ins.opcode.bytes[0];
253 op2 = ins.opcode.bytes[1];
254 op3 = ins.opcode.bytes[2];
255
256 if (ins.rex_prefix.nbytes) {
257 rex = ins.rex_prefix.bytes[0];
258 rex_w = X86_REX_W(rex) >> 3;
259 rex_r = X86_REX_R(rex) >> 2;
260 rex_x = X86_REX_X(rex) >> 1;
261 rex_b = X86_REX_B(rex);
262 }
263
264 if (ins.modrm.nbytes) {
265 modrm = ins.modrm.bytes[0];
266 modrm_mod = X86_MODRM_MOD(modrm);
267 modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
268 modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b;
269 }
270
271 if (ins.sib.nbytes) {
272 sib = ins.sib.bytes[0];
273 /* sib_scale = X86_SIB_SCALE(sib); */
274 sib_index = X86_SIB_INDEX(sib) + 8*rex_x;
275 sib_base = X86_SIB_BASE(sib) + 8*rex_b;
276 }
277
278 switch (op1) {
279
280 case 0x1:
281 case 0x29:
282 if (rex_w && rm_is_reg(CFI_SP)) {
283
284 /* add/sub reg, %rsp */
285 ADD_OP(op) {
286 op->src.type = OP_SRC_ADD;
287 op->src.reg = modrm_reg;
288 op->dest.type = OP_DEST_REG;
289 op->dest.reg = CFI_SP;
290 }
291 }
292 break;
293
294 case 0x50 ... 0x57:
295
296 /* push reg */
297 ADD_OP(op) {
298 op->src.type = OP_SRC_REG;
299 op->src.reg = (op1 & 0x7) + 8*rex_b;
300 op->dest.type = OP_DEST_PUSH;
301 }
302
303 break;
304
305 case 0x58 ... 0x5f:
306
307 /* pop reg */
308 ADD_OP(op) {
309 op->src.type = OP_SRC_POP;
310 op->dest.type = OP_DEST_REG;
311 op->dest.reg = (op1 & 0x7) + 8*rex_b;
312 }
313
314 break;
315
316 case 0x68:
317 case 0x6a:
318 /* push immediate */
319 ADD_OP(op) {
320 op->src.type = OP_SRC_CONST;
321 op->dest.type = OP_DEST_PUSH;
322 }
323 break;
324
325 case 0x70 ... 0x7f:
326 insn->type = INSN_JUMP_CONDITIONAL;
327 break;
328
329 case 0x80 ... 0x83:
330 /*
331 * 1000 00sw : mod OP r/m : immediate
332 *
333 * s - sign extend immediate
334 * w - imm8 / imm32
335 *
336 * OP: 000 ADD 100 AND
337 * 001 OR 101 SUB
338 * 010 ADC 110 XOR
339 * 011 SBB 111 CMP
340 */
341
342 /* 64bit only */
343 if (!rex_w)
344 break;
345
346 /* %rsp target only */
347 if (!rm_is_reg(CFI_SP))
348 break;
349
350 imm = ins.immediate.value;
351 if (op1 & 2) { /* sign extend */
352 if (op1 & 1) { /* imm32 */
353 imm <<= 32;
354 imm = (s64)imm >> 32;
355 } else { /* imm8 */
356 imm <<= 56;
357 imm = (s64)imm >> 56;
358 }
359 }
360
361 switch (modrm_reg & 7) {
362 case 5:
363 imm = -imm;
364 fallthrough;
365 case 0:
366 /* add/sub imm, %rsp */
367 ADD_OP(op) {
368 op->src.type = OP_SRC_ADD;
369 op->src.reg = CFI_SP;
370 op->src.offset = imm;
371 op->dest.type = OP_DEST_REG;
372 op->dest.reg = CFI_SP;
373 }
374 break;
375
376 case 4:
377 /* and imm, %rsp */
378 ADD_OP(op) {
379 op->src.type = OP_SRC_AND;
380 op->src.reg = CFI_SP;
381 op->src.offset = ins.immediate.value;
382 op->dest.type = OP_DEST_REG;
383 op->dest.reg = CFI_SP;
384 }
385 break;
386
387 default:
388 /* ERROR ? */
389 break;
390 }
391
392 break;
393
394 case 0x89:
395 if (!rex_w)
396 break;
397
398 if (modrm_reg == CFI_SP) {
399
400 if (mod_is_reg()) {
401 /* mov %rsp, reg */
402 ADD_OP(op) {
403 op->src.type = OP_SRC_REG;
404 op->src.reg = CFI_SP;
405 op->dest.type = OP_DEST_REG;
406 op->dest.reg = modrm_rm;
407 }
408 break;
409
410 } else {
411 /* skip RIP relative displacement */
412 if (is_RIP())
413 break;
414
415 /* skip nontrivial SIB */
416 if (have_SIB()) {
417 modrm_rm = sib_base;
418 if (sib_index != CFI_SP)
419 break;
420 }
421
422 /* mov %rsp, disp(%reg) */
423 ADD_OP(op) {
424 op->src.type = OP_SRC_REG;
425 op->src.reg = CFI_SP;
426 op->dest.type = OP_DEST_REG_INDIRECT;
427 op->dest.reg = modrm_rm;
428 op->dest.offset = ins.displacement.value;
429 }
430 break;
431 }
432
433 break;
434 }
435
436 if (rm_is_reg(CFI_SP)) {
437
438 /* mov reg, %rsp */
439 ADD_OP(op) {
440 op->src.type = OP_SRC_REG;
441 op->src.reg = modrm_reg;
442 op->dest.type = OP_DEST_REG;
443 op->dest.reg = CFI_SP;
444 }
445 break;
446 }
447
448 fallthrough;
449 case 0x88:
450 if (!rex_w)
451 break;
452
453 if (rm_is_mem(CFI_BP)) {
454
455 /* mov reg, disp(%rbp) */
456 ADD_OP(op) {
457 op->src.type = OP_SRC_REG;
458 op->src.reg = modrm_reg;
459 op->dest.type = OP_DEST_REG_INDIRECT;
460 op->dest.reg = CFI_BP;
461 op->dest.offset = ins.displacement.value;
462 }
463 break;
464 }
465
466 if (rm_is_mem(CFI_SP)) {
467
468 /* mov reg, disp(%rsp) */
469 ADD_OP(op) {
470 op->src.type = OP_SRC_REG;
471 op->src.reg = modrm_reg;
472 op->dest.type = OP_DEST_REG_INDIRECT;
473 op->dest.reg = CFI_SP;
474 op->dest.offset = ins.displacement.value;
475 }
476 break;
477 }
478
479 break;
480
481 case 0x8b:
482 if (!rex_w)
483 break;
484
485 if (rm_is_mem(CFI_BP)) {
486
487 /* mov disp(%rbp), reg */
488 ADD_OP(op) {
489 op->src.type = OP_SRC_REG_INDIRECT;
490 op->src.reg = CFI_BP;
491 op->src.offset = ins.displacement.value;
492 op->dest.type = OP_DEST_REG;
493 op->dest.reg = modrm_reg;
494 }
495 break;
496 }
497
498 if (rm_is_mem(CFI_SP)) {
499
500 /* mov disp(%rsp), reg */
501 ADD_OP(op) {
502 op->src.type = OP_SRC_REG_INDIRECT;
503 op->src.reg = CFI_SP;
504 op->src.offset = ins.displacement.value;
505 op->dest.type = OP_DEST_REG;
506 op->dest.reg = modrm_reg;
507 }
508 break;
509 }
510
511 break;
512
513 case 0x8d:
514 if (mod_is_reg()) {
515 WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
516 break;
517 }
518
519 /* skip non 64bit ops */
520 if (!rex_w)
521 break;
522
523 /* skip nontrivial SIB */
524 if (have_SIB()) {
525 modrm_rm = sib_base;
526 if (sib_index != CFI_SP)
527 break;
528 }
529
530 /* lea disp(%rip), %dst */
531 if (is_RIP()) {
532 insn->type = INSN_LEA_RIP;
533 break;
534 }
535
536 /* lea disp(%src), %dst */
537 ADD_OP(op) {
538 op->src.offset = ins.displacement.value;
539 if (!op->src.offset) {
540 /* lea (%src), %dst */
541 op->src.type = OP_SRC_REG;
542 } else {
543 /* lea disp(%src), %dst */
544 op->src.type = OP_SRC_ADD;
545 }
546 op->src.reg = modrm_rm;
547 op->dest.type = OP_DEST_REG;
548 op->dest.reg = modrm_reg;
549 }
550 break;
551
552 case 0x8f:
553 /* pop to mem */
554 ADD_OP(op) {
555 op->src.type = OP_SRC_POP;
556 op->dest.type = OP_DEST_MEM;
557 }
558 break;
559
560 case 0x90:
561 if (rex_b) /* XCHG %r8, %rax */
562 break;
563
564 if (prefix == 0xf3) /* REP NOP := PAUSE */
565 break;
566
567 insn->type = INSN_NOP;
568 break;
569
570 case 0x9c:
571 /* pushf */
572 ADD_OP(op) {
573 op->src.type = OP_SRC_CONST;
574 op->dest.type = OP_DEST_PUSHF;
575 }
576 break;
577
578 case 0x9d:
579 /* popf */
580 ADD_OP(op) {
581 op->src.type = OP_SRC_POPF;
582 op->dest.type = OP_DEST_MEM;
583 }
584 break;
585
586 case 0x0f:
587
588 if (op2 == 0x01) {
589
590 switch (insn_last_prefix_id(&ins)) {
591 case INAT_PFX_REPE:
592 case INAT_PFX_REPNE:
593 if (modrm == 0xca)
594 /* eretu/erets */
595 insn->type = INSN_SYSRET;
596 break;
597 default:
598 if (modrm == 0xca)
599 insn->type = INSN_CLAC;
600 else if (modrm == 0xcb)
601 insn->type = INSN_STAC;
602 break;
603 }
604 } else if (op2 >= 0x80 && op2 <= 0x8f) {
605
606 insn->type = INSN_JUMP_CONDITIONAL;
607
608 } else if (op2 == 0x05 || op2 == 0x34) {
609
610 /* syscall, sysenter */
611 insn->type = INSN_SYSCALL;
612
613 } else if (op2 == 0x07 || op2 == 0x35) {
614
615 /* sysret, sysexit */
616 insn->type = INSN_SYSRET;
617
618 } else if (op2 == 0x0b || op2 == 0xb9) {
619
620 /* ud2, ud1 */
621 insn->type = INSN_BUG;
622
623 } else if (op2 == 0x1f) {
624
625 /* 0f 1f /0 := NOPL */
626 if (modrm_reg == 0)
627 insn->type = INSN_NOP;
628
629 } else if (op2 == 0x1e) {
630
631 if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb))
632 insn->type = INSN_ENDBR;
633
634
635 } else if (op2 == 0x38 && op3 == 0xf8) {
636 if (ins.prefixes.nbytes == 1 &&
637 ins.prefixes.bytes[0] == 0xf2) {
638 /* ENQCMD cannot be used in the kernel. */
639 WARN("ENQCMD instruction at %s:%lx", sec->name, offset);
640 }
641
642 } else if (op2 == 0xa0 || op2 == 0xa8) {
643
644 /* push fs/gs */
645 ADD_OP(op) {
646 op->src.type = OP_SRC_CONST;
647 op->dest.type = OP_DEST_PUSH;
648 }
649
650 } else if (op2 == 0xa1 || op2 == 0xa9) {
651
652 /* pop fs/gs */
653 ADD_OP(op) {
654 op->src.type = OP_SRC_POP;
655 op->dest.type = OP_DEST_MEM;
656 }
657 }
658
659 break;
660
661 case 0xc9:
662 /*
663 * leave
664 *
665 * equivalent to:
666 * mov bp, sp
667 * pop bp
668 */
669 ADD_OP(op) {
670 op->src.type = OP_SRC_REG;
671 op->src.reg = CFI_BP;
672 op->dest.type = OP_DEST_REG;
673 op->dest.reg = CFI_SP;
674 }
675 ADD_OP(op) {
676 op->src.type = OP_SRC_POP;
677 op->dest.type = OP_DEST_REG;
678 op->dest.reg = CFI_BP;
679 }
680 break;
681
682 case 0xcc:
683 /* int3 */
684 insn->type = INSN_TRAP;
685 break;
686
687 case 0xe3:
688 /* jecxz/jrcxz */
689 insn->type = INSN_JUMP_CONDITIONAL;
690 break;
691
692 case 0xe9:
693 case 0xeb:
694 insn->type = INSN_JUMP_UNCONDITIONAL;
695 break;
696
697 case 0xc2:
698 case 0xc3:
699 insn->type = INSN_RETURN;
700 break;
701
702 case 0xc7: /* mov imm, r/m */
703 if (!opts.noinstr)
704 break;
705
706 if (ins.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
707 struct reloc *immr, *disp;
708 struct symbol *func;
709 int idx;
710
711 immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
712 disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
713
714 if (!immr || strcmp(immr->sym->name, "pv_ops"))
715 break;
716
717 idx = (reloc_addend(immr) + 8) / sizeof(void *);
718
719 func = disp->sym;
720 if (disp->sym->type == STT_SECTION)
721 func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
722 if (!func) {
723 ERROR("no func for pv_ops[]");
724 return -1;
725 }
726
727 objtool_pv_add(file, idx, func);
728 }
729
730 break;
731
732 case 0xcf: /* iret */
733 /*
734 * Handle sync_core(), which has an IRET to self.
735 * All other IRET are in STT_NONE entry code.
736 */
737 sym = find_symbol_containing(sec, offset);
738 if (sym && sym->type == STT_FUNC) {
739 ADD_OP(op) {
740 /* add $40, %rsp */
741 op->src.type = OP_SRC_ADD;
742 op->src.reg = CFI_SP;
743 op->src.offset = 5*8;
744 op->dest.type = OP_DEST_REG;
745 op->dest.reg = CFI_SP;
746 }
747 break;
748 }
749
750 fallthrough;
751
752 case 0xca: /* retf */
753 case 0xcb: /* retf */
754 insn->type = INSN_SYSRET;
755 break;
756
757 case 0xd6: /* udb */
758 insn->type = INSN_BUG;
759 break;
760
761 case 0xe0: /* loopne */
762 case 0xe1: /* loope */
763 case 0xe2: /* loop */
764 insn->type = INSN_JUMP_CONDITIONAL;
765 break;
766
767 case 0xe8:
768 insn->type = INSN_CALL;
769 /*
770 * For the impact on the stack, a CALL behaves like
771 * a PUSH of an immediate value (the return address).
772 */
773 ADD_OP(op) {
774 op->src.type = OP_SRC_CONST;
775 op->dest.type = OP_DEST_PUSH;
776 }
777 break;
778
779 case 0xfc:
780 insn->type = INSN_CLD;
781 break;
782
783 case 0xfd:
784 insn->type = INSN_STD;
785 break;
786
787 case 0xff:
788 if (modrm_reg == 2 || modrm_reg == 3) {
789
790 insn->type = INSN_CALL_DYNAMIC;
791 if (has_notrack_prefix(&ins))
792 WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
793
794 } else if (modrm_reg == 4) {
795
796 insn->type = INSN_JUMP_DYNAMIC;
797 if (has_notrack_prefix(&ins))
798 WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
799
800 } else if (modrm_reg == 5) {
801
802 /* jmpf */
803 insn->type = INSN_SYSRET;
804
805 } else if (modrm_reg == 6) {
806
807 /* push from mem */
808 ADD_OP(op) {
809 op->src.type = OP_SRC_CONST;
810 op->dest.type = OP_DEST_PUSH;
811 }
812 }
813
814 break;
815
816 default:
817 break;
818 }
819
820 if (ins.immediate.nbytes)
821 insn->immediate = ins.immediate.value;
822 else if (ins.displacement.nbytes)
823 insn->immediate = ins.displacement.value;
824
825 return 0;
826}
827
828void arch_initial_func_cfi_state(struct cfi_init_state *state)
829{
830 int i;
831
832 for (i = 0; i < CFI_NUM_REGS; i++) {
833 state->regs[i].base = CFI_UNDEFINED;
834 state->regs[i].offset = 0;
835 }
836
837 /* initial CFA (call frame address) */
838 state->cfa.base = CFI_SP;
839 state->cfa.offset = 8;
840
841 /* initial RA (return address) */
842 state->regs[CFI_RA].base = CFI_CFA;
843 state->regs[CFI_RA].offset = -8;
844}
845
846const char *arch_nop_insn(int len)
847{
848 static const char nops[5][5] = {
849 { BYTES_NOP1 },
850 { BYTES_NOP2 },
851 { BYTES_NOP3 },
852 { BYTES_NOP4 },
853 { BYTES_NOP5 },
854 };
855
856 if (len < 1 || len > 5) {
857 ERROR("invalid NOP size: %d\n", len);
858 return NULL;
859 }
860
861 return nops[len-1];
862}
863
864#define BYTE_RET 0xC3
865
866const char *arch_ret_insn(int len)
867{
868 static const char ret[5][5] = {
869 { BYTE_RET },
870 { BYTE_RET, 0xcc },
871 { BYTE_RET, 0xcc, BYTES_NOP1 },
872 { BYTE_RET, 0xcc, BYTES_NOP2 },
873 { BYTE_RET, 0xcc, BYTES_NOP3 },
874 };
875
876 if (len < 1 || len > 5) {
877 ERROR("invalid RET size: %d\n", len);
878 return NULL;
879 }
880
881 return ret[len-1];
882}
883
884int arch_decode_hint_reg(u8 sp_reg, int *base)
885{
886 switch (sp_reg) {
887 case ORC_REG_UNDEFINED:
888 *base = CFI_UNDEFINED;
889 break;
890 case ORC_REG_SP:
891 *base = CFI_SP;
892 break;
893 case ORC_REG_BP:
894 *base = CFI_BP;
895 break;
896 case ORC_REG_SP_INDIRECT:
897 *base = CFI_SP_INDIRECT;
898 break;
899 case ORC_REG_R10:
900 *base = CFI_R10;
901 break;
902 case ORC_REG_R13:
903 *base = CFI_R13;
904 break;
905 case ORC_REG_DI:
906 *base = CFI_DI;
907 break;
908 case ORC_REG_DX:
909 *base = CFI_DX;
910 break;
911 default:
912 return -1;
913 }
914
915 return 0;
916}
917
918bool arch_is_retpoline(struct symbol *sym)
919{
920 return !strncmp(sym->name, "__x86_indirect_", 15) ||
921 !strncmp(sym->name, "__pi___x86_indirect_", 20);
922}
923
924bool arch_is_rethunk(struct symbol *sym)
925{
926 return !strcmp(sym->name, "__x86_return_thunk") ||
927 !strcmp(sym->name, "__pi___x86_return_thunk");
928}
929
930bool arch_is_embedded_insn(struct symbol *sym)
931{
932 return !strcmp(sym->name, "retbleed_return_thunk") ||
933 !strcmp(sym->name, "srso_alias_safe_ret") ||
934 !strcmp(sym->name, "srso_safe_ret");
935}
936
937unsigned int arch_reloc_size(struct reloc *reloc)
938{
939 switch (reloc_type(reloc)) {
940 case R_X86_64_32:
941 case R_X86_64_32S:
942 case R_X86_64_PC32:
943 case R_X86_64_PLT32:
944 return 4;
945 default:
946 return 8;
947 }
948}
949
950bool arch_absolute_reloc(struct elf *elf, struct reloc *reloc)
951{
952 switch (reloc_type(reloc)) {
953 case R_X86_64_32:
954 case R_X86_64_32S:
955 case R_X86_64_64:
956 return true;
957 default:
958 return false;
959 }
960}
961
962#ifdef DISAS
963
964int arch_disas_info_init(struct disassemble_info *dinfo)
965{
966 return disas_info_init(dinfo, bfd_arch_i386,
967 bfd_mach_i386_i386, bfd_mach_x86_64,
968 "att");
969}
970
971#endif /* DISAS */