From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id wTMuOCKasWrpuC4AWB0awg (envelope-from ) for ; Mon, 21 Sep 2026 16:57:06 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=xgEK83KZ; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=H5H+Suw7; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=FLSUTK6b; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=S8pwqfJD; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id E2A161E01F; Mon, 21 Sep 2026 16:57:06 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id E39011E01F for ; Mon, 21 Sep 2026 16:57:05 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B0D254BA903A for ; Mon, 21 Sep 2026 20:57:04 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B0D254BA903A Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=xgEK83KZ; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=H5H+Suw7; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=FLSUTK6b; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=S8pwqfJD Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2a07:de40:b251:101:10:150:64:2]) by sourceware.org (Postfix) with ESMTPS id CD25B4BA9014 for ; Mon, 21 Sep 2026 20:56:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CD25B4BA9014 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CD25B4BA9014 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2a07:de40:b251:101:10:150:64:2 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1790024169; cv=none; b=kwiznDGSgxPJIDqyeXh/tK2Ad5vwN4OcSZATFixWQd80CbOqciY2wtVupyR7wdziB7Pk5RLFJysEh8AmD+jk2CF3xqTlaKn+SZpu3ypcBxhq5KtavWWUJGPQ3Hy/r5KkOLNTCki4tinGWacXK61fmEagM7jJH+5Buzc4/HMU6oY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1790024169; c=relaxed/simple; bh=sBHN4fsSQ1h4vHYwmLqQOpne8/d4aAh0JtlTPf0ySmA=; h=DKIM-Signature:DKIM-Signature:DKIM-Signature:DKIM-Signature:From: To:Subject:Date:Message-ID:MIME-Version; b=klg3oq0/RG0WiOcRkAPFU3cGzjM9i98AhsqWnbo1c7f+24mXY/l2QWvvLiGPggBFUpqoSsjew621AnfJeqwDpTTOgtNmN7qQxV687uImq4u2lfEUUahm/yYzILAAlQKyHgTqbnA24qW1zqzTC1fKlF3ffYSKSoNHWffCXJfVDBM= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=xgEK83KZ; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=H5H+Suw7; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=FLSUTK6b; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=S8pwqfJD DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CD25B4BA9014 Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 90C8E1FE25 for ; Mon, 21 Sep 2026 20:55:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1790024163; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=78kjHo+kAKN/CJ+qdo372mcMgI1mTdFvQcweAKgyvGQ=; b=xgEK83KZO+OXejQIHZWlavnjar4sq3zXDPaPct9bui9h7ooDTVYoAkKgrVLsv12RzIIBNW cQLuzKfGcEQgduXnf4B4NFQdnmXxDl+bBQnJGnCHf2HGCuveihsZ4L5fnjgwqAgT8i/RAe r9UOZRq3AhYzcdoT8MMjdlM2u700Y1A= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1790024163; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=78kjHo+kAKN/CJ+qdo372mcMgI1mTdFvQcweAKgyvGQ=; b=H5H+Suw7woYZIgsbui+pMs4eFCCd9nQPNQfn7+y8malDNi1aslyIMxMAUFB6ahF7S/oxk8 DNtCAdgMYHS2LsAQ== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1790024159; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=78kjHo+kAKN/CJ+qdo372mcMgI1mTdFvQcweAKgyvGQ=; b=FLSUTK6bABTB9A3W2zJQNLJ9tXT2LeUXmcvyFK49mLmBZ1jKqnxWIJDPpJEGyY2dUOTPAD Mt5DdssyF8IWbWukveQmcuhpfu/xQz45ENxJzFvB8wvMxmUEhoOy4mPsuWrCYo3Lq/tuFi oY8Xo7CFGAIP+vihTfo2mQuw5IFE5/U= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1790024159; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=78kjHo+kAKN/CJ+qdo372mcMgI1mTdFvQcweAKgyvGQ=; b=S8pwqfJDCw/OWjs3nhwwJ0bJn0C3KcT/DIoyxUY2WnPOfba5X+zIArIFKO0fzV3juOU9MZ PGMqIzyLSic4V8Aw== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id D47C0139EA for ; Mon, 21 Sep 2026 20:55:58 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id 7SRYDN6ZsWo9UQAAD6G6ig:T5 (envelope-from ) for ; Mon, 21 Sep 2026 20:55:58 +0000 From: Tom de Vries To: gdb-patches@sourceware.org Subject: [PATCH v3 4/5] [gdb] Handle sections when disassembling Date: Mon, 21 Sep 2026 22:55:56 +0200 Message-ID: <20260921205557.2706300-5-tdevries@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260921205557.2706300-1-tdevries@suse.de> References: <20260921205557.2706300-1-tdevries@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spamd-Result: default: False [-2.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-0.993]; MIME_GOOD(-0.10)[text/plain]; ARC_NA(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; RCVD_VIA_SMTP_AUTH(0.00)[]; MIME_TRACE(0.00)[0:+]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; PREVIOUSLY_DELIVERED(0.00)[gdb-patches@sourceware.org]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:mid,imap1.dmz-prg2.suse.org:helo]; RCVD_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_ALL(0.00)[]; TO_DN_NONE(0.00)[]; RCVD_TLS_ALL(0.00)[] 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~public-inbox=simark.ca@sourceware.org Consider the following session: ... $ gdb -q -batch a.out -ex start -ex "disassemble _init,0x0000000000401030" ... Dump of assembler code from 0x401000 to 0x401030: ... 0x000000000040101a <_init+26>: ret 0x000000000040101b: add %al,(%rax) 0x000000000040101d: add %al,(%rax) 0x000000000040101f: add %bh,%bh 0x0000000000401021: xor $0x2fca,%eax 0x0000000000401026: jmp *0x2fcc(%rip) 0x000000000040102c: nopl 0x0(%rax) End of assembler dump. ... If disassemble with objdump instead, we get: ... Disassembly of section .init: 0000000000401000 <_init>: ... 40101a: c3 ret Disassembly of section .plt: 0000000000401020 : 401020: ff 35 ca 2f 00 00 push 0x2fca(%rip) 401026: ff 25 cc 2f 00 00 jmp *0x2fcc(%rip) 40102c: 0f 1f 40 00 nopl 0x0(%rax) ... Note the xor vs push. So gdb: - first disassembles the .init section - then disassembles the section hole in between .init and .plt - interprets the first byte of .plt as the last byte of an instruction starting in the section hole - continues disassembling at .plt+1 instead of .plt+0 Fix this in gdb_disassembly by making it section-aware, and not disassembling across a section change, getting us instead: ... 0x000000000040101a <_init+26>: ret 0x000000000040101b: add %al,(%rax) 0x000000000040101d: add %al,(%rax) 0x000000000040101f: add %bh,%bh 0x0000000000401020: push 0x2fca(%rip) # 0x403ff0 0x0000000000401026: jmp *0x2fcc(%rip) # 0x403ff8 0x000000000040102c: nopl 0x0(%rax) ... Likewise in tui_disassemble. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34617 --- gdb/disasm.c | 72 ++++++++++++++++++++++++++++++------- gdb/tui/tui-disasm.c | 85 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 125 insertions(+), 32 deletions(-) diff --git a/gdb/disasm.c b/gdb/disasm.c index 01361fe4323..9e8334b065e 100644 --- a/gdb/disasm.c +++ b/gdb/disasm.c @@ -34,6 +34,7 @@ #include "cli/cli-style.h" #include "objfiles.h" #include "inferior.h" +#include "addrmap.h" /* Disassemble functions. FIXME: We should get rid of all the duplicate code in gdb that does @@ -524,7 +525,7 @@ dump_insns (struct gdbarch *gdbarch, N.B. This view is deprecated. */ -static void +static int do_mixed_source_and_assembly_deprecated (struct gdbarch *gdbarch, struct ui_out *uiout, struct symtab *symtab, @@ -669,6 +670,8 @@ do_mixed_source_and_assembly_deprecated if (how_many >= 0 && num_displayed >= how_many) break; } + + return num_displayed; } /* The idea here is to present a source-O-centric view of a @@ -676,7 +679,7 @@ do_mixed_source_and_assembly_deprecated in source order, with (possibly) out of order assembly immediately following. */ -static void +static int do_mixed_source_and_assembly (struct gdbarch *gdbarch, struct ui_out *uiout, struct symtab *main_symtab, @@ -906,16 +909,18 @@ do_mixed_source_and_assembly (struct gdbarch *gdbarch, last_symtab = sal.symtab; last_line = sal.line; } + + return num_displayed; } -static void +static int do_assembly_only (struct gdbarch *gdbarch, struct ui_out *uiout, CORE_ADDR low, CORE_ADDR high, int how_many, gdb_disassembly_flags flags) { ui_out_emit_list list_emitter (uiout, "asm_insns"); - dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL); + return dump_insns (gdbarch, uiout, low, high, how_many, flags, NULL); } /* Combine implicit and user disassembler options and return them @@ -1141,10 +1146,12 @@ gdb_disassembler::print_insn (CORE_ADDR memaddr, return length; } -void -gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, - gdb_disassembly_flags flags, int how_many, - CORE_ADDR low, CORE_ADDR high) +/* Helper function for gdb_disassembly. */ + +static int +gdb_disassembly_1 (struct gdbarch *gdbarch, struct ui_out *uiout, + gdb_disassembly_flags flags, int how_many, + CORE_ADDR low, CORE_ADDR high) { struct symtab *symtab; int nlines = -1; @@ -1155,19 +1162,58 @@ gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, if (symtab != NULL && symtab->linetable () != NULL) nlines = symtab->linetable ()->nitems; + int num_displayed = 0; if (!(flags & (DISASSEMBLY_SOURCE_DEPRECATED | DISASSEMBLY_SOURCE)) || nlines <= 0) - do_assembly_only (gdbarch, uiout, low, high, how_many, flags); + num_displayed + = do_assembly_only (gdbarch, uiout, low, high, how_many, flags); else if (flags & DISASSEMBLY_SOURCE) - do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high, - how_many, flags); + num_displayed + = do_mixed_source_and_assembly (gdbarch, uiout, symtab, low, high, + how_many, flags); else if (flags & DISASSEMBLY_SOURCE_DEPRECATED) - do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab, - low, high, how_many, flags); + num_displayed + = do_mixed_source_and_assembly_deprecated (gdbarch, uiout, symtab, + low, high, how_many, flags); gdb_flush (gdb_stdout); + return num_displayed; +} + +void +gdb_disassembly (struct gdbarch *gdbarch, struct ui_out *uiout, + gdb_disassembly_flags flags, int how_many, + CORE_ADDR low, CORE_ADDR high) +{ + std::unique_ptr map = section_addrmap (); + bool update_how_many = how_many != -1; + + while (low < high) + { + CORE_ADDR tmp_high = high; + + CORE_ADDR range_high; + map->find (low, nullptr, &range_high); + + /* Don't disassemble past a section change. */ + if (range_high != (CORE_ADDR)-1) + tmp_high = std::min (tmp_high, range_high + 1); + + int res + = gdb_disassembly_1 (gdbarch, uiout, flags, how_many, low, + tmp_high); + + if (update_how_many) + { + how_many -= res; + if (how_many <= 0) + break; + } + + low = tmp_high; + } } /* Print the instruction at address MEMADDR in debugged memory, diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c index 1a1866003dd..26afc4bd978 100644 --- a/gdb/tui/tui-disasm.c +++ b/gdb/tui/tui-disasm.c @@ -38,6 +38,7 @@ #include "tui/tui-location.h" #include "gdbsupport/selftest.h" #include "inferior.h" +#include "addrmap.h" struct tui_asm_line { @@ -80,23 +81,13 @@ len_without_escapes (const std::string &str) return len; } -/* Function to disassemble up to COUNT instructions starting from address - PC into the ASM_LINES vector (which will be emptied of any previous - contents). Return the address after the last disassembled instruction. - When ADDR_SIZE is non-null then place the maximum size of an address and - label into the value pointed to by ADDR_SIZE, and set the addr_size - field on each item in ASM_LINES, otherwise the addr_size fields within - ASM_LINES are undefined. +/* Helper function for tui_disassemble. */ - It is worth noting that ASM_LINES might not have COUNT entries when this - function returns. If the disassembly is truncated for some other - reason, for example, we hit invalid memory, then ASM_LINES can have - fewer entries than requested. */ static CORE_ADDR -tui_disassemble (struct gdbarch *gdbarch, - std::vector &asm_lines, - CORE_ADDR pc, int count, - size_t *addr_size = nullptr) +tui_disassemble_1 (struct gdbarch *gdbarch, + std::vector &asm_lines, CORE_ADDR pc, + std::optional high_pc, int count, + size_t *addr_size) { bool term_out = disassembler_styling && gdb_stdout->can_emit_style_escape (); string_file gdb_dis_out (term_out); @@ -104,20 +95,29 @@ tui_disassemble (struct gdbarch *gdbarch, ? (decltype (stream))&null_stream : (decltype (stream))&gdb_dis_out); - /* Must start with an empty list. */ - asm_lines.clear (); - /* Now construct each line. */ for (int i = 0; i < count; ++i) { tui_asm_line tal; + if (high_pc.has_value () && pc >= *high_pc) + break; + /* Save the instruction address. */ tal.addr = pc; try { - pc += gdb_print_insn (gdbarch, pc, stream, NULL); + int len = gdb_print_insn (gdbarch, pc, stream, NULL); + CORE_ADDR next_pc = pc + len; + if (high_pc.has_value () && next_pc > *high_pc) + { + /* Instruction spans high_pc. */ + tal.insn = "(bad)"; + next_pc = *high_pc; + } + + pc = next_pc; } catch (const gdb_exception_error &except) { @@ -153,6 +153,53 @@ tui_disassemble (struct gdbarch *gdbarch, return pc; } +/* Function to disassemble up to COUNT instructions starting from address + PC into the ASM_LINES vector (which will be emptied of any previous + contents). Return the address after the last disassembled instruction. + When ADDR_SIZE is non-null then place the maximum size of an address and + label into the value pointed to by ADDR_SIZE, and set the addr_size + field on each item in ASM_LINES, otherwise the addr_size fields within + ASM_LINES are undefined. + + It is worth noting that ASM_LINES might not have COUNT entries when this + function returns. If the disassembly is truncated for some other + reason, for example, we hit invalid memory, then ASM_LINES can have + fewer entries than requested. */ + +static CORE_ADDR +tui_disassemble (struct gdbarch *gdbarch, + std::vector &asm_lines, + CORE_ADDR pc, int count, + size_t *addr_size = nullptr) +{ + std::unique_ptr map = section_addrmap (); + + /* Must start with an empty list. */ + asm_lines.clear (); + + while (count > 0) + { + CORE_ADDR range_high; + map->find (pc, nullptr, &range_high); + + /* Don't disassemble past a section change. */ + std::optional high_pc; + if (range_high != (CORE_ADDR)-1) + high_pc = range_high + 1; + + int prev_nr_lines = asm_lines.size (); + pc = tui_disassemble_1 (gdbarch, asm_lines, pc, high_pc, count, + addr_size); + int nr_lines = asm_lines.size () - prev_nr_lines; + if (nr_lines == 0) + break; + + count -= nr_lines; + } + + return pc; +} + /* Look backward from ADDR for an address from which we can start disassembling, this needs to be something we can be reasonably confident will fall on an instruction boundary. We use msymbol -- 2.51.0