From patchwork Thu Feb 23 15:46:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 65522 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 6DEE03858284 for ; Thu, 23 Feb 2023 15:47:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6DEE03858284 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1677167254; bh=vbNxPaj5ZoKxkSuVhOvzm1o9SCSzqcQN6u0F/F4zjXw=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=uNbfMLi+X5M/SWovPJ+L/rki4DVNO7IsCHGe22y+eRTDUNwnUnmvedeH6GEhqAcEV 9/ujJg/kI6PUzLyD4BtQOjdF9DT6bnyAFthULCYuYOXdr17aafcE8+wyQfg7j+foot Qwm+9chVXQAEgYUR2IEry7r4KfY71HRT9ePnxAR0= 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 EFC1B385B507 for ; Thu, 23 Feb 2023 15:47:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EFC1B385B507 Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-413-46RUHMomNhSFwd1SPJ-H4A-1; Thu, 23 Feb 2023 10:47:02 -0500 X-MC-Unique: 46RUHMomNhSFwd1SPJ-H4A-1 Received: by mail-wr1-f71.google.com with SMTP id d14-20020adfa34e000000b002bfc062eaa8so2633116wrb.20 for ; Thu, 23 Feb 2023 07:47:02 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vbNxPaj5ZoKxkSuVhOvzm1o9SCSzqcQN6u0F/F4zjXw=; b=zWub5W97fumSJ7yGzB93mcEYFVsuAoZ0Xu0WfOWcMn/VtucDv952ucQFMu5fWpiOnz mMBmrJFgqbZn9CPM/yQex6KRWZy2qinjCkHlSljy/vsZSMyTnSB8E0Q58p/Ysx2iD8mM 0bwLel7eOWEmyvUItynt4rQFNh1GEWrIcAlW0o0Bb9NaCMTgNZR3ckPcAe+b4pv9jGgU tkDcFyHxIDIJNiDA0Rl8AwlzE2icGsO4YIp/cQ/jhoyEofXeDH6IO7sTDcb44dOT+7XL ncyj+Fs38ahXMucON9pV05hQUXoJlPETY+9hIBhvOVn1XYWmL82RWhyicVYeB9mic9Nw Vagg== X-Gm-Message-State: AO0yUKXcCcGPrXdL8mEHeVQLAd9Ng8xjWcnIXzk0zByycbRTGTMUtRrl gl/XuIeXAanQbQumaeXIr+aEaPsGjvG0dlxNO9h4glaUTHwGqSXi9SEeRqwCQ1VyQnWKgmb/1xl xDQI+lSTMbDpp1b0yjgUAEHC4uvn4ENg9h+qlSRZvqoDTMFdn3QmKrIpx/toyaMZrVLgV8hcWo4 15r3Q= X-Received: by 2002:a05:600c:329b:b0:3e2:12a2:ecdc with SMTP id t27-20020a05600c329b00b003e212a2ecdcmr9089731wmp.25.1677167221042; Thu, 23 Feb 2023 07:47:01 -0800 (PST) X-Google-Smtp-Source: AK7set+evZnhJE9d/pbBZI91vbYGYwrBj8ddLAiR+knZ2fA+FrziQrIOkZnY3I2fr567iX6kNHfrUQ== X-Received: by 2002:a05:600c:329b:b0:3e2:12a2:ecdc with SMTP id t27-20020a05600c329b00b003e212a2ecdcmr9089713wmp.25.1677167220616; Thu, 23 Feb 2023 07:47:00 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id v25-20020a5d5919000000b002c551f7d452sm10085455wrd.98.2023.02.23.07.47.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Feb 2023 07:47:00 -0800 (PST) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb: more debug output for displaced stepping Date: Thu, 23 Feb 2023 15:46:52 +0000 Message-Id: <87c9768d27c6412603915d6bd846aed0b7239446.1677167018.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" While investigating a displaced stepping issue I wanted an easy way to see what GDB thought the original instruction was, and what instruction GDB replaced that with when performing the displaced step. We do print out the address that is being stepped, so I can track down the original instruction. And we do print out the bytes of the new instruction, so I can figure out what the replacement instruction was, but it's not really easy. In this commit, within displaced_step_buffers::prepare, I add new debug output which disassembles both the original instruction, and the replacement instruction, and prints both these instructions, along with the bytes that make these instructions, to the debug output. This new debug improved on some debug that was already present in infrun.c, however, the old infrun.c debug (a) didn't actually disassemble the instruction, it just printed the bytes, and (b) there was an assumption that all instructions are 4-bytes long, which clearly isn't correct. I think it makes more sense to have all this debug in the displaced-stepping.c file, so I've removed the infrun.c code, and added my new debug in displaced-stepping.c. Here's an example of what the output looks like on x86-64 (this is with 'set debug displaced on'). The two interesting lines contain the strings 'original insn' and 'replacement insn': (gdb) step [displaced] displaced_step_prepare_throw: displaced-stepping 2073893.2073893.0 now [displaced] prepare: selected buffer at 0x401052 [displaced] prepare: saved 0x401052: 1e fa 31 ed 49 89 d1 5e 48 89 e2 48 83 e4 f0 50 [displaced] prepare: original insn 0x401030: ff 25 e2 2f 00 00 jmp *0x2fe2(%rip) # 0x404018 [displaced] fixup_riprel: %rip-relative addressing used. [displaced] fixup_riprel: using temp reg 2, old value 0x7ffff7f8a578, new value 0x401036 [displaced] amd64_displaced_step_copy_insn: copy 0x401030->0x401052: ff a1 e2 2f 00 00 68 00 00 00 00 e9 e0 ff ff ff [displaced] prepare: replacement insn 0x401052: ff a1 e2 2f 00 00 jmp *0x2fe2(%rcx) [displaced] displaced_step_prepare_throw: prepared successfully thread=2073893.2073893.0, original_pc=0x401030, displaced_pc=0x401052 [displaced] finish: restored 2073893.2073893.0 0x401052 [displaced] amd64_displaced_step_fixup: fixup (0x401030, 0x401052), insn = 0xff 0xa1 ... [displaced] amd64_displaced_step_fixup: restoring reg 2 to 0x7ffff7f8a578 0x00007ffff7e402c0 in puts () from /lib64/libc.so.6 (gdb) One final note. For many targets that support displaced stepping (in fact all targets except ARM) the replacement instruction is always a single instruction. But on ARM the replacement could actually be a series of instructions. The debug code tries to handle this by disassembling the entire displaced stepping buffer. Obviously this might actually print more than is necessary, but there's (currently) no easy way to know how many instructions to disassemble; that knowledge is all locked in the architecture specific code. Still I don't think it really hurts, if someone is looking at this debug then hopefully they known what to expect. --- gdb/displaced-stepping.c | 72 ++++++++++++++++++++++++++++++++++++++++ gdb/displaced-stepping.h | 3 ++ gdb/infrun.c | 35 ------------------- gdb/infrun.h | 3 -- 4 files changed, 75 insertions(+), 38 deletions(-) diff --git a/gdb/displaced-stepping.c b/gdb/displaced-stepping.c index 06b32a80f6a..7c9610ee728 100644 --- a/gdb/displaced-stepping.c +++ b/gdb/displaced-stepping.c @@ -28,6 +28,7 @@ #include "inferior.h" #include "regcache.h" #include "target/target.h" +#include "disasm.h" /* Default destructor for displaced_step_copy_insn_closure. */ @@ -43,6 +44,24 @@ show_debug_displaced (struct ui_file *file, int from_tty, gdb_printf (file, _("Displace stepping debugging is %s.\n"), value); } +/* See displaced-stepping.h. */ + +std::string +displaced_step_dump_bytes (const gdb_byte *buf, size_t len) +{ + std::string ret; + + for (size_t i = 0; i < len; i++) + { + if (i == 0) + ret += string_printf ("%02x", buf[i]); + else + ret += string_printf (" %02x", buf[i]); + } + + return ret; +} + displaced_step_prepare_status displaced_step_buffers::prepare (thread_info *thread, CORE_ADDR &displaced_pc) { @@ -125,6 +144,26 @@ displaced_step_buffers::prepare (thread_info *thread, CORE_ADDR &displaced_pc) displaced_step_dump_bytes (buffer->saved_copy.data (), len).c_str ()); + /* Display the instruction we are going to copy. */ + if (debug_displaced) + { + string_file tmp_stream; + int dislen = gdb_print_insn (arch, buffer->original_pc, &tmp_stream, + nullptr); + + gdb::byte_vector insn_buf (dislen); + read_memory (buffer->original_pc, insn_buf.data (), insn_buf.size ()); + + std::string insn_bytes + = displaced_step_dump_bytes (insn_buf.data (), insn_buf.size ()); + /* Extra spaces at the start of this debug line ensure alignment with + the 'replacement insn' line below. */ + displaced_debug_printf (" original insn %s: %s\t%s", + paddress (arch, buffer->original_pc), + insn_bytes.c_str (), + tmp_stream.string ().c_str ()); + } + /* Save this in a local variable first, so it's released if code below throws. */ displaced_step_copy_insn_closure_up copy_insn_closure @@ -139,6 +178,39 @@ displaced_step_buffers::prepare (thread_info *thread, CORE_ADDR &displaced_pc) return DISPLACED_STEP_PREPARE_STATUS_CANT; } + /* Display the new displaced instruction(s). */ + if (debug_displaced) + { + string_file tmp_stream; + CORE_ADDR addr = buffer->addr; + + /* If displaced stepping is going to use h/w single step then we know + that the replacement instruction can only be a single instruction, + in that case set the end address at the next byte. + + Otherwise the displaced stepping copy instruction routine could + have generated multiple instructions, and all we know is that they + must fit within the LEN bytes of the buffer. */ + CORE_ADDR end + = addr + (gdbarch_displaced_step_hw_singlestep (arch) ? 1 : len); + + while (addr < end) + { + int dislen = gdb_print_insn (arch, addr, &tmp_stream, nullptr); + + gdb::byte_vector insn_buf (dislen); + read_memory (buffer->addr, insn_buf.data (), insn_buf.size ()); + + std::string insn_bytes + = displaced_step_dump_bytes (insn_buf.data (), insn_buf.size ()); + std::string insn_str = tmp_stream.release (); + displaced_debug_printf ("replacement insn %s: %s\t%s", + paddress (arch, addr), insn_bytes.c_str (), + insn_str.c_str ()); + addr += dislen; + } + } + /* This marks the buffer as being in use. */ buffer->current_thread = thread; diff --git a/gdb/displaced-stepping.h b/gdb/displaced-stepping.h index e154927ad92..b3c5cdb1109 100644 --- a/gdb/displaced-stepping.h +++ b/gdb/displaced-stepping.h @@ -207,4 +207,7 @@ struct displaced_step_buffers std::vector m_buffers; }; +/* Dump LEN bytes at BUF in hex to a string and return it. */ +extern std::string displaced_step_dump_bytes (const gdb_byte *buf, size_t len); + #endif /* DISPLACED_STEPPING_H */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 3629db0443a..0867d86cd78 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1655,24 +1655,6 @@ displaced_step_reset (displaced_step_thread_state *displaced) using displaced_step_reset_cleanup = FORWARD_SCOPE_EXIT (displaced_step_reset); -/* See infrun.h. */ - -std::string -displaced_step_dump_bytes (const gdb_byte *buf, size_t len) -{ - std::string ret; - - for (size_t i = 0; i < len; i++) - { - if (i == 0) - ret += string_printf ("%02x", buf[i]); - else - ret += string_printf (" %02x", buf[i]); - } - - return ret; -} - /* Prepare to single-step, using displaced stepping. Note that we cannot use displaced stepping when we have a signal to @@ -2614,23 +2596,6 @@ resume_1 (enum gdb_signal sig) step = false; } - if (debug_displaced - && tp->control.trap_expected - && use_displaced_stepping (tp) - && !step_over_info_valid_p ()) - { - struct regcache *resume_regcache = get_thread_regcache (tp); - struct gdbarch *resume_gdbarch = resume_regcache->arch (); - CORE_ADDR actual_pc = regcache_read_pc (resume_regcache); - gdb_byte buf[4]; - - read_memory (actual_pc, buf, sizeof (buf)); - displaced_debug_printf ("run %s: %s", - paddress (resume_gdbarch, actual_pc), - displaced_step_dump_bytes - (buf, sizeof (buf)).c_str ()); - } - if (tp->control.may_range_step) { /* If we're resuming a thread with the PC out of the step diff --git a/gdb/infrun.h b/gdb/infrun.h index 43fd1b44f5a..419beb20ddb 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -263,9 +263,6 @@ extern void update_signals_program_target (void); $_exitsignal. */ extern void clear_exit_convenience_vars (void); -/* Dump LEN bytes at BUF in hex to a string and return it. */ -extern std::string displaced_step_dump_bytes (const gdb_byte *buf, size_t len); - extern void update_observer_mode (void); extern void signal_catch_update (const unsigned int *);