From patchwork Thu Nov 2 17:44:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yang Liu X-Patchwork-Id: 78957 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4E3D43858C36 for ; Thu, 2 Nov 2023 17:44:48 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from cstnet.cn (smtp81.cstnet.cn [159.226.251.81]) by sourceware.org (Postfix) with ESMTPS id BB3033858D28 for ; Thu, 2 Nov 2023 17:44:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BB3033858D28 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=iscas.ac.cn Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=iscas.ac.cn ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BB3033858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=159.226.251.81 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698947074; cv=none; b=YG5xjZ3Cbw6In4mDssWoO6YnrBOhKz145jjF6baqxUpBz517rW3HWsR7bE+7R9WQx8XHiyxEbrMFglztPgGCvVfrX3SMktaCUtNdCQQAoZgIg2lAYRXkSbLgMRBoAA9srQj7OHjj0vPjp4VWMZjE0H7nZ+fj80dEPuWgTXzl8zc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1698947074; c=relaxed/simple; bh=TI8eyL3iUhYrAeCMJgamdkd5Qt8VXSdrS7wope5MMxY=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=vxZeOZnLooGE7Q+ZrPhM36BScwX959egc4WRw5jvQByTUEtEF4tZ29iHLnhtI3N5AvBZNc8Jik61Uo9W8v9Gjfza1QrWmPPRWnIEJZuK/s7pjAhENXCI15o/znrNjZcoV5T9TwEsMW9cySzXcoRTepsAnR9O0WvU2d3klnEpyUo= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from localhost.localdomain (unknown [113.120.165.216]) by APP-03 (Coremail) with SMTP id rQCowABXXpb030Nl5klFAg--.59565S2; Fri, 03 Nov 2023 01:44:21 +0800 (CST) From: Yang Liu To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, palmer@dabbelt.com, simon.marchi@polymtl.ca, Yang Liu Subject: [PATCH v2] gdb: RISC-V: Refine lr/sc sequence support Date: Fri, 3 Nov 2023 01:44:18 +0800 Message-ID: <20231102174418.46080-1-liuyang22@iscas.ac.cn> X-Mailer: git-send-email 2.42.0 MIME-Version: 1.0 X-CM-TRANSID: rQCowABXXpb030Nl5klFAg--.59565S2 X-Coremail-Antispam: 1UD129KBjvJXoWfGF4rur18uryrCr1xtrWxCrg_yoWkXw4rpr s3Cw40yr4UJa1fArn7JF4DWw4rAr45C3s5Jr1qq3yIkasIqr43WFyDKw1a93Z7CF1j9w13 uayakr4UCa1ayaDanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUkl14x267AKxVWUJVW8JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2ocxC64kIII0Yj41l84x0c7CEw4AK67xGY2AK02 1l84ACjcxK6xIIjxv20xvE14v26r1j6r1xM28EF7xvwVC0I7IYx2IY6xkF7I0E14v26r1j 6r4UM28EF7xvwVC2z280aVAFwI0_Jr0_Gr1l84ACjcxK6I8E87Iv6xkF7I0E14v26r4j6r 4UJwAac4AC62xK8xCEY4vEwIxC4wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC 0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr 1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4x0x7Aq67IIx4CEVc8vx2IE rcIFxwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14 v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkG c2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUJVWUCwCI42IY6xIIjxv20xvEc7CjxVAFwI 0_Jr0_Gr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4U MIIF0xvEx4A2jsIEc7CjxVAFwI0_Jr0_GrUvcSsGvfC2KfnxnUUI43ZEXa7VUb0PfJUUUU U== X-Originating-IP: [113.120.165.216] X-CM-SenderInfo: 5olx5tdqjsjq5lvft2wodfhubq/ X-Spam-Status: No, score=-13.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Per RISC-V spec, the lr/sc sequence can consist of up to 16 instructions, and we cannot insert breakpoints in the middle of this sequence. Before this, we only detected a specific pattern (the most common one). This patch improves this part and now supports more complex pattern detection. gdb/ChangeLog: * gdb/riscv-tdep.c (class riscv_insn): Add more needed opcode enums. (riscv_insn::decode): Decode newly added opcodes. (riscv_insn_is_non_cti_and_allowed_in_atomic_sequence): New. (riscv_insn_is_direct_branch): New. (riscv_next_pc_atomic_sequence): Removed. (riscv_deal_with_atomic_sequence): Rename from riscv_next_pc_atomic_sequence. (riscv_software_single_step): Adjust to use the renamed one. Signed-off-by: Yang Liu --- gdb/riscv-tdep.c | 275 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 236 insertions(+), 39 deletions(-) diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 3a2891c2c92..3c5afea99ca 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1578,8 +1578,34 @@ class riscv_insn BLTU, BGEU, /* These are needed for stepping over atomic sequences. */ - LR, - SC, + SLTI, + SLTIU, + XORI, + ORI, + ANDI, + SLLI, + SLLIW, + SRLI, + SRLIW, + SRAI, + SRAIW, + SUB, + SUBW, + SLL, + SLLW, + SLT, + SLTU, + XOR, + SRL, + SRLW, + SRA, + SRAW, + OR, + AND, + LR_W, + LR_D, + SC_W, + SC_D, /* This instruction is used to do a syscall. */ ECALL, @@ -1768,6 +1794,13 @@ class riscv_insn m_imm.s = EXTRACT_CBTYPE_IMM (ival); } + void decode_ca_type_insn (enum opcode opcode, ULONGEST ival) + { + m_opcode = opcode; + m_rs1 = decode_register_index_short (ival, OP_SH_CRS1S); + m_rs2 = decode_register_index_short (ival, OP_SH_CRS2S); + } + /* Fetch instruction from target memory at ADDR, return the content of the instruction, and update LEN with the instruction length. */ static ULONGEST fetch_instruction (struct gdbarch *gdbarch, @@ -1882,14 +1915,62 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) decode_b_type_insn (BLTU, ival); else if (is_bgeu_insn (ival)) decode_b_type_insn (BGEU, ival); + else if (is_slti_insn(ival)) + decode_i_type_insn (SLTI, ival); + else if (is_sltiu_insn(ival)) + decode_i_type_insn (SLTIU, ival); + else if (is_xori_insn(ival)) + decode_i_type_insn (XORI, ival); + else if (is_ori_insn(ival)) + decode_i_type_insn (ORI, ival); + else if (is_andi_insn(ival)) + decode_i_type_insn (ANDI, ival); + else if (is_slli_insn(ival)) + decode_i_type_insn (SLLI, ival); + else if (is_slliw_insn(ival)) + decode_i_type_insn (SLLIW, ival); + else if (is_srli_insn(ival)) + decode_i_type_insn (SRLI, ival); + else if (is_srliw_insn(ival)) + decode_i_type_insn (SRLIW, ival); + else if (is_srai_insn(ival)) + decode_i_type_insn (SRAI, ival); + else if (is_sraiw_insn(ival)) + decode_i_type_insn (SRAIW, ival); + else if (is_sub_insn(ival)) + decode_r_type_insn (SUB, ival); + else if (is_subw_insn(ival)) + decode_r_type_insn (SUBW, ival); + else if (is_sll_insn(ival)) + decode_r_type_insn (SLL, ival); + else if (is_sllw_insn(ival)) + decode_r_type_insn (SLLW, ival); + else if (is_slt_insn(ival)) + decode_r_type_insn (SLT, ival); + else if (is_sltu_insn(ival)) + decode_r_type_insn (SLTU, ival); + else if (is_xor_insn(ival)) + decode_r_type_insn (XOR, ival); + else if (is_srl_insn(ival)) + decode_r_type_insn (SRL, ival); + else if (is_srlw_insn(ival)) + decode_r_type_insn (SRLW, ival); + else if (is_sra_insn(ival)) + decode_r_type_insn (SRA, ival); + else if (is_sraw_insn(ival)) + decode_r_type_insn (SRAW, ival); + else if (is_or_insn(ival)) + decode_r_type_insn (OR, ival); + else if (is_and_insn(ival)) + decode_r_type_insn (AND, ival); else if (is_lr_w_insn (ival)) - decode_r_type_insn (LR, ival); + decode_r_type_insn (LR_W, ival); else if (is_lr_d_insn (ival)) - decode_r_type_insn (LR, ival); + decode_r_type_insn (LR_D, ival); else if (is_sc_w_insn (ival)) - decode_r_type_insn (SC, ival); + decode_r_type_insn (SC_W, ival); else if (is_sc_d_insn (ival)) - decode_r_type_insn (SC, ival); + decode_r_type_insn (SC_D, ival); else if (is_ecall_insn (ival)) decode_i_type_insn (ECALL, ival); else if (is_ld_insn (ival)) @@ -1944,6 +2025,24 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) m_rd = decode_register_index (ival, OP_SH_CRS1S); m_imm.s = EXTRACT_CITYPE_LUI_IMM (ival); } + else if (is_c_srli_insn (ival)) + decode_cb_type_insn (SRLI, ival); + else if (is_c_srai_insn (ival)) + decode_cb_type_insn (SRAI, ival); + else if (is_c_andi_insn (ival)) + decode_cb_type_insn (ANDI, ival); + else if (is_c_sub_insn (ival)) + decode_ca_type_insn (SUB, ival); + else if (is_c_xor_insn (ival)) + decode_ca_type_insn (XOR, ival); + else if (is_c_or_insn (ival)) + decode_ca_type_insn (OR, ival); + else if (is_c_and_insn (ival)) + decode_ca_type_insn (AND, ival); + else if (is_c_subw_insn (ival)) + decode_ca_type_insn (SUBW, ival); + else if (is_c_addw_insn (ival)) + decode_ca_type_insn (ADDW, ival); else if (is_c_li_insn (ival)) decode_ci_type_insn (LI, ival); /* C_SD and C_FSW have the same opcode. C_SD is RV64 and RV128 only, @@ -4404,51 +4503,149 @@ riscv_next_pc (struct regcache *regcache, CORE_ADDR pc) return next_pc; } +/* Return true if INSN is not a control transfer instruction and is allowed to + appear in the middle of the lr/sc sequence. */ + +static bool +riscv_insn_is_non_cti_and_allowed_in_atomic_sequence(const struct riscv_insn &insn) +{ + switch (insn.opcode ()) + { + case riscv_insn::LUI: + case riscv_insn::AUIPC: + case riscv_insn::ADDI: + case riscv_insn::ADDIW: + case riscv_insn::SLTI: + case riscv_insn::SLTIU: + case riscv_insn::XORI: + case riscv_insn::ORI: + case riscv_insn::ANDI: + case riscv_insn::SLLI: + case riscv_insn::SLLIW: + case riscv_insn::SRLI: + case riscv_insn::SRLIW: + case riscv_insn::SRAI: + case riscv_insn::ADD: + case riscv_insn::ADDW: + case riscv_insn::SRAIW: + case riscv_insn::SUB: + case riscv_insn::SUBW: + case riscv_insn::SLL: + case riscv_insn::SLLW: + case riscv_insn::SLT: + case riscv_insn::SLTU: + case riscv_insn::XOR: + case riscv_insn::SRL: + case riscv_insn::SRLW: + case riscv_insn::SRA: + case riscv_insn::SRAW: + case riscv_insn::OR: + case riscv_insn::AND: + return true; + } + + return false; +} + +/* Return true if INSN is a direct branch insctruction. */ + +static bool +riscv_insn_is_direct_branch(const struct riscv_insn &insn) +{ + switch (insn.opcode ()) + { + case riscv_insn::BEQ: + case riscv_insn::BNE: + case riscv_insn::BLT: + case riscv_insn::BGE: + case riscv_insn::BLTU: + case riscv_insn::BGEU: + case riscv_insn::JAL: + return true; + } + + return false; +} + /* We can't put a breakpoint in the middle of a lr/sc atomic sequence, so look for the end of the sequence and put the breakpoint there. */ -static bool -riscv_next_pc_atomic_sequence (struct regcache *regcache, CORE_ADDR pc, - CORE_ADDR *next_pc) +static std::vector +riscv_deal_with_atomic_sequence (struct regcache *regcache, CORE_ADDR pc) { struct gdbarch *gdbarch = regcache->arch (); struct riscv_insn insn; - CORE_ADDR cur_step_pc = pc; - CORE_ADDR last_addr = 0; + CORE_ADDR cur_step_pc = pc, next_pc; + std::vector next_pcs; + const int atomic_sequence_length = 16; + bool found_valid_atomic_sequence = false; + enum riscv_insn::opcode lr_opcode; /* First instruction has to be a load reserved. */ insn.decode (gdbarch, cur_step_pc); - if (insn.opcode () != riscv_insn::LR) - return false; - cur_step_pc = cur_step_pc + insn.length (); + lr_opcode = insn.opcode (); + if (lr_opcode != riscv_insn::LR_D && lr_opcode != riscv_insn::LR_W) + return {}; - /* Next instruction should be branch to exit. */ - insn.decode (gdbarch, cur_step_pc); - if (insn.opcode () != riscv_insn::BNE) - return false; - last_addr = cur_step_pc + insn.imm_signed (); - cur_step_pc = cur_step_pc + insn.length (); + /* A lr/sc sequence comprise at most 16 instructions placed sequentially in memory. */ + for (int insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) + { + cur_step_pc += insn.length (); + insn.decode (gdbarch, cur_step_pc); - /* Next instruction should be store conditional. */ - insn.decode (gdbarch, cur_step_pc); - if (insn.opcode () != riscv_insn::SC) - return false; - cur_step_pc = cur_step_pc + insn.length (); + /* The dynamic code executed between lr/sc can only contain instructions + from the base I instruction set, excluding loads, stores, backward jumps, + taken backward branches, JALR, FENCE, FENCE.I, and SYSTEM instructions. + If the C extension is supported, then compressed forms of the aforementioned + I instructions are also permitted. */ + + if (riscv_insn_is_non_cti_and_allowed_in_atomic_sequence (insn)) + { + continue; + } + /* Look for a conditional branch instruction, check if it's taken forward or not. */ + else if (riscv_insn_is_direct_branch (insn)) + { + if (insn.imm_signed () > 0) + { + next_pc = cur_step_pc + insn.imm_signed (); + next_pcs.push_back (next_pc); + } + else + break; + } + /* Look for a paired SC instruction which closes the atomic sequence. */ + else if ((insn.opcode () == riscv_insn::SC_D && lr_opcode == riscv_insn::LR_D) + || (insn.opcode () == riscv_insn::SC_W && lr_opcode == riscv_insn::LR_W)) + { + found_valid_atomic_sequence = true; + } + else + break; + } + + if (!found_valid_atomic_sequence) + return {}; /* Next instruction should be branch to start. */ insn.decode (gdbarch, cur_step_pc); if (insn.opcode () != riscv_insn::BNE) - return false; + return {}; if (pc != (cur_step_pc + insn.imm_signed ())) - return false; - cur_step_pc = cur_step_pc + insn.length (); + return {}; + cur_step_pc += insn.length (); - /* We should now be at the end of the sequence. */ - if (cur_step_pc != last_addr) - return false; + /* Remove all PCs that jump within the sequence. */ + auto matcher = [cur_step_pc] (const CORE_ADDR addr) + { + return addr < cur_step_pc; + }; + auto it = std::remove_if (next_pcs.begin (), next_pcs.end (), matcher); + next_pcs.erase (it, next_pcs.end ()); - *next_pc = cur_step_pc; - return true; + next_pc = cur_step_pc; + next_pcs.push_back (next_pc); + return next_pcs; } /* This is called just before we want to resume the inferior, if we want to @@ -4458,14 +4655,14 @@ riscv_next_pc_atomic_sequence (struct regcache *regcache, CORE_ADDR pc, std::vector riscv_software_single_step (struct regcache *regcache) { - CORE_ADDR pc, next_pc; - - pc = regcache_read_pc (regcache); + CORE_ADDR cur_pc = regcache_read_pc (regcache), next_pc; + std::vector next_pcs + = riscv_deal_with_atomic_sequence (regcache, cur_pc); - if (riscv_next_pc_atomic_sequence (regcache, pc, &next_pc)) - return {next_pc}; + if (!next_pcs.empty ()) + return next_pcs; - next_pc = riscv_next_pc (regcache, pc); + next_pc = riscv_next_pc (regcache, cur_pc); return {next_pc}; }