[lldb-dev] Understanding debugger launch events sequence

Jim Ingham via lldb-dev lldb-dev at lists.llvm.org
Fri Jan 29 09:21:23 PST 2016


There is no requirement that the lldb API’s be called on a particular thread on OS X.  LLDB tries to be robust against being called from multiple threads simultaneously for the same debugger, but you can still make it fall over if you try hard, particularly if you allow multiple threads to restart the process you are debugging.  Running multiple SBDebuggers on separate threads works fine, that’s the mode Xcode uses, and we haven’t had problems with this in quite a while.

Jim

> On Jan 29, 2016, at 8:54 AM, Jeffrey.fudan via lldb-dev <lldb-dev at lists.llvm.org> wrote:
> 
> 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
>>> 
> _______________________________________________
> 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