public inbox for frysk@sourceware.org
 help / color / mirror / Atom feed
From: Roland McGrath <roland@redhat.com>
To: Nurdin Premji <npremji@redhat.com>
Cc: frysk <frysk@sources.redhat.com>
Subject: Re: Libunwind and elfutils question.
Date: Thu, 19 Apr 2007 09:20:00 -0000	[thread overview]
Message-ID: <20070419030227.C35221800A1@magilla.sf.frob.com> (raw)
In-Reply-To: Nurdin Premji's message of  Monday, 16 April 2007 11:29:13 -0400 <46239649.2030101@redhat.com>

Hi Nurdin.  Sorry I was not able to get back to you before now (I was
travelling, in meetings, or on vacation).  I hope I can clarify some things
to help you accomplish what needs to be done here.

Firstly, please be explicit about exactly which libunwind code you intend
to hook into, so we can read along and understand how it fits together.

The libdwfl "module" concept refers to the unit of one ELF file
(executable, DSO, or .ko) as used in a debugged process at run-time.
When comments in libdwfl code mention the "main file", that means
the ELF file on disk that is actually executed or mapped in as a
DSO--this file contains the disk representation of everything that
has an address lying within the module's address boundaries.  It's
the "main file" as opposed to the "debug file", which is the ELF
file that contains the DWARF sections describing the code in the
main file--this is either the main file itself, or it's the separate
debuginfo file (or else there is none to be had).

When reading /proc/PID/maps, you are looking at the kernel virtual
memory system's view of the process address space.  This is precise
about boundaries that arise purely from implementation details of
the vm system and how exactly things have been used.  This is
informative about what program-level mappings there are, but does
not give a one-to-one correspondence with program-level ideas of
mappings, mmap calls, or libdwfl "module" boundaries.  Basically,
you shouldn't be worrying about this because other components worry
about it for you.

The Dwfl type represents one process address space, with the set of
modules (Dwfl_Module) being used therein.  The dwfl_report_* calls
are how an application maintains a Dwfl object with the right set of
modules.  The Frysk infrastructure is already responsible for
maintaining a Dwfl for an address space you're interested in.  This
is already used for the source line information.  Any component you
are writing should not have to worry about any dwfl_report_* calls
of any kind.  You should be starting out with a Dwfl that is already
populated with modules.  If you have a run-time address you are
considering, "dwfl_addrmodule (dwfl, address)" gets the module you want.

dwfl_module_relocation_info and related calls do not do what you seem to
have thought they did.  These are strictly for producing storable static
representations of run-time addresses that can be relocated for another
instance of the same code later where run-time addresses differ.  This
is used by systemtap, for example.  This has nothing to do with a
general query about ELF sections related in some way to an address.  As
you've noticed, there are never any section names used by these calls
for executable and DSO modules, which are the only kinds you will
encounter.  The index returned by dwfl_module_relocate_address is purely
for calling dwfl_module_relocation_info, and has no intrinsic meaning.

Trying to read the file yourself is not the way to go.  libdwfl is
already reading that file, and the reason the libraries are there is to
help you deal with the contents of such files.  What you need for
libunwind is to get the contents of the .eh_frame and .eh_frame_hdr
sections available in memory.

Given a module, dwfl_module_getelf gives you an Elf * open on the main
ELF file.  This is the open file description for the main ELF file,
which contains anything represented by an address.  (If you wanted the
debug file, you could use "dwarf_getelf (dwfl_module_getdwarf (mod))".
That is not what you need at the moment.  I can surmise from the fact
that you asked about finding frame data by address that libunwind still
only handles .eh_frame format and not .debug_frame format; but that is a
subject for another day.)

You want to use libelf calls to get at the chunks of the file that you
need to hand to libunwind.  When you have an address to start with,
there are two ways to translate that into part of the ELF file.  For
now, let's stick just with sections, which is one of those two ways.
I'm adding a convenience function to elfutils:

	/* Find the ELF section that *ADDRESS lies inside and return it.
	   On success, adjusts *ADDRESS to be relative to the section,
	   and sets *BIAS to the difference between addresses used in
	   the returned section's headers and run-time addresses.  */
	extern Elf_Scn *dwfl_module_address_section (Dwfl_Module *mod,
						     Dwarf_Addr *address,
						     Dwarf_Addr *bias)
	  __nonnull_attribute__ (2, 3);

But you can already do the equivalent of that pretty simply.  
From dwfl_module_getelf you got an Elf *, and an address bias.
Look at each section for the address you want:

	Dwarf_Addr bias;
	Elf *elf = dwfl_module_getelf (mod, &bias);
	Elf_Scn *scn = NULL;
	while ((scn = elf_nextscn (elf, scn)) != NULL)
	  {
	    GElf_Shdr shdr_mem;
	    GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
	    if (shdr == NULL)
	      ... libelf error ...;
	    if ((shdr->sh_flags & SHF_ALLOC)
		&& address >= shdr->sh_addr + bias
		&& address < shdr->sh_addr + bias + shdr->sh_size)
	      {
		address -= shdr->sh_addr + bias;
	        break;
	      }
	  }

That approximates:

	Dwarf_Addr bias;
	Elf_Scn *scn = dwfl_module_address_section (mod, &address, &bias);
	
Then you get the raw contents for the Elf_Scn into memory:

	if (scn == NULL)
	  ... did not find it! ...;
	Elf_Data *contents = elf_rawdata (scn, NULL);
	... use contents->d_buf, contents->d_size bytes long ...


Thanks,
Roland

      reply	other threads:[~2007-04-19  3:02 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-16 15:29 Nurdin Premji
2007-04-19  9:20 ` Roland McGrath [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070419030227.C35221800A1@magilla.sf.frob.com \
    --to=roland@redhat.com \
    --cc=frysk@sources.redhat.com \
    --cc=npremji@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).