From 2d6c5dc2c7f35f46bdbcee6ea442a97ae880db4b Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Sun, 9 Oct 2011 19:29:11 +0000 Subject: [PATCH] gdb/ Protect entry values against self tail calls. * dwarf2loc.c (VEC (CORE_ADDR), func_verify_no_selftailcall): New. (dwarf_expr_dwarf_reg_entry_value): Call func_verify_no_selftailcall. gdb/testsuite/ Protect entry values against self tail calls. * gdb.arch/amd64-entry-value.cc (self2, self): New. (main): Call self. * gdb.arch/amd64-entry-value.exp (self: breakhere, self: bt) (set debug entry-values 1, self: bt debug entry-values): New tests. --- gdb/ChangeLog | 6 ++ gdb/dwarf2loc.c | 85 ++++++++++++++++++++++++++++ gdb/testsuite/ChangeLog | 8 +++ gdb/testsuite/gdb.arch/amd64-entry-value.cc | 24 ++++++++ gdb/testsuite/gdb.arch/amd64-entry-value.exp | 13 +++++ 5 files changed, 136 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 76e62f2..3c11113 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,11 @@ 2011-10-09 Jan Kratochvil + Protect entry values against self tail calls. + * dwarf2loc.c (VEC (CORE_ADDR), func_verify_no_selftailcall): New. + (dwarf_expr_dwarf_reg_entry_value): Call func_verify_no_selftailcall. + +2011-10-09 Jan Kratochvil + Recognize virtual tail call frames. * Makefile.in (SFILES): Add dwarf2-frame-tailcall.c. (HFILES_NO_SRCDIR): Add dwarf2-frame-tailcall.h. diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 1661d9f..fef0c6b 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -422,6 +422,87 @@ func_addr_to_tail_call_list (struct gdbarch *gdbarch, CORE_ADDR addr) return sym; } +/* Define VEC (CORE_ADDR) functions. */ +DEF_VEC_I (CORE_ADDR); + +/* Verify function with entry point exact address ADDR can never call itself + via its tail calls (incl. transitively). Throw NO_ENTRY_VALUE_ERROR if it + can call itself via tail calls. + + If a funtion can tail call itself its entry value based parameters are + unreliable. There is no verification whether the value of some/all + parameters is unchanged through the self tail call, we expect if there is + a self tail call all the parameters can be modified. */ + +static void +func_verify_no_selftailcall (struct gdbarch *gdbarch, CORE_ADDR verify_addr) +{ + struct obstack addr_obstack; + struct cleanup *old_chain; + CORE_ADDR addr; + + /* Track here CORE_ADDRs which were already visited. */ + htab_t addr_hash; + + /* The verification is completely unordered. Track here function addresses + which still need to be iterated. */ + VEC (CORE_ADDR) *todo = NULL; + + obstack_init (&addr_obstack); + old_chain = make_cleanup_obstack_free (&addr_obstack); + addr_hash = htab_create_alloc_ex (64, core_addr_hash, core_addr_eq, NULL, + &addr_obstack, hashtab_obstack_allocate, + NULL); + make_cleanup_htab_delete (addr_hash); + + make_cleanup (VEC_cleanup (CORE_ADDR), &todo); + + VEC_safe_push (CORE_ADDR, todo, verify_addr); + while (!VEC_empty (CORE_ADDR, todo)) + { + struct symbol *func_sym; + struct call_site *call_site; + + addr = VEC_pop (CORE_ADDR, todo); + + func_sym = func_addr_to_tail_call_list (gdbarch, addr); + + for (call_site = TYPE_TAIL_CALL_LIST (SYMBOL_TYPE (func_sym)); + call_site; call_site = call_site->tail_call_next) + { + CORE_ADDR target_addr; + void **slot; + + /* CALLER_FRAME with registers is not available for tail-call jumped + frames. */ + target_addr = call_site_to_target_addr (gdbarch, call_site, NULL); + + if (target_addr == verify_addr) + { + struct minimal_symbol *msym; + + msym = lookup_minimal_symbol_by_pc (verify_addr); + throw_error (NO_ENTRY_VALUE_ERROR, + _("DW_OP_GNU_entry_value resolving has found " + "function \"%s\" at %s can call itself via tail " + "calls"), + msym == NULL ? "???" : SYMBOL_PRINT_NAME (msym), + paddress (gdbarch, verify_addr)); + } + + slot = htab_find_slot (addr_hash, &target_addr, INSERT); + if (*slot == NULL) + { + *slot = obstack_copy (&addr_obstack, &target_addr, + sizeof (target_addr)); + VEC_safe_push (CORE_ADDR, todo, target_addr); + } + } + } + + do_cleanups (old_chain); +} + /* Print user readable form of CALL_SITE->PC to gdb_stdlog. Used only for ENTRY_VALUES_DEBUG. */ @@ -780,6 +861,10 @@ dwarf_expr_reg_to_entry_parameter (struct frame_info *frame, int dwarf_reg, paddress (gdbarch, func_addr)); } + /* No entry value based parameters would be reliable if this function can + call itself via tail calls. */ + func_verify_no_selftailcall (gdbarch, func_addr); + for (iparams = 0; iparams < call_site->parameter_count; iparams++) { parameter = &call_site->parameter[iparams]; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index ce9800c..86fe0e9 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,13 @@ 2011-10-09 Jan Kratochvil + Protect entry values against self tail calls. + * gdb.arch/amd64-entry-value.cc (self2, self): New. + (main): Call self. + * gdb.arch/amd64-entry-value.exp (self: breakhere, self: bt) + (set debug entry-values 1, self: bt debug entry-values): New tests. + +2011-10-09 Jan Kratochvil + Recognize virtual tail call frames. * gdb.arch/amd64-entry-value.cc (c, a, b, amb_z, amb_y, amb_x, amb) (amb_b, amb_a): New. diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.cc b/gdb/testsuite/gdb.arch/amd64-entry-value.cc index 9e09c8a..44b7564 100644 --- a/gdb/testsuite/gdb.arch/amd64-entry-value.cc +++ b/gdb/testsuite/gdb.arch/amd64-entry-value.cc @@ -91,6 +91,29 @@ amb_a (int i) amb_b (i + 1); } +static void __attribute__((noinline, noclone)) self (int i); + +static void __attribute__((noinline, noclone)) +self2 (int i) +{ + self (i); +} + +static void __attribute__((noinline, noclone)) +self (int i) +{ + if (i == 200) + { + /* GCC would inline `self' as `cmovne' without the `self2' indirect. */ + self2 (i + 1); + } + else + { + e (v, v); + d (i + 2, i + 2.5); + } +} + int main () { @@ -100,5 +123,6 @@ main () else b (5, 5.25); amb_a (100); + self (200); return 0; } diff --git a/gdb/testsuite/gdb.arch/amd64-entry-value.exp b/gdb/testsuite/gdb.arch/amd64-entry-value.exp index 6abc7ab..fdf8040 100644 --- a/gdb/testsuite/gdb.arch/amd64-entry-value.exp +++ b/gdb/testsuite/gdb.arch/amd64-entry-value.exp @@ -73,3 +73,16 @@ gdb_continue_to_breakpoint "ambiguous: breakhere" gdb_test "bt" "^bt\r\n#0 +d \\(i=, j=\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in amb_z \\(i=\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in amb_y \\(i=\\)\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in amb_x \\(i=\\)\[^\r\n\]*\r\n#4 +0x\[0-9a-f\]+ in amb_b \\(i=101\\)\[^\r\n\]*\r\n#5 +0x\[0-9a-f\]+ in amb_a \\(i=100\\)\[^\r\n\]*\r\n#6 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \ "ambiguous: bt" + + +# Test self tail calls verification. +# GDB should not print the real value as it is ambiguous. + +gdb_continue_to_breakpoint "self: breakhere" + +gdb_test "bt" "^bt\r\n#0 +d \\(i=, j=\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in self \\(i=\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in main \\(\\)\[^\r\n\]*" \ + "self: bt" + +gdb_test_no_output "set debug entry-values 1" +gdb_test "bt" "DW_OP_GNU_entry_value resolving has found function \"self\\(int\\)\" at 0x\[0-9a-f\]+ can call itself via tail calls\r\n.*" \ + "self: bt debug entry-values" -- 2.7.4