Mirror of the gdb mailing list
 help / color / mirror / Atom feed
* how to make gdb happy with my linkmap
@ 2008-12-18 21:42 Mathieu Lacage
  2008-12-18 21:49 ` Daniel Jacobowitz
  0 siblings, 1 reply; 10+ messages in thread
From: Mathieu Lacage @ 2008-12-18 21:42 UTC (permalink / raw)
  To: gdb

hi,

I am currently trying to write a small ELF loader and make gdb be
happy with it. One of the things I have been doing until now is manage
the following link map:

(gdb) info linkmap
084661e0 ldso
08430518
084661e0 /lib/libc.so.6
(gdb)

The most notable thing to note here is that the first item in the
linkmap is not the main binary: it is the loader itself. This,
however, seems to be problematic for gdb since I get the following
message:
warning: Temporarily disabling breakpoints for unloaded shared library "ldso"
when I invoke the _r_debug_state function where gdb has put a
breakpoint (I should point out that, of course, I did not remove _any_
entry from the link map at this point)

Although it seems clear to me that I won't be able to keep managing my
link map as I do now and that I will have to move the main binary as
the first entry in the map (I have already done this and it makes gdb
much happier), I was trying to figure out why this so problematic for
gdb, mainly because I fear that there are some other subtle
requirements from gdb on the structure of the link map.

Hence, my question: what are the requirements on the structure of a
linkmap which is compatible with gdb's usage (beyond the mere ABI
offset requirements). I am also curious to know if there is anywhere a
document which describes the overall interface between gdb and the
inferior's loader: so far, reading the code has been enough for me to
figure out how this all works but, well, I wonder if I could have
saved myself all this code-reading work.

Anyhow, that piece of code is fairly readable and really nicely
structured so, thanks a lot for this cool software I have been using
for so long.

Mathieu
-- 
Mathieu Lacage <mathieu.lacage@gmail.com>


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

* Re: how to make gdb happy with my linkmap
  2008-12-18 21:42 how to make gdb happy with my linkmap Mathieu Lacage
@ 2008-12-18 21:49 ` Daniel Jacobowitz
  2008-12-18 22:03   ` Mathieu Lacage
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-12-18 21:49 UTC (permalink / raw)
  To: Mathieu Lacage; +Cc: gdb

On Thu, Dec 18, 2008 at 10:41:20PM +0100, Mathieu Lacage wrote:
> hi,
> 
> I am currently trying to write a small ELF loader and make gdb be
> happy with it.

On SVR4 systems, basically, you can't.  There is some information you
won't be able to update because it lives in the kernel (auxilliary
vector).  This is one of the reasons I recently implemented "set
wrapper"; if the loader is far enough along when GDB starts looking
at it, and has a link map already set up, then it will (generally)
not go poking around the auxilliary vector.

> Hence, my question: what are the requirements on the structure of a
> linkmap which is compatible with gdb's usage (beyond the mere ABI
> offset requirements).

I don't think this is possible to answer.  The answer is that GDB is
written to work as best it can with all the system loaders we've
encountered.  If there's a change that would make things easier for
your loader, without breaking any of those systems, you're welcome to
propose it :-)

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: how to make gdb happy with my linkmap
  2008-12-18 21:49 ` Daniel Jacobowitz
@ 2008-12-18 22:03   ` Mathieu Lacage
  2008-12-18 22:10     ` Daniel Jacobowitz
  0 siblings, 1 reply; 10+ messages in thread
From: Mathieu Lacage @ 2008-12-18 22:03 UTC (permalink / raw)
  To: Mathieu Lacage, gdb

On Thu, Dec 18, 2008 at 10:48 PM, Daniel Jacobowitz <drow@false.org> wrote:
> On Thu, Dec 18, 2008 at 10:41:20PM +0100, Mathieu Lacage wrote:
>> hi,
>>
>> I am currently trying to write a small ELF loader and make gdb be
>> happy with it.
>
> On SVR4 systems, basically, you can't.  There is some information you
> won't be able to update because it lives in the kernel (auxilliary
> vector).  This is one of the reasons I recently implemented "set

erm, I might be totally naive, but, how does the libc loader achieve
this then ? The only thing I am trying to do is be sufficiently
compatible with the libc loader to make gdb happy with my loader. Did
I mention that I am trying to replace the libc loader rather than try
to make two loaders co-exist in the same process image (which would
create another set of challenging problems from a compatibility
perspective).

> wrapper"; if the loader is far enough along when GDB starts looking

will grep for this.

> at it, and has a link map already set up, then it will (generally)
> not go poking around the auxilliary vector.
>
>> Hence, my question: what are the requirements on the structure of a
>> linkmap which is compatible with gdb's usage (beyond the mere ABI
>> offset requirements).
>
> I don't think this is possible to answer.  The answer is that GDB is
> written to work as best it can with all the system loaders we've
> encountered.  If there's a change that would make things easier for
> your loader, without breaking any of those systems, you're welcome to
> propose it :-)

Ok, my question then, is: what can I do in my loader to be fully
compatible with what gdb expects  :) I am willing to go through quite
a bit of pain in the name of compatibility: whatever gdb asks me to do
will be probably orders of magnitude easier than what glibc is asking
me to provide

Mathieu
-- 
Mathieu Lacage <mathieu.lacage@gmail.com>


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

* Re: how to make gdb happy with my linkmap
  2008-12-18 22:03   ` Mathieu Lacage
@ 2008-12-18 22:10     ` Daniel Jacobowitz
  2008-12-26 10:40       ` Mathieu Lacage
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-12-18 22:10 UTC (permalink / raw)
  To: Mathieu Lacage; +Cc: gdb

On Thu, Dec 18, 2008 at 11:02:22PM +0100, Mathieu Lacage wrote:
> > On SVR4 systems, basically, you can't.  There is some information you
> > won't be able to update because it lives in the kernel (auxilliary
> > vector).  This is one of the reasons I recently implemented "set
> 
> erm, I might be totally naive, but, how does the libc loader achieve
> this then ? The only thing I am trying to do is be sufficiently
> compatible with the libc loader to make gdb happy with my loader. Did
> I mention that I am trying to replace the libc loader rather than try
> to make two loaders co-exist in the same process image (which would
> create another set of challenging problems from a compatibility
> perspective).

Oh!  Sorry.  Then I was off on a tangent.  The salient difference is
whether your loader is started by the kernel based on a PT_INTERP
entry in the executable, or from the command line.  If it's started
by PT_INTERP, things are much easier to handle.

The only things I can think of are having the main application first,
and having the debug function be named _dl_debug_state (because we set
a breakpoint before _r_debug is initialized).  There's not much more
to it.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: how to make gdb happy with my linkmap
  2008-12-18 22:10     ` Daniel Jacobowitz
@ 2008-12-26 10:40       ` Mathieu Lacage
  2008-12-26 12:54         ` Daniel Jacobowitz
  0 siblings, 1 reply; 10+ messages in thread
From: Mathieu Lacage @ 2008-12-26 10:40 UTC (permalink / raw)
  To: Mathieu Lacage, gdb

On Thu, Dec 18, 2008 at 11:10 PM, Daniel Jacobowitz <drow@false.org> wrote:

> Oh!  Sorry.  Then I was off on a tangent.  The salient difference is
> whether your loader is started by the kernel based on a PT_INTERP
> entry in the executable, or from the command line.  If it's started
> by PT_INTERP, things are much easier to handle.
>
> The only things I can think of are having the main application first,
> and having the debug function be named _dl_debug_state (because we set
> a breakpoint before _r_debug is initialized).  There's not much more
> to it.

Ok, it appears that this is, indeed, sufficient to get good debugging
when running the executable from a PT_INTERP. However, as you
mentioned above, running the executable from the command-line without
an associated PT_INTERP entry seems to confuse gdb quite a bit: it
seems unable to place or handle breakpoints. Is there something I
could do to help alleviate this problem (I would be happy to do
whatever is needed in gdb proper) ? Maybe I could go and hack the
on-stack aux vectors to help gdb ?

regards,
Mathieu
-- 
Mathieu Lacage <mathieu.lacage@gmail.com>


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

* Re: how to make gdb happy with my linkmap
  2008-12-26 10:40       ` Mathieu Lacage
@ 2008-12-26 12:54         ` Daniel Jacobowitz
  2009-01-05 14:58           ` Mathieu Lacage
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-12-26 12:54 UTC (permalink / raw)
  To: Mathieu Lacage; +Cc: gdb

On Fri, Dec 26, 2008 at 11:39:59AM +0100, Mathieu Lacage wrote:
> Ok, it appears that this is, indeed, sufficient to get good debugging
> when running the executable from a PT_INTERP. However, as you
> mentioned above, running the executable from the command-line without
> an associated PT_INTERP entry seems to confuse gdb quite a bit: it
> seems unable to place or handle breakpoints. Is there something I
> could do to help alleviate this problem (I would be happy to do
> whatever is needed in gdb proper) ? Maybe I could go and hack the
> on-stack aux vectors to help gdb ?

Does it work any better with ld.so?  I doubt it - GDB doesn't do
this well, and I don't have any clear idea on how to improve it.
Sorry.  There's probably a way that I haven't thought of.

Modifying the on-stack auxv copy won't make a difference; GDB uses the
read-only copy in the kernel (since locating the stack copy is
unreliable, and it is prone to corruption).

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: how to make gdb happy with my linkmap
  2008-12-26 12:54         ` Daniel Jacobowitz
@ 2009-01-05 14:58           ` Mathieu Lacage
  2009-01-05 17:13             ` Daniel Jacobowitz
  2009-01-12 15:08             ` Mathieu Lacage
  0 siblings, 2 replies; 10+ messages in thread
From: Mathieu Lacage @ 2009-01-05 14:58 UTC (permalink / raw)
  To: gdb

> Does it work any better with ld.so?  I doubt it - GDB doesn't do

It does not seem to work any better with ld-linux.so.2. I tried to
look into this a bit more but I did not make much progress. Here is
what I get:

mathieu@mathieu-boulot:~/code/elf-loader$ gdb ./ldso
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) b stage1
Breakpoint 1 at 0x944: file ldso.c, line 304.
(gdb) r ./hello
Starting program: /home/mathieu/code/elf-loader/ldso ./hello
hello

Program exited normally.
(gdb)

What I find weird is:
1) mathieu@mathieu-boulot:~/code/elf-loader$ readelf -s ./ldso |grep stage1
   225: 00000932   135 FUNC    GLOBAL HIDDEN    6 stage1
mathieu@mathieu-boulot:~/code/elf-loader$ readelf -l ./ldso

Elf file type is DYN (Shared object file)
Entry point 0x932
There are 6 program headers, starting at offset 52
[...]

i.e., stage1 is located at offset 0x932, and not 0x944 so, I can't
figure out where the 0x944 displayed by gdb is coming from. I also
find it surprising that gdb is actually trying to set a breakpoint at
address 0x944: this is a pie binary so, gdb should know that the
address will be known only once the program is run....

To summarize, 2 questions:
1) what do I need to do to make gdb _not_ attempt to really set the
breakpoint before the program is run ?

2) why is gdb using 0x944 and not 0x932 ?

I am shooting a bit in the dark here, obviously.

Mathieu
-- 
Mathieu Lacage <mathieu.lacage@gmail.com>


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

* Re: how to make gdb happy with my linkmap
  2009-01-05 14:58           ` Mathieu Lacage
@ 2009-01-05 17:13             ` Daniel Jacobowitz
  2009-01-07 16:46               ` Doug Evans
  2009-01-12 15:08             ` Mathieu Lacage
  1 sibling, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2009-01-05 17:13 UTC (permalink / raw)
  To: Mathieu Lacage; +Cc: gdb

On Mon, Jan 05, 2009 at 03:58:39PM +0100, Mathieu Lacage wrote:
> What I find weird is:
> 1) mathieu@mathieu-boulot:~/code/elf-loader$ readelf -s ./ldso |grep stage1
>    225: 00000932   135 FUNC    GLOBAL HIDDEN    6 stage1
> mathieu@mathieu-boulot:~/code/elf-loader$ readelf -l ./ldso
> 
> Elf file type is DYN (Shared object file)
> Entry point 0x932
> There are 6 program headers, starting at offset 52
> [...]
> 
> i.e., stage1 is located at offset 0x932, and not 0x944 so, I can't
> figure out where the 0x944 displayed by gdb is coming from.

That's prologue skipping; it's just walking past the frame setup.
This helps GDB to display function arguments correctly.

> I also
> find it surprising that gdb is actually trying to set a breakpoint at
> address 0x944: this is a pie binary so, gdb should know that the
> address will be known only once the program is run....

This is the same problem as PIE support.  Ubuntu and Fedora carry some
patches to improve PIE support; I think that Jan K. was talking about
merging those at some point.  I haven't looked at them in years.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: how to make gdb happy with my linkmap
  2009-01-05 17:13             ` Daniel Jacobowitz
@ 2009-01-07 16:46               ` Doug Evans
  0 siblings, 0 replies; 10+ messages in thread
From: Doug Evans @ 2009-01-07 16:46 UTC (permalink / raw)
  To: Mathieu Lacage, gdb

On Mon, Jan 5, 2009 at 9:13 AM, Daniel Jacobowitz <drow@false.org> wrote:
> On Mon, Jan 05, 2009 at 03:58:39PM +0100, Mathieu Lacage wrote:
>> What I find weird is:
>> 1) mathieu@mathieu-boulot:~/code/elf-loader$ readelf -s ./ldso |grep stage1
>>    225: 00000932   135 FUNC    GLOBAL HIDDEN    6 stage1
>> mathieu@mathieu-boulot:~/code/elf-loader$ readelf -l ./ldso
>>
>> Elf file type is DYN (Shared object file)
>> Entry point 0x932
>> There are 6 program headers, starting at offset 52
>> [...]
>>
>> i.e., stage1 is located at offset 0x932, and not 0x944 so, I can't
>> figure out where the 0x944 displayed by gdb is coming from.
>
> That's prologue skipping; it's just walking past the frame setup.
> This helps GDB to display function arguments correctly.

For completeness' sake,
to avoid prologue skipping one can do "b *stage1".


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

* Re: how to make gdb happy with my linkmap
  2009-01-05 14:58           ` Mathieu Lacage
  2009-01-05 17:13             ` Daniel Jacobowitz
@ 2009-01-12 15:08             ` Mathieu Lacage
  1 sibling, 0 replies; 10+ messages in thread
From: Mathieu Lacage @ 2009-01-12 15:08 UTC (permalink / raw)
  To: gdb

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

Just in case it helps anyone, since I did not really have time to
investigate the gdb issues, I came up with the attached elf editor
which replaces the content of PT_INTERP. Eventually, I will have to
deal with gdb but, not now :)


Mathieu



On Mon, Jan 5, 2009 at 3:58 PM, Mathieu Lacage <mathieu.lacage@gmail.com> wrote:
>> Does it work any better with ld.so?  I doubt it - GDB doesn't do
>
> It does not seem to work any better with ld-linux.so.2. I tried to
> look into this a bit more but I did not make much progress. Here is
> what I get:
>
> mathieu@mathieu-boulot:~/code/elf-loader$ gdb ./ldso
> GNU gdb 6.8-debian
> Copyright (C) 2008 Free Software Foundation, Inc.
> License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
> This is free software: you are free to change and redistribute it.
> There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
> and "show warranty" for details.
> This GDB was configured as "i486-linux-gnu"...
> (gdb) b stage1
> Breakpoint 1 at 0x944: file ldso.c, line 304.
> (gdb) r ./hello
> Starting program: /home/mathieu/code/elf-loader/ldso ./hello
> hello
>
> Program exited normally.
> (gdb)
>
> What I find weird is:
> 1) mathieu@mathieu-boulot:~/code/elf-loader$ readelf -s ./ldso |grep stage1
>   225: 00000932   135 FUNC    GLOBAL HIDDEN    6 stage1
> mathieu@mathieu-boulot:~/code/elf-loader$ readelf -l ./ldso
>
> Elf file type is DYN (Shared object file)
> Entry point 0x932
> There are 6 program headers, starting at offset 52
> [...]
>
> i.e., stage1 is located at offset 0x932, and not 0x944 so, I can't
> figure out where the 0x944 displayed by gdb is coming from. I also
> find it surprising that gdb is actually trying to set a breakpoint at
> address 0x944: this is a pie binary so, gdb should know that the
> address will be known only once the program is run....
>
> To summarize, 2 questions:
> 1) what do I need to do to make gdb _not_ attempt to really set the
> breakpoint before the program is run ?
>
> 2) why is gdb using 0x944 and not 0x932 ?
>
> I am shooting a bit in the dark here, obviously.
>
> Mathieu
> --
> Mathieu Lacage <mathieu.lacage@gmail.com>
>



-- 
Mathieu Lacage <mathieu.lacage@gmail.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: elfedit.c --]
[-- Type: text/x-csrc; name=elfedit.c, Size: 1758 bytes --]

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>
#include <link.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>


int main (int argc, char *argv[])
{
  const char *filename = argv[1];
  ElfW(Ehdr) header;
  int fd = open (filename, O_RDWR);

  ssize_t bytes_read = read (fd, &header, sizeof (header));
  if (bytes_read != sizeof (header))
    {
      return -1;
    }

  ElfW(Phdr) *ph = malloc (header.e_phnum * header.e_phentsize);
  if (ph == 0)
    {
      return -2;
    }
  if (lseek (fd, header.e_phoff, SEEK_SET) == -1)
    {
      return -3;
    }
  if (read (fd, ph, header.e_phnum * header.e_phentsize) != header.e_phnum * header.e_phentsize)
    {
      return -4;
    }
  int i;
  for (i = 0; i < header.e_phnum; i++)
    {
      if (ph[i].p_type == PT_INTERP)
	{
	  if (strlen (argv[2]) + 1> ph[i].p_filesz)
	    {
	      return -5;
	    }
	  if (lseek (fd, ph[i].p_offset, SEEK_SET) == -1)
	    {
	      return -6;
	    }
	  char *interp = malloc (ph[i].p_filesz);
	  memset (interp, 0, ph[i].p_filesz);
	  memcpy (interp, argv[2], strlen (argv[2]));
	  if (write (fd, argv[2], ph[i].p_filesz) != ph[i].p_filesz)
	    {
	      return -7;
	    }
	  if (lseek (fd, header.e_phoff + ((long)&ph[i].p_filesz - (long)ph), SEEK_SET) == -1)
	    {
	      return -8;
	    }
	  ElfW(Xword) filesz = strlen (argv[2])+1;
	  if (write (fd, &filesz, sizeof(filesz)) != sizeof(filesz))
	    {
	      return -9;
	    }
	  if (lseek (fd, header.e_phoff + ((long)&ph[i].p_memsz-(long)ph), SEEK_SET) == -1)
	    {
	      return -10;
	    }
	  ElfW(Xword) memsz = strlen (argv[2])+1;
	  if (write (fd, &memsz, sizeof(memsz)) != sizeof(memsz))
	    {
	      return -11;
	    }
	  return 0;
	}
    }
  

  return 0;
}

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

end of thread, other threads:[~2009-01-12 15:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-18 21:42 how to make gdb happy with my linkmap Mathieu Lacage
2008-12-18 21:49 ` Daniel Jacobowitz
2008-12-18 22:03   ` Mathieu Lacage
2008-12-18 22:10     ` Daniel Jacobowitz
2008-12-26 10:40       ` Mathieu Lacage
2008-12-26 12:54         ` Daniel Jacobowitz
2009-01-05 14:58           ` Mathieu Lacage
2009-01-05 17:13             ` Daniel Jacobowitz
2009-01-07 16:46               ` Doug Evans
2009-01-12 15:08             ` Mathieu Lacage

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