- Support GNU IFUNCs - indirect functions (BZ 539590).

- Fix bp conditionals [bp_location-accel] regression (Phil Muldoon, BZ
    538626).
- Fix missed breakpoint location [bp_location-accel] regression (upstream).
This commit is contained in:
Jan Kratochvil 2009-11-25 10:38:24 +00:00
parent 6e5cc88fad
commit 9bb4d3d924
4 changed files with 703 additions and 34 deletions

View File

@ -2,7 +2,7 @@ http://sourceware.org/gdb/wiki/ProjectArcher
http://sourceware.org/gdb/wiki/ArcherBranchManagement
GIT snapshot:
commit 5b73ea6a0f74e63db3b504792fc1d37f548bdf5c
commit b125345fb36abbb9bd00128e2093dc636a859da5
branch `archer' - the merge of branches:
archer-tromey-call-frame-cfa
@ -463,7 +463,7 @@ index 53e7371..d373f8a 100644
+
#endif /* BLOCK_H */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 811cdfb..b0bf314 100644
index 811cdfb..0f35101 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -61,6 +61,7 @@
@ -684,14 +684,14 @@ index 811cdfb..b0bf314 100644
+
+ /* Find BC_L which is a leftmost element which may affect BUF content. It is
+ safe to report lower value but a failure to report higher one. */
+
- ALL_BP_LOCATIONS (b)
+ bc_l = 0;
+ bc_r = bp_location_count;
+ while (bc_l + 1 < bc_r)
+ {
+ struct bp_location *b;
- ALL_BP_LOCATIONS (b)
+
+ bc = (bc_l + bc_r) / 2;
+ b = bp_location[bc];
+
@ -1553,7 +1553,7 @@ index 811cdfb..b0bf314 100644
/* If SHOULD_INSERT is false, do not insert any breakpoint locations
into the inferior, only remove already-inserted locations that no
longer should be inserted. Functions that delete a breakpoint or
@@ -7777,49 +7951,66 @@ static void
@@ -7777,49 +7951,78 @@ static void
update_global_location_list (int should_insert)
{
struct breakpoint *b;
@ -1625,11 +1625,11 @@ index 811cdfb..b0bf314 100644
{
- /* Tells if 'loc' is found amoung the new locations. If not, we
+ struct bp_location *old_loc = *old_locp;
+ struct bp_location **loc2p;
+
+ /* Tells if 'old_loc' is found amoung the new locations. If not, we
have to free it. */
- int found_object = 0;
+ int found_object;
int found_object = 0;
/* Tells if the location should remain inserted in the target. */
int keep_in_target = 0;
int removed = 0;
@ -1643,13 +1643,24 @@ index 811cdfb..b0bf314 100644
+ /* Skip LOCP entries which will definitely never be needed. Stop either
+ at or being the one matching OLD_LOC. */
+ while (locp < bp_location + bp_location_count
+ && bp_location_compare (*locp, old_loc) < 0)
+ && (*locp)->address < old_loc->address)
+ locp++;
+ found_object = locp < bp_location + bp_location_count && *locp == old_loc;
+
+ for (loc2p = locp;
+ (loc2p < bp_location + bp_location_count
+ && (*loc2p)->address == old_loc->address);
+ loc2p++)
+ {
+ if (*loc2p == old_loc)
+ {
+ found_object = 1;
+ break;
+ }
+ }
/* If this location is no longer present, and inserted, look if there's
maybe a new location at the same address. If so, mark that one
@@ -7827,11 +8018,11 @@ update_global_location_list (int should_insert)
@@ -7827,11 +8030,11 @@ update_global_location_list (int should_insert)
don't have a time window where a breakpoint at certain location is not
inserted. */
@ -1663,7 +1674,7 @@ index 811cdfb..b0bf314 100644
{
/* The location is still present in the location list, and still
should be inserted. Don't do anything. */
@@ -7842,37 +8033,46 @@ update_global_location_list (int should_insert)
@@ -7842,37 +8045,46 @@ update_global_location_list (int should_insert)
/* The location is either no longer present, or got disabled.
See if there's another location at the same address, in which
case we don't need to remove this one from the target. */
@ -1685,24 +1696,24 @@ index 811cdfb..b0bf314 100644
+
+ if (breakpoint_address_is_meaningful (old_loc->owner))
+ {
+ struct bp_location **loc2p;
+
+ for (loc2p = locp;
+ loc2p < bp_location + bp_location_count
+ && (*loc2p)->address == old_loc->address;
+ (loc2p < bp_location + bp_location_count
+ && (*loc2p)->address == old_loc->address);
+ loc2p++)
+ {
+ struct bp_location *loc2 = *loc2p;
+
+ /* For the sake of should_be_inserted.
+ Duplicates check below will fix up this later. */
+ loc2->duplicate = 0;
+ if (loc2 != old_loc && should_be_inserted (loc2))
+ {
+ loc2->inserted = 1;
+ loc2->target_info = old_loc->target_info;
+ keep_in_target = 1;
+ break;
+ {
+ /* For the sake of should_be_inserted.
+ Duplicates check below will fix up this later. */
+ loc2->duplicate = 0;
+ if (loc2 != old_loc && should_be_inserted (loc2))
+ {
+ loc2->inserted = 1;
+ loc2->target_info = old_loc->target_info;
+ keep_in_target = 1;
+ break;
+ }
+ }
+ }
+ }
@ -1728,7 +1739,7 @@ index 811cdfb..b0bf314 100644
}
removed = 1;
}
@@ -7894,19 +8094,59 @@ update_global_location_list (int should_insert)
@@ -7894,19 +8106,59 @@ update_global_location_list (int should_insert)
longer need to keep this breakpoint. This is just a
heuristic, but if it's wrong, we'll report unexpected SIGTRAP,
which is usability issue, but not a correctness problem. */
@ -1794,7 +1805,7 @@ index 811cdfb..b0bf314 100644
}
if (breakpoints_always_inserted_mode () && should_insert
@@ -8083,6 +8323,7 @@ delete_command (char *arg, int from_tty)
@@ -8083,6 +8335,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_thread_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
@ -1802,7 +1813,7 @@ index 811cdfb..b0bf314 100644
&& b->number >= 0)
{
breaks_to_delete = 1;
@@ -8102,6 +8343,7 @@ delete_command (char *arg, int from_tty)
@@ -8102,6 +8355,7 @@ delete_command (char *arg, int from_tty)
&& b->type != bp_jit_event
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
@ -1810,7 +1821,7 @@ index 811cdfb..b0bf314 100644
&& b->number >= 0)
delete_breakpoint (b);
}
@@ -8404,6 +8646,7 @@ breakpoint_re_set_one (void *bint)
@@ -8404,6 +8658,7 @@ breakpoint_re_set_one (void *bint)
reset later by breakpoint_re_set. */
case bp_overlay_event:
case bp_longjmp_master:
@ -1818,7 +1829,7 @@ index 811cdfb..b0bf314 100644
delete_breakpoint (b);
break;
@@ -8427,6 +8670,8 @@ breakpoint_re_set_one (void *bint)
@@ -8427,6 +8682,8 @@ breakpoint_re_set_one (void *bint)
case bp_longjmp:
case bp_longjmp_resume:
case bp_jit_event:
@ -1827,7 +1838,7 @@ index 811cdfb..b0bf314 100644
break;
}
@@ -8462,6 +8707,7 @@ breakpoint_re_set (void)
@@ -8462,6 +8719,7 @@ breakpoint_re_set (void)
create_longjmp_master_breakpoint ("_longjmp");
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
@ -1835,7 +1846,7 @@ index 811cdfb..b0bf314 100644
}
/* Reset the thread number of this breakpoint:
@@ -9327,6 +9573,22 @@ all_tracepoints ()
@@ -9327,6 +9585,22 @@ all_tracepoints ()
return tp_vec;
}
@ -1858,7 +1869,7 @@ index 811cdfb..b0bf314 100644
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -9850,4 +10112,5 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
@@ -9850,4 +10124,5 @@ inferior in all-stop mode, gdb behaves as if always-inserted mode is off."),
automatic_hardware_breakpoints = 1;
observer_attach_about_to_proceed (breakpoint_about_to_proceed);

View File

@ -0,0 +1,134 @@
Index: gdb-7.0/gdb/breakpoint.c
===================================================================
--- gdb-7.0.orig/gdb/breakpoint.c 2009-11-25 10:24:49.000000000 +0100
+++ gdb-7.0/gdb/breakpoint.c 2009-11-25 10:28:35.000000000 +0100
@@ -337,14 +337,21 @@ static int executing_startup;
B ? (TMP=B->next, 1): 0; \
B = TMP)
-/* Similar iterator for the low-level breakpoints. SAFE variant is not
- provided so update_global_location_list must not be called while executing
- the block of ALL_BP_LOCATIONS. */
-
-#define ALL_BP_LOCATIONS(B,BP_TMP) \
- for (BP_TMP = bp_location; \
- BP_TMP < bp_location + bp_location_count && (B = *BP_TMP); \
- BP_TMP++)
+/* Similar iterator for the low-level breakpoints. This iterator
+ requires a defined BP_LOCATION array and BP_LOCATION_COUNT. */
+
+#define ALL_BP_LOCATIONS_FROM(B,BP_TMP,BP_LOCATION,BP_LOCATION_COUNT) \
+ for (BP_TMP = BP_LOCATION; \
+ BP_TMP < BP_LOCATION + BP_LOCATION_COUNT && (B = *BP_TMP); \
+ BP_TMP++)
+
+/* Iterator that calls ALL_BP_LOCATIONS_FROM with the global
+ bp_locations and bp_location_count variables. SAFE variant is not
+ provided so update_global_location_list must not be called while
+ executing the block of ALL_BP_LOCATIONS. */
+
+#define ALL_BP_LOCATIONS(B,BP_TMP) \
+ ALL_BP_LOCATIONS_FROM(B,BP_TMP,bp_location, bp_location_count)
/* Iterator for tracepoints only. */
@@ -3313,6 +3320,7 @@ bpstat_check_breakpoint_conditions (bpst
bpstat
bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
{
+ struct cleanup *old_chain;
struct breakpoint *b = NULL;
struct bp_location *bl, **blp_tmp;
struct bp_location *loc;
@@ -3322,8 +3330,14 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
bpstat bs = root_bs;
int ix;
int need_remove_insert, update_locations = 0;
+ struct bp_location **saved_bp_location;
+ int saved_bp_location_count = bp_location_count;
- ALL_BP_LOCATIONS (bl, blp_tmp)
+ saved_bp_location = xmalloc (sizeof (*bp_location) * bp_location_count);
+ memcpy (saved_bp_location, bp_location, sizeof (*bp_location) * bp_location_count);
+ old_chain = make_cleanup (xfree, saved_bp_location);
+
+ ALL_BP_LOCATIONS_FROM (bl, blp_tmp, saved_bp_location, saved_bp_location_count)
{
bpstat bs_prev = bs;
@@ -3460,6 +3474,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
insert_breakpoints ();
}
+ do_cleanups (old_chain);
return root_bs->next;
}
Index: gdb-7.0/gdb/testsuite/gdb.base/condbreak.exp
===================================================================
--- gdb-7.0.orig/gdb/testsuite/gdb.base/condbreak.exp 2009-01-03 06:58:03.000000000 +0100
+++ gdb-7.0/gdb/testsuite/gdb.base/condbreak.exp 2009-11-25 10:27:50.000000000 +0100
@@ -68,6 +68,8 @@ set bp_location1 [gdb_get_line_number "
set bp_location6 [gdb_get_line_number "set breakpoint 6 here"]
set bp_location8 [gdb_get_line_number "set breakpoint 8 here" $srcfile1]
set bp_location9 [gdb_get_line_number "set breakpoint 9 here" $srcfile1]
+set bp_location13 [gdb_get_line_number "set breakpoint 13 here" $srcfile1]
+set bp_location14 [gdb_get_line_number "set breakpoint 14 here" $srcfile1]
set bp_location15 [gdb_get_line_number "set breakpoint 15 here" $srcfile1]
set bp_location16 [gdb_get_line_number "set breakpoint 16 here" $srcfile1]
@@ -110,15 +112,23 @@ gdb_test "break marker2 if (a==43)" \
"Breakpoint.*at.* file .*$srcfile1, line.*"
#
+# Check break involving inferior function call.
+#
+gdb_test "break marker4 if (multi_line_if_conditional(1,1,1)==0)" \
+ "Breakpoint.*at.* file .*$srcfile1, line.*"
+
+#
# check to see what breakpoints are set
#
if {$hp_aCC_compiler} {
set marker1_proto "\\(void\\)"
set marker2_proto "\\(int\\)"
+ set marker4_proto "\\(long\\)"
} else {
set marker1_proto ""
set marker2_proto ""
+ set marker4_proto ""
}
gdb_test "info break" \
@@ -129,7 +139,9 @@ gdb_test "info break" \
\[0-9\]+\[\t \]+breakpoint keep y.* in main at .*$srcfile:$bp_location1.*
\[\t \]+stop only if \\(1==1\\).*
\[0-9\]+\[\t \]+breakpoint keep y.* in marker2$marker2_proto at .*$srcfile1:($bp_location8|$bp_location9).*
-\[\t \]+stop only if \\(a==43\\).*" \
+\[\t \]+stop only if \\(a==43\\).*
+\[0-9\]+\[\t \]+breakpoint keep y.* in marker4$marker4_proto at .*$srcfile1:($bp_location13|$bp_location14).*
+\[\t \]+stop only if \\(multi_line_if_conditional\\(1,1,1\\)==0\\).*" \
"breakpoint info"
@@ -220,3 +232,19 @@ gdb_expect {
fail "(timeout) run until breakpoint at marker2"
}
}
+
+send_gdb "continue\n"
+gdb_expect {
+ -re "Continuing\\..*Breakpoint \[0-9\]+, marker4 \\(d=177601976\\) at .*$srcfile1:($bp_location13|$bp_location14).*($bp_location13|$bp_location14)\[\t \]+.*" {
+ pass "run until breakpoint at marker4"
+ }
+ -re "Continuing\\..*Breakpoint \[0-9\]+, $hex in marker4 \\(d=177601976\\) at .*$srcfile1:($bp_location13|$bp_location14).*($bp_location13|$bp_location14)\[\t \]+.*" {
+ xfail "run until breakpoint at marker4"
+ }
+ -re "$gdb_prompt $" {
+ fail "run until breakpoint at marker4"
+ }
+ timeout {
+ fail "(timeout) run until breakpoint at marker4"
+ }
+}

View File

@ -0,0 +1,511 @@
gdb/
2009-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
Transparent GNU-IFUNCs support.
* elfread.c (record_minimal_symbol): Apply also for mst_text_gnu_ifunc.
(elf_symtab_read): Set also mst_text_gnu_ifunc.
* gdbtypes.c (init_type): Support TYPE_FLAG_GNU_IFUNC.
(gdbtypes_post_init): Initialize builtin_func_func_ptr.
(objfile_type): Initialize nodebug_text_gnu_ifunc_symbol.
* gdbtypes.h (enum type_flag_value <TYPE_FLAG_GNU_IFUNC>)
(TYPE_GNU_IFUNC, struct main_type <flag_gnu_ifunc>)
(struct builtin_type <builtin_func_func_ptr>)
(struct objfile_type <nodebug_text_gnu_ifunc_symbol>): New.
* infcall.c (find_function_addr <TYPE_GNU_IFUNC (ftype)>): New.
* minsyms.c (lookup_minimal_symbol_text, prim_record_minimal_symbol)
(find_solib_trampoline_target): Support also mst_text_gnu_ifunc.
(in_gnu_ifunc_stub): New.
* parse.c (write_exp_msymbol <mst_text_gnu_ifunc>): New.
* solib-svr4.c (svr4_in_dynsym_resolve_code): Call also
in_gnu_ifunc_stub.
* symmisc.c (dump_msymbols <mst_text_gnu_ifunc>): New.
* symtab.c (search_symbols): Support also mst_text_gnu_ifunc.
* symtab.h (enum minimal_symbol_type <mst_text_gnu_ifunc>)
(in_gnu_ifunc_stub): New.
* linespec.c: Include infcall.h.
(minsym_found <MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc>): New.
gdb/testsuite/
2009-11-24 Jan Kratochvil <jan.kratochvil@redhat.com>
Transparent GNU-IFUNCs support.
* gdb.base/gnu-ifunc-lib.c, gdb.base/gnu-ifunc.c,
gdb.base/gnu-ifunc.exp: New.
Index: gdb-7.0/gdb/elfread.c
===================================================================
--- gdb-7.0.orig/gdb/elfread.c 2009-11-25 10:24:45.000000000 +0100
+++ gdb-7.0/gdb/elfread.c 2009-11-25 10:25:50.000000000 +0100
@@ -168,7 +168,8 @@ record_minimal_symbol (char *name, CORE_
{
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- if (ms_type == mst_text || ms_type == mst_file_text)
+ if (ms_type == mst_text || ms_type == mst_file_text
+ || ms_type == mst_text_gnu_ifunc)
address = gdbarch_smash_text_address (gdbarch, address);
return prim_record_minimal_symbol_and_info
@@ -373,7 +374,10 @@ elf_symtab_read (struct objfile *objfile
{
if (sym->flags & (BSF_GLOBAL | BSF_WEAK))
{
- ms_type = mst_text;
+ if (sym->flags & BSF_GNU_INDIRECT_FUNCTION)
+ ms_type = mst_text_gnu_ifunc;
+ else
+ ms_type = mst_text;
}
else if ((sym->name[0] == '.' && sym->name[1] == 'L')
|| ((sym->flags & BSF_LOCAL)
Index: gdb-7.0/gdb/gdbtypes.c
===================================================================
--- gdb-7.0.orig/gdb/gdbtypes.c 2009-11-25 10:24:47.000000000 +0100
+++ gdb-7.0/gdb/gdbtypes.c 2009-11-25 10:24:56.000000000 +0100
@@ -1904,6 +1904,8 @@ init_type (enum type_code code, int leng
TYPE_NOTTEXT (type) = 1;
if (flags & TYPE_FLAG_FIXED_INSTANCE)
TYPE_FIXED_INSTANCE (type) = 1;
+ if (flags & TYPE_FLAG_GNU_IFUNC)
+ TYPE_GNU_IFUNC (type) = 1;
if (name)
TYPE_NAME (type) = obsavestring (name, strlen (name),
@@ -3762,6 +3764,8 @@ gdbtypes_post_init (struct gdbarch *gdba
= lookup_pointer_type (builtin_type->builtin_void);
builtin_type->builtin_func_ptr
= lookup_pointer_type (lookup_function_type (builtin_type->builtin_void));
+ builtin_type->builtin_func_func_ptr
+ = lookup_pointer_type (lookup_function_type (builtin_type->builtin_func_ptr));
/* This type represents a GDB internal function. */
builtin_type->internal_fn
@@ -3878,6 +3882,11 @@ objfile_type (struct objfile *objfile)
"<text variable, no debug info>", objfile);
TYPE_TARGET_TYPE (objfile_type->nodebug_text_symbol)
= objfile_type->builtin_int;
+ objfile_type->nodebug_text_gnu_ifunc_symbol
+ = init_type (TYPE_CODE_FUNC, 1, TYPE_FLAG_GNU_IFUNC,
+ "<text gnu-ifunc variable, no debug info>", objfile);
+ TYPE_TARGET_TYPE (objfile_type->nodebug_text_gnu_ifunc_symbol)
+ = objfile_type->nodebug_text_symbol;
objfile_type->nodebug_data_symbol
= init_type (TYPE_CODE_INT,
gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, 0,
Index: gdb-7.0/gdb/gdbtypes.h
===================================================================
--- gdb-7.0.orig/gdb/gdbtypes.h 2009-11-25 10:24:48.000000000 +0100
+++ gdb-7.0/gdb/gdbtypes.h 2009-11-25 10:25:17.000000000 +0100
@@ -187,6 +187,7 @@ enum type_flag_value
TYPE_FLAG_FIXED_INSTANCE = (1 << 15),
TYPE_FLAG_STUB_SUPPORTED = (1 << 16),
TYPE_FLAG_NOTTEXT = (1 << 17),
+ TYPE_FLAG_GNU_IFUNC = (1 << 18),
/* Used for error-checking. */
TYPE_FLAG_MIN = TYPE_FLAG_UNSIGNED
@@ -292,6 +293,12 @@ enum type_instance_flag_value
#define TYPE_NOTTEXT(t) (TYPE_MAIN_TYPE (t)->flag_nottext)
+/* Currently used only for TYPE_CODE_FUNC where specifies the real function
+ address is returned by this function call. TYPE_TARGET_TYPE determines the
+ final returned function type to be presented to user. */
+
+#define TYPE_GNU_IFUNC(t) (TYPE_MAIN_TYPE (t)->flag_gnu_ifunc)
+
/* Type owner. If TYPE_OBJFILE_OWNED is true, the type is owned by
the objfile retrieved as TYPE_OBJFILE. Otherweise, the type is
owned by an architecture; TYPE_OBJFILE is NULL in this case. */
@@ -427,6 +434,7 @@ struct main_type
unsigned int flag_vector : 1;
unsigned int flag_stub_supported : 1;
unsigned int flag_nottext : 1;
+ unsigned int flag_gnu_ifunc : 1;
unsigned int flag_fixed_instance : 1;
unsigned int flag_objfile_owned : 1;
unsigned int flag_discardable : 1;
@@ -1144,6 +1152,10 @@ struct builtin_type
(*) () can server as a generic function pointer. */
struct type *builtin_func_ptr;
+ /* `pointer to function returning pointer to function (returning void)' type.
+ The final void return type is not significant for it. */
+ struct type *builtin_func_func_ptr;
+
/* Special-purpose types. */
@@ -1186,6 +1198,7 @@ struct objfile_type
/* Types used for symbols with no debug information. */
struct type *nodebug_text_symbol;
+ struct type *nodebug_text_gnu_ifunc_symbol;
struct type *nodebug_data_symbol;
struct type *nodebug_unknown_symbol;
struct type *nodebug_tls_symbol;
Index: gdb-7.0/gdb/infcall.c
===================================================================
--- gdb-7.0.orig/gdb/infcall.c 2009-11-25 10:24:45.000000000 +0100
+++ gdb-7.0/gdb/infcall.c 2009-11-25 10:24:56.000000000 +0100
@@ -286,6 +286,27 @@ find_function_addr (struct value *functi
else
error (_("Invalid data type for function to be called."));
+ if (TYPE_GNU_IFUNC (ftype))
+ {
+ struct type *func_func_ptr;
+
+ funaddr += gdbarch_deprecated_function_start_offset (gdbarch);
+
+ /* Cast FUNADDR to drop TYPE_GNU_IFUNC and being able to call gnu-ifunc
+ FUNADDR without causing deadlock by this block of code. */
+
+ func_func_ptr = builtin_type (gdbarch)->builtin_func_func_ptr;
+ function = value_from_pointer (func_func_ptr, funaddr);
+
+ /* gnu-ifuncs have no arguments. */
+ function = call_function_by_hand (function, 0, NULL);
+
+ funaddr = value_as_address (function);
+
+ /* This is `int' as the return type of the final function. */
+ value_type = TYPE_TARGET_TYPE (value_type);
+ }
+
if (retval_type != NULL)
*retval_type = value_type;
return funaddr + gdbarch_deprecated_function_start_offset (gdbarch);
Index: gdb-7.0/gdb/linespec.c
===================================================================
--- gdb-7.0.orig/gdb/linespec.c 2009-11-25 10:24:45.000000000 +0100
+++ gdb-7.0/gdb/linespec.c 2009-11-25 10:24:56.000000000 +0100
@@ -40,6 +40,7 @@
#include "interps.h"
#include "mi/mi-cmds.h"
#include "target.h"
+#include "infcall.h"
/* We share this one with symtab.c, but it is not exported widely. */
@@ -1875,6 +1876,22 @@ minsym_found (int funfirstline, struct m
pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
values.sals[0].pc,
&current_target);
+
+ /* Call gnu-ifunc to resolve breakpoint at its returned function. */
+ if (MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
+ {
+ struct type *func_func_ptr;
+ struct value *function;
+
+ func_func_ptr = builtin_type (gdbarch)->builtin_func_func_ptr;
+ function = value_from_pointer (func_func_ptr, pc);
+
+ /* gnu-ifuncs have no arguments. */
+ function = call_function_by_hand (function, 0, NULL);
+
+ pc = value_as_address (function);
+ }
+
if (pc != values.sals[0].pc)
values.sals[0] = find_pc_sect_line (pc, NULL, 0);
Index: gdb-7.0/gdb/minsyms.c
===================================================================
--- gdb-7.0.orig/gdb/minsyms.c 2009-11-25 10:24:47.000000000 +0100
+++ gdb-7.0/gdb/minsyms.c 2009-11-25 10:24:56.000000000 +0100
@@ -331,8 +331,9 @@ lookup_minimal_symbol_text (const char *
msymbol = msymbol->hash_next)
{
if (strcmp (SYMBOL_LINKAGE_NAME (msymbol), name) == 0 &&
- (MSYMBOL_TYPE (msymbol) == mst_text ||
- MSYMBOL_TYPE (msymbol) == mst_file_text))
+ (MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc
+ || MSYMBOL_TYPE (msymbol) == mst_file_text))
{
switch (MSYMBOL_TYPE (msymbol))
{
@@ -699,6 +700,16 @@ lookup_minimal_symbol_by_pc (CORE_ADDR p
{
return lookup_minimal_symbol_by_pc_section (pc, NULL);
}
+
+/* Return non-zero iff PC is in function implementing gnu-ifunc selection. */
+
+int
+in_gnu_ifunc_stub (CORE_ADDR pc)
+{
+ struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (pc);
+
+ return msymbol && MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc;
+}
/* Return leading symbol character for a BFD. If BFD is NULL,
@@ -738,6 +749,7 @@ prim_record_minimal_symbol (const char *
switch (ms_type)
{
case mst_text:
+ case mst_text_gnu_ifunc:
case mst_file_text:
case mst_solib_trampoline:
section = SECT_OFF_TEXT (objfile);
@@ -1184,7 +1196,8 @@ find_solib_trampoline_target (struct fra
{
ALL_MSYMBOLS (objfile, msymbol)
{
- if (MSYMBOL_TYPE (msymbol) == mst_text
+ if ((MSYMBOL_TYPE (msymbol) == mst_text
+ || MSYMBOL_TYPE (msymbol) == mst_text_gnu_ifunc)
&& strcmp (SYMBOL_LINKAGE_NAME (msymbol),
SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
return SYMBOL_VALUE_ADDRESS (msymbol);
Index: gdb-7.0/gdb/parse.c
===================================================================
--- gdb-7.0.orig/gdb/parse.c 2009-11-25 10:24:47.000000000 +0100
+++ gdb-7.0/gdb/parse.c 2009-11-25 10:26:16.000000000 +0100
@@ -517,6 +517,11 @@ write_exp_msymbol (struct minimal_symbol
write_exp_elt_type (objfile_type (objfile)->nodebug_text_symbol);
break;
+ case mst_text_gnu_ifunc:
+ write_exp_elt_type (objfile_type (objfile)
+ ->nodebug_text_gnu_ifunc_symbol);
+ break;
+
case mst_data:
case mst_file_data:
case mst_bss:
Index: gdb-7.0/gdb/solib-svr4.c
===================================================================
--- gdb-7.0.orig/gdb/solib-svr4.c 2009-11-25 10:24:49.000000000 +0100
+++ gdb-7.0/gdb/solib-svr4.c 2009-11-25 10:26:41.000000000 +0100
@@ -1242,7 +1242,8 @@ svr4_in_dynsym_resolve_code (CORE_ADDR p
{
return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
|| (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
- || in_plt_section (pc, NULL));
+ || in_plt_section (pc, NULL)
+ || in_gnu_ifunc_stub (pc));
}
/* Given an executable's ABFD and target, compute the entry-point
Index: gdb-7.0/gdb/symmisc.c
===================================================================
--- gdb-7.0.orig/gdb/symmisc.c 2009-11-25 10:24:47.000000000 +0100
+++ gdb-7.0/gdb/symmisc.c 2009-11-25 10:24:56.000000000 +0100
@@ -287,6 +287,9 @@ dump_msymbols (struct objfile *objfile,
case mst_text:
ms_type = 'T';
break;
+ case mst_text_gnu_ifunc:
+ ms_type = 'i';
+ break;
case mst_solib_trampoline:
ms_type = 'S';
break;
Index: gdb-7.0/gdb/symtab.c
===================================================================
--- gdb-7.0.orig/gdb/symtab.c 2009-11-25 10:24:47.000000000 +0100
+++ gdb-7.0/gdb/symtab.c 2009-11-25 10:24:56.000000000 +0100
@@ -3155,7 +3155,7 @@ search_symbols (char *regexp, domain_enu
{mst_file_data, mst_solib_trampoline, mst_abs, mst_unknown};
static enum minimal_symbol_type types4[]
=
- {mst_file_bss, mst_text, mst_abs, mst_unknown};
+ {mst_file_bss, mst_text_gnu_ifunc, mst_abs, mst_unknown};
enum minimal_symbol_type ourtype;
enum minimal_symbol_type ourtype2;
enum minimal_symbol_type ourtype3;
Index: gdb-7.0/gdb/symtab.h
===================================================================
--- gdb-7.0.orig/gdb/symtab.h 2009-11-25 10:24:45.000000000 +0100
+++ gdb-7.0/gdb/symtab.h 2009-11-25 10:24:56.000000000 +0100
@@ -275,6 +275,8 @@ enum minimal_symbol_type
{
mst_unknown = 0, /* Unknown type, the default */
mst_text, /* Generally executable instructions */
+ mst_text_gnu_ifunc, /* Executable code returning address
+ of executable code */
mst_data, /* Generally initialized data */
mst_bss, /* Generally uninitialized data */
mst_abs, /* Generally absolute (nonrelocatable) */
@@ -1149,6 +1151,8 @@ extern struct minimal_symbol *lookup_min
extern struct minimal_symbol *lookup_minimal_symbol_by_pc (CORE_ADDR);
+extern int in_gnu_ifunc_stub (CORE_ADDR pc);
+
extern struct minimal_symbol
*lookup_minimal_symbol_by_pc_section (CORE_ADDR, struct obj_section *);
Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc-lib.c 2009-11-25 10:24:56.000000000 +0100
@@ -0,0 +1,45 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <assert.h>
+
+typedef int (*final_t) (int arg);
+
+static int
+final (int arg)
+{
+ return arg + 1;
+}
+
+static volatile int gnu_ifunc_initialized;
+
+void
+gnu_ifunc_pre (void)
+{
+ assert (!gnu_ifunc_initialized);
+}
+
+final_t gnu_ifuncX (void) asm ("gnu_ifunc");
+asm (".type gnu_ifunc, @gnu_indirect_function");
+
+final_t
+gnu_ifuncX (void)
+{
+ gnu_ifunc_initialized = 1;
+
+ return final;
+}
Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.c 2009-11-25 10:24:56.000000000 +0100
@@ -0,0 +1,36 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2009 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 <assert.h>
+
+extern int gnu_ifunc (int arg);
+extern void gnu_ifunc_pre (void);
+
+int
+main (void)
+{
+ int i;
+
+ gnu_ifunc_pre ();
+
+ i = gnu_ifunc (1); /* break-at-call */
+ assert (i == 2);
+
+ gnu_ifunc (2); /* break-at-nextcall */
+
+ return 0; /* break-at-exit */
+}
Index: gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb-7.0/gdb/testsuite/gdb.base/gnu-ifunc.exp 2009-11-25 10:24:56.000000000 +0100
@@ -0,0 +1,72 @@
+# Copyright (C) 2009 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/>.
+
+if {[skip_shlib_tests]} {
+ return 0
+}
+
+set testfile "gnu-ifunc"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+set libfile "${testfile}-lib"
+set libsrc ${libfile}.c
+set lib_so ${objdir}/${subdir}/${libfile}.so
+
+set lib_opts [list debug]
+set exec_opts [list debug shlib=$lib_so]
+
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != ""
+ || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} {
+ untested "Could not compile either $libsrc or $srcfile."
+ return -1
+}
+
+# Start with a fresh gdb.
+
+clean_restart $testfile
+gdb_load_shlibs ${lib_so}
+
+if ![runto_main] then {
+ fail "Can't run to main"
+ return 1;
+}
+
+gdb_breakpoint [gdb_get_line_number "break-at-nextcall"]
+
+gdb_breakpoint [gdb_get_line_number "break-at-call"]
+gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
+
+# Test GDB will automatically indirect the call.
+
+gdb_test "p gnu_ifunc (3)" " = 4"
+
+# Test GDB will skip the gnu_ifunc resolver on first call.
+
+gdb_test "step" "\r\nfinal .*"
+
+# Test GDB will not break before the final chosen implementation.
+
+gdb_continue_to_breakpoint "break-at-nextcall" ".*break-at-nextcall.*"
+
+gdb_breakpoint "gnu_ifunc"
+
+gdb_continue_to_breakpoint "nextcall gnu_ifunc"
+
+gdb_test "frame" "#0 +final \\(.*" "nextcall gnu_ifunc skipped"

View File

@ -14,7 +14,7 @@ Version: 7.0
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
Release: 6%{?_with_upstream:.upstream}%{?dist}
Release: 7%{?_with_upstream:.upstream}%{?dist}
License: GPLv3+
Group: Development/Debuggers
@ -371,6 +371,12 @@ Patch383: gdb-bz528668-symfile-sepcrc.patch
Patch384: gdb-bz528668-symfile-cleanup.patch
Patch385: gdb-bz528668-symfile-multi.patch
# Support GNU IFUNCs - indirect functions (BZ 539590).
Patch387: gdb-bz539590-gnu-ifunc.patch
# Fix bp conditionals [bp_location-accel] regression (Phil Muldoon, BZ 538626).
Patch388: gdb-bz538626-bp_location-accel-bp-cond.patch
BuildRequires: ncurses-devel texinfo gettext flex bison expat-devel
Requires: readline
BuildRequires: readline-devel
@ -571,6 +577,8 @@ rm -f gdb/jv-exp.c gdb/m2-exp.c gdb/objc-exp.c gdb/p-exp.c
%patch376 -p1
%patch381 -p1
%patch382 -p1
%patch387 -p1
%patch388 -p1
%patch124 -p1
find -name "*.orig" | xargs rm -f
@ -876,6 +884,11 @@ fi
%endif
%changelog
* Wed Nov 25 2009 Jan Kratochvil <jan.kratochvil@redhat.com> - 7.0-7.fc12
- Support GNU IFUNCs - indirect functions (BZ 539590).
- Fix bp conditionals [bp_location-accel] regression (Phil Muldoon, BZ 538626).
- Fix missed breakpoint location [bp_location-accel] regression (upstream).
* Fri Oct 30 2009 Jan Kratochvil <jan.kratochvil@redhat.com> - 7.0-6
- Fix missing zlib-devel BuildRequires to support compressed DWARF sections.
- Include post-7.0 FSF GDB fixes.