@@ -49,12 +49,266 @@ static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, con
49
49
return ops ;
50
50
}
51
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
+
56
+ struct insn_offset {
57
+ const char * name ;
58
+ int value ;
59
+ };
60
+
61
+ /*
62
+ * There are memory instructions with opcode 31 which are
63
+ * of X Form, Example:
64
+ * ldx RT,RA,RB
65
+ * ______________________________________
66
+ * | 31 | RT | RA | RB | 21 |/|
67
+ * --------------------------------------
68
+ * 0 6 11 16 21 30 31
69
+ *
70
+ * But all instructions with opcode 31 are not memory.
71
+ * Example: add RT,RA,RB
72
+ *
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_LDX
76
+ * value => 21
77
+ */
78
+
79
+ static 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 state
141
+ * changes. Example:
142
+ *
143
+ * lwz r10,264(r3)
144
+ * add r31, r3, r3
145
+ * 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 sample
149
+ * is hit at next "lwz r9, 0(r31)", by this instruction tracking,
150
+ * data type of r31 can be resolved.
151
+ */
152
+ static 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
+
175
+ static 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
+
184
+ static 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
+
192
+ static 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_31
201
+ };
202
+ char name_insn [32 ];
203
+
204
+ /*
205
+ * Instructions with opcode 32 to 63 are memory
206
+ * instructions in powerpc
207
+ */
208
+ if ((opcode & 0x20 )) {
209
+ /*
210
+ * Set name in case of raw instruction to
211
+ * opcode to be used in insn-stat
212
+ */
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,r3
251
+ * <<after some sequence>
252
+ * ld r9,312(r31)
253
+ *
254
+ * Previous instruction sequence shows that register state of r3
255
+ * is moved to r31. update_insn_state_powerpc tracks these state
256
+ * changes
257
+ */
258
+ #ifdef HAVE_DWARF_SUPPORT
259
+ static 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 the
275
+ * source and destination reg correctly
276
+ */
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
+
52
305
static int powerpc__annotate_init (struct arch * arch , char * cpuid __maybe_unused )
53
306
{
54
307
if (!arch -> initialized ) {
55
308
arch -> initialized = true;
56
309
arch -> associate_instruction_ops = powerpc__associate_instruction_ops ;
57
310
arch -> objdump .comment_char = '#' ;
311
+ annotate_opts .show_asm_raw = true;
58
312
}
59
313
60
314
return 0 ;
0 commit comments