public inbox for frysk@sourceware.org
 help / color / mirror / Atom feed
* Libunwind and elfutils question.
@ 2007-04-16 15:29 Nurdin Premji
  2007-04-19  9:20 ` Roland McGrath
  0 siblings, 1 reply; 2+ messages in thread
From: Nurdin Premji @ 2007-04-16 15:29 UTC (permalink / raw)
  To: frysk

All work on the following is being done on branch 
npremji-libunwind-find-proc-info-20070329-branch.

I am trying to abstract out the code that libunwind uses to load an elf 
image into memory. Then the address of the elf image and size can be 
passed to libunwind, and libunwind does not need to worry about how it 
was obtained. This will enable multi-platform unwinding and will also 
allow unwinding of core files.

I have reached the point were I am fairly confident that I am loading 
the elf image into memory correctly. However libunwind also requires the 
segbase and mapoffset. In a /proc/pid/maps file, these correspond to the 
start address and offset fields of the section that the given ip is in.

My goal is to find these fields. (Given an ip, and pid).

I have used elfutils to find out the name of the elf image. Elfutils, 
like libunwind, looks through the processes /proc/pid/maps file to find 
which elf object to use.  Elfutils does this through the 
dwfl_linux_proc_report method, which calls proc_maps_report (in 
libdwfl/linux-proc-maps.c). However elfutils creates a single module for 
each elf object whereas in a proc/pid/maps, there may be several, not 
necessarily contiguous (in terms of start-end addresses) sections 
corresponding to a single DwflModule. So while elfutils does return a 
low address value for the module, it may not correspond to the section 
in the maps file. Elfutils does not return the offset field.

I was looking at the dwfl_module_relocation methods, specifically:
int idx = dwfl_module_relocate_address(dwflModule, ip);
which returns an index to a section.

Gelf_Word *shndxp;
dwfl_module_relocation_info(dwflModule, idx, shndxp);
which returns a section header index.

Elf_Shdr = get shdr from shndxp.

and use shdr.sh_addr and shdr.sh_offset for the base address and map 
offset respectively.

However I do not know whether a relocation section corresponds to a 
/proc/pid/map. Elfutils mentions that executables will have 0 indexes, 
and dynamic libraries will have only 1. So I could be mistaken in my 
assumption that this is the data I am looking for.

So how do I find out the value for these two fields?

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

* Re: Libunwind and elfutils question.
  2007-04-16 15:29 Libunwind and elfutils question Nurdin Premji
@ 2007-04-19  9:20 ` Roland McGrath
  0 siblings, 0 replies; 2+ messages in thread
From: Roland McGrath @ 2007-04-19  9:20 UTC (permalink / raw)
  To: Nurdin Premji; +Cc: frysk

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

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

end of thread, other threads:[~2007-04-19  3:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-16 15:29 Libunwind and elfutils question Nurdin Premji
2007-04-19  9:20 ` Roland McGrath

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).