gdb/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Sun, 9 Oct 2011 19:29:11 +0000 (19:29 +0000)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Sun, 9 Oct 2011 19:29:11 +0000 (19:29 +0000)
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
gdb/dwarf2loc.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/amd64-entry-value.cc
gdb/testsuite/gdb.arch/amd64-entry-value.exp

index 76e62f2256ce7b6b95434f20e35d7442884312ca..3c11113f1bd75f4916785d38596f4e029e060792 100644 (file)
@@ -1,3 +1,9 @@
+2011-10-09  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       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  <jan.kratochvil@redhat.com>
 
        Recognize virtual tail call frames.
index 1661d9fa17f930a7cbf70a865b51d60d867cb12b..fef0c6b26a210ae7648dfb3690c6a1bf5a04329d 100644 (file)
@@ -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];
index ce9800c3d163b5595e7113031215fea47d180114..86fe0e9a43d29426d31c9e1ab32ce5b3754c7298 100644 (file)
@@ -1,3 +1,11 @@
+2011-10-09  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       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  <jan.kratochvil@redhat.com>
 
        Recognize virtual tail call frames.
index 9e09c8a3efc43f9c7e39cd90bd605aa52170b4dc..44b7564c680fc917c27723ae174a4c9e40078de9 100644 (file)
@@ -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;
 }
index 6abc7ab9d9ce9527b0a5ea567b39d46daf10b966..fdf8040b86ad27fd115b6d9c93ff8dfb7be17dcb 100644 (file)
@@ -73,3 +73,16 @@ gdb_continue_to_breakpoint "ambiguous: breakhere"
 
 gdb_test "bt" "^bt\r\n#0 +d \\(i=<optimized out>, j=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in amb_z \\(i=<optimized out>\\)\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in amb_y \\(i=<optimized out>\\)\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in amb_x \\(i=<optimized out>\\)\[^\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=<optimized out>, j=<optimized out>\\)\[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in self \\(i=<optimized out>\\)\[^\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"