From patchwork Mon Mar 13 21:46:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 66326 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 806AF3858430 for ; Mon, 13 Mar 2023 21:47:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 806AF3858430 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1678744041; bh=fjAhQo86mJETDux+JrGc5Vb6YamQoh0drU5NE5zqYpA=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=hqU1VvnFC4kGhEnzkb7pP480OvIIjrKDz/B3mm4kwgj1MDOkoqJwH2DParA/S24we MZQUPYUc7tLQ05UDZzV+2G/sSQ5iYBmzStEmhWAxPLtksH5yeaURH6VqBP3F7/Um/P A7eharj+xb2dhtB6ovfPEjSjdIse/LN2IbwbPodU= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 8F67D3858D32 for ; Mon, 13 Mar 2023 21:46:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8F67D3858D32 Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-256-l4ssd2_gMfOaBrkv6pJnpQ-1; Mon, 13 Mar 2023 17:46:25 -0400 X-MC-Unique: l4ssd2_gMfOaBrkv6pJnpQ-1 Received: by mail-ed1-f70.google.com with SMTP id c1-20020a0564021f8100b004acbe232c03so18512348edc.9 for ; Mon, 13 Mar 2023 14:46:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678743984; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fjAhQo86mJETDux+JrGc5Vb6YamQoh0drU5NE5zqYpA=; b=XbjAep4aKkOcNjrhKVzXTP3rZznMWMAdHrs0yv3ap4tPNwDRUHA+7GiMaI8V2d5sxW JUHyopZQBhQwozhRR7Pyj0QgGAEHmdLHTquUdARGpYa3Amv7F/K96T/DrbY2hU6N9FfE Zlt+Kwq7RilGQUnouqe2f9h/x3gJOhtWhDGaipLfRYAnMO+FO2uunrcmn6UhGtBEjT50 oyQF4DhXb+mvjpnbRzzQCwcFXGP9B7h1dDzKSvb1vrt5mm/JrtRpdXuxZ901wgg4g9x0 8pa3syamF/jexkJIXf5r9XwO6N5m2OkB4kLMy1reNrAAkzfFLxaJ9ftAm3PtOn2cbG/m P4xg== X-Gm-Message-State: AO0yUKVYJ4XFPe/0zs4Y0SLVNvdBhuLCWC4Y4KSzt7ngbuxWJQxZH+x1 lmiNI8hJqVTKi7TEhWI6WPPKnDY5g7ll7K7JnKw9ewkq8otoniKYn4DEw+o+TWFtcrycAIdHiR2 xbevVQ0lyGkxGy3KhI+cGlEyXx20qjsEQ/IPG25iLy8wJgbRRZS1XQyUkHcmC6Mp50c9EG0srr6 EjsHFLQQ== X-Received: by 2002:a17:907:6d1a:b0:8b1:238b:80ac with SMTP id sa26-20020a1709076d1a00b008b1238b80acmr46918872ejc.67.1678743984408; Mon, 13 Mar 2023 14:46:24 -0700 (PDT) X-Google-Smtp-Source: AK7set/MXzDLv4AmNCS8BZXfU7eSYwBpdE6BK+DKlZOnd3UGkPCPVFhmFCjVZ2t6+K6FBlV3YSokXA== X-Received: by 2002:a17:907:6d1a:b0:8b1:238b:80ac with SMTP id sa26-20020a1709076d1a00b008b1238b80acmr46918847ejc.67.1678743983984; Mon, 13 Mar 2023 14:46:23 -0700 (PDT) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id ot10-20020a170906ccca00b008e51a1fd7bfsm260439ejb.172.2023.03.13.14.46.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Mar 2023 14:46:23 -0700 (PDT) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb/riscv: convert riscv debug settings to new debug print scheme Date: Mon, 13 Mar 2023 21:46:17 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP 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.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Convert the RISC-V specific debug settings to use the new debug printing scheme. This updates the following settings: set/show debug riscv breakpoints set/show debug riscv gdbarch set/show debug riscv infcall set/show debug riscv unwinder All of these settings now take a boolean rather than an integer, and all print their output using the new debug scheme. There should be no visible change for anyone not turning on debug. --- gdb/riscv-tdep.c | 223 +++++++++++++++++++++++++---------------------- 1 file changed, 120 insertions(+), 103 deletions(-) diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 388ce8c2519..ba7eab41ac6 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -73,25 +73,56 @@ static inline bool is_ ## INSN_NAME ## _insn (long insn) \ #include "opcode/riscv-opc.h" #undef DECLARE_INSN -/* When this is set to non-zero debugging information about breakpoint - kinds will be printed. */ +/* When this is true debugging information about breakpoint kinds will be + printed. */ -static unsigned int riscv_debug_breakpoints = 0; +static bool riscv_debug_breakpoints = false; -/* When this is set to non-zero debugging information about inferior calls - will be printed. */ +/* Print a "riscv-breakpoints" debug statement. */ + +#define riscv_breakpoints_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (riscv_debug_breakpoints, \ + "riscv-breakpoints", \ + fmt, ##__VA_ARGS__) + +/* When this is true debugging information about inferior calls will be + printed. */ + +static bool riscv_debug_infcall = false; + +/* Print a "riscv-infcall" debug statement. */ + +#define riscv_infcall_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (riscv_debug_infcall, "riscv-infcall", \ + fmt, ##__VA_ARGS__) + +/* Print "riscv-infcall" start/end debug statements. */ -static unsigned int riscv_debug_infcall = 0; +#define RISCV_INFCALL_SCOPED_DEBUG_START_END(fmt, ...) \ + scoped_debug_start_end (riscv_debug_infcall, "riscv-infcall", \ + fmt, ##__VA_ARGS__) -/* When this is set to non-zero debugging information about stack unwinding +/* When this is true debugging information about stack unwinding will be + printed. */ + +static bool riscv_debug_unwinder = false; + +/* Print a "riscv-unwinder" debug statement. */ + +#define riscv_unwinder_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (riscv_debug_unwinder, "riscv-unwinder", \ + fmt, ##__VA_ARGS__) + +/* When this is true debugging information about gdbarch initialisation will be printed. */ -static unsigned int riscv_debug_unwinder = 0; +static bool riscv_debug_gdbarch = false; -/* When this is set to non-zero debugging information about gdbarch - initialisation will be printed. */ +/* Print a "riscv-gdbarch" debug statement. */ -static unsigned int riscv_debug_gdbarch = 0; +#define riscv_gdbarch_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (riscv_debug_gdbarch, "riscv-gdbarch", \ + fmt, ##__VA_ARGS__) /* The names of the RISC-V target description features. */ const char *riscv_feature_name_csr = "org.gnu.gdb.riscv.csr"; @@ -831,13 +862,15 @@ riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) const char *bp = (unaligned_p || riscv_insn_length (buf[0]) == 2 ? "C.EBREAK" : "EBREAK"); - gdb_printf (gdb_stdlog, "Using %s for breakpoint at %s ", - bp, paddress (gdbarch, *pcptr)); + std::string suffix; if (unaligned_p) - gdb_printf (gdb_stdlog, "(unaligned address)\n"); + suffix = "(unaligned address)"; else - gdb_printf (gdb_stdlog, "(instruction length %d)\n", - riscv_insn_length (buf[0])); + suffix = string_printf ("(instruction length %d)", + riscv_insn_length (buf[0])); + riscv_breakpoints_debug_printf ("Using %s for breakpoint at %s %s", + bp, paddress (gdbarch, *pcptr), + suffix.c_str ()); } if (unaligned_p || riscv_insn_length (buf[0]) == 2) return 2; @@ -1970,12 +2003,9 @@ riscv_scan_prologue (struct gdbarch *gdbarch, regs[regno] = pv_register (regno, 0); pv_area stack (RISCV_SP_REGNUM, gdbarch_addr_bit (gdbarch)); - if (riscv_debug_unwinder) - gdb_printf - (gdb_stdlog, - "Prologue scan for function starting at %s (limit %s)\n", - core_addr_to_string (start_pc), - core_addr_to_string (end_pc)); + riscv_unwinder_debug_printf ("function starting at %s (limit %s)", + core_addr_to_string (start_pc), + core_addr_to_string (end_pc)); for (next_pc = cur_pc = start_pc; cur_pc < end_pc; cur_pc = next_pc) { @@ -2107,9 +2137,8 @@ riscv_scan_prologue (struct gdbarch *gdbarch, if (end_prologue_addr == 0) end_prologue_addr = cur_pc; - if (riscv_debug_unwinder) - gdb_printf (gdb_stdlog, "End of prologue at %s\n", - core_addr_to_string (end_prologue_addr)); + riscv_unwinder_debug_printf ("end of prologue at %s", + core_addr_to_string (end_prologue_addr)); if (cache != NULL) { @@ -2138,17 +2167,13 @@ riscv_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR offset; if (stack.find_reg (gdbarch, i, &offset)) { - if (riscv_debug_unwinder) - { - /* Display OFFSET as a signed value, the offsets are from - the frame base address to the registers location on - the stack, with a descending stack this means the - offsets are always negative. */ - gdb_printf (gdb_stdlog, - "Register $%s at stack offset %s\n", - gdbarch_register_name (gdbarch, i), - plongest ((LONGEST) offset)); - } + /* Display OFFSET as a signed value, the offsets are from the + frame base address to the registers location on the stack, + with a descending stack this means the offsets are always + negative. */ + riscv_unwinder_debug_printf ("register $%s at stack offset %s", + gdbarch_register_name (gdbarch, i), + plongest ((LONGEST) offset)); cache->regs[i].set_addr (offset); } } @@ -2221,12 +2246,10 @@ riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, there will be no need to write to memory later. */ int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn)); - if (riscv_debug_breakpoints || riscv_debug_infcall) - gdb_printf (gdb_stdlog, - "Writing %s-byte nop instruction to %s: %s\n", - plongest (sizeof (nop_insn)), - paddress (gdbarch, *bp_addr), - (status == 0 ? "success" : "failed")); + riscv_infcall_debug_printf ("writing %s-byte nop instruction to %s: %s", + plongest (sizeof (nop_insn)), + paddress (gdbarch, *bp_addr), + (status == 0 ? "success" : "failed")); return sp; } @@ -3077,35 +3100,36 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, sp = sp_refs = align_down (sp - call_info.memory.ref_offset, SP_ALIGNMENT); sp = sp_args = align_down (sp - call_info.memory.arg_offset, SP_ALIGNMENT); - if (riscv_debug_infcall > 0) + if (riscv_debug_infcall) { - gdb_printf (gdb_stdlog, "dummy call args:\n"); - gdb_printf (gdb_stdlog, ": floating point ABI %s in use\n", - (riscv_has_fp_abi (gdbarch) ? "is" : "is not")); - gdb_printf (gdb_stdlog, ": xlen: %d\n: flen: %d\n", - call_info.xlen, call_info.flen); + RISCV_INFCALL_SCOPED_DEBUG_START_END ("dummy call args"); + riscv_infcall_debug_printf ("floating point ABI %s in use", + (riscv_has_fp_abi (gdbarch) + ? "is" : "is not")); + riscv_infcall_debug_printf ("xlen: %d", call_info.xlen); + riscv_infcall_debug_printf ("flen: %d", call_info.flen); if (return_method == return_method_struct) - gdb_printf (gdb_stdlog, - "[*] struct return pointer in register $A0\n"); + riscv_infcall_debug_printf + ("[**] struct return pointer in register $A0"); for (i = 0; i < nargs; ++i) { struct riscv_arg_info *info = &arg_info [i]; + string_file tmp; - gdb_printf (gdb_stdlog, "[%2d] ", i); - riscv_print_arg_location (gdb_stdlog, gdbarch, info, sp_refs, sp_args); - gdb_printf (gdb_stdlog, "\n"); + riscv_print_arg_location (&tmp, gdbarch, info, sp_refs, sp_args); + riscv_infcall_debug_printf ("[%2d] %s", i, tmp.string ().c_str ()); } if (call_info.memory.arg_offset > 0 || call_info.memory.ref_offset > 0) { - gdb_printf (gdb_stdlog, " Original sp: %s\n", - core_addr_to_string (osp)); - gdb_printf (gdb_stdlog, "Stack required (for args): 0x%x\n", - call_info.memory.arg_offset); - gdb_printf (gdb_stdlog, "Stack required (for refs): 0x%x\n", - call_info.memory.ref_offset); - gdb_printf (gdb_stdlog, " Stack allocated: %s\n", - core_addr_to_string_nz (osp - sp)); + riscv_infcall_debug_printf (" Original sp: %s", + core_addr_to_string (osp)); + riscv_infcall_debug_printf ("Stack required (for args): 0x%x", + call_info.memory.arg_offset); + riscv_infcall_debug_printf ("Stack required (for refs): 0x%x", + call_info.memory.ref_offset); + riscv_infcall_debug_printf (" Stack allocated: %s", + core_addr_to_string_nz (osp - sp)); } } @@ -3203,16 +3227,13 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, /* Set the dummy return value to bp_addr. A dummy breakpoint will be setup to execute the call. */ - if (riscv_debug_infcall > 0) - gdb_printf (gdb_stdlog, ": writing $ra = %s\n", - core_addr_to_string (bp_addr)); + riscv_infcall_debug_printf ("writing $ra = %s", + core_addr_to_string (bp_addr)); regcache_cooked_write_unsigned (regcache, RISCV_RA_REGNUM, bp_addr); /* Finally, update the stack pointer. */ - if (riscv_debug_infcall > 0) - gdb_printf (gdb_stdlog, ": writing $sp = %s\n", - core_addr_to_string (sp)); + riscv_infcall_debug_printf ("writing $sp = %s", core_addr_to_string (sp)); regcache_cooked_write_unsigned (regcache, RISCV_SP_REGNUM, sp); return sp; @@ -3235,12 +3256,11 @@ riscv_return_value (struct gdbarch *gdbarch, arg_type = check_typedef (type); riscv_arg_location (gdbarch, &info, &call_info, arg_type, false); - if (riscv_debug_infcall > 0) + if (riscv_debug_infcall) { - gdb_printf (gdb_stdlog, "riscv return value:\n"); - gdb_printf (gdb_stdlog, "[R] "); - riscv_print_arg_location (gdb_stdlog, gdbarch, &info, 0, 0); - gdb_printf (gdb_stdlog, "\n"); + string_file tmp; + riscv_print_arg_location (&tmp, gdbarch, &info, 0, 0); + riscv_infcall_debug_printf ("[R] %s", tmp.string ().c_str ()); } if (read_value != nullptr || writebuf != nullptr) @@ -3465,12 +3485,11 @@ riscv_frame_cache (frame_info_ptr this_frame, void **this_cache) cache->frame_base = (get_frame_register_unsigned (this_frame, cache->frame_base_reg) + cache->frame_base_offset); - if (riscv_debug_unwinder) - gdb_printf (gdb_stdlog, "Frame base is %s ($%s + 0x%x)\n", - core_addr_to_string (cache->frame_base), - gdbarch_register_name (gdbarch, - cache->frame_base_reg), - cache->frame_base_offset); + riscv_unwinder_debug_printf ("frame base is %s ($%s + 0x%x)", + core_addr_to_string (cache->frame_base), + gdbarch_register_name (gdbarch, + cache->frame_base_reg), + cache->frame_base_offset); /* The prologue scanner sets the address of registers stored to the stack as the offset of that register from the frame base. The prologue @@ -3799,8 +3818,7 @@ riscv_gdbarch_init (struct gdbarch_info info, tdesc = riscv_find_default_target_description (info); gdb_assert (tdesc != nullptr); - if (riscv_debug_gdbarch) - gdb_printf (gdb_stdlog, "Have got a target description\n"); + riscv_gdbarch_debug_printf ("have got a target description"); tdesc_arch_data_up tdesc_data = tdesc_data_alloc (); std::vector pending_aliases; @@ -3817,8 +3835,7 @@ riscv_gdbarch_init (struct gdbarch_info info, &pending_aliases, &features)); if (!valid_p) { - if (riscv_debug_gdbarch) - gdb_printf (gdb_stdlog, "Target description is not valid\n"); + riscv_gdbarch_debug_printf ("target description is not valid"); return NULL; } @@ -4262,45 +4279,45 @@ _initialize_riscv_tdep () &setdebugriscvcmdlist, &showdebugriscvcmdlist, &setdebuglist, &showdebuglist); - add_setshow_zuinteger_cmd ("breakpoints", class_maintenance, - &riscv_debug_breakpoints, _("\ + add_setshow_boolean_cmd ("breakpoints", class_maintenance, + &riscv_debug_breakpoints, _("\ Set riscv breakpoint debugging."), _("\ Show riscv breakpoint debugging."), _("\ When non-zero, print debugging information for the riscv specific parts\n\ of the breakpoint mechanism."), - NULL, - show_riscv_debug_variable, - &setdebugriscvcmdlist, &showdebugriscvcmdlist); + nullptr, + show_riscv_debug_variable, + &setdebugriscvcmdlist, &showdebugriscvcmdlist); - add_setshow_zuinteger_cmd ("infcall", class_maintenance, - &riscv_debug_infcall, _("\ + add_setshow_boolean_cmd ("infcall", class_maintenance, + &riscv_debug_infcall, _("\ Set riscv inferior call debugging."), _("\ Show riscv inferior call debugging."), _("\ When non-zero, print debugging information for the riscv specific parts\n\ of the inferior call mechanism."), - NULL, - show_riscv_debug_variable, - &setdebugriscvcmdlist, &showdebugriscvcmdlist); + nullptr, + show_riscv_debug_variable, + &setdebugriscvcmdlist, &showdebugriscvcmdlist); - add_setshow_zuinteger_cmd ("unwinder", class_maintenance, - &riscv_debug_unwinder, _("\ + add_setshow_boolean_cmd ("unwinder", class_maintenance, + &riscv_debug_unwinder, _("\ Set riscv stack unwinding debugging."), _("\ Show riscv stack unwinding debugging."), _("\ -When non-zero, print debugging information for the riscv specific parts\n\ +When on, print debugging information for the riscv specific parts\n\ of the stack unwinding mechanism."), - NULL, - show_riscv_debug_variable, - &setdebugriscvcmdlist, &showdebugriscvcmdlist); + nullptr, + show_riscv_debug_variable, + &setdebugriscvcmdlist, &showdebugriscvcmdlist); - add_setshow_zuinteger_cmd ("gdbarch", class_maintenance, - &riscv_debug_gdbarch, _("\ + add_setshow_boolean_cmd ("gdbarch", class_maintenance, + &riscv_debug_gdbarch, _("\ Set riscv gdbarch initialisation debugging."), _("\ Show riscv gdbarch initialisation debugging."), _("\ When non-zero, print debugging information for the riscv gdbarch\n\ initialisation process."), - NULL, - show_riscv_debug_variable, - &setdebugriscvcmdlist, &showdebugriscvcmdlist); + nullptr, + show_riscv_debug_variable, + &setdebugriscvcmdlist, &showdebugriscvcmdlist); /* Add root prefix command for all "set riscv" and "show riscv" commands. */ add_setshow_prefix_cmd ("riscv", no_class, From patchwork Mon Mar 13 21:46:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 66325 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 87F213854830 for ; Mon, 13 Mar 2023 21:46:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 87F213854830 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1678744012; bh=fZ+CCGdgdLArViJ9QBZnUkgerUNhHyBC9QecLlHvLK0=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=MxC695ngiqfCE68M/xRc01E6IuOH+XjJwwdPNy7DG0OlbhpzZfvC6/066dpbFImAf 4+wLNmPB9m1pDEWWFF3BegDOYV3afM99XBHDekyIvjHSiuf4kypRopjmXf4oMU0Rlw O4QpZo1EFEUWZK0RNwRapFpMsy+0byh9oynMlxUU= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id E83B83858C30 for ; Mon, 13 Mar 2023 21:46:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E83B83858C30 Received: from mail-ed1-f71.google.com (mail-ed1-f71.google.com [209.85.208.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-46-J_Bav0PFPJ6qv77oqskImQ-1; Mon, 13 Mar 2023 17:46:27 -0400 X-MC-Unique: J_Bav0PFPJ6qv77oqskImQ-1 Received: by mail-ed1-f71.google.com with SMTP id b1-20020aa7dc01000000b004ad062fee5eso18587615edu.17 for ; Mon, 13 Mar 2023 14:46:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678743985; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fZ+CCGdgdLArViJ9QBZnUkgerUNhHyBC9QecLlHvLK0=; b=P/2QBW9kJrHXVHbl5gXwDBs4+K3vZ+H7tUFbniGPz5M7FXKURzeNU8CcsTDnNx9MNv 9976t/cnFGwZ+YJTvC2ZBc3OYtSloNDY3+iDujQCoIqLKcTZ2TVTQHyF97zzCbohwQjf ZVev6UuOmJZsNcCsNJsAYE6kmyrR74GlTtr3E10fEp64qfjfkdxqU74DVzylbu2unu3g d3SaUxKNQ0oRu4Wbm28N1aDOA/FPAcxJHBcBhNrownXEgMLlHBip+v1BGbTNWinzZKv4 A8tYr7cQsngD2J+fDodLbPVtknDF7eby6RMJV3Qa55IqGy8My95U10qpNXPRkV8SPQHt x+Fw== X-Gm-Message-State: AO0yUKUNj0+Jh/+ozYuIlx1oEAYhrx5yfM0sm0xaqCxfLyuD5ali+qGh tzh6vZOVo75cAwp3aD2DL2eTp/FcEF/ikpnLtqYESnYkuZ6F4qMykdn1hIdUEQOIHMqDtccxPvf b2/lNcspN3ALmvVf4v/smGzjuXXgLG0iqEW6kwpNOq+BtfdP1zUWp1K3NKK3Pm9+xxBhTWTUD37 dvbNprIg== X-Received: by 2002:a17:907:9894:b0:92b:f119:3964 with SMTP id ja20-20020a170907989400b0092bf1193964mr13440ejc.37.1678743985670; Mon, 13 Mar 2023 14:46:25 -0700 (PDT) X-Google-Smtp-Source: AK7set+lJBhGhNHMZ8ihGzS7SA85zEJjd01UKKgoqhx6OxXZ8FZ1RKIYEa04q1QUuRu1JFXd7vx1wA== X-Received: by 2002:a17:907:9894:b0:92b:f119:3964 with SMTP id ja20-20020a170907989400b0092bf1193964mr13429ejc.37.1678743985360; Mon, 13 Mar 2023 14:46:25 -0700 (PDT) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id xa13-20020a170907b9cd00b0091ec885e016sm273836ejc.54.2023.03.13.14.46.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Mar 2023 14:46:25 -0700 (PDT) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 2/3] gdb/riscv: support c.ldsp and c.lwsp in prologue scanner Date: Mon, 13 Mar 2023 21:46:18 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP 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.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Add support to the RISC-V prologue scanner for c.ldsp and c.lwsp instructions. This fixes some of the failures in gdb.base/unwind-on-each-insn.exp, though there are further failures that are not fixed by this commit. This change started as a wider fix that would address all the failures in gdb.base/unwind-on-each-insn.exp, however, that wider fix needed support for the two additional compressed instructions. When I added support for those two compressed instructions I noticed that some of the failures in gdb.base/unwind-on-each-insn.exp resolved themselves! Here's what's going on: The reason for the failures is that GDB is trying to build the frame-id during the last few instructions of the function. These are the instructions that restore the frame and stack pointers just prior to the return instruction itself. By the time we reach the function epilogue the stack offset that we calculated during the prologue scan is no longer valid, and so we calculate the wrong frame-id. However, in the particular case of interest here, the test function 'foo', the function is so simple and short that GDB's prologue scan could, in theory, scan every instruction of the function. I say "could, in theory," because currently GDB stops the prologue scan early when it hits an unknown instruction. The unknown instruction happens to be one of the compressed instructions that I'm adding support for in this commit. Now that GDB understands the compressed instructions the prologue scan really does go from the start of the function right up to the current program counter. As such, GDB sees that the stack frame has been allocated, and then deallocated, and so builds the correct frame-id. Of course, most real functions are not as simple as the test function 'foo'. As such, we can realistically rely on scanning right up to the end of the function. There are some instructions we always need to stop at because we can't reason about how they change the inferior state (e.g. a function call). The test function 'bar' is just such an example. After this commit, we can now build the frame-id correctly for every instruction in 'foo', but there are some tests still failing in 'bar'. --- gdb/riscv-tdep.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index ba7eab41ac6..5ef76555918 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1668,11 +1668,20 @@ class riscv_insn m_imm.s = EXTRACT_ITYPE_IMM (ival); } - /* Helper for DECODE, decode 16-bit compressed I-type instruction. */ - void decode_ci_type_insn (enum opcode opcode, ULONGEST ival) + /* Helper for DECODE, decode 16-bit compressed I-type instruction. Some + of the CI instruction have a hard-coded rs1 register, while others + just use rd for both the source and destination. RS1_REGNUM, if + passed, is the value to place in rs1, otherwise rd is duplicated into + rs1. */ + void decode_ci_type_insn (enum opcode opcode, ULONGEST ival, + gdb::optional rs1_regnum = {}) { m_opcode = opcode; - m_rd = m_rs1 = decode_register_index (ival, OP_SH_CRS1S); + m_rd = decode_register_index (ival, OP_SH_CRS1S); + if (rs1_regnum.has_value ()) + m_rs1 = *rs1_regnum; + else + m_rs1 = m_rd; m_imm.s = EXTRACT_CITYPE_IMM (ival); } @@ -1959,6 +1968,10 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) decode_cl_type_insn (LD, ival); else if (is_c_lw_insn (ival)) decode_cl_type_insn (LW, ival); + else if (is_c_ldsp_insn (ival)) + decode_ci_type_insn (LD, ival, RISCV_SP_REGNUM); + else if (is_c_lwsp_insn (ival)) + decode_ci_type_insn (LW, ival, RISCV_SP_REGNUM); else /* None of the other fields of INSN are valid in this case. */ m_opcode = OTHER; From patchwork Mon Mar 13 21:46:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 66327 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 C7DD23858C33 for ; Mon, 13 Mar 2023 21:47:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C7DD23858C33 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1678744069; bh=DpT6Jd52PRe21Umngx/qgs0+dKBnK5fKyLHEdUt7LJ0=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=gsyR5LrvwvIf+JlgZDUQo/DGQ/Jk7Ud5MUAfTtMwDCpleZcK08/uvTAf4YMwa8vqW L5778Q0mdXCDUjkVKsglPSrIXGJ8HW8SqBwbjVEqj7fgymzkq6BWAO8qS8/4I3chuh e68WFDj54VS2btm+nN5LFBkBtfwtyCaBa2+BhLDM= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 30DF13858423 for ; Mon, 13 Mar 2023 21:46:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 30DF13858423 Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-262-PM_lOLkUNsGSpo0pehfajw-1; Mon, 13 Mar 2023 17:46:28 -0400 X-MC-Unique: PM_lOLkUNsGSpo0pehfajw-1 Received: by mail-ed1-f72.google.com with SMTP id t14-20020a056402240e00b004fb36e6d670so6851248eda.5 for ; Mon, 13 Mar 2023 14:46:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1678743987; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DpT6Jd52PRe21Umngx/qgs0+dKBnK5fKyLHEdUt7LJ0=; b=BazYjf1rk4YaGy20j6zKOW3FbYFGzOAslcjZozMnjsZXr6apXIBaKNO2O040Jl8DXI tilj3MoQraZK5AXPOVLyvOjwyArcX0NYMZqotOReIUj39q8dtKLTLGb7vCkblUEoIMDF T3IFzkOrYfWXmgiZtaqk5tARCDh0E499QbDqFN8G3Bg6ptCgFDXCMGbQCEztpqkkxTh9 QvNOd5VoUhyz6a5cGuQooTCwD297S54DfidFFKyJOYEVvZ8O1Ckw9v2TThHcmZcsJJmx WtHbXGDc1+UQavuaCx0hV5BZ95d5UhoNH2HGTko4G/nKk23bccEJh06jt0xca47jh4Rh e7DA== X-Gm-Message-State: AO0yUKUY1L7zscJj+eLKn1NNK2HCJKdKD8oSM5XjM8a1y1LDeohDuJPA 3V8VwbTpP2i6v+HRhjeWEBoKQVQzq90iLmXfAuv8r6i7kHBFJOzuWzk4sywkiLs/J5QVJGa3bZJ kBlXblY1MYGh+4mQB8Fegibqx6ClrcFK6Wdn2AQukxcnxZAbCEiqglrqVU0SByKf6QjPfToNDP+ IPWpiYuA== X-Received: by 2002:a17:907:7d92:b0:8b1:2614:edfe with SMTP id oz18-20020a1709077d9200b008b12614edfemr46165ejc.9.1678743987209; Mon, 13 Mar 2023 14:46:27 -0700 (PDT) X-Google-Smtp-Source: AK7set9Fbwq0sGISrgovd2bVlZIJUuJavva1nVRX9tfxzgSXBWcKhxy3n5k45rk9KeietMbemcDB3w== X-Received: by 2002:a17:907:7d92:b0:8b1:2614:edfe with SMTP id oz18-20020a1709077d9200b008b12614edfemr46149ejc.9.1678743986857; Mon, 13 Mar 2023 14:46:26 -0700 (PDT) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id g17-20020a1709061e1100b00922547486f9sm263512ejj.146.2023.03.13.14.46.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Mar 2023 14:46:26 -0700 (PDT) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 3/3] gdb/riscv: fix regressions in gdb.base/unwind-on-each-insn.exp Date: Mon, 13 Mar 2023 21:46:19 +0000 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP 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.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This commit builds on the previous one to fix all the remaining failures in gdb.base/unwind-on-each-insn.exp for RISC-V. The problem we have in gdb.base/unwind-on-each-insn.exp is that, when we are in the function epilogue, the previous frame and stack pointer values are being restored, and so, the values that we calculated during the function prologue are no longer suitable. Here's an example from the function 'bar' in the mentioned test. This was compiled for 64-bit RISC-V with compressed instruction support: Dump of assembler code for function bar: 0x000000000001018a <+0>: add sp,sp,-32 0x000000000001018c <+2>: sd ra,24(sp) 0x000000000001018e <+4>: sd fp,16(sp) 0x0000000000010190 <+6>: add fp,sp,32 0x0000000000010192 <+8>: sd a0,-24(fp) 0x0000000000010196 <+12>: ld a0,-24(fp) 0x000000000001019a <+16>: jal 0x10178 0x000000000001019e <+20>: nop 0x00000000000101a0 <+22>: ld ra,24(sp) 0x00000000000101a2 <+24>: ld fp,16(sp) 0x00000000000101a4 <+26>: add sp,sp,32 0x00000000000101a6 <+28>: ret End of assembler dump. When we are at address 0x101a4 the previous instruction has restored the frame-pointer, as such GDB's (current) preference for using the frame-pointer as the frame base address is clearly not going to work. We need to switch to using the stack-pointer instead. At address 0x101a6 the previous instruction has restored the stack-pointer value. Currently GDB will not understand this and so will still assume the stack has been decreased by 32 bytes in this function. My proposed solution is to add some additional code that scans the instructions at the current $pc. We're looking for this pattern: ld fp,16(sp) add sp,sp,32 ret Obviously the immediates can change, but the basic pattern indicates that the function is in the process of restoring state before returning. With this implemented then gdb.base/unwind-on-each-insn.exp now fully passes. Obviously what I've implemented is just a heuristic. It's not going to work for every function. If the compiler reorders the instructions, or merges the epilogue back into the function body then GDB is once again going to get the frame-id wrong. I'm OK with that. Remember, this is for debugging code without debug information, and (in our imagined situation) with more aggressive levels of optimisation being used. Obviously GDB is going to struggle in these situations. My thinking is, lets get something in place now. Then, later, if possible, we might be able to improve the logic to cover more situations -- if there's an interest in doing so. But I figure we need something in place as a starting point. After this commit gdb.base/unwind-on-each-insn.exp passes with no failures on RV64. --- gdb/riscv-tdep.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 4 deletions(-) diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 5ef76555918..771d892df26 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1986,6 +1986,214 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) } } +/* Return true if INSN represents an instruction something like: + + ld fp,IMMEDIATE(sp) + + That is, a load from stack-pointer plus some immediate offset, with the + result stored into the frame pointer. We also accept 'lw' as well as + 'ld'. */ + +static bool +is_insn_load_of_fp_from_sp (const struct riscv_insn &insn) +{ + return ((insn.opcode () == riscv_insn::LD + || insn.opcode () == riscv_insn::LW) + && insn.rd () == RISCV_FP_REGNUM + && insn.rs1 () == RISCV_SP_REGNUM); +} + +/* Return true if INSN represents an instruction something like: + + add sp,sp,IMMEDIATE + + That is, an add of an immediate to the value in the stack pointer + register, with the result stored back to the stack pointer register. */ + +static bool +is_insn_addi_of_sp_to_sp (const struct riscv_insn &insn) +{ + return ((insn.opcode () == riscv_insn::ADDI + || insn.opcode () == riscv_insn::ADDIW) + && insn.rd () == RISCV_SP_REGNUM + && insn.rs1 () == RISCV_SP_REGNUM); +} + +/* Is the instruction in code memory prior to address PC a load from stack + instruction? Return true if it is, otherwise, return false. + + This is a best effort that is used as part of the function prologue + scanning logic. With compressed instructions and arbitrary control + flow in the inferior, we can never be certain what the instruction + prior to PC is. + + This function first looks for a compressed instruction, then looks for + a 32-bit non-compressed instruction. */ + +static bool +previous_insn_is_load_fp_from_stack (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + struct riscv_insn insn; + insn.decode (gdbarch, pc - 2); + gdb_assert (insn.length () > 0); + + if (insn.length () != 2 || !is_insn_load_of_fp_from_sp (insn)) + { + insn.decode (gdbarch, pc - 4); + gdb_assert (insn.length () > 0); + + if (insn.length () != 4 || !is_insn_load_of_fp_from_sp (insn)) + return false; + } + + riscv_unwinder_debug_printf + ("previous instruction at %s (length %d) was 'ld'", + core_addr_to_string (pc - insn.length ()), insn.length ()); + return true; +} + +/* Is the instruction in code memory prior to address PC an add of an + immediate to the stack pointer, with the result being written back into + the stack pointer? Return true and set *PREV_PC to the address of the + previous instruction if we believe the previous instruction is such an + add, otherwise return false and *PREV_PC is undefined. + + This is a best effort that is used as part of the function prologue + scanning logic. With compressed instructions and arbitrary control + flow in the inferior, we can never be certain what the instruction + prior to PC is. + + This function first looks for a compressed instruction, then looks for + a 32-bit non-compressed instruction. */ + +static bool +previous_insn_is_add_imm_to_sp (struct gdbarch *gdbarch, CORE_ADDR pc, + CORE_ADDR *prev_pc) +{ + struct riscv_insn insn; + insn.decode (gdbarch, pc - 2); + gdb_assert (insn.length () > 0); + + if (insn.length () != 2 || !is_insn_addi_of_sp_to_sp (insn)) + { + insn.decode (gdbarch, pc - 4); + gdb_assert (insn.length () > 0); + + if (insn.length () != 4 || !is_insn_addi_of_sp_to_sp (insn)) + return false; + } + + riscv_unwinder_debug_printf + ("previous instruction at %s (length %d) was 'add'", + core_addr_to_string (pc - insn.length ()), insn.length ()); + *prev_pc = pc - insn.length (); + return true; +} + +/* Try to spot when PC is located in an exit sequence for a particular + function. Detecting an exit sequence involves a limited amount of + scanning backwards through the disassembly, and so, when considering + compressed instructions, we can never be certain that we have + disassembled the preceding instructions correctly. On top of that, we + can't be certain that the inferior arrived at PC by passing through the + preceding instructions. + + With all that said, we know that using prologue scanning to figure a + functions unwind information starts to fail when we consider returns + from an instruction -- we must pass through some instructions that + restore the previous state prior to the final return instruction, and + with state partially restored, our prologue derived unwind information + is no longer valid. + + This function then, aims to spot instruction sequences like this: + + ld fp, IMM_1(sp) + add sp, sp, IMM_2 + ret + + The first instruction restores the previous frame-pointer value, the + second restores the previous stack pointer value, and the final + instruction is the actual return. + + We need to consider that some or all of these instructions might be + compressed. + + This function makes the assumption that, when the inferior reaches the + 'ret' instruction the stack pointer will have been restored to its value + on entry to this function. This assumption will be true in most well + formed programs. + + Return true if we detect that we are in such an instruction sequence, + that is PC points at one of the three instructions given above. In this + case, set *OFFSET to IMM_2 if PC points to either of the first + two instructions (the 'ld' or 'add'), otherwise set *OFFSET to 0. + + Otherwise, this function returns false, and the contents of *OFFSET are + undefined. */ + +static bool +riscv_detect_end_of_function (struct gdbarch *gdbarch, CORE_ADDR pc, + int *offset) +{ + *offset = 0; + + /* We only want to scan a maximum of 3 instructions. */ + for (int i = 0; i < 3; ++i) + { + struct riscv_insn insn; + insn.decode (gdbarch, pc); + gdb_assert (insn.length () > 0); + + if (is_insn_load_of_fp_from_sp (insn)) + { + riscv_unwinder_debug_printf ("found 'ld' instruction at %s", + core_addr_to_string (pc)); + if (i > 0) + return false; + pc += insn.length (); + } + else if (is_insn_addi_of_sp_to_sp (insn)) + { + riscv_unwinder_debug_printf ("found 'add' instruction at %s", + core_addr_to_string (pc)); + if (i > 1) + return false; + if (i == 0) + { + if (!previous_insn_is_load_fp_from_stack (gdbarch, pc)) + return false; + + i = 1; + } + *offset = insn.imm_signed (); + pc += insn.length (); + } + else if (insn.opcode () == riscv_insn::JALR + && insn.rs1 () == RISCV_RA_REGNUM + && insn.rs2 () == RISCV_ZERO_REGNUM) + { + riscv_unwinder_debug_printf ("found 'ret' instruction at %s", + core_addr_to_string (pc)); + gdb_assert (i != 1); + if (i == 0) + { + CORE_ADDR prev_pc; + if (!previous_insn_is_add_imm_to_sp (gdbarch, pc, &prev_pc)) + return false; + if (!previous_insn_is_load_fp_from_stack (gdbarch, prev_pc)) + return false; + i = 2; + } + + pc += insn.length (); + } + else + return false; + } + + return true; +} + /* The prologue scanner. This is currently only used for skipping the prologue of a function when the DWARF information is not sufficient. However, it is written with filling of the frame cache in mind, which @@ -2000,6 +2208,7 @@ riscv_scan_prologue (struct gdbarch *gdbarch, struct riscv_unwind_cache *cache) { CORE_ADDR cur_pc, next_pc, after_prologue_pc; + CORE_ADDR original_end_pc = end_pc; CORE_ADDR end_prologue_addr = 0; /* Find an upper limit on the function prologue using the debug @@ -2031,10 +2240,7 @@ riscv_scan_prologue (struct gdbarch *gdbarch, next_pc = cur_pc + insn.length (); /* Look for common stack adjustment insns. */ - if ((insn.opcode () == riscv_insn::ADDI - || insn.opcode () == riscv_insn::ADDIW) - && insn.rd () == RISCV_SP_REGNUM - && insn.rs1 () == RISCV_SP_REGNUM) + if (is_insn_addi_of_sp_to_sp (insn)) { /* Handle: addi sp, sp, -i or: addiw sp, sp, -i */ @@ -2171,6 +2377,27 @@ riscv_scan_prologue (struct gdbarch *gdbarch, cache->frame_base_offset = -regs[RISCV_SP_REGNUM].k; } + /* Check to see if we are located near to a return instruction in + this function. If we are then the one or both of the stack + pointer and frame pointer may have been restored to their previous + value. If we can spot this situation then we can adjust which + register and offset we use for the frame base. */ + if (cache->frame_base_reg != RISCV_SP_REGNUM + || cache->frame_base_offset != 0) + { + int sp_offset; + + if (riscv_detect_end_of_function (gdbarch, original_end_pc, + &sp_offset)) + { + riscv_unwinder_debug_printf + ("in function epilogue at %s, stack offset is %d", + core_addr_to_string (original_end_pc), sp_offset); + cache->frame_base_reg= RISCV_SP_REGNUM; + cache->frame_base_offset = sp_offset; + } + } + /* Assign offset from old SP to all saved registers. As we don't have the previous value for the frame base register at this point, we store the offset as the address in the trad_frame, and