@@ -6129,6 +6129,31 @@ dr_insert_mbr_instrumentation(void *drcontext, instrlist_t *ilist, instr_t *inst
6129
6129
#elif defined(RISCV64 )
6130
6130
/* FIXME i#3544: Not implemented */
6131
6131
ASSERT_NOT_IMPLEMENTED (false);
6132
+ #elif defined(AARCH64 )
6133
+ ptr_uint_t address ;
6134
+ opnd_t target ;
6135
+ CLIENT_ASSERT (drcontext != NULL ,
6136
+ "dr_insert_mbr_instrumentation: drcontext cannot be NULL" );
6137
+ address = (ptr_uint_t )instr_get_translation (instr );
6138
+ CLIENT_ASSERT (address != 0 ,
6139
+ "dr_insert_mbr_instrumentation: can't determine app address" );
6140
+ CLIENT_ASSERT (instr_is_mbr (instr ),
6141
+ "dr_insert_mbr_instrumentation must be applied to a mbr" );
6142
+
6143
+ /* Retrieve target address. */
6144
+ target = instr_get_target (instr );
6145
+
6146
+ dr_insert_clean_call_ex (
6147
+ drcontext , ilist , instr , callee ,
6148
+ /* Many users will ask for mcontexts; some will set; it doesn't seem worth
6149
+ * asking the user to pass in a flag: if they're using this they are not
6150
+ * super concerned about overhead.
6151
+ */
6152
+ DR_CLEANCALL_READS_APP_CONTEXT | DR_CLEANCALL_WRITES_APP_CONTEXT , 2 ,
6153
+ /* Address of mbr is 1st param. */
6154
+ OPND_CREATE_INTPTR (address ),
6155
+ /* Indirect target is 2nd param. */
6156
+ target );
6132
6157
#endif /* X86/ARM/RISCV64 */
6133
6158
}
6134
6159
@@ -6367,7 +6392,169 @@ dr_insert_cbr_instrumentation_help(void *drcontext, instrlist_t *ilist, instr_t
6367
6392
#elif defined(RISCV64 )
6368
6393
/* FIXME i#3544: Not implemented */
6369
6394
ASSERT_NOT_IMPLEMENTED (false);
6370
- #endif /* X86/ARM/RISCV64 */
6395
+ #elif defined(AARCH64 )
6396
+ dcontext_t * dcontext = (dcontext_t * )drcontext ;
6397
+ ptr_uint_t address , target ;
6398
+ reg_id_t dir = DR_REG_NULL ;
6399
+ reg_id_t flags = DR_REG_NULL ;
6400
+ reg_id_t temp = DR_REG_X0 ;
6401
+ bool temp_used = false;
6402
+ int opc ;
6403
+ CLIENT_ASSERT (drcontext != NULL ,
6404
+ "dr_insert_cbr_instrumentation: drcontext cannot be NULL" );
6405
+ address = (ptr_uint_t )instr_get_translation (instr );
6406
+ CLIENT_ASSERT (address != 0 ,
6407
+ "dr_insert_cbr_instrumentation: can't determine app address" );
6408
+ CLIENT_ASSERT (instr_is_cbr (instr ),
6409
+ "dr_insert_cbr_instrumentation must be applied to a cbr" );
6410
+ target = (ptr_uint_t )opnd_get_pc (instr_get_target (instr ));
6411
+
6412
+ /* Compute branch direction. */
6413
+ opc = instr_get_opcode (instr );
6414
+ if (opc == OP_cbnz || opc == OP_cbz ) {
6415
+ /* XXX: which is faster, additional conditional branch or cmp + csinc? */
6416
+ opnd_t reg_op = instr_get_src (instr , 1 );
6417
+ reg_id_t reg = opnd_get_reg (reg_op );
6418
+ /* If the register is stolen, we need to read the actual value first. */
6419
+ if (reg_is_stolen (reg )) {
6420
+ /* Save old value of temp register to SPILL_SLOT_3. */
6421
+ dr_save_reg (dcontext , ilist , instr , temp , SPILL_SLOT_3 );
6422
+ /* Read actual register value if stolen */
6423
+ dr_insert_get_stolen_reg_value (dcontext , ilist , instr , temp );
6424
+ /* Use temp register to access actual register value. */
6425
+ temp_used = true;
6426
+ reg = reg_resize_to_opsz (temp , reg_get_size (reg ));
6427
+ reg_op = opnd_create_reg (reg );
6428
+ }
6429
+
6430
+ /* Use dir register to compute direction. */
6431
+ dir = (reg_to_pointer_sized (reg ) == DR_REG_X0 ) ? DR_REG_X1 : DR_REG_X0 ;
6432
+ /* Save old value of dir register to SPILL_SLOT_1. */
6433
+ dr_save_reg (dcontext , ilist , instr , dir , SPILL_SLOT_1 );
6434
+ /* Use flags register to save nzcv. */
6435
+ flags = (reg_to_pointer_sized (reg ) == DR_REG_X2 ) ? DR_REG_X3 : DR_REG_X2 ;
6436
+ /* Save old value of flags register to SPILL_SLOT_2. */
6437
+ dr_save_reg (dcontext , ilist , instr , flags , SPILL_SLOT_2 );
6438
+ /* Save flags to flags register. */
6439
+ dr_save_arith_flags_to_reg (dcontext , ilist , instr , flags );
6440
+
6441
+ /* Compare reg against zero. */
6442
+ instr_t * cmp = INSTR_CREATE_cmp (dcontext , reg_op , OPND_CREATE_INT (0 ));
6443
+ MINSERT (ilist , instr , cmp );
6444
+ /* Compute branch direction. */
6445
+ opnd_t dir_op = opnd_create_reg (dir );
6446
+ instr_t * cset = INSTR_CREATE_csinc (
6447
+ dcontext , dir_op , OPND_CREATE_ZR (dir_op ), OPND_CREATE_ZR (dir_op ),
6448
+ opnd_create_cond (opc == OP_cbnz ? DR_PRED_EQ : DR_PRED_NE ));
6449
+ MINSERT (ilist , instr , cset );
6450
+ } else if (opc == OP_tbnz || opc == OP_tbz ) {
6451
+ opnd_t reg_op = instr_get_src (instr , 1 );
6452
+ reg_id_t reg = opnd_get_reg (reg_op );
6453
+ reg_id_t dir_same_width = DR_REG_NULL ;
6454
+ /* If the register is stolen, we need to read the actual value first. */
6455
+ if (reg_is_stolen (reg )) {
6456
+ /* Save old value of temp register to SPILL_SLOT_3. */
6457
+ dr_save_reg (dcontext , ilist , instr , temp , SPILL_SLOT_3 );
6458
+ /* Read actual register value if stolen */
6459
+ dr_insert_get_stolen_reg_value (dcontext , ilist , instr , temp );
6460
+ /* Use temp register to access actual register value. */
6461
+ temp_used = true;
6462
+ reg = reg_resize_to_opsz (temp , reg_get_size (reg ));
6463
+ reg_op = opnd_create_reg (reg );
6464
+ }
6465
+
6466
+ /* Use dir register to compute direction. */
6467
+ dir = (reg_to_pointer_sized (reg ) == DR_REG_X0 ) ? DR_REG_X1 : DR_REG_X0 ;
6468
+ dir_same_width = reg_resize_to_opsz (dir , reg_get_size (reg ));
6469
+ /* Save old value of dir register to SPILL_SLOT_1. */
6470
+ dr_save_reg (dcontext , ilist , instr , dir , SPILL_SLOT_1 );
6471
+
6472
+ /* Extract tst_bit from reg. */
6473
+ int tst_bit = opnd_get_immed_int (instr_get_src (instr , 2 ));
6474
+ opnd_t dir_same_width_op = opnd_create_reg (dir_same_width );
6475
+ instr_t * ubfm =
6476
+ INSTR_CREATE_ubfm (dcontext , dir_same_width_op , reg_op ,
6477
+ OPND_CREATE_INT (tst_bit ), OPND_CREATE_INT (tst_bit ));
6478
+ MINSERT (ilist , instr , ubfm );
6479
+
6480
+ /* Invert result if tbz. */
6481
+ if (opc == OP_tbz ) {
6482
+ instr_t * eor =
6483
+ INSTR_CREATE_eor (dcontext , dir_same_width_op , OPND_CREATE_INT (1 ));
6484
+ MINSERT (ilist , instr , eor );
6485
+ }
6486
+ } else if (opc == OP_bcond ) {
6487
+ /* Use dir register to compute direction. */
6488
+ dir = SCRATCH_REG0 ;
6489
+ /* Save old value of dir register to SPILL_SLOT_1. */
6490
+ dr_save_reg (dcontext , ilist , instr , dir , SPILL_SLOT_1 );
6491
+ /* Compute branch direction. */
6492
+ dr_pred_type_t pred = instr_get_predicate (instr );
6493
+ opnd_t dir_op = opnd_create_reg (dir );
6494
+ instr_t * cset = INSTR_CREATE_csinc (
6495
+ dcontext , dir_op , OPND_CREATE_ZR (dir_op ), OPND_CREATE_ZR (dir_op ),
6496
+ opnd_create_cond (instr_invert_predicate (pred )));
6497
+ MINSERT (ilist , instr , cset );
6498
+ } else {
6499
+ CLIENT_ASSERT (false, "unknown conditional branch type" );
6500
+ return ;
6501
+ }
6502
+
6503
+ if (has_fallthrough ) {
6504
+ ptr_uint_t fallthrough = address + instr_length (drcontext , instr );
6505
+ CLIENT_ASSERT (fallthrough > address , "wrong fallthrough address" );
6506
+ dr_insert_clean_call_ex (
6507
+ drcontext , ilist , instr , callee ,
6508
+ /* Many users will ask for mcontexts; some will set; it doesn't seem worth
6509
+ * asking the user to pass in a flag: if they're using this they are not
6510
+ * super concerned about overhead.
6511
+ */
6512
+ DR_CLEANCALL_READS_APP_CONTEXT | DR_CLEANCALL_WRITES_APP_CONTEXT , 5 ,
6513
+ /* Address of cbr is 1st parameter. */
6514
+ OPND_CREATE_INTPTR (address ),
6515
+ /* Target is 2nd parameter. */
6516
+ OPND_CREATE_INTPTR (target ),
6517
+ /* Fall-through is 3rd parameter. */
6518
+ OPND_CREATE_INTPTR (fallthrough ),
6519
+ /* Branch direction is 4th parameter. */
6520
+ opnd_create_reg (dir ),
6521
+ /* User defined data is 5th parameter. */
6522
+ opnd_is_null (user_data ) ? OPND_CREATE_INT32 (0 ) : user_data );
6523
+ } else {
6524
+ dr_insert_clean_call_ex (
6525
+ drcontext , ilist , instr , callee ,
6526
+ /* Many users will ask for mcontexts; some will set; it doesn't seem worth
6527
+ * asking the user to pass in a flag: if they're using this they are not
6528
+ * super concerned about overhead.
6529
+ */
6530
+ DR_CLEANCALL_READS_APP_CONTEXT | DR_CLEANCALL_WRITES_APP_CONTEXT , 3 ,
6531
+ /* Address of cbr is 1st parameter. */
6532
+ OPND_CREATE_INTPTR (address ),
6533
+ /* Target is 2nd parameter. */
6534
+ OPND_CREATE_INTPTR (target ),
6535
+ /* Branch direction is 3rd parameter. */
6536
+ opnd_create_reg (dir ));
6537
+ }
6538
+
6539
+ /* Restore state */
6540
+ if (opc == OP_cbnz || opc == OP_cbz ) {
6541
+ /* Restore arith flags. */
6542
+ dr_restore_arith_flags_from_reg (dcontext , ilist , instr , flags );
6543
+ /* Restore old value of flags register. */
6544
+ dr_restore_reg (dcontext , ilist , instr , flags , SPILL_SLOT_2 );
6545
+ /* Restore old value of dir register. */
6546
+ dr_restore_reg (dcontext , ilist , instr , dir , SPILL_SLOT_1 );
6547
+ } else if (opc == OP_bcond || opc == OP_tbnz || opc == OP_tbz ) {
6548
+ /* Restore old value of dir register. */
6549
+ dr_restore_reg (dcontext , ilist , instr , dir , SPILL_SLOT_1 );
6550
+ } else {
6551
+ CLIENT_ASSERT (false, "unknown conditional branch type" );
6552
+ }
6553
+ if (temp_used ) {
6554
+ /* Restore old value of temp register. */
6555
+ dr_restore_reg (dcontext , ilist , instr , temp , SPILL_SLOT_3 );
6556
+ }
6557
+ #endif /* X86/ARM/RISCV64/AARCH64 */
6371
6558
}
6372
6559
6373
6560
DR_API void
0 commit comments