Questions for module/symbol load/unload events

Hi,

I am trying to listen for module/symbol load/unload events and display them in output UI so that debugger users can have a basic clue what is debugger busy doing while launching a big executable linking many shared libraries.

Questions:

  1. I did not find an API to get current load/unload module during module events. I was expecting some static API like lldb.SBModule(or SBTarget).GetModuleFromEvent(SBEvent), but this does not exists. I tried to treat current PC’s module as loading module in module load/unload events. But that does not work too(I think because process is not stopped in module load/unload events). Do I miss something here?

  2. Even though “image list” shows I have around 42 modules loaded in process, I only got two module load events. Why is that?

  3. Even though I added lldb.SBTarget.eBroadcastBitSymbolsLoaded, there is no event of type eBroadcastBitSymbolsLoaded generated. Is it expected? Apparently I have the symbols next to the binary.

This is tested on mac OSX lldb.

Jeffrey

Hi,

I am trying to listen for module/symbol load/unload events and display them in output UI so that debugger users can have a basic clue what is debugger busy doing while launching a big executable linking many shared libraries.

Questions:

  1. I did not find an API to get current load/unload module during module events. I was expecting some static API like lldb.SBModule(or SBTarget).GetModuleFromEvent(SBEvent), but this does not exists. I tried to treat current PC’s module as loading module in module load/unload events. But that does not work too(I think because process is not stopped in module load/unload events). Do I miss something here?

From SBTarget.h:

static uint32_t
GetNumModulesFromEvent (const lldb::SBEvent &event);

static lldb::SBModule
GetModuleAtIndexFromEvent (const uint32_t idx, const lldb::SBEvent &event);

Note, you can also cause the process to stop with modules are loaded with the setting:

target.process.stop-on-sharedlibrary-events

if that is more convenient for you.

  1. Even though “image list” shows I have around 42 modules loaded in process, I only got two module load events. Why is that?

On OS X the loader loads the closure of modules for whatever it is loading, and only stops and informs the debugger when this is all done. So it is quite usual to see only a few load events even though many modules get loaded.

  1. Even though I added lldb.SBTarget.eBroadcastBitSymbolsLoaded, there is no event of type eBroadcastBitSymbolsLoaded generated. Is it expected? Apparently I have the symbols next to the binary.

That event gets sent when symbols are added to an already loaded module. It is so a UI will know to refresh the backtrace, local variables, source view, etc when code goes from having no symbols to having some symbols. Those actions are not needed if the library & its symbols get loaded simultaneously, so it isn’t sent in that case.

Jim

This is very useful, thanks for the info!

In general where you see the event bits defined like SBTarget.h for your case, the class that contains the event bit definitions:

class SBTarget
{
public:
    //------------------------------------------------------------------
    // Broadcaster bits.
    //------------------------------------------------------------------
    enum
    {
        eBroadcastBitBreakpointChanged = (1 << 0),
        eBroadcastBitModulesLoaded = (1 << 1),
        eBroadcastBitModulesUnloaded = (1 << 2),
        eBroadcastBitWatchpointChanged = (1 << 3),
        eBroadcastBitSymbolsLoaded = (1 << 4)
    };
...

Also contains all of the static functions that can extract data from those events:

class SBTarget
{
public:
...
    static bool
    EventIsTargetEvent (const lldb::SBEvent &event);

    static lldb::SBTarget
    GetTargetFromEvent (const lldb::SBEvent &event);
    
    static uint32_t
    GetNumModulesFromEvent (const lldb::SBEvent &event);

    static lldb::SBModule
    GetModuleAtIndexFromEvent (const uint32_t idx, const lldb::SBEvent &event);

Greg Clayton

I see why I did not find them in the first place. These two APIs are not listed in the official doc:
http://lldb.llvm.org/python_reference/index.html

Someone might want to add it.

Thanks
Jeffrey

Greg, missed your reply. Yeah, the problem is that I only looked at the python API(which is what I am using) doc which does not contain these APIs.

Btw: I did not find an API to retrieve the load address of the SBModule? This seems to be weird to me, did I miss anything?

There isn’t necessarily A load address for an SBModule. After all, the different segments could load with different offsets. We usually list the offset of the TEXT address as the load address - for instance in “image list", since if you are only interested in symbolication, that’s what you care about. But there isn’t just one load address.

Jim

As Jim said there really isn't just one address per module. You will want to display the address of each of the sections for a module under that module. So something like:

a.out
  >- .text @ 0x10000
  >- .data @ 0x20000
  \- .bss @ 0x30000

My assumption is that different sections of the binary will be mapped continuously in memory; and the first section(which should be a header section for the binary) will stands for the base address of the whole module.
Is this assumption not true for all platforms? Basically, I would like to show the memory range of the whole module, instead of just text section, so that if a debugger user got a magic address, he can quickly examine the image list to see which binary this address falls into. I guess I can calculate and combine all sections, but it is a bit cumbersome to do.

That is not correct for all platforms. On MacOSX, any shared library in your DYLD shared cache will have its sections mapped all over the place:

libfoo.dylib __TEXT 0x100000
barfoo.dylib __TEXT 0x200000
libfoo.dylib __DATA 0x8100000
barfoo.dylib __TEXT 0x8200000
libfoo.dylib __OBJC 0x9100000
barfoo.dylib __OBJC 0x9200000

So you can't make any assumptions. That being said, each platform has the notion of where a library is actually loaded. For MacOSX, this is the address of the __TEXT segment. Not sure for other platforms.

The easy thing for you to do it to show the largest address range that contains all sections in a shared library. Get all sections from the module and then calculate the min and max address of all sections and then use the largest address range so show the addresses that the shared library could contain. It doesn't mean that a shared library does contain and address since the above shared libraries from my example above would be something like:

libfoo.dylib [0x100000 - 0x91fffff]
barfoo.dylib [0x200000 - 0x92fffff]

Note that they overlap, but this does show correct info to the user...