From patchwork Wed Dec 7 13:50:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guinevere Larsen X-Patchwork-Id: 61660 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C3D59388A022 for ; Wed, 7 Dec 2022 13:52:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C3D59388A022 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1670421129; bh=XCQyqRHq5bGCmIXLXlr3PmosAKTqndmTuRkNPFjrHGs=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=XljCbIcuuN4wscbGFMCkoBMhFqgIJ9dEFqaQScJjZ7LaNvYqOd/F+w7qHnyyG53w3 FJvaG51b8T+riabqRcKjKisrtjfJAEOpXvDjMAPkwpT7fczPCClyB1NZAO8QBzjtv7 dXJhGcEQ78zHW3RjPvJmCTp0bq3spNpS9FK2Xchw= 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 ESMTPS id 0F429383A0EB for ; Wed, 7 Dec 2022 13:51:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0F429383A0EB Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-569-__6F5svsN-WZFCAHLiPD-g-1; Wed, 07 Dec 2022 08:51:41 -0500 X-MC-Unique: __6F5svsN-WZFCAHLiPD-g-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 420F8802804 for ; Wed, 7 Dec 2022 13:51:41 +0000 (UTC) Received: from fedora.redhat.com (ovpn-194-124.brq.redhat.com [10.40.194.124]) by smtp.corp.redhat.com (Postfix) with ESMTPS id BEE042166B29; Wed, 7 Dec 2022 13:51:40 +0000 (UTC) To: gdb-patches@sourceware.org Cc: Bruno Larsen Subject: [PATCH] gdb: add 'maintenance print record-instruction' command Date: Wed, 7 Dec 2022 14:50:00 +0100 Message-Id: <20221207135000.1344331-1-blarsen@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Bruno Larsen via Gdb-patches From: Guinevere Larsen Reply-To: Bruno Larsen Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" While chasing some reverse debugging bugs, I found myself wondering what was recorded by GDB to undo and redo a certain instruction. This commit implements a simple way of printing that information. --- gdb/NEWS | 6 ++++ gdb/doc/gdb.texinfo | 8 +++++ gdb/record-full.c | 81 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/gdb/NEWS b/gdb/NEWS index c4ccfcc9e32..d6ce6bf86a0 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -103,6 +103,12 @@ * New commands +maintenance print record-instruction [ N ] + Print the recorded information for a given instruction. If N is not given + prints how GDB would undo the last instruction executed. If N is negative, + prints how GDB would undo the N-th previous instruction, and if N is + positive, it prints how GDB will redo the N-th following instruction. + maintenance set ignore-prologue-end-flag on|off maintenance show ignore-prologue-end-flag This setting, which is off by default, controls whether GDB ignores the diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 5b566669975..807af351e79 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40531,6 +40531,14 @@ that symbol is described. The type chain produced by this command is a recursive definition of the data type as stored in @value{GDBN}'s data structures, including its flags and contained types. +@kindex maint print record-instruction +@item maint print record-instruction +@itemx maint print record-instruction @var{N} +@cindex print how GDB recorded a given instruction. If N is not positive +number, it prints the values stored by the inferior before the N-th previous +instruction was exectued. If N is positive, print the values after the N-th +following instruction is executed. If N is not given, 0 is assumed. + @kindex maint selftest @cindex self tests @item maint selftest @r{[}-verbose@r{]} @r{[}@var{filter}@r{]} diff --git a/gdb/record-full.c b/gdb/record-full.c index 48b92281fe6..47cdf75eea4 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -2764,6 +2764,79 @@ set_record_full_insn_max_num (const char *args, int from_tty, } } +/* Implement the 'maintenance print record-instruction' command. */ + +static void +maintenance_print_record_instruction (const char *args, int from_tty) +{ + struct record_full_entry* to_print = record_full_list; + + 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 0. */ + while (to_print->next && offset > 0) + { + to_print = to_print->next; + if (!to_print->type) + offset --; + } + if (offset != 0) + error (_("Not enough recorded history")); + } + else + { + while (to_print->prev && offset < 0) + { + to_print = to_print->prev; + if (!to_print->type) + offset++; + } + if (offset != 0) + error (_("Not enough recorded history")); + } + } + gdb_assert (to_print != nullptr); + + /* Go back to the start of the instruction. */ + while (to_print->prev && to_print->prev->type) + to_print = to_print->prev; + + while (to_print->type) + { + switch (to_print->type) + { + case record_full_reg: + { + gdb_byte* b = record_full_get_loc (to_print); + gdb_printf ("Register %%%s changed:", + gdbarch_register_name (target_gdbarch (), + to_print->u.reg.num)); + for (int i = 0; i < to_print->u.reg.len; i++) + gdb_printf (" %02x",b[i]); + gdb_printf ("\n"); + break; + } + case record_full_mem: + { + gdb_byte* b = record_full_get_loc (to_print); + gdb_printf ("%d bytes of memory at address %s changed from:", + to_print->u.mem.len, + print_core_address (target_gdbarch (), + to_print->u.mem.addr)); + for (int i = 0; i < to_print->u.mem.len; i++) + gdb_printf (" %02x",b[i]); + gdb_printf ("\n"); + break; + } + } + to_print = to_print->next; + } +} + void _initialize_record_full (); void _initialize_record_full () @@ -2868,4 +2941,12 @@ When ON, query if PREC cannot record memory change of next instruction."), c = add_alias_cmd ("memory-query", record_full_memory_query_cmds.show, no_class, 1,&show_record_cmdlist); deprecate_cmd (c, "show record full memory-query"); + + add_cmd ("record-instruction", class_maintenance, + maintenance_print_record_instruction, + _("\ +Print a recorded instruction.\nIf no argument is provided, print the last \ +instruction recorded.\nIf a negative argument is given, prints how the nth \ +previous instruction will be undone.\nIf a positive argument is given, prints \ +how the nth following instruction will be redone."), &maintenanceprintlist); }