Prologue not set properly for Non-Gcc compilers

Bug #1030813 reported by karthik
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Linaro GDB
Fix Released
Undecided
Unassigned

Bug Description

Dear All,
I'm are trying to use GDB Linaro (7.2) with binary generated from non-Gcc compiler. I'm using clang 3.1 generated compiling the code from LLVM site (http://www.llvm.org/)
In this case when we try to set a breakpoint in a function with float/double arguments GDB is unable to detect the prologue end properly.

The same is reproducible with latest GDB as well.

Please find the example below-

int floater(float a1)
{
int a = a1;
return a;
}
int main()
{
  int a = floater(1);
  return 0;
}

The assembly for this code is attached. When we call --
break floater in GDB the breakpoint is getting set at the start of function instead of 1st executable instruction.

[OUR ANALYSIS]
Upon analysing we found that for non-gcc compilers GDB specifically checks for prologue sequence with few pre recognized instruction set.
File: arm-tdep.c
Function: arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)

In the function arm_skip_prologue GDB calls arm_analyze_prologue which checks for the prologue sequence with predefined register sets. It seems like not all instructions possible in prologue is covered by GDB in this function as several possible prologues can be written, resulting in slightly different stack configuration.

In the example above we added few logs and extracted the object dump-
GDB Logs-

(gdb) b floater
post_prologue_pc is 83c4
analyzed_limit is 83bc
post_prologue_pc is 83c4
analyzed_limit is 83bc

Object Dump -

000083b8 <floater>:
    83b8: e24dd008 sub sp, sp, #8
    83bc: ee000a10 vmov s0, r0
    83c0: e58d0004 str r0, [sp, #4]
    83c4: eebd0ac0 vcvt.s32.f32 s0, s0
    83c8: ed8d0a00 vstr s0, [sp]
    83cc: ee100a10 vmov r0, s0
    83d0: e28dd008 add sp, sp, #8
    83d4: e12fff1e bx lr

As shown in the snippet above GDB is unable to recognize vmov as a valid instruction in Prologue and hence the check

 if (analyzed_limit != post_prologue_pc) in function arm_skip_prologue succeeds and func_addr is returned instead of post_prologue_pc resulting in breakpoint set at the start of function instead of 1st executable instruction.

[FIX AND Query]
I had a query as to if the call to arm_analyze_prologue is required for non-GCC compilers. We already have the prologue end location in post_prologue_pc. Is it not possible to return the same directly?

We modified the code to emit post_prologue_pc irrespective of the return value of arm_analyze_prologue as we have already determined the prologue end properly in post_prologue_pc. After the fix GDB sets breakpoint properly for non-GCC compilers as well.

Modified code -

      if (post_prologue_pc != 0)
 {
    return post_prologue_pc; // Just return post_prologue_pc .
 }

I would like to get few inputs form you all if we can push this fix into GDB trunk.

Files and analysis are attached.

Thanks and Regrds
Karthik V Bhat

Revision history for this message
Michael Hope (michaelh1) wrote :

Hi Karthik. My understanding is that GDB only falls back to prologue parsing if there's no debug information present. As it's a fallback, it doesn't handle every situation and has been tested against GDB best.

Out of interest, could you try it with the latest GDB 7.5 and debug info on?

Revision history for this message
karthik (kv-bhat) wrote :

Hi Michael,
Thanks for your reply. Yes as you suggested the code flow is going into fallback as the check in
file - arm-tdep.c
function - arm_skip_prologue-

if (post_prologue_pc
   && (s == NULL
       || s->producer == NULL
       || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0)
return post_prologue_pc;

Fails for clang/LLVM generated binary as as s->producer will not be "GNU".

We wanted to add support for clang/LLVM in Linaro GDB. Since clang also generates line note before prologue and another after as in case of GCC we can take advantage of the same and skip prologue sequence checking.

We can extend the code above to support clang by-

if (post_prologue_pc
   && (s == NULL
       || s->producer == NULL
       || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0 || strncmp (s->producer, "clang", sizeof ("clang") - 1) == 0))
return post_prologue_pc;

We wanted input from community if we can push this patch through to the trunk.

Awaiting response.
Thanks.

Revision history for this message
Michael Hope (michaelh1) wrote :

Hi Karthik. I like the idea. I recommend doing this first then supporting the fallback method in the future. Does Clang guarantee a line note before and after the prologue in the same way as GCC?

I recommend shifting this discussion to upstream GDB. Once landed there, we can backport it to Linaro GDB if need be.

Ulrich, your thoughts? We should make the prologue parser handle Clang in the future as well.

Revision history for this message
karthik (kv-bhat) wrote :

Hi Michael,
Yes clang does guarantee a line note before and after the prologue.
We have tried this patch with clang generated binary and it works fine. Also prologue_end tag is generated by clang as specified in DWARF3 standard when prologue is emitted.

We will try to shift this discussion on main stream GDB. We had submitted the same at
http://sourceware.org/bugzilla/process_bug.cgi
we are awaiting their response.

Thanks.

Revision history for this message
karthik (kv-bhat) wrote :
Revision history for this message
Ulrich Weigand (uweigand) wrote :

If clang does the same trick as gcc w.r.t. the two line directives, then I'd be fine with extending the producer check to treat clang the same as gcc here.

Revision history for this message
karthik (kv-bhat) wrote :

Hi.. the patch for this issue has been committed to mainstream GDB.

http://sourceware.org/ml/gdb-cvs/2012-09/msg00148.html

Please let me know if it can be back ported into GDB Linaro.

Thanks.

Revision history for this message
Ulrich Weigand (uweigand) wrote :

Looks good to me.

Revision history for this message
karthik (kv-bhat) wrote :

Hi All,
I have a similar patch for issue the same issue on i386. Could experts please review and comment.

Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.14849
diff -u -p -r1.14849 ChangeLog
--- ChangeLog 21 Nov 2012 14:09:03 -0000 1.14849
+++ ChangeLog 21 Nov 2012 15:11:47 -0000
@@ -1,3 +1,9 @@
+2012-11-20 Karthik Bhat <email address hidden>
+
+ * i386-tdep.c (i386_skip_prologue): See if we
+ can determine the end of the prologue via the symbol table.
+ If so use the same instead of going through prologue instructions.
+
 2012-11-21 Yao Qi <email address hidden>

  PR tdep/7438
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.364
diff -u -p -r1.364 i386-tdep.c
--- i386-tdep.c 21 Nov 2012 14:09:10 -0000 1.364
+++ i386-tdep.c 21 Nov 2012 15:11:48 -0000
@@ -1582,6 +1582,27 @@ i386_skip_prologue (struct gdbarch *gdba
   CORE_ADDR pc;
   gdb_byte op;
   int i;
+ CORE_ADDR func_addr;
+
+ if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL))
+ {
+ CORE_ADDR post_prologue_pc
+ = skip_prologue_using_sal (gdbarch, func_addr);
+ struct symtab *s = find_pc_symtab (func_addr);
+
+ /* GCC and clang always emits a line note before the prologue and another
+ one after, even if the two are at the same address or on the
+ same line. Take advantage of this so that we do not need to
+ know every instruction that might appear in the prologue. We
+ will have producer information for most binaries; if it is
+ missing (e.g. for -gstabs), assuming the GNU tools. */
+ if (post_prologue_pc
+ && (s == NULL
+ || s->producer == NULL
+ || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0
+ || strncmp (s->producer, "clang ", sizeof ("clang ") - 1) == 0))
+ return max (start_pc, post_prologue_pc);
+ }

   cache.locals = -1;
   pc = i386_analyze_prologue (gdbarch, start_pc, 0xffffffff, &cache);

I wanted to add this patch in GDB to fix a problem which we are currently facing when we use gdb with binary compiled with clang.
The problem faced is clang generates function prologue which is a bit different from that of GCC as a result when we try to skip prologue instruction by instruction it results in incorrect prologue_end.

There is one more method to skip prologue which is used in other architectures such as ARM(arm-tdep.c), MIPS(mips-tdep.c) etc. In this method we try to determine prologue end via symbol table.
If we are unable to do this we then we examine instruction to determine prologue end.

Added the same for i386. Here we are trying to see if we can resolve prologue end from symbol table.
This will avoid instruction by instruction examining to determine prologue end if we are able to determine it through symbol table.

Thanks

Changed in gdb-linaro:
status: New → Fix Committed
Changed in gdb-linaro:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.