[lldb-dev] Understanding debugger launch events sequence

Jeffrey.fudan via lldb-dev lldb-dev at lists.llvm.org
Fri Jan 29 08:54:10 PST 2016


Great, this is very helpful, will give a try.
Btw: is there any threading requirement of lldb API? For example, are all the Apis must be called on the event thread or they are free to be called on any thread? I know windows debug API has some limitation on this.

Sent from my iPad

> On Jan 29, 2016, at 2:59 AM, Pavel Labath <labath at google.com> wrote:
> 
> Hi Jeffrey,
> 
> I see a couple of problems with the way you are using the lldb's API.
> The main problem is you are launching the target via the command-line
> API, which does not allow you to specify the listener upon creation.
> When you start it this way all events go to the default debugger
> listener (debugger.GetListener()), and by the time you connect your
> own listener, some of these events have already been broadcast, and
> that is why you get nondeterministic behavior. You should use the
> SBTarget.Launch function to specify the listener from the start.
> 
> The second problem is the handling of the Stopped events. Sometimes
> LLDB needs to stop the inferior do to some internal work, but this the
> program is immediately resumed. This event is broadcast as a "stopped"
> event with a special "restarted" bit set (see
> SBProcess.GetRestartedFromEvent, and
> <http://lists.llvm.org/pipermail/lldb-dev/2016-January/009291.html>)
> 
> hope that helps,
> pl
> 
> 
> 
> On 29 January 2016 at 03:53, Jeffrey Tan via lldb-dev
> <lldb-dev at lists.llvm.org> wrote:
>> Hi,
>> 
>> On mac OS, I am having difficulty understanding the launch debugger events
>> sequence of lldb. I used the following code to play around LLDB. I found,
>> for some binaries, debugger will enter stopped/paused mode, waiting for my
>> further input, print stack shows:
>> dbg> bt
>> * thread #1: tid = 0x15153e, 0x00007fff5fc0d2af
>> dyld`gdb_image_notifier(dyld_image_mode, unsigned int, dyld_image_info
>> const*) + 1
>>  * frame #0: 0x00007fff5fc0d2af dyld`gdb_image_notifier(dyld_image_mode,
>> unsigned int, dyld_image_info const*) + 1
>>    frame #1: 0x000000000000401d
>> 
>> But some other binaries, it just print "Process event: stopped, reason: 1"
>> and inferior just exits immediately without waiting for debugger's further
>> input.
>> 
>> Questions:
>> 1. When I launch a binary, is there supposed to be a loader breakpoint
>> waiting for debugger continue? Any other debug events do I expect to get and
>> continue?
>> 2. What about attach?
>> 3. What is the dyld`gdb_image_notifier() debugger break above? Why does it
>> happen for some binary but not others?
>> 
>> Thanks for any information!
>> 
>> # Should be first for LLDB package to be added to search path.
>> from find_lldb import lldb
>> from lldb import eStateStepping, eStateRunning, eStateExited, SBBreakpoint,
>> SBEvent, SBListener, SBProcess, SBTarget
>> import sys
>> import os
>> import subprocess
>> from sys import stdin, stdout
>> from threading import Thread
>> 
>> class LLDBListenerThread(Thread):
>>    should_quit = False
>> 
>>    def __init__(self, process):
>>      Thread.__init__(self)
>>      self.listener = SBListener('Chrome Dev Tools Listener')
>>      self._add_listener_to_process(process)
>>      self._broadcast_process_state(process)
>>      self._add_listener_to_target(process.target)
>> 
>>    def _add_listener_to_target(self, target):
>>        # Listen for breakpoint/watchpoint events
>> (Added/Removed/Disabled/etc).
>>        broadcaster = target.GetBroadcaster()
>>        mask = SBTarget.eBroadcastBitBreakpointChanged |
>> SBTarget.eBroadcastBitWatchpointChanged |
>> SBTarget.eBroadcastBitModulesLoaded
>>        broadcaster.AddListener(self.listener, mask)
>> 
>>    def _add_listener_to_process(self, process):
>>        # Listen for process events (Start/Stop/Interrupt/etc).
>>        broadcaster = process.GetBroadcaster()
>>        mask = SBProcess.eBroadcastBitStateChanged
>>        broadcaster.AddListener(self.listener, mask)
>> 
>>    def _broadcast_process_state(self, process):
>>        state = 'stopped'
>>        if process.state == eStateStepping or process.state ==
>> eStateRunning:
>>            state = 'running'
>>        elif process.state == eStateExited:
>>            state = 'exited'
>>            self.should_quit = True
>>        thread = process.selected_thread
>>        print 'Process event: %s, reason: %d' % (state,
>> thread.GetStopReason())
>> 
>>    def _breakpoint_event(self, event):
>>        breakpoint = SBBreakpoint.GetBreakpointFromEvent(event)
>>        print 'Breakpoint event: %s' % str(breakpoint)
>> 
>>    def run(self):
>>        while not self.should_quit:
>>            event = SBEvent()
>>            if self.listener.WaitForEvent(1, event):
>>                if event.GetType() == SBTarget.eBroadcastBitModulesLoaded:
>>                    print 'Module load: %s' % str(event)
>>                elif SBProcess.EventIsProcessEvent(event):
>> 
>> self._broadcast_process_state(SBProcess.GetProcessFromEvent(event))
>>                elif SBBreakpoint.EventIsBreakpointEvent(event):
>>                    self._breakpoint_event(event)
>> 
>> def _interctive_loop(debugger):
>>    process = debugger.GetSelectedTarget().process
>>    event_thread = LLDBListenerThread(process)
>>    event_thread.start()
>> 
>>    while (True):
>>        stdout.write('dbg> ')
>>        command = stdin.readline().rstrip()
>>        if len(command) == 0:
>>            continue
>>        debugger.HandleCommand(command)
>> 
>> 
>> def main():
>>    debugger = lldb.SBDebugger.Create()
>> 
>>    print('Working Directory: %s' % os.getcwd())
>>    debugger.HandleCommand('target create /usr/bin/find')
>>    debugger.HandleCommand('run .')
>>    _interctive_loop(debugger)
>> 
>> if __name__ == '__main__':
>>    main()
>> 
>> 
>> _______________________________________________
>> lldb-dev mailing list
>> lldb-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>> 


More information about the lldb-dev mailing list