Bug 9474 - GDB will not set pending breakpoints in DLL's loaded with LoadLibrary()
Summary: GDB will not set pending breakpoints in DLL's loaded with LoadLibrary()
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: win32 (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-11-26 02:48 UTC by brandon
Modified: 2011-05-02 10:44 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description brandon 2007-11-26 02:48:01 UTC
[Converted from Gnats 2369]

After having set breakpoint-pending to ON, DLL's loaded with LoadLibrary() will not break.  If the DLL is linked at compile time, the pending breakpoints are hit.

This has been broken for as long as i can remember, my apologies for not submitting the bug sooner.

Release:
GDB 6.6, GDB 6.7.5.20071023

How-To-Repeat:
set the breakpoint-pending flag to on.  set a breakpoint in a DLL that the application loads via LoadLibrary().  GDB will say no source file is found and no breakpoint will be set.
Comment 1 Paul Bolle 2011-04-27 13:05:57 UTC
0) If I understand this API correctly (ie, if I didn't miss something in wine's source) there actually are four functions:
- LoadLibraryA()
- LoadLibraryExA()
- LoadLibraryW()
- LoadLibraryExW()

1) I suppose supporting this would mean something like:
- locating "imports" of one or more of those four functions in the header of the executable where imported functions should be listed;
- setting a (certain type of) breakpoint at those locations. That breakpoint should make sure that if those functions are (successfully) called the list of functions imported from DLL will be updated, that this list is checked for pending breakpoints, etc.

2) In short, an interface broadly similar to the interface used for 
"manually" loading shared libraries on systems that use dlopen(3). That looks doable (but far for from trivial, certainly for me).

3) To aid my memory: see bp_shlib_event and create_solib_event_breakpoint() for an introduction to that interface.
Comment 2 Pedro Alves 2011-04-27 14:51:06 UTC
Hmm?  Doesn't the win32 debug API send a LOAD_DLL_DEBUG_EVENT event when a dll is loaded with LoadLibrary?

You don't seem to be tackling the same issue the OP reported:

"How-To-Repeat:
set the breakpoint-pending flag to on.  set a breakpoint in a DLL that the application loads via LoadLibrary().  GDB will say no source file is found and no breakpoint will be set."

I remember fixing _that_ one years ago.  GDB wouldn't even create the pending breakpoint.  Please reopen if it's broken again.
Comment 3 Paul Bolle 2011-04-28 15:19:43 UTC
(In reply to comment #2)
> Hmm?  Doesn't the win32 debug API send a LOAD_DLL_DEBUG_EVENT event when a dll
> is loaded with LoadLibrary?

0) You are right, of course. A little grepping on LOAD_DLL_DEBUG_EVENT pointed me to the 'set debugevents' command. Using that command it became clear that the DLL I was interested in was indeed loaded (and that gdb was aware of that fact too).

> You don't seem to be tackling the same issue the OP reported:

1) This is what seems to be happening and what made me believe no breakpoints were set (some of this is probably basic stuff that I record here to aid my own memory):
- this PE32 DLL exports a number of symbols. objdump shows is uses a "Export Address Table", a "Name Pointer Table" and a "Ordinal Table";
- if you look at the the dump of the "Export Address Table" and the "[Ordinal/Name Pointer] Table" one sees that the "[Ordinal/Name Pointer] Table" is in (basically) random order: it's not sorted on ordinal nor (alphabetically) on the symbols;
- it turns out that (the version of) gdb (that I use) looks up the address of a symbol in the "[Ordinal/Name Pointer] Table" as if that tables has the same order as the "Export Address Table". But what actually should be done is: look up a symbol in the O/NP table, get its ordinal and look up an address in the EAT for that ordinal;
- I just happened to test gdb with a couple of symbols (which I knew from wine's debugging output were used) that gdb mapped to addresses that simply were not used at all in the code paths I apparently ran;
- this confusing behaviour quickly made me think that gdb never set pending breakpoints in that DLL (which I knew as loaded through LoadLibraryA). Hence the feeling I ran into the issue reported in this bug.

1) I looked around a bit in gdb's source (for instance in bfd/peXXigen.c), but haven't found the place(s) were this mapping of symbols to addresses goes awry for PE32 DLLs. Any suggestions were to look?

2) By the way, should I open a new report for this issue?
Comment 4 Paul Bolle 2011-04-28 21:19:44 UTC
(In reply to comment #3)
> 1) I looked around a bit in gdb's source (for instance in bfd/peXXigen.c), but
> haven't found the place(s) were this mapping of symbols to addresses goes awry
> for PE32 DLLs. Any suggestions were to look?

Not even compile tested:

diff --git a/gdb/coff-pe-read.c b/gdb/coff-pe-read.c
index ca87b72..0483158 100644
--- a/gdb/coff-pe-read.c
+++ b/gdb/coff-pe-read.c
@@ -150,6 +150,14 @@ read_pe_truncate_name (char *dll_name)
     }
 }
 

+static unsigned int
+pe_as16 (void *ptr)
+{
+  unsigned char *b = ptr;
+
+  return b[0] + (b[1] << 8);
+}
+
 /* Low-level support functions, direct from the ld module pe-dll.c.  */
 static unsigned int
 pe_get16 (bfd *abfd, int where)
@@ -309,11 +317,11 @@ read_pe_exported_syms (struct objfile *objfile)
   bfd_bread (expdata, (bfd_size_type) export_size, dll);
   erva = expdata - export_rva;
 
+  ordbase = pe_as32 (expdata + 16); /* unused */
   nexp = pe_as32 (expdata + 24);
+  exp_funcbase = pe_as32 (expdata + 28);
   name_rvas = pe_as32 (expdata + 32);
   ordinals = pe_as32 (expdata + 36);
-  ordbase = pe_as32 (expdata + 16);
-  exp_funcbase = pe_as32 (expdata + 28);
 
   /* Use internal dll name instead of full pathname.  */
   dll_name = pe_as32 (expdata + 12) + erva;
@@ -339,8 +347,10 @@ read_pe_exported_syms (struct objfile *objfile)
       /* Pointer to the names vector.  */
       unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
 
+      unsigned long ordinal = pe_as16 (erva + ordinals + i * 2);
+
       /* Pointer to the function address vector.  */
-      unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
+      unsigned long func_rva = pe_as32 (erva + exp_funcbase + ordinal * 4);
 
       /* Find this symbol's section in our own array.  */
       int sectix = 0;
Comment 5 Pedro Alves 2011-04-29 10:19:32 UTC
Do you have your copyright papers in place (please see src/gdb/CONTRIBUTE)?

Please do open a new report for this issue.  Please paste there your bug description and any analysis you've done, and unless you plan on assigning copyright, please avoid pasting patches.
Comment 6 Paul Bolle 2011-04-29 19:31:47 UTC
(In reply to comment #5)
> Do you have your copyright papers in place (please see src/gdb/CONTRIBUTE)?

0) No. Assuming that we'll end up with something passing the trivial threshold, where can I get the relevant form(s).  
 
> Please do open a new report for this issue.

1) That new report is bug #12716.

> Please paste there your bug
> description and any analysis you've done, and unless you plan on assigning
> copyright, please avoid pasting patches.

2) As should be clear by now, assigning copyright to the FSF is fine with me.
Comment 7 Pedro Alves 2011-05-02 10:44:39 UTC
Great!  I've sent you the form.