107b972ffSIan Rogers // SPDX-License-Identifier: GPL-2.0 207b972ffSIan Rogers #include <string.h> 307b972ffSIan Rogers #include <linux/compiler.h> 407b972ffSIan Rogers #include <linux/kernel.h> 507b972ffSIan Rogers #include "../annotate-data.h" 607b972ffSIan Rogers #include "../debug.h" 707b972ffSIan Rogers #include "../disasm.h" 807b972ffSIan Rogers 907b972ffSIan Rogers #define PPC_OP(op) (((op) >> 26) & 0x3F) 1007b972ffSIan Rogers #define PPC_21_30(R) (((R) >> 1) & 0x3ff) 1107b972ffSIan Rogers #define PPC_22_30(R) (((R) >> 1) & 0x1ff) 1207b972ffSIan Rogers 1307b972ffSIan Rogers #define MINUS_EXT_XO_FORM 234 1407b972ffSIan Rogers #define SUB_EXT_XO_FORM 232 1507b972ffSIan Rogers #define ADD_ZERO_EXT_XO_FORM 202 1607b972ffSIan Rogers #define SUB_ZERO_EXT_XO_FORM 200 1707b972ffSIan Rogers 1807b972ffSIan Rogers static int arithmetic__scnprintf(const struct ins *ins, char *bf, size_t size, 1907b972ffSIan Rogers struct ins_operands *ops, int max_ins_name) 2007b972ffSIan Rogers { 2107b972ffSIan Rogers return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 2207b972ffSIan Rogers ops->raw); 2307b972ffSIan Rogers } 2407b972ffSIan Rogers 2507b972ffSIan Rogers /* 2607b972ffSIan Rogers * Sets the fields: multi_regs and "mem_ref". 2707b972ffSIan Rogers * "mem_ref" is set for ops->source which is later used to 2807b972ffSIan Rogers * fill the objdump->memory_ref-char field. This ops is currently 2907b972ffSIan Rogers * used by powerpc and since binary instruction code is used to 3007b972ffSIan Rogers * extract opcode, regs and offset, no other parsing is needed here. 3107b972ffSIan Rogers * 3207b972ffSIan Rogers * Dont set multi regs for 4 cases since it has only one operand 3307b972ffSIan Rogers * for source: 3407b972ffSIan Rogers * - Add to Minus One Extended XO-form ( Ex: addme, addmeo ) 3507b972ffSIan Rogers * - Subtract From Minus One Extended XO-form ( Ex: subfme ) 3607b972ffSIan Rogers * - Add to Zero Extended XO-form ( Ex: addze, addzeo ) 3707b972ffSIan Rogers * - Subtract From Zero Extended XO-form ( Ex: subfze ) 3807b972ffSIan Rogers */ 3907b972ffSIan Rogers static int arithmetic__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops, 4007b972ffSIan Rogers struct map_symbol *ms __maybe_unused, struct disasm_line *dl) 4107b972ffSIan Rogers { 4207b972ffSIan Rogers int opcode = PPC_OP(dl->raw.raw_insn); 4307b972ffSIan Rogers 4407b972ffSIan Rogers ops->source.mem_ref = false; 4507b972ffSIan Rogers if (opcode == 31) { 4607b972ffSIan Rogers if ((opcode != MINUS_EXT_XO_FORM) && (opcode != SUB_EXT_XO_FORM) && 4707b972ffSIan Rogers (opcode != ADD_ZERO_EXT_XO_FORM) && (opcode != SUB_ZERO_EXT_XO_FORM)) 4807b972ffSIan Rogers ops->source.multi_regs = true; 4907b972ffSIan Rogers } 5007b972ffSIan Rogers 5107b972ffSIan Rogers ops->target.mem_ref = false; 5207b972ffSIan Rogers ops->target.multi_regs = false; 5307b972ffSIan Rogers 5407b972ffSIan Rogers return 0; 5507b972ffSIan Rogers } 5607b972ffSIan Rogers 5707b972ffSIan Rogers static const struct ins_ops arithmetic_ops = { 5807b972ffSIan Rogers .parse = arithmetic__parse, 5907b972ffSIan Rogers .scnprintf = arithmetic__scnprintf, 6007b972ffSIan Rogers }; 6107b972ffSIan Rogers 6207b972ffSIan Rogers static int load_store__scnprintf(const struct ins *ins, char *bf, size_t size, 6307b972ffSIan Rogers struct ins_operands *ops, int max_ins_name) 6407b972ffSIan Rogers { 6507b972ffSIan Rogers return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 6607b972ffSIan Rogers ops->raw); 6707b972ffSIan Rogers } 6807b972ffSIan Rogers 6907b972ffSIan Rogers /* 7007b972ffSIan Rogers * Sets the fields: multi_regs and "mem_ref". 7107b972ffSIan Rogers * "mem_ref" is set for ops->source which is later used to 7207b972ffSIan Rogers * fill the objdump->memory_ref-char field. This ops is currently 7307b972ffSIan Rogers * used by powerpc and since binary instruction code is used to 7407b972ffSIan Rogers * extract opcode, regs and offset, no other parsing is needed here 7507b972ffSIan Rogers */ 7607b972ffSIan Rogers static int load_store__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops, 7707b972ffSIan Rogers struct map_symbol *ms __maybe_unused, struct disasm_line *dl __maybe_unused) 7807b972ffSIan Rogers { 7907b972ffSIan Rogers ops->source.mem_ref = true; 8007b972ffSIan Rogers ops->source.multi_regs = false; 8107b972ffSIan Rogers /* opcode 31 is of X form */ 8207b972ffSIan Rogers if (PPC_OP(dl->raw.raw_insn) == 31) 8307b972ffSIan Rogers ops->source.multi_regs = true; 8407b972ffSIan Rogers 8507b972ffSIan Rogers ops->target.mem_ref = false; 8607b972ffSIan Rogers ops->target.multi_regs = false; 8707b972ffSIan Rogers 8807b972ffSIan Rogers return 0; 8907b972ffSIan Rogers } 9007b972ffSIan Rogers 9107b972ffSIan Rogers static const struct ins_ops load_store_ops = { 9207b972ffSIan Rogers .parse = load_store__parse, 9307b972ffSIan Rogers .scnprintf = load_store__scnprintf, 9407b972ffSIan Rogers }; 9507b972ffSIan Rogers 9607b972ffSIan Rogers static const struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name) 9707b972ffSIan Rogers { 9807b972ffSIan Rogers int i; 9907b972ffSIan Rogers const struct ins_ops *ops; 10007b972ffSIan Rogers 10107b972ffSIan Rogers /* 10207b972ffSIan Rogers * - Interested only if instruction starts with 'b'. 10307b972ffSIan Rogers * - Few start with 'b', but aren't branch instructions. 10407b972ffSIan Rogers */ 10507b972ffSIan Rogers if (name[0] != 'b' || 10607b972ffSIan Rogers !strncmp(name, "bcd", 3) || 10707b972ffSIan Rogers !strncmp(name, "brinc", 5) || 10807b972ffSIan Rogers !strncmp(name, "bper", 4)) 10907b972ffSIan Rogers return NULL; 11007b972ffSIan Rogers 11107b972ffSIan Rogers ops = &jump_ops; 11207b972ffSIan Rogers 11307b972ffSIan Rogers i = strlen(name) - 1; 11407b972ffSIan Rogers if (i < 0) 11507b972ffSIan Rogers return NULL; 11607b972ffSIan Rogers 11707b972ffSIan Rogers /* ignore optional hints at the end of the instructions */ 11807b972ffSIan Rogers if (name[i] == '+' || name[i] == '-') 11907b972ffSIan Rogers i--; 12007b972ffSIan Rogers 12107b972ffSIan Rogers if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) { 12207b972ffSIan Rogers /* 12307b972ffSIan Rogers * if the instruction ends up with 'l' or 'la', then 12407b972ffSIan Rogers * those are considered 'calls' since they update LR. 12507b972ffSIan Rogers * ... except for 'bnl' which is branch if not less than 12607b972ffSIan Rogers * and the absolute form of the same. 12707b972ffSIan Rogers */ 12807b972ffSIan Rogers if (strcmp(name, "bnl") && strcmp(name, "bnl+") && 12907b972ffSIan Rogers strcmp(name, "bnl-") && strcmp(name, "bnla") && 13007b972ffSIan Rogers strcmp(name, "bnla+") && strcmp(name, "bnla-")) 13107b972ffSIan Rogers ops = &call_ops; 13207b972ffSIan Rogers } 13307b972ffSIan Rogers if (name[i] == 'r' && name[i-1] == 'l') 13407b972ffSIan Rogers /* 13507b972ffSIan Rogers * instructions ending with 'lr' are considered to be 13607b972ffSIan Rogers * return instructions 13707b972ffSIan Rogers */ 13807b972ffSIan Rogers ops = &ret_ops; 13907b972ffSIan Rogers 14007b972ffSIan Rogers arch__associate_ins_ops(arch, name, ops); 14107b972ffSIan Rogers return ops; 14207b972ffSIan Rogers } 14307b972ffSIan Rogers 14407b972ffSIan Rogers struct insn_offset { 14507b972ffSIan Rogers const char *name; 14607b972ffSIan Rogers int value; 14707b972ffSIan Rogers }; 14807b972ffSIan Rogers 14907b972ffSIan Rogers /* 15007b972ffSIan Rogers * There are memory instructions with opcode 31 which are 15107b972ffSIan Rogers * of X Form, Example: 15207b972ffSIan Rogers * ldx RT,RA,RB 15307b972ffSIan Rogers * ______________________________________ 15407b972ffSIan Rogers * | 31 | RT | RA | RB | 21 |/| 15507b972ffSIan Rogers * -------------------------------------- 15607b972ffSIan Rogers * 0 6 11 16 21 30 31 15707b972ffSIan Rogers * 15807b972ffSIan Rogers * But all instructions with opcode 31 are not memory. 15907b972ffSIan Rogers * Example: add RT,RA,RB 16007b972ffSIan Rogers * 16107b972ffSIan Rogers * Use bits 21 to 30 to check memory insns with 31 as opcode. 16207b972ffSIan Rogers * In ins_array below, for ldx instruction: 16307b972ffSIan Rogers * name => OP_31_XOP_LDX 16407b972ffSIan Rogers * value => 21 16507b972ffSIan Rogers */ 16607b972ffSIan Rogers 16707b972ffSIan Rogers static struct insn_offset ins_array[] = { 16807b972ffSIan Rogers { .name = "OP_31_XOP_LXSIWZX", .value = 12, }, 16907b972ffSIan Rogers { .name = "OP_31_XOP_LWARX", .value = 20, }, 17007b972ffSIan Rogers { .name = "OP_31_XOP_LDX", .value = 21, }, 17107b972ffSIan Rogers { .name = "OP_31_XOP_LWZX", .value = 23, }, 17207b972ffSIan Rogers { .name = "OP_31_XOP_LDUX", .value = 53, }, 17307b972ffSIan Rogers { .name = "OP_31_XOP_LWZUX", .value = 55, }, 17407b972ffSIan Rogers { .name = "OP_31_XOP_LXSIWAX", .value = 76, }, 17507b972ffSIan Rogers { .name = "OP_31_XOP_LDARX", .value = 84, }, 17607b972ffSIan Rogers { .name = "OP_31_XOP_LBZX", .value = 87, }, 17707b972ffSIan Rogers { .name = "OP_31_XOP_LVX", .value = 103, }, 17807b972ffSIan Rogers { .name = "OP_31_XOP_LBZUX", .value = 119, }, 17907b972ffSIan Rogers { .name = "OP_31_XOP_STXSIWX", .value = 140, }, 18007b972ffSIan Rogers { .name = "OP_31_XOP_STDX", .value = 149, }, 18107b972ffSIan Rogers { .name = "OP_31_XOP_STWX", .value = 151, }, 18207b972ffSIan Rogers { .name = "OP_31_XOP_STDUX", .value = 181, }, 18307b972ffSIan Rogers { .name = "OP_31_XOP_STWUX", .value = 183, }, 18407b972ffSIan Rogers { .name = "OP_31_XOP_STBX", .value = 215, }, 18507b972ffSIan Rogers { .name = "OP_31_XOP_STVX", .value = 231, }, 18607b972ffSIan Rogers { .name = "OP_31_XOP_STBUX", .value = 247, }, 18707b972ffSIan Rogers { .name = "OP_31_XOP_LHZX", .value = 279, }, 18807b972ffSIan Rogers { .name = "OP_31_XOP_LHZUX", .value = 311, }, 18907b972ffSIan Rogers { .name = "OP_31_XOP_LXVDSX", .value = 332, }, 19007b972ffSIan Rogers { .name = "OP_31_XOP_LWAX", .value = 341, }, 19107b972ffSIan Rogers { .name = "OP_31_XOP_LHAX", .value = 343, }, 19207b972ffSIan Rogers { .name = "OP_31_XOP_LWAUX", .value = 373, }, 19307b972ffSIan Rogers { .name = "OP_31_XOP_LHAUX", .value = 375, }, 19407b972ffSIan Rogers { .name = "OP_31_XOP_STHX", .value = 407, }, 19507b972ffSIan Rogers { .name = "OP_31_XOP_STHUX", .value = 439, }, 19607b972ffSIan Rogers { .name = "OP_31_XOP_LXSSPX", .value = 524, }, 19707b972ffSIan Rogers { .name = "OP_31_XOP_LDBRX", .value = 532, }, 19807b972ffSIan Rogers { .name = "OP_31_XOP_LSWX", .value = 533, }, 19907b972ffSIan Rogers { .name = "OP_31_XOP_LWBRX", .value = 534, }, 20007b972ffSIan Rogers { .name = "OP_31_XOP_LFSUX", .value = 567, }, 20107b972ffSIan Rogers { .name = "OP_31_XOP_LXSDX", .value = 588, }, 20207b972ffSIan Rogers { .name = "OP_31_XOP_LSWI", .value = 597, }, 20307b972ffSIan Rogers { .name = "OP_31_XOP_LFDX", .value = 599, }, 20407b972ffSIan Rogers { .name = "OP_31_XOP_LFDUX", .value = 631, }, 20507b972ffSIan Rogers { .name = "OP_31_XOP_STXSSPX", .value = 652, }, 20607b972ffSIan Rogers { .name = "OP_31_XOP_STDBRX", .value = 660, }, 20707b972ffSIan Rogers { .name = "OP_31_XOP_STXWX", .value = 661, }, 20807b972ffSIan Rogers { .name = "OP_31_XOP_STWBRX", .value = 662, }, 20907b972ffSIan Rogers { .name = "OP_31_XOP_STFSX", .value = 663, }, 21007b972ffSIan Rogers { .name = "OP_31_XOP_STFSUX", .value = 695, }, 21107b972ffSIan Rogers { .name = "OP_31_XOP_STXSDX", .value = 716, }, 21207b972ffSIan Rogers { .name = "OP_31_XOP_STSWI", .value = 725, }, 21307b972ffSIan Rogers { .name = "OP_31_XOP_STFDX", .value = 727, }, 21407b972ffSIan Rogers { .name = "OP_31_XOP_STFDUX", .value = 759, }, 21507b972ffSIan Rogers { .name = "OP_31_XOP_LXVW4X", .value = 780, }, 21607b972ffSIan Rogers { .name = "OP_31_XOP_LHBRX", .value = 790, }, 21707b972ffSIan Rogers { .name = "OP_31_XOP_LXVD2X", .value = 844, }, 21807b972ffSIan Rogers { .name = "OP_31_XOP_LFIWAX", .value = 855, }, 21907b972ffSIan Rogers { .name = "OP_31_XOP_LFIWZX", .value = 887, }, 22007b972ffSIan Rogers { .name = "OP_31_XOP_STXVW4X", .value = 908, }, 22107b972ffSIan Rogers { .name = "OP_31_XOP_STHBRX", .value = 918, }, 22207b972ffSIan Rogers { .name = "OP_31_XOP_STXVD2X", .value = 972, }, 22307b972ffSIan Rogers { .name = "OP_31_XOP_STFIWX", .value = 983, }, 22407b972ffSIan Rogers }; 22507b972ffSIan Rogers 22607b972ffSIan Rogers /* 22707b972ffSIan Rogers * Arithmetic instructions which are having opcode as 31. 22807b972ffSIan Rogers * These instructions are tracked to save the register state 22907b972ffSIan Rogers * changes. Example: 23007b972ffSIan Rogers * 23107b972ffSIan Rogers * lwz r10,264(r3) 23207b972ffSIan Rogers * add r31, r3, r3 23307b972ffSIan Rogers * lwz r9, 0(r31) 23407b972ffSIan Rogers * 23507b972ffSIan Rogers * Here instruction tracking needs to identify the "add" 23607b972ffSIan Rogers * instruction and save data type of r3 to r31. If a sample 23707b972ffSIan Rogers * is hit at next "lwz r9, 0(r31)", by this instruction tracking, 23807b972ffSIan Rogers * data type of r31 can be resolved. 23907b972ffSIan Rogers */ 24007b972ffSIan Rogers static struct insn_offset arithmetic_ins_op_31[] = { 24107b972ffSIan Rogers { .name = "SUB_CARRY_XO_FORM", .value = 8, }, 24207b972ffSIan Rogers { .name = "MUL_HDW_XO_FORM1", .value = 9, }, 24307b972ffSIan Rogers { .name = "ADD_CARRY_XO_FORM", .value = 10, }, 24407b972ffSIan Rogers { .name = "MUL_HW_XO_FORM1", .value = 11, }, 24507b972ffSIan Rogers { .name = "SUB_XO_FORM", .value = 40, }, 24607b972ffSIan Rogers { .name = "MUL_HDW_XO_FORM", .value = 73, }, 24707b972ffSIan Rogers { .name = "MUL_HW_XO_FORM", .value = 75, }, 24807b972ffSIan Rogers { .name = "SUB_EXT_XO_FORM", .value = 136, }, 24907b972ffSIan Rogers { .name = "ADD_EXT_XO_FORM", .value = 138, }, 25007b972ffSIan Rogers { .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, }, 25107b972ffSIan Rogers { .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, }, 25207b972ffSIan Rogers { .name = "SUB_EXT_XO_FORM2", .value = 232, }, 25307b972ffSIan Rogers { .name = "MUL_DW_XO_FORM", .value = 233, }, 25407b972ffSIan Rogers { .name = "ADD_EXT_XO_FORM2", .value = 234, }, 25507b972ffSIan Rogers { .name = "MUL_W_XO_FORM", .value = 235, }, 25607b972ffSIan Rogers { .name = "ADD_XO_FORM", .value = 266, }, 25707b972ffSIan Rogers { .name = "DIV_DW_XO_FORM1", .value = 457, }, 25807b972ffSIan Rogers { .name = "DIV_W_XO_FORM1", .value = 459, }, 25907b972ffSIan Rogers { .name = "DIV_DW_XO_FORM", .value = 489, }, 26007b972ffSIan Rogers { .name = "DIV_W_XO_FORM", .value = 491, }, 26107b972ffSIan Rogers }; 26207b972ffSIan Rogers 26307b972ffSIan Rogers static struct insn_offset arithmetic_two_ops[] = { 26407b972ffSIan Rogers { .name = "mulli", .value = 7, }, 26507b972ffSIan Rogers { .name = "subfic", .value = 8, }, 26607b972ffSIan Rogers { .name = "addic", .value = 12, }, 26707b972ffSIan Rogers { .name = "addic.", .value = 13, }, 26807b972ffSIan Rogers { .name = "addi", .value = 14, }, 26907b972ffSIan Rogers { .name = "addis", .value = 15, }, 27007b972ffSIan Rogers }; 27107b972ffSIan Rogers 27207b972ffSIan Rogers static int cmp_offset(const void *a, const void *b) 27307b972ffSIan Rogers { 27407b972ffSIan Rogers const struct insn_offset *val1 = a; 27507b972ffSIan Rogers const struct insn_offset *val2 = b; 27607b972ffSIan Rogers 27707b972ffSIan Rogers return (val1->value - val2->value); 27807b972ffSIan Rogers } 27907b972ffSIan Rogers 28007b972ffSIan Rogers const struct ins_ops *check_ppc_insn(struct disasm_line *dl) 28107b972ffSIan Rogers { 28207b972ffSIan Rogers int raw_insn = dl->raw.raw_insn; 28307b972ffSIan Rogers int opcode = PPC_OP(raw_insn); 28407b972ffSIan Rogers int mem_insn_31 = PPC_21_30(raw_insn); 28507b972ffSIan Rogers struct insn_offset *ret; 28607b972ffSIan Rogers struct insn_offset mem_insns_31_opcode = { 28707b972ffSIan Rogers "OP_31_INSN", 28807b972ffSIan Rogers mem_insn_31 28907b972ffSIan Rogers }; 29007b972ffSIan Rogers char name_insn[32]; 29107b972ffSIan Rogers 29207b972ffSIan Rogers /* 29307b972ffSIan Rogers * Instructions with opcode 32 to 63 are memory 29407b972ffSIan Rogers * instructions in powerpc 29507b972ffSIan Rogers */ 29607b972ffSIan Rogers if ((opcode & 0x20)) { 29707b972ffSIan Rogers /* 29807b972ffSIan Rogers * Set name in case of raw instruction to 29907b972ffSIan Rogers * opcode to be used in insn-stat 30007b972ffSIan Rogers */ 30107b972ffSIan Rogers if (!strlen(dl->ins.name)) { 30207b972ffSIan Rogers sprintf(name_insn, "%d", opcode); 30307b972ffSIan Rogers dl->ins.name = strdup(name_insn); 30407b972ffSIan Rogers } 30507b972ffSIan Rogers return &load_store_ops; 30607b972ffSIan Rogers } else if (opcode == 31) { 30707b972ffSIan Rogers /* Check for memory instructions with opcode 31 */ 30807b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset); 30907b972ffSIan Rogers if (ret) { 31007b972ffSIan Rogers if (!strlen(dl->ins.name)) 31107b972ffSIan Rogers dl->ins.name = strdup(ret->name); 31207b972ffSIan Rogers return &load_store_ops; 31307b972ffSIan Rogers } else { 31407b972ffSIan Rogers mem_insns_31_opcode.value = PPC_22_30(raw_insn); 31507b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31), 31607b972ffSIan Rogers sizeof(arithmetic_ins_op_31[0]), cmp_offset); 31707b972ffSIan Rogers if (ret != NULL) 31807b972ffSIan Rogers return &arithmetic_ops; 31907b972ffSIan Rogers /* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */ 32007b972ffSIan Rogers if (PPC_21_30(raw_insn) == 444) 32107b972ffSIan Rogers return &arithmetic_ops; 32207b972ffSIan Rogers } 32307b972ffSIan Rogers } else { 32407b972ffSIan Rogers mem_insns_31_opcode.value = opcode; 32507b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops), 32607b972ffSIan Rogers sizeof(arithmetic_two_ops[0]), cmp_offset); 32707b972ffSIan Rogers if (ret != NULL) 32807b972ffSIan Rogers return &arithmetic_ops; 32907b972ffSIan Rogers } 33007b972ffSIan Rogers 33107b972ffSIan Rogers return NULL; 33207b972ffSIan Rogers } 33307b972ffSIan Rogers 33407b972ffSIan Rogers /* 33507b972ffSIan Rogers * Instruction tracking function to track register state moves. 33607b972ffSIan Rogers * Example sequence: 33707b972ffSIan Rogers * ld r10,264(r3) 33807b972ffSIan Rogers * mr r31,r3 33907b972ffSIan Rogers * <<after some sequence> 34007b972ffSIan Rogers * ld r9,312(r31) 34107b972ffSIan Rogers * 34207b972ffSIan Rogers * Previous instruction sequence shows that register state of r3 34307b972ffSIan Rogers * is moved to r31. update_insn_state_powerpc tracks these state 34407b972ffSIan Rogers * changes 34507b972ffSIan Rogers */ 34607b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT 34707b972ffSIan Rogers static void update_insn_state_powerpc(struct type_state *state, 34807b972ffSIan Rogers struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused, 34907b972ffSIan Rogers struct disasm_line *dl) 35007b972ffSIan Rogers { 35107b972ffSIan Rogers struct annotated_insn_loc loc; 35207b972ffSIan Rogers struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; 35307b972ffSIan Rogers struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; 35407b972ffSIan Rogers struct type_state_reg *tsr; 35507b972ffSIan Rogers u32 insn_offset = dl->al.offset; 35607b972ffSIan Rogers 35707b972ffSIan Rogers if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) 35807b972ffSIan Rogers return; 35907b972ffSIan Rogers 36007b972ffSIan Rogers /* 36107b972ffSIan Rogers * Value 444 for bits 21:30 is for "mr" 36207b972ffSIan Rogers * instruction. "mr" is extended OR. So set the 36307b972ffSIan Rogers * source and destination reg correctly 36407b972ffSIan Rogers */ 36507b972ffSIan Rogers if (PPC_21_30(dl->raw.raw_insn) == 444) { 36607b972ffSIan Rogers int src_reg = src->reg1; 36707b972ffSIan Rogers 36807b972ffSIan Rogers src->reg1 = dst->reg1; 36907b972ffSIan Rogers dst->reg1 = src_reg; 37007b972ffSIan Rogers } 37107b972ffSIan Rogers 37207b972ffSIan Rogers if (!has_reg_type(state, dst->reg1)) 37307b972ffSIan Rogers return; 37407b972ffSIan Rogers 37507b972ffSIan Rogers tsr = &state->regs[dst->reg1]; 37607b972ffSIan Rogers 37707b972ffSIan Rogers if (!has_reg_type(state, src->reg1) || 37807b972ffSIan Rogers !state->regs[src->reg1].ok) { 37907b972ffSIan Rogers tsr->ok = false; 38007b972ffSIan Rogers return; 38107b972ffSIan Rogers } 38207b972ffSIan Rogers 38307b972ffSIan Rogers tsr->type = state->regs[src->reg1].type; 38407b972ffSIan Rogers tsr->kind = state->regs[src->reg1].kind; 38507b972ffSIan Rogers tsr->ok = true; 38607b972ffSIan Rogers 38707b972ffSIan Rogers pr_debug_dtp("mov [%x] reg%d -> reg%d", 38807b972ffSIan Rogers insn_offset, src->reg1, dst->reg1); 38907b972ffSIan Rogers pr_debug_type_name(&tsr->type, tsr->kind); 39007b972ffSIan Rogers } 39107b972ffSIan Rogers #endif /* HAVE_LIBDW_SUPPORT */ 39207b972ffSIan Rogers 393*0e26ba5aSIan Rogers const struct arch *arch__new_powerpc(const struct e_machine_and_e_flags *id, 394*0e26ba5aSIan Rogers const char *cpuid __maybe_unused) 39507b972ffSIan Rogers { 396*0e26ba5aSIan Rogers struct arch *arch = zalloc(sizeof(*arch)); 397*0e26ba5aSIan Rogers 398*0e26ba5aSIan Rogers if (!arch) 399*0e26ba5aSIan Rogers return NULL; 400*0e26ba5aSIan Rogers 401*0e26ba5aSIan Rogers arch->name = "powerpc"; 402*0e26ba5aSIan Rogers arch->id = *id; 40307b972ffSIan Rogers arch->objdump.comment_char = '#'; 40407b972ffSIan Rogers annotate_opts.show_asm_raw = true; 405*0e26ba5aSIan Rogers arch->associate_instruction_ops = powerpc__associate_instruction_ops; 40607b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT 40707b972ffSIan Rogers arch->update_insn_state = update_insn_state_powerpc; 40807b972ffSIan Rogers #endif 409*0e26ba5aSIan Rogers return arch; 41007b972ffSIan Rogers } 411