From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15458 invoked by alias); 22 Jul 2002 23:19:59 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 15451 invoked from network); 22 Jul 2002 23:19:58 -0000 Received: from unknown (HELO takamaka.act-europe.fr) (142.179.108.108) by sources.redhat.com with SMTP; 22 Jul 2002 23:19:58 -0000 Received: by takamaka.act-europe.fr (Postfix, from userid 507) id B31A7D2CBD; Mon, 22 Jul 2002 16:19:57 -0700 (PDT) Date: Mon, 22 Jul 2002 17:36:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: [RFC] breakpoints and function prologues... Message-ID: <20020722231957.GE4999@gnat.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="k1lZvvs/B4yU6o8G" Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2002-07/txt/msg00449.txt.bz2 --k1lZvvs/B4yU6o8G Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 3457 I would like to have your opinion on the following issue. This is more spectacular on Tru64, but the idea behind this can be reproduced on any system. Given the following simple program: 1 #include 2 3 void 4 hello (void) 5 { 6 printf ("Hello world.\n"); 7 } 8 9 int 10 main (void) 11 { 12 hello (); 13 return 0; 14 } (compiled using "gcc -g hello.c -o hello") The program does not stop if I put a breakpoint at line 4 before running it: (gdb) b hello.c:4 Breakpoint 1 at 0x120001150: file hello.c, line 4. (gdb) run Starting program: /usr/prague.a/brobecke/skip_prologue/hello Hello world. Program exited normally. (gdb) On the other hand, if I use the function name to put the breakpoint, then the program stops: (gdb) b hello Breakpoint 2 at 0x120001168: file hello.c, line 6. (gdb) run Starting program: /usr/prague.a/brobecke/skip_prologue/hello Breakpoint 2, hello () at hello.c:6 6 printf ("Hello world.\n"); (gdb) It is more spectacular in the Tru64 case, because the Tru64 linker performs some optimization by default that often cause the first few instructions to be skipped (usually the instruction loading the gp). A disass in function main() shows this: 0x1200011b0 : bsr ra,0x120001158 But the problem is a bit more general that this: - "break function-name" causes GDB to skip the function prologue - On the other hand, "break file:line_num" does not cause GDB to skip the function prologue Some of our users have been confused by this, mostly because they use a graphical front-end where it is so easy to click to put a breakpoint on a given line that they sometimes don't know or want to know that there are other ways to insert breakpoints. Some of our users thought that breakpoint 1 and 2 above where equivalent, and where therefore surprised to see that their function parameters had junk values. Once you know that in case of breakpoint 1, the prologue has not been executed, it is easy to figure out that the parameter homing had not taken place yet, hence the incorrect values. In our experience, the only case when a user don't want to skip the function prologue is when doing instruction-level debugging. So, we are considering changing the behavior of the "break file:line-num" command to behave like "break function-name", that is slightly offset the breakpoint address to skip the prologue. That will fix the Tru64 problem, and we believe that it will make GDB more user-friendly by making breakpoint 1 and 2 equivalent. I would like to have your opinion on this. Interestingly enough, I had made a prototype change that was adding this capability to GDB due to another problem (it was a compiler deficiency that I wanted to work-around in GDB). I never finished this work because I convinced myself that it was better to fix the compiler (which, due to lack of time, I haven't done yet :-). I am attaching this patch to this mail just as a reference. It probably needs a bit of dusting off, and some touch-ups before it is suitable for submission if the GDB community like the idea. -- Joel --k1lZvvs/B4yU6o8G Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="bp.diff" Content-length: 4230 Index: breakpoint.c =================================================================== RCS file: /nile.c/cvs/Dev/gdb/gdb-5/gdb/breakpoint.c,v retrieving revision 1.1.1.1.2.6 diff -u -5 -r1.1.1.1.2.6 breakpoint.c --- breakpoint.c 5 Feb 2002 08:59:32 -0000 1.1.1.1.2.6 +++ breakpoint.c 6 Feb 2002 11:22:00 -0000 @@ -4726,23 +4726,41 @@ (*addr_string)[i] = savestring (addr_start, (*address) - addr_start); } } } - /* Convert each SAL into a real PC. Verify that the PC can be inserted as a breakpoint. If it can't throw an error. */ void breakpoint_sals_to_pc (struct symtabs_and_lines *sals, - char *address) + char *address, + char **address_string) { int i; for (i = 0; i < sals->nelts; i++) { resolve_sal_pc (&sals->sals[i]); + /* If the PC for the breakpoint points to the first instruction + of a function (ie the begining of a function prologue), then + skip the prologue. What happens is that certain smart linkers + such as the Tru64 linker perform some optimizations which + sometimes cause part of the prologue to be skipped. The + consequence for the user is that his breakpoint is never hit + even though his code is actually executed. + + Do not perform this adjustment if the user asked to put the + breakpoint at a specified address (using the *addr notation). + If the user goes down to this level, it is likely that he knows + what he is doing. */ + + if (address_string[i] != NULL && + address_string[i][0] != '*' && + get_pc_function_start (sals->sals[i].pc) == sals->sals[i].pc) + sals->sals[i].pc = SKIP_PROLOGUE (sals->sals[i].pc); + /* It's possible for the PC to be nonzero, but still an illegal value on some targets. For example, on HP-UX if you start gdb, and before running the inferior you try to set a breakpoint on a shared library function @@ -4834,11 +4852,11 @@ make_cleanup (free, addr_string[i]); } /* Resolve all line numbers to PC's and verify that the addresses are ok for the target. */ - breakpoint_sals_to_pc (&sals, addr_start); + breakpoint_sals_to_pc (&sals, addr_start, addr_string); /* Verify that condition can be parsed, before setting any breakpoints. Allocate a separate condition expression for each breakpoint. */ thread = -1; /* No specific thread yet */ @@ -4994,11 +5012,11 @@ memory. */ if (*address_end != '\0') error ("Garbage %s following breakpoint address", address_end); /* Resolve all line numbers to PC's. */ - breakpoint_sals_to_pc (&sals, args->address); + breakpoint_sals_to_pc (&sals, args->address, addr_string); /* Verify that conditions can be parsed, before setting any breakpoints. */ for (i = 0; i < sals.nelts; i++) { @@ -7087,10 +7105,27 @@ s = b->addr_string; sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, (char ***) NULL); for (i = 0; i < sals.nelts; i++) { resolve_sal_pc (&sals.sals[i]); + + /* If the PC for the breakpoint points to the first instruction + of a function (ie the begining of a function prologue), then + skip the prologue. What happens is that certain smart linkers + such as the Tru64 linker perform some optimizations which + sometimes cause part of the prologue to be skipped. The + consequence for the user is that his breakpoint is never + hit even though his code is actually executed. + + Do not perform this adjustment if the user asked to put the + breakpoint at a specified address (using the *addr notation). + If the user goes down to this level, it is likely that he knows + what he is doing. */ + + if (s[0] != '*' && + get_pc_function_start (sals.sals[i].pc) == sals.sals[i].pc) + sals.sals[i].pc = SKIP_PROLOGUE (sals.sals[i].pc); /* Reparse conditions, they might contain references to the old symtab. */ if (b->cond_string != NULL) { --k1lZvvs/B4yU6o8G--