1*07b972ffSIan Rogers // SPDX-License-Identifier: GPL-2.0 2*07b972ffSIan Rogers #include <string.h> 3*07b972ffSIan Rogers #include <linux/compiler.h> 4*07b972ffSIan Rogers #include <linux/kernel.h> 5*07b972ffSIan Rogers #include "../annotate-data.h" 6*07b972ffSIan Rogers #include "../debug.h" 7*07b972ffSIan Rogers #include "../disasm.h" 8*07b972ffSIan Rogers 9*07b972ffSIan Rogers #define PPC_OP(op) (((op) >> 26) & 0x3F) 10*07b972ffSIan Rogers #define PPC_21_30(R) (((R) >> 1) & 0x3ff) 11*07b972ffSIan Rogers #define PPC_22_30(R) (((R) >> 1) & 0x1ff) 12*07b972ffSIan Rogers 13*07b972ffSIan Rogers #define MINUS_EXT_XO_FORM 234 14*07b972ffSIan Rogers #define SUB_EXT_XO_FORM 232 15*07b972ffSIan Rogers #define ADD_ZERO_EXT_XO_FORM 202 16*07b972ffSIan Rogers #define SUB_ZERO_EXT_XO_FORM 200 17*07b972ffSIan Rogers 18*07b972ffSIan Rogers static int arithmetic__scnprintf(const struct ins *ins, char *bf, size_t size, 19*07b972ffSIan Rogers struct ins_operands *ops, int max_ins_name) 20*07b972ffSIan Rogers { 21*07b972ffSIan Rogers return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 22*07b972ffSIan Rogers ops->raw); 23*07b972ffSIan Rogers } 24*07b972ffSIan Rogers 25*07b972ffSIan Rogers /* 26*07b972ffSIan Rogers * Sets the fields: multi_regs and "mem_ref". 27*07b972ffSIan Rogers * "mem_ref" is set for ops->source which is later used to 28*07b972ffSIan Rogers * fill the objdump->memory_ref-char field. This ops is currently 29*07b972ffSIan Rogers * used by powerpc and since binary instruction code is used to 30*07b972ffSIan Rogers * extract opcode, regs and offset, no other parsing is needed here. 31*07b972ffSIan Rogers * 32*07b972ffSIan Rogers * Dont set multi regs for 4 cases since it has only one operand 33*07b972ffSIan Rogers * for source: 34*07b972ffSIan Rogers * - Add to Minus One Extended XO-form ( Ex: addme, addmeo ) 35*07b972ffSIan Rogers * - Subtract From Minus One Extended XO-form ( Ex: subfme ) 36*07b972ffSIan Rogers * - Add to Zero Extended XO-form ( Ex: addze, addzeo ) 37*07b972ffSIan Rogers * - Subtract From Zero Extended XO-form ( Ex: subfze ) 38*07b972ffSIan Rogers */ 39*07b972ffSIan Rogers static int arithmetic__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops, 40*07b972ffSIan Rogers struct map_symbol *ms __maybe_unused, struct disasm_line *dl) 41*07b972ffSIan Rogers { 42*07b972ffSIan Rogers int opcode = PPC_OP(dl->raw.raw_insn); 43*07b972ffSIan Rogers 44*07b972ffSIan Rogers ops->source.mem_ref = false; 45*07b972ffSIan Rogers if (opcode == 31) { 46*07b972ffSIan Rogers if ((opcode != MINUS_EXT_XO_FORM) && (opcode != SUB_EXT_XO_FORM) && 47*07b972ffSIan Rogers (opcode != ADD_ZERO_EXT_XO_FORM) && (opcode != SUB_ZERO_EXT_XO_FORM)) 48*07b972ffSIan Rogers ops->source.multi_regs = true; 49*07b972ffSIan Rogers } 50*07b972ffSIan Rogers 51*07b972ffSIan Rogers ops->target.mem_ref = false; 52*07b972ffSIan Rogers ops->target.multi_regs = false; 53*07b972ffSIan Rogers 54*07b972ffSIan Rogers return 0; 55*07b972ffSIan Rogers } 56*07b972ffSIan Rogers 57*07b972ffSIan Rogers static const struct ins_ops arithmetic_ops = { 58*07b972ffSIan Rogers .parse = arithmetic__parse, 59*07b972ffSIan Rogers .scnprintf = arithmetic__scnprintf, 60*07b972ffSIan Rogers }; 61*07b972ffSIan Rogers 62*07b972ffSIan Rogers static int load_store__scnprintf(const struct ins *ins, char *bf, size_t size, 63*07b972ffSIan Rogers struct ins_operands *ops, int max_ins_name) 64*07b972ffSIan Rogers { 65*07b972ffSIan Rogers return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 66*07b972ffSIan Rogers ops->raw); 67*07b972ffSIan Rogers } 68*07b972ffSIan Rogers 69*07b972ffSIan Rogers /* 70*07b972ffSIan Rogers * Sets the fields: multi_regs and "mem_ref". 71*07b972ffSIan Rogers * "mem_ref" is set for ops->source which is later used to 72*07b972ffSIan Rogers * fill the objdump->memory_ref-char field. This ops is currently 73*07b972ffSIan Rogers * used by powerpc and since binary instruction code is used to 74*07b972ffSIan Rogers * extract opcode, regs and offset, no other parsing is needed here 75*07b972ffSIan Rogers */ 76*07b972ffSIan Rogers static int load_store__parse(const struct arch *arch __maybe_unused, struct ins_operands *ops, 77*07b972ffSIan Rogers struct map_symbol *ms __maybe_unused, struct disasm_line *dl __maybe_unused) 78*07b972ffSIan Rogers { 79*07b972ffSIan Rogers ops->source.mem_ref = true; 80*07b972ffSIan Rogers ops->source.multi_regs = false; 81*07b972ffSIan Rogers /* opcode 31 is of X form */ 82*07b972ffSIan Rogers if (PPC_OP(dl->raw.raw_insn) == 31) 83*07b972ffSIan Rogers ops->source.multi_regs = true; 84*07b972ffSIan Rogers 85*07b972ffSIan Rogers ops->target.mem_ref = false; 86*07b972ffSIan Rogers ops->target.multi_regs = false; 87*07b972ffSIan Rogers 88*07b972ffSIan Rogers return 0; 89*07b972ffSIan Rogers } 90*07b972ffSIan Rogers 91*07b972ffSIan Rogers static const struct ins_ops load_store_ops = { 92*07b972ffSIan Rogers .parse = load_store__parse, 93*07b972ffSIan Rogers .scnprintf = load_store__scnprintf, 94*07b972ffSIan Rogers }; 95*07b972ffSIan Rogers 96*07b972ffSIan Rogers static const struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name) 97*07b972ffSIan Rogers { 98*07b972ffSIan Rogers int i; 99*07b972ffSIan Rogers const struct ins_ops *ops; 100*07b972ffSIan Rogers 101*07b972ffSIan Rogers /* 102*07b972ffSIan Rogers * - Interested only if instruction starts with 'b'. 103*07b972ffSIan Rogers * - Few start with 'b', but aren't branch instructions. 104*07b972ffSIan Rogers */ 105*07b972ffSIan Rogers if (name[0] != 'b' || 106*07b972ffSIan Rogers !strncmp(name, "bcd", 3) || 107*07b972ffSIan Rogers !strncmp(name, "brinc", 5) || 108*07b972ffSIan Rogers !strncmp(name, "bper", 4)) 109*07b972ffSIan Rogers return NULL; 110*07b972ffSIan Rogers 111*07b972ffSIan Rogers ops = &jump_ops; 112*07b972ffSIan Rogers 113*07b972ffSIan Rogers i = strlen(name) - 1; 114*07b972ffSIan Rogers if (i < 0) 115*07b972ffSIan Rogers return NULL; 116*07b972ffSIan Rogers 117*07b972ffSIan Rogers /* ignore optional hints at the end of the instructions */ 118*07b972ffSIan Rogers if (name[i] == '+' || name[i] == '-') 119*07b972ffSIan Rogers i--; 120*07b972ffSIan Rogers 121*07b972ffSIan Rogers if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) { 122*07b972ffSIan Rogers /* 123*07b972ffSIan Rogers * if the instruction ends up with 'l' or 'la', then 124*07b972ffSIan Rogers * those are considered 'calls' since they update LR. 125*07b972ffSIan Rogers * ... except for 'bnl' which is branch if not less than 126*07b972ffSIan Rogers * and the absolute form of the same. 127*07b972ffSIan Rogers */ 128*07b972ffSIan Rogers if (strcmp(name, "bnl") && strcmp(name, "bnl+") && 129*07b972ffSIan Rogers strcmp(name, "bnl-") && strcmp(name, "bnla") && 130*07b972ffSIan Rogers strcmp(name, "bnla+") && strcmp(name, "bnla-")) 131*07b972ffSIan Rogers ops = &call_ops; 132*07b972ffSIan Rogers } 133*07b972ffSIan Rogers if (name[i] == 'r' && name[i-1] == 'l') 134*07b972ffSIan Rogers /* 135*07b972ffSIan Rogers * instructions ending with 'lr' are considered to be 136*07b972ffSIan Rogers * return instructions 137*07b972ffSIan Rogers */ 138*07b972ffSIan Rogers ops = &ret_ops; 139*07b972ffSIan Rogers 140*07b972ffSIan Rogers arch__associate_ins_ops(arch, name, ops); 141*07b972ffSIan Rogers return ops; 142*07b972ffSIan Rogers } 143*07b972ffSIan Rogers 144*07b972ffSIan Rogers struct insn_offset { 145*07b972ffSIan Rogers const char *name; 146*07b972ffSIan Rogers int value; 147*07b972ffSIan Rogers }; 148*07b972ffSIan Rogers 149*07b972ffSIan Rogers /* 150*07b972ffSIan Rogers * There are memory instructions with opcode 31 which are 151*07b972ffSIan Rogers * of X Form, Example: 152*07b972ffSIan Rogers * ldx RT,RA,RB 153*07b972ffSIan Rogers * ______________________________________ 154*07b972ffSIan Rogers * | 31 | RT | RA | RB | 21 |/| 155*07b972ffSIan Rogers * -------------------------------------- 156*07b972ffSIan Rogers * 0 6 11 16 21 30 31 157*07b972ffSIan Rogers * 158*07b972ffSIan Rogers * But all instructions with opcode 31 are not memory. 159*07b972ffSIan Rogers * Example: add RT,RA,RB 160*07b972ffSIan Rogers * 161*07b972ffSIan Rogers * Use bits 21 to 30 to check memory insns with 31 as opcode. 162*07b972ffSIan Rogers * In ins_array below, for ldx instruction: 163*07b972ffSIan Rogers * name => OP_31_XOP_LDX 164*07b972ffSIan Rogers * value => 21 165*07b972ffSIan Rogers */ 166*07b972ffSIan Rogers 167*07b972ffSIan Rogers static struct insn_offset ins_array[] = { 168*07b972ffSIan Rogers { .name = "OP_31_XOP_LXSIWZX", .value = 12, }, 169*07b972ffSIan Rogers { .name = "OP_31_XOP_LWARX", .value = 20, }, 170*07b972ffSIan Rogers { .name = "OP_31_XOP_LDX", .value = 21, }, 171*07b972ffSIan Rogers { .name = "OP_31_XOP_LWZX", .value = 23, }, 172*07b972ffSIan Rogers { .name = "OP_31_XOP_LDUX", .value = 53, }, 173*07b972ffSIan Rogers { .name = "OP_31_XOP_LWZUX", .value = 55, }, 174*07b972ffSIan Rogers { .name = "OP_31_XOP_LXSIWAX", .value = 76, }, 175*07b972ffSIan Rogers { .name = "OP_31_XOP_LDARX", .value = 84, }, 176*07b972ffSIan Rogers { .name = "OP_31_XOP_LBZX", .value = 87, }, 177*07b972ffSIan Rogers { .name = "OP_31_XOP_LVX", .value = 103, }, 178*07b972ffSIan Rogers { .name = "OP_31_XOP_LBZUX", .value = 119, }, 179*07b972ffSIan Rogers { .name = "OP_31_XOP_STXSIWX", .value = 140, }, 180*07b972ffSIan Rogers { .name = "OP_31_XOP_STDX", .value = 149, }, 181*07b972ffSIan Rogers { .name = "OP_31_XOP_STWX", .value = 151, }, 182*07b972ffSIan Rogers { .name = "OP_31_XOP_STDUX", .value = 181, }, 183*07b972ffSIan Rogers { .name = "OP_31_XOP_STWUX", .value = 183, }, 184*07b972ffSIan Rogers { .name = "OP_31_XOP_STBX", .value = 215, }, 185*07b972ffSIan Rogers { .name = "OP_31_XOP_STVX", .value = 231, }, 186*07b972ffSIan Rogers { .name = "OP_31_XOP_STBUX", .value = 247, }, 187*07b972ffSIan Rogers { .name = "OP_31_XOP_LHZX", .value = 279, }, 188*07b972ffSIan Rogers { .name = "OP_31_XOP_LHZUX", .value = 311, }, 189*07b972ffSIan Rogers { .name = "OP_31_XOP_LXVDSX", .value = 332, }, 190*07b972ffSIan Rogers { .name = "OP_31_XOP_LWAX", .value = 341, }, 191*07b972ffSIan Rogers { .name = "OP_31_XOP_LHAX", .value = 343, }, 192*07b972ffSIan Rogers { .name = "OP_31_XOP_LWAUX", .value = 373, }, 193*07b972ffSIan Rogers { .name = "OP_31_XOP_LHAUX", .value = 375, }, 194*07b972ffSIan Rogers { .name = "OP_31_XOP_STHX", .value = 407, }, 195*07b972ffSIan Rogers { .name = "OP_31_XOP_STHUX", .value = 439, }, 196*07b972ffSIan Rogers { .name = "OP_31_XOP_LXSSPX", .value = 524, }, 197*07b972ffSIan Rogers { .name = "OP_31_XOP_LDBRX", .value = 532, }, 198*07b972ffSIan Rogers { .name = "OP_31_XOP_LSWX", .value = 533, }, 199*07b972ffSIan Rogers { .name = "OP_31_XOP_LWBRX", .value = 534, }, 200*07b972ffSIan Rogers { .name = "OP_31_XOP_LFSUX", .value = 567, }, 201*07b972ffSIan Rogers { .name = "OP_31_XOP_LXSDX", .value = 588, }, 202*07b972ffSIan Rogers { .name = "OP_31_XOP_LSWI", .value = 597, }, 203*07b972ffSIan Rogers { .name = "OP_31_XOP_LFDX", .value = 599, }, 204*07b972ffSIan Rogers { .name = "OP_31_XOP_LFDUX", .value = 631, }, 205*07b972ffSIan Rogers { .name = "OP_31_XOP_STXSSPX", .value = 652, }, 206*07b972ffSIan Rogers { .name = "OP_31_XOP_STDBRX", .value = 660, }, 207*07b972ffSIan Rogers { .name = "OP_31_XOP_STXWX", .value = 661, }, 208*07b972ffSIan Rogers { .name = "OP_31_XOP_STWBRX", .value = 662, }, 209*07b972ffSIan Rogers { .name = "OP_31_XOP_STFSX", .value = 663, }, 210*07b972ffSIan Rogers { .name = "OP_31_XOP_STFSUX", .value = 695, }, 211*07b972ffSIan Rogers { .name = "OP_31_XOP_STXSDX", .value = 716, }, 212*07b972ffSIan Rogers { .name = "OP_31_XOP_STSWI", .value = 725, }, 213*07b972ffSIan Rogers { .name = "OP_31_XOP_STFDX", .value = 727, }, 214*07b972ffSIan Rogers { .name = "OP_31_XOP_STFDUX", .value = 759, }, 215*07b972ffSIan Rogers { .name = "OP_31_XOP_LXVW4X", .value = 780, }, 216*07b972ffSIan Rogers { .name = "OP_31_XOP_LHBRX", .value = 790, }, 217*07b972ffSIan Rogers { .name = "OP_31_XOP_LXVD2X", .value = 844, }, 218*07b972ffSIan Rogers { .name = "OP_31_XOP_LFIWAX", .value = 855, }, 219*07b972ffSIan Rogers { .name = "OP_31_XOP_LFIWZX", .value = 887, }, 220*07b972ffSIan Rogers { .name = "OP_31_XOP_STXVW4X", .value = 908, }, 221*07b972ffSIan Rogers { .name = "OP_31_XOP_STHBRX", .value = 918, }, 222*07b972ffSIan Rogers { .name = "OP_31_XOP_STXVD2X", .value = 972, }, 223*07b972ffSIan Rogers { .name = "OP_31_XOP_STFIWX", .value = 983, }, 224*07b972ffSIan Rogers }; 225*07b972ffSIan Rogers 226*07b972ffSIan Rogers /* 227*07b972ffSIan Rogers * Arithmetic instructions which are having opcode as 31. 228*07b972ffSIan Rogers * These instructions are tracked to save the register state 229*07b972ffSIan Rogers * changes. Example: 230*07b972ffSIan Rogers * 231*07b972ffSIan Rogers * lwz r10,264(r3) 232*07b972ffSIan Rogers * add r31, r3, r3 233*07b972ffSIan Rogers * lwz r9, 0(r31) 234*07b972ffSIan Rogers * 235*07b972ffSIan Rogers * Here instruction tracking needs to identify the "add" 236*07b972ffSIan Rogers * instruction and save data type of r3 to r31. If a sample 237*07b972ffSIan Rogers * is hit at next "lwz r9, 0(r31)", by this instruction tracking, 238*07b972ffSIan Rogers * data type of r31 can be resolved. 239*07b972ffSIan Rogers */ 240*07b972ffSIan Rogers static struct insn_offset arithmetic_ins_op_31[] = { 241*07b972ffSIan Rogers { .name = "SUB_CARRY_XO_FORM", .value = 8, }, 242*07b972ffSIan Rogers { .name = "MUL_HDW_XO_FORM1", .value = 9, }, 243*07b972ffSIan Rogers { .name = "ADD_CARRY_XO_FORM", .value = 10, }, 244*07b972ffSIan Rogers { .name = "MUL_HW_XO_FORM1", .value = 11, }, 245*07b972ffSIan Rogers { .name = "SUB_XO_FORM", .value = 40, }, 246*07b972ffSIan Rogers { .name = "MUL_HDW_XO_FORM", .value = 73, }, 247*07b972ffSIan Rogers { .name = "MUL_HW_XO_FORM", .value = 75, }, 248*07b972ffSIan Rogers { .name = "SUB_EXT_XO_FORM", .value = 136, }, 249*07b972ffSIan Rogers { .name = "ADD_EXT_XO_FORM", .value = 138, }, 250*07b972ffSIan Rogers { .name = "SUB_ZERO_EXT_XO_FORM", .value = 200, }, 251*07b972ffSIan Rogers { .name = "ADD_ZERO_EXT_XO_FORM", .value = 202, }, 252*07b972ffSIan Rogers { .name = "SUB_EXT_XO_FORM2", .value = 232, }, 253*07b972ffSIan Rogers { .name = "MUL_DW_XO_FORM", .value = 233, }, 254*07b972ffSIan Rogers { .name = "ADD_EXT_XO_FORM2", .value = 234, }, 255*07b972ffSIan Rogers { .name = "MUL_W_XO_FORM", .value = 235, }, 256*07b972ffSIan Rogers { .name = "ADD_XO_FORM", .value = 266, }, 257*07b972ffSIan Rogers { .name = "DIV_DW_XO_FORM1", .value = 457, }, 258*07b972ffSIan Rogers { .name = "DIV_W_XO_FORM1", .value = 459, }, 259*07b972ffSIan Rogers { .name = "DIV_DW_XO_FORM", .value = 489, }, 260*07b972ffSIan Rogers { .name = "DIV_W_XO_FORM", .value = 491, }, 261*07b972ffSIan Rogers }; 262*07b972ffSIan Rogers 263*07b972ffSIan Rogers static struct insn_offset arithmetic_two_ops[] = { 264*07b972ffSIan Rogers { .name = "mulli", .value = 7, }, 265*07b972ffSIan Rogers { .name = "subfic", .value = 8, }, 266*07b972ffSIan Rogers { .name = "addic", .value = 12, }, 267*07b972ffSIan Rogers { .name = "addic.", .value = 13, }, 268*07b972ffSIan Rogers { .name = "addi", .value = 14, }, 269*07b972ffSIan Rogers { .name = "addis", .value = 15, }, 270*07b972ffSIan Rogers }; 271*07b972ffSIan Rogers 272*07b972ffSIan Rogers static int cmp_offset(const void *a, const void *b) 273*07b972ffSIan Rogers { 274*07b972ffSIan Rogers const struct insn_offset *val1 = a; 275*07b972ffSIan Rogers const struct insn_offset *val2 = b; 276*07b972ffSIan Rogers 277*07b972ffSIan Rogers return (val1->value - val2->value); 278*07b972ffSIan Rogers } 279*07b972ffSIan Rogers 280*07b972ffSIan Rogers const struct ins_ops *check_ppc_insn(struct disasm_line *dl) 281*07b972ffSIan Rogers { 282*07b972ffSIan Rogers int raw_insn = dl->raw.raw_insn; 283*07b972ffSIan Rogers int opcode = PPC_OP(raw_insn); 284*07b972ffSIan Rogers int mem_insn_31 = PPC_21_30(raw_insn); 285*07b972ffSIan Rogers struct insn_offset *ret; 286*07b972ffSIan Rogers struct insn_offset mem_insns_31_opcode = { 287*07b972ffSIan Rogers "OP_31_INSN", 288*07b972ffSIan Rogers mem_insn_31 289*07b972ffSIan Rogers }; 290*07b972ffSIan Rogers char name_insn[32]; 291*07b972ffSIan Rogers 292*07b972ffSIan Rogers /* 293*07b972ffSIan Rogers * Instructions with opcode 32 to 63 are memory 294*07b972ffSIan Rogers * instructions in powerpc 295*07b972ffSIan Rogers */ 296*07b972ffSIan Rogers if ((opcode & 0x20)) { 297*07b972ffSIan Rogers /* 298*07b972ffSIan Rogers * Set name in case of raw instruction to 299*07b972ffSIan Rogers * opcode to be used in insn-stat 300*07b972ffSIan Rogers */ 301*07b972ffSIan Rogers if (!strlen(dl->ins.name)) { 302*07b972ffSIan Rogers sprintf(name_insn, "%d", opcode); 303*07b972ffSIan Rogers dl->ins.name = strdup(name_insn); 304*07b972ffSIan Rogers } 305*07b972ffSIan Rogers return &load_store_ops; 306*07b972ffSIan Rogers } else if (opcode == 31) { 307*07b972ffSIan Rogers /* Check for memory instructions with opcode 31 */ 308*07b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset); 309*07b972ffSIan Rogers if (ret) { 310*07b972ffSIan Rogers if (!strlen(dl->ins.name)) 311*07b972ffSIan Rogers dl->ins.name = strdup(ret->name); 312*07b972ffSIan Rogers return &load_store_ops; 313*07b972ffSIan Rogers } else { 314*07b972ffSIan Rogers mem_insns_31_opcode.value = PPC_22_30(raw_insn); 315*07b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31), 316*07b972ffSIan Rogers sizeof(arithmetic_ins_op_31[0]), cmp_offset); 317*07b972ffSIan Rogers if (ret != NULL) 318*07b972ffSIan Rogers return &arithmetic_ops; 319*07b972ffSIan Rogers /* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */ 320*07b972ffSIan Rogers if (PPC_21_30(raw_insn) == 444) 321*07b972ffSIan Rogers return &arithmetic_ops; 322*07b972ffSIan Rogers } 323*07b972ffSIan Rogers } else { 324*07b972ffSIan Rogers mem_insns_31_opcode.value = opcode; 325*07b972ffSIan Rogers ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops), 326*07b972ffSIan Rogers sizeof(arithmetic_two_ops[0]), cmp_offset); 327*07b972ffSIan Rogers if (ret != NULL) 328*07b972ffSIan Rogers return &arithmetic_ops; 329*07b972ffSIan Rogers } 330*07b972ffSIan Rogers 331*07b972ffSIan Rogers return NULL; 332*07b972ffSIan Rogers } 333*07b972ffSIan Rogers 334*07b972ffSIan Rogers /* 335*07b972ffSIan Rogers * Instruction tracking function to track register state moves. 336*07b972ffSIan Rogers * Example sequence: 337*07b972ffSIan Rogers * ld r10,264(r3) 338*07b972ffSIan Rogers * mr r31,r3 339*07b972ffSIan Rogers * <<after some sequence> 340*07b972ffSIan Rogers * ld r9,312(r31) 341*07b972ffSIan Rogers * 342*07b972ffSIan Rogers * Previous instruction sequence shows that register state of r3 343*07b972ffSIan Rogers * is moved to r31. update_insn_state_powerpc tracks these state 344*07b972ffSIan Rogers * changes 345*07b972ffSIan Rogers */ 346*07b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT 347*07b972ffSIan Rogers static void update_insn_state_powerpc(struct type_state *state, 348*07b972ffSIan Rogers struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused, 349*07b972ffSIan Rogers struct disasm_line *dl) 350*07b972ffSIan Rogers { 351*07b972ffSIan Rogers struct annotated_insn_loc loc; 352*07b972ffSIan Rogers struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; 353*07b972ffSIan Rogers struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; 354*07b972ffSIan Rogers struct type_state_reg *tsr; 355*07b972ffSIan Rogers u32 insn_offset = dl->al.offset; 356*07b972ffSIan Rogers 357*07b972ffSIan Rogers if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) 358*07b972ffSIan Rogers return; 359*07b972ffSIan Rogers 360*07b972ffSIan Rogers /* 361*07b972ffSIan Rogers * Value 444 for bits 21:30 is for "mr" 362*07b972ffSIan Rogers * instruction. "mr" is extended OR. So set the 363*07b972ffSIan Rogers * source and destination reg correctly 364*07b972ffSIan Rogers */ 365*07b972ffSIan Rogers if (PPC_21_30(dl->raw.raw_insn) == 444) { 366*07b972ffSIan Rogers int src_reg = src->reg1; 367*07b972ffSIan Rogers 368*07b972ffSIan Rogers src->reg1 = dst->reg1; 369*07b972ffSIan Rogers dst->reg1 = src_reg; 370*07b972ffSIan Rogers } 371*07b972ffSIan Rogers 372*07b972ffSIan Rogers if (!has_reg_type(state, dst->reg1)) 373*07b972ffSIan Rogers return; 374*07b972ffSIan Rogers 375*07b972ffSIan Rogers tsr = &state->regs[dst->reg1]; 376*07b972ffSIan Rogers 377*07b972ffSIan Rogers if (!has_reg_type(state, src->reg1) || 378*07b972ffSIan Rogers !state->regs[src->reg1].ok) { 379*07b972ffSIan Rogers tsr->ok = false; 380*07b972ffSIan Rogers return; 381*07b972ffSIan Rogers } 382*07b972ffSIan Rogers 383*07b972ffSIan Rogers tsr->type = state->regs[src->reg1].type; 384*07b972ffSIan Rogers tsr->kind = state->regs[src->reg1].kind; 385*07b972ffSIan Rogers tsr->ok = true; 386*07b972ffSIan Rogers 387*07b972ffSIan Rogers pr_debug_dtp("mov [%x] reg%d -> reg%d", 388*07b972ffSIan Rogers insn_offset, src->reg1, dst->reg1); 389*07b972ffSIan Rogers pr_debug_type_name(&tsr->type, tsr->kind); 390*07b972ffSIan Rogers } 391*07b972ffSIan Rogers #endif /* HAVE_LIBDW_SUPPORT */ 392*07b972ffSIan Rogers 393*07b972ffSIan Rogers int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) 394*07b972ffSIan Rogers { 395*07b972ffSIan Rogers if (!arch->initialized) { 396*07b972ffSIan Rogers arch->initialized = true; 397*07b972ffSIan Rogers arch->associate_instruction_ops = powerpc__associate_instruction_ops; 398*07b972ffSIan Rogers arch->objdump.comment_char = '#'; 399*07b972ffSIan Rogers annotate_opts.show_asm_raw = true; 400*07b972ffSIan Rogers #ifdef HAVE_LIBDW_SUPPORT 401*07b972ffSIan Rogers arch->update_insn_state = update_insn_state_powerpc; 402*07b972ffSIan Rogers #endif 403*07b972ffSIan Rogers } 404*07b972ffSIan Rogers 405*07b972ffSIan Rogers return 0; 406*07b972ffSIan Rogers } 407