From patchwork Fri May 15 16:36:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135079 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2980840A1FB0 for ; Fri, 15 May 2026 16:42:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2980840A1FB0 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=h+l/yYO9 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 ESMTP id CA6B340A00C7 for ; Fri, 15 May 2026 16:38:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CA6B340A00C7 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CA6B340A00C7 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863139; cv=none; b=EfQwl64U6HWJPwYpU6uVhdPC+t2SShUUdaqwf6azuAq0Thinm9FlNoC6JO7hk6oNPSWgsmNNM304Y3E5h+CYUEHv9pllpQBi6yyVdWOO84xbllRGxRpl/BE4kbW8dzAOEBdcYgozMke4dhsgpes2uCsB4I0XVqeiyw+WJTDKqEM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863139; c=relaxed/simple; bh=t2BXJ3Be43rrHu2P5vu9oVXnTU4yF0+1qykI1K8Z/4g=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Stp/cZkayzxSSncmT7BvgRfrUMxf30BZUCAbTk15ihh4CYbfbGTLBTwDdQqP9iNbNa8jwDBExVRq23XNVC9BMj50kkhdbZC2z55YaaF6CmVAgnPYpvHPDhyMGQltKsZ2k2PRUg9CnNdI3loeXSdQnujbJpqjs1UYuKoiqjCuyd8= ARC-Authentication-Results: i=1; sourceware.org; dkim=fail (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=h+l/yYO9 reason="signature verification failed" DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CA6B340A00C7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863139; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=uH+ggoonuSmuxpiYZscpDYKJVhtaFWG6GxPCJMJEHFg=; b=h+l/yYO9rvS6iTg0MPPbtUkeHaLnBHoUymyBmMT7a6CYmHdv6nVWcM3xsQYl+XQA78QwOH QRWucBvVZmlt8KoKYdQhhyHqfRWCzf7ocY/vtKf3rJ4x/sjdK2/zm2ReIywL9Xe5ePBUNX 3DhrQqol4JUHt3lgCSFpZ74QpTHDqYg= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-688-e3DSpg_nPiO3Yy0AqCRZNw-1; Fri, 15 May 2026 12:38:55 -0400 X-MC-Unique: e3DSpg_nPiO3Yy0AqCRZNw-1 X-Mimecast-MFC-AGG-ID: e3DSpg_nPiO3Yy0AqCRZNw_1778863135 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7FD4719560AA; Fri, 15 May 2026 16:38:54 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A5DBD1955F2D; Fri, 15 May 2026 16:38:51 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen , Thiago Jung Bauermann Subject: [PATCH v3 1/7] gdb/record: Refactor record history Date: Fri, 15 May 2026 13:36:58 -0300 Message-ID: <20260515163706.3355686-2-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: wnWOh6mQYbncfaGKZ3hAfiKUOf68XHXDvginp9JWuYU_1778863135 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-8.6 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_QUARANTINE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This is the first step in a large refactor in how GDB keeps execution history. Rather than using a linked list where multiple entries can describe a single instruction, the history will now be stored in an std::deque, each instruction being one entry in the deque. The choice was initially to use an std::vector, but it would become unwieldy because it needs all the memory to be consecutive, which is hard for 200 thousand entries. Deque was picked because it was a nice midpoint between vector (maximum cache cohesion) and linked list (maximum ease of finding space to store more). Each instruction in memory will be now one record_full_instruction entry, which for this commit just contains a vector of record_full_entry for the effects of the instruction, and the data that was stored in the record_full_end entry (that is, the instruction number and the signal, if any). This change introduced a minimal performance improvement (what's important is that it isn't a degradation) and a reduction in the total memory footprint of roughly 20% if the entire history is used. Reviewed-by: Thiago Jung Bauermann --- gdb/aarch64-tdep.c | 2 - gdb/amd64-linux-tdep.c | 3 - gdb/arm-tdep.c | 2 - gdb/i386-linux-tdep.c | 3 - gdb/i386-tdep.c | 4 - gdb/loongarch-tdep.c | 2 - gdb/moxie-tdep.c | 2 - gdb/ppc-linux-tdep.c | 3 - gdb/record-full.c | 1186 ++++++++++++++++------------------------ gdb/record-full.h | 1 - gdb/riscv-tdep.c | 3 - gdb/rs6000-tdep.c | 4 - gdb/s390-linux-tdep.c | 3 - gdb/s390-tdep.c | 2 - 14 files changed, 484 insertions(+), 736 deletions(-) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 4befaa2720d..a532992b1d8 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -6210,8 +6210,6 @@ aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, aarch64_record.aarch64_mems[rec_no].len)) ret = -1; - if (record_full_arch_list_add_end ()) - ret = -1; } deallocate_reg_mem (&aarch64_record); diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index a5ac26654cf..9b23db72bbe 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -1591,9 +1591,6 @@ amd64_linux_record_signal (struct gdbarch *gdbarch, + AMD64_LINUX_frame_size)) return -1; - if (record_full_arch_list_add_end ()) - return -1; - return 0; } diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 08cce9dbad8..1ce0927f26b 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -14911,8 +14911,6 @@ arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache, } } - if (record_full_arch_list_add_end ()) - ret = -1; } diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c index 23aeccac9fc..4f33766fcdd 100644 --- a/gdb/i386-linux-tdep.c +++ b/gdb/i386-linux-tdep.c @@ -949,9 +949,6 @@ i386_linux_record_signal (struct gdbarch *gdbarch, I386_LINUX_xstate + I386_LINUX_frame_size)) return -1; - if (record_full_arch_list_add_end ()) - return -1; - return 0; } diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index fa935b5fcdb..fee36b46a73 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -5201,8 +5201,6 @@ i386_record_vex (struct i386_record_s *ir, uint8_t vex_w, uint8_t vex_r, } record_full_arch_list_add_reg (ir->regcache, ir->regmap[X86_RECORD_REIP_REGNUM]); - if (record_full_arch_list_add_end ()) - return -1; return 0; } @@ -8359,8 +8357,6 @@ Do you want to stop the program?"), /* In the future, maybe still need to deal with need_dasm. */ I386_RECORD_FULL_ARCH_LIST_ADD_REG (X86_RECORD_REIP_REGNUM); - if (record_full_arch_list_add_end ()) - return -1; return 0; diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index 225b1abb703..5ec6b2a48d0 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -2789,8 +2789,6 @@ loongarch_process_record (struct gdbarch *gdbarch, struct regcache *regcache, LOONGARCH_PC_REGNUM)) return -1; - if (record_full_arch_list_add_end ()) - return -1; } return ret; diff --git a/gdb/moxie-tdep.c b/gdb/moxie-tdep.c index c8a04d21f59..2f8f0186488 100644 --- a/gdb/moxie-tdep.c +++ b/gdb/moxie-tdep.c @@ -1040,8 +1040,6 @@ moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache, if (record_full_arch_list_add_reg (regcache, MOXIE_PC_REGNUM)) return -1; - if (record_full_arch_list_add_end ()) - return -1; return 0; } diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 19698eaacbe..e2f53551709 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -1565,9 +1565,6 @@ ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache, if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe)) return -1; - if (record_full_arch_list_add_end ()) - return -1; - return 0; } diff --git a/gdb/record-full.c b/gdb/record-full.c index 69d2c100e57..02a57726a95 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -47,6 +47,9 @@ #include "interps.h" #include "cli/cli-style.h" +#include +#include +#include #include /* This module implements "target record-full", also known as "process @@ -72,20 +75,17 @@ #define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000 #define RECORD_FULL_IS_REPLAY \ - (record_full_list->next || ::execution_direction == EXEC_REVERSE) + ((record_full_next_insn != record_full_list.size ()) \ + || ::execution_direction == EXEC_REVERSE) #define RECORD_FULL_FILE_MAGIC netorder32(0x20091016) /* These are the core structs of the process record functionality. A record_full_entry is a record of the value change of a register - ("record_full_reg") or a part of memory ("record_full_mem"). And each - instruction must have a struct record_full_entry ("record_full_end") - that indicates that this is the last struct record_full_entry of this - instruction. - - Each struct record_full_entry is linked to "record_full_list" by "prev" - and "next" pointers. */ + ("record_full_reg") or a part of memory ("record_full_mem"). + These are saved on the record_full_instruction struct, which also + contains some extra information, such as delivered signals. */ struct record_full_mem_entry { @@ -112,47 +112,14 @@ struct record_full_reg_entry } u; }; -struct record_full_end_entry -{ - enum gdb_signal sigval; - ULONGEST insn_num; -}; - enum record_full_type { - record_full_end = 0, record_full_reg, record_full_mem }; -/* This is the data structure that makes up the execution log. - - The execution log consists of a single linked list of entries - of type "struct record_full_entry". It is doubly linked so that it - can be traversed in either direction. - - The start of the list is anchored by a struct called - "record_full_first". The pointer "record_full_list" either points - to the last entry that was added to the list (in record mode), or to - the next entry in the list that will be executed (in replay mode). - - Each list element (struct record_full_entry), in addition to next - and prev pointers, consists of a union of three entry types: mem, - reg, and end. A field called "type" determines which entry type is - represented by a given list element. - - Each instruction that is added to the execution log is represented - by a variable number of list elements ('entries'). The instruction - will have one "reg" entry for each register that is changed by - executing the instruction (including the PC in every case). It - will also have one "mem" entry for each memory change. Finally, - each instruction will have an "end" entry that separates it from - the changes associated with the next instruction. */ - struct record_full_entry { - struct record_full_entry *prev; - struct record_full_entry *next; enum record_full_type type; union { @@ -160,11 +127,31 @@ struct record_full_entry struct record_full_reg_entry reg; /* mem */ struct record_full_mem_entry mem; - /* end */ - struct record_full_end_entry end; } u; }; +/* This is the main structure that comprises the execution log. + Each instruction is comprised of: + * The instruction number: How many instructions were recorded before + this one; + * sigval: Whether the inferior received a signal while the following + instruction was being recorded; + * effects: A list of record_full_entry structures, each of which + describing one effect that the instruction has on the inferior. + + Note, the signal is stored in the previous instruction for historical + reasons. This is how it was first implemented, and no one has gotten + around to changing it yet. */ + +struct record_full_instruction +{ + /* This might be different from the index if + we had to remove the first few instructions. */ + uint32_t insn_num; + std::optional sigval; + std::vector effects; +}; + /* If true, query if PREC cannot record memory change of next instruction. */ bool record_full_memory_query = false; @@ -181,27 +168,25 @@ static detached_regcache *record_full_core_regbuf = NULL; static std::vector record_full_core_sections; static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; -/* The following variables are used for managing the linked list that - represents the execution log. +/* The following variables are used for managing the history of executed + instructions from the inferior. - record_full_first is the anchor that holds down the beginning of - the list. + record_full_list contains all instructions that were fully executed and + saved to the log, so that we can replay the execution. - record_full_list serves two functions: - 1) In record mode, it anchors the end of the list. - 2) In replay mode, it traverses the list and points to - the next instruction that must be emulated. + record_full_next_insn always points to the next instruction that would + be executed if the inferior executes forward. In the special case when + the inferior is not replaying, record_full_next_insn points past the + end of the history. - record_full_arch_list_head and record_full_arch_list_tail are used - to manage a separate list, which is used to build up the change - elements of the currently executing instruction during record mode. - When this instruction has been completely annotated in the "arch - list", it will be appended to the main execution log. */ + record_full_incomplete_instruction holds a partial instruction, while + the lower target is disassembling the instruction, or as partial xfers are + happening. It is manipulated by the "arch list" functions for historical + reasons. */ -static struct record_full_entry record_full_first; -static struct record_full_entry *record_full_list = &record_full_first; -static struct record_full_entry *record_full_arch_list_head = NULL; -static struct record_full_entry *record_full_arch_list_tail = NULL; +static std::deque record_full_list; +static record_full_instruction record_full_incomplete_instruction; +static int record_full_next_insn; /* true ask user. false auto delete the last struct record_full_entry. */ static bool record_full_stop_at_limit = true; @@ -361,6 +346,14 @@ record_full_target::kill () record_kill (this); } +static void +record_full_reset_incomplete () +{ + record_full_incomplete_instruction.effects.clear (); + record_full_incomplete_instruction.sigval.reset (); + record_full_incomplete_instruction.insn_num = 0; +} + /* See record-full.h. */ int @@ -390,156 +383,124 @@ static struct cmd_list_element *show_record_full_cmdlist; /* Command list for "record full". */ static struct cmd_list_element *record_full_cmdlist; -static void record_full_goto_insn (struct record_full_entry *entry, +static void record_full_goto_insn (size_t target_insn, enum exec_direction_kind dir); -/* Alloc and free functions for record_full_reg, record_full_mem, and - record_full_end entries. */ +/* Initialization and cleanup functions for record_full_reg and + record_full_mem entries. */ -/* Alloc a record_full_reg record entry. */ +/* Init a record_full_reg record entry. */ -static inline struct record_full_entry * -record_full_reg_alloc (struct regcache *regcache, int regnum) +static inline record_full_entry +record_full_reg_init (struct regcache *regcache, int regnum) { - struct record_full_entry *rec; + record_full_entry rec; struct gdbarch *gdbarch = regcache->arch (); - rec = XCNEW (struct record_full_entry); - rec->type = record_full_reg; - rec->u.reg.num = regnum; - rec->u.reg.len = register_size (gdbarch, regnum); - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len); + rec.type = record_full_reg; + rec.u.reg.num = regnum; + rec.u.reg.len = register_size (gdbarch, regnum); + if (rec.u.reg.len > sizeof (rec.u.reg.u.buf)) + rec.u.reg.u.ptr = (gdb_byte *) xmalloc (rec.u.reg.len); return rec; } -/* Free a record_full_reg record entry. */ +/* Cleanup a record_full_reg record entry. */ static inline void -record_full_reg_release (struct record_full_entry *rec) +record_full_reg_cleanup (record_full_entry rec) { - gdb_assert (rec->type == record_full_reg); - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - xfree (rec->u.reg.u.ptr); - xfree (rec); + gdb_assert (rec.type == record_full_reg); + if (rec.u.reg.len > sizeof (rec.u.reg.u.buf)) + xfree (rec.u.reg.u.ptr); } -/* Alloc a record_full_mem record entry. */ +/* Init a record_full_mem record entry. */ -static inline struct record_full_entry * -record_full_mem_alloc (CORE_ADDR addr, int len) +static inline record_full_entry +record_full_mem_init (CORE_ADDR addr, int len) { - struct record_full_entry *rec; + record_full_entry rec; - rec = XCNEW (struct record_full_entry); - rec->type = record_full_mem; - rec->u.mem.addr = addr; - rec->u.mem.len = len; - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - rec->u.mem.u.ptr = (gdb_byte *) xmalloc (len); + rec.type = record_full_mem; + rec.u.mem.addr = addr; + rec.u.mem.len = len; + if (rec.u.mem.len > sizeof (rec.u.mem.u.buf)) + rec.u.mem.u.ptr = (gdb_byte *) xmalloc (len); + rec.u.mem.mem_entry_not_accessible = 0; return rec; } -/* Free a record_full_mem record entry. */ +/* Cleanup a record_full_mem record entry. */ static inline void -record_full_mem_release (struct record_full_entry *rec) +record_full_mem_cleanup (record_full_entry rec) { - gdb_assert (rec->type == record_full_mem); - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - xfree (rec->u.mem.u.ptr); - xfree (rec); + gdb_assert (rec.type == record_full_mem); + if (rec.u.mem.len > sizeof (rec.u.mem.u.buf)) + xfree (rec.u.mem.u.ptr); } -/* Alloc a record_full_end record entry. */ - -static inline struct record_full_entry * -record_full_end_alloc (void) -{ - struct record_full_entry *rec; - - rec = XCNEW (struct record_full_entry); - rec->type = record_full_end; - - return rec; -} - -/* Free a record_full_end record entry. */ +/* Free one record entry, any type. */ static inline void -record_full_end_release (struct record_full_entry *rec) +record_full_entry_cleanup (record_full_entry rec) { - xfree (rec); -} - -/* Free one record entry, any type. - Return entry->type, in case caller wants to know. */ -static inline enum record_full_type -record_full_entry_release (struct record_full_entry *rec) -{ - enum record_full_type type = rec->type; - - switch (type) { + switch (rec.type) { case record_full_reg: - record_full_reg_release (rec); + record_full_reg_cleanup (rec); break; case record_full_mem: - record_full_mem_release (rec); - break; - case record_full_end: - record_full_end_release (rec); + record_full_mem_cleanup (rec); break; } - return type; } -/* Free all record entries in list pointed to by REC. */ - static void -record_full_list_release (struct record_full_entry *rec) +record_full_reset_history () { - if (!rec) - return; - - while (rec->next) - rec = rec->next; + record_full_insn_num = 0; + record_full_insn_count = 0; + record_full_next_insn = 0; - while (rec->prev) + for (auto &insn : record_full_list) { - rec = rec->prev; - record_full_entry_release (rec->next); + for (auto &entry : insn.effects) + record_full_entry_cleanup (entry); } - if (rec == &record_full_first) + record_full_list.clear (); +} + +static void +record_full_list_release_following (int index) +{ + for (int i = record_full_list.size () - 1; i > index; i--) { - record_full_insn_num = 0; - record_full_first.next = NULL; + for (auto &entry : record_full_list[i].effects) + record_full_entry_cleanup (entry); + record_full_list.pop_back (); } - else - record_full_entry_release (rec); + /* Set the next instruction to be past the end of the log so we + start recording if the user moves forward again. */ + record_full_next_insn = index; } -/* Free all record entries forward of the given list position. */ +/* Save the incomplete instruction in the log. */ static void -record_full_list_release_following (struct record_full_entry *rec) +record_full_save_instruction () { - struct record_full_entry *tmp = rec->next; + ++record_full_insn_count; + record_full_incomplete_instruction.insn_num = record_full_insn_count; + record_full_incomplete_instruction.effects.shrink_to_fit (); + record_full_list.push_back (std::move (record_full_incomplete_instruction)); + record_full_next_insn++; - rec->next = NULL; - while (tmp) - { - rec = tmp->next; - if (record_full_entry_release (tmp) == record_full_end) - { - record_full_insn_num--; - record_full_insn_count--; - } - tmp = rec; - } + record_full_reset_incomplete (); } /* Delete the first instruction from the beginning of the log, to make @@ -550,52 +511,22 @@ record_full_list_release_following (struct record_full_entry *rec) static void record_full_list_release_first (void) { - struct record_full_entry *tmp; - - if (!record_full_first.next) + if (record_full_list.empty ()) return; - /* Loop until a record_full_end. */ - while (1) - { - /* Cut record_full_first.next out of the linked list. */ - tmp = record_full_first.next; - record_full_first.next = tmp->next; - tmp->next->prev = &record_full_first; - - /* tmp is now isolated, and can be deleted. */ - if (record_full_entry_release (tmp) == record_full_end) - break; /* End loop at first record_full_end. */ + for (auto &entry : record_full_list[0].effects) + record_full_entry_cleanup (entry); - if (!record_full_first.next) - { - gdb_assert (record_full_insn_num == 1); - break; /* End loop when list is empty. */ - } - } + record_full_list.pop_front (); + --record_full_next_insn; } /* Add a struct record_full_entry to record_full_arch_list. */ static void -record_full_arch_list_add (struct record_full_entry *rec) +record_full_arch_list_add (record_full_entry &rec) { - if (record_debug > 1) - gdb_printf (gdb_stdlog, - "Process record: record_full_arch_list_add %s.\n", - host_address_to_string (rec)); - - if (record_full_arch_list_tail) - { - record_full_arch_list_tail->next = rec; - rec->prev = record_full_arch_list_tail; - record_full_arch_list_tail = rec; - } - else - { - record_full_arch_list_head = rec; - record_full_arch_list_tail = rec; - } + record_full_incomplete_instruction.effects.push_back (rec); } /* Return the value storage location of a record entry. */ @@ -613,7 +544,6 @@ record_full_get_loc (struct record_full_entry *rec) return rec->u.reg.u.ptr; else return rec->u.reg.u.buf; - case record_full_end: default: gdb_assert_not_reached ("unexpected record_full_entry type"); return NULL; @@ -625,7 +555,7 @@ record_full_get_loc (struct record_full_entry *rec) int record_full_arch_list_add_reg (struct regcache *regcache, int regnum) { - struct record_full_entry *rec; + record_full_entry rec; if (record_debug > 1) gdb_printf (gdb_stdlog, @@ -633,9 +563,9 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum) "record list.\n", regnum); - rec = record_full_reg_alloc (regcache, regnum); + rec = record_full_reg_init (regcache, regnum); - regcache->cooked_read (regnum, record_full_get_loc (rec)); + regcache->cooked_read (regnum, record_full_get_loc (&rec)); record_full_arch_list_add (rec); @@ -648,7 +578,7 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum) int record_full_arch_list_add_mem (CORE_ADDR addr, int len) { - struct record_full_entry *rec; + record_full_entry rec; if (record_debug > 1) gdb_printf (gdb_stdlog, @@ -659,12 +589,12 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) if (!addr) /* FIXME: Why? Some arch must permit it... */ return 0; - rec = record_full_mem_alloc (addr, len); + rec = record_full_mem_init (addr, len); if (record_read_memory (current_inferior ()->arch (), addr, - record_full_get_loc (rec), len)) + record_full_get_loc (&rec), len)) { - record_full_mem_release (rec); + record_full_mem_cleanup (rec); return -1; } @@ -673,27 +603,6 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) return 0; } -/* Add a record_full_end type struct record_full_entry to - record_full_arch_list. */ - -int -record_full_arch_list_add_end (void) -{ - struct record_full_entry *rec; - - if (record_debug > 1) - gdb_printf (gdb_stdlog, - "Process record: add end to arch list.\n"); - - rec = record_full_end_alloc (); - rec->u.end.sigval = GDB_SIGNAL_0; - rec->u.end.insn_num = ++record_full_insn_count; - - record_full_arch_list_add (rec); - - return 0; -} - static void record_full_check_insn_num (void) { @@ -725,8 +634,7 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) try { - record_full_arch_list_head = NULL; - record_full_arch_list_tail = NULL; + record_full_reset_incomplete (); /* Check record_full_insn_num. */ record_full_check_insn_num (); @@ -746,20 +654,16 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) the user says something different, like "deliver this signal" during the replay mode). - User should understand that nothing he does during the replay - mode will change the behavior of the child. If he tries, + User should understand that nothing they do during the replay + mode will change the behavior of the child. If they try, then that is a user error. But we should still deliver the signal to gdb during the replay, if we delivered it during the recording. Therefore we should record the signal during record_full_wait, not record_full_resume. */ - if (record_full_list != &record_full_first) /* FIXME better way - to check */ - { - gdb_assert (record_full_list->type == record_full_end); - record_full_list->u.end.sigval = signal; - } + if (signal != GDB_SIGNAL_0 && !record_full_list.empty ()) + record_full_list[record_full_next_insn - 1].sigval = signal; if (signal == GDB_SIGNAL_0 || !gdbarch_process_record_signal_p (gdbarch)) @@ -778,13 +682,11 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) } catch (const gdb_exception &ex) { - record_full_list_release (record_full_arch_list_tail); + record_full_reset_incomplete (); throw; } - record_full_list->next = record_full_arch_list_head; - record_full_arch_list_head->prev = record_full_list; - record_full_list = record_full_arch_list_tail; + record_full_save_instruction (); if (record_full_insn_num == record_full_insn_max_num) record_full_list_release_first (); @@ -829,9 +731,9 @@ static enum target_stop_reason record_full_stop_reason entries and memory entries, followed by an 'end' entry. */ static inline void -record_full_exec_insn (struct regcache *regcache, - struct gdbarch *gdbarch, - struct record_full_entry *entry) +record_full_exec_entry (regcache *regcache, + gdbarch *gdbarch, + record_full_entry *entry) { switch (entry->type) { @@ -909,6 +811,15 @@ record_full_exec_insn (struct regcache *regcache, } } +static inline void +record_full_exec_insn (regcache *regcache, + gdbarch *gdbarch, + record_full_instruction &insn) +{ + for (auto &entry : insn.effects) + record_full_exec_entry (regcache, gdbarch, &entry); +} + static void record_full_restore (struct bfd &cbfd); /* Asynchronous signal handle registered as event loop source for when @@ -983,10 +894,7 @@ record_full_open (const char *args, int from_tty) record_preopen (); /* Reset */ - record_full_insn_num = 0; - record_full_insn_count = 0; - record_full_list = &record_full_first; - record_full_list->next = NULL; + record_full_reset_history (); bfd *cbfd = get_inferior_core_bfd (current_inferior ()); if (cbfd != nullptr) @@ -1014,7 +922,7 @@ record_full_base_target::close () if (record_debug) gdb_printf (gdb_stdlog, "Process record: record_full_close\n"); - record_full_list_release (record_full_list); + record_full_reset_history (); /* Release record_full_core_regbuf. */ if (record_full_core_regbuf) @@ -1313,7 +1221,6 @@ record_full_wait_1 (struct target_ops *ops, struct gdbarch *gdbarch = regcache->arch (); const address_space *aspace = current_inferior ()->aspace.get (); int continue_flag = 1; - int first_record_full_end = 1; try { @@ -1322,7 +1229,6 @@ record_full_wait_1 (struct target_ops *ops, record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON; status->set_stopped (GDB_SIGNAL_0); - /* Check breakpoint when forward execute. */ if (execution_direction == EXEC_FORWARD) { tmp_pc = regcache_read_pc (regcache); @@ -1330,8 +1236,7 @@ record_full_wait_1 (struct target_ops *ops, &record_full_stop_reason)) { if (record_debug) - gdb_printf (gdb_stdlog, - "Process record: break at %s.\n", + gdb_printf (gdb_stdlog, "Process record: break at %s.\n", paddress (gdbarch, tmp_pc)); goto replay_out; } @@ -1344,10 +1249,10 @@ record_full_wait_1 (struct target_ops *ops, the signal. */ target_terminal::ours (); - /* In EXEC_FORWARD mode, record_full_list points to the tail of prev - instruction. */ - if (execution_direction == EXEC_FORWARD && record_full_list->next) - record_full_list = record_full_list->next; + /* In EXEC_FORWARD mode, record_full_next_insn is the next + instruction to be executed. */ + if (execution_direction == EXEC_REVERSE) + record_full_next_insn--; /* Loop over the record_full_list, looking for the next place to stop. */ @@ -1355,108 +1260,92 @@ record_full_wait_1 (struct target_ops *ops, { /* Check for beginning and end of log. */ if (execution_direction == EXEC_REVERSE - && record_full_list == &record_full_first) + && record_full_next_insn < 0) { /* Hit beginning of record log in reverse. */ status->set_no_history (); + record_full_next_insn = 0; break; } if (execution_direction != EXEC_REVERSE - && !record_full_list->next) + && record_full_next_insn == record_full_list.size ()) { /* Hit end of record log going forward. */ status->set_no_history (); break; } - record_full_exec_insn (regcache, gdbarch, record_full_list); + record_full_exec_insn + (regcache, gdbarch, + record_full_list[record_full_next_insn]); - if (record_full_list->type == record_full_end) + /* step */ + if (record_full_resume_step) { if (record_debug > 1) - gdb_printf - (gdb_stdlog, - "Process record: record_full_end %s to " - "inferior.\n", - host_address_to_string (record_full_list)); - - if (first_record_full_end - && execution_direction == EXEC_REVERSE) - { - /* When reverse execute, the first - record_full_end is the part of current - instruction. */ - first_record_full_end = 0; - } - else - { - /* In EXEC_REVERSE mode, this is the - record_full_end of prev instruction. In - EXEC_FORWARD mode, this is the - record_full_end of current instruction. */ - /* step */ - if (record_full_resume_step) - { - if (record_debug > 1) - gdb_printf (gdb_stdlog, - "Process record: step.\n"); - continue_flag = 0; - } - - /* check breakpoint */ - tmp_pc = regcache_read_pc (regcache); - if (record_check_stopped_by_breakpoint - (aspace, tmp_pc, &record_full_stop_reason)) - { - if (record_debug) - gdb_printf (gdb_stdlog, - "Process record: break " - "at %s.\n", - paddress (gdbarch, tmp_pc)); + gdb_printf (gdb_stdlog, + "Process record: step.\n"); + continue_flag = 0; + } - continue_flag = 0; - } + /* check breakpoint */ + tmp_pc = regcache_read_pc (regcache); + if (record_check_stopped_by_breakpoint + (aspace, tmp_pc, &record_full_stop_reason)) + { + if (record_debug) + gdb_printf (gdb_stdlog, + "Process record: break " + "at %s.\n", + paddress (gdbarch, tmp_pc)); - if (record_full_stop_reason - == TARGET_STOPPED_BY_WATCHPOINT) - { - if (record_debug) - gdb_printf (gdb_stdlog, - "Process record: hit hw " - "watchpoint.\n"); - continue_flag = 0; - } - /* Check target signal */ - if (record_full_list->u.end.sigval != GDB_SIGNAL_0) - /* FIXME: better way to check */ - continue_flag = 0; - } + continue_flag = 0; } - if (continue_flag) + if (record_full_stop_reason + == TARGET_STOPPED_BY_WATCHPOINT) { - if (execution_direction == EXEC_REVERSE) - { - if (record_full_list->prev) - record_full_list = record_full_list->prev; - } - else - { - if (record_full_list->next) - record_full_list = record_full_list->next; - } + if (record_debug) + gdb_printf (gdb_stdlog, + "Process record: hit hw " + "watchpoint.\n"); + continue_flag = 0; } + if (record_full_list[record_full_next_insn].sigval.has_value ()) + continue_flag = 0; + + if (execution_direction == EXEC_REVERSE) + record_full_next_insn--; + else + record_full_next_insn++; } while (continue_flag); + if (record_full_next_insn < 0) + { + gdb_assert (execution_direction == EXEC_REVERSE); + record_full_next_insn = 0; + } + else if (record_full_next_insn > record_full_list.size ()) + { + gdb_assert (execution_direction == EXEC_FORWARD); + record_full_next_insn = record_full_list.size (); + } + /* Reset the current instruction to point to the one to be replayed + moving forward. */ + else if (execution_direction == EXEC_REVERSE) + record_full_next_insn++; + replay_out: if (status->kind () == TARGET_WAITKIND_STOPPED) { + int insn = (execution_direction == EXEC_FORWARD) + ? record_full_next_insn - 1 : record_full_next_insn; if (record_full_get_sig) status->set_stopped (GDB_SIGNAL_INT); - else if (record_full_list->u.end.sigval != GDB_SIGNAL_0) - /* FIXME: better way to check */ - status->set_stopped (record_full_list->u.end.sigval); + else if (record_full_list[insn].sigval.has_value ()) + status->set_stopped + (record_full_list[insn].sigval.value ()); else status->set_stopped (GDB_SIGNAL_TRAP); } @@ -1464,12 +1353,9 @@ record_full_wait_1 (struct target_ops *ops, catch (const gdb_exception &ex) { if (execution_direction == EXEC_REVERSE) - { - if (record_full_list->next) - record_full_list = record_full_list->next; - } + record_full_next_insn++; else - record_full_list = record_full_list->prev; + record_full_next_insn--; throw; } @@ -1557,8 +1443,7 @@ record_full_registers_change (struct regcache *regcache, int regnum) /* Check record_full_insn_num. */ record_full_check_insn_num (); - record_full_arch_list_head = NULL; - record_full_arch_list_tail = NULL; + record_full_reset_incomplete (); if (regnum < 0) { @@ -1568,7 +1453,7 @@ record_full_registers_change (struct regcache *regcache, int regnum) { if (record_full_arch_list_add_reg (regcache, i)) { - record_full_list_release (record_full_arch_list_tail); + record_full_reset_incomplete (); error (_("Process record: failed to record execution log.")); } } @@ -1577,18 +1462,11 @@ record_full_registers_change (struct regcache *regcache, int regnum) { if (record_full_arch_list_add_reg (regcache, regnum)) { - record_full_list_release (record_full_arch_list_tail); + record_full_reset_incomplete (); error (_("Process record: failed to record execution log.")); } } - if (record_full_arch_list_add_end ()) - { - record_full_list_release (record_full_arch_list_tail); - error (_("Process record: failed to record execution log.")); - } - record_full_list->next = record_full_arch_list_head; - record_full_arch_list_head->prev = record_full_list; - record_full_list = record_full_arch_list_tail; + record_full_save_instruction (); if (record_full_insn_num == record_full_insn_max_num) record_full_list_release_first (); @@ -1607,7 +1485,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno) { int n; - /* Let user choose if he wants to write register or not. */ + /* Let user choose if they want to write register or not. */ if (regno < 0) n = query (_("Because GDB is in replay mode, changing the " @@ -1642,7 +1520,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno) } /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_list); + record_full_list_release_following (record_full_next_insn); } record_full_registers_change (regcache, regno); @@ -1675,36 +1553,24 @@ record_full_target::xfer_partial (enum target_object object, error (_("Process record canceled the operation.")); /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_list); + record_full_list_release_following (record_full_next_insn); } /* Check record_full_insn_num */ record_full_check_insn_num (); /* Record registers change to list as an instruction. */ - record_full_arch_list_head = NULL; - record_full_arch_list_tail = NULL; + record_full_reset_incomplete (); if (record_full_arch_list_add_mem (offset, len)) { - record_full_list_release (record_full_arch_list_tail); - if (record_debug) - gdb_printf (gdb_stdlog, - "Process record: failed to record " - "execution log."); - return TARGET_XFER_E_IO; - } - if (record_full_arch_list_add_end ()) - { - record_full_list_release (record_full_arch_list_tail); + record_full_reset_incomplete (); if (record_debug) gdb_printf (gdb_stdlog, "Process record: failed to record " "execution log."); return TARGET_XFER_E_IO; } - record_full_list->next = record_full_arch_list_head; - record_full_arch_list_head->prev = record_full_list; - record_full_list = record_full_arch_list_tail; + record_full_save_instruction (); if (record_full_insn_num == record_full_insn_max_num) record_full_list_release_first (); @@ -1865,9 +1731,11 @@ record_full_base_target::get_bookmark (const char *args, int from_tty) { char *ret = NULL; + if (record_full_list.empty ()) + return (gdb_byte *) ret; + /* Return stringified form of instruction count. */ - if (record_full_list && record_full_list->type == record_full_end) - ret = xstrdup (pulongest (record_full_list->u.end.insn_num)); + ret = xstrdup (pulongest (record_full_list[record_full_next_insn].insn_num)); if (record_debug) { @@ -1923,30 +1791,22 @@ record_full_base_target::record_method (ptid_t ptid) void record_full_base_target::info_record () { - struct record_full_entry *p; - if (RECORD_FULL_IS_REPLAY) gdb_printf (_("Replay mode:\n")); else gdb_printf (_("Record mode:\n")); - /* Find entry for first actual instruction in the log. */ - for (p = record_full_first.next; - p != NULL && p->type != record_full_end; - p = p->next) - ; - /* Do we have a log at all? */ - if (p != NULL && p->type == record_full_end) + if (!record_full_list.empty ()) { /* Display instruction number for first instruction in the log. */ - gdb_printf (_("Lowest recorded instruction number is %s.\n"), - pulongest (p->u.end.insn_num)); + gdb_printf (_("Lowest recorded instruction number is %u.\n"), + record_full_list[0].insn_num); /* If in replay mode, display where we are in the log. */ if (RECORD_FULL_IS_REPLAY) - gdb_printf (_("Current instruction number is %s.\n"), - pulongest (record_full_list->u.end.insn_num)); + gdb_printf (_("Current instruction number is %u.\n"), + record_full_list[record_full_next_insn].insn_num); /* Display instruction number for last instruction in the log. */ gdb_printf (_("Highest recorded instruction number is %s.\n"), @@ -1975,7 +1835,7 @@ record_full_base_target::supports_delete_record () void record_full_base_target::delete_record () { - record_full_list_release_following (record_full_list); + record_full_reset_history (); } /* The "record_is_replaying" target method. */ @@ -2001,23 +1861,23 @@ record_full_base_target::record_will_replay (ptid_t ptid, int dir) /* Go to a specific entry. */ static void -record_full_goto_entry (struct record_full_entry *p) +record_full_goto_entry (size_t target_insn) { - if (p == NULL) + if (target_insn >= record_full_list.size ()) error (_("Target insn not found.")); - else if (p == record_full_list) + else if (target_insn == record_full_next_insn) error (_("Already at target insn.")); - else if (p->u.end.insn_num > record_full_list->u.end.insn_num) + else if (target_insn > record_full_next_insn) { gdb_printf (_("Go forward to insn number %s\n"), - pulongest (p->u.end.insn_num)); - record_full_goto_insn (p, EXEC_FORWARD); + pulongest (record_full_list[target_insn].insn_num)); + record_full_goto_insn (target_insn, EXEC_FORWARD); } else { gdb_printf (_("Go backward to insn number %s\n"), - pulongest (p->u.end.insn_num)); - record_full_goto_insn (p, EXEC_REVERSE); + pulongest (target_insn)); + record_full_goto_insn (target_insn, EXEC_REVERSE); } registers_changed (); @@ -2033,13 +1893,7 @@ record_full_goto_entry (struct record_full_entry *p) void record_full_base_target::goto_record_begin () { - struct record_full_entry *p = NULL; - - for (p = &record_full_first; p != NULL; p = p->next) - if (p->type == record_full_end) - break; - - record_full_goto_entry (p); + record_full_goto_entry (0); } /* The "goto_record_end" target method. */ @@ -2047,15 +1901,7 @@ record_full_base_target::goto_record_begin () void record_full_base_target::goto_record_end () { - struct record_full_entry *p = NULL; - - for (p = record_full_list; p->next != NULL; p = p->next) - ; - for (; p!= NULL; p = p->prev) - if (p->type == record_full_end) - break; - - record_full_goto_entry (p); + record_full_goto_entry (record_full_list.size () - 1); } /* The "goto_record" target method. */ @@ -2063,13 +1909,7 @@ record_full_base_target::goto_record_end () void record_full_base_target::goto_record (ULONGEST target_insn) { - struct record_full_entry *p = NULL; - - for (p = &record_full_first; p != NULL; p = p->next) - if (p->type == record_full_end && p->u.end.insn_num == target_insn) - break; - - record_full_goto_entry (p); + record_full_goto_entry (target_insn); } /* The "record_stop_replaying" target method. */ @@ -2339,19 +2179,96 @@ netorder32 (uint32_t input) return ret; } +static void +record_full_read_entry_from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) +{ + uint8_t rectype; + uint32_t regnum, len; + uint64_t addr; + regcache *cache = get_thread_regcache (inferior_thread ()); + + bfdcore_read (cbfd, osec, &rectype, sizeof (rectype), bfd_offset); + switch (rectype) + { + case record_full_reg: /* reg */ + { + /* Get register number to regnum. */ + bfdcore_read (cbfd, osec, ®num, sizeof (regnum), bfd_offset); + regnum = netorder32 (regnum); + + record_full_entry rec; + + rec = record_full_reg_init (cache, regnum); + + /* Get val. */ + bfdcore_read (cbfd, osec, record_full_get_loc (&rec), + rec.u.reg.len, bfd_offset); + + if (record_debug) + gdb_printf (gdb_stdlog, + " Reading register %d (1 " + "plus %lu plus %d bytes)\n", + rec.u.reg.num, + (unsigned long) sizeof (regnum), + rec.u.reg.len); + + record_full_arch_list_add (rec); + break; + } + + case record_full_mem: /* mem */ + { + /* Get len. */ + bfdcore_read (cbfd, osec, &len, sizeof (len), bfd_offset); + len = netorder32 (len); + + /* Get addr. */ + bfdcore_read (cbfd, osec, &addr, sizeof (addr), + bfd_offset); + addr = netorder64 (addr); + + record_full_entry rec; + rec = record_full_mem_init (addr, len); + + /* Get val. */ + bfdcore_read (cbfd, osec, record_full_get_loc (&rec), len, + bfd_offset); + + if (record_debug) + gdb_printf (gdb_stdlog, + " Reading memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", + paddress (get_current_arch (), + rec.u.mem.addr), + (unsigned long) sizeof (addr), + (unsigned long) sizeof (len), + len); + + record_full_arch_list_add (rec); + break; + } + + default: + error (_("Bad entry type %d, offset %d of %lu in core file %ps."), + rectype, *bfd_offset, bfd_section_size (osec), + styled_string (file_name_style.style (), + bfd_get_filename (cbfd))); + break; + } +} + /* Restore the execution log from core file CBFD. */ static void record_full_restore (struct bfd &cbfd) { uint32_t magic; - struct record_full_entry *rec; asection *osec; uint32_t osec_size; int bfd_offset = 0; /* "record_full_restore" can only be called when record list is empty. */ - gdb_assert (record_full_first.next == NULL); + gdb_assert (record_full_list.empty ()); if (record_debug) gdb_printf (gdb_stdlog, "Restoring recording from core file.\n"); @@ -2379,124 +2296,47 @@ record_full_restore (struct bfd &cbfd) "RECORD_FULL_FILE_MAGIC (0x%s)\n", phex_nz (netorder32 (magic), 4)); - /* Restore the entries in recfd into record_full_arch_list_head and - record_full_arch_list_tail. */ - record_full_arch_list_head = NULL; - record_full_arch_list_tail = NULL; record_full_insn_num = 0; try { - regcache *regcache = get_thread_regcache (inferior_thread ()); - - while (1) + while (bfd_offset < osec_size) { - uint8_t rectype; - uint32_t regnum, len, signal, count; - uint64_t addr; + record_full_reset_incomplete (); + uint32_t eff_count = 0; + uint8_t sigval; + uint32_t insn_num; - /* We are finished when offset reaches osec_size. */ - if (bfd_offset >= osec_size) - break; - bfdcore_read (&cbfd, osec, &rectype, sizeof (rectype), &bfd_offset); + /* First read the generic information for an instruction. */ + bfdcore_read (&cbfd, osec, &sigval, sizeof (uint8_t), &bfd_offset); + bfdcore_read (&cbfd, osec, &eff_count, sizeof (uint32_t), + &bfd_offset); + bfdcore_read (&cbfd, osec, &insn_num, sizeof (uint32_t), + &bfd_offset); - switch (rectype) - { - case record_full_reg: /* reg */ - /* Get register number to regnum. */ - bfdcore_read (&cbfd, osec, ®num, sizeof (regnum), - &bfd_offset); - regnum = netorder32 (regnum); - - rec = record_full_reg_alloc (regcache, regnum); - - /* Get val. */ - bfdcore_read (&cbfd, osec, record_full_get_loc (rec), - rec->u.reg.len, &bfd_offset); - - if (record_debug) - gdb_printf (gdb_stdlog, - " Reading register %d (1 " - "plus %lu plus %d bytes)\n", - rec->u.reg.num, - (unsigned long) sizeof (regnum), - rec->u.reg.len); - break; + record_full_incomplete_instruction.insn_num = netorder32 (insn_num); + if (sigval != GDB_SIGNAL_0) + record_full_incomplete_instruction.sigval = (gdb_signal) sigval; - case record_full_mem: /* mem */ - /* Get len. */ - bfdcore_read (&cbfd, osec, &len, sizeof (len), &bfd_offset); - len = netorder32 (len); - - /* Get addr. */ - bfdcore_read (&cbfd, osec, &addr, sizeof (addr), &bfd_offset); - addr = netorder64 (addr); - - rec = record_full_mem_alloc (addr, len); - - /* Get val. */ - bfdcore_read (&cbfd, osec, record_full_get_loc (rec), - rec->u.mem.len, &bfd_offset); - - if (record_debug) - gdb_printf (gdb_stdlog, - " Reading memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (get_current_arch (), - rec->u.mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - rec->u.mem.len); - break; + eff_count = netorder32 (eff_count); - case record_full_end: /* end */ - rec = record_full_end_alloc (); - record_full_insn_num ++; - - /* Get signal value. */ - bfdcore_read (&cbfd, osec, &signal, sizeof (signal), - &bfd_offset); - signal = netorder32 (signal); - rec->u.end.sigval = (enum gdb_signal) signal; - - /* Get insn count. */ - bfdcore_read (&cbfd, osec, &count, sizeof (count), &bfd_offset); - count = netorder32 (count); - rec->u.end.insn_num = count; - record_full_insn_count = count + 1; - if (record_debug) - gdb_printf (gdb_stdlog, - " Reading record_full_end (1 + " - "%lu + %lu bytes), offset == %s\n", - (unsigned long) sizeof (signal), - (unsigned long) sizeof (count), - paddress (get_current_arch (), - bfd_offset)); - break; + /* This deals with all the side effects. */ + while (eff_count > 0) + { + eff_count--; - default: - error (_("Bad entry type in core file %ps."), - styled_string (file_name_style.style (), - bfd_get_filename (&cbfd))); - break; - } + record_full_read_entry_from_bfd (&cbfd, osec, &bfd_offset); + } - /* Add rec to record arch list. */ - record_full_arch_list_add (rec); + record_full_save_instruction (); } } catch (const gdb_exception &ex) { - record_full_list_release (record_full_arch_list_tail); + record_full_reset_incomplete (); throw; } - /* Add record_full_arch_list_head to the end of record list. */ - record_full_first.next = record_full_arch_list_head; - record_full_arch_list_head->prev = &record_full_first; - record_full_arch_list_tail->next = NULL; - record_full_list = &record_full_first; - /* Update record_full_insn_max_num. */ if (record_full_insn_num > record_full_insn_max_num) { @@ -2505,6 +2345,10 @@ record_full_restore (struct bfd &cbfd) record_full_insn_max_num); } + /* When loading a recording, we'll always start at the oldest possible + instruction, no matter where the original recording was stopped. */ + record_full_next_insn = 0; + /* Succeeded. */ gdb_printf (_("Restored records from core file %s.\n"), bfd_get_filename (&cbfd)); @@ -2538,13 +2382,73 @@ cmd_record_full_restore (const char *args, int from_tty) record_full_open (nullptr, from_tty); } +static void +record_full_write_entry_to_bfd (record_full_entry &entry, + gdb_bfd_ref_ptr obfd, + asection *osec, int *bfd_offset, + gdbarch *gdbarch) +{ + /* Save entry. */ + uint8_t type; + uint32_t regnum, len; + uint64_t addr; + + type = entry.type; + bfdcore_write (obfd.get (), osec, &type, sizeof (type), bfd_offset); + + switch (entry.type) + { + case record_full_reg: /* reg */ + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing register %d (1 " + "plus %lu plus %d bytes)\n", + entry.u.reg.num, + (unsigned long) sizeof (regnum), + entry.u.reg.len); + + /* Write regnum. */ + regnum = netorder32 (entry.u.reg.num); + bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), bfd_offset); + + /* Write regval. */ + bfdcore_write (obfd.get (), osec, record_full_get_loc (&entry), + entry.u.reg.len, bfd_offset); + break; + + case record_full_mem: /* mem */ + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", + paddress (gdbarch, + entry.u.mem.addr), + (unsigned long) sizeof (addr), + (unsigned long) sizeof (len), + entry.u.mem.len); + + /* Write memlen. */ + len = netorder32 (entry.u.mem.len); + bfdcore_write (obfd.get (), osec, &len, sizeof (len), bfd_offset); + + /* Write memaddr. */ + addr = netorder64 (entry.u.mem.addr); + bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), bfd_offset); + + /* Write memval. */ + bfdcore_write (obfd.get (), osec, record_full_get_loc (&entry), + entry.u.mem.len, bfd_offset); + break; + } + +} + /* Save the execution log to a file. We use a modified elf corefile format, with an extra section for our data. */ void record_full_base_target::save_record (const char *recfilename) { - struct record_full_entry *cur_record_full_list; uint32_t magic; struct gdbarch *gdbarch; int save_size = 0; @@ -2562,9 +2466,6 @@ record_full_base_target::save_record (const char *recfilename) /* Arrange to remove the output file on failure. */ gdb::unlinker unlink_file (recfilename); - /* Save the current record entry to "cur_record_full_list". */ - cur_record_full_list = record_full_list; - /* Get the values of regcache and gdbarch. */ regcache *regcache = get_thread_regcache (inferior_thread ()); gdbarch = regcache->arch (); @@ -2574,34 +2475,27 @@ record_full_base_target::save_record (const char *recfilename) = record_full_gdb_operation_disable_set (); /* Reverse execute to the begin of record list. */ - while (1) - { - /* Check for beginning and end of log. */ - if (record_full_list == &record_full_first) - break; - - record_full_exec_insn (regcache, gdbarch, record_full_list); - - if (record_full_list->prev) - record_full_list = record_full_list->prev; - } + for (int i = record_full_next_insn - 1; i >= 0; i--) + record_full_exec_insn (regcache, gdbarch, + record_full_list[i]); /* Compute the size needed for the extra bfd section. */ save_size = 4; /* magic cookie */ - for (record_full_list = record_full_first.next; record_full_list; - record_full_list = record_full_list->next) - switch (record_full_list->type) - { - case record_full_end: - save_size += 1 + 4 + 4; - break; - case record_full_reg: - save_size += 1 + 4 + record_full_list->u.reg.len; - break; - case record_full_mem: - save_size += 1 + 4 + 8 + record_full_list->u.mem.len; - break; - } + for (int i = record_full_list.size () - 1; i >= 0; i--) + { + /* Number of effects of an instruction. */ + save_size += sizeof (uint32_t) + sizeof (uint8_t) + sizeof (uint32_t); + for (auto &entry : record_full_list[i].effects) + switch (entry.type) + { + case record_full_reg: + save_size += 1 + 4 + entry.u.reg.len; + break; + case record_full_mem: + save_size += 1 + 4 + 8 + entry.u.mem.len; + break; + } + } /* Make the new bfd section. */ osec = bfd_make_section_anyway_with_flags (obfd.get (), "precord", @@ -2630,108 +2524,32 @@ record_full_base_target::save_record (const char *recfilename) /* Save the entries to recfd and forward execute to the end of record list. */ - record_full_list = &record_full_first; - while (1) + for (int i = 0; i < record_full_list.size (); i++) { - /* Save entry. */ - if (record_full_list != &record_full_first) + uint32_t eff_count = (uint32_t) record_full_list[i].effects.size (); + uint32_t insn_num = record_full_list[i].insn_num; + uint8_t sigval = (record_full_list[i].sigval.has_value ()) + ? record_full_list[i].sigval.value () + : GDB_SIGNAL_0; + + /* Signal. */ + bfdcore_write (obfd.get (), osec, &sigval, sizeof (sigval), &bfd_offset); + eff_count = netorder32 (eff_count); + /* Number of effects. */ + bfdcore_write (obfd.get (), osec, &eff_count, sizeof (eff_count), + &bfd_offset); + /* Instruction number. */ + bfdcore_write (obfd.get (), osec, &insn_num, sizeof (uint32_t), + &bfd_offset); + + for (auto &entry : record_full_list[i].effects) { - uint8_t type; - uint32_t regnum, len, signal, count; - uint64_t addr; - - type = record_full_list->type; - bfdcore_write (obfd.get (), osec, &type, sizeof (type), &bfd_offset); - - switch (record_full_list->type) - { - case record_full_reg: /* reg */ - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing register %d (1 " - "plus %lu plus %d bytes)\n", - record_full_list->u.reg.num, - (unsigned long) sizeof (regnum), - record_full_list->u.reg.len); - - /* Write regnum. */ - regnum = netorder32 (record_full_list->u.reg.num); - bfdcore_write (obfd.get (), osec, ®num, - sizeof (regnum), &bfd_offset); - - /* Write regval. */ - bfdcore_write (obfd.get (), osec, - record_full_get_loc (record_full_list), - record_full_list->u.reg.len, &bfd_offset); - break; - - case record_full_mem: /* mem */ - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (gdbarch, - record_full_list->u.mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - record_full_list->u.mem.len); - - /* Write memlen. */ - len = netorder32 (record_full_list->u.mem.len); - bfdcore_write (obfd.get (), osec, &len, sizeof (len), - &bfd_offset); - - /* Write memaddr. */ - addr = netorder64 (record_full_list->u.mem.addr); - bfdcore_write (obfd.get (), osec, &addr, - sizeof (addr), &bfd_offset); - - /* Write memval. */ - bfdcore_write (obfd.get (), osec, - record_full_get_loc (record_full_list), - record_full_list->u.mem.len, &bfd_offset); - break; - - case record_full_end: - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing record_full_end (1 + " - "%lu + %lu bytes)\n", - (unsigned long) sizeof (signal), - (unsigned long) sizeof (count)); - /* Write signal value. */ - signal = netorder32 (record_full_list->u.end.sigval); - bfdcore_write (obfd.get (), osec, &signal, - sizeof (signal), &bfd_offset); - - /* Write insn count. */ - count = netorder32 (record_full_list->u.end.insn_num); - bfdcore_write (obfd.get (), osec, &count, - sizeof (count), &bfd_offset); - break; - } + record_full_write_entry_to_bfd (entry, obfd, osec, &bfd_offset, + gdbarch); } - /* Execute entry. */ - record_full_exec_insn (regcache, gdbarch, record_full_list); - - if (record_full_list->next) - record_full_list = record_full_list->next; - else - break; - } - - /* Reverse execute to cur_record_full_list. */ - while (1) - { - /* Check for beginning and end of log. */ - if (record_full_list == cur_record_full_list) - break; - - record_full_exec_insn (regcache, gdbarch, record_full_list); - - if (record_full_list->prev) - record_full_list = record_full_list->prev; + if (i < record_full_next_insn) + record_full_exec_insn (regcache, gdbarch, record_full_list[i]); } unlink_file.keep (); @@ -2742,11 +2560,11 @@ record_full_base_target::save_record (const char *recfilename) } /* record_full_goto_insn -- rewind the record log (forward or backward, - depending on DIR) to the given entry, changing the program state - correspondingly. */ + depending on DIR) to the entry in position TARGET_INSN in the history, + changing the program state correspondingly. */ static void -record_full_goto_insn (struct record_full_entry *entry, +record_full_goto_insn (size_t target_insn, enum exec_direction_kind dir) { scoped_restore restore_operation_disable @@ -2757,17 +2575,12 @@ record_full_goto_insn (struct record_full_entry *entry, /* Assume everything is valid: we will hit the entry, and we will not hit the end of the recording. */ - if (dir == EXEC_FORWARD) - record_full_list = record_full_list->next; - - do - { - record_full_exec_insn (regcache, gdbarch, record_full_list); - if (dir == EXEC_REVERSE) - record_full_list = record_full_list->prev; - else - record_full_list = record_full_list->next; - } while (record_full_list != entry); + if (dir == EXEC_REVERSE) + for (int i = record_full_next_insn; i > target_insn; i--) + record_full_exec_insn (regcache, gdbarch, record_full_list[i - 1]); + else + for (int i = record_full_next_insn; i < target_insn; i++) + record_full_exec_insn (regcache, gdbarch, record_full_list[i]); } /* Alias for "target record-full". */ @@ -2798,61 +2611,36 @@ set_record_full_insn_max_num (const char *args, int from_tty, static void maintenance_print_record_instruction (const char *args, int from_tty) { - struct record_full_entry *to_print = record_full_list; + if (record_full_list.empty ()) + error (_("Not enough recorded history")); + int offset = record_full_next_insn - 1; + /* Reduce the offset by 1 if the record_full_next_insn is after the end + so that we show the last recorded instruction instead of crashing. */ + if (offset == record_full_list.size ()) + offset--; if (args != nullptr) { - int offset = value_as_long (parse_and_eval (args)); - if (offset > 0) - { - /* Move forward OFFSET instructions. We know we found the - end of an instruction when to_print->type is record_full_end. */ - while (to_print->next != nullptr && offset > 0) - { - to_print = to_print->next; - if (to_print->type == record_full_end) - offset--; - } - if (offset != 0) - error (_("Not enough recorded history")); - } - else - { - while (to_print->prev != nullptr && offset < 0) - { - to_print = to_print->prev; - if (to_print->type == record_full_end) - offset++; - } - if (offset != 0) - error (_("Not enough recorded history")); - } + offset += value_as_long (parse_and_eval (args)); + if (offset >= record_full_list.size () || offset < 0) + error (_("Not enough recorded history")); } - gdb_assert (to_print != nullptr); + auto to_print = record_full_list.begin () + offset; gdbarch *arch = current_inferior ()->arch (); - /* Go back to the start of the instruction. */ - while (to_print->prev != nullptr && to_print->prev->type != record_full_end) - to_print = to_print->prev; - - /* if we're in the first record, there are no actual instructions - recorded. Warn the user and leave. */ - if (to_print == &record_full_first) - error (_("Not enough recorded history")); - - while (to_print->type != record_full_end) + for (auto entry : to_print->effects) { - switch (to_print->type) + switch (entry.type) { case record_full_reg: { - type *regtype = gdbarch_register_type (arch, to_print->u.reg.num); + type *regtype = gdbarch_register_type (arch, entry.u.reg.num); value *val = value_from_contents (regtype, - record_full_get_loc (to_print)); + record_full_get_loc (&entry)); gdb_printf ("Register %s changed: ", - gdbarch_register_name (arch, to_print->u.reg.num)); + gdbarch_register_name (arch, entry.u.reg.num)); struct value_print_options opts; get_user_print_options (&opts); opts.raw = true; @@ -2862,17 +2650,16 @@ maintenance_print_record_instruction (const char *args, int from_tty) } case record_full_mem: { - gdb_byte *b = record_full_get_loc (to_print); + gdb_byte *b = record_full_get_loc (&entry); gdb_printf ("%d bytes of memory at address %s changed from:", - to_print->u.mem.len, - print_core_address (arch, to_print->u.mem.addr)); - for (int i = 0; i < to_print->u.mem.len; i++) + entry.u.mem.len, + print_core_address (arch, entry.u.mem.addr)); + for (int i = 0; i < entry.u.mem.len; i++) gdb_printf (" %02x", b[i]); gdb_printf ("\n"); break; } } - to_print = to_print->next; } } @@ -2880,11 +2667,6 @@ INIT_GDB_FILE (record_full) { struct cmd_list_element *c; - /* Init record_full_first. */ - record_full_first.prev = NULL; - record_full_first.next = NULL; - record_full_first.type = record_full_end; - add_target (record_full_target_info, record_full_open); add_deprecated_target_alias (record_full_target_info, "record"); add_target (record_full_core_target_info, record_full_open); diff --git a/gdb/record-full.h b/gdb/record-full.h index 51effe74560..c327d879a8a 100644 --- a/gdb/record-full.h +++ b/gdb/record-full.h @@ -41,7 +41,6 @@ enum record_result extern int record_full_arch_list_add_reg (struct regcache *regcache, int num); extern int record_full_arch_list_add_mem (CORE_ADDR addr, int len); -extern int record_full_arch_list_add_end (void); /* Returns true if the process record target is open. */ extern int record_full_is_used (void); diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 6b5c9c02d46..f5b1f66844c 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -5466,8 +5466,5 @@ riscv_process_record (struct gdbarch *gdbarch, struct regcache *regcache, if (res != RECORD_SUCCESS) return res; - if (record_full_arch_list_add_end ()) - return -1; - return 0; } diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index e135df94a40..f964889a49f 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -7138,8 +7138,6 @@ ppc_process_prefix_instruction (int insn_prefix, int insn_suffix, if (record_full_arch_list_add_reg (regcache, PPC_PC_REGNUM)) return -1; - if (record_full_arch_list_add_end ()) - return -1; return 0; } @@ -7447,8 +7445,6 @@ ppc_process_record (struct gdbarch *gdbarch, struct regcache *regcache, if (record_full_arch_list_add_reg (regcache, PPC_PC_REGNUM)) return -1; - if (record_full_arch_list_add_end ()) - return -1; return 0; } diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c index 3cd6b359d13..6bea30f08dc 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -910,9 +910,6 @@ s390_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache, if (record_full_arch_list_add_mem (sp, sizeof_rt_sigframe)) return -1; - if (record_full_arch_list_add_end ()) - return -1; - return 0; } diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c index f9d7bdd04e4..36ce659ea15 100644 --- a/gdb/s390-tdep.c +++ b/gdb/s390-tdep.c @@ -7019,8 +7019,6 @@ s390_process_record (struct gdbarch *gdbarch, struct regcache *regcache, if (record_full_arch_list_add_reg (regcache, S390_PSWA_REGNUM)) return -1; - if (record_full_arch_list_add_end ()) - return -1; return 0; } From patchwork Fri May 15 16:36:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135073 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 346E240A00DE for ; Fri, 15 May 2026 16:40:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 346E240A00DE Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=aFKkhb0z 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.129.124]) by sourceware.org (Postfix) with ESMTP id 1C25340A24B1 for ; Fri, 15 May 2026 16:39:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C25340A24B1 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1C25340A24B1 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863141; cv=none; b=KbR0XxnSnHOeYbApbzfjfVep7sqfeYjkMZYt2BBuCGQl+vtsI9/gNPS0WSQcejLXGm+H61pN/VBzS5zrkLzRZSfhsjRVDI4rW+Ekknk8iVYUXgImbMzeUuVGa7bz1J/6tY3OhLswxjNdOtqsXaoT+V2L5iFEKw7rqBd8+rfGojE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863141; c=relaxed/simple; bh=XK9nGXOK0C6VDbfGEIrJgp2iC7NvD7U1n3eShyQQKT0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=OPyrqUEJm5FcvV93GJOYMi8yeLLw6ku8VXm7hn50bLqAJ1wriS/kxgzRWbSx7B3IqST+AMKPqCGer2/cc4wcUdQzKfKiiLhbtn1BB3Rl6JdhhGYesybKDPO3xtSzmW8zheuCGNqwAB9V0967D+5IQEkbDrargaW2x5QvGnqmXq8= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=aFKkhb0z DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1C25340A24B1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863140; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EJLEvtj9yhjGnCmnmX2nQurGWrwuMNs//s/cBRfQDyo=; b=aFKkhb0zOYLoKakuDOZLAL/L+WcqBPY0cvKbowRECK7pLvYCl6WUIvQuvyK8FxoDOgHzgl Z32Us+rRNEW/KZfwIEeWoPWOwG5j/HqML8MuPKlxWGiSUlq/ZRpBPLmUPCyTjYf/KLe+6F fTvDosZy5AQbr4xNLy2h402NsKkFyw8= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-685-s4F9LCzBMr-2KdEAy6nH0g-1; Fri, 15 May 2026 12:38:57 -0400 X-MC-Unique: s4F9LCzBMr-2KdEAy6nH0g-1 X-Mimecast-MFC-AGG-ID: s4F9LCzBMr-2KdEAy6nH0g_1778863136 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A106C180034E; Fri, 15 May 2026 16:38:56 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 2F97D1955F2D; Fri, 15 May 2026 16:38:54 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen , Thiago Jung Bauermann Subject: [PATCH v3 2/7] gdb/record: remove record_full_insn_num Date: Fri, 15 May 2026 13:36:59 -0300 Message-ID: <20260515163706.3355686-3-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ZKHA4GnUT1GG7wgHpuqhqh7fSeqJjG8_2jqJjlGgPk4_1778863136 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.5 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_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Now that record_full_list uses a deque, we don't need a variable to track the amount of items recorded, so it is just dropped. Reviewed-by: Thiago Jung Bauermann Reviewed-By: Christina Schimpe --- gdb/record-full.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 02a57726a95..e4dd07dc300 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -193,8 +193,6 @@ static bool record_full_stop_at_limit = true; /* Maximum allowed number of insns in execution log. */ static unsigned int record_full_insn_max_num = DEFAULT_RECORD_FULL_INSN_MAX_NUM; -/* Actual count of insns presently in execution log. */ -static unsigned int record_full_insn_num = 0; /* Count of insns logged so far (may be larger than count of insns presently in execution log). */ static ULONGEST record_full_insn_count; @@ -462,7 +460,6 @@ record_full_entry_cleanup (record_full_entry rec) static void record_full_reset_history () { - record_full_insn_num = 0; record_full_insn_count = 0; record_full_next_insn = 0; @@ -504,9 +501,7 @@ record_full_save_instruction () } /* Delete the first instruction from the beginning of the log, to make - room for adding a new instruction at the end of the log. - - Note -- this function does not modify record_full_insn_num. */ + room for adding a new instruction at the end of the log. */ static void record_full_list_release_first (void) @@ -606,7 +601,7 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) static void record_full_check_insn_num (void) { - if (record_full_insn_num == record_full_insn_max_num) + if (record_full_list.size () == record_full_insn_max_num) { /* Ask user what to do. */ if (record_full_stop_at_limit) @@ -688,10 +683,8 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) record_full_save_instruction (); - if (record_full_insn_num == record_full_insn_max_num) + if (record_full_list.size () == record_full_insn_max_num) record_full_list_release_first (); - else - record_full_insn_num++; } static bool @@ -1468,10 +1461,8 @@ record_full_registers_change (struct regcache *regcache, int regnum) } record_full_save_instruction (); - if (record_full_insn_num == record_full_insn_max_num) + if (record_full_list.size () == record_full_insn_max_num) record_full_list_release_first (); - else - record_full_insn_num++; } /* "store_registers" method for process record target. */ @@ -1572,10 +1563,8 @@ record_full_target::xfer_partial (enum target_object object, } record_full_save_instruction (); - if (record_full_insn_num == record_full_insn_max_num) + if (record_full_list.size () == record_full_insn_max_num) record_full_list_release_first (); - else - record_full_insn_num++; } return this->beneath ()->xfer_partial (object, annex, readbuf, writebuf, @@ -1813,8 +1802,8 @@ record_full_base_target::info_record () pulongest (record_full_insn_count)); /* Display log count. */ - gdb_printf (_("Log contains %u instructions.\n"), - record_full_insn_num); + gdb_printf (_("Log contains %lu instructions.\n"), + (unsigned long int) record_full_list.size ()); } else gdb_printf (_("No instructions have been logged.\n")); @@ -2296,8 +2285,6 @@ record_full_restore (struct bfd &cbfd) "RECORD_FULL_FILE_MAGIC (0x%s)\n", phex_nz (netorder32 (magic), 4)); - record_full_insn_num = 0; - try { while (bfd_offset < osec_size) @@ -2338,9 +2325,9 @@ record_full_restore (struct bfd &cbfd) } /* Update record_full_insn_max_num. */ - if (record_full_insn_num > record_full_insn_max_num) + if (record_full_list.size () > record_full_insn_max_num) { - record_full_insn_max_num = record_full_insn_num; + record_full_insn_max_num = record_full_list.size (); warning (_("Auto increase record/replay buffer limit to %u."), record_full_insn_max_num); } @@ -2595,14 +2582,10 @@ static void set_record_full_insn_max_num (const char *args, int from_tty, struct cmd_list_element *c) { - if (record_full_insn_num > record_full_insn_max_num) + if (record_full_list.size () > record_full_insn_max_num) { - /* Count down record_full_insn_num while releasing records from list. */ - while (record_full_insn_num > record_full_insn_max_num) - { - record_full_list_release_first (); - record_full_insn_num--; - } + while (record_full_list.size () > record_full_insn_max_num) + record_full_list_release_first (); } } From patchwork Fri May 15 16:37:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135074 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 056004AB0F49 for ; Fri, 15 May 2026 16:40:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 056004AB0F49 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bE2K/8y+ 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 ESMTP id CE81340A00CB for ; Fri, 15 May 2026 16:39:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CE81340A00CB Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CE81340A00CB Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863141; cv=none; b=Fx15Fbhq0eD2A3Hlo0Yc4xinDmDjoA9FwiaVIg3F2uY9vXoWZk6w9cq3uCMRI478tN1/avuvHjPadgQTeUAsKg7dvIPePEFVEQaMITJXRwWWYbw2Zm3guB2HdpMlc1pJ0PXeoQVLxOkFkli7qijzmRR8fpt6CurPe+R3PRObGLw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863141; c=relaxed/simple; bh=qy+Mmi0vg2WSgE6wLtSBmH8AzCx/qXOEEVkEWoaumA0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=PAcd8L6Hk1jset7L8OKaL/f5qFFvRJSUdOOF7RBitnkXC4a7CIqMX0FkranbBspVqV0oye8iELBxwP+teaHTfW+FbZjQukC/aRR/ifcgg4tmLW4ndVcoVf09F7gSHl01umGuYC03tbMvWMbAR1SfFQJttz+c0tAYgem4WsX2sVI= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bE2K/8y+ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CE81340A00CB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863141; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=d+0rfIIOSXFWfe/ioeJcNwIFk/QHxAEXM/fjqKXorGU=; b=bE2K/8y+qFZaJMAoZ9fqIei6/ArFgu5xTcop+aA9ilWadLoZqAymzFbWORtxgLU9N/btvP cTgXrva6VU9a42H2i2Sl+3fOw1QJzrtZYRBZuPFNHGkx3OtHP8Iz9Sq/0Vz8Oo45c5/Wrw AHh9KN1fzmDav7uzyXvFFVInf+ikGeI= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-446-TAmwzNPGOFOCmSHERVcE7g-1; Fri, 15 May 2026 12:38:59 -0400 X-MC-Unique: TAmwzNPGOFOCmSHERVcE7g-1 X-Mimecast-MFC-AGG-ID: TAmwzNPGOFOCmSHERVcE7g_1778863139 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E3D8D1800371; Fri, 15 May 2026 16:38:58 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8D1B31955F2D; Fri, 15 May 2026 16:38:56 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen , Thiago Jung Bauermann Subject: [PATCH v3 3/7] gdb/record: c++ify internal structures of record-full.c Date: Fri, 15 May 2026 13:37:00 -0300 Message-ID: <20260515163706.3355686-4-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: fYNgxDJxBO6q94G3b1Fc-SqqRX-oHoAub7eAK5TPwgE_1778863139 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.5 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_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This commit adds a constructor, destructor, and some methods to the structures record_full_entry, record_full_reg_entry and record_full_mem_entry. This is a move to disentangle the internal representation of the data and how record-full manipulates it for replaying. Along with this change, record_full_entry is changed to use an std::variant, since it was basically doing that already, but now we have the stdlibc++ error checking to make sure we're only accessing elements we're allowed to. Reviewed-by: Thiago Jung Bauermann --- gdb/record-full.c | 601 +++++++++++++++++++++++++--------------------- 1 file changed, 321 insertions(+), 280 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index e4dd07dc300..24e94eaf5da 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -51,6 +51,7 @@ #include #include #include +#include /* This module implements "target record-full", also known as "process record and replay". This target sits on top of a "normal" target @@ -93,12 +94,113 @@ struct record_full_mem_entry int len; /* Set this flag if target memory for this entry can no longer be accessed. */ - int mem_entry_not_accessible; + bool mem_entry_accessible; union { gdb_byte *ptr; gdb_byte buf[sizeof (gdb_byte *)]; } u; + + record_full_mem_entry () : addr (0), len (0) { } + + record_full_mem_entry (CORE_ADDR mem_addr, int mem_len) + { + addr = mem_addr; + len = mem_len; + if (len > sizeof (u.buf)) + u.ptr = new gdb_byte[len]; + mem_entry_accessible = true; + } + + record_full_mem_entry (record_full_mem_entry &&other) + { + addr = other.addr; + len = other.len; + memcpy (u.buf, other.u.buf, sizeof (u.buf)); + mem_entry_accessible = other.mem_entry_accessible; + /* With len == 0, OTHER is guaranteed to not try to free the + memory when it is destructed. */ + other.len = 0; + } + + ~record_full_mem_entry () + { + if (len > sizeof (u.buf)) + delete[] u.ptr; + } + + record_full_mem_entry &operator= (record_full_mem_entry &&other) + { + addr = other.addr; + len = other.len; + memcpy (u.buf, other.u.buf, sizeof (u.buf)); + mem_entry_accessible = other.mem_entry_accessible; + /* With len == 0, OTHER is guaranteed to not try to free the + memory when it is destructed. */ + other.len = 0; + return *this; + } + + DISABLE_COPY_AND_ASSIGN (record_full_mem_entry); + + gdb_byte *get_loc () + { + if (len > sizeof (u.buf)) + return u.ptr; + else + return u.buf; + } + + bool execute (gdbarch *gdbarch) + { + /* Nothing to do if the memory is flagged not_accessible. */ + if (!mem_entry_accessible) + return false; + + gdb::byte_vector buf (len); + + if (record_debug > 1) + gdb_printf (gdb_stdlog, + "Process record: record_full_mem %s to " + "inferior addr = %s len = %d.\n", + host_address_to_string (this), + paddress (gdbarch, addr), + len); + + if (record_read_memory (gdbarch, addr, buf.data (), len)) + mem_entry_accessible = false; + else + { + if (target_write_memory (addr, + get_loc (), + len)) + { + mem_entry_accessible = false; + if (record_debug) + warning (_("Process record: error writing memory at " + "addr = %s len = %d."), + paddress (gdbarch, addr), + len); + } + else + { + memcpy (get_loc (), buf.data (), len); + + /* We've changed memory --- check if a hardware + watchpoint should trap. Note that this + presently assumes the target beneath supports + continuable watchpoints. On non-continuable + watchpoints target, we'll want to check this + _before_ actually doing the memory change, and + not doing the change at all if the watchpoint + traps. */ + if (hardware_watchpoint_inserted_in_range + (current_inferior ()->aspace.get (), addr, len)) + return true; + } + } + return false; + } }; struct record_full_reg_entry @@ -110,6 +212,70 @@ struct record_full_reg_entry gdb_byte *ptr; gdb_byte buf[2 * sizeof (gdb_byte *)]; } u; + + record_full_reg_entry () : num (0), len (0) { } + + record_full_reg_entry (gdbarch *gdbarch, int regnum) + { + num = regnum; + len = register_size (gdbarch, regnum); + if (len > sizeof (u.buf)) + u.ptr = new gdb_byte[len]; + } + + record_full_reg_entry (record_full_reg_entry &&other) + { + num = other.num; + len = other.len; + memcpy (u.buf, other.u.buf, sizeof (u.buf)); + /* With len == 0, OTHER is guaranteed to not try to free the + memory when it is destructed. */ + other.len = 0; + } + + ~record_full_reg_entry () + { + if (len > sizeof (u.buf)) + delete[] u.ptr; + } + + record_full_reg_entry &operator=(record_full_reg_entry &&other) + { + num = other.num; + len = other.len; + memcpy (u.buf, other.u.buf, sizeof (u.buf)); + /* With len == 0, OTHER is guaranteed to not try to free the + memory when it is destructed. */ + other.len = 0; + return *this; + } + + DISABLE_COPY_AND_ASSIGN (record_full_reg_entry); + + gdb_byte *get_loc () + { + if (len > sizeof (u.buf)) + return u.ptr; + else + return u.buf; + } + + bool execute (regcache *regcache) + { + gdb::byte_vector buf (len); + + if (record_debug > 1) + gdb_printf (gdb_stdlog, + "Process record: record_full_reg %s to " + "inferior num = %d.\n", + host_address_to_string (this), + num); + + regcache->cooked_read (num, buf); + regcache->cooked_write (num, get_loc ()); + memcpy (get_loc (), buf.data (), len); + return false; + } }; enum record_full_type @@ -118,16 +284,88 @@ enum record_full_type record_full_mem }; -struct record_full_entry +class record_full_entry { - enum record_full_type type; - union + std::variant entry; + +public: + record_full_entry () : entry (record_full_reg_entry ()) {} + + /* Constructor for a register entry. Type is here to make it + easier to recognize it in the constructor calls, it isn't + actually important. */ + record_full_entry (record_full_type reg_type, gdbarch *gdbarch, + int regnum) + : entry(record_full_reg_entry (gdbarch, regnum)) { - /* reg */ - struct record_full_reg_entry reg; - /* mem */ - struct record_full_mem_entry mem; - } u; + gdb_assert (reg_type == record_full_reg); + } + + record_full_entry (record_full_type mem_type, CORE_ADDR addr, int len) + : entry(record_full_mem_entry (addr, len)) + { + gdb_assert (mem_type == record_full_mem); + } + + record_full_entry (record_full_entry &&other) + : entry (std::move (other.entry)) + { + } + + DISABLE_COPY_AND_ASSIGN (record_full_entry); + + record_full_reg_entry& reg () + { + gdb_assert (type () == record_full_reg); + return std::get (entry); + } + + record_full_mem_entry& mem () + { + gdb_assert (type () == record_full_mem); + return std::get (entry); + } + + record_full_type type () + { + switch (entry.index ()) + { + case 0: + return record_full_reg; + case 1: + return record_full_mem; + } + gdb_assert_not_reached ("Impossible variant index"); + } + + /* Get the pointer to the data stored by this entry. */ + gdb_byte *get_loc () + { + switch (type ()) + { + case record_full_reg: + return reg ().get_loc (); + case record_full_mem: + return mem ().get_loc (); + } + gdb_assert_not_reached ("Impossible entry type"); + } + + /* Execute this entry, swapping the appropriate values from memory or + register and the recorded ones. Returns TRUE if the execution was + stopped by a watchpoint. */ + + bool execute (regcache *regcache) + { + switch (type ()) + { + case record_full_reg: + return reg ().execute (regcache); + case record_full_mem: + return mem ().execute (regcache->arch ()); + } + return false; + } }; /* This is the main structure that comprises the execution log. @@ -384,91 +622,12 @@ static struct cmd_list_element *record_full_cmdlist; static void record_full_goto_insn (size_t target_insn, enum exec_direction_kind dir); -/* Initialization and cleanup functions for record_full_reg and - record_full_mem entries. */ - -/* Init a record_full_reg record entry. */ - -static inline record_full_entry -record_full_reg_init (struct regcache *regcache, int regnum) -{ - record_full_entry rec; - struct gdbarch *gdbarch = regcache->arch (); - - rec.type = record_full_reg; - rec.u.reg.num = regnum; - rec.u.reg.len = register_size (gdbarch, regnum); - if (rec.u.reg.len > sizeof (rec.u.reg.u.buf)) - rec.u.reg.u.ptr = (gdb_byte *) xmalloc (rec.u.reg.len); - - return rec; -} - -/* Cleanup a record_full_reg record entry. */ - -static inline void -record_full_reg_cleanup (record_full_entry rec) -{ - gdb_assert (rec.type == record_full_reg); - if (rec.u.reg.len > sizeof (rec.u.reg.u.buf)) - xfree (rec.u.reg.u.ptr); -} - -/* Init a record_full_mem record entry. */ - -static inline record_full_entry -record_full_mem_init (CORE_ADDR addr, int len) -{ - record_full_entry rec; - - rec.type = record_full_mem; - rec.u.mem.addr = addr; - rec.u.mem.len = len; - if (rec.u.mem.len > sizeof (rec.u.mem.u.buf)) - rec.u.mem.u.ptr = (gdb_byte *) xmalloc (len); - rec.u.mem.mem_entry_not_accessible = 0; - - return rec; -} - -/* Cleanup a record_full_mem record entry. */ - -static inline void -record_full_mem_cleanup (record_full_entry rec) -{ - gdb_assert (rec.type == record_full_mem); - if (rec.u.mem.len > sizeof (rec.u.mem.u.buf)) - xfree (rec.u.mem.u.ptr); -} - -/* Free one record entry, any type. */ - -static inline void -record_full_entry_cleanup (record_full_entry rec) -{ - - switch (rec.type) { - case record_full_reg: - record_full_reg_cleanup (rec); - break; - case record_full_mem: - record_full_mem_cleanup (rec); - break; - } -} - static void record_full_reset_history () { record_full_insn_count = 0; record_full_next_insn = 0; - for (auto &insn : record_full_list) - { - for (auto &entry : insn.effects) - record_full_entry_cleanup (entry); - } - record_full_list.clear (); } @@ -476,11 +635,7 @@ static void record_full_list_release_following (int index) { for (int i = record_full_list.size () - 1; i > index; i--) - { - for (auto &entry : record_full_list[i].effects) - record_full_entry_cleanup (entry); - record_full_list.pop_back (); - } + record_full_list.pop_back (); /* Set the next instruction to be past the end of the log so we start recording if the user moves forward again. */ record_full_next_insn = index; @@ -509,9 +664,6 @@ record_full_list_release_first (void) if (record_full_list.empty ()) return; - for (auto &entry : record_full_list[0].effects) - record_full_entry_cleanup (entry); - record_full_list.pop_front (); --record_full_next_insn; } @@ -521,28 +673,7 @@ record_full_list_release_first (void) static void record_full_arch_list_add (record_full_entry &rec) { - record_full_incomplete_instruction.effects.push_back (rec); -} - -/* Return the value storage location of a record entry. */ -static inline gdb_byte * -record_full_get_loc (struct record_full_entry *rec) -{ - switch (rec->type) { - case record_full_mem: - if (rec->u.mem.len > sizeof (rec->u.mem.u.buf)) - return rec->u.mem.u.ptr; - else - return rec->u.mem.u.buf; - case record_full_reg: - if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) - return rec->u.reg.u.ptr; - else - return rec->u.reg.u.buf; - default: - gdb_assert_not_reached ("unexpected record_full_entry type"); - return NULL; - } + record_full_incomplete_instruction.effects.push_back (std::move (rec)); } /* Record the value of a register NUM to record_full_arch_list. */ @@ -550,7 +681,7 @@ record_full_get_loc (struct record_full_entry *rec) int record_full_arch_list_add_reg (struct regcache *regcache, int regnum) { - record_full_entry rec; + record_full_entry rec (record_full_reg, regcache->arch (), regnum); if (record_debug > 1) gdb_printf (gdb_stdlog, @@ -558,9 +689,7 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum) "record list.\n", regnum); - rec = record_full_reg_init (regcache, regnum); - - regcache->cooked_read (regnum, record_full_get_loc (&rec)); + regcache->cooked_read (regnum, rec.get_loc ()); record_full_arch_list_add (rec); @@ -573,7 +702,7 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum) int record_full_arch_list_add_mem (CORE_ADDR addr, int len) { - record_full_entry rec; + record_full_entry rec (record_full_mem, addr, len); if (record_debug > 1) gdb_printf (gdb_stdlog, @@ -584,14 +713,9 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) if (!addr) /* FIXME: Why? Some arch must permit it... */ return 0; - rec = record_full_mem_init (addr, len); - if (record_read_memory (current_inferior ()->arch (), addr, - record_full_get_loc (&rec), len)) - { - record_full_mem_cleanup (rec); - return -1; - } + rec.get_loc (), len)) + return -1; record_full_arch_list_add (rec); @@ -719,98 +843,14 @@ record_full_gdb_operation_disable_set (void) static enum target_stop_reason record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON; -/* Execute one instruction from the record log. Each instruction in - the log will be represented by an arbitrary sequence of register - entries and memory entries, followed by an 'end' entry. */ - -static inline void -record_full_exec_entry (regcache *regcache, - gdbarch *gdbarch, - record_full_entry *entry) -{ - switch (entry->type) - { - case record_full_reg: /* reg */ - { - gdb::byte_vector reg (entry->u.reg.len); - - if (record_debug > 1) - gdb_printf (gdb_stdlog, - "Process record: record_full_reg %s to " - "inferior num = %d.\n", - host_address_to_string (entry), - entry->u.reg.num); - - regcache->cooked_read (entry->u.reg.num, reg.data ()); - regcache->cooked_write (entry->u.reg.num, record_full_get_loc (entry)); - memcpy (record_full_get_loc (entry), reg.data (), entry->u.reg.len); - } - break; - - case record_full_mem: /* mem */ - { - /* Nothing to do if the entry is flagged not_accessible. */ - if (!entry->u.mem.mem_entry_not_accessible) - { - gdb::byte_vector mem (entry->u.mem.len); - - if (record_debug > 1) - gdb_printf (gdb_stdlog, - "Process record: record_full_mem %s to " - "inferior addr = %s len = %d.\n", - host_address_to_string (entry), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - - if (record_read_memory (gdbarch, - entry->u.mem.addr, mem.data (), - entry->u.mem.len)) - entry->u.mem.mem_entry_not_accessible = 1; - else - { - if (target_write_memory (entry->u.mem.addr, - record_full_get_loc (entry), - entry->u.mem.len)) - { - entry->u.mem.mem_entry_not_accessible = 1; - if (record_debug) - warning (_("Process record: error writing memory at " - "addr = %s len = %d."), - paddress (gdbarch, entry->u.mem.addr), - entry->u.mem.len); - } - else - { - memcpy (record_full_get_loc (entry), mem.data (), - entry->u.mem.len); - - /* We've changed memory --- check if a hardware - watchpoint should trap. Note that this - presently assumes the target beneath supports - continuable watchpoints. On non-continuable - watchpoints target, we'll want to check this - _before_ actually doing the memory change, and - not doing the change at all if the watchpoint - traps. */ - if (hardware_watchpoint_inserted_in_range - (current_inferior ()->aspace.get (), - entry->u.mem.addr, entry->u.mem.len)) - record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; - } - } - } - } - break; - } -} - static inline void record_full_exec_insn (regcache *regcache, gdbarch *gdbarch, record_full_instruction &insn) { for (auto &entry : insn.effects) - record_full_exec_entry (regcache, gdbarch, &entry); + if (entry.execute (regcache)) + record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; } static void record_full_restore (struct bfd &cbfd); @@ -2185,21 +2225,19 @@ record_full_read_entry_from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) bfdcore_read (cbfd, osec, ®num, sizeof (regnum), bfd_offset); regnum = netorder32 (regnum); - record_full_entry rec; - - rec = record_full_reg_init (cache, regnum); + record_full_entry rec (record_full_reg, cache->arch (), regnum); /* Get val. */ - bfdcore_read (cbfd, osec, record_full_get_loc (&rec), - rec.u.reg.len, bfd_offset); + bfdcore_read (cbfd, osec, rec.get_loc (), + rec.reg ().len, bfd_offset); if (record_debug) gdb_printf (gdb_stdlog, " Reading register %d (1 " "plus %lu plus %d bytes)\n", - rec.u.reg.num, + rec.reg ().num, (unsigned long) sizeof (regnum), - rec.u.reg.len); + rec.reg ().len); record_full_arch_list_add (rec); break; @@ -2216,19 +2254,17 @@ record_full_read_entry_from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) bfd_offset); addr = netorder64 (addr); - record_full_entry rec; - rec = record_full_mem_init (addr, len); + record_full_entry rec (record_full_mem, addr, len); /* Get val. */ - bfdcore_read (cbfd, osec, record_full_get_loc (&rec), len, - bfd_offset); + bfdcore_read (cbfd, osec, rec.get_loc (), len, bfd_offset); if (record_debug) gdb_printf (gdb_stdlog, " Reading memory %s (1 plus " "%lu plus %lu plus %d bytes)\n", paddress (get_current_arch (), - rec.u.mem.addr), + rec.mem ().addr), (unsigned long) sizeof (addr), (unsigned long) sizeof (len), len); @@ -2380,52 +2416,56 @@ record_full_write_entry_to_bfd (record_full_entry &entry, uint32_t regnum, len; uint64_t addr; - type = entry.type; + type = entry.type (); bfdcore_write (obfd.get (), osec, &type, sizeof (type), bfd_offset); - switch (entry.type) + switch (type) { case record_full_reg: /* reg */ - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing register %d (1 " - "plus %lu plus %d bytes)\n", - entry.u.reg.num, - (unsigned long) sizeof (regnum), - entry.u.reg.len); - - /* Write regnum. */ - regnum = netorder32 (entry.u.reg.num); - bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), bfd_offset); - - /* Write regval. */ - bfdcore_write (obfd.get (), osec, record_full_get_loc (&entry), - entry.u.reg.len, bfd_offset); - break; + { + auto ® = entry.reg (); + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing register %d (1 " + "plus %lu plus %d bytes)\n", + reg.num, + (unsigned long) sizeof (regnum), + reg.len); + + /* Write regnum. */ + regnum = netorder32 (reg.num); + bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), bfd_offset); + + /* Write regval. */ + bfdcore_write (obfd.get (), osec, entry.get_loc (), reg.len, bfd_offset); + break; + } case record_full_mem: /* mem */ - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (gdbarch, - entry.u.mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - entry.u.mem.len); - - /* Write memlen. */ - len = netorder32 (entry.u.mem.len); - bfdcore_write (obfd.get (), osec, &len, sizeof (len), bfd_offset); - - /* Write memaddr. */ - addr = netorder64 (entry.u.mem.addr); - bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), bfd_offset); - - /* Write memval. */ - bfdcore_write (obfd.get (), osec, record_full_get_loc (&entry), - entry.u.mem.len, bfd_offset); - break; + { + auto &mem = entry.mem (); + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", + paddress (gdbarch, mem.addr), + (unsigned long) sizeof (addr), + (unsigned long) sizeof (len), + mem.len); + + /* Write memlen. */ + len = netorder32 (mem.len); + bfdcore_write (obfd.get (), osec, &len, sizeof (len), bfd_offset); + + /* Write memaddr. */ + addr = netorder64 (mem.addr); + bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), bfd_offset); + + /* Write memval. */ + bfdcore_write (obfd.get (), osec, entry.get_loc (), mem.len, + bfd_offset); + break; + } } } @@ -2473,13 +2513,13 @@ record_full_base_target::save_record (const char *recfilename) /* Number of effects of an instruction. */ save_size += sizeof (uint32_t) + sizeof (uint8_t) + sizeof (uint32_t); for (auto &entry : record_full_list[i].effects) - switch (entry.type) + switch (entry.type ()) { case record_full_reg: - save_size += 1 + 4 + entry.u.reg.len; + save_size += 1 + 4 + entry.reg ().len; break; case record_full_mem: - save_size += 1 + 4 + 8 + entry.u.mem.len; + save_size += 1 + 4 + 8 + entry.mem ().len; break; } } @@ -2612,18 +2652,18 @@ maintenance_print_record_instruction (const char *args, int from_tty) gdbarch *arch = current_inferior ()->arch (); - for (auto entry : to_print->effects) + for (auto &entry : to_print->effects) { - switch (entry.type) + switch (entry.type ()) { case record_full_reg: { - type *regtype = gdbarch_register_type (arch, entry.u.reg.num); + type *regtype = gdbarch_register_type (arch, entry.reg ().num); value *val = value_from_contents (regtype, - record_full_get_loc (&entry)); + entry.get_loc ()); gdb_printf ("Register %s changed: ", - gdbarch_register_name (arch, entry.u.reg.num)); + gdbarch_register_name (arch, entry.reg ().num)); struct value_print_options opts; get_user_print_options (&opts); opts.raw = true; @@ -2633,11 +2673,12 @@ maintenance_print_record_instruction (const char *args, int from_tty) } case record_full_mem: { - gdb_byte *b = record_full_get_loc (&entry); + record_full_mem_entry& mem = entry.mem (); + gdb_byte *b = entry.get_loc (); gdb_printf ("%d bytes of memory at address %s changed from:", - entry.u.mem.len, - print_core_address (arch, entry.u.mem.addr)); - for (int i = 0; i < entry.u.mem.len; i++) + mem.len, + print_core_address (arch, mem.addr)); + for (int i = 0; i < mem.len; i++) gdb_printf (" %02x", b[i]); gdb_printf ("\n"); break; From patchwork Fri May 15 16:37:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135077 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DA9CB40A00F8 for ; Fri, 15 May 2026 16:41:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DA9CB40A00F8 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=iVmOehxa 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 ESMTP id 38D4051A4327 for ; Fri, 15 May 2026 16:39:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 38D4051A4327 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 38D4051A4327 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863143; cv=none; b=YtX3mOgMjmn6XPVW1H5op+Mih22+OmNCZrEbBE8S6IXiV5k2js03/q0YxK/tbABZJWDrXwgJPE7NHFi2tDYWnBl2cuwlGYkssmKQ+kOchEL5QZQTwzh8hU6PufItB46zKlTQck4k04DNTUKQv3jxhAKZLTeDabwxj4eiZmhC4J8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863143; c=relaxed/simple; bh=ZW3KpMUj96h+gVg0RUMGW+l2xHRSV5oYtZ7IOCEHutQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Og/oi7SJVhV0r876iLIVzM9gehdd5ozkcqxtpDFZm9f6ExOOH+wJ4Y7kLET5aZwcNHqnmdKrL6+AoHOI1MFkbO6uthxVWF2fZmUjLHI8HF7oeUdD4vVEQ279tyFh4IbW0XnFfwFBE3sa4wmzVQFrKE/RjB5+zfhKv2i0uK4IFrE= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=iVmOehxa DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 38D4051A4327 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863142; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=yfThCC++HweG5nfHt57o6BlWmcTA4VoUaa02R+4x/+o=; b=iVmOehxapUclqUYzIfvs495jpNFQl7RcLxR4xGnE5rZ9dGV8Fvh740aCD0f84QBPFN30v+ kR1o9/TPVlTBmBjcMi5TCeKISyIXwKId5OwhoTRsT4XqAJX6XSuQDirsu/qWWBQgeD4H0B biCgAaXFQHJfbGE4Pj4tE3kl0CAU2vg= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-422-o8oK76ngNrCo6surRAaAqA-1; Fri, 15 May 2026 12:39:01 -0400 X-MC-Unique: o8oK76ngNrCo6surRAaAqA-1 X-Mimecast-MFC-AGG-ID: o8oK76ngNrCo6surRAaAqA_1778863140 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B7DD71956055 for ; Fri, 15 May 2026 16:39:00 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 81F8C19432BB; Fri, 15 May 2026 16:38:59 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v3 4/7] gdb/record: make record_full_history more c++-like Date: Fri, 15 May 2026 13:37:01 -0300 Message-ID: <20260515163706.3355686-5-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: nrnPLgNtUcWkhOyCqD96qGaYW6LaXf2zfPMViSIKQBM_1778863140 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.5 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_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Move some functions to being a method of record_full_history, instead of floating functions. Reviewed-by: Thiago Jung Bauermann Reviewed-By: Christina Schimpe --- gdb/record-full.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 24e94eaf5da..8cabd6e9438 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -388,6 +388,10 @@ struct record_full_instruction uint32_t insn_num; std::optional sigval; std::vector effects; + + /* Execute the full instruction. As a side effect, set + record_full_stop_reason. */ + void exec_insn (regcache *regcache); }; /* If true, query if PREC cannot record memory @@ -843,12 +847,9 @@ record_full_gdb_operation_disable_set (void) static enum target_stop_reason record_full_stop_reason = TARGET_STOPPED_BY_NO_REASON; -static inline void -record_full_exec_insn (regcache *regcache, - gdbarch *gdbarch, - record_full_instruction &insn) +void record_full_instruction::exec_insn (regcache *regcache) { - for (auto &entry : insn.effects) + for (auto &entry : effects) if (entry.execute (regcache)) record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; } @@ -1308,9 +1309,7 @@ record_full_wait_1 (struct target_ops *ops, break; } - record_full_exec_insn - (regcache, gdbarch, - record_full_list[record_full_next_insn]); + record_full_list[record_full_next_insn].exec_insn (regcache); /* step */ if (record_full_resume_step) @@ -2503,8 +2502,7 @@ record_full_base_target::save_record (const char *recfilename) /* Reverse execute to the begin of record list. */ for (int i = record_full_next_insn - 1; i >= 0; i--) - record_full_exec_insn (regcache, gdbarch, - record_full_list[i]); + record_full_list[i].exec_insn (regcache); /* Compute the size needed for the extra bfd section. */ save_size = 4; /* magic cookie */ @@ -2576,7 +2574,7 @@ record_full_base_target::save_record (const char *recfilename) } /* Execute entry. */ if (i < record_full_next_insn) - record_full_exec_insn (regcache, gdbarch, record_full_list[i]); + record_full_list[i].exec_insn (regcache); } unlink_file.keep (); @@ -2597,17 +2595,16 @@ record_full_goto_insn (size_t target_insn, scoped_restore restore_operation_disable = record_full_gdb_operation_disable_set (); regcache *regcache = get_thread_regcache (inferior_thread ()); - struct gdbarch *gdbarch = regcache->arch (); /* Assume everything is valid: we will hit the entry, and we will not hit the end of the recording. */ if (dir == EXEC_REVERSE) for (int i = record_full_next_insn; i > target_insn; i--) - record_full_exec_insn (regcache, gdbarch, record_full_list[i - 1]); + record_full_list[i-1].exec_insn (regcache); else for (int i = record_full_next_insn; i < target_insn; i++) - record_full_exec_insn (regcache, gdbarch, record_full_list[i]); + record_full_list[i].exec_insn (regcache); } /* Alias for "target record-full". */ From patchwork Fri May 15 16:37:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135075 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0A6CD40A00E9 for ; Fri, 15 May 2026 16:41:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0A6CD40A00E9 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=RjglvrJZ 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 ESMTP id 62A6A40A00CB for ; Fri, 15 May 2026 16:39:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 62A6A40A00CB Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 62A6A40A00CB Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863148; cv=none; b=WaE0HOlY4JogDV43ksPzNmA+f/SQlwdArYGEYQ2KpACU1uMbpFbL2k8+jdjf53ViYVPoN3IxOX5Hp+wNhWiuKuUuN2ehNGTveGfoEqecLOSE7BhQCJhkBU4ByxNdVdiEowXLZ2jRGWtHMYnkyVrdxvA3+MKUVjRPr7m5LRq5Kcc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863148; c=relaxed/simple; bh=g3JuEJyvIhMFF64W91JUXORyyRCuU7hMSHCJDD0zshU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=EFSV3tjtk3NtwWEkWCmnw1E4TcyEWK5byVcbfTCttxtNHiZhGNfr0KFWZJtfCD+tr+WMm2tsNLhv92ZuY2zeBUtrHv+XL3C84MdkhxhsTlDJxtdJuGSOfZWEDmrhEpghzNVeC0IrXse34WgFaxcAbu0B9uJc4qa1yep4ahGjcVk= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=RjglvrJZ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 62A6A40A00CB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863148; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DnWbE25PkSeVoozJ7u+wq9/wPOwutJticD6fdErAMSM=; b=RjglvrJZngmAHC1wHyBImsRYZ6/cj7tQgryyUOWvsAlllWXkG2eoObDkzRJAKDIZuSsCcI wjpCZFN/hzrAZUiIyten/PV2S/iw2qRW62u9CRdXCfQ4Fg/kn6Xtn5EiYmCIKtiOAHNOJF 8v/N1eXcOY5vMav8Cqfv/ETjmdHzowQ= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-360-I4Rvo_0VObm6DT2wwIjG5g-1; Fri, 15 May 2026 12:39:06 -0400 X-MC-Unique: I4Rvo_0VObm6DT2wwIjG5g-1 X-Mimecast-MFC-AGG-ID: I4Rvo_0VObm6DT2wwIjG5g_1778863145 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D62B1180056E for ; Fri, 15 May 2026 16:39:05 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4D5251955F2D; Fri, 15 May 2026 16:39:03 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v3 5/7] gdb/record: extract the PC to record_full_instruction Date: Fri, 15 May 2026 13:37:03 -0300 Message-ID: <20260515163706.3355686-7-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 0hTg1_USqSZrtd5q3w-vHPplZV0pRPGil-PKli_v1j0_1778863145 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.5 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_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 This commit makes it so the PC is not saved as part of the record_full_instruction effects, but rather gets a special location. That is because a couple of commands would really benefit from it being easy to find the PC (especially ones from record-btrace that's haven't been implemented to record-full yet, such as the ones in PR record/18059), while also possibly allowing for one fewer resizing of the effect vector (and saving an entire byte in the process). This commit also refactored record_full_read_entry_from_bfd and record_full_write_entry_to_bfd, to make them methods of record_full_reg_entry and record_full_mem_entry, and also creates similar methods for record_full_entry and record_full_instruction. These could be turned into constructors in a future step of c++ification, but it felt like too much change for a single commit. Reviewed-by: Thiago Jung Bauermann --- gdb/record-full.c | 386 ++++++++++++++++++++++++++++------------------ 1 file changed, 239 insertions(+), 147 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 8cabd6e9438..17696e07c0d 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -143,6 +143,14 @@ struct record_full_mem_entry DISABLE_COPY_AND_ASSIGN (record_full_mem_entry); + /* Create a mem_entry from a bfd file, when restoring a recording. */ + static record_full_mem_entry from_bfd (bfd *cbfd, asection* osec, + int *bfd_offset); + + /* Save this mem entry to a bfd file. */ + void to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, int *bfd_offset, + gdbarch *gdbarch); + gdb_byte *get_loc () { if (len > sizeof (u.buf)) @@ -252,6 +260,14 @@ struct record_full_reg_entry DISABLE_COPY_AND_ASSIGN (record_full_reg_entry); + /* Create a reg_entry from a bfd file, when restoring a recording. */ + static record_full_reg_entry from_bfd (bfd *cbfd, asection* osec, + int *bfd_offset); + + /* Save this reg entry to a bfd file. */ + void to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, int *bfd_offset, + gdbarch *gdbarch); + gdb_byte *get_loc () { if (len > sizeof (u.buf)) @@ -314,6 +330,13 @@ class record_full_entry DISABLE_COPY_AND_ASSIGN (record_full_entry); + /* Create a generic entry from a bfd file, when restoring a recording. */ + static void from_bfd (bfd *cbfd, asection* osec, int *bfd_offset); + + /* Save this entry to a bfd file. */ + void to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, int *bfd_offset, + gdbarch *gdbarch); + record_full_reg_entry& reg () { gdb_assert (type () == record_full_reg); @@ -374,6 +397,7 @@ class record_full_entry this one; * sigval: Whether the inferior received a signal while the following instruction was being recorded; + * pc: The Program Counter for where the instruction starts; * effects: A list of record_full_entry structures, each of which describing one effect that the instruction has on the inferior. @@ -388,10 +412,18 @@ struct record_full_instruction uint32_t insn_num; std::optional sigval; std::vector effects; + record_full_reg_entry pc; /* Execute the full instruction. As a side effect, set record_full_stop_reason. */ void exec_insn (regcache *regcache); + + /* Create a full recorded instruction from a bfd. */ + static void from_bfd (bfd *cbfd, asection* osec, int *bfd_offset); + + /* Save this instruction to a bfd file. */ + void to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, int *bfd_offset, + gdbarch *gdbarch); }; /* If true, query if PREC cannot record memory @@ -695,7 +727,10 @@ record_full_arch_list_add_reg (struct regcache *regcache, int regnum) regcache->cooked_read (regnum, rec.get_loc ()); - record_full_arch_list_add (rec); + if (regnum == gdbarch_pc_regnum (regcache->arch ())) + record_full_incomplete_instruction.pc = std::move (rec.reg ()); + else + record_full_arch_list_add (rec); return 0; } @@ -849,6 +884,7 @@ static enum target_stop_reason record_full_stop_reason void record_full_instruction::exec_insn (regcache *regcache) { + pc.execute (regcache); for (auto &entry : effects) if (entry.execute (regcache)) record_full_stop_reason = TARGET_STOPPED_BY_WATCHPOINT; @@ -2207,68 +2243,88 @@ netorder32 (uint32_t input) return ret; } -static void -record_full_read_entry_from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) +record_full_reg_entry +record_full_reg_entry::from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) { - uint8_t rectype; - uint32_t regnum, len; - uint64_t addr; + uint32_t regnum; regcache *cache = get_thread_regcache (inferior_thread ()); + /* Get register number to regnum. */ + bfdcore_read (cbfd, osec, ®num, sizeof (regnum), + bfd_offset); + regnum = netorder32 (regnum); + + record_full_reg_entry reg (cache->arch (), regnum); + + /* Get val. */ + bfdcore_read (cbfd, osec, reg.get_loc (), + reg.len, bfd_offset); + + if (record_debug) + gdb_printf (gdb_stdlog, + " Reading register %d (1 " + "plus %lu plus %d bytes)\n", + reg.num, + (unsigned long) sizeof (regnum), + reg.len); + return reg; + +} + +record_full_mem_entry +record_full_mem_entry::from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) +{ + uint32_t len; + uint64_t addr; + + /* Get len. */ + bfdcore_read (cbfd, osec, &len, sizeof (len), bfd_offset); + len = netorder32 (len); + + /* Get addr. */ + bfdcore_read (cbfd, osec, &addr, sizeof (addr), + bfd_offset); + addr = netorder64 (addr); + + record_full_mem_entry mem (addr, len); + + /* Get val. */ + bfdcore_read (cbfd, osec, mem.get_loc (), + len, bfd_offset); + + if (record_debug) + gdb_printf (gdb_stdlog, + " Reading memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", + paddress (get_current_arch (), + mem.addr), + (unsigned long) sizeof (addr), + (unsigned long) sizeof (len), + len); + + return mem; +} + +void +record_full_entry::from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) +{ + uint8_t rectype; + record_full_entry rec; + bfdcore_read (cbfd, osec, &rectype, sizeof (rectype), bfd_offset); switch (rectype) { case record_full_reg: /* reg */ { - /* Get register number to regnum. */ - bfdcore_read (cbfd, osec, ®num, sizeof (regnum), bfd_offset); - regnum = netorder32 (regnum); - - record_full_entry rec (record_full_reg, cache->arch (), regnum); - - /* Get val. */ - bfdcore_read (cbfd, osec, rec.get_loc (), - rec.reg ().len, bfd_offset); - - if (record_debug) - gdb_printf (gdb_stdlog, - " Reading register %d (1 " - "plus %lu plus %d bytes)\n", - rec.reg ().num, - (unsigned long) sizeof (regnum), - rec.reg ().len); - - record_full_arch_list_add (rec); + rec.entry = std::move (record_full_reg_entry::from_bfd + (cbfd, osec, bfd_offset)); break; } case record_full_mem: /* mem */ { - /* Get len. */ - bfdcore_read (cbfd, osec, &len, sizeof (len), bfd_offset); - len = netorder32 (len); - - /* Get addr. */ - bfdcore_read (cbfd, osec, &addr, sizeof (addr), - bfd_offset); - addr = netorder64 (addr); - - record_full_entry rec (record_full_mem, addr, len); - - /* Get val. */ - bfdcore_read (cbfd, osec, rec.get_loc (), len, bfd_offset); - - if (record_debug) - gdb_printf (gdb_stdlog, - " Reading memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (get_current_arch (), - rec.mem ().addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - len); - - record_full_arch_list_add (rec); + rec.entry = std::move (record_full_mem_entry::from_bfd + (cbfd, osec, bfd_offset)); break; } @@ -2279,6 +2335,39 @@ record_full_read_entry_from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) bfd_get_filename (cbfd))); break; } + record_full_arch_list_add (rec); +} + +void +record_full_instruction::from_bfd (bfd *cbfd, asection *osec, int *bfd_offset) +{ + uint32_t eff_count = 0; + uint8_t sigval; + uint32_t insn_num; + + /* First read the generic information for an instruction. */ + bfdcore_read (cbfd, osec, &sigval, sizeof (uint8_t), bfd_offset); + bfdcore_read (cbfd, osec, &eff_count, sizeof (uint32_t), + bfd_offset); + bfdcore_read (cbfd, osec, &insn_num, sizeof (uint32_t), + bfd_offset); + + record_full_incomplete_instruction.insn_num = netorder32 (insn_num); + if (sigval != GDB_SIGNAL_0) + record_full_incomplete_instruction.sigval = (gdb_signal) sigval; + + record_full_incomplete_instruction.pc + = record_full_reg_entry::from_bfd (cbfd, osec, bfd_offset); + + eff_count = netorder32 (eff_count); + + /* This deals with all the side effects. */ + while (eff_count > 0) + { + eff_count--; + + record_full_entry::from_bfd (cbfd, osec, bfd_offset); + } } /* Restore the execution log from core file CBFD. */ @@ -2325,30 +2414,8 @@ record_full_restore (struct bfd &cbfd) while (bfd_offset < osec_size) { record_full_reset_incomplete (); - uint32_t eff_count = 0; - uint8_t sigval; - uint32_t insn_num; - - /* First read the generic information for an instruction. */ - bfdcore_read (&cbfd, osec, &sigval, sizeof (uint8_t), &bfd_offset); - bfdcore_read (&cbfd, osec, &eff_count, sizeof (uint32_t), - &bfd_offset); - bfdcore_read (&cbfd, osec, &insn_num, sizeof (uint32_t), - &bfd_offset); - - record_full_incomplete_instruction.insn_num = netorder32 (insn_num); - if (sigval != GDB_SIGNAL_0) - record_full_incomplete_instruction.sigval = (gdb_signal) sigval; - eff_count = netorder32 (eff_count); - - /* This deals with all the side effects. */ - while (eff_count > 0) - { - eff_count--; - - record_full_read_entry_from_bfd (&cbfd, osec, &bfd_offset); - } + record_full_instruction::from_bfd (&cbfd, osec, &bfd_offset); record_full_save_instruction (); } @@ -2404,71 +2471,109 @@ cmd_record_full_restore (const char *args, int from_tty) record_full_open (nullptr, from_tty); } -static void -record_full_write_entry_to_bfd (record_full_entry &entry, - gdb_bfd_ref_ptr obfd, - asection *osec, int *bfd_offset, - gdbarch *gdbarch) +void +record_full_reg_entry::to_bfd (gdb_bfd_ref_ptr obfd, + asection *osec, int *bfd_offset, + gdbarch *gdbarch) +{ + uint32_t regnum; + + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing register %d (1 " + "plus %lu plus %d bytes)\n", + this->num, + (unsigned long) sizeof (regnum), + this->len); + + /* Write regnum. */ + regnum = netorder32 (this->num); + bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), bfd_offset); + + /* Write regval. */ + bfdcore_write (obfd.get (), osec, this->get_loc (), this->len, bfd_offset); +} + +void +record_full_mem_entry::to_bfd (gdb_bfd_ref_ptr obfd, + asection *osec, int *bfd_offset, + gdbarch *gdbarch) +{ + uint32_t len; + uint64_t addr; + + if (record_debug) + gdb_printf (gdb_stdlog, + " Writing memory %s (1 plus " + "%lu plus %lu plus %d bytes)\n", + paddress (gdbarch, this->addr), + (unsigned long) sizeof (addr), + (unsigned long) sizeof (len), + this->len); + + /* Write memlen. */ + len = netorder32 (this->len); + bfdcore_write (obfd.get (), osec, &len, sizeof (len), bfd_offset); + + /* Write memaddr. */ + addr = netorder64 (this->addr); + bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), bfd_offset); + + /* Write memval. */ + bfdcore_write (obfd.get (), osec, this->get_loc (), this->len, bfd_offset); +} + +void +record_full_entry::to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, + int *bfd_offset, gdbarch *gdbarch) { /* Save entry. */ uint8_t type; - uint32_t regnum, len; - uint64_t addr; - type = entry.type (); + type = this->type (); bfdcore_write (obfd.get (), osec, &type, sizeof (type), bfd_offset); switch (type) { case record_full_reg: /* reg */ - { - auto ® = entry.reg (); - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing register %d (1 " - "plus %lu plus %d bytes)\n", - reg.num, - (unsigned long) sizeof (regnum), - reg.len); - - /* Write regnum. */ - regnum = netorder32 (reg.num); - bfdcore_write (obfd.get (), osec, ®num, sizeof (regnum), bfd_offset); - - /* Write regval. */ - bfdcore_write (obfd.get (), osec, entry.get_loc (), reg.len, bfd_offset); - break; - } + reg ().to_bfd (obfd, osec, bfd_offset, gdbarch); + break; case record_full_mem: /* mem */ - { - auto &mem = entry.mem (); - if (record_debug) - gdb_printf (gdb_stdlog, - " Writing memory %s (1 plus " - "%lu plus %lu plus %d bytes)\n", - paddress (gdbarch, mem.addr), - (unsigned long) sizeof (addr), - (unsigned long) sizeof (len), - mem.len); - - /* Write memlen. */ - len = netorder32 (mem.len); - bfdcore_write (obfd.get (), osec, &len, sizeof (len), bfd_offset); - - /* Write memaddr. */ - addr = netorder64 (mem.addr); - bfdcore_write (obfd.get (), osec, &addr, sizeof (addr), bfd_offset); - - /* Write memval. */ - bfdcore_write (obfd.get (), osec, entry.get_loc (), mem.len, - bfd_offset); - break; - } + mem ().to_bfd (obfd, osec, bfd_offset, gdbarch); + break; } } +void +record_full_instruction::to_bfd (gdb_bfd_ref_ptr obfd, asection *osec, + int *bfd_offset, gdbarch *gdbarch) +{ + uint32_t eff_count = (uint32_t) this->effects.size (); + uint32_t insn_num = this->insn_num; + uint8_t sigval = (this->sigval.has_value ()) + ? this->sigval.value () + : GDB_SIGNAL_0; + + /* Signal. */ + bfdcore_write (obfd.get (), osec, &sigval, sizeof (sigval), bfd_offset); + eff_count = netorder32 (eff_count); + /* Number of effects. */ + bfdcore_write (obfd.get (), osec, &eff_count, sizeof (eff_count), + bfd_offset); + /* Instruction number. */ + bfdcore_write (obfd.get (), osec, &insn_num, sizeof (uint32_t), + bfd_offset); + + this->pc.to_bfd (obfd, osec, bfd_offset, gdbarch); + + for (auto &entry : this->effects) + { + entry.to_bfd (obfd, osec, bfd_offset, gdbarch); + } +} + /* Save the execution log to a file. We use a modified elf corefile format, with an extra section for our data. */ @@ -2510,6 +2615,7 @@ record_full_base_target::save_record (const char *recfilename) { /* Number of effects of an instruction. */ save_size += sizeof (uint32_t) + sizeof (uint8_t) + sizeof (uint32_t); + save_size += 4 + record_full_list[i].pc.len; for (auto &entry : record_full_list[i].effects) switch (entry.type ()) { @@ -2551,27 +2657,7 @@ record_full_base_target::save_record (const char *recfilename) record list. */ for (int i = 0; i < record_full_list.size (); i++) { - uint32_t eff_count = (uint32_t) record_full_list[i].effects.size (); - uint32_t insn_num = record_full_list[i].insn_num; - uint8_t sigval = (record_full_list[i].sigval.has_value ()) - ? record_full_list[i].sigval.value () - : GDB_SIGNAL_0; - - /* Signal. */ - bfdcore_write (obfd.get (), osec, &sigval, sizeof (sigval), &bfd_offset); - eff_count = netorder32 (eff_count); - /* Number of effects. */ - bfdcore_write (obfd.get (), osec, &eff_count, sizeof (eff_count), - &bfd_offset); - /* Instruction number. */ - bfdcore_write (obfd.get (), osec, &insn_num, sizeof (uint32_t), - &bfd_offset); - - for (auto &entry : record_full_list[i].effects) - { - record_full_write_entry_to_bfd (entry, obfd, osec, &bfd_offset, - gdbarch); - } + record_full_list[i].to_bfd (obfd, osec, &bfd_offset, gdbarch); /* Execute entry. */ if (i < record_full_next_insn) record_full_list[i].exec_insn (regcache); @@ -2648,6 +2734,9 @@ maintenance_print_record_instruction (const char *args, int from_tty) auto to_print = record_full_list.begin () + offset; gdbarch *arch = current_inferior ()->arch (); + struct value_print_options opts; + get_user_print_options (&opts); + opts.raw = true; for (auto &entry : to_print->effects) { @@ -2661,9 +2750,6 @@ maintenance_print_record_instruction (const char *args, int from_tty) entry.get_loc ()); gdb_printf ("Register %s changed: ", gdbarch_register_name (arch, entry.reg ().num)); - struct value_print_options opts; - get_user_print_options (&opts); - opts.raw = true; value_print (val, gdb_stdout, &opts); gdb_printf ("\n"); break; @@ -2682,6 +2768,12 @@ maintenance_print_record_instruction (const char *args, int from_tty) } } } + type *regtype = gdbarch_register_type (arch, to_print->pc.num); + value *val = value_from_contents (regtype, to_print->pc.get_loc ()); + gdb_printf ("Register %s changed: ", + gdbarch_register_name (arch, to_print->pc.num)); + value_print (val, gdb_stdout, &opts); + gdb_printf ("\n"); } INIT_GDB_FILE (record_full) From patchwork Fri May 15 16:37:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135076 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 60CA5409FC8B for ; Fri, 15 May 2026 16:41:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 60CA5409FC8B Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MgOwBAyX 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.129.124]) by sourceware.org (Postfix) with ESMTP id 15F464AB0F4B for ; Fri, 15 May 2026 16:39:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 15F464AB0F4B Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 15F464AB0F4B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863159; cv=none; b=n1F595mgHh6GT96gVtm6kwzVEcV16HanqD2r95uQXAZVRTCRlELei9C7CK6UX5qyx3A7SyWAlOJ+U4cnBDeT0pWMelV1aa7u63XQRpe8TAY2a7Vn2rYebgFn05y/ukeiO9pHr7yzPynXoZ9c4EYj7qy2x7UcN87bQlhil1+wu88= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863159; c=relaxed/simple; bh=0zwnpnWpJt5H93ms0TtavU4lyZ4bcZYxJtIOYqRQ1ng=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=WwW8zmowH+gxG5g6kThg9tuN5QDt+7ygHQiKquPmzaxzkThwTdm6+/4LlJBlrHZJI3BSH4osZbrGTqUYpU/5iCNuBzRISkO+bCTdToc9LAWN37Y3JnK4a9HQeLnVJhegpofFK8wj804opqScp0q9XXrmPhFRYE3D6VftFPPDxm8= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MgOwBAyX DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 15F464AB0F4B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863153; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/2HgKUTpQWge7upEpXh4FZY89Lxl9SjOw93DHMs9mC8=; b=MgOwBAyXWHglORW4prM/8t36tsaC6ueCJRMJxwScwx6xlhDDcbPwjkr0IU0agqaMw5h+/J z2I+Z7jVTCM4pXUNttJrSkoG0bs+rWXhTGQhCEy/tORCWsNcLUvkkaYt/kKXpBu0blCMuh ra/DXmHdwIjzR07vr7YIuRpQJVjRmIw= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-GmPaaCaaMuOVFho9OyRvTg-1; Fri, 15 May 2026 12:39:12 -0400 X-MC-Unique: GmPaaCaaMuOVFho9OyRvTg-1 X-Mimecast-MFC-AGG-ID: GmPaaCaaMuOVFho9OyRvTg_1778863151 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 36DA31800359 for ; Fri, 15 May 2026 16:39:11 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B3B78196B09E; Fri, 15 May 2026 16:39:09 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v3 6/6] gdb/record: rename record_full_list to record_full_log Date: Fri, 15 May 2026 13:37:05 -0300 Message-ID: <20260515163706.3355686-9-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: J3_qylYjB0hoo680wcFoS00pQ6cyR65tqKX5bg83E9E_1778863151 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.5 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_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Now that we no longer use a linked list to manage the history, the name "record_full_list" is no longer meaningful. This commit changes the name to record_full_log since it is the execution log. I decided to not say "record_full_execution_log" to avoid overly long lines when accessing it. Reviewed-By: Christina Schimpe --- gdb/record-full.c | 120 +++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 055d2c66346..3c63753d24e 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -76,7 +76,7 @@ #define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000 #define RECORD_FULL_IS_REPLAY \ - ((record_full_next_insn != record_full_list.size ()) \ + ((record_full_next_insn != record_full_log.size ()) \ || ::execution_direction == EXEC_REVERSE) #define RECORD_FULL_FILE_MAGIC_OLD netorder32(0x20091016) @@ -446,7 +446,7 @@ static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; /* The following variables are used for managing the history of executed instructions from the inferior. - record_full_list contains all instructions that were fully executed and + record_full_log contains all instructions that were fully executed and saved to the log, so that we can replay the execution. record_full_next_insn always points to the next instruction that would @@ -459,7 +459,7 @@ static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; happening. It is manipulated by the "arch list" functions for historical reasons. */ -static std::deque record_full_list; +static std::deque record_full_log; static record_full_instruction record_full_incomplete_instruction; static int record_full_next_insn; @@ -665,14 +665,14 @@ record_full_reset_history () record_full_insn_count = 0; record_full_next_insn = 0; - record_full_list.clear (); + record_full_log.clear (); } static void -record_full_list_release_following (int index) +record_full_log_release_following (int index) { - for (int i = record_full_list.size () - 1; i > index; i--) - record_full_list.pop_back (); + for (int i = record_full_log.size () - 1; i > index; i--) + record_full_log.pop_back (); /* Set the next instruction to be past the end of the log so we start recording if the user moves forward again. */ record_full_next_insn = index; @@ -686,7 +686,7 @@ record_full_save_instruction () ++record_full_insn_count; record_full_incomplete_instruction.insn_num = record_full_insn_count; record_full_incomplete_instruction.effects.shrink_to_fit (); - record_full_list.push_back (std::move (record_full_incomplete_instruction)); + record_full_log.push_back (std::move (record_full_incomplete_instruction)); record_full_next_insn++; record_full_reset_incomplete (); @@ -696,12 +696,12 @@ record_full_save_instruction () room for adding a new instruction at the end of the log. */ static void -record_full_list_release_first (void) +record_full_log_release_first (void) { - if (record_full_list.empty ()) + if (record_full_log.empty ()) return; - record_full_list.pop_front (); + record_full_log.pop_front (); --record_full_next_insn; } @@ -765,7 +765,7 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) static void record_full_check_insn_num (void) { - if (record_full_list.size () == record_full_insn_max_num) + if (record_full_log.size () == record_full_insn_max_num) { /* Ask user what to do. */ if (record_full_stop_at_limit) @@ -781,9 +781,9 @@ record_full_check_insn_num (void) /* Before inferior step (when GDB record the running message, inferior only can step), GDB will call this function to record the values to - record_full_list. This function will call gdbarch_process_record to + record_full_log. This function will call gdbarch_process_record to record the running message of inferior and set them to - record_full_arch_list, and add it to record_full_list. */ + record_full_arch_list, and add it to record_full_log. */ static void record_full_message (struct regcache *regcache, enum gdb_signal signal) @@ -821,8 +821,8 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) if we delivered it during the recording. Therefore we should record the signal during record_full_wait, not record_full_resume. */ - if (signal != GDB_SIGNAL_0 && !record_full_list.empty ()) - record_full_list[record_full_next_insn - 1].sigval = signal; + if (signal != GDB_SIGNAL_0 && !record_full_log.empty ()) + record_full_log[record_full_next_insn - 1].sigval = signal; if (signal == GDB_SIGNAL_0 || !gdbarch_process_record_signal_p (gdbarch)) @@ -847,8 +847,8 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } static bool @@ -1325,7 +1325,7 @@ record_full_wait_1 (struct target_ops *ops, if (execution_direction == EXEC_REVERSE) record_full_next_insn--; - /* Loop over the record_full_list, looking for the next place to + /* Loop over the record_full_log, looking for the next place to stop. */ do { @@ -1339,14 +1339,14 @@ record_full_wait_1 (struct target_ops *ops, break; } if (execution_direction != EXEC_REVERSE - && record_full_next_insn == record_full_list.size ()) + && record_full_next_insn == record_full_log.size ()) { /* Hit end of record log going forward. */ status->set_no_history (); break; } - record_full_list[record_full_next_insn].exec_insn (regcache); + record_full_log[record_full_next_insn].exec_insn (regcache); /* step */ if (record_full_resume_step) @@ -1380,7 +1380,7 @@ record_full_wait_1 (struct target_ops *ops, "watchpoint.\n"); continue_flag = 0; } - if (record_full_list[record_full_next_insn].sigval.has_value ()) + if (record_full_log[record_full_next_insn].sigval.has_value ()) continue_flag = 0; if (execution_direction == EXEC_REVERSE) @@ -1395,10 +1395,10 @@ record_full_wait_1 (struct target_ops *ops, gdb_assert (execution_direction == EXEC_REVERSE); record_full_next_insn = 0; } - else if (record_full_next_insn > record_full_list.size ()) + else if (record_full_next_insn > record_full_log.size ()) { gdb_assert (execution_direction == EXEC_FORWARD); - record_full_next_insn = record_full_list.size (); + record_full_next_insn = record_full_log.size (); } /* Reset the current instruction to point to the one to be replayed moving forward. */ @@ -1412,9 +1412,9 @@ record_full_wait_1 (struct target_ops *ops, ? record_full_next_insn - 1 : record_full_next_insn; if (record_full_get_sig) status->set_stopped (GDB_SIGNAL_INT); - else if (record_full_list[insn].sigval.has_value ()) + else if (record_full_log[insn].sigval.has_value ()) status->set_stopped - (record_full_list[insn].sigval.value ()); + (record_full_log[insn].sigval.value ()); else status->set_stopped (GDB_SIGNAL_TRAP); } @@ -1537,8 +1537,8 @@ record_full_registers_change (struct regcache *regcache, int regnum) } record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } /* "store_registers" method for process record target. */ @@ -1587,7 +1587,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno) } /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_next_insn); + record_full_log_release_following (record_full_next_insn); } record_full_registers_change (regcache, regno); @@ -1620,7 +1620,7 @@ record_full_target::xfer_partial (enum target_object object, error (_("Process record canceled the operation.")); /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_next_insn); + record_full_log_release_following (record_full_next_insn); } /* Check record_full_insn_num */ @@ -1639,8 +1639,8 @@ record_full_target::xfer_partial (enum target_object object, } record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } return this->beneath ()->xfer_partial (object, annex, readbuf, writebuf, @@ -1796,11 +1796,11 @@ record_full_base_target::get_bookmark (const char *args, int from_tty) { char *ret = NULL; - if (record_full_list.empty ()) + if (record_full_log.empty ()) return (gdb_byte *) ret; /* Return stringified form of instruction count. */ - ret = xstrdup (pulongest (record_full_list[record_full_next_insn].insn_num)); + ret = xstrdup (pulongest (record_full_log[record_full_next_insn].insn_num)); if (record_debug) { @@ -1862,16 +1862,16 @@ record_full_base_target::info_record () gdb_printf (_("Record mode:\n")); /* Do we have a log at all? */ - if (!record_full_list.empty ()) + if (!record_full_log.empty ()) { /* Display instruction number for first instruction in the log. */ gdb_printf (_("Lowest recorded instruction number is %u.\n"), - record_full_list[0].insn_num); + record_full_log[0].insn_num); /* If in replay mode, display where we are in the log. */ if (RECORD_FULL_IS_REPLAY) gdb_printf (_("Current instruction number is %u.\n"), - record_full_list[record_full_next_insn].insn_num); + record_full_log[record_full_next_insn].insn_num); /* Display instruction number for last instruction in the log. */ gdb_printf (_("Highest recorded instruction number is %s.\n"), @@ -1879,7 +1879,7 @@ record_full_base_target::info_record () /* Display log count. */ gdb_printf (_("Log contains %lu instructions.\n"), - (unsigned long int) record_full_list.size ()); + (unsigned long int) record_full_log.size ()); } else gdb_printf (_("No instructions have been logged.\n")); @@ -1928,14 +1928,14 @@ record_full_base_target::record_will_replay (ptid_t ptid, int dir) static void record_full_goto_entry (size_t target_insn) { - if (target_insn >= record_full_list.size ()) + if (target_insn >= record_full_log.size ()) error (_("Target insn not found.")); else if (target_insn == record_full_next_insn) error (_("Already at target insn.")); else if (target_insn > record_full_next_insn) { gdb_printf (_("Go forward to insn number %s\n"), - pulongest (record_full_list[target_insn].insn_num)); + pulongest (record_full_log[target_insn].insn_num)); record_full_goto_insn (target_insn, EXEC_FORWARD); } else @@ -1966,7 +1966,7 @@ record_full_base_target::goto_record_begin () void record_full_base_target::goto_record_end () { - record_full_goto_entry (record_full_list.size () - 1); + record_full_goto_entry (record_full_log.size () - 1); } /* The "goto_record" target method. */ @@ -2403,7 +2403,7 @@ record_full_restore (struct bfd &cbfd) int bfd_offset = 0; /* "record_full_restore" can only be called when record list is empty. */ - gdb_assert (record_full_list.empty ()); + gdb_assert (record_full_log.empty ()); if (record_debug) gdb_printf (gdb_stdlog, "Restoring recording from core file.\n"); @@ -2454,9 +2454,9 @@ record_full_restore (struct bfd &cbfd) } /* Update record_full_insn_max_num. */ - if (record_full_list.size () > record_full_insn_max_num) + if (record_full_log.size () > record_full_insn_max_num) { - record_full_insn_max_num = record_full_list.size (); + record_full_insn_max_num = record_full_log.size (); warning (_("Auto increase record/replay buffer limit to %u."), record_full_insn_max_num); } @@ -2634,16 +2634,16 @@ record_full_base_target::save_record (const char *recfilename) /* Reverse execute to the begin of record list. */ for (int i = record_full_next_insn - 1; i >= 0; i--) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); /* Compute the size needed for the extra bfd section. */ save_size = 4; /* magic cookie */ - for (int i = record_full_list.size () - 1; i >= 0; i--) + for (int i = record_full_log.size () - 1; i >= 0; i--) { /* Number of effects of an instruction. */ save_size += sizeof (uint32_t) + sizeof (uint8_t) + sizeof (uint32_t); - save_size += 4 + record_full_list[i].pc.len; - for (auto &entry : record_full_list[i].effects) + save_size += 4 + record_full_log[i].pc.len; + for (auto &entry : record_full_log[i].effects) switch (entry.type ()) { case record_full_reg: @@ -2682,12 +2682,12 @@ record_full_base_target::save_record (const char *recfilename) /* Save the entries to recfd and forward execute to the end of record list. */ - for (int i = 0; i < record_full_list.size (); i++) + for (int i = 0; i < record_full_log.size (); i++) { - record_full_list[i].to_bfd (obfd, osec, &bfd_offset, gdbarch); + record_full_log[i].to_bfd (obfd, osec, &bfd_offset, gdbarch); /* Execute entry. */ if (i < record_full_next_insn) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); } unlink_file.keep (); @@ -2714,10 +2714,10 @@ record_full_goto_insn (size_t target_insn, if (dir == EXEC_REVERSE) for (int i = record_full_next_insn; i > target_insn; i--) - record_full_list[i-1].exec_insn (regcache); + record_full_log[i-1].exec_insn (regcache); else for (int i = record_full_next_insn; i < target_insn; i++) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); } /* Alias for "target record-full". */ @@ -2732,10 +2732,10 @@ static void set_record_full_insn_max_num (const char *args, int from_tty, struct cmd_list_element *c) { - if (record_full_list.size () > record_full_insn_max_num) + if (record_full_log.size () > record_full_insn_max_num) { - while (record_full_list.size () > record_full_insn_max_num) - record_full_list_release_first (); + while (record_full_log.size () > record_full_insn_max_num) + record_full_log_release_first (); } } @@ -2744,21 +2744,21 @@ set_record_full_insn_max_num (const char *args, int from_tty, static void maintenance_print_record_instruction (const char *args, int from_tty) { - if (record_full_list.empty ()) + if (record_full_log.empty ()) error (_("Not enough recorded history")); int offset = record_full_next_insn - 1; /* Reduce the offset by 1 if the record_full_next_insn is after the end so that we show the last recorded instruction instead of crashing. */ - if (offset == record_full_list.size ()) + if (offset == record_full_log.size ()) offset--; if (args != nullptr) { offset += value_as_long (parse_and_eval (args)); - if (offset >= record_full_list.size () || offset < 0) + if (offset >= record_full_log.size () || offset < 0) error (_("Not enough recorded history")); } - auto to_print = record_full_list.begin () + offset; + auto to_print = record_full_log.begin () + offset; gdbarch *arch = current_inferior ()->arch (); struct value_print_options opts; From patchwork Fri May 15 16:37:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 135081 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E4CF94C900D6 for ; Fri, 15 May 2026 16:44:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E4CF94C900D6 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KSKEP7iz 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 ESMTP id 3105F4C31849 for ; Fri, 15 May 2026 16:39:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3105F4C31849 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3105F4C31849 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863156; cv=none; b=wboJ1E9yI0Hi3+ZwJGpMY7WXwapCBkbYz/DH43sxGx69f5NjuCEiTEPHssJl0/lAaHtEBAX5qWQvak8VBQOYeV7SQRcCa/22A9GxDS5hB8NYRLKMr203N21Nosl8AiP2d4FJ0KJ2xkESl2Mhguwsq0R9X04gGFqv8MEXO8rvSsg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778863156; c=relaxed/simple; bh=0zwnpnWpJt5H93ms0TtavU4lyZ4bcZYxJtIOYqRQ1ng=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=UeCQAMPUIUJwGSHin1UhjYk4vaG7UWy4VJijulc/8xW9wSLHIJLUB1ui0YY0mFm1+ipWMn2TJ8FMzNMVQnd2D6gLXSD0VCyPMJ4djnFbjyjN+R6DRGBYq4pScHSoRhzfJOxKb4MQDGHSqs94KJPmikFTHBdG98WIm7wTGD0+PcQ= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KSKEP7iz DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3105F4C31849 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1778863155; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/2HgKUTpQWge7upEpXh4FZY89Lxl9SjOw93DHMs9mC8=; b=KSKEP7izH+g6XiLY1h9LGw+lwL7oFPCPVf/DtgMnJ8bAR+Th06TLumd1S9btoMEQ4TCtlo yZoGlGlCwX7hHD+HQGPailmNrhbjR6idUfIr02iW4kL8aW8HjL/VRHWl2B7u1293V70w5y bV+vS4vnwaV3u9ZEXzIYMJMJ+v1BHtU= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-572-Z98JyIrYO3WSqK6X2NhfpA-1; Fri, 15 May 2026 12:39:14 -0400 X-MC-Unique: Z98JyIrYO3WSqK6X2NhfpA-1 X-Mimecast-MFC-AGG-ID: Z98JyIrYO3WSqK6X2NhfpA_1778863153 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 42856195605C for ; Fri, 15 May 2026 16:39:13 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.96.134.23]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C05241955F2D; Fri, 15 May 2026 16:39:11 +0000 (UTC) From: Guinevere Larsen To: gdb-patches@sourceware.org Cc: Guinevere Larsen Subject: [PATCH v3 7/7] gdb/record: rename record_full_list to record_full_log Date: Fri, 15 May 2026 13:37:06 -0300 Message-ID: <20260515163706.3355686-10-guinevere@redhat.com> In-Reply-To: <20260515163706.3355686-1-guinevere@redhat.com> References: <20260515163706.3355686-1-guinevere@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: pQ5WyS4vXRc2-FJnrzpDccTDGE_ieI-CLZBpcV5iEDE_1778863153 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.6 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_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on 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 Now that we no longer use a linked list to manage the history, the name "record_full_list" is no longer meaningful. This commit changes the name to record_full_log since it is the execution log. I decided to not say "record_full_execution_log" to avoid overly long lines when accessing it. Reviewed-by: Thiago Jung Bauermann --- gdb/record-full.c | 120 +++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/gdb/record-full.c b/gdb/record-full.c index 055d2c66346..3c63753d24e 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -76,7 +76,7 @@ #define DEFAULT_RECORD_FULL_INSN_MAX_NUM 200000 #define RECORD_FULL_IS_REPLAY \ - ((record_full_next_insn != record_full_list.size ()) \ + ((record_full_next_insn != record_full_log.size ()) \ || ::execution_direction == EXEC_REVERSE) #define RECORD_FULL_FILE_MAGIC_OLD netorder32(0x20091016) @@ -446,7 +446,7 @@ static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; /* The following variables are used for managing the history of executed instructions from the inferior. - record_full_list contains all instructions that were fully executed and + record_full_log contains all instructions that were fully executed and saved to the log, so that we can replay the execution. record_full_next_insn always points to the next instruction that would @@ -459,7 +459,7 @@ static struct record_full_core_buf_entry *record_full_core_buf_list = NULL; happening. It is manipulated by the "arch list" functions for historical reasons. */ -static std::deque record_full_list; +static std::deque record_full_log; static record_full_instruction record_full_incomplete_instruction; static int record_full_next_insn; @@ -665,14 +665,14 @@ record_full_reset_history () record_full_insn_count = 0; record_full_next_insn = 0; - record_full_list.clear (); + record_full_log.clear (); } static void -record_full_list_release_following (int index) +record_full_log_release_following (int index) { - for (int i = record_full_list.size () - 1; i > index; i--) - record_full_list.pop_back (); + for (int i = record_full_log.size () - 1; i > index; i--) + record_full_log.pop_back (); /* Set the next instruction to be past the end of the log so we start recording if the user moves forward again. */ record_full_next_insn = index; @@ -686,7 +686,7 @@ record_full_save_instruction () ++record_full_insn_count; record_full_incomplete_instruction.insn_num = record_full_insn_count; record_full_incomplete_instruction.effects.shrink_to_fit (); - record_full_list.push_back (std::move (record_full_incomplete_instruction)); + record_full_log.push_back (std::move (record_full_incomplete_instruction)); record_full_next_insn++; record_full_reset_incomplete (); @@ -696,12 +696,12 @@ record_full_save_instruction () room for adding a new instruction at the end of the log. */ static void -record_full_list_release_first (void) +record_full_log_release_first (void) { - if (record_full_list.empty ()) + if (record_full_log.empty ()) return; - record_full_list.pop_front (); + record_full_log.pop_front (); --record_full_next_insn; } @@ -765,7 +765,7 @@ record_full_arch_list_add_mem (CORE_ADDR addr, int len) static void record_full_check_insn_num (void) { - if (record_full_list.size () == record_full_insn_max_num) + if (record_full_log.size () == record_full_insn_max_num) { /* Ask user what to do. */ if (record_full_stop_at_limit) @@ -781,9 +781,9 @@ record_full_check_insn_num (void) /* Before inferior step (when GDB record the running message, inferior only can step), GDB will call this function to record the values to - record_full_list. This function will call gdbarch_process_record to + record_full_log. This function will call gdbarch_process_record to record the running message of inferior and set them to - record_full_arch_list, and add it to record_full_list. */ + record_full_arch_list, and add it to record_full_log. */ static void record_full_message (struct regcache *regcache, enum gdb_signal signal) @@ -821,8 +821,8 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) if we delivered it during the recording. Therefore we should record the signal during record_full_wait, not record_full_resume. */ - if (signal != GDB_SIGNAL_0 && !record_full_list.empty ()) - record_full_list[record_full_next_insn - 1].sigval = signal; + if (signal != GDB_SIGNAL_0 && !record_full_log.empty ()) + record_full_log[record_full_next_insn - 1].sigval = signal; if (signal == GDB_SIGNAL_0 || !gdbarch_process_record_signal_p (gdbarch)) @@ -847,8 +847,8 @@ record_full_message (struct regcache *regcache, enum gdb_signal signal) record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } static bool @@ -1325,7 +1325,7 @@ record_full_wait_1 (struct target_ops *ops, if (execution_direction == EXEC_REVERSE) record_full_next_insn--; - /* Loop over the record_full_list, looking for the next place to + /* Loop over the record_full_log, looking for the next place to stop. */ do { @@ -1339,14 +1339,14 @@ record_full_wait_1 (struct target_ops *ops, break; } if (execution_direction != EXEC_REVERSE - && record_full_next_insn == record_full_list.size ()) + && record_full_next_insn == record_full_log.size ()) { /* Hit end of record log going forward. */ status->set_no_history (); break; } - record_full_list[record_full_next_insn].exec_insn (regcache); + record_full_log[record_full_next_insn].exec_insn (regcache); /* step */ if (record_full_resume_step) @@ -1380,7 +1380,7 @@ record_full_wait_1 (struct target_ops *ops, "watchpoint.\n"); continue_flag = 0; } - if (record_full_list[record_full_next_insn].sigval.has_value ()) + if (record_full_log[record_full_next_insn].sigval.has_value ()) continue_flag = 0; if (execution_direction == EXEC_REVERSE) @@ -1395,10 +1395,10 @@ record_full_wait_1 (struct target_ops *ops, gdb_assert (execution_direction == EXEC_REVERSE); record_full_next_insn = 0; } - else if (record_full_next_insn > record_full_list.size ()) + else if (record_full_next_insn > record_full_log.size ()) { gdb_assert (execution_direction == EXEC_FORWARD); - record_full_next_insn = record_full_list.size (); + record_full_next_insn = record_full_log.size (); } /* Reset the current instruction to point to the one to be replayed moving forward. */ @@ -1412,9 +1412,9 @@ record_full_wait_1 (struct target_ops *ops, ? record_full_next_insn - 1 : record_full_next_insn; if (record_full_get_sig) status->set_stopped (GDB_SIGNAL_INT); - else if (record_full_list[insn].sigval.has_value ()) + else if (record_full_log[insn].sigval.has_value ()) status->set_stopped - (record_full_list[insn].sigval.value ()); + (record_full_log[insn].sigval.value ()); else status->set_stopped (GDB_SIGNAL_TRAP); } @@ -1537,8 +1537,8 @@ record_full_registers_change (struct regcache *regcache, int regnum) } record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } /* "store_registers" method for process record target. */ @@ -1587,7 +1587,7 @@ record_full_target::store_registers (struct regcache *regcache, int regno) } /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_next_insn); + record_full_log_release_following (record_full_next_insn); } record_full_registers_change (regcache, regno); @@ -1620,7 +1620,7 @@ record_full_target::xfer_partial (enum target_object object, error (_("Process record canceled the operation.")); /* Destroy the record from here forward. */ - record_full_list_release_following (record_full_next_insn); + record_full_log_release_following (record_full_next_insn); } /* Check record_full_insn_num */ @@ -1639,8 +1639,8 @@ record_full_target::xfer_partial (enum target_object object, } record_full_save_instruction (); - if (record_full_list.size () == record_full_insn_max_num) - record_full_list_release_first (); + if (record_full_log.size () == record_full_insn_max_num) + record_full_log_release_first (); } return this->beneath ()->xfer_partial (object, annex, readbuf, writebuf, @@ -1796,11 +1796,11 @@ record_full_base_target::get_bookmark (const char *args, int from_tty) { char *ret = NULL; - if (record_full_list.empty ()) + if (record_full_log.empty ()) return (gdb_byte *) ret; /* Return stringified form of instruction count. */ - ret = xstrdup (pulongest (record_full_list[record_full_next_insn].insn_num)); + ret = xstrdup (pulongest (record_full_log[record_full_next_insn].insn_num)); if (record_debug) { @@ -1862,16 +1862,16 @@ record_full_base_target::info_record () gdb_printf (_("Record mode:\n")); /* Do we have a log at all? */ - if (!record_full_list.empty ()) + if (!record_full_log.empty ()) { /* Display instruction number for first instruction in the log. */ gdb_printf (_("Lowest recorded instruction number is %u.\n"), - record_full_list[0].insn_num); + record_full_log[0].insn_num); /* If in replay mode, display where we are in the log. */ if (RECORD_FULL_IS_REPLAY) gdb_printf (_("Current instruction number is %u.\n"), - record_full_list[record_full_next_insn].insn_num); + record_full_log[record_full_next_insn].insn_num); /* Display instruction number for last instruction in the log. */ gdb_printf (_("Highest recorded instruction number is %s.\n"), @@ -1879,7 +1879,7 @@ record_full_base_target::info_record () /* Display log count. */ gdb_printf (_("Log contains %lu instructions.\n"), - (unsigned long int) record_full_list.size ()); + (unsigned long int) record_full_log.size ()); } else gdb_printf (_("No instructions have been logged.\n")); @@ -1928,14 +1928,14 @@ record_full_base_target::record_will_replay (ptid_t ptid, int dir) static void record_full_goto_entry (size_t target_insn) { - if (target_insn >= record_full_list.size ()) + if (target_insn >= record_full_log.size ()) error (_("Target insn not found.")); else if (target_insn == record_full_next_insn) error (_("Already at target insn.")); else if (target_insn > record_full_next_insn) { gdb_printf (_("Go forward to insn number %s\n"), - pulongest (record_full_list[target_insn].insn_num)); + pulongest (record_full_log[target_insn].insn_num)); record_full_goto_insn (target_insn, EXEC_FORWARD); } else @@ -1966,7 +1966,7 @@ record_full_base_target::goto_record_begin () void record_full_base_target::goto_record_end () { - record_full_goto_entry (record_full_list.size () - 1); + record_full_goto_entry (record_full_log.size () - 1); } /* The "goto_record" target method. */ @@ -2403,7 +2403,7 @@ record_full_restore (struct bfd &cbfd) int bfd_offset = 0; /* "record_full_restore" can only be called when record list is empty. */ - gdb_assert (record_full_list.empty ()); + gdb_assert (record_full_log.empty ()); if (record_debug) gdb_printf (gdb_stdlog, "Restoring recording from core file.\n"); @@ -2454,9 +2454,9 @@ record_full_restore (struct bfd &cbfd) } /* Update record_full_insn_max_num. */ - if (record_full_list.size () > record_full_insn_max_num) + if (record_full_log.size () > record_full_insn_max_num) { - record_full_insn_max_num = record_full_list.size (); + record_full_insn_max_num = record_full_log.size (); warning (_("Auto increase record/replay buffer limit to %u."), record_full_insn_max_num); } @@ -2634,16 +2634,16 @@ record_full_base_target::save_record (const char *recfilename) /* Reverse execute to the begin of record list. */ for (int i = record_full_next_insn - 1; i >= 0; i--) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); /* Compute the size needed for the extra bfd section. */ save_size = 4; /* magic cookie */ - for (int i = record_full_list.size () - 1; i >= 0; i--) + for (int i = record_full_log.size () - 1; i >= 0; i--) { /* Number of effects of an instruction. */ save_size += sizeof (uint32_t) + sizeof (uint8_t) + sizeof (uint32_t); - save_size += 4 + record_full_list[i].pc.len; - for (auto &entry : record_full_list[i].effects) + save_size += 4 + record_full_log[i].pc.len; + for (auto &entry : record_full_log[i].effects) switch (entry.type ()) { case record_full_reg: @@ -2682,12 +2682,12 @@ record_full_base_target::save_record (const char *recfilename) /* Save the entries to recfd and forward execute to the end of record list. */ - for (int i = 0; i < record_full_list.size (); i++) + for (int i = 0; i < record_full_log.size (); i++) { - record_full_list[i].to_bfd (obfd, osec, &bfd_offset, gdbarch); + record_full_log[i].to_bfd (obfd, osec, &bfd_offset, gdbarch); /* Execute entry. */ if (i < record_full_next_insn) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); } unlink_file.keep (); @@ -2714,10 +2714,10 @@ record_full_goto_insn (size_t target_insn, if (dir == EXEC_REVERSE) for (int i = record_full_next_insn; i > target_insn; i--) - record_full_list[i-1].exec_insn (regcache); + record_full_log[i-1].exec_insn (regcache); else for (int i = record_full_next_insn; i < target_insn; i++) - record_full_list[i].exec_insn (regcache); + record_full_log[i].exec_insn (regcache); } /* Alias for "target record-full". */ @@ -2732,10 +2732,10 @@ static void set_record_full_insn_max_num (const char *args, int from_tty, struct cmd_list_element *c) { - if (record_full_list.size () > record_full_insn_max_num) + if (record_full_log.size () > record_full_insn_max_num) { - while (record_full_list.size () > record_full_insn_max_num) - record_full_list_release_first (); + while (record_full_log.size () > record_full_insn_max_num) + record_full_log_release_first (); } } @@ -2744,21 +2744,21 @@ set_record_full_insn_max_num (const char *args, int from_tty, static void maintenance_print_record_instruction (const char *args, int from_tty) { - if (record_full_list.empty ()) + if (record_full_log.empty ()) error (_("Not enough recorded history")); int offset = record_full_next_insn - 1; /* Reduce the offset by 1 if the record_full_next_insn is after the end so that we show the last recorded instruction instead of crashing. */ - if (offset == record_full_list.size ()) + if (offset == record_full_log.size ()) offset--; if (args != nullptr) { offset += value_as_long (parse_and_eval (args)); - if (offset >= record_full_list.size () || offset < 0) + if (offset >= record_full_log.size () || offset < 0) error (_("Not enough recorded history")); } - auto to_print = record_full_list.begin () + offset; + auto to_print = record_full_log.begin () + offset; gdbarch *arch = current_inferior ()->arch (); struct value_print_options opts;