I found the race condition. Seems Process::LoadCore() doesn't ensure the target
is stopped before it returns:
Crashed Thread: 7
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT
Thread 0:: Dispatch queue: com.apple.main-thread
0 _lldb.so 0x000000010df4d161
std::__1::weak_ptr<lldb_private::Process>::lock() const + 1
1 _lldb.so 0x000000010fcc1d63
lldb_private::UnwindLLDB::DoGetFrameInfoAtIndex(unsigned int, unsigned long
long&, unsigned long long&) + 75
2 _lldb.so 0x000000010fd88c8b
lldb_private::Unwind::GetFrameInfoAtIndex(unsigned int, unsigned long long&,
unsigned long long&) + 61
3 _lldb.so 0x000000010fd87766
lldb_private::StackFrameList::GetFramesUpTo(unsigned int) + 286
4 _lldb.so 0x000000010fd882c1
lldb_private::StackFrameList::GetFrameAtIndex(unsigned int) + 185
5 _lldb.so 0x000000010fd63060
lldb_private::Thread::GetSelectedFrame() + 48
6 _lldb.so 0x000000010df4008b
lldb::SBThread::GetSelectedFrame() + 203
7 _lldb.so 0x000000010dff19e5
_wrap_SBThread_GetSelectedFrame(_object*, _object*) + 128
8 org.python.python 0x000000010ce7c7c9 PyEval_EvalFrameEx +
14387
9 org.python.python 0x000000010ce7f60e 0x10cdf5000 + 566798
10 org.python.python 0x000000010ce7c3e3 PyEval_EvalFrameEx +
13389
11 org.python.python 0x000000010ce7f60e 0x10cdf5000 + 566798
12 org.python.python 0x000000010ce7c3e3 PyEval_EvalFrameEx +
13389
13 org.python.python 0x000000010ce7f60e 0x10cdf5000 + 566798
14 org.python.python 0x000000010ce7c3e3 PyEval_EvalFrameEx +
13389
15 org.python.python 0x000000010ce78d62 PyEval_EvalCodeEx +
1413
16 org.python.python 0x000000010ce787d7 PyEval_EvalCode + 54
17 org.python.python 0x000000010ce987bd 0x10cdf5000 + 669629
18 org.python.python 0x000000010ce98860 PyRun_FileExFlags +
133
19 org.python.python 0x000000010ce983fd
PyRun_SimpleFileExFlags + 769
20 org.python.python 0x000000010cea9b23 Py_Main + 3051
21 libdyld.dylib 0x00007fff87fa25c9 start + 1
Thread 7 Crashed:
0 _lldb.so 0x000000010df4d17c
std::__1::weak_ptr<lldb_private::Process>::lock() const + 28
1 _lldb.so 0x000000010fcc1d63
lldb_private::UnwindLLDB::DoGetFrameInfoAtIndex(unsigned int, unsigned long
long&, unsigned long long&) + 75
2 _lldb.so 0x000000010fd88c8b
lldb_private::Unwind::GetFrameInfoAtIndex(unsigned int, unsigned long long&,
unsigned long long&) + 61
3 _lldb.so 0x000000010fd8795e
lldb_private::StackFrameList::GetFramesUpTo(unsigned int) + 790
4 _lldb.so 0x000000010fd87246
lldb_private::StackFrameList::ResetCurrentInlinedDepth() + 46
5 _lldb.so 0x000000010fda1bcf
lldb_private::Thread::ShouldStop(lldb_private::Event*) + 719
6 _lldb.so 0x000000010fda7790
lldb_private::ThreadList::ShouldStop(lldb_private::Event*) + 488
7 _lldb.so 0x000000010fd77f19
lldb_private::Process::ShouldBroadcastEvent(lldb_private::Event*) + 379
8 _lldb.so 0x000000010fd754c5
lldb_private::Process::HandlePrivateEvent(std::__1::shared_ptr<lldb_private::Event>&)
+ 365
9 _lldb.so 0x000000010fd7865b
lldb_private::Process::RunPrivateStateThread() + 511
10 _lldb.so 0x000000010fd7810f
lldb_private::Process::PrivateStateThread(void*) + 9
11 libsystem_pthread.dylib 0x00007fff81357268 _pthread_body + 131
12 libsystem_pthread.dylib 0x00007fff813571e5 _pthread_start + 176
13 libsystem_pthread.dylib 0x00007fff8135541d thread_start + 13
Thread 7 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000001 rbx: 0x000000012a2ce798 rcx: 0x0000000000000000
rdx: 0x0000000000000000
rdi: 0x000000012a2ce798 rsi: 0x10000000000000f0 rbp: 0x000000012a2ce780
rsp: 0x000000012a2ce770
r8: 0x0000000000000000 r9: 0x000000012a2cf000 r10: 0x00007f8fca82f400
r11: 0x00007f8fca82fdd0
r12: 0x0000000000000000 r13: 0x00007f8fc951b9a0 r14: 0x10000000000000f0
r15: 0x000000012a2cea10
rip: 0x000000010df4d17c rfl: 0x0000000000010206 cr2: 0x000000010fea75f8
The issue is we have a read/write lock that controls when stuff can be done to
a process. Multiple threads can request that the run lock stay stopped, and
only one can request that it runs. So the problem is we call
lldb::SBThread::GetSelectedFrame() on the main thread while the private state
thread is still finding out that the process has stopped.
lldb::SBThread::GetSelectedFrame() tries to get the run lock and keep the
process stopped, and it succeeds because LoadCore wasn't synchronously making
sure the core file was ready to be played with.
So the solution is to make sure that SBTarget::LoadCore() is a synchronous call
that has the target stopped _before_ it returns. Then the process will be setup
and ready to allow requests.
A work around for now is to call time.sleep(1) after calling LoadCore() to give
the Process::PrivateStateThread() time to get settled. Other race conditions
could cause the run lock to no be acquired:
lldb::SBFrame
SBThread::GetSelectedFrame ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
SBFrame sb_frame;
StackFrameSP frame_sp;
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
if (exe_ctx.HasThreadScope())
{
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
{
}
else
{
if (log)
log->Printf ("SBThread(%p)::GetSelectedFrame() => error:
process is running",
static_cast<void*>(exe_ctx.GetThreadPtr()));
}
And an error would be returned and an empty SBFrame would be returned.
I'll have a fix committed shortly.
Greg
> On Feb 20, 2015, at 11:18 AM, Paul Smith <[email protected]> wrote:
>
> #!/usr/bin/env python
>
> import lldb
> import sys
>
> def load_core(debugger, exe, core):
> """
>
> @param exe: Path to the executable binary
> @param core: Path to the core
> @rtype: SBProcess
> @return:
> """
> target = debugger.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT)
> """ @type : SBTarget """
> if target:
> process = target.LoadCore(core)
> """ @type : SBProcess """
> if process:
> return process
>
> raise Exception("Could not load core")
> raise Exception("Could not create target")
>
>
> def print_version(process):
> """
> @type process: SBProcess
> """
> thread = process.GetSelectedThread()
> """ @type : SBThread """
> if thread:
> frame = thread.GetSelectedFrame()
> """ @type : SBFrame """
> if frame:
> version = frame.EvaluateExpression('globals->version.data')
> """ @type : SBValue """
> if version:
> err = lldb.SBError()
> version_string =
> process.ReadCStringFromMemory(int(version.GetValue(), 16), 512, err)
> if err.Success():
> print("*** Version: " + version_string)
> else:
> print("*** Error extracting version")
> print("")
> return
>
> raise Exception("Invalid expression result, can't extract version")
> raise Exception("Invalid frame, can't extract version")
> raise Exception("Invalid thread, can't extract version")
>
>
> def print_all_backtraces(process):
> """
> @type process: SBProcess
> """
> print("*** All Threads Backtrace:")
> for thread in reversed(process.threads):
> if thread:
> print_backtrace(thread)
> else:
> print("ERROR: Failed to print backtrace for a thread")
>
>
> def print_backtrace(thread, include_label=False):
> """
> @type thread: SBThread
> """
> if include_label:
> print("*** Backtrace:")
>
> print("Thread %d (core thread %d):" % (thread.GetIndexID(),
> thread.GetThreadID()))
> for frame in thread:
> if frame:
> print(frame)
> else:
> print("ERROR: Failed to print a frame")
>
> print("")
>
>
> def print_environment(process):
> """
> @type process: SBProcess
> """
> print("*** Environment:")
> print(' ' + '\n '.join(read_null_term_array(process,
> 'globals->environment->envp')))
> print("")
>
>
> def read_null_term_array(process, expr, max_length=1000):
> """
> @type process: SBProcess
> """
> thread = process.GetSelectedThread()
> """ @type : SBThread """
> if thread:
> frame = thread.GetSelectedFrame()
> """ @type : SBFrame """
> if frame:
> array_value = frame.EvaluateExpression(expr)
> """ @type : SBValue """
> if array_value:
> array_address = array_value.GetValueAsUnsigned()
> idx = 0
> ptr_err = lldb.SBError()
> array_data = []
> for i in xrange(0, max_length):
> element_ptr = process.ReadPointerFromMemory(array_address
> + idx * array_value.GetByteSize(),
> ptr_err)
> if ptr_err.Success():
> if element_ptr == 0:
> break
>
> val_err = lldb.SBError()
> element = process.ReadCStringFromMemory(element_ptr,
> 1024*10, val_err)
> if val_err.Success():
> array_data.append(element)
> else:
> print("ERROR: Unable to read value at address %s"
> % (str(element_ptr)))
>
> idx += 1
> else:
> print("ERROR: Unable to read pointer at address %s" %
> (str(array_address + idx *
> array_value.GetByteSize()),))
> break
>
> return array_data
>
> raise Exception("Unable to read array address for %s" % (expr,))
> raise Exception("Invalid frame for %s" % (expr,))
> raise Exception("Invalid thread for %s" % (expr,))
>
>
> def main():
> if len(sys.argv) != 3:
> print("usage: python %s core_file exe_file" % (sys.argv[0],))
> exit(1)
>
> core = sys.argv[1]
> exe = sys.argv[2]
>
> debugger = lldb.SBDebugger.Create()
> """ @type : SBDebugger """
>
> process = load_core(debugger, exe, core)
> if process:
> print_version(process)
> print_backtrace(process.GetSelectedThread(), True)
> print_all_backtraces(process)
> print_environment(process)
> else:
> print("Failed to debug core " + core)
>
> if __name__ == '__main__':
> main()
_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev