summaryrefslogtreecommitdiffstats
path: root/lldb
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2014-05-13 22:02:48 +0000
committerJason Molenda <jmolenda@apple.com>2014-05-13 22:02:48 +0000
commitb4892cd266dfafb9c6986ee46a8025c8031c3792 (patch)
tree5b127dbb778899f9efbdd51026ef74edeceefbd1 /lldb
parent1b91aa2cf5141ee3dc4cbbf2e6bdb931b51411ff (diff)
downloadbcm5719-llvm-b4892cd266dfafb9c6986ee46a8025c8031c3792.tar.gz
bcm5719-llvm-b4892cd266dfafb9c6986ee46a8025c8031c3792.zip
Add a new SBThread::SafeToCallFunctions API; this calls over to
the SystemRuntime to check if a thread will have any problems performing an inferior function call so the driver can skip making that function call on that thread. Often the function call can be executed on another thread instead. <rdar://problem/16777874> llvm-svn: 208732
Diffstat (limited to 'lldb')
-rw-r--r--lldb/include/lldb/API/SBThread.h3
-rw-r--r--lldb/include/lldb/Target/SystemRuntime.h21
-rw-r--r--lldb/include/lldb/Target/Thread.h13
-rw-r--r--lldb/scripts/Python/interface/SBThread.i10
-rw-r--r--lldb/source/API/SBThread.cpp9
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp8
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp8
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp8
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp8
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp15
-rw-r--r--lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h3
-rw-r--r--lldb/source/Target/Thread.cpp16
-rw-r--r--lldb/test/macosx/safe-to-func-call/Makefile28
-rw-r--r--lldb/test/macosx/safe-to-func-call/TestSafeFuncCalls.py81
-rw-r--r--lldb/test/macosx/safe-to-func-call/main.c30
15 files changed, 261 insertions, 0 deletions
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h
index f3b34728085..c71b55a52b1 100644
--- a/lldb/include/lldb/API/SBThread.h
+++ b/lldb/include/lldb/API/SBThread.h
@@ -210,6 +210,9 @@ public:
uint32_t
GetExtendedBacktraceOriginatingIndexID ();
+ bool
+ SafeToCallFunctions ();
+
protected:
friend class SBBreakpoint;
friend class SBBreakpointLocation;
diff --git a/lldb/include/lldb/Target/SystemRuntime.h b/lldb/include/lldb/Target/SystemRuntime.h
index 294d509ee64..7c6383491f6 100644
--- a/lldb/include/lldb/Target/SystemRuntime.h
+++ b/lldb/include/lldb/Target/SystemRuntime.h
@@ -309,6 +309,27 @@ public:
{
}
+ //------------------------------------------------------------------
+ /// Determine whether it is safe to run an expression on a given thread
+ ///
+ /// If a system must not run functions on a thread in some particular state,
+ /// this method gives a way for it to flag that the expression should not be
+ /// run.
+ ///
+ /// @param [in] thread_sp
+ /// The thread we want to run the expression on.
+ ///
+ /// @return
+ /// True will be returned if there are no known problems with running an
+ /// expression on this thread. False means that the inferior function
+ /// call should not be made on this thread.
+ //------------------------------------------------------------------
+ virtual bool
+ SafeToCallFunctionsOnThisThread (lldb::ThreadSP thread_sp)
+ {
+ return true;
+ }
+
protected:
//------------------------------------------------------------------
// Member variables.
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index a7b800a943e..dfd8390b710 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -592,6 +592,19 @@ public:
virtual lldb::addr_t
GetThreadLocalData (const lldb::ModuleSP module);
+ //------------------------------------------------------------------
+ /// Check whether this thread is safe to run functions
+ ///
+ /// The SystemRuntime may know of certain thread states (functions in
+ /// process of execution, for instance) which can make it unsafe for
+ /// functions to be called.
+ ///
+ /// @return
+ /// True if it is safe to call functions on this thread.
+ /// False if function calls should be avoided on this thread.
+ //------------------------------------------------------------------
+ virtual bool
+ SafeToCallFunctions ();
//------------------------------------------------------------------
// Thread Plan Providers:
diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i
index ecf0475dec1..d1dd82a0cda 100644
--- a/lldb/scripts/Python/interface/SBThread.i
+++ b/lldb/scripts/Python/interface/SBThread.i
@@ -297,6 +297,16 @@ public:
uint32_t
GetExtendedBacktraceOriginatingIndexID();
+ %feature("autodoc","
+ Takes no arguments, returns a bool.
+ lldb may be able to detect that function calls should not be executed
+ on a given thread at a particular point in time. It is recommended that
+ this is checked before performing an inferior function call on a given
+ thread.
+ ") SafeToCallFunctions;
+ bool
+ SafeToCallFunctions ();
+
%pythoncode %{
class frames_access(object):
'''A helper object that will lazily hand out frames for a thread when supplied an index.'''
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 97bd6f4fed7..60731e85d0b 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -1437,3 +1437,12 @@ SBThread::GetExtendedBacktraceOriginatingIndexID ()
return thread_sp->GetExtendedBacktraceOriginatingIndexID();
return LLDB_INVALID_INDEX32;
}
+
+bool
+SBThread::SafeToCallFunctions ()
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp->SafeToCallFunctions();
+ return true;
+}
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
index 7d62548dbc5..64b2e229962 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp
@@ -269,6 +269,14 @@ AppleGetItemInfoHandler::GetItemInfo (Thread &thread, uint64_t item, addr_t page
error.Clear();
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
// Set up the arguments for a call to
// struct get_item_info_return_values
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
index ac39fef798b..51b797aa1ac 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp
@@ -274,6 +274,14 @@ AppleGetPendingItemsHandler::GetPendingItems (Thread &thread, addr_t queue, addr
error.Clear();
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
// Set up the arguments for a call to
// struct get_pending_items_return_values
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
index 403ebf1571f..cd15d475150 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp
@@ -282,6 +282,14 @@ AppleGetQueuesHandler::GetCurrentQueues (Thread &thread, addr_t page_to_free, ui
error.Clear();
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
// Set up the arguments for a call to
// struct get_current_queues_return_values
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
index 40b61fe9981..46e76663c47 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp
@@ -273,6 +273,14 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo (Thread &thread, tid_t thread_i
error.Clear();
+ if (thread.SafeToCallFunctions() == false)
+ {
+ if (log)
+ log->Printf ("Not safe to call functions on thread 0x%" PRIx64, thread.GetID());
+ error.SetErrorString ("Not safe to call functions on this thread.");
+ return return_value;
+ }
+
// Set up the arguments for a call to
// struct get_thread_item_info_return_values
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
index 7ff14fc5e09..f3f1fa31cd7 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
@@ -214,6 +214,21 @@ SystemRuntimeMacOSX::GetQueueKind (addr_t dispatch_queue_addr)
return kind;
}
+bool
+SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread (ThreadSP thread_sp)
+{
+ if (thread_sp && thread_sp->GetStackFrameCount() > 0 && thread_sp->GetFrameWithConcreteFrameIndex(0))
+ {
+ const SymbolContext sym_ctx (thread_sp->GetFrameWithConcreteFrameIndex(0)->GetSymbolContext (eSymbolContextSymbol));
+ static ConstString g_select_symbol ("__select");
+ if (sym_ctx.GetFunctionName() == g_select_symbol)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
lldb::queue_id_t
SystemRuntimeMacOSX::GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr)
{
diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
index f7a4d2bfb16..30956fa3ece 100644
--- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
+++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
@@ -108,6 +108,9 @@ public:
virtual lldb::QueueKind
GetQueueKind (lldb::addr_t dispatch_queue_addr);
+ virtual bool
+ SafeToCallFunctionsOnThisThread (lldb::ThreadSP thread_sp);
+
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index 4543dc03678..af5a9a45b25 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -26,6 +26,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
@@ -1953,6 +1954,21 @@ Thread::GetThreadLocalData (const ModuleSP module)
return LLDB_INVALID_ADDRESS;
}
+bool
+Thread::SafeToCallFunctions ()
+{
+ Process *process = GetProcess().get();
+ if (process)
+ {
+ SystemRuntime *runtime = process->GetSystemRuntime ();
+ if (runtime)
+ {
+ return runtime->SafeToCallFunctionsOnThisThread (shared_from_this());
+ }
+ }
+ return true;
+}
+
lldb::StackFrameSP
Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
{
diff --git a/lldb/test/macosx/safe-to-func-call/Makefile b/lldb/test/macosx/safe-to-func-call/Makefile
new file mode 100644
index 00000000000..d956512a279
--- /dev/null
+++ b/lldb/test/macosx/safe-to-func-call/Makefile
@@ -0,0 +1,28 @@
+CC ?= clang
+ifeq "$(ARCH)" ""
+ ARCH = x86_64
+endif
+
+ifeq "$(OS)" ""
+ OS = $(shell uname -s)
+endif
+
+CFLAGS ?= -g -O0
+CWD := $(shell pwd)
+
+LIB_PREFIX := lib
+
+ifeq "$(OS)" "Darwin"
+ CFLAGS += -arch $(ARCH)
+endif
+
+all: a.out
+
+a.out: main.o
+ $(CC) $(CFLAGS) -o a.out main.o
+
+main.o: main.c
+ $(CC) $(CFLAGS) -c main.c
+
+clean:
+ rm -rf *.o *~ *.dylib *.so a.out *.dSYM
diff --git a/lldb/test/macosx/safe-to-func-call/TestSafeFuncCalls.py b/lldb/test/macosx/safe-to-func-call/TestSafeFuncCalls.py
new file mode 100644
index 00000000000..be303d8697d
--- /dev/null
+++ b/lldb/test/macosx/safe-to-func-call/TestSafeFuncCalls.py
@@ -0,0 +1,81 @@
+"""Test function call thread safety."""
+
+import os, time
+import unittest2
+import lldb
+import lldbutil
+from lldbtest import *
+
+class TestSafeFuncCalls(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @python_api_test
+ @dsym_test
+ def test_with_dsym_and_python_api(self):
+ """Test function call thread safety."""
+ self.buildDsym()
+ self.function_call_safety_check()
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @python_api_test
+ @dwarf_test
+ def test_with_dwarf_and_python_api(self):
+ """Test function call thread safety."""
+ self.buildDwarf()
+ self.function_call_safety_check()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+ # Find the line numbers that we will step to in main:
+ self.main_source = "main.c"
+
+
+
+ def check_number_of_threads(self, process):
+ self.assertTrue(process.GetNumThreads() == 2, "Check that the process has two threads when sitting at the stopper() breakpoint")
+
+ def safe_to_call_func_on_main_thread (self, main_thread):
+ self.assertTrue(main_thread.SafeToCallFunctions() == True, "It is safe to call functions on the main thread")
+
+ def safe_to_call_func_on_select_thread (self, select_thread):
+ self.assertTrue(select_thread.SafeToCallFunctions() == False, "It is not safe to call functions on the select thread")
+
+ def function_call_safety_check(self):
+ """Test function call safety checks"""
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+ self.main_source_spec = lldb.SBFileSpec (self.main_source)
+ break1 = target.BreakpointCreateByName ("stopper", 'a.out')
+ self.assertTrue(break1, VALID_BREAKPOINT)
+ process = target.LaunchSimple (None, None, self.get_process_working_directory())
+ self.assertTrue(process, PROCESS_IS_VALID)
+ threads = lldbutil.get_threads_stopped_at_breakpoint (process, break1)
+ if len(threads) != 1:
+ self.fail ("Failed to stop at breakpoint 1.")
+
+ self.check_number_of_threads(process)
+
+ main_thread = lldb.SBThread()
+ select_thread = lldb.SBThread()
+ for idx in range (0, process.GetNumThreads()):
+ t = process.GetThreadAtIndex (idx)
+ if t.GetName() == "main thread":
+ main_thread = t
+ if t.GetName() == "select thread":
+ select_thread = t
+
+ self.assertTrue(main_thread.IsValid() and select_thread.IsValid(), "Got both expected threads")
+
+ self.safe_to_call_func_on_main_thread (main_thread)
+ self.safe_to_call_func_on_select_thread (select_thread)
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/macosx/safe-to-func-call/main.c b/lldb/test/macosx/safe-to-func-call/main.c
new file mode 100644
index 00000000000..613384ff73b
--- /dev/null
+++ b/lldb/test/macosx/safe-to-func-call/main.c
@@ -0,0 +1,30 @@
+#include <sys/select.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+
+void *
+select_thread (void *in)
+{
+ pthread_setname_np ("select thread");
+ fd_set fdset;
+ FD_SET (STDIN_FILENO, &fdset);
+ while (1)
+ select (2, &fdset, NULL, NULL, NULL);
+ return NULL;
+}
+
+void stopper ()
+{
+ while (1)
+ sleep(1); // break here
+}
+
+int main ()
+{
+ pthread_setname_np ("main thread");
+ pthread_t other_thread;
+ pthread_create (&other_thread, NULL, select_thread, NULL);
+ sleep (1);
+ stopper();
+}
OpenPOWER on IntegriCloud