From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id aQ3aLZq5jmks3jgAWB0awg (envelope-from ) for ; Fri, 13 Feb 2026 00:41:46 -0500 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=LGI4DFpb; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id B5E661E089; Fri, 13 Feb 2026 00:41:46 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.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,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 690661E089 for ; Fri, 13 Feb 2026 00:41:45 -0500 (EST) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 78DD24B9DB69 for ; Fri, 13 Feb 2026 05:41:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 78DD24B9DB69 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=LGI4DFpb Received: from smtp.polymtl.ca (smtp.polymtl.ca [132.207.4.11]) by sourceware.org (Postfix) with ESMTPS id 67CD14B9DB49 for ; Fri, 13 Feb 2026 05:39:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 67CD14B9DB49 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=polymtl.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=polymtl.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 67CD14B9DB49 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=132.207.4.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770961162; cv=none; b=Te+Zy9MAqNRoSw9aDHX47Z3h3ALo0PmuKErxyWl4mA0nW5bkOdjQaQLR9FPcuSw1OV91mLjnIHzHjcIX5R2jwjDZTV8dChJjUel++0u5vf1ymYLShBNINPJvox/WqEiyyU2rb6e9x2gm8v9GLnOpEXdVJGpmJjTM/YREtKnhHmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1770961162; c=relaxed/simple; bh=BpXNy3LE2lLHCezIURvx07txDMx3/sziB583PUKcycU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=IHAI0m5cUvuXEVq5i92QMiooFksD2Py9714ADm/rIi1VkkPiFubk1/6AgCjkQBhKLAspOnNI+GY5s3+2Xs7r594OyFnQBiaiQ68ELuN3n3jkXOdDs4/L7Au2/CdsZh0dSfvDHS1yAHueuG1BjaZj5HuatZG47XCBcyhaBtxZi3M= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 67CD14B9DB49 Received: from simark.ca (simark.ca [158.69.221.121]) (authenticated bits=0) by smtp.polymtl.ca (8.14.7/8.14.7) with ESMTP id 61D5dE3h014801 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 13 Feb 2026 00:39:19 -0500 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.polymtl.ca 61D5dE3h014801 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=polymtl.ca; s=oct2025; t=1770961160; bh=FadwkYQbDJW7BULB6HBJYOMLsVraotkCkZ4Wt5mQRKA=; h=From:To:Cc:Subject:Date:From; b=LGI4DFpb9xP7svlwEOjFxwWrMbbOh9lZoLWeqkzkOZHFb5rVx4hQ6vyBU6qeIt0W0 ZMiDhpLU4Wcz2RwA9LlJarqm2Gl9nUJU3sFQkrRUmsxuExU4s4Y3bBsRRSCWnTGVdy Pev/kwJ/LWXkLAy5WZgVGKzlumNP8/Glbn15Q3ZaODy6ao0+la8dHosepuFVRF5KD8 3MU89njqpQ2GJSazWV4MvopVh6P//lPnQizKjN6d2/ts019SCiz/PSyRV/MrT9DwTM am2SUPMRbuhiLtz9hGEm7Va31vveQ1bgYHSs0aXAhV9TyAwuO0AKGBHLU7RN1HaE+9 XCucz5/T108Ig== Received: by simark.ca (Postfix) id 657871E089; Fri, 13 Feb 2026 00:39:13 -0500 (EST) From: simon.marchi@polymtl.ca To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH 1/4] gdb/elfread: add debug output for GNU ifunc resolution Date: Fri, 13 Feb 2026 00:38:48 -0500 Message-ID: <20260213053912.3520505-1-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Poly-FromMTA: (simark.ca [158.69.221.121]) at Fri, 13 Feb 2026 05:39:14 +0000 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 From: Simon Marchi Add some debug prints throughout the ifunc resolution code, to be able to better understand what GDB does. Add the new "set debug gnu-ifunc" knob to control it. Add the debug_prefixed_printf_cond_func macro to implement gnu_ifunc_debug_printf_func, that takes an explicit function name. This is needed to avoid showing "operator()" as the function name in the debug message. Here is a sample session with the new debug output enabled. (gdb) b the_function [gnu-ifunc] elf_gnu_ifunc_resolve_name: resolving name "the_function" [gnu-ifunc] elf_gnu_ifunc_resolve_by_cache: resolving "the_function" by cache [gnu-ifunc] elf_gnu_ifunc_resolve_by_cache: cache miss for "the_function" [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: resolving "the_function" by GOT [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: GOT entry "the_function@got.plt" points to 0x7ffff7fb7036 [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fb7036 [gnu-ifunc] elf_gnu_ifunc_record_cache: minimal symbol "the_function@plt" at 0x7ffff7fb7030 does not match addr 0x7ffff7fb7036, not caching [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: GOT entry "the_function@got.plt" points to 0x7ffff7fb2036 [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fb2036 [gnu-ifunc] elf_gnu_ifunc_record_cache: minimal symbol "the_function@plt" at 0x7ffff7fb2030 does not match addr 0x7ffff7fb2036, not caching [gnu-ifunc] elf_gnu_ifunc_resolve_by_got: failed to resolve "the_function" by GOT [gnu-ifunc] elf_gnu_ifunc_resolve_name: failed to resolve name "the_function" Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7fa80e9 (gdb) c Continuing. [gnu-ifunc] elf_gnu_ifunc_resolver_stop: stop on resolver for "the_function" [gnu-ifunc] elf_gnu_ifunc_resolver_stop: created resolver return breakpoint at 0x7ffff7fd7186 [gnu-ifunc] elf_gnu_ifunc_resolver_return_stop: stop on resolver return [gnu-ifunc] elf_gnu_ifunc_resolver_return_stop: resolver for "the_function" returned resolved address=0x7ffff7fad0e9, resolved pc=0x7ffff7fad0e9 [gnu-ifunc] elf_gnu_ifunc_record_cache: recording cache entry for "the_function" at 0x7ffff7fad0e9 [gnu-ifunc] elf_gnu_ifunc_record_cache: cached "the_function" -> 0x7ffff7fad0e9 in objfile /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/ifunc-resolver/libimpl.so Breakpoint 2, the_function_impl_0 (caller_id=1) at /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/ifunc-resolver-libimpl.c:25 25 the_function_last_caller_id = caller_id; /* break-in-impl */ Change-Id: I64f667e3457feaedfe9bb530de58faaf22545fa5 --- gdb/NEWS | 4 ++ gdb/doc/gdb.texinfo | 6 +++ gdb/elfread.c | 110 +++++++++++++++++++++++++++++++++++--- gdbsupport/common-debug.h | 9 ++++ 4 files changed, 123 insertions(+), 6 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index fa6e7ca61219..1957e63eae44 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -85,6 +85,10 @@ maintenance test-remote-args ARGS Test splitting and joining of inferior arguments ARGS as they would be split and joined when being passed to a remote target. +set debug gnu-ifunc on|off +show debug gnu-ifunc + Turn on or off debug messages related to GNU ifunc resolution. + set progress-bars enabled on|off show progress-bars enabled Allows the progress bars, used when debuginfod is downloading diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 5169be1965c5..c614e93b812e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -29331,6 +29331,12 @@ default is off. Displays the current state of displaying @value{GDBN} frame debugging info. +@cindex GNU ifunc debug messages +@item set debug gnu-ifunc +Turn on or off debugging messages related to GNU ifunc resolution. +@item show debug gnu-ifunc +Show the current state of GNU ifunc resolution debugging messages. + @item set debug gnu-nat @cindex @sc{gnu}/Hurd debug messages Turn on or off debugging messages from the @sc{gnu}/Hurd debug support. diff --git a/gdb/elfread.c b/gdb/elfread.c index 722f21bf7753..61dd8ad260ba 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -47,6 +47,23 @@ /* Whether ctf should always be read, or only if no dwarf is present. */ static bool always_read_ctf; +/* Value of the 'set debug gnu-ifunc' configuration variable. */ +static bool debug_gnu_ifunc; + +static void +show_debug_gnu_ifunc (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + gdb_printf (file, _("gnu-ifunc debugging is %s.\n"), value); +} + +#define gnu_ifunc_debug_printf(fmt, ...) \ + debug_prefixed_printf_cond (debug_gnu_ifunc, "gnu-ifunc", fmt, ##__VA_ARGS__) + +#define gnu_ifunc_debug_printf_func(func, fmt, ...) \ + debug_prefixed_printf_cond_func (debug_gnu_ifunc, "gnu-ifunc", func, fmt, \ + ##__VA_ARGS__) + /* The struct elfinfo is available only during ELF symbol table and psymtab reading. It is destroyed at the completion of psymtab-reading. It's local to elf_symfile_read. */ @@ -695,11 +712,28 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr) struct elf_gnu_ifunc_cache entry_local, *entry_p; void **slot; + gnu_ifunc_debug_printf ("recording cache entry for \"%s\" at %s", + name, paddress (current_inferior ()->arch (), addr)); + bound_minimal_symbol msym = lookup_minimal_symbol_by_pc (addr); if (msym.minsym == NULL) - return 0; + { + gnu_ifunc_debug_printf ("no minimal symbol found at %s, not caching", + paddress (current_inferior ()->arch (), addr)); + return 0; + } + if (msym.value_address () != addr) - return 0; + { + gnu_ifunc_debug_printf ("minimal symbol \"%s\" at %s does not match " + "addr %s, not caching", + msym.minsym->linkage_name (), + paddress (current_inferior ()->arch (), + msym.value_address ()), + paddress (current_inferior ()->arch (), addr)); + return 0; + } + objfile = msym.objfile; /* If .plt jumps back to .plt the symbol is still deferred for later @@ -711,10 +745,18 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr) symbol is in the .plt section because some systems have @plt symbols in the .text section. */ if (len > 4 && strcmp (target_name + len - 4, "@plt") == 0) - return 0; + { + gnu_ifunc_debug_printf ("target \"%s\" is a PLT stub, not caching", + target_name); + return 0; + } if (strcmp (target_name, "_PROCEDURE_LINKAGE_TABLE_") == 0) - return 0; + { + gnu_ifunc_debug_printf ("target is _PROCEDURE_LINKAGE_TABLE_, " + "not caching"); + return 0; + } htab = elf_objfile_gnu_ifunc_cache_data.get (objfile); if (htab == NULL) @@ -754,6 +796,9 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr) } *slot = entry_p; + gnu_ifunc_debug_printf ("cached \"%s\" -> %s in objfile %s", + name, paddress (objfile->arch (), addr), + objfile_name (objfile)); return 1; } @@ -767,6 +812,7 @@ elf_gnu_ifunc_record_cache (const char *name, CORE_ADDR addr) static int elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p) { + gnu_ifunc_debug_printf ("resolving \"%s\" by cache", name); int found = 0; /* FIXME: we only search the initial namespace. @@ -797,10 +843,17 @@ elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p) if (addr_p) *addr_p = entry_p->addr; + gnu_ifunc_debug_printf ("cache hit for \"%s\" -> %s in objfile %s", + name, + paddress (objfile->arch (), entry_p->addr), + objfile_name (objfile)); found = 1; return 1; }, nullptr); + if (!found) + gnu_ifunc_debug_printf ("cache miss for \"%s\"", name); + return found; } @@ -815,9 +868,11 @@ elf_gnu_ifunc_resolve_by_cache (const char *name, CORE_ADDR *addr_p) static int elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p) { + gnu_ifunc_debug_printf ("resolving \"%s\" by GOT", name); char *name_got_plt; const size_t got_suffix_len = strlen (SYMBOL_GOT_PLT_SUFFIX); int found = 0; + const char *func = __func__; name_got_plt = (char *) alloca (strlen (name) + got_suffix_len + 1); sprintf (name_got_plt, "%s" SYMBOL_GOT_PLT_SUFFIX, name); @@ -827,7 +882,7 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p) To search other namespaces, we would need to provide context, e.g. in form of an objfile in that namespace. */ current_program_space->iterate_over_objfiles_in_search_order - ([name, name_got_plt, &addr_p, &found] (struct objfile *objfile) + ([name, name_got_plt, &addr_p, &found, func] (struct objfile *objfile) { bfd *obfd = objfile->obfd.get (); struct gdbarch *gdbarch = objfile->arch (); @@ -859,11 +914,16 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p) (gdbarch, addr, current_inferior ()->top_target ()); addr = gdbarch_addr_bits_remove (gdbarch, addr); + gnu_ifunc_debug_printf_func (func, "GOT entry \"%s\" points to %s", + name_got_plt, paddress (gdbarch, addr)); + if (elf_gnu_ifunc_record_cache (name, addr)) { if (addr_p != NULL) *addr_p = addr; + gnu_ifunc_debug_printf ("resolved \"%s\" via GOT to %s", + name, paddress (gdbarch, addr)); found = 1; return 1; } @@ -871,6 +931,9 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p) return 0; }, nullptr); + if (!found) + gnu_ifunc_debug_printf ("failed to resolve \"%s\" by GOT", name); + return found; } @@ -884,17 +947,20 @@ elf_gnu_ifunc_resolve_by_got (const char *name, CORE_ADDR *addr_p) static bool elf_gnu_ifunc_resolve_name (const char *name, CORE_ADDR *addr_p) { + gnu_ifunc_debug_printf ("resolving name \"%s\"", name); + if (elf_gnu_ifunc_resolve_by_cache (name, addr_p)) return true; if (elf_gnu_ifunc_resolve_by_got (name, addr_p)) return true; + gnu_ifunc_debug_printf ("failed to resolve name \"%s\"", name); return false; } /* Call STT_GNU_IFUNC - a function returning address of a real function to - call. PC is theSTT_GNU_IFUNC resolving function entry. The value returned + call. PC is the STT_GNU_IFUNC resolving function entry. The value returned is the entry point of the resolved STT_GNU_IFUNC target function to call. */ @@ -908,6 +974,8 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc) CORE_ADDR hwcap = 0; struct value *hwcap_val; + gnu_ifunc_debug_printf ("resolving ifunc %s", paddress (gdbarch, pc)); + /* Try first any non-intrusive methods without an inferior call. */ if (find_pc_partial_function (pc, &name_at_pc, &start_at_pc, NULL) @@ -919,6 +987,9 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc) else name_at_pc = NULL; + gnu_ifunc_debug_printf ("resolving via inferior call to resolver at %s", + paddress (gdbarch, pc)); + function = value::allocate (func_func_type); function->set_lval (lval_memory); function->set_address (pc); @@ -936,6 +1007,10 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc) (gdbarch, address, current_inferior ()->top_target ()); address = gdbarch_addr_bits_remove (gdbarch, address); + gnu_ifunc_debug_printf ("resolver at %s returned %s", + paddress (gdbarch, pc), + paddress (gdbarch, address)); + if (name_at_pc) elf_gnu_ifunc_record_cache (name_at_pc, address); @@ -953,6 +1028,9 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b) CORE_ADDR prev_pc = get_frame_pc (prev_frame); int thread_id = inferior_thread ()->global_num; + gnu_ifunc_debug_printf ("stop on resolver for \"%s\"", + b->locspec->to_string ()); + gdb_assert (b->type == bp_gnu_ifunc_resolver); for (b_return = b->related_breakpoint; b_return != b; @@ -983,12 +1061,17 @@ elf_gnu_ifunc_resolver_stop (code_breakpoint *b) prev_frame_id, bp_gnu_ifunc_resolver_return).release (); + gnu_ifunc_debug_printf ("created resolver return breakpoint at %s", + paddress (get_frame_arch (prev_frame), prev_pc)); /* Add new b_return to the ring list b->related_breakpoint. */ gdb_assert (b_return->related_breakpoint == b_return); b_return->related_breakpoint = b->related_breakpoint; b->related_breakpoint = b_return; } + else + gnu_ifunc_debug_printf ("found existing resolver return breakpoint at %s", + paddress (get_frame_arch (prev_frame), prev_pc)); } /* Handle inferior hit of bp_gnu_ifunc_resolver_return, see its definition. */ @@ -1005,6 +1088,8 @@ elf_gnu_ifunc_resolver_return_stop (code_breakpoint *b) struct value *value; CORE_ADDR resolved_address, resolved_pc; + gnu_ifunc_debug_printf ("stop on resolver return"); + gdb_assert (b->type == bp_gnu_ifunc_resolver_return); while (b->related_breakpoint != b) @@ -1040,6 +1125,12 @@ elf_gnu_ifunc_resolver_return_stop (code_breakpoint *b) (gdbarch, resolved_address, current_inferior ()->top_target ()); resolved_pc = gdbarch_addr_bits_remove (gdbarch, resolved_pc); + gnu_ifunc_debug_printf ("resolver for \"%s\" returned resolved address=%s, " + "resolved pc=%s", + b->locspec->to_string (), + paddress (gdbarch, resolved_address), + paddress (gdbarch, resolved_pc)); + gdb_assert (current_program_space == b->pspace || b->pspace == NULL); elf_gnu_ifunc_record_cache (b->locspec->to_string (), resolved_pc); @@ -1343,6 +1434,13 @@ INIT_GDB_FILE (elfread) gnu_ifunc_fns_p = &elf_gnu_ifunc_fns; + add_setshow_boolean_cmd + ("gnu-ifunc", class_maintenance, &debug_gnu_ifunc, + _("Set GNU ifunc debugging."), + _("Show GNU ifunc debugging."), + _("When on, debug output for GNU ifunc resolution is displayed."), + nullptr, show_debug_gnu_ifunc, &setdebuglist, &showdebuglist); + /* Add "set always-read-ctf on/off". */ add_setshow_boolean_cmd ("always-read-ctf", class_support, &always_read_ctf, _("\ diff --git a/gdbsupport/common-debug.h b/gdbsupport/common-debug.h index f0edd49faead..206a7c96dc1a 100644 --- a/gdbsupport/common-debug.h +++ b/gdbsupport/common-debug.h @@ -71,6 +71,15 @@ extern void ATTRIBUTE_PRINTF (3, 0) debug_prefixed_vprintf } \ while (0) +#define debug_prefixed_printf_cond_func(debug_enabled_cond, mod, func, fmt, \ + ...) \ + do \ + { \ + if (debug_enabled_cond) \ + debug_prefixed_printf (mod, func, fmt, ##__VA_ARGS__); \ + } \ + while (0) + #define debug_prefixed_printf_cond_nofunc(debug_enabled_cond, mod, fmt, ...) \ do \ { \ base-commit: 3a862dc6c3da4214aa12d36d5fbc45a420fb40d5 -- 2.53.0