[RFA] Handle sh-elf-gcc scheduling code into a prologue when no debug info present

Fred Fish
2004-02-12T22:05:44Z

For the following test case:

sub1 ()
{
printf ("In sub1\n");
}

sub2 ()
{
printf ("In sub2\n");
}

main ()
{
sub1 ();
sub2 ();
}

sh-elf-gcc with -O2 will schedule the code to call sub1 into the
prologue of main. If the code is compiled WITHOUT debug info, the
prologue scanner in gdb will not stop when it sees the jsr and will
eventually return a pc somewhere after the jsr. For example:

(gdb) br main
Breakpoint 1 at 0x1162
(gdb) x/8i main
0x1158 : mov.l r14,@-r15
0x115a <main+2>: mov.l 0x116c <main+20>,r0 ! 0x1120
0x115c <main+4>: sts.l pr,@-r15
0x115e <main+6>: jsr @r0
0x1160 <main+8>: mov r15,r14
* 0x1162 <main+10>: mov.l 0x1170 <main+24>,r1 ! 0x113c
0x1164 <main+12>: mov r14,r15
0x1166 <main+14>: lds.l @r15+,pr

Note that the breakpoint on main() gets set well after the jsr. When
you set breakpoints at sub1 and sub2 and run the program, you get:

(gdb) run
Starting program: /links1/build/sourceware/gdb/T-sh-elf/gdb/g
Breakpoint 2, 0x00001128 in sub1 ()
(gdb) c
Continuing.
In sub1
Breakpoint 1, 0x00001162 in main ()
(gdb) c
Continuing.
Breakpoint 3, 0x00001144 in sub2 ()
(gdb) c
Continuing.
In sub2
Program exited with code 012.

which is very confusing because it appears that sub1 is called before main!

With the attached patch, the prologue scanner returns the pc of the
jsr instruction, allowing the breakpoint at main to be hit before the
breakpoint at sub1:

(gdb) br main
Breakpoint 1 at 0x115e
(gdb) x/8i main
0x1158 : mov.l r14,@-r15
0x115a <main+2>: mov.l 0x116c <main+20>,r0 ! 0x1120
0x115c <main+4>: sts.l pr,@-r15
* 0x115e <main+6>: jsr @r0
0x1160 <main+8>: mov r15,r14
0x1162 <main+10>: mov.l 0x1170 <main+24>,r1 ! 0x113c
0x1164 <main+12>: mov r14,r15
0x1166 <main+14>: lds.l @r15+,pr
(gdb) br sub1
Breakpoint 2 at 0x1128
(gdb) br sub2
Breakpoint 3 at 0x1144
(gdb) run
Starting program: /links1/build/sourceware/gdb/T-sh-elf/gdb/g
Breakpoint 1, 0x0000115e in main ()
(gdb) c
Continuing.
Breakpoint 2, 0x00001128 in sub1 ()
(gdb) c
Continuing.
In sub1
Breakpoint 3, 0x00001144 in sub2 ()
(gdb) c
Continuing.
In sub2
Program exited with code 012.

It's also useful to note where the breakpoint gets set if you recompile to generate
debugging information:

(gdb) br main
Breakpoint 1 at 0x115a: file g.c, line 13.
(gdb) x/8i main
0x1158 : mov.l r14,@-r15
0x115a <main+2>: mov.l 0x116c <main+20>,r0 ! 0x1120
0x115c <main+4>: sts.l pr,@-r15
0x115e <main+6>: jsr @r0
0x1160 <main+8>: mov r15,r14
0x1162 <main+10>: mov.l 0x1170 <main+24>,r1 ! 0x113c
0x1164 <main+12>: mov r14,r15
0x1166 <main+14>: lds.l @r15+,pr

This patch causes no regressions in the gdb testsuite. Anyone see any
issues with installing it? :-)

-Fred

2004-02-12 Fred Fish <fnf@redhat.com>

* sh-tdep.c (IS_JSR): New macro.
(sh_analyze_prologue): Use IS_JSR to terminate prologue scan.

Index: sh-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sh-tdep.c,v
retrieving revision 1.158
diff -c -p -r1.158 sh-tdep.c
*** sh-tdep.c 11 Feb 2004 15:40:28 -0000 1.158
--- sh-tdep.c 12 Feb 2004 21:16:39 -0000
*************** sh_breakpoint_from_pc (CORE_ADDR *pcptr,
*** 333,338 ****
--- 333,341 ----
#define GET_SOURCE_REG(x) (((x) >> 4) & 0xf)
#define GET_TARGET_REG(x) (((x) >> 8) & 0xf)

+ /* JSR @Rm 0100mmmm00001011 */
+ #define IS_JSR(x) (((x) & 0xf0ff) == 0x400b)
+
/* STS.L PR,@-r15 0100111100100010
r15-4-->r15, PR-->(r15) */
#define IS_STS(x) ((x) == 0x4f22)
*************** sh_analyze_prologue (CORE_ADDR pc, CORE_
*** 530,535 ****
--- 533,552 ----
else
break;
}
+ break;
+ }
+ else if (IS_JSR (inst))
+ {
+ /* We have found a jsr that has been scheduled into the prologue.
+ If we continue the scan and return a pc someplace after this,
+ then setting a breakpoint on this function will cause it to
+ appear to be called after the function it is calling via the
+ jsr, which will be very confusing. Most likely the next
+ instruction is going to be IS_MOV_SP_FP in the delay slot. If
+ so, note that before returning the current pc. */
+ inst = read_memory_integer (pc + 2, 2);
+ if (IS_MOV_SP_FP (inst))
+ cache->uses_fp = 1;
break;
}
#if 0 /* This used to just stop when it found an instruction that