1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdio.h>
#include <stdlib.h>
#include <objtool/check.h>
#include <objtool/disas.h>
#include <objtool/elf.h>
#include <objtool/arch.h>
#include <objtool/warn.h>
#include <objtool/builtin.h>
const char *arch_reg_name[CFI_NUM_REGS] = {
"r0", "sp", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19",
"r20", "r21", "r22", "r23",
"r24", "r25", "r26", "r27",
"r28", "r29", "r30", "r31",
"ra"
};
int arch_ftrace_match(const char *name)
{
return !strcmp(name, "_mcount");
}
s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc)
{
return reloc_addend(reloc);
}
bool arch_callee_saved_reg(unsigned char reg)
{
return false;
}
int arch_decode_hint_reg(u8 sp_reg, int *base)
{
exit(-1);
}
const char *arch_nop_insn(int len)
{
exit(-1);
}
const char *arch_ret_insn(int len)
{
exit(-1);
}
int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
unsigned long offset, unsigned int maxlen,
struct instruction *insn)
{
unsigned int opcode;
enum insn_type typ;
unsigned long imm;
u32 ins;
ins = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
opcode = ins >> 26;
typ = INSN_OTHER;
imm = 0;
switch (opcode) {
case 18: /* b[l][a] */
if (ins == 0x48000005) /* bl .+4 */
typ = INSN_OTHER;
else if (ins & 1) /* bl[a] */
typ = INSN_CALL;
else /* b[a] */
typ = INSN_JUMP_UNCONDITIONAL;
imm = ins & 0x3fffffc;
if (imm & 0x2000000)
imm -= 0x4000000;
imm |= ins & 2; /* AA flag */
break;
}
if (opcode == 1)
insn->len = 8;
else
insn->len = 4;
insn->type = typ;
insn->immediate = imm;
return 0;
}
unsigned long arch_jump_destination(struct instruction *insn)
{
if (insn->immediate & 2)
return insn->immediate & ~2;
return insn->offset + insn->immediate;
}
bool arch_pc_relative_reloc(struct reloc *reloc)
{
/*
* The powerpc build only allows certain relocation types, see
* relocs_check.sh, and none of those accepted are PC relative.
*/
return false;
}
void arch_initial_func_cfi_state(struct cfi_init_state *state)
{
int i;
for (i = 0; i < CFI_NUM_REGS; i++) {
state->regs[i].base = CFI_UNDEFINED;
state->regs[i].offset = 0;
}
/* initial CFA (call frame address) */
state->cfa.base = CFI_SP;
state->cfa.offset = 0;
/* initial LR (return address) */
state->regs[CFI_RA].base = CFI_CFA;
state->regs[CFI_RA].offset = 0;
}
unsigned int arch_reloc_size(struct reloc *reloc)
{
switch (reloc_type(reloc)) {
case R_PPC_REL32:
case R_PPC_ADDR32:
case R_PPC_UADDR32:
case R_PPC_PLT32:
case R_PPC_PLTREL32:
return 4;
default:
return 8;
}
}
#ifdef DISAS
int arch_disas_info_init(struct disassemble_info *dinfo)
{
return disas_info_init(dinfo, bfd_arch_powerpc,
bfd_mach_ppc, bfd_mach_ppc64,
NULL);
}
#endif /* DISAS */
|