diff --git a/clients/drcachesim/tracer/output.cpp b/clients/drcachesim/tracer/output.cpp index 99472c41f02..6f28e14e0f8 100644 --- a/clients/drcachesim/tracer/output.cpp +++ b/clients/drcachesim/tracer/output.cpp @@ -728,9 +728,9 @@ output_buffer(void *drcontext, per_thread_t *data, byte *buf_base, byte *buf_ptr size_t header_size) { byte *pipe_start = buf_base; - byte *pipe_end = pipe_start; if (!op_offline.get_value()) { byte *post_header = buf_base + header_size; + byte *last_ok_to_split_ref = nullptr; // Pipe split headers are just the tid. header_size = instru->sizeof_entry(); for (byte *mem_ref = post_header; mem_ref < buf_ptr; @@ -743,7 +743,6 @@ output_buffer(void *drcontext, per_thread_t *data, byte *buf_base, byte *buf_ptr // it or one instr after. if (is_ok_to_split_before(instru->get_entry_type(mem_ref), instru->get_entry_size(mem_ref))) { - pipe_end = mem_ref; // We check the end of this entry + the max # of delay entries to // avoid splitting an instr from its subsequent bundle entry. // An alternative is to have the reader use per-thread state. @@ -752,8 +751,23 @@ output_buffer(void *drcontext, per_thread_t *data, byte *buf_base, byte *buf_ptr DR_ASSERT(is_ok_to_split_before( instru->get_entry_type(pipe_start + header_size), instru->get_entry_size(pipe_start + header_size))); - pipe_start = atomic_pipe_write(drcontext, pipe_start, pipe_end, - get_local_window(data)); + // Check if we went over the edge waiting for enough entries to + // write. If we did, we simply write till the last ok-to-split ref. + if (mem_ref - pipe_start > ipc_pipe.get_atomic_write_size()) { + DR_ASSERT_MSG( + last_ok_to_split_ref != nullptr, + "Found too many entries without an ok-to-split point"); + pipe_start = + atomic_pipe_write(drcontext, pipe_start, last_ok_to_split_ref, + get_local_window(data)); + last_ok_to_split_ref = mem_ref; + } else { + pipe_start = atomic_pipe_write(drcontext, pipe_start, mem_ref, + get_local_window(data)); + last_ok_to_split_ref = nullptr; + } + } else { + last_ok_to_split_ref = mem_ref; } } } @@ -767,7 +781,9 @@ output_buffer(void *drcontext, per_thread_t *data, byte *buf_base, byte *buf_ptr DR_ASSERT( is_ok_to_split_before(instru->get_entry_type(pipe_start + header_size), instru->get_entry_size(pipe_start + header_size))); - pipe_start = atomic_pipe_write(drcontext, pipe_start, pipe_end, + DR_ASSERT_MSG(last_ok_to_split_ref != nullptr, + "Found too many entries without an ok-to-split point"); + pipe_start = atomic_pipe_write(drcontext, pipe_start, last_ok_to_split_ref, get_local_window(data)); } if ((buf_ptr - pipe_start) > (ssize_t)buf_hdr_slots_size) { diff --git a/core/arch/arch.c b/core/arch/arch.c index a7237327f16..0c29eb58b89 100644 --- a/core/arch/arch.c +++ b/core/arch/arch.c @@ -3893,7 +3893,7 @@ get_time() bool is_ibl_routine_type(dcontext_t *dcontext, cache_pc target, ibl_branch_type_t branch_type) { - ibl_type_t ibl_type; + ibl_type_t ibl_type = { 0 }; DEBUG_DECLARE(bool is_ibl =) get_ibl_routine_type_ex(dcontext, target, &ibl_type _IF_X86_64(NULL)); ASSERT(is_ibl); diff --git a/core/fragment.h b/core/fragment.h index 50d0c35123c..85b3285783c 100644 --- a/core/fragment.h +++ b/core/fragment.h @@ -222,11 +222,14 @@ frag_flags_from_isa_mode(dr_isa_mode_t mode) } /* to save space size field is a ushort => maximum fragment size */ -#ifndef AARCH64 -enum { MAX_FRAGMENT_SIZE = USHRT_MAX }; -#else +#ifdef AARCH64 /* On AArch64, TBNZ/TBZ has a range of +/- 32 KiB. */ enum { MAX_FRAGMENT_SIZE = 0x8000 }; +#elif defined(RISCV64) +/* On RISCV64, direct branch has a range of +/- 4 KiB. */ +enum { MAX_FRAGMENT_SIZE = 0x1000 }; +#else +enum { MAX_FRAGMENT_SIZE = USHRT_MAX }; #endif /* fragment structure used for basic blocks and traces diff --git a/core/ir/opnd_api.h b/core/ir/opnd_api.h index 62bc82e0d62..a9eb205dffc 100644 --- a/core/ir/opnd_api.h +++ b/core/ir/opnd_api.h @@ -1930,7 +1930,7 @@ enum { FAR_PC_kind, /* a segment is specified as a selector value */ FAR_INSTR_kind, /* a segment is specified as a selector value */ # if defined(X64) || defined(ARM) - REL_ADDR_kind, /* pc-relative address: ARM or 64-bit X86 only */ + REL_ADDR_kind, /* pc-relative address: ARM/RISCV64/64-bit X86 only */ # endif # ifdef X64 ABS_ADDR_kind, /* 64-bit absolute address: x64 only */ diff --git a/core/ir/riscv64/codec.c b/core/ir/riscv64/codec.c index a4dea48b048..cb5d636c346 100644 --- a/core/ir/riscv64/codec.c +++ b/core/ir/riscv64/codec.c @@ -486,7 +486,9 @@ decode_u_immpc_opnd(dcontext_t *dc, uint32_t inst, int op_sz, byte *pc, byte *or int idx, instr_t *out) { int32_t uimm = GET_FIELD(inst, 31, 12); - opnd_t opnd = opnd_create_pc(orig_pc + (uimm << 12)); + /* OPSZ_0 is used here to indicate that this is not a real memory access instruction. + */ + opnd_t opnd = opnd_create_rel_addr(orig_pc + (uimm << 12), OPSZ_0); instr_set_src(out, idx, opnd); return true; } @@ -1937,8 +1939,8 @@ encode_u_immpc_opnd(instr_t *instr, byte *pc, int idx, uint32_t *out, decode_inf { opnd_t opnd = instr_get_src(instr, idx); uint32_t imm; - if (opnd.kind == PC_kind) - imm = opnd_get_pc(opnd) - pc; + if (opnd.kind == REL_ADDR_kind) + imm = (app_pc)opnd_get_addr(opnd) - pc; else if (opnd.kind == INSTR_kind) imm = (byte *)opnd_get_instr(opnd)->offset - (byte *)instr->offset; else diff --git a/core/ir/riscv64/instr.c b/core/ir/riscv64/instr.c index f11e47ff56f..60bd1bec2ee 100644 --- a/core/ir/riscv64/instr.c +++ b/core/ir/riscv64/instr.c @@ -48,16 +48,58 @@ instr_get_isa_mode(instr_t *instr) int instr_length_arch(dcontext_t *dcontext, instr_t *instr) { - /* FIXME i#3544: Compressed Instructions ISA extension has a shorter instruction - * length. */ - return RISCV64_INSTR_SIZE; + int opcode = instr_get_opcode(instr); + switch (opcode) { + case OP_LABEL: return 0; + case OP_c_flwsp: + case OP_c_fswsp: + case OP_c_flw: + case OP_c_fsw: + case OP_c_jal: + case OP_c_ldsp: + case OP_c_sdsp: + case OP_c_ld: + case OP_c_sd: + case OP_c_addiw: + case OP_c_addw: + case OP_c_subw: + case OP_c_lwsp: + case OP_c_fldsp: + case OP_c_swsp: + case OP_c_fsdsp: + case OP_c_lw: + case OP_c_fld: + case OP_c_sw: + case OP_c_fsd: + case OP_c_j: + case OP_c_jr: + case OP_c_jalr: + case OP_c_beqz: + case OP_c_bnez: + case OP_c_li: + case OP_c_lui: + case OP_c_addi: + case OP_c_addi16sp: + case OP_c_addi4spn: + case OP_c_slli: + case OP_c_srli: + case OP_c_srai: + case OP_c_andi: + case OP_c_mv: + case OP_c_add: + case OP_c_and: + case OP_c_or: + case OP_c_xor: + case OP_c_sub: + case OP_c_nop: + case OP_c_ebreak: return RISCV64_INSTR_COMPRESSED_SIZE; + default: return RISCV64_INSTR_SIZE; + } } bool opc_is_not_a_real_memory_load(int opc) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return opc == OP_auipc; } @@ -120,46 +162,40 @@ bool instr_is_call_arch(instr_t *instr) { int opc = instr_get_opcode(instr); - return (opc == OP_jal || opc == OP_jalr || opc == OP_c_j || opc == OP_c_jal || - opc == OP_c_jr || opc == OP_c_jalr); + return ((opc == OP_jal || opc == OP_jalr || opc == OP_c_jal || opc == OP_c_jalr) && + opnd_get_reg(instr_get_dst(instr, 0)) != DR_REG_ZERO); } bool instr_is_call_direct(instr_t *instr) { - /* FIXME i#3544: Check if valid */ int opc = instr_get_opcode(instr); - return (opc == OP_jal); + return ((opc == OP_jal || opc == OP_c_jal) && + opnd_get_reg(instr_get_dst(instr, 0)) != DR_REG_ZERO); } bool instr_is_near_call_direct(instr_t *instr) { - /* FIXME i#3544: Check if valid */ - int opc = instr_get_opcode(instr); - return (opc == OP_jal); + return instr_is_call_direct(instr); } bool instr_is_call_indirect(instr_t *instr) { - /* FIXME i#3544: Check if valid */ int opc = instr_get_opcode(instr); - return (opc == OP_jalr); + return ((opc == OP_jalr || opc == OP_c_jalr) && + opnd_get_reg(instr_get_dst(instr, 0)) != DR_REG_ZERO); } bool instr_is_return(instr_t *instr) { - /* FIXME i#3544: Check if valid */ int opc = instr_get_opcode(instr); - if (instr_num_srcs(instr) < 1 || instr_num_dsts(instr) < 1) - return false; - opnd_t rd = instr_get_dst(instr, 0); - opnd_t rs = instr_get_src(instr, 0); - return (opc == OP_jalr && opnd_get_reg(rd) == DR_REG_X0 && - opnd_is_memory_reference(rs) && opnd_get_base(rs) == DR_REG_X1 && - opnd_get_disp(rs) == 0); + return ((opc == OP_c_jr || opc == OP_jalr) && + opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_X0 && + opnd_get_reg(instr_get_src(instr, 0)) == DR_REG_RA && + opnd_get_immed_int(instr_get_src(instr, 1)) == 0); } bool @@ -173,20 +209,13 @@ instr_is_cbr_arch(instr_t *instr) bool instr_is_mbr_arch(instr_t *instr) { - int opc = instr->opcode; /* caller ensures opcode is valid */ - switch (opc) { - case OP_jalr: - case OP_c_jalr: - case OP_c_jr: return true; - default: return false; - } + int opc = instr_get_opcode(instr); + return (opc == OP_jalr || opc == OP_c_jr || opc == OP_c_jalr); } bool instr_is_far_cti(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return false; } @@ -194,7 +223,8 @@ bool instr_is_ubr_arch(instr_t *instr) { int opc = instr_get_opcode(instr); - return opc == OP_jal || opc == OP_jalr; + return ((opc == OP_jal || opc == OP_c_j) && + opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_ZERO); } bool @@ -206,8 +236,9 @@ instr_is_near_ubr(instr_t *instr) bool instr_is_cti_short(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); + /* The branch with smallest reach is direct branch, with range +/- 4 KiB. + * We have restricted MAX_FRAGMENT_SIZE on RISCV64 accordingly. + */ return false; } @@ -226,15 +257,13 @@ instr_is_cti_short_rewrite(instr_t *instr, byte *pc) bool instr_is_interrupt(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); - return false; + int opc = instr_get_opcode(instr); + return (opc == OP_ecall); } bool instr_is_syscall(instr_t *instr) { - /* FIXME i#3544: Check if valid */ int opc = instr_get_opcode(instr); return (opc == OP_ecall); } @@ -242,40 +271,46 @@ instr_is_syscall(instr_t *instr) bool instr_is_mov_constant(instr_t *instr, ptr_int_t *value) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); + uint opc = instr_get_opcode(instr); + + if (opc == OP_addi || opc == OP_addiw || opc == OP_c_addi || opc == OP_c_addiw || + opc == OP_c_addi4spn || opc == OP_c_addi16sp) { + opnd_t op1 = instr_get_src(instr, 0); + opnd_t op2 = instr_get_src(instr, 1); + if (opnd_is_reg(op1) && opnd_get_reg(op1) == DR_REG_X0) { + *value = opnd_get_immed_int(op2); + return true; + } + } return false; } bool instr_is_prefetch(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); - return false; + switch (instr_get_opcode(instr)) { + case OP_prefetch_i: + case OP_prefetch_r: + case OP_prefetch_w: return true; + default: return false; + } } bool instr_is_string_op(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return false; } bool instr_is_rep_string_op(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return false; } bool instr_saves_float_pc(instr_t *instr) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return false; } @@ -334,8 +369,6 @@ instr_predicate_writes_eflags(dr_pred_type_t pred) bool instr_predicate_is_cond(dr_pred_type_t pred) { - /* FIXME i#3544: Not implemented */ - ASSERT_NOT_IMPLEMENTED(false); return false; } diff --git a/core/unix/os.c b/core/unix/os.c index d5133bf1646..d71cc34d4bc 100644 --- a/core/unix/os.c +++ b/core/unix/os.c @@ -10503,7 +10503,7 @@ wait_for_event(event_t e, int timeout_ms) #ifdef DEBUG dcontext_t *dcontext = get_thread_private_dcontext(); #endif - uint64 start_time, cur_time; + uint64 start_time = 0, cur_time = 0; if (timeout_ms > 0) start_time = query_time_millis(); /* Use a user-space event on Linux, a kernel event on Windows. */ diff --git a/suite/tests/api/ir_riscv64.c b/suite/tests/api/ir_riscv64.c index 9d46183a75c..cf8eb856bdf 100644 --- a/suite/tests/api/ir_riscv64.c +++ b/suite/tests/api/ir_riscv64.c @@ -1115,15 +1115,15 @@ test_jump_and_branch(void *dc) /* Not printing disassembly for jal and branch instructions below, see comment of * test_instr_encoding_jal_or_branch(). */ instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0), - opnd_create_pc(pc + (3 << 12))); + OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0)); test_instr_encoding_auipc(dc, OP_auipc, pc, instr); instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0), - opnd_create_pc(pc - (3 << 12))); + OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0)); test_instr_encoding_auipc(dc, OP_auipc, pc, instr); instr = INSTR_CREATE_auipc(dc, opnd_create_reg(DR_REG_A0), - opnd_create_pc(pc + (3 << 12))); + OPND_CREATE_ABSMEM(pc + (3 << 12), OPSZ_0)); /* This is expected to fail since we are using an unaligned PC (i.e. target_pc - * instr_encode_pc has non-zero lower 12 bits). */ test_instr_encoding_failure(dc, OP_auipc, pc + 4, instr); diff --git a/suite/tests/api/ir_riscv64.expect b/suite/tests/api/ir_riscv64.expect index 3bd9cf309f1..27f95d8fe5a 100644 --- a/suite/tests/api/ir_riscv64.expect +++ b/suite/tests/api/ir_riscv64.expect @@ -221,7 +221,7 @@ c.xor fp a5 -> fp c.sub fp a5 -> fp test_integer_arith complete lui 0x2a -> a0 - a0'> + 0x0000004000018244 -> a0'> jalr a1 0x2a -> a0 c.li zero 31 -> a1 c.lui 1 -> a1