diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile new file mode 100644 index 0000000000000..90ec8b9d913de --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +CXXFLAGS += -std=c++11 +CXX_SOURCES := ParallelTask.cpp +ENABLE_STD_THREADS := YES +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp new file mode 100755 index 0000000000000..71fb8e3bb565a --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include +#include +#include + +class TaskPoolImpl +{ +public: + TaskPoolImpl(uint32_t num_threads) : + m_stop(false) + { + for (uint32_t i = 0; i < num_threads; ++i) + m_threads.emplace_back(Worker, this); + } + + ~TaskPoolImpl() + { + Stop(); + } + + template + std::future::type> + AddTask(F&& f, Args&&... args) + { + auto task = std::make_shared::type()>>( + std::bind(std::forward(f), std::forward(args)...)); + + std::unique_lock lock(m_tasks_mutex); + assert(!m_stop && "Can't add task to TaskPool after it is stopped"); + m_tasks.emplace([task](){ (*task)(); }); + lock.unlock(); + m_tasks_cv.notify_one(); + + return task->get_future(); + } + + void + Stop() + { + std::unique_lock lock(m_tasks_mutex); + m_stop = true; + m_tasks_mutex.unlock(); + m_tasks_cv.notify_all(); + for (auto& t : m_threads) + t.join(); + } + +private: + static void + Worker(TaskPoolImpl* pool) + { + while (true) + { + std::unique_lock lock(pool->m_tasks_mutex); + if (pool->m_tasks.empty()) + pool->m_tasks_cv.wait(lock, [pool](){ return !pool->m_tasks.empty() || pool->m_stop; }); + if (pool->m_tasks.empty()) + break; + + std::function f = pool->m_tasks.front(); + pool->m_tasks.pop(); + lock.unlock(); + + f(); + } + } + + std::queue> m_tasks; + std::mutex m_tasks_mutex; + std::condition_variable m_tasks_cv; + bool m_stop; + std::vector m_threads; +}; + +class TaskPool +{ +public: + // Add a new task to the thread pool and return a std::future belongs for the newly created task. + // The caller of this function have to wait on the future for this task to complete. + template + static std::future::type> + AddTask(F&& f, Args&&... args) + { + return GetImplementation().AddTask(std::forward(f), std::forward(args)...); + } + + // Run all of the specified tasks on the thread pool and wait until all of them are finished + // before returning + template + static void + RunTasks(T&&... t) + { + RunTaskImpl::Run(std::forward(t)...); + } + +private: + static TaskPoolImpl& + GetImplementation() + { + static TaskPoolImpl g_task_pool_impl(std::thread::hardware_concurrency()); + return g_task_pool_impl; + } + + template + struct RunTaskImpl; +}; + +template +struct TaskPool::RunTaskImpl +{ + static void + Run(H&& h, T&&... t) + { + auto f = AddTask(std::forward(h)); + RunTaskImpl::Run(std::forward(t)...); + f.wait(); + } +}; + +template<> +struct TaskPool::RunTaskImpl<> +{ + static void + Run() {} +}; + +int main() +{ + std::vector> tasks; + for (int i = 0; i < 100000; ++i) + { + tasks.emplace_back(TaskPool::AddTask([](int i){ + uint32_t s = 0; + for (int j = 0; j <= i; ++j) + s += j; + return s; + }, + i)); + } + + for (auto& it : tasks) // Set breakpoint here + it.wait(); + + TaskPool::RunTasks( + []() { return 1; }, + []() { return "aaaa"; } + ); +} diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py new file mode 100644 index 0000000000000..d4000548b2c49 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py @@ -0,0 +1,54 @@ +""" +Test regression for Bug 25251. +""" + +import os, time +import unittest2 +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class BreakpointAfterJoinTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number for our breakpoint. + self.breakpoint = line_number('ParallelTask.cpp', '// Set breakpoint here') + + def test(self): + """Test breakpoint handling after a thread join.""" + self.build(dictionary=self.getBuildFlags()) + + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # This should create a breakpoint + lldbutil.run_break_set_by_file_and_line (self, "ParallelTask.cpp", self.breakpoint, num_expected_locations=-1) + + # The breakpoint list should show 1 location. + self.expect("breakpoint list -f", "Breakpoint location shown correctly", + substrs = ["1: file = 'ParallelTask.cpp', line = %d, exact_match = 0" % self.breakpoint]) + + # Run the program. + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # This should not result in a segmentation fault + self.expect("thread backtrace all", STOPPED_DUE_TO_BREAKPOINT, + substrs = ["stop reason = breakpoint 1."]) + + # Run to completion + self.runCmd("continue") + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py b/lldb/packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py index 9a73f85175917..594c052896330 100644 --- a/lldb/packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py +++ b/lldb/packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py @@ -32,7 +32,7 @@ def image_lookup_for_multiple_typedefs(self): """Test 'image lookup -t a' at different scopes and check for correct display.""" exe = os.path.join(os.getcwd(), "a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) - typearray = ("float", "float", "char", "float", "int", "double", "float", "float") + typearray = ("float", "float", "char", "double *", "float", "int", "double", "float", "float") arraylen = len(typearray)+1 for i in range(1,arraylen): loc_line = line_number('main.c', '// Set break point ' + str(i) + '.') diff --git a/lldb/packages/Python/lldbsuite/test/lang/c/typedef/main.c b/lldb/packages/Python/lldbsuite/test/lang/c/typedef/main.c index 6c13affbbc106..62f8a00e6644e 100644 --- a/lldb/packages/Python/lldbsuite/test/lang/c/typedef/main.c +++ b/lldb/packages/Python/lldbsuite/test/lang/c/typedef/main.c @@ -6,6 +6,11 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +void test() +{ + typedef double * a; + a b = 0; // Set break point 4. +} int main (int argc, char const *argv[]) { typedef float a; @@ -16,25 +21,26 @@ int main (int argc, char const *argv[]) typedef char a; i++; a charvariable = 'a'; // Set break point 3. + test(); } { int c = 0; - c++; // Set break point 4. + c++; // Set break point 5. for(i = 0 ; i < 1 ; i++) { typedef int a; a b; - b = 7; // Set break point 5. + b = 7; // Set break point 6. } for(i = 0 ; i < 1 ; i++) { typedef double a; a b; - b = 3.14; // Set break point 6. + b = 3.14; // Set break point 7. } - c = 1; // Set break point 7. + c = 1; // Set break point 8. } floatvariable = 2.5; - floatvariable = 2.8; // Set break point 8. + floatvariable = 2.8; // Set break point 9. return 0; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 6ff1c986558b8..1186fed2b92fe 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1559,14 +1559,14 @@ SymbolFileDWARF::CompleteType (CompilerType &compiler_type) } Type* -SymbolFileDWARF::ResolveType (const DWARFDIE &die, bool assert_not_being_parsed) +SymbolFileDWARF::ResolveType (const DWARFDIE &die, bool assert_not_being_parsed, bool resolve_function_context) { if (die) { Type *type = GetDIEToType().lookup (die.GetDIE()); if (type == NULL) - type = GetTypeForDIE (die).get(); + type = GetTypeForDIE (die, resolve_function_context).get(); if (assert_not_being_parsed) { @@ -2927,7 +2927,7 @@ SymbolFileDWARF::FindTypes (const SymbolContext& sc, if (!DIEInDeclContext(parent_decl_ctx, die)) continue; // The containing decl contexts don't match - Type *matching_type = ResolveType (die); + Type *matching_type = ResolveType (die, true, true); if (matching_type) { // We found a type pointer, now find the shared pointer form our type list @@ -3065,7 +3065,7 @@ SymbolFileDWARF::FindNamespace (const SymbolContext& sc, } TypeSP -SymbolFileDWARF::GetTypeForDIE (const DWARFDIE &die) +SymbolFileDWARF::GetTypeForDIE (const DWARFDIE &die, bool resolve_function_context) { TypeSP type_sp; if (die) @@ -3084,7 +3084,7 @@ SymbolFileDWARF::GetTypeForDIE (const DWARFDIE &die) parent_die = parent_die->GetParent(); } SymbolContext sc_backup = sc; - if (parent_die != nullptr && !GetFunction(DWARFDIE(die.GetCU(),parent_die), sc)) + if (resolve_function_context && parent_die != nullptr && !GetFunction(DWARFDIE(die.GetCU(),parent_die), sc)) sc = sc_backup; type_sp = ParseType(sc, die, NULL); @@ -3270,7 +3270,7 @@ SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDIE &die, if (try_resolving_type) { - Type *resolved_type = ResolveType (type_die, false); + Type *resolved_type = ResolveType (type_die, false, true); if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) { DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n", diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index ccd85e805e2d6..818ce68eabbf1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -148,7 +148,8 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::Us lldb_private::Type * ResolveType (const DWARFDIE &die, - bool assert_not_being_parsed = true); + bool assert_not_being_parsed = true, + bool resolve_function_context = false); lldb_private::CompilerDecl GetDeclForUID (lldb::user_id_t uid) override; @@ -434,7 +435,7 @@ class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::Us lldb_private::SymbolContextList& sc_list); lldb::TypeSP - GetTypeForDIE (const DWARFDIE &die); + GetTypeForDIE (const DWARFDIE &die, bool resolve_function_context = false); void Index();