No stopping event during launch(stop_at_entry=True) on Linux?

Hi,

I have got lldb launch working fine on my macbook for sometime. But when I try the same code on Linux, it failed to emit any stopping events during initial launch.

When I run the reproduce code(listed at the end), I got the following different results:

The key difference is that Macbook will emit a stopped event which caused our IDE UI to enter break mode, while Linux violates this assumption. Is this a bug?

======================Mac======================

lldb_pythonpath: /Applications/Xcode.app/Contents/Developer/…/SharedFrameworks/LLDB.framework/Resources/Python
Launch result: success
Listening Thread ID: 4610625536

Target event: ModulesLoaded
Process event: StateChanged, Stopped
Stop reason: 5
bt

  • thread #1: tid = 0x101f01d, 0x00007fff6401a000 dyld`_dyld_start, stop reason = signal SIGSTOP
  • frame #0: 0x00007fff6401a000 dyld`_dyld_start

======================Mac======================

======================Linux======================

python linux_launch.py
find_lldb: <module ‘lldb’ from ‘/home/jeffreytan/project/llvm-bin/Debug+Asserts/lib/python2.7/site-packages/lldb/init.pyc’>
Launch result: success
Listening Thread ID: 140316621375232

bt

  • thread #1: tid = 2794520, 0x00007f6165b7bb00, name = ‘foo’, stop reason = signal SIGSTOP
  • frame #0: 0x00007f6165b7bb00
    ======================Linux======================

============================Repro main.py============================

Should be first for LLDB package to be added to search path.

from find_lldb import lldb
import sys
import os
import time
from sys import stdin, stdout
from event_thread import LLDBListenerThread
import threading

def interctive_loop(debugger):
while (True):
stdout.write('dbg> ')
command = stdin.readline().rstrip()
if len(command) == 0:
continue
if command == ‘q’:
return
debugger.HandleCommand(command)

def do_test():
debugger = lldb.SBDebugger.Create()
debugger.SetAsync(True)
executable_path = ‘~/Personal/compiler/CompilerConstruction/code/compiler’
target = debugger.CreateTargetWithFileAndArch(executable_path, lldb.LLDB_ARCH_DEFAULT)

listener = lldb.SBListener(‘Event Listener’)
error = lldb.SBError()
process = target.Launch (listener,
None, # argv
None, # envp
None, # stdin_path
None, # stdout_path
None, # stderr_path
None, # working directory
0, # launch flags
True, # Stop at entry
error) # error
print ‘Launch result: %s’ % str(error)

running_signal = threading.Event()
stopped_signal = threading.Event()
event_thread = LLDBListenerThread(debugger, running_signal, stopped_signal)
event_thread.start()

interctive_loop(debugger)

event_thread.should_quit = True
event_thread.join()

lldb.SBDebugger.Destroy(debugger)
return debugger

def main():
debugger = do_test()

if name == ‘main’:
main()

============================Event_thread============================

class LLDBListenerThread(Thread):
should_quit = False

def init(self, debugger, running_signal=None, stopped_sigal=None):
Thread.init(self)
self._running_signal = running_signal
self._stopped_sigal = stopped_sigal
process = debugger.GetSelectedTarget().process
self.listener = debugger.GetListener()
self._add_listener_to_process(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 = lldb.SBTarget.eBroadcastBitBreakpointChanged | lldb.SBTarget.eBroadcastBitWatchpointChanged | lldb.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 = lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR | lldb.SBProcess.eBroadcastBitInterrupt
broadcaster.AddListener(self.listener, mask)

def run(self):
print ‘ Listening Thread ID: %d’ % thread.get_ident()
while not self.should_quit:
event = lldb.SBEvent()
if self.listener.WaitForEvent(1, event):
if lldb.SBTarget.EventIsTargetEvent(event):
self._handle_target_event(event)
elif lldb.SBProcess.EventIsProcessEvent(event):
self._handle_process_event(event)
elif lldb.SBBreakpoint.EventIsBreakpointEvent(event):
self._handle_breakpoint_event(event)
elif lldb.SBThread.EventIsThreadEvent(event):
self._handle_thread_event(event)
else:
self._handle_unknown_event(event)
print ‘ Exiting listener thread’

def _handle_target_event(self, event):
event_type = event.GetType()
print ‘Target event: %s’ % target_event_type_to_name_map[event_type]

def _handle_process_event(self, event):
if lldb.SBProcess.GetRestartedFromEvent(event):
print ‘Non stopping event: %s’ % str(event)
return
process = lldb.SBProcess.GetProcessFromEvent(event)
event_type = event.GetType()
print ‘Process event: %s, %s’ % (process_event_type_to_name_map[event_type], process_state_name_map[process.state])
if process.state == lldb.eStateExited:
self.should_quit = True
elif process.state == lldb.eStateStopped:
if self._stopped_sigal:
self._stopped_sigal.set()
else:
if self._running_signal:
self._running_signal.set()

thread = process.selected_thread
print ‘Stop reason: %d’ % thread.GetStopReason()
if event_type == lldb.SBProcess.eBroadcastBitSTDOUT:
print ‘Stdout:’
while True:
output = process.GetSTDOUT(1024)
if len(output) == 0:
break
stdout.write(output)

def _handle_breakpoint_event(self, event):
breakpoint = lldb.SBBreakpoint.GetBreakpointFromEvent(event)
event_type = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event)
print ‘Breakpoint event: [%s] %s’ % (breakpoint_event_type_to_name_map[event_type], str(breakpoint))

def _handle_unknown_event(self, event):
print ‘Unknown event’

If the linux side is not obeying "stop_at_entry" then that is a bug.

Jim

I am not sure. From the output, it seems lldb does stop at the entry point(because you can issue “bt” command to dump the stack) in both platforms; the problem seems to be that it did not emit the stopped event for its stop on linux.

That also is a bug. If it is going to do a public stop, it has to send a stop event.

Jim

Makes sense, will file a bug for it.

This is a known bug (bugzilla is slugish right now, so I can't look up
the number). The stopped event does not seem to get through most of
the times, although the stop is actually performed. I am afraid I
can't offer any workaround for the time being...