Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [i386/fyi] small adjustment to i386 frame code
@ 2006-08-23 18:17 Joel Brobecker
  2006-08-23 18:40 ` Daniel Jacobowitz
  0 siblings, 1 reply; 4+ messages in thread
From: Joel Brobecker @ 2006-08-23 18:17 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1813 bytes --]

Hello,

Since this has been discussed here in several occasions...

Since GDB 6.0, the debugger has been using a more sophisticated
frame unwinder. It used to blindly follow the %ebp register, but
no longer does that unless it is sure that the frame base address
has been saved there.

Although the new frame code gives more much more accurate results
most of the time, there are some occasional cases where we have
to unwind through functions which do not follow the ABI, and for
which no frame debugging info seem to be provided. In these particular
cases, the unwinder fails, and a backtrace from such function aborts
prematurely. One such example is WaitForSingleObjectEx (in one of
the windows DLL). I posted the assembly of this function a long while
ago, it's just plain impossible to determine where the frame base is.

Unfortunately for us, that function is used fairly regularly by any
application which would use tasking (a high-level equivalent of threads
in C), which is something relatively common in the Ada world. So we
really need to be able to unwind past that function.

When it comes to unwinding using prologue analysis, there is probably
no perfect solution. Here is the approach we are going to try out:
Follow blindly the %ebp register for "the complicated functions".
And because we've only encountered this type of code in a DLL, we've
limited this hack to code in DLLs. I added a comment in the code
explaining the condition that implements "complicated".

We know there is a risk of %ebp being clobbered, we also know that
%ebp is the base address of the caller's frame, now ours. But that
will at least give us a chance of having the backtrace reach the user
code.

If this is something of general interest, in this form or any variation,
I would be happy to contribute it.

-- 
Joel

[-- Attachment #2: ebp.diff --]
[-- Type: text/plain, Size: 3402 bytes --]

Index: i386-tdep.c
===================================================================
RCS file: /gnat.dev/cvs/Dev/gdb/gdb-6.4/gdb/i386-tdep.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -p -r1.4 -r1.5
--- i386-tdep.c	10 Aug 2006 22:18:30 -0000	1.4
+++ i386-tdep.c	22 Aug 2006 21:45:53 -0000	1.5
@@ -1029,6 +1029,41 @@ i386_frameless_adjust_cache_hack (struct
     }
 }
 
+/* Return non-zero if the function starting at START_PC has a prologue
+   that sets up a standard frame.  */
+
+static int
+i386_function_has_frame (CORE_ADDR start_pc)
+{
+  struct i386_frame_cache cache;
+
+  cache.locals = -1;
+  i386_analyze_prologue (start_pc, 0xffffffff, &cache);
+
+  return (cache.locals >= 0);
+}
+
+/* Return non-zero if PC is inside one of the inferior's DLLs.  */
+
+static int
+i386_in_dll (CORE_ADDR pc)
+{
+   char *so_name = solib_address (pc);
+   int len;
+
+   if (so_name == NULL)
+     return 0;
+
+   len = strlen (so_name);
+   if (len < 5)
+     return 0;
+
+   return ((so_name[len - 1] == 'l' || so_name[len - 1] == 'L')
+           && (so_name[len - 2] == 'l' || so_name[len - 2] == 'L')
+           && (so_name[len - 3] == 'd' || so_name[len - 3] == 'D')
+           && so_name[len - 4] == '.');
+}
+
 /* Normal frames.  */
 
 static struct i386_frame_cache *
@@ -1075,10 +1110,38 @@ i386_frame_cache (struct frame_info *nex
 	 frame by looking at the stack pointer.  For truly "frameless"
 	 functions this might work too.  */
 
-      i386_frameless_adjust_cache_hack (cache, frame_pc_unwind (next_frame));
+      if (i386_in_dll (cache->pc)
+          && !i386_function_has_frame (cache->pc))
+        {
+          /* Functions in DLL for which do not seem to create a standard
+             frame are unwound using %ebp.  This is actually the caller's
+             frame base instead of our own, but there are some functions
+             such as WaitForSingleObjectEx in one of the Windows system
+             DLLs for which the frame base cannot possibly be determined
+             from the stack pointer.  As a consequence, our caller will be
+             missing from the backtrace, but this is better than having
+             an aborted backtrace due to a bogus frame base.
+             
+             We use this approach only for functions in DLLs because
+             this is the only place where we have seen the type of
+             highly optimized code that cause us trouble.  In other
+             cases, we expect the code to come with frame debugging
+             information, making prologue scanning unnecessary.
+             
+             We also avoid blindly following %ebp if we are midway through
+             setting up a standard frame.  In that case, we know how to
+             determine the frame base using the stack pointer.  */
 
-      frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
-      cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+          cache->saved_regs[I386_EBP_REGNUM] = 0;
+        }
+      else
+        {
+          i386_frameless_adjust_cache_hack (cache,
+                                            frame_pc_unwind (next_frame));
+ 
+          frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+          cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+        }
     }
 
   /* Now that we have the base address for the stack frame we can

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [i386/fyi] small adjustment to i386 frame code
  2006-08-23 18:17 [i386/fyi] small adjustment to i386 frame code Joel Brobecker
@ 2006-08-23 18:40 ` Daniel Jacobowitz
  2006-08-23 21:30   ` Joel Brobecker
  0 siblings, 1 reply; 4+ messages in thread
From: Daniel Jacobowitz @ 2006-08-23 18:40 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Wed, Aug 23, 2006 at 10:38:49AM -0700, Joel Brobecker wrote:
> Although the new frame code gives more much more accurate results
> most of the time, there are some occasional cases where we have
> to unwind through functions which do not follow the ABI, and for
> which no frame debugging info seem to be provided. In these particular
> cases, the unwinder fails, and a backtrace from such function aborts
> prematurely. One such example is WaitForSingleObjectEx (in one of
> the windows DLL). I posted the assembly of this function a long while
> ago, it's just plain impossible to determine where the frame base is.

FYI: I'm not at all sure I agree with your assertion of impossibility.
But when I tried to debug native Windows code, my main problem was
figuring out the starts of symbols.  The DLLs themselves don't have
enough symbolic information in them.  Things that look like a single
function are actually often many functions in a row, only one of which
was exported.

Symbolic info files are available automatically from Microsoft, but it
seems like a serious hassle to auto-download them.  And if you want to
get a lot of useful information out of them you need a DLL (which is
freely distributable) but also its header (which isn't; it's part of
the commercial Visual Studio offerings only).  That's where I gave up.

It should be possible to do this very nicely.  I was considering a
standalone program, not part of GDB, which would generate separate
symbol files in a non-Microsoft format that GDB could understand
(maybe Dwarf).  As long as you don't redistribute the result I
think that's OK by the MS licensing.  I just didn't have time to work
on it myself.

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [i386/fyi] small adjustment to i386 frame code
  2006-08-23 18:40 ` Daniel Jacobowitz
@ 2006-08-23 21:30   ` Joel Brobecker
  2006-08-24 12:43     ` Daniel Jacobowitz
  0 siblings, 1 reply; 4+ messages in thread
From: Joel Brobecker @ 2006-08-23 21:30 UTC (permalink / raw)
  To: gdb-patches

> FYI: I'm not at all sure I agree with your assertion of impossibility.
> But when I tried to debug native Windows code, my main problem was
> figuring out the starts of symbols.  The DLLs themselves don't have
> enough symbolic information in them.  Things that look like a single
> function are actually often many functions in a row, only one of which
> was exported.

Humpf, that could indeed mess things up. We've seen this on IRIX as well
IIRC (static symbols not beeing part of the symbol table after the link).

> Symbolic info files are available automatically from Microsoft, but it
> seems like a serious hassle to auto-download them.  And if you want to
> get a lot of useful information out of them you need a DLL (which is
> freely distributable) but also its header (which isn't; it's part of
> the commercial Visual Studio offerings only).  That's where I gave up.
> 
> It should be possible to do this very nicely.  I was considering a
> standalone program, not part of GDB, which would generate separate
> symbol files in a non-Microsoft format that GDB could understand
> (maybe Dwarf).  As long as you don't redistribute the result I
> think that's OK by the MS licensing.  I just didn't have time to work
> on it myself.

This is very interesting information, thanks!  Just some thoughts...

It looks like a very nice project for a Windows lover (I'm the
opposite). I wonder what the implications would be in terms of
licensing if we used the header.

Here's what I'm thinking: Make the header optional during compile
time. If found, then use it. Then make the DLL optional during
runtime. If found, then load it, and then use it. That way,
users that download the sources can build with extra support.
Companies like us who provide binaries should be able to use
the header file just during the build, and would not need to
distribute.

Actually, I'm not sure about making the DLL optional at link time.
My experience with libunwind use in GDB tells me that it might be
better to link the DLL in at build time.

-- 
Joel


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [i386/fyi] small adjustment to i386 frame code
  2006-08-23 21:30   ` Joel Brobecker
@ 2006-08-24 12:43     ` Daniel Jacobowitz
  0 siblings, 0 replies; 4+ messages in thread
From: Daniel Jacobowitz @ 2006-08-24 12:43 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Wed, Aug 23, 2006 at 11:10:36AM -0700, Joel Brobecker wrote:
> It looks like a very nice project for a Windows lover (I'm the
> opposite). I wonder what the implications would be in terms of
> licensing if we used the header.

I'd be willing to do it, but not for free :-)  Not least because
I'd have to buy a copy of the relevant MS devkit.

I am not convinced that integrating this directly into GDB is really
a good idea.  I would be at least initially inclined to do it in a
separate program.  Maybe even invoke that program from GDB
automatically.

The problem is that the mingw32 headers are reverse-engineered, which
is OK for relatively "simple" interfaces, but at the rate MS evolves
new C++/COM interfaces it's hard to keep up.  Even if there aren't
GPL issues, I'd believe there might be general FSF issues; it makes
me uncomfortable, anyway!

-- 
Daniel Jacobowitz
CodeSourcery


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-08-23 18:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-08-23 18:17 [i386/fyi] small adjustment to i386 frame code Joel Brobecker
2006-08-23 18:40 ` Daniel Jacobowitz
2006-08-23 21:30   ` Joel Brobecker
2006-08-24 12:43     ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox