brintos

brintos / linux-shallow public Read only

0
0
Text · 9.8 KiB · ede9eea Raw
316 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/compiler.h>3 4static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)5{6	int i;7	struct ins_ops *ops;8 9	/*10	 * - Interested only if instruction starts with 'b'.11	 * - Few start with 'b', but aren't branch instructions.12	 */13	if (name[0] != 'b'             ||14	    !strncmp(name, "bcd", 3)   ||15	    !strncmp(name, "brinc", 5) ||16	    !strncmp(name, "bper", 4))17		return NULL;18 19	ops = &jump_ops;20 21	i = strlen(name) - 1;22	if (i < 0)23		return NULL;24 25	/* ignore optional hints at the end of the instructions */26	if (name[i] == '+' || name[i] == '-')27		i--;28 29	if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) {30		/*31		 * if the instruction ends up with 'l' or 'la', then32		 * those are considered 'calls' since they update LR.33		 * ... except for 'bnl' which is branch if not less than34		 * and the absolute form of the same.35		 */36		if (strcmp(name, "bnl") && strcmp(name, "bnl+") &&37		    strcmp(name, "bnl-") && strcmp(name, "bnla") &&38		    strcmp(name, "bnla+") && strcmp(name, "bnla-"))39			ops = &call_ops;40	}41	if (name[i] == 'r' && name[i-1] == 'l')42		/*43		 * instructions ending with 'lr' are considered to be44		 * return instructions45		 */46		ops = &ret_ops;47 48	arch__associate_ins_ops(arch, name, ops);49	return ops;50}51 52#define PPC_OP(op)	(((op) >> 26) & 0x3F)53#define PPC_21_30(R)	(((R) >> 1) & 0x3ff)54#define PPC_22_30(R)	(((R) >> 1) & 0x1ff)55 56struct insn_offset {57	const char	*name;58	int		value;59};60 61/*62 * There are memory instructions with opcode 31 which are63 * of X Form, Example:64 * ldx RT,RA,RB65 * ______________________________________66 * | 31 |  RT  |  RA |  RB |   21     |/|67 * --------------------------------------68 * 0    6     11    16    21         30 3169 *70 * But all instructions with opcode 31 are not memory.71 * Example: add RT,RA,RB72 *73 * Use bits 21 to 30 to check memory insns with 31 as opcode.74 * In ins_array below, for ldx instruction:75 * name => OP_31_XOP_LDX76 * value => 2177 */78 79static struct insn_offset ins_array[] = {80	{ .name = "OP_31_XOP_LXSIWZX",  .value = 12, },81	{ .name = "OP_31_XOP_LWARX",	.value = 20, },82	{ .name = "OP_31_XOP_LDX",	.value = 21, },83	{ .name = "OP_31_XOP_LWZX",	.value = 23, },84	{ .name = "OP_31_XOP_LDUX",	.value = 53, },85	{ .name = "OP_31_XOP_LWZUX",	.value = 55, },86	{ .name = "OP_31_XOP_LXSIWAX",  .value = 76, },87	{ .name = "OP_31_XOP_LDARX",    .value = 84, },88	{ .name = "OP_31_XOP_LBZX",	.value = 87, },89	{ .name = "OP_31_XOP_LVX",      .value = 103, },90	{ .name = "OP_31_XOP_LBZUX",    .value = 119, },91	{ .name = "OP_31_XOP_STXSIWX",  .value = 140, },92	{ .name = "OP_31_XOP_STDX",	.value = 149, },93	{ .name = "OP_31_XOP_STWX",	.value = 151, },94	{ .name = "OP_31_XOP_STDUX",	.value = 181, },95	{ .name = "OP_31_XOP_STWUX",	.value = 183, },96	{ .name = "OP_31_XOP_STBX",	.value = 215, },97	{ .name = "OP_31_XOP_STVX",     .value = 231, },98	{ .name = "OP_31_XOP_STBUX",	.value = 247, },99	{ .name = "OP_31_XOP_LHZX",	.value = 279, },100	{ .name = "OP_31_XOP_LHZUX",	.value = 311, },101	{ .name = "OP_31_XOP_LXVDSX",   .value = 332, },102	{ .name = "OP_31_XOP_LWAX",	.value = 341, },103	{ .name = "OP_31_XOP_LHAX",	.value = 343, },104	{ .name = "OP_31_XOP_LWAUX",	.value = 373, },105	{ .name = "OP_31_XOP_LHAUX",	.value = 375, },106	{ .name = "OP_31_XOP_STHX",	.value = 407, },107	{ .name = "OP_31_XOP_STHUX",	.value = 439, },108	{ .name = "OP_31_XOP_LXSSPX",   .value = 524, },109	{ .name = "OP_31_XOP_LDBRX",	.value = 532, },110	{ .name = "OP_31_XOP_LSWX",	.value = 533, },111	{ .name = "OP_31_XOP_LWBRX",	.value = 534, },112	{ .name = "OP_31_XOP_LFSUX",    .value = 567, },113	{ .name = "OP_31_XOP_LXSDX",    .value = 588, },114	{ .name = "OP_31_XOP_LSWI",	.value = 597, },115	{ .name = "OP_31_XOP_LFDX",     .value = 599, },116	{ .name = "OP_31_XOP_LFDUX",    .value = 631, },117	{ .name = "OP_31_XOP_STXSSPX",  .value = 652, },118	{ .name = "OP_31_XOP_STDBRX",	.value = 660, },119	{ .name = "OP_31_XOP_STXWX",	.value = 661, },120	{ .name = "OP_31_XOP_STWBRX",	.value = 662, },121	{ .name = "OP_31_XOP_STFSX",	.value = 663, },122	{ .name = "OP_31_XOP_STFSUX",	.value = 695, },123	{ .name = "OP_31_XOP_STXSDX",   .value = 716, },124	{ .name = "OP_31_XOP_STSWI",	.value = 725, },125	{ .name = "OP_31_XOP_STFDX",	.value = 727, },126	{ .name = "OP_31_XOP_STFDUX",	.value = 759, },127	{ .name = "OP_31_XOP_LXVW4X",   .value = 780, },128	{ .name = "OP_31_XOP_LHBRX",	.value = 790, },129	{ .name = "OP_31_XOP_LXVD2X",   .value = 844, },130	{ .name = "OP_31_XOP_LFIWAX",	.value = 855, },131	{ .name = "OP_31_XOP_LFIWZX",	.value = 887, },132	{ .name = "OP_31_XOP_STXVW4X",  .value = 908, },133	{ .name = "OP_31_XOP_STHBRX",	.value = 918, },134	{ .name = "OP_31_XOP_STXVD2X",  .value = 972, },135	{ .name = "OP_31_XOP_STFIWX",	.value = 983, },136};137 138/*139 * Arithmetic instructions which are having opcode as 31.140 * These instructions are tracked to save the register state141 * changes. Example:142 *143 * lwz	r10,264(r3)144 * add	r31, r3, r3145 * lwz	r9, 0(r31)146 *147 * Here instruction tracking needs to identify the "add"148 * instruction and save data type of r3 to r31. If a sample149 * is hit at next "lwz r9, 0(r31)", by this instruction tracking,150 * data type of r31 can be resolved.151 */152static struct insn_offset arithmetic_ins_op_31[] = {153	{ .name = "SUB_CARRY_XO_FORM",  .value = 8, },154	{ .name = "MUL_HDW_XO_FORM1",   .value = 9, },155	{ .name = "ADD_CARRY_XO_FORM",  .value = 10, },156	{ .name = "MUL_HW_XO_FORM1",    .value = 11, },157	{ .name = "SUB_XO_FORM",        .value = 40, },158	{ .name = "MUL_HDW_XO_FORM",    .value = 73, },159	{ .name = "MUL_HW_XO_FORM",     .value = 75, },160	{ .name = "SUB_EXT_XO_FORM",    .value = 136, },161	{ .name = "ADD_EXT_XO_FORM",    .value = 138, },162	{ .name = "SUB_ZERO_EXT_XO_FORM",       .value = 200, },163	{ .name = "ADD_ZERO_EXT_XO_FORM",       .value = 202, },164	{ .name = "SUB_EXT_XO_FORM2",   .value = 232, },165	{ .name = "MUL_DW_XO_FORM",     .value = 233, },166	{ .name = "ADD_EXT_XO_FORM2",   .value = 234, },167	{ .name = "MUL_W_XO_FORM",      .value = 235, },168	{ .name = "ADD_XO_FORM",	.value = 266, },169	{ .name = "DIV_DW_XO_FORM1",    .value = 457, },170	{ .name = "DIV_W_XO_FORM1",     .value = 459, },171	{ .name = "DIV_DW_XO_FORM",	.value = 489, },172	{ .name = "DIV_W_XO_FORM",	.value = 491, },173};174 175static struct insn_offset arithmetic_two_ops[] = {176	{ .name = "mulli",      .value = 7, },177	{ .name = "subfic",     .value = 8, },178	{ .name = "addic",      .value = 12, },179	{ .name = "addic.",     .value = 13, },180	{ .name = "addi",       .value = 14, },181	{ .name = "addis",      .value = 15, },182};183 184static int cmp_offset(const void *a, const void *b)185{186	const struct insn_offset *val1 = a;187	const struct insn_offset *val2 = b;188 189	return (val1->value - val2->value);190}191 192static struct ins_ops *check_ppc_insn(struct disasm_line *dl)193{194	int raw_insn = dl->raw.raw_insn;195	int opcode = PPC_OP(raw_insn);196	int mem_insn_31 = PPC_21_30(raw_insn);197	struct insn_offset *ret;198	struct insn_offset mem_insns_31_opcode = {199		"OP_31_INSN",200		mem_insn_31201	};202	char name_insn[32];203 204	/*205	 * Instructions with opcode 32 to 63 are memory206	 * instructions in powerpc207	 */208	if ((opcode & 0x20)) {209		/*210		 * Set name in case of raw instruction to211		 * opcode to be used in insn-stat212		 */213		if (!strlen(dl->ins.name)) {214			sprintf(name_insn, "%d", opcode);215			dl->ins.name = strdup(name_insn);216		}217		return &load_store_ops;218	} else if (opcode == 31) {219		/* Check for memory instructions with opcode 31 */220		ret = bsearch(&mem_insns_31_opcode, ins_array, ARRAY_SIZE(ins_array), sizeof(ins_array[0]), cmp_offset);221		if (ret) {222			if (!strlen(dl->ins.name))223				dl->ins.name = strdup(ret->name);224			return &load_store_ops;225		} else {226			mem_insns_31_opcode.value = PPC_22_30(raw_insn);227			ret = bsearch(&mem_insns_31_opcode, arithmetic_ins_op_31, ARRAY_SIZE(arithmetic_ins_op_31),228					sizeof(arithmetic_ins_op_31[0]), cmp_offset);229			if (ret != NULL)230				return &arithmetic_ops;231			/* Bits 21 to 30 has value 444 for "mr" insn ie, OR X form */232			if (PPC_21_30(raw_insn) == 444)233				return &arithmetic_ops;234		}235	} else {236		mem_insns_31_opcode.value = opcode;237		ret = bsearch(&mem_insns_31_opcode, arithmetic_two_ops, ARRAY_SIZE(arithmetic_two_ops),238				sizeof(arithmetic_two_ops[0]), cmp_offset);239		if (ret != NULL)240			return &arithmetic_ops;241	}242 243	return NULL;244}245 246/*247 * Instruction tracking function to track register state moves.248 * Example sequence:249 *    ld      r10,264(r3)250 *    mr      r31,r3251 *    <<after some sequence>252 *    ld      r9,312(r31)253 *254 * Previous instruction sequence shows that register state of r3255 * is moved to r31. update_insn_state_powerpc tracks these state256 * changes257 */258#ifdef HAVE_DWARF_SUPPORT259static void update_insn_state_powerpc(struct type_state *state,260		struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused,261		struct disasm_line *dl)262{263	struct annotated_insn_loc loc;264	struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE];265	struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET];266	struct type_state_reg *tsr;267	u32 insn_offset = dl->al.offset;268 269	if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0)270		return;271 272	/*273	 * Value 444 for bits 21:30 is for "mr"274	 * instruction. "mr" is extended OR. So set the275	 * source and destination reg correctly276	 */277	if (PPC_21_30(dl->raw.raw_insn) == 444) {278		int src_reg = src->reg1;279 280		src->reg1 = dst->reg1;281		dst->reg1 = src_reg;282	}283 284	if (!has_reg_type(state, dst->reg1))285		return;286 287	tsr = &state->regs[dst->reg1];288 289	if (!has_reg_type(state, src->reg1) ||290			!state->regs[src->reg1].ok) {291		tsr->ok = false;292		return;293	}294 295	tsr->type = state->regs[src->reg1].type;296	tsr->kind = state->regs[src->reg1].kind;297	tsr->ok = true;298 299	pr_debug_dtp("mov [%x] reg%d -> reg%d",300			insn_offset, src->reg1, dst->reg1);301	pr_debug_type_name(&tsr->type, tsr->kind);302}303#endif /* HAVE_DWARF_SUPPORT */304 305static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused)306{307	if (!arch->initialized) {308		arch->initialized = true;309		arch->associate_instruction_ops = powerpc__associate_instruction_ops;310		arch->objdump.comment_char      = '#';311		annotate_opts.show_asm_raw = true;312	}313 314	return 0;315}316