Bug 44189 - PIC compilation on ARM screws up DWARF lineinfo in function prologue
Summary: PIC compilation on ARM screws up DWARF lineinfo in function prologue
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-debug
Depends on:
Blocks:
 
Reported: 2010-05-18 11:32 UTC by Gergely Risko
Modified: 2010-09-08 10:03 UTC (History)
3 users (show)

See Also:
Host: i486-linux-gnu
Target: arm-linux-gnueabi
Build: i486-linux-gnu
Known to work:
Known to fail: 4.6.0 4.5.3 4.4.5
Last reconfirmed: 2010-09-08 09:12:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Gergely Risko 2010-05-18 11:32:30 UTC
SVN revision: 159525

Configure line: ../gcc-svn/configure --prefix=/tmp/gcc-cross/gcc-svn-bin/ --target=arm-linux-gnueabi --with-headers=/tmp/gcc-cross/gcc-svn-bin/arm-linux-gnueabi/include --with-libs=/tmp/gcc-cross/gcc-svn-bin/arm-linux-gnueabi/lib/ --enable-threads=posix --enable-shared --enable-languages=c

Command line: arm-linux-gnueabi-gcc -fpic -Wall -g -O0 -S -o - -c test.c

No errors/warnings from the compiler.

Input program, test.c:
int ext_var;
void ext_fn(int x);

void bad(int x) {
	ext_fn(ext_var);
}

The resulting assembly of the bad function:
bad:
.LFB0:
	.file 1 "test.c"
	.loc 1 4 0
	.cfi_startproc
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	stmfd	sp!, {fp, lr}
.LCFI0:
	.cfi_def_cfa_offset 8
	add	fp, sp, #4
	.cfi_offset 14, -4
	.cfi_offset 11, -8
.LCFI1:
	.cfi_def_cfa 11, 4
	sub	sp, sp, #8
	.loc 1 5 0                      <---------- should not be here
	ldr	r3, .L2
.LPIC0:
	add	r3, pc, r3
	.loc 1 4 0                      <---------- should not be here
	str	r0, [fp, #-8]
	.loc 1 5 0
	ldr	r2, .L2+4
	ldr	r3, [r3, r2]
	ldr	r3, [r3, #0]
	mov	r0, r3
	bl	ext_fn(PLT)
	.loc 1 6 0
	sub	sp, fp, #4
	ldmfd	sp!, {fp, pc}

I have marked the .loc directives that cause the problems for me, because of those GDB stops too early (when the function parameters are not stored yet) and because of this GDB command `bt' shows bad parameters for the top frame.  The `next' command is confused too, of course.  Furthermore, objdump -S is also confused, shows the function header twice:
00000000 <bad>:
int ext_var;
void ext_fn(int x);

void bad(int x) {
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
	ext_fn(ext_var);
   c:	e59f3020 	ldr	r3, [pc, #32]	; 34 <bad+0x34>
  10:	e08f3003 	add	r3, pc, r3
int ext_var;
void ext_fn(int x);

void bad(int x) {
  14:	e50b0008 	str	r0, [fp, #-8]
	ext_fn(ext_var);
  18:	e59f2018 	ldr	r2, [pc, #24]	; 38 <bad+0x38>
  1c:	e7933002 	ldr	r3, [r3, r2]
  20:	e5933000 	ldr	r3, [r3]
  24:	e1a00003 	mov	r0, r3
  28:	ebfffffe 	bl	0 <ext_fn>
}
  2c:	e24bd004 	sub	sp, fp, #4
  30:	e8bd8800 	pop	{fp, pc}
  34:	0000001c 	.word	0x0000001c
  38:	00000000 	.word	0x00000000

To my understanding, the issue is caused by the "on-demand" generation of the pic register loading logic for the function prologue.  That part of the prologue gets line number info of the statement that causes the generation.

My quick fix is:
Index: gcc/config/arm/arm.c
===================================================================
--- gcc/config/arm/arm.c	(revision 159525)
+++ gcc/config/arm/arm.c	(working copy)
@@ -4897,13 +4897,23 @@
 	     process.  */
 	  if (current_ir_type () != IR_GIMPLE || currently_expanding_to_rtl)
 	    {
+	      /* We want the PIC register loading instructions to have
+		 the same line number info as the function
+		 prologue. */
+	      location_t saved_curr_loc = get_curr_insn_source_location ();
+	      set_curr_insn_source_location (cfun->function_start_locus);
+
 	      crtl->uses_pic_offset_table = 1;
 	      start_sequence ();
 
 	      arm_load_pic_register (0UL);
 
 	      seq = get_insns ();
 	      end_sequence ();
+
+	      set_curr_insn_source_location (saved_curr_loc);
+
 	      /* We can be called during expansion of PHI nodes, where
 	         we can't yet emit instructions directly in the final
 		 insn stream.  Queue the insns on the entry edge, they will

This patch solves the issue for me.

This is the first time I try to do anything internally with GCC, so please forgive my mistakes and show me the better way to fix the issue.
Comment 1 Gergely Risko 2010-05-18 19:17:29 UTC
Added wrong-debug as a keyword.
Comment 2 Gergely Risko 2010-05-21 08:06:50 UTC
Based on code in cfgexpand.c (search for start_locus), my patch
should probably use something like this for setting the location:
              /* Eventually, all FEs should explicitly set function_start_locus.  */
              if (cfun->function_start_locus == UNKNOWN_LOCATION)
                set_curr_insn_source_location
                  (DECL_SOURCE_LOCATION (current_function_decl));
              else
                set_curr_insn_source_location (cfun->function_start_locus);

I am not sure if there are still frontends that do not set function_start_locus.

And probably this functionality should be moved to a function and we should only call that function from two places.
Comment 3 Ian Bolton 2010-09-08 09:12:00 UTC
Thanks for raising this bug, Gergely, and suggesting a patch.  I've moved the bug to the NEW state, so if you want to post your patch to the gcc-patches list, then you will hopefully get some feedback on it there and we will be able to work towards an approved fix.