@@ -188,3 +188,108 @@ bool __kprobes simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *r
188
188
189
189
return true;
190
190
}
191
+
192
+ bool __kprobes simulate_c_j (u32 opcode , unsigned long addr , struct pt_regs * regs )
193
+ {
194
+ /*
195
+ * 15 13 12 2 1 0
196
+ * | funct3 | offset[11|4|9:8|10|6|7|3:1|5] | opcode |
197
+ * 3 11 2
198
+ */
199
+
200
+ s32 offset ;
201
+
202
+ offset = ((opcode >> 3 ) & 0x7 ) << 1 ;
203
+ offset |= ((opcode >> 11 ) & 0x1 ) << 4 ;
204
+ offset |= ((opcode >> 2 ) & 0x1 ) << 5 ;
205
+ offset |= ((opcode >> 7 ) & 0x1 ) << 6 ;
206
+ offset |= ((opcode >> 6 ) & 0x1 ) << 7 ;
207
+ offset |= ((opcode >> 9 ) & 0x3 ) << 8 ;
208
+ offset |= ((opcode >> 8 ) & 0x1 ) << 10 ;
209
+ offset |= ((opcode >> 12 ) & 0x1 ) << 11 ;
210
+
211
+ instruction_pointer_set (regs , addr + sign_extend32 (offset , 11 ));
212
+
213
+ return true;
214
+ }
215
+
216
+ static bool __kprobes simulate_c_jr_jalr (u32 opcode , unsigned long addr , struct pt_regs * regs ,
217
+ bool is_jalr )
218
+ {
219
+ /*
220
+ * 15 12 11 7 6 2 1 0
221
+ * | funct4 | rs1 | rs2 | op |
222
+ * 4 5 5 2
223
+ */
224
+
225
+ unsigned long jump_addr ;
226
+
227
+ u32 rs1 = (opcode >> 7 ) & 0x1f ;
228
+
229
+ if (rs1 == 0 ) /* C.JR is only valid when rs1 != x0 */
230
+ return false;
231
+
232
+ if (!rv_insn_reg_get_val (regs , rs1 , & jump_addr ))
233
+ return false;
234
+
235
+ if (is_jalr && !rv_insn_reg_set_val (regs , 1 , addr + 2 ))
236
+ return false;
237
+
238
+ instruction_pointer_set (regs , jump_addr );
239
+
240
+ return true;
241
+ }
242
+
243
+ bool __kprobes simulate_c_jr (u32 opcode , unsigned long addr , struct pt_regs * regs )
244
+ {
245
+ return simulate_c_jr_jalr (opcode , addr , regs , false);
246
+ }
247
+
248
+ bool __kprobes simulate_c_jalr (u32 opcode , unsigned long addr , struct pt_regs * regs )
249
+ {
250
+ return simulate_c_jr_jalr (opcode , addr , regs , true);
251
+ }
252
+
253
+ static bool __kprobes simulate_c_bnez_beqz (u32 opcode , unsigned long addr , struct pt_regs * regs ,
254
+ bool is_bnez )
255
+ {
256
+ /*
257
+ * 15 13 12 10 9 7 6 2 1 0
258
+ * | funct3 | offset[8|4:3] | rs1' | offset[7:6|2:1|5] | op |
259
+ * 3 3 3 5 2
260
+ */
261
+
262
+ s32 offset ;
263
+ u32 rs1 ;
264
+ unsigned long rs1_val ;
265
+
266
+ rs1 = 0x8 | ((opcode >> 7 ) & 0x7 );
267
+
268
+ if (!rv_insn_reg_get_val (regs , rs1 , & rs1_val ))
269
+ return false;
270
+
271
+ if ((rs1_val != 0 && is_bnez ) || (rs1_val == 0 && !is_bnez )) {
272
+ offset = ((opcode >> 3 ) & 0x3 ) << 1 ;
273
+ offset |= ((opcode >> 10 ) & 0x3 ) << 3 ;
274
+ offset |= ((opcode >> 2 ) & 0x1 ) << 5 ;
275
+ offset |= ((opcode >> 5 ) & 0x3 ) << 6 ;
276
+ offset |= ((opcode >> 12 ) & 0x1 ) << 8 ;
277
+ offset = sign_extend32 (offset , 8 );
278
+ } else {
279
+ offset = 2 ;
280
+ }
281
+
282
+ instruction_pointer_set (regs , addr + offset );
283
+
284
+ return true;
285
+ }
286
+
287
+ bool __kprobes simulate_c_bnez (u32 opcode , unsigned long addr , struct pt_regs * regs )
288
+ {
289
+ return simulate_c_bnez_beqz (opcode , addr , regs , true);
290
+ }
291
+
292
+ bool __kprobes simulate_c_beqz (u32 opcode , unsigned long addr , struct pt_regs * regs )
293
+ {
294
+ return simulate_c_bnez_beqz (opcode , addr , regs , false);
295
+ }
0 commit comments