This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] [SH] Prologue skipping if there is none


Hi!

(No specific SH maintainer CCed as none is listed in MAINTAINERS.)


First, for SH GNU/Linux, when running the testsuite via gdbserver on
pristine sources, I'm getting a large number of ERRORs, in the 350s.  Is
that normal or at least known?  They're basically all of the kind
``ERROR: Process no longer exists'', and then follow-up errors until the
end of the specific testcase.  From a very quick glance, they all seem to
be happening after the testcase has instructed GDB to invoke a function,
such as:

    (gdb) PASS: gdb.cp/classes.exp: print g_D.p
    call class_param.Aptr_a (&g_A)
    ERROR: Process no longer exists
    UNRESOLVED: gdb.cp/classes.exp: call class_param.Aptr_a (&g_A)
    ERROR: Couldn't send call class_param.Aptr_x (&g_A) to GDB.

This probably suggests where to begin looking unless that's know already.


The prologue skipping issue is that GDB fails to place breakpoints
correctly at the beginning of a function -- such as for ``break main'' --
for the case that there is no prologue in that function.  In such a case,
it will currently place the breakpoint *after* the first source code line
instead of at its beginning, for example ``break main'' for
gdb.base/arrayidx.c will put a breakpoint on line 25 instead of 23:

        20  int
        21  main (void)
        22  {
        23    array[0] = 5;
        24  
        25    return 0;
        26  }

    Dump of assembler code for function main:
       0x00400600 <+0>:     mov.l   0x400610 <main+16>,r1   ! 0x41083c <array>
       0x00400602 <+2>:     mov     #5,r2
       0x00400604 <+4>:     mov.l   r2,@r1
       0x00400606 <+6>:     mov     #0,r1
       0x00400608 <+8>:     mov     r1,r0
       0x0040060a <+10>:    rts
       0x0040060c <+12>:    nop
       0x0040060e <+14>:    nop
       0x00400610 <+16>:    mov.b   @(r0,r3),r8
       0x00400612 <+18>:    .word 0x0041
    End of assembler dump.

Crude log of debugging the SH GNU/Linux GDB when advising it to ``break
main'':

    Breakpoint 3, sh_skip_prologue (gdbarch=0x90043c8, start_pc=4195840)

OK, this is start_pc == 0x400600.

    715       if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
    Value returned is $3 = 1
    (gdb) print/x func_addr 
    $4 = 0x400600
    (gdb) print/x func_end
    $5 = 0x400614

OK.

    2137      return find_pc_sect_line (pc, section, notcurrent);
    Value returned is $8 = {pspace = 0x8fed340, symtab = 0x901a21c, section = 0x0, line = 23, pc = 4195840, end = 4195846, explicit_pc = 0, explicit_line = 0}

OK, still $8->pc == 0x400600, and $8->end == 0x400606, and these are
attached to line 23, ``array[0] = 5;''.

    after_prologue (pc=4195840) at /scratch/tschwing/ST_sh-linux-gnu-lite/obj/gdb-src-2012.03-999999-sh-linux-gnu-i686-pc-linux-gnu/gdb/sh-tdep.c:726
    726       if (sal.end < func_end)
    (gdb) n
    727         return sal.end;
    (gdb) print/x sal.end
    $9 = 0x400606

Wrong, because we now have not skipped the prologue, but the first real
instruction.


Anyway, apart from the 350 ERRORs (with and without my patch), there is a
clear tendency of improvement, and no regressions:

    Progressions and removed failures:
    
    FAIL -> PASS: default/gdb.sum:gdb.base/arrayidx.exp: Print array with array-indexes off
    FAIL -> PASS: default/gdb.sum:gdb.base/arrayidx.exp: Print array with array-indexes on
    FAIL -> PASS: default/gdb.sum:gdb.base/break-always.exp: continue to breakpoint: bar
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-td
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-te
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-tld
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-tll
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for finish; return call-sc-ts
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-td
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-te
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-tld
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-tll
    FAIL -> PASS: default/gdb.sum:gdb.base/call-sc.exp: advance to fun for return; return call-sc-ts
    FAIL -> PASS: default/gdb.sum:gdb.base/gdb11531.exp: watchpoint variable triggers at next
    FAIL -> PASS: default/gdb.sum:gdb.base/reread.exp: breakpoint foo in first file
    FAIL -> PASS: default/gdb.sum:gdb.base/reread.exp: run to foo()
    FAIL -> PASS: default/gdb.sum:gdb.base/return.exp: continue to return of -5
    FAIL -> PASS: default/gdb.sum:gdb.base/return.exp: continue to return of -5.0
    FAIL -> PASS: default/gdb.sum:gdb.base/return2.exp: void function returned successfully
    FAIL -> PASS: default/gdb.sum:gdb.base/scope.exp: print funclocal at bar
    FAIL -> PASS: default/gdb.sum:gdb.base/scope.exp: print funclocal_bss at bar
    FAIL -> PASS: default/gdb.sum:gdb.base/skip.exp: step after deleting 1 (3)
    FAIL -> PASS: default/gdb.sum:gdb.base/skip.exp: step after disabling 3 (5)
    FAIL -> PASS: default/gdb.sum:gdb.base/skip.exp: step after enable 3 (3)
    FAIL -> PASS: default/gdb.sum:gdb.base/step-resume-infcall.exp: step
    FAIL -> PASS: default/gdb.sum:gdb.base/step-test.exp: step into
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-td
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-tld
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-tll
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 1 structs-ts
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tc-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tc-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tf-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-ti-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for finish; return 2 structs-tl-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-td
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-tld
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-tll
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 1 structs-ts
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tc-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tc-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tf
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tf-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-ti
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-ti-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tl
    FAIL -> PASS: default/gdb.sum:gdb.base/structs.exp: advance to fun<n> for return; return 2 structs-tl-tc
    FAIL -> PASS: default/gdb.sum:gdb.base/value-double-free.exp: continue
    FAIL -> PASS: default/gdb.sum:gdb.base/watch-cond-infcall.exp: sw: continue
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint hit count is 2
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint hit count is 3
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint hit count is 4
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint hit count is 5
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint ival1 hit count is 2
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: Watchpoint ival1 hit count is 3
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint hit, fifth time
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint hit, fourth time
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint hit, second time
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint hit, third time
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint ival1 hit, second time
    FAIL -> PASS: default/gdb.sum:gdb.base/watchpoints.exp: watchpoint ival1 hit, third time
    FAIL -> PASS: default/gdb.sum:gdb.cp/expand-sals.exp: continue to breakpoint: func
    FAIL -> PASS: default/gdb.sum:gdb.cp/expand-sals.exp: continue to breakpoint: next caller func
    FAIL -> PASS: default/gdb.sum:gdb.cp/extern-c.exp: continue to breakpoint: c_func
    FAIL -> PASS: default/gdb.sum:gdb.cp/extern-c.exp: continue to breakpoint: c_funcs_1
    FAIL -> PASS: default/gdb.sum:gdb.cp/extern-c.exp: continue to breakpoint: c_funcs_2
    FAIL -> PASS: default/gdb.sum:gdb.cp/namespace-nested-import.exp: print C::x
    FAIL -> PASS: default/gdb.sum:gdb.linespec/linespec.exp: set breakpoint at lspec.cc instance of NameSpace::overload
    FAIL -> PASS: default/gdb.sum:gdb.linespec/linespec.exp: set breakpoint at specific instance of NameSpace::overload
    Removed FAIL: default/gdb.sum:gdb.base/chng-syms.exp: continue until exit at breakpoint first time through (the program is no longer running)
    Removed FAIL: default/gdb.sum:gdb.base/chng-syms.exp: running to stop_here first time

The patch is modeled after what most of all other targets are doing for
getting past the prologue (if there is one), and have been changed
accordingly before, such as in Git commits
93afe5e97284a3d460c19f72f096c4f561673e48,
42294ab40a733dbca9258929d0a6ec72e3059fbc,
5c176a3a457b50fb047477d5e32bdde5ca2dd267, for example.

Probably the very same patch should be applied to sh64-tdep.c, but I
don't have any possibility for testing that.  Shall I to do that change
``blindly''?

2012-02-15  Thomas Schwinge  <thomas@codesourcery.com>

	* sh-tdep.c (sh_skip_prologue): Use skip_prologue_using_sal.
	(after_prologue): Remove.

Index: gdb/sh-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sh-tdep.c,v
retrieving revision 1.236
diff -u -p -r1.236 sh-tdep.c
--- gdb/sh-tdep.c	28 Jan 2012 18:08:20 -0000	1.236
+++ gdb/sh-tdep.c	15 Feb 2012 13:08:39 -0000
@@ -697,50 +697,25 @@ sh_analyze_prologue (struct gdbarch *gdb
 }
 
 /* Skip any prologue before the guts of a function.  */
-
-/* Skip the prologue using the debug information.  If this fails we'll
-   fall back on the 'guess' method below.  */
-static CORE_ADDR
-after_prologue (CORE_ADDR pc)
-{
-  struct symtab_and_line sal;
-  CORE_ADDR func_addr, func_end;
-
-  /* If we can not find the symbol in the partial symbol table, then
-     there is no hope we can determine the function's start address
-     with this code.  */
-  if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
-    return 0;
-
-  /* Get the line associated with FUNC_ADDR.  */
-  sal = find_pc_line (func_addr, 0);
-
-  /* There are only two cases to consider.  First, the end of the source line
-     is within the function bounds.  In that case we return the end of the
-     source line.  Second is the end of the source line extends beyond the
-     bounds of the current function.  We need to use the slow code to
-     examine instructions in that case.  */
-  if (sal.end < func_end)
-    return sal.end;
-  else
-    return 0;
-}
-
 static CORE_ADDR
 sh_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
 {
-  CORE_ADDR pc;
+  CORE_ADDR pc, func_addr;
   struct sh_frame_cache cache;
 
   /* See if we can determine the end of the prologue via the symbol table.
      If so, then return either PC, or the PC after the prologue, whichever
      is greater.  */
-  pc = after_prologue (start_pc);
+  if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc
+        = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+        return max (start_pc, post_prologue_pc);
+    }
 
-  /* If after_prologue returned a useful address, then use it.  Else
-     fall back on the instruction skipping code.  */
-  if (pc)
-    return max (pc, start_pc);
+   /* Can't determine prologue from the symbol table, need to examine
+      instructions.  */
 
   cache.sp_offset = -4;
   pc = sh_analyze_prologue (gdbarch, start_pc, (CORE_ADDR) -1, &cache, 0);


GrÃÃe,
 Thomas

Attachment: pgp00000.pgp
Description: PGP signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]