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 <p...@mad-scientist.net> 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
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to