This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Difficulties while adding local init_regs support to libebl


Hi Ben,

[Maybe read it all first before trying anything. At the end I think I
got the correct solution, I start with some more cumbersome
workarounds...]

On Thu, 2015-09-03 at 22:10 +0200, Ben Gamari wrote:
> I now have a few patches [1] adding support for collecting initial
> register values from the current thread. While I believe the initial
> register collection logic works (it works for GHC), I have encountered
> an unfortunate issue while folding this code into libebl. Namely, it
> seems that libebl backends are dynamically loaded.
> 
> To see why this is problematic, consider this example,
>
>   void test() {
>     Dwfl *dwfl = dwfl_begin (&proc_callbacks);
> 
>     // Figure out what modules are loaded
>     dwfl_linux_proc_report(dwfl, getpid());
>     dwfl_report_end (dwfl, NULL, NULL);
> 
>     // but the ebl backend, libebl_x86_64.so, only gets loaded here
>     dwfl_linux_local_attach(dwfl);
> 
>     // therefore when we begin to unwind we have no debug information
>     // for libebl, which is where PC sits when we collect the initial
>     // register values. Unwinding consequently fails
>     dwfl_getthread_frames (dwfl, getpid(), frame_cb, dwfl) != 0;
>   }
> 
> The issue here is that debug information is not reported to libdwfl as
> it is not loaded at the time we report the loaded modules.

Ah, interesting case indeed. I think the easiest workaround for now
would just be to cheat and force the load of the native ebl backend in
some initial setup/initialization function:

static Dwfl *dwfl;
init ()
{
  Dwfl_Module *mod;
  Dwarf_Addr bias;
  Dwarf_CFI *cfi;

  dwfl = dwfl_begin (&proc_callbacks);
  dwfl_linux_proc_report(dwfl, getpid());
  dwfl_report_end (dwfl, NULL, NULL);
pc_here:
  mod = dwfl_addrmodule (dwfl, (Dwarf_Addr) &&pc_here);
  cfi = dwfl_module_eh_cfi (mod, &bias);

  // Don't do this, it will unload the backend again.
  // dwfl_end (dwfl);
}

But then checking none of the functions fail of course. The
dwfl_module_eh_cfi () will force the loading of the native backend.

You could even cheat a bit more and just call ebl_openbackend ()
directly yourself. But that isn't officially supported.

> At this point I'm a bit unsure of how to proceed. I can think of a few
> options,
> 
>   * teach dwfl_linux_local_attach to report libebl when it gets
>     loaded. This would be rather ugly as we would either need to
>     re-read the /proc map data or somehow extract the necessary
>     information from the dynamic linker

It might be interesting to have a Dwfl *dwfl_linux_local_report () that
creates a Dwfl using the dynamic linker structures. It could come with a
_refresh function or keep things automagically up to date (although that
might be tricky with threading). But that seems a but more work than
what you signed up for right now.

>   * Expose an entirely different interface from dwfl_getthread_frames
>     for local unwinding such that PC doesn't sit within libebl when
>     initial register values are collected.
> [...[
>     Unfortunately this is quite a departure from the current interface
>     and seems to break the nice separation between libebl and the
>     libdwfl.

Yeah, that seems not great.

>   * Something I haven't yet thought of...

Maybe you could just do:

  dwfl_report_begin (dwfl);
  dwfl_linux_proc_report(dwfl, getpid());
  dwfl_report_end (dwfl, NULL, NULL);

after dwfl_linux_local_attach (), but before dwfl_getthread_frames ().

That is supported to simply refreshes the Dwfl_Modules into the Dwfl.
The only downside is that you reparse the /proc/pid/maps again, so it
isn't as efficient as it could be.

O, I should have thought of this at the start. Maybe you could just
start with an empty Dwfl. Do you need to call dwfl_linux_proc_report ()
before dwfl_linux_local_attach () at all? dwfl_linux_local_attach ()
should be able to figure out the ebl backend it needs on its own. Then
you could just report the modules as above after you called
dwfl_linux_local_attach ().

Cheers,

Mark

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]