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
arithmetic__scnprintf(const struct ins * ins,char * bf,size_t size,struct ins_operands * ops,int max_ins_name)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 */
arithmetic__parse(const struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused,struct disasm_line * dl)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
load_store__scnprintf(const struct ins * ins,char * bf,size_t size,struct ins_operands * ops,int max_ins_name)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 */
load_store__parse(const struct arch * arch __maybe_unused,struct ins_operands * ops,struct map_symbol * ms __maybe_unused,struct disasm_line * dl __maybe_unused)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
powerpc__associate_instruction_ops(struct arch * arch,const char * name)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
cmp_offset(const void * a,const void * b)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
check_ppc_insn(struct disasm_line * dl)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
update_insn_state_powerpc(struct type_state * state,struct data_loc_info * dloc,Dwarf_Die * cu_die __maybe_unused,struct disasm_line * dl)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
arch__new_powerpc(const struct e_machine_and_e_flags * id,const char * cpuid __maybe_unused)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