* [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs
@ 2026-06-30 11:04 Muhammad Kamran
2026-06-30 11:04 ` [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions Muhammad Kamran
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Muhammad Kamran @ 2026-06-30 11:04 UTC (permalink / raw)
To: gdb-patches
Cc: Simon Marchi, Andrew Burgess, Wilco Dijkstra, Yury Khrustalev,
Thiago Jung Bauermann, Adhemerval Zanella Netto,
Carlos O'Donell, Muhammad Kamran
This series fixes a GDB inferior-call issue exposed by malloc being a GNU
IFUNC in glibc on AArch64. The underlying problem is not AArch64-specific:
it can affect any inferior helper found through find_function_in_inferior's
minimal-symbol fallback when that helper is a GNU IFUNC.
GDB calls find_function_in_inferior ("malloc") when expression evaluation
needs to allocate memory in the inferior, for example for string literal
arguments. In the minimal-symbol fallback, GDB created a synthetic ordinary
function pointer from the minimal symbol address. If the symbol was a GNU
IFUNC, this lost the IFUNC marker, so call_function_by_hand did not resolve
the symbol before calling it.
Patch 1 checks the minimal symbol kind directly and propagates the GNU IFUNC
marker to the synthetic function type for mst_text_gnu_ifunc and
mst_data_gnu_ifunc symbols. The existing fallback address and return type
are unchanged.
Patch 2 fixes the follow-on return-type issue after IFUNC resolution. When
the resolved target type, or the type inferred from the resolver return type,
does not provide a usable return type, find_function_addr now keeps the
original function type's return type. This preserves the synthetic fallback
return type used by find_function_in_inferior ("malloc").
The tests add an internal inferior-call case using an IFUNC malloc and run it
through the existing gdb.base/gnu-ifunc.exp matrix for resolver attr,
resolver debug info, and resolved-target debug info.
Changes since v3:
* Move the ifunc resolver into a shared library.
Changes since v2:
* Rework the minimal-symbol fallback to check the minimal symbol kind
directly as suggested by Simon.
* Add coverage for both debug and no-debug IFUNC malloc variants by
using the existing framework.
* Preserve the original IFUNC return type when the resolved target type
is unknown.
Muhammad Kamran (2):
gdb: Preserve IFUNC marker when finding inferior functions
gdb: Keep original IFUNC return type when target type is unknown
gdb/infcall.c | 12 +++-
.../gdb.base/gnu-ifunc-inferior-call-final.c | 27 ++++++++
.../gnu-ifunc-inferior-call-resolver.c | 43 ++++++++++++
.../gdb.base/gnu-ifunc-inferior-call.c | 37 +++++++++++
gdb/testsuite/gdb.base/gnu-ifunc.exp | 66 +++++++++++++++++++
gdb/valops.c | 5 ++
6 files changed, 188 insertions(+), 2 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c
create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c
create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions 2026-06-30 11:04 [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran @ 2026-06-30 11:04 ` Muhammad Kamran 2026-08-10 21:12 ` Andrew Burgess 2026-06-30 11:04 ` [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown Muhammad Kamran 2026-08-04 9:02 ` [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran 2 siblings, 1 reply; 7+ messages in thread From: Muhammad Kamran @ 2026-06-30 11:04 UTC (permalink / raw) To: gdb-patches Cc: Simon Marchi, Andrew Burgess, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell, Muhammad Kamran GDB calls find_function_in_inferior ("malloc") when expression evaluation needs to allocate memory in the inferior, e.g. for string literal arguments. The minimal-symbol fallback created a synthetic ordinary function pointer from msymbol.value_address (). If the symbol was a GNU IFUNC, this discarded the IFUNC marker, so call_function_by_hand did not resolve the symbol before calling it. Check the minimal symbol kind directly and propagate the GNU IFUNC marker to the synthetic function type for mst_text_gnu_ifunc and mst_data_gnu_ifunc symbols. This keeps the existing fallback address and return type while allowing inferior calls through IFUNC symbols to be resolved correctly. Extend gdb.base/gnu-ifunc.exp with an internal inferior-call test that uses an IFUNC malloc. The test runs through the existing IFUNC matrix for resolver attr, resolver debug info, and resolved-target debug info. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34330 --- .../gdb.base/gnu-ifunc-inferior-call-final.c | 27 +++++++ .../gnu-ifunc-inferior-call-resolver.c | 43 +++++++++++ .../gdb.base/gnu-ifunc-inferior-call.c | 37 ++++++++++ gdb/testsuite/gdb.base/gnu-ifunc.exp | 73 +++++++++++++++++++ gdb/valops.c | 5 ++ 5 files changed, 185 insertions(+) create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c new file mode 100644 index 00000000000..1a9ae6fdcba --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> + +extern char arena[32]; + +void * +dummy_malloc (size_t size) +{ + (void) size; + return arena; +} diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c new file mode 100644 index 00000000000..217002968de --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c @@ -0,0 +1,43 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> + +extern void *dummy_malloc (size_t size); + +typedef void *(*malloc_t) (size_t size); + +#ifndef IFUNC_RESOLVER_ATTR +asm (".type malloc, %gnu_indirect_function"); +malloc_t +malloc (unsigned long hwcap) +#else +static malloc_t +resolve_malloc (void) +#endif +{ +#ifndef IFUNC_RESOLVER_ATTR + (void) hwcap; +#endif + return dummy_malloc; +} + +#ifdef IFUNC_RESOLVER_ATTR +extern void *malloc (size_t size); + +__typeof (malloc) malloc __attribute__ ((ifunc ("resolve_malloc"))); +#endif diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c new file mode 100644 index 00000000000..67d195d25f0 --- /dev/null +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c @@ -0,0 +1,37 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +char arena[32]; +const char *str; + +int +str_in_arena (void) +{ + return str == arena; +} + +void +get_string (const char *s) +{ + str = s; +} + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp index e6389102ae3..23a5aadbcbf 100644 --- a/gdb/testsuite/gdb.base/gnu-ifunc.exp +++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp @@ -25,6 +25,13 @@ set libsrc ${libfile}.c set final_file "${testfile}-final" set final_src ${final_file}.c +set infcall_file "${testfile}-inferior-call" +set infcall_src ${infcall_file}.c +set infcall_resolver_file "${testfile}-inferior-call-resolver" +set infcall_resolver_src ${infcall_resolver_file}.c +set infcall_final_file "${testfile}-inferior-call-final" +set infcall_final_src ${infcall_final_file}.c + # Return the binary suffix appended to program and library names to # make each testcase variant unique. proc make_binsuffix {resolver_attr resolver_debug final_debug} { @@ -356,6 +363,71 @@ proc misc_tests {resolver_attr resolver_debug final_debug} { } } +# Test that GDB resolves a GNU IFUNC minimal symbol when it uses +# find_function_in_inferior to make an internal inferior call. String +# literals are copied into the inferior with a call to malloc, so an +# IFUNC malloc exercises this path. + +proc_with_prefix test_inferior_call {resolver_attr resolver_debug final_debug} { + global srcdir subdir + global infcall_file infcall_src + global infcall_resolver_file infcall_resolver_src + global infcall_final_file infcall_final_src + + set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug] + set executable ${infcall_file}-$suffix + set binfile [standard_output_file $executable] + set infcall_lib_so [standard_output_file ${infcall_file}-$suffix.so] + set resolver_obj [standard_output_file ${infcall_resolver_file}-$suffix.o] + set final_obj [standard_output_file ${infcall_final_file}-$suffix.o] + + set resolver_opts {additional_flags=-fno-builtin-malloc additional_flags=-fpic} + set final_opts {additional_flags=-fpic} + set shlib_opts {ldflags=-Wl,-z,lazy} + set exec_opts [list debug shlib=$infcall_lib_so] + lappend exec_opts "ldflags=-Wl,-z,lazy" + + if {$resolver_attr} { + lappend resolver_opts "additional_flags=-DIFUNC_RESOLVER_ATTR" + } + + if {$resolver_debug} { + lappend resolver_opts "debug" + } + + if {$final_debug} { + lappend final_opts "debug" + } + + if { [gdb_compile ${srcdir}/${subdir}/${infcall_resolver_src} \ + $resolver_obj object $resolver_opts] != "" + || [gdb_compile ${srcdir}/${subdir}/${infcall_final_src} \ + $final_obj object $final_opts] != "" + || [gdb_compile_shlib [list $resolver_obj $final_obj] \ + $infcall_lib_so $shlib_opts] != "" + || [gdb_compile ${srcdir}/${subdir}/${infcall_src} \ + $binfile executable $exec_opts] != "" } { + untested "failed to compile inferior call testcase" + return + } + + clean_restart $executable + if {![runto_main]} { + return + } + + # Without debug info for both the resolver and the resolved target, + # find_function_addr currently loses the synthetic return type after + # resolving the IFUNC. + if {!$resolver_debug && !$final_debug} { + unsupported "internal call resolves IFUNC malloc" + return + } + gdb_test "print (get_string (\"hello-ifunc\"), str_in_arena ())" \ + " = 1" \ + "internal call resolves IFUNC malloc" +} + # Test all the combinations of: # # - An ifunc resolver with the same name as the ifunc symbol vs an @@ -374,6 +446,7 @@ foreach_with_prefix resolver_attr {0 1} { if { [build $resolver_attr $resolver_debug $final_debug] != 0 } { misc_tests $resolver_attr $resolver_debug $final_debug set-break $resolver_attr $resolver_debug $final_debug + test_inferior_call $resolver_attr $resolver_debug $final_debug } } } diff --git a/gdb/valops.c b/gdb/valops.c index ab6fd5079e1..454f093ab68 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -138,6 +138,11 @@ find_function_in_inferior (const char *name, struct objfile **objf_p) type = lookup_function_type (type); type = lookup_pointer_type (type); maddr = msymbol.value_address (); + minimal_symbol_type minsym_type = msymbol.minsym->type (); + + if (minsym_type == mst_text_gnu_ifunc + || minsym_type == mst_data_gnu_ifunc) + type->target_type ()->set_is_gnu_ifunc (true); if (objf_p) *objf_p = objfile; -- 2.43.0 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions 2026-06-30 11:04 ` [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions Muhammad Kamran @ 2026-08-10 21:12 ` Andrew Burgess 2026-08-13 12:38 ` Muhammad Kamran 0 siblings, 1 reply; 7+ messages in thread From: Andrew Burgess @ 2026-08-10 21:12 UTC (permalink / raw) To: Muhammad Kamran, gdb-patches Cc: Simon Marchi, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell, Muhammad Kamran Muhammad Kamran <muhammad.kamran@arm.com> writes: > GDB calls find_function_in_inferior ("malloc") when expression > evaluation needs to allocate memory in the inferior, e.g. for string > literal arguments. > > The minimal-symbol fallback created a synthetic ordinary function > pointer from msymbol.value_address (). If the symbol was a GNU IFUNC, > this discarded the IFUNC marker, so call_function_by_hand did not > resolve the symbol before calling it. > > Check the minimal symbol kind directly and propagate the GNU IFUNC > marker to the synthetic function type for mst_text_gnu_ifunc and > mst_data_gnu_ifunc symbols. This keeps the existing fallback address > and return type while allowing inferior calls through IFUNC symbols to > be resolved correctly. > > Extend gdb.base/gnu-ifunc.exp with an internal inferior-call test that > uses an IFUNC malloc. The test runs through the existing IFUNC matrix > for resolver attr, resolver debug info, and resolved-target debug > info. Thanks for working on this. This fix is looking good. I have a couple of minor testsuite issues to address, but I've proposed some code inline below. I've pretty sure that I've managed to find 3 other bugs in this area while reviewing this patch. I don't think we need to block this patch for fixing these additional issues, and I'll try to explain what I found inline below. > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34330 > --- > .../gdb.base/gnu-ifunc-inferior-call-final.c | 27 +++++++ > .../gnu-ifunc-inferior-call-resolver.c | 43 +++++++++++ > .../gdb.base/gnu-ifunc-inferior-call.c | 37 ++++++++++ > gdb/testsuite/gdb.base/gnu-ifunc.exp | 73 +++++++++++++++++++ > gdb/valops.c | 5 ++ > 5 files changed, 185 insertions(+) > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c > > diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c > new file mode 100644 > index 00000000000..1a9ae6fdcba > --- /dev/null > +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c > @@ -0,0 +1,27 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2026 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. */ > + > +#include <stddef.h> > + > +extern char arena[32]; > + > +void * > +dummy_malloc (size_t size) > +{ > + (void) size; > + return arena; > +} > diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c > new file mode 100644 > index 00000000000..217002968de > --- /dev/null > +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c > @@ -0,0 +1,43 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2026 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. */ > + > +#include <stddef.h> > + > +extern void *dummy_malloc (size_t size); > + > +typedef void *(*malloc_t) (size_t size); > + > +#ifndef IFUNC_RESOLVER_ATTR > +asm (".type malloc, %gnu_indirect_function"); > +malloc_t > +malloc (unsigned long hwcap) > +#else > +static malloc_t > +resolve_malloc (void) > +#endif > +{ > +#ifndef IFUNC_RESOLVER_ATTR > + (void) hwcap; > +#endif > + return dummy_malloc; > +} > + > +#ifdef IFUNC_RESOLVER_ATTR > +extern void *malloc (size_t size); > + > +__typeof (malloc) malloc __attribute__ ((ifunc ("resolve_malloc"))); > +#endif > diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c > new file mode 100644 > index 00000000000..67d195d25f0 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c > @@ -0,0 +1,37 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2026 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see <http://www.gnu.org/licenses/>. */ > + > +char arena[32]; > +const char *str; > + > +int > +str_in_arena (void) > +{ > + return str == arena; > +} > + > +void > +get_string (const char *s) > +{ > + str = s; > +} > + > +int > +main (void) > +{ > + return 0; > +} > diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp > index e6389102ae3..23a5aadbcbf 100644 > --- a/gdb/testsuite/gdb.base/gnu-ifunc.exp > +++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp > @@ -25,6 +25,13 @@ set libsrc ${libfile}.c > set final_file "${testfile}-final" > set final_src ${final_file}.c > > +set infcall_file "${testfile}-inferior-call" > +set infcall_src ${infcall_file}.c > +set infcall_resolver_file "${testfile}-inferior-call-resolver" > +set infcall_resolver_src ${infcall_resolver_file}.c > +set infcall_final_file "${testfile}-inferior-call-final" > +set infcall_final_src ${infcall_final_file}.c > + > # Return the binary suffix appended to program and library names to > # make each testcase variant unique. > proc make_binsuffix {resolver_attr resolver_debug final_debug} { > @@ -356,6 +363,71 @@ proc misc_tests {resolver_attr resolver_debug final_debug} { > } > } > > +# Test that GDB resolves a GNU IFUNC minimal symbol when it uses > +# find_function_in_inferior to make an internal inferior call. String > +# literals are copied into the inferior with a call to malloc, so an > +# IFUNC malloc exercises this path. > + > +proc_with_prefix test_inferior_call {resolver_attr resolver_debug final_debug} { > + global srcdir subdir > + global infcall_file infcall_src > + global infcall_resolver_file infcall_resolver_src > + global infcall_final_file infcall_final_src > + > + set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug] > + set executable ${infcall_file}-$suffix > + set binfile [standard_output_file $executable] > + set infcall_lib_so [standard_output_file ${infcall_file}-$suffix.so] > + set resolver_obj [standard_output_file ${infcall_resolver_file}-$suffix.o] > + set final_obj [standard_output_file ${infcall_final_file}-$suffix.o] > + > + set resolver_opts {additional_flags=-fno-builtin-malloc additional_flags=-fpic} > + set final_opts {additional_flags=-fpic} > + set shlib_opts {ldflags=-Wl,-z,lazy} > + set exec_opts [list debug shlib=$infcall_lib_so] > + lappend exec_opts "ldflags=-Wl,-z,lazy" > + > + if {$resolver_attr} { > + lappend resolver_opts "additional_flags=-DIFUNC_RESOLVER_ATTR" > + } > + > + if {$resolver_debug} { > + lappend resolver_opts "debug" > + } > + > + if {$final_debug} { > + lappend final_opts "debug" > + } > + > + if { [gdb_compile ${srcdir}/${subdir}/${infcall_resolver_src} \ > + $resolver_obj object $resolver_opts] != "" > + || [gdb_compile ${srcdir}/${subdir}/${infcall_final_src} \ > + $final_obj object $final_opts] != "" > + || [gdb_compile_shlib [list $resolver_obj $final_obj] \ > + $infcall_lib_so $shlib_opts] != "" > + || [gdb_compile ${srcdir}/${subdir}/${infcall_src} \ > + $binfile executable $exec_opts] != "" } { > + untested "failed to compile inferior call testcase" > + return > + } > + > + clean_restart $executable You should add a line containing: gdb_load_shlib $infcall_lib_so here. This will copy the shared library to the host and setup the library paths so the inferior can load the library when testing with remote host boards. All the other test in this file do something similar. You can see the failures when using 'make check-all-boards'. > + if {![runto_main]} { > + return > + } In order to get this test passing I added the following code here: set malloc_addr {} gdb_test_multiple "pipe maint print msymbols | grep \" malloc \"" \ "look for malloc msyms" \ { -re "($::hex) malloc section \[^\r\n\]+\r\n" { lappend malloc_addr $expect_out(1,string) exp_continue } -re "$::gdb_prompt $" { gdb_assert {[llength $malloc_addr] > 0} \ "found at least one malloc symbol" } } set found_correct_malloc false set first_addr [lindex $malloc_addr 0] set infcall_lib_tail [file tail $infcall_lib_so] gdb_test_multiple "info symbol $first_addr" "check first malloc symbol" { -re -wrap " in section \[^\r\n\]+ of \[^\r\n\]+/$infcall_lib_tail" { set found_correct_malloc true } -re -wrap " in section \[^\r\n\]+" { # Nothing to do. } } if { !$found_correct_malloc } { unsupported "found some other malloc symbol" return } The cause of all my problems is that older versions of the dynamic linker export a weak 'malloc' symbol, and in some configurations GDB ends up finding that symbol before it finds your test's 'malloc' IFUNC. The above catches tries to figure out when GDB is about to call the wrong/other function by looking at where the first minimal_symbol is defined. If it's in the test's shared library then GDB is going to call the right function. If the first minimal_symbol is in some other location then GDB is not going to call the expected function and the test will naturally fail. Now, I don't think GDB _should_ be calling the wrong function here. I think we should always be calling the symbol from the test. The reason we don't is explained below. > + > + # Without debug info for both the resolver and the resolved target, > + # find_function_addr currently loses the synthetic return type after > + # resolving the IFUNC. > + if {!$resolver_debug && !$final_debug} { > + unsupported "internal call resolves IFUNC malloc" > + return > + } > + gdb_test "print (get_string (\"hello-ifunc\"), str_in_arena ())" \ > + " = 1" \ > + "internal call resolves IFUNC malloc" > +} > + > # Test all the combinations of: > # > # - An ifunc resolver with the same name as the ifunc symbol vs an > @@ -374,6 +446,7 @@ foreach_with_prefix resolver_attr {0 1} { > if { [build $resolver_attr $resolver_debug $final_debug] != 0 } { > misc_tests $resolver_attr $resolver_debug $final_debug > set-break $resolver_attr $resolver_debug $final_debug > + test_inferior_call $resolver_attr $resolver_debug $final_debug > } > } > } > diff --git a/gdb/valops.c b/gdb/valops.c > index ab6fd5079e1..454f093ab68 100644 > --- a/gdb/valops.c > +++ b/gdb/valops.c > @@ -138,6 +138,11 @@ find_function_in_inferior (const char *name, struct objfile **objf_p) > type = lookup_function_type (type); > type = lookup_pointer_type (type); > maddr = msymbol.value_address (); > + minimal_symbol_type minsym_type = msymbol.minsym->type (); > + > + if (minsym_type == mst_text_gnu_ifunc > + || minsym_type == mst_data_gnu_ifunc) > + type->target_type ()->set_is_gnu_ifunc (true); > > if (objf_p) > *objf_p = objfile; Here you're patching the minimal_symbol code path. You'd think that we'd only get here if we fail to find an actual full debug symbol for the function. But how does find_function_in_inferior look for a debug symbol? Like this: sym = lookup_symbol (name, nullptr, SEARCH_TYPE_DOMAIN, nullptr); Notice we use SEARCH_TYPE_DOMAIN. That doesn't seem right. We're looking for functions, not types. I'm pretty sure that this check always fails, and has always failed. We get away with it because we just fall back on the minimal symbol lookup path, and that usually works. When we make an inferior call, like "print malloc(10)" we use SEARCH_VFT in the c-exp.y file. If we switch to using that here then we suddenly start to get hits for malloc in some of the cases. I suspect we might want to consider using SEARCH_FUNCTION_DOMAIN though as we know we only need functions. One problem with fixing the above though is that we end up with more IFUNC issues as the above doesn't handle them. But we can see how this might be handled by looking elsewhere in c-exp.y where we do: bound_minimal_symbol resolver = find_gnu_ifunc (sym.symbol); if (resolver.minsym != NULL) pstate->push_new<var_msym_value_operation> (resolver); else pstate->push_new<var_value_operation> (sym); We could do something similar (see patch below), and indeed this gets fixes a bunch of the problem cases for me. But not all. The final issue will require some deeper fixing. The malloc symbol exported by the older linkers is a weak symbol. The problem is that GDB doesn't track weak vs strong symbols. If we did then we would be able to prefer returning a strong symbol to a weak one, and this would mean that we always found the test's IFUNC symbol. I've said all this mostly so there's a record of all the things I found, I don't think that you need to fix any of these for this patch. I took a look through all the feedback you received on previous versions, and I think everything raised has been addressed. If you're happy to incorporate the two testsuite fixes I proposed above then I think this patch is OK. Approved-By: Andrew Burgess <aburgess@redhat.com> I'll take a look at patch 2/2 tomorrow, unless someone else beats me to it. Thanks, Andrew --- diff --git i/gdb/valops.c w/gdb/valops.c index c478bdc3f15..f278d7b7cab 100644 --- i/gdb/valops.c +++ w/gdb/valops.c @@ -113,52 +113,53 @@ struct value * find_function_in_inferior (const char *name, struct objfile **objf_p) { struct block_symbol sym; + bound_minimal_symbol msymbol; - sym = lookup_symbol (name, nullptr, SEARCH_TYPE_DOMAIN, nullptr); + sym = lookup_symbol (name, nullptr, SEARCH_VFT, nullptr); if (sym.symbol != NULL) { - if (objf_p) - *objf_p = sym.symbol->objfile (); + msymbol = find_gnu_ifunc (sym.symbol); + if (msymbol.minsym == nullptr) + { + if (objf_p) + *objf_p = sym.symbol->objfile (); + return value_of_variable (sym.symbol, sym.block); + } + } + else + msymbol = lookup_minimal_symbol (current_program_space, name); - return value_of_variable (sym.symbol, sym.block); + if (msymbol.minsym != NULL) + { + struct objfile *objfile = msymbol.objfile; + struct gdbarch *gdbarch = objfile->arch (); + + struct type *type; + CORE_ADDR maddr; + type = lookup_pointer_type (builtin_type (gdbarch)->builtin_char); + type = lookup_function_type (type); + type = lookup_pointer_type (type); + maddr = msymbol.value_address (); + minimal_symbol_type minsym_type = msymbol.minsym->type (); + + if (minsym_type == mst_text_gnu_ifunc + || minsym_type == mst_data_gnu_ifunc) + type->target_type ()->set_is_gnu_ifunc (true); + + if (objf_p) + *objf_p = objfile; + + return value_from_pointer (type, maddr); } else { - bound_minimal_symbol msymbol - = lookup_minimal_symbol (current_program_space, name); - - if (msymbol.minsym != NULL) - { - struct objfile *objfile = msymbol.objfile; - struct gdbarch *gdbarch = objfile->arch (); - - struct type *type; - CORE_ADDR maddr; - type = lookup_pointer_type (builtin_type (gdbarch)->builtin_char); - type = lookup_function_type (type); - type = lookup_pointer_type (type); - maddr = msymbol.value_address (); - minimal_symbol_type minsym_type = msymbol.minsym->type (); - - if (minsym_type == mst_text_gnu_ifunc - || minsym_type == mst_data_gnu_ifunc) - type->target_type ()->set_is_gnu_ifunc (true); - - if (objf_p) - *objf_p = objfile; - - return value_from_pointer (type, maddr); - } + if (!target_has_execution ()) + error (_("evaluation of this expression " + "requires the target program to be active")); else - { - if (!target_has_execution ()) - error (_("evaluation of this expression " - "requires the target program to be active")); - else - error (_("evaluation of this expression requires the " - "program to have a function \"%s\"."), - name); - } + error (_("evaluation of this expression requires the " + "program to have a function \"%s\"."), + name); } } ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions 2026-08-10 21:12 ` Andrew Burgess @ 2026-08-13 12:38 ` Muhammad Kamran 0 siblings, 0 replies; 7+ messages in thread From: Muhammad Kamran @ 2026-08-13 12:38 UTC (permalink / raw) To: Andrew Burgess, gdb-patches Cc: Simon Marchi, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell On 10/08/2026 22:12, Andrew Burgess wrote: > > I took a look through all the feedback you received on previous > versions, and I think everything raised has been addressed. If you're > happy to incorporate the two testsuite fixes I proposed above then I > think this patch is OK. > > Approved-By: Andrew Burgess <aburgess@redhat.com> > Thanks for the review and the approval. I’ve addressed your feedback in v5, which I’ve posted to the mailing list [1]. The updated series adds the gdb_load_shlib call, includes the minimal-symbol guard for the test’s malloc, and applies the style fixes you suggested for patch 2. I don’t have write access, so if everything looks OK now, could a maintainer please commit the series for me? Thanks, Kamran [1] https://inbox.sourceware.org/gdb-patches/20260811131219.510776-1-muhammad.kamran@arm.com/T/ > I'll take a look at patch 2/2 tomorrow, unless someone else beats me to > it. > > Thanks, > Andrew > > --- > > diff --git i/gdb/valops.c w/gdb/valops.c > index c478bdc3f15..f278d7b7cab 100644 > --- i/gdb/valops.c > +++ w/gdb/valops.c > @@ -113,52 +113,53 @@ struct value * > find_function_in_inferior (const char *name, struct objfile **objf_p) > { > struct block_symbol sym; > + bound_minimal_symbol msymbol; > > - sym = lookup_symbol (name, nullptr, SEARCH_TYPE_DOMAIN, nullptr); > + sym = lookup_symbol (name, nullptr, SEARCH_VFT, nullptr); > if (sym.symbol != NULL) > { > - if (objf_p) > - *objf_p = sym.symbol->objfile (); > + msymbol = find_gnu_ifunc (sym.symbol); > + if (msymbol.minsym == nullptr) > + { > + if (objf_p) > + *objf_p = sym.symbol->objfile (); > + return value_of_variable (sym.symbol, sym.block); > + } > + } > + else > + msymbol = lookup_minimal_symbol (current_program_space, name); > > - return value_of_variable (sym.symbol, sym.block); > + if (msymbol.minsym != NULL) > + { > + struct objfile *objfile = msymbol.objfile; > + struct gdbarch *gdbarch = objfile->arch (); > + > + struct type *type; > + CORE_ADDR maddr; > + type = lookup_pointer_type (builtin_type (gdbarch)->builtin_char); > + type = lookup_function_type (type); > + type = lookup_pointer_type (type); > + maddr = msymbol.value_address (); > + minimal_symbol_type minsym_type = msymbol.minsym->type (); > + > + if (minsym_type == mst_text_gnu_ifunc > + || minsym_type == mst_data_gnu_ifunc) > + type->target_type ()->set_is_gnu_ifunc (true); > + > + if (objf_p) > + *objf_p = objfile; > + > + return value_from_pointer (type, maddr); > } > else > { > - bound_minimal_symbol msymbol > - = lookup_minimal_symbol (current_program_space, name); > - > - if (msymbol.minsym != NULL) > - { > - struct objfile *objfile = msymbol.objfile; > - struct gdbarch *gdbarch = objfile->arch (); > - > - struct type *type; > - CORE_ADDR maddr; > - type = lookup_pointer_type (builtin_type (gdbarch)->builtin_char); > - type = lookup_function_type (type); > - type = lookup_pointer_type (type); > - maddr = msymbol.value_address (); > - minimal_symbol_type minsym_type = msymbol.minsym->type (); > - > - if (minsym_type == mst_text_gnu_ifunc > - || minsym_type == mst_data_gnu_ifunc) > - type->target_type ()->set_is_gnu_ifunc (true); > - > - if (objf_p) > - *objf_p = objfile; > - > - return value_from_pointer (type, maddr); > - } > + if (!target_has_execution ()) > + error (_("evaluation of this expression " > + "requires the target program to be active")); > else > - { > - if (!target_has_execution ()) > - error (_("evaluation of this expression " > - "requires the target program to be active")); > - else > - error (_("evaluation of this expression requires the " > - "program to have a function \"%s\"."), > - name); > - } > + error (_("evaluation of this expression requires the " > + "program to have a function \"%s\"."), > + name); > } > } > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown 2026-06-30 11:04 [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran 2026-06-30 11:04 ` [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions Muhammad Kamran @ 2026-06-30 11:04 ` Muhammad Kamran 2026-08-11 10:09 ` Andrew Burgess 2026-08-04 9:02 ` [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran 2 siblings, 1 reply; 7+ messages in thread From: Muhammad Kamran @ 2026-06-30 11:04 UTC (permalink / raw) To: gdb-patches Cc: Simon Marchi, Andrew Burgess, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell, Muhammad Kamran When find_function_addr resolves a GNU IFUNC, it tries to replace the original function type with the resolved target type, or with the type returned by the resolver. If neither source provides a useful return type, keep the return type from the original function value. This matters for internal inferior calls such as find_function_in_inferior ("malloc"), where GDB creates a synthetic function type with a known fallback return type. Remove the guard from the IFUNC inferior-call test so the no-debug resolver/no-debug target variants are tested too. --- gdb/infcall.c | 12 ++++++++++-- gdb/testsuite/gdb.base/gnu-ifunc.exp | 7 ------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/gdb/infcall.c b/gdb/infcall.c index e6b24ff5310..077407073ac 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -395,6 +395,9 @@ find_function_addr (struct value *function, FUNCTION_TYPE have been asked for. */ if (retval_type != NULL || function_type != NULL) { + /* Default to original function type's return type. Target type + replaces this only if it provides a usable return type. */ + value_type = ftype->target_type (); type *target_ftype = find_function_type (funaddr); /* If we don't have debug info for the target function, see if we can instead extract the target function's @@ -403,8 +406,13 @@ find_function_addr (struct value *function, target_ftype = find_gnu_ifunc_target_type (resolver_addr); if (target_ftype != NULL) { - value_type = check_typedef (target_ftype)->target_type (); - ftype = target_ftype; + struct type *target_value_type + = check_typedef (target_ftype)->target_type (); + if (target_value_type != NULL) + { + value_type = target_value_type; + ftype = target_ftype; + } } } } diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp index 23a5aadbcbf..2d7100276f8 100644 --- a/gdb/testsuite/gdb.base/gnu-ifunc.exp +++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp @@ -416,13 +416,6 @@ proc_with_prefix test_inferior_call {resolver_attr resolver_debug final_debug} { return } - # Without debug info for both the resolver and the resolved target, - # find_function_addr currently loses the synthetic return type after - # resolving the IFUNC. - if {!$resolver_debug && !$final_debug} { - unsupported "internal call resolves IFUNC malloc" - return - } gdb_test "print (get_string (\"hello-ifunc\"), str_in_arena ())" \ " = 1" \ "internal call resolves IFUNC malloc" -- 2.43.0 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown 2026-06-30 11:04 ` [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown Muhammad Kamran @ 2026-08-11 10:09 ` Andrew Burgess 0 siblings, 0 replies; 7+ messages in thread From: Andrew Burgess @ 2026-08-11 10:09 UTC (permalink / raw) To: Muhammad Kamran, gdb-patches Cc: Simon Marchi, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell, Muhammad Kamran Muhammad Kamran <muhammad.kamran@arm.com> writes: > When find_function_addr resolves a GNU IFUNC, it tries to replace the > original function type with the resolved target type, or with the type > returned by the resolver. If neither source provides a useful return > type, keep the return type from the original function value. > > This matters for internal inferior calls such as > find_function_in_inferior ("malloc"), where GDB creates a synthetic > function type with a known fallback return type. > > Remove the guard from the IFUNC inferior-call test so the no-debug > resolver/no-debug target variants are tested too. It is probably worth adding the Bug: link from the previous commit here too. > --- > gdb/infcall.c | 12 ++++++++++-- > gdb/testsuite/gdb.base/gnu-ifunc.exp | 7 ------- > 2 files changed, 10 insertions(+), 9 deletions(-) > > diff --git a/gdb/infcall.c b/gdb/infcall.c > index e6b24ff5310..077407073ac 100644 > --- a/gdb/infcall.c > +++ b/gdb/infcall.c > @@ -395,6 +395,9 @@ find_function_addr (struct value *function, > FUNCTION_TYPE have been asked for. */ > if (retval_type != NULL || function_type != NULL) > { > + /* Default to original function type's return type. Target type > + replaces this only if it provides a usable return type. */ > + value_type = ftype->target_type (); > type *target_ftype = find_function_type (funaddr); > /* If we don't have debug info for the target function, > see if we can instead extract the target function's > @@ -403,8 +406,13 @@ find_function_addr (struct value *function, > target_ftype = find_gnu_ifunc_target_type (resolver_addr); > if (target_ftype != NULL) > { > - value_type = check_typedef (target_ftype)->target_type (); > - ftype = target_ftype; > + struct type *target_value_type I think you should drop the 'struct' here. Newer GDB code avoids the 'struct' where possible. This function has a mix so I think adopting the new style would be best. > + = check_typedef (target_ftype)->target_type (); > + if (target_value_type != NULL) Replace 'NULL' with 'nullptr' in new code please. With those minor fixes: Approved-By: Andrew Burgess <aburgess@redhat.com> Thanks, Andrew ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs 2026-06-30 11:04 [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran 2026-06-30 11:04 ` [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions Muhammad Kamran 2026-06-30 11:04 ` [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown Muhammad Kamran @ 2026-08-04 9:02 ` Muhammad Kamran 2 siblings, 0 replies; 7+ messages in thread From: Muhammad Kamran @ 2026-08-04 9:02 UTC (permalink / raw) To: gdb-patches Cc: Simon Marchi, Andrew Burgess, Wilco Dijkstra, Yury Khrustalev, Thiago Jung Bauermann, Adhemerval Zanella Netto, Carlos O'Donell Ping. Is this patch series OK to push? This would also unblock the GNU IFUNC malloc implementation in glibc. Thanks, Kamran On 30/06/2026 12:04, Muhammad Kamran wrote: > This series fixes a GDB inferior-call issue exposed by malloc being a GNU > IFUNC in glibc on AArch64. The underlying problem is not AArch64-specific: > it can affect any inferior helper found through find_function_in_inferior's > minimal-symbol fallback when that helper is a GNU IFUNC. > > GDB calls find_function_in_inferior ("malloc") when expression evaluation > needs to allocate memory in the inferior, for example for string literal > arguments. In the minimal-symbol fallback, GDB created a synthetic ordinary > function pointer from the minimal symbol address. If the symbol was a GNU > IFUNC, this lost the IFUNC marker, so call_function_by_hand did not resolve > the symbol before calling it. > > Patch 1 checks the minimal symbol kind directly and propagates the GNU IFUNC > marker to the synthetic function type for mst_text_gnu_ifunc and > mst_data_gnu_ifunc symbols. The existing fallback address and return type > are unchanged. > > Patch 2 fixes the follow-on return-type issue after IFUNC resolution. When > the resolved target type, or the type inferred from the resolver return type, > does not provide a usable return type, find_function_addr now keeps the > original function type's return type. This preserves the synthetic fallback > return type used by find_function_in_inferior ("malloc"). > > The tests add an internal inferior-call case using an IFUNC malloc and run it > through the existing gdb.base/gnu-ifunc.exp matrix for resolver attr, > resolver debug info, and resolved-target debug info. > > Changes since v3: > * Move the ifunc resolver into a shared library. > > Changes since v2: > * Rework the minimal-symbol fallback to check the minimal symbol kind > directly as suggested by Simon. > * Add coverage for both debug and no-debug IFUNC malloc variants by > using the existing framework. > * Preserve the original IFUNC return type when the resolved target type > is unknown. > > Muhammad Kamran (2): > gdb: Preserve IFUNC marker when finding inferior functions > gdb: Keep original IFUNC return type when target type is unknown > > gdb/infcall.c | 12 +++- > .../gdb.base/gnu-ifunc-inferior-call-final.c | 27 ++++++++ > .../gnu-ifunc-inferior-call-resolver.c | 43 ++++++++++++ > .../gdb.base/gnu-ifunc-inferior-call.c | 37 +++++++++++ > gdb/testsuite/gdb.base/gnu-ifunc.exp | 66 +++++++++++++++++++ > gdb/valops.c | 5 ++ > 6 files changed, 188 insertions(+), 2 deletions(-) > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-final.c > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call-resolver.c > create mode 100644 gdb/testsuite/gdb.base/gnu-ifunc-inferior-call.c > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-13 12:39 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-06-30 11:04 [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran 2026-06-30 11:04 ` [PATCH v4 1/2] gdb: Preserve IFUNC marker when finding inferior functions Muhammad Kamran 2026-08-10 21:12 ` Andrew Burgess 2026-08-13 12:38 ` Muhammad Kamran 2026-06-30 11:04 ` [PATCH v4 2/2] gdb: Keep original IFUNC return type when target type is unknown Muhammad Kamran 2026-08-11 10:09 ` Andrew Burgess 2026-08-04 9:02 ` [PATCH v4 0/2] gdb: Fix internal inferior calls through GNU IFUNCs Muhammad Kamran
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox