diff options
Diffstat (limited to 'tools/objtool/arch/powerpc/decode.c')
| -rw-r--r-- | tools/objtool/arch/powerpc/decode.c | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/powerpc/decode.c index 9c653805a08a..e534ac1123b3 100644 --- a/tools/objtool/arch/powerpc/decode.c +++ b/tools/objtool/arch/powerpc/decode.c @@ -3,20 +3,32 @@ #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> -#include <objtool/endianness.h> -int arch_ftrace_match(char *name) +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"); } -unsigned long arch_dest_reloc_offset(int addend) +s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc) { - return addend; + return reloc_addend(reloc); } bool arch_callee_saved_reg(unsigned char reg) @@ -41,44 +53,50 @@ const char *arch_ret_insn(int len) int arch_decode_instruction(struct objtool_file *file, const struct section *sec, unsigned long offset, unsigned int maxlen, - unsigned int *len, enum insn_type *type, - unsigned long *immediate, - struct list_head *ops_list) + struct instruction *insn) { unsigned int opcode; enum insn_type typ; unsigned long imm; - u32 insn; + u32 ins; - insn = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset)); - opcode = insn >> 26; + 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 ((insn & 3) == 1) /* bl */ + 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 = insn & 0x3fffffc; + imm = ins & 0x3fffffc; if (imm & 0x2000000) imm -= 0x4000000; + imm |= ins & 2; /* AA flag */ break; } if (opcode == 1) - *len = 8; + insn->len = 8; else - *len = 4; + insn->len = 4; - *type = typ; - *immediate = imm; + 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; } @@ -108,3 +126,28 @@ void arch_initial_func_cfi_state(struct cfi_init_state *state) 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 */ |
