From 8b4000f13b303cc154136abc74c55670673e2a96 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 8 May 2017 17:13:54 +0000 Subject: [PATCH] Vendor import of lldb trunk r302418: https://llvm.org/svn/llvm-project/lldb/trunk@302418 --- include/lldb/API/SBAddress.h | 4 + include/lldb/API/SBInstruction.h | 2 + include/lldb/API/SBInstructionList.h | 9 + include/lldb/Core/Disassembler.h | 2 + include/lldb/Expression/Expression.h | 10 + include/lldb/Host/MainLoop.h | 7 + include/lldb/Host/common/UDPSocket.h | 4 +- include/lldb/Target/ThreadPlanCallFunction.h | 2 +- .../Target/ThreadPlanCallUserExpression.h | 3 + include/lldb/Utility/TaskPool.h | 108 +-------- .../multiline/TestMultilineExpressions.py | 28 +++ .../TestStepOverBreakpoint.py | 9 +- .../return-value/TestReturnValue.py | 50 ++++- .../lldb-server/TestGdbRemoteHostInfo.py | 1 + scripts/interface/SBInstruction.i | 3 + scripts/interface/SBInstructionList.i | 3 + source/API/SBAddress.cpp | 6 + source/API/SBInstruction.cpp | 7 + source/API/SBInstructionList.cpp | 26 +++ source/API/SBProcess.cpp | 16 +- source/Core/Disassembler.cpp | 4 + source/Host/common/Editline.cpp | 2 +- source/Host/common/MainLoop.cpp | 212 +++++++++--------- source/Host/common/UDPSocket.cpp | 82 +++---- .../Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp | 34 ++- .../MacOSX-DYLD/DynamicLoaderMacOS.cpp | 17 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 73 +++--- .../Target/ThreadPlanCallUserExpression.cpp | 11 + source/Utility/TaskPool.cpp | 23 ++ unittests/Host/CMakeLists.txt | 1 + unittests/Host/MainLoopTest.cpp | 120 ++++++++++ unittests/Utility/TaskPoolTest.cpp | 27 +-- www/lldb-gdb.html | 31 +++ 33 files changed, 567 insertions(+), 370 deletions(-) create mode 100644 unittests/Host/MainLoopTest.cpp diff --git a/include/lldb/API/SBAddress.h b/include/lldb/API/SBAddress.h index ddbe5a742786..9e697beffdd1 100644 --- a/include/lldb/API/SBAddress.h +++ b/include/lldb/API/SBAddress.h @@ -103,6 +103,8 @@ protected: const lldb_private::Address *operator->() const; + friend bool operator==(const SBAddress &lhs, const SBAddress &rhs); + lldb_private::Address *get(); lldb_private::Address &ref(); @@ -117,6 +119,8 @@ private: std::unique_ptr m_opaque_ap; }; +bool operator==(const SBAddress &lhs, const SBAddress &rhs); + } // namespace lldb #endif // LLDB_SBAddress_h_ diff --git a/include/lldb/API/SBInstruction.h b/include/lldb/API/SBInstruction.h index 0fc12eb61cba..23daf1c56637 100644 --- a/include/lldb/API/SBInstruction.h +++ b/include/lldb/API/SBInstruction.h @@ -53,6 +53,8 @@ public: bool HasDelaySlot(); + bool CanSetBreakpoint(); + void Print(FILE *out); bool GetDescription(lldb::SBStream &description); diff --git a/include/lldb/API/SBInstructionList.h b/include/lldb/API/SBInstructionList.h index 29baef5790eb..0323a3c80c05 100644 --- a/include/lldb/API/SBInstructionList.h +++ b/include/lldb/API/SBInstructionList.h @@ -32,6 +32,15 @@ public: lldb::SBInstruction GetInstructionAtIndex(uint32_t idx); + // ---------------------------------------------------------------------- + // Returns the number of instructions between the start and end address. + // If canSetBreakpoint is true then the count will be the number of + // instructions on which a breakpoint can be set. + // ---------------------------------------------------------------------- + size_t GetInstructionsCount(const SBAddress &start, + const SBAddress &end, + bool canSetBreakpoint = false); + void Clear(); void AppendInstruction(lldb::SBInstruction inst); diff --git a/include/lldb/Core/Disassembler.h b/include/lldb/Core/Disassembler.h index 929b668c092b..addc83ad5e9d 100644 --- a/include/lldb/Core/Disassembler.h +++ b/include/lldb/Core/Disassembler.h @@ -173,6 +173,8 @@ public: virtual bool HasDelaySlot(); + bool CanSetBreakpoint (); + virtual size_t Decode(const Disassembler &disassembler, const DataExtractor &data, lldb::offset_t data_offset) = 0; diff --git a/include/lldb/Expression/Expression.h b/include/lldb/Expression/Expression.h index f48a7992227d..860444e9c2c2 100644 --- a/include/lldb/Expression/Expression.h +++ b/include/lldb/Expression/Expression.h @@ -99,6 +99,16 @@ public: //------------------------------------------------------------------ lldb::addr_t StartAddress() { return m_jit_start_addr; } + //------------------------------------------------------------------ + /// Called to notify the expression that it is about to be executed. + //------------------------------------------------------------------ + virtual void WillStartExecuting() {} + + //------------------------------------------------------------------ + /// Called to notify the expression that its execution has finished. + //------------------------------------------------------------------ + virtual void DidFinishExecuting() {} + virtual ExpressionTypeSystemHelper *GetTypeSystemHelper() { return nullptr; } protected: diff --git a/include/lldb/Host/MainLoop.h b/include/lldb/Host/MainLoop.h index 79370bf8461f..f5d906e98a7b 100644 --- a/include/lldb/Host/MainLoop.h +++ b/include/lldb/Host/MainLoop.h @@ -42,6 +42,7 @@ private: public: typedef std::unique_ptr SignalHandleUP; + MainLoop(); ~MainLoop() override; ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, @@ -71,6 +72,9 @@ protected: void UnregisterSignal(int signo); private: + void ProcessReadObject(IOObject::WaitableHandle handle); + void ProcessSignal(int signo); + class SignalHandle { public: ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } @@ -97,6 +101,9 @@ private: llvm::DenseMap m_read_fds; llvm::DenseMap m_signals; +#if HAVE_SYS_EVENT_H + int m_kqueue; +#endif bool m_terminate_request : 1; }; diff --git a/include/lldb/Host/common/UDPSocket.h b/include/lldb/Host/common/UDPSocket.h index 38524fa8f62b..977ce151e4ff 100644 --- a/include/lldb/Host/common/UDPSocket.h +++ b/include/lldb/Host/common/UDPSocket.h @@ -21,15 +21,13 @@ public: Socket *&socket); private: - UDPSocket(NativeSocket socket, const UDPSocket &listen_socket); + UDPSocket(NativeSocket socket); size_t Send(const void *buf, const size_t num_bytes) override; Error Connect(llvm::StringRef name) override; Error Listen(llvm::StringRef name, int backlog) override; Error Accept(Socket *&socket) override; - Error CreateSocket(); - SocketAddress m_sockaddr; }; } diff --git a/include/lldb/Target/ThreadPlanCallFunction.h b/include/lldb/Target/ThreadPlanCallFunction.h index 3d43491af9af..1c75b0a3645c 100644 --- a/include/lldb/Target/ThreadPlanCallFunction.h +++ b/include/lldb/Target/ThreadPlanCallFunction.h @@ -117,7 +117,7 @@ protected: lldb::addr_t &start_load_addr, lldb::addr_t &function_load_addr); - void DoTakedown(bool success); + virtual void DoTakedown(bool success); void SetBreakpoints(); diff --git a/include/lldb/Target/ThreadPlanCallUserExpression.h b/include/lldb/Target/ThreadPlanCallUserExpression.h index f1425b2f97e1..5fe80927ca21 100644 --- a/include/lldb/Target/ThreadPlanCallUserExpression.h +++ b/include/lldb/Target/ThreadPlanCallUserExpression.h @@ -35,6 +35,8 @@ public: void GetDescription(Stream *s, lldb::DescriptionLevel level) override; + void DidPush() override; + void WillPop() override; lldb::StopInfoSP GetRealStopInfo() override; @@ -48,6 +50,7 @@ public: } protected: + void DoTakedown(bool success) override; private: lldb::UserExpressionSP m_user_expression_sp; // This is currently just used to ensure the diff --git a/include/lldb/Utility/TaskPool.h b/include/lldb/Utility/TaskPool.h index fb936bbb739a..87b8824f9226 100644 --- a/include/lldb/Utility/TaskPool.h +++ b/include/lldb/Utility/TaskPool.h @@ -53,50 +53,6 @@ private: static void AddTaskImpl(std::function &&task_fn); }; -// Wrapper class around the global TaskPool implementation to make it possible -// to create a set of -// tasks and then wait for the tasks to be completed by the -// WaitForNextCompletedTask call. This -// class should be used when WaitForNextCompletedTask is needed because this -// class add no other -// extra functionality to the TaskPool class and it have a very minor -// performance overhead. -template // The return type of the tasks what will be added to this - // task runner - class TaskRunner { -public: - // Add a task to the task runner what will also add the task to the global - // TaskPool. The - // function doesn't return the std::future for the task because it will be - // supplied by the - // WaitForNextCompletedTask after the task is completed. - template void AddTask(F &&f, Args &&... args); - - // Wait for the next task in this task runner to finish and then return the - // std::future what - // belongs to the finished task. If there is no task in this task runner - // (neither pending nor - // comleted) then this function will return an invalid future. Usually this - // function should be - // called in a loop processing the results of the tasks until it returns an - // invalid std::future - // what means that all task in this task runner is completed. - std::future WaitForNextCompletedTask(); - - // Convenience method to wait for all task in this TaskRunner to finish. Do - // NOT use this class - // just because of this method. Use TaskPool instead and wait for each - // std::future returned by - // AddTask in a loop. - void WaitForAllTasks(); - -private: - std::list> m_ready; - std::list> m_pending; - std::mutex m_mutex; - std::condition_variable m_cv; -}; - template std::future::type> TaskPool::AddTask(F &&f, Args &&... args) { @@ -126,64 +82,10 @@ template <> struct TaskPool::RunTaskImpl<> { static void Run() {} }; -template -template -void TaskRunner::AddTask(F &&f, Args &&... args) { - std::unique_lock lock(m_mutex); - auto it = m_pending.emplace(m_pending.end()); - *it = std::move(TaskPool::AddTask( - [this, it](F f, Args... args) { - T &&r = f(std::forward(args)...); - - std::unique_lock lock(this->m_mutex); - this->m_ready.splice(this->m_ready.end(), this->m_pending, it); - lock.unlock(); - - this->m_cv.notify_one(); - return r; - }, - std::forward(f), std::forward(args)...)); -} - -template <> -template -void TaskRunner::AddTask(F &&f, Args &&... args) { - std::unique_lock lock(m_mutex); - auto it = m_pending.emplace(m_pending.end()); - *it = std::move(TaskPool::AddTask( - [this, it](F f, Args... args) { - f(std::forward(args)...); - - std::unique_lock lock(this->m_mutex); - this->m_ready.emplace_back(std::move(*it)); - this->m_pending.erase(it); - lock.unlock(); - - this->m_cv.notify_one(); - }, - std::forward(f), std::forward(args)...)); -} - -template std::future TaskRunner::WaitForNextCompletedTask() { - std::unique_lock lock(m_mutex); - if (m_ready.empty() && m_pending.empty()) - return std::future(); // No more tasks - - if (m_ready.empty()) - m_cv.wait(lock, [this]() { return !this->m_ready.empty(); }); - - std::future res = std::move(m_ready.front()); - m_ready.pop_front(); - - lock.unlock(); - res.wait(); - - return std::move(res); -} - -template void TaskRunner::WaitForAllTasks() { - while (WaitForNextCompletedTask().valid()) - ; -} +// Run 'func' on every value from begin .. end-1. Each worker will grab +// 'batch_size' numbers at a time to work on, so for very fast functions, batch +// should be large enough to avoid too much cache line contention. +void TaskMapOverInt(size_t begin, size_t end, + std::function const &func); #endif // #ifndef utility_TaskPool_h_ diff --git a/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py b/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py index b1b5cbe677c4..aa369ebeff87 100644 --- a/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py +++ b/packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py @@ -12,6 +12,7 @@ from lldbsuite.test import lldbutil class MultilineExpressionsTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True def setUp(self): # Call super's setUp(). @@ -60,3 +61,30 @@ class MultilineExpressionsTestCase(TestBase): child.expect_exact(prompt) self.expect(child.before, exe=False, patterns=['= 5']) + + @skipIfRemote + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_empty_list(self): + """Test printing an empty list of expressions""" + import pexpect + prompt = "(lldb) " + + # So that the child gets torn down after the test + self.child = pexpect.spawn( + "%s %s" % + (lldbtest_config.lldbExec, self.lldbOption)) + child = self.child + + # Turn on logging for what the child sends back. + if self.TraceOn(): + child.logfile_read = sys.stdout + + # We expect a prompt, then send "print" to start a list of expressions, + # then an empty line. We expect a prompt back. + child.expect_exact(prompt) + child.sendline("print") + child.expect_exact('1:') + child.sendline("") + child.expect_exact(prompt) diff --git a/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py b/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py index 00ddc628607c..4dfeae3f5e19 100644 --- a/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py +++ b/packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py @@ -62,12 +62,11 @@ class StepOverBreakpointsTestCase(TestBase): instructions = function.GetInstructions(self.target) addr_1 = self.breakpoint1.GetLocationAtIndex(0).GetAddress() addr_4 = self.breakpoint4.GetLocationAtIndex(0).GetAddress() - for i in range(instructions.GetSize()) : - addr = instructions.GetInstructionAtIndex(i).GetAddress() - if (addr == addr_1) : index_1 = i - if (addr == addr_4) : index_4 = i - steps_expected = index_4 - index_1 + # if third argument is true then the count will be the number of + # instructions on which a breakpoint can be set. + # start = addr_1, end = addr_4, canSetBreakpoint = True + steps_expected = instructions.GetInstructionsCount(addr_1, addr_4, True) step_count = 0 # Step from breakpoint_1 to breakpoint_4 while True: diff --git a/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py b/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py index 778c098a38ee..90562f52a4b2 100644 --- a/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py +++ b/packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py @@ -171,17 +171,45 @@ class ReturnValueTestCase(TestBase): #self.return_and_test_struct_value ("return_one_int_one_double_packed") self.return_and_test_struct_value("return_one_int_one_long") - # icc and gcc don't support this extension. - if self.getCompiler().endswith('clang'): - self.return_and_test_struct_value("return_vector_size_float32_8") - self.return_and_test_struct_value("return_vector_size_float32_16") - self.return_and_test_struct_value("return_vector_size_float32_32") - self.return_and_test_struct_value( - "return_ext_vector_size_float32_2") - self.return_and_test_struct_value( - "return_ext_vector_size_float32_4") - self.return_and_test_struct_value( - "return_ext_vector_size_float32_8") + @expectedFailureAll(oslist=["freebsd"], archs=["i386"]) + @expectedFailureAll(oslist=["macosx"], archs=["i386"], bugnumber="") + @expectedFailureAll( + oslist=["linux"], + compiler="clang", + compiler_version=[ + "<=", + "3.6"], + archs=["i386"]) + @expectedFailureAll( + bugnumber="llvm.org/pr25785", + hostoslist=["windows"], + compiler="gcc", + archs=["i386"], + triple='.*-android') + @expectedFailureAll(compiler=["gcc"], archs=["x86_64", "i386"]) + @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24778") + def test_vector_values(self): + self.build() + exe = os.path.join(os.getcwd(), "a.out") + error = lldb.SBError() + + self.target = self.dbg.CreateTarget(exe) + self.assertTrue(self.target, VALID_TARGET) + + main_bktp = self.target.BreakpointCreateByName("main", exe) + self.assertTrue(main_bktp, VALID_BREAKPOINT) + + self.process = self.target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertEqual(len(lldbutil.get_threads_stopped_at_breakpoint( + self.process, main_bktp)), 1) + + self.return_and_test_struct_value("return_vector_size_float32_8") + self.return_and_test_struct_value("return_vector_size_float32_16") + self.return_and_test_struct_value("return_vector_size_float32_32") + self.return_and_test_struct_value("return_ext_vector_size_float32_2") + self.return_and_test_struct_value("return_ext_vector_size_float32_4") + self.return_and_test_struct_value("return_ext_vector_size_float32_8") def return_and_test_struct_value(self, func_name): """Pass in the name of the function to return from - takes in value, returns value.""" diff --git a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteHostInfo.py b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteHostInfo.py index 5089ee85773f..d84511d54273 100644 --- a/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteHostInfo.py +++ b/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteHostInfo.py @@ -14,6 +14,7 @@ class TestGdbRemoteHostInfo(GdbRemoteTestCaseBase): mydir = TestBase.compute_mydir(__file__) KNOWN_HOST_INFO_KEYS = set([ + "arch", "cputype", "cpusubtype", "distribution_id", diff --git a/scripts/interface/SBInstruction.i b/scripts/interface/SBInstruction.i index d5b60201e95e..c78799c6fe69 100644 --- a/scripts/interface/SBInstruction.i +++ b/scripts/interface/SBInstruction.i @@ -54,6 +54,9 @@ public: bool HasDelaySlot (); + bool + CanSetBreakpoint (); + void Print (FILE *out); diff --git a/scripts/interface/SBInstructionList.i b/scripts/interface/SBInstructionList.i index 32603be5cc1e..f4b572c341cd 100644 --- a/scripts/interface/SBInstructionList.i +++ b/scripts/interface/SBInstructionList.i @@ -44,6 +44,9 @@ public: lldb::SBInstruction GetInstructionAtIndex (uint32_t idx); + size_t GetInstructionsCount(const SBAddress &start, const SBAddress &end, + bool canSetBreakpoint); + void Clear (); diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp index b452ce327ab7..a3493d7c743f 100644 --- a/source/API/SBAddress.cpp +++ b/source/API/SBAddress.cpp @@ -55,6 +55,12 @@ const SBAddress &SBAddress::operator=(const SBAddress &rhs) { return *this; } +bool lldb::operator==(const SBAddress &lhs, const SBAddress &rhs) { + if (lhs.IsValid() && rhs.IsValid()) + return lhs.ref() == rhs.ref(); + return false; +} + bool SBAddress::IsValid() const { return m_opaque_ap.get() != NULL && m_opaque_ap->IsValid(); } diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp index c47307c733a8..8b7deb7011be 100644 --- a/source/API/SBInstruction.cpp +++ b/source/API/SBInstruction.cpp @@ -176,6 +176,13 @@ bool SBInstruction::HasDelaySlot() { return false; } +bool SBInstruction::CanSetBreakpoint () { + lldb::InstructionSP inst_sp(GetOpaque()); + if (inst_sp) + return inst_sp->CanSetBreakpoint(); + return false; +} + lldb::InstructionSP SBInstruction::GetOpaque() { if (m_opaque_sp) return m_opaque_sp->GetSP(); diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp index 04c37f50c2d7..3edb9eae98c1 100644 --- a/source/API/SBInstructionList.cpp +++ b/source/API/SBInstructionList.cpp @@ -9,6 +9,7 @@ #include "lldb/API/SBInstructionList.h" #include "lldb/API/SBInstruction.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBStream.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -49,6 +50,31 @@ SBInstruction SBInstructionList::GetInstructionAtIndex(uint32_t idx) { return inst; } +size_t SBInstructionList::GetInstructionsCount(const SBAddress &start, + const SBAddress &end, + bool canSetBreakpoint) { + size_t num_instructions = GetSize(); + size_t i = 0; + SBAddress addr; + size_t lower_index = 0; + size_t upper_index = 0; + size_t instructions_to_skip = 0; + for (i = 0; i < num_instructions; ++i) { + addr = GetInstructionAtIndex(i).GetAddress(); + if (start == addr) + lower_index = i; + if (end == addr) + upper_index = i; + } + if (canSetBreakpoint) + for (i = lower_index; i <= upper_index; ++i) { + SBInstruction insn = GetInstructionAtIndex(i); + if (!insn.CanSetBreakpoint()) + ++instructions_to_skip; + } + return upper_index - lower_index - instructions_to_skip; +} + void SBInstructionList::Clear() { m_opaque_sp.reset(); } void SBInstructionList::AppendInstruction(SBInstruction insn) {} diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp index 5614cb468a69..0348113a9873 100644 --- a/source/API/SBProcess.cpp +++ b/source/API/SBProcess.cpp @@ -1157,22 +1157,34 @@ uint32_t SBProcess::LoadImage(lldb::SBFileSpec &sb_remote_image_spec, uint32_t SBProcess::LoadImage(const lldb::SBFileSpec &sb_local_image_spec, const lldb::SBFileSpec &sb_remote_image_spec, lldb::SBError &sb_error) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); ProcessSP process_sp(GetSP()); if (process_sp) { Process::StopLocker stop_locker; if (stop_locker.TryLock(&process_sp->GetRunLock())) { + if (log) + log->Printf("SBProcess(%p)::LoadImage() => calling Platform::LoadImage" + "for: %s", + static_cast(process_sp.get()), + sb_local_image_spec.GetFilename()); + std::lock_guard guard( - process_sp->GetTarget().GetAPIMutex()); + process_sp->GetTarget().GetAPIMutex()); PlatformSP platform_sp = process_sp->GetTarget().GetPlatform(); return platform_sp->LoadImage(process_sp.get(), *sb_local_image_spec, *sb_remote_image_spec, sb_error.ref()); } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); if (log) log->Printf("SBProcess(%p)::LoadImage() => error: process is running", static_cast(process_sp.get())); sb_error.SetErrorString("process is running"); } + } else { + if (log) + log->Printf("SBProcess(%p)::LoadImage() => error: called with invalid" + " process", + static_cast(process_sp.get())); + sb_error.SetErrorString("process is invalid"); } return LLDB_INVALID_IMAGE_TOKEN; } diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp index 3880bfd16ecc..51d93d9acdbb 100644 --- a/source/Core/Disassembler.cpp +++ b/source/Core/Disassembler.cpp @@ -759,6 +759,10 @@ bool Instruction::DumpEmulation(const ArchSpec &arch) { return false; } +bool Instruction::CanSetBreakpoint () { + return !HasDelaySlot(); +} + bool Instruction::HasDelaySlot() { // Default is false. return false; diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp index b157cdb7c110..851287e76331 100644 --- a/source/Host/common/Editline.cpp +++ b/source/Host/common/Editline.cpp @@ -367,7 +367,7 @@ void Editline::MoveCursor(CursorLocation from, CursorLocation to) { if (to == CursorLocation::EditingCursor) { toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1; - } else if (to == CursorLocation::BlockEnd) { + } else if (to == CursorLocation::BlockEnd && !m_input_lines.empty()) { toColumn = ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % 80) + diff --git a/source/Host/common/MainLoop.cpp b/source/Host/common/MainLoop.cpp index 8a9d4f020d5f..abd52f7f46fb 100644 --- a/source/Host/common/MainLoop.cpp +++ b/source/Host/common/MainLoop.cpp @@ -18,6 +18,11 @@ #include #include +// Multiplexing is implemented using kqueue on systems that support it (BSD +// variants including OSX). On linux we use ppoll, while android uses pselect +// (ppoll is present but not implemented properly). On windows we use WSApoll +// (which does not support signals). + #if HAVE_SYS_EVENT_H #include #elif defined(LLVM_ON_WIN32) @@ -65,92 +70,72 @@ static void SignalHandler(int signo, siginfo_t *info, void *) { class MainLoop::RunImpl { public: - // TODO: Use llvm::Expected - static std::unique_ptr Create(MainLoop &loop, Error &error); - ~RunImpl(); + RunImpl(MainLoop &loop); + ~RunImpl() = default; Error Poll(); - - template void ForEachReadFD(F &&f); - template void ForEachSignal(F &&f); + void ProcessEvents(); private: MainLoop &loop; #if HAVE_SYS_EVENT_H - int queue_id; std::vector in_events; struct kevent out_events[4]; int num_events = -1; - RunImpl(MainLoop &loop, int queue_id) : loop(loop), queue_id(queue_id) { - in_events.reserve(loop.m_read_fds.size() + loop.m_signals.size()); - } #else - std::vector signals; #ifdef FORCE_PSELECT fd_set read_fd_set; #else std::vector read_fds; #endif - RunImpl(MainLoop &loop) : loop(loop) { - signals.reserve(loop.m_signals.size()); - } - sigset_t get_sigmask(); #endif }; #if HAVE_SYS_EVENT_H -MainLoop::RunImpl::~RunImpl() { - int r = close(queue_id); - assert(r == 0); - (void)r; -} -std::unique_ptr MainLoop::RunImpl::Create(MainLoop &loop, Error &error) -{ - error.Clear(); - int queue_id = kqueue(); - if(queue_id < 0) { - error = Error(errno, eErrorTypePOSIX); - return nullptr; - } - return std::unique_ptr(new RunImpl(loop, queue_id)); +MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) { + in_events.reserve(loop.m_read_fds.size()); } Error MainLoop::RunImpl::Poll() { - in_events.resize(loop.m_read_fds.size() + loop.m_signals.size()); + in_events.resize(loop.m_read_fds.size()); unsigned i = 0; for (auto &fd : loop.m_read_fds) EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0); - for (const auto &sig : loop.m_signals) - EV_SET(&in_events[i++], sig.first, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); - - num_events = kevent(queue_id, in_events.data(), in_events.size(), out_events, - llvm::array_lengthof(out_events), nullptr); + num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(), + out_events, llvm::array_lengthof(out_events), nullptr); if (num_events < 0) return Error("kevent() failed with error %d\n", num_events); return Error(); } -template void MainLoop::RunImpl::ForEachReadFD(F &&f) { +void MainLoop::RunImpl::ProcessEvents() { assert(num_events >= 0); for (int i = 0; i < num_events; ++i) { - f(out_events[i].ident); if (loop.m_terminate_request) return; + switch (out_events[i].filter) { + case EVFILT_READ: + loop.ProcessReadObject(out_events[i].ident); + break; + case EVFILT_SIGNAL: + loop.ProcessSignal(out_events[i].ident); + break; + default: + llvm_unreachable("Unknown event"); + } } } -template void MainLoop::RunImpl::ForEachSignal(F && f) {} #else -MainLoop::RunImpl::~RunImpl() {} -std::unique_ptr MainLoop::RunImpl::Create(MainLoop &loop, Error &error) -{ - error.Clear(); - return std::unique_ptr(new RunImpl(loop)); +MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) { +#ifndef FORCE_PSELECT + read_fds.reserve(loop.m_read_fds.size()); +#endif } sigset_t MainLoop::RunImpl::get_sigmask() { @@ -162,18 +147,14 @@ sigset_t MainLoop::RunImpl::get_sigmask() { assert(ret == 0); (void) ret; - for (const auto &sig : loop.m_signals) { - signals.push_back(sig.first); + for (const auto &sig : loop.m_signals) sigdelset(&sigmask, sig.first); - } return sigmask; #endif } #ifdef FORCE_PSELECT Error MainLoop::RunImpl::Poll() { - signals.clear(); - FD_ZERO(&read_fd_set); int nfds = 0; for (const auto &fd : loop.m_read_fds) { @@ -188,20 +169,8 @@ Error MainLoop::RunImpl::Poll() { return Error(); } - -template void MainLoop::RunImpl::ForEachReadFD(F &&f) { - for (const auto &fd : loop.m_read_fds) { - if(!FD_ISSET(fd.first, &read_fd_set)) - continue; - - f(fd.first); - if (loop.m_terminate_request) - return; - } -} #else Error MainLoop::RunImpl::Poll() { - signals.clear(); read_fds.clear(); sigset_t sigmask = get_sigmask(); @@ -220,33 +189,47 @@ Error MainLoop::RunImpl::Poll() { return Error(); } +#endif -template void MainLoop::RunImpl::ForEachReadFD(F &&f) { +void MainLoop::RunImpl::ProcessEvents() { +#ifdef FORCE_PSELECT + for (const auto &fd : loop.m_read_fds) { + if (!FD_ISSET(fd.first, &read_fd_set)) + continue; + IOObject::WaitableHandle handle = fd.first; +#else for (const auto &fd : read_fds) { if ((fd.revents & POLLIN) == 0) continue; - - f(fd.fd); + IOObject::WaitableHandle handle = fd.fd; +#endif if (loop.m_terminate_request) return; - } -} -#endif -template void MainLoop::RunImpl::ForEachSignal(F &&f) { - for (int sig : signals) { - if (g_signal_flags[sig] == 0) + loop.ProcessReadObject(handle); + } + + for (const auto &entry : loop.m_signals) { + if (loop.m_terminate_request) + return; + if (g_signal_flags[entry.first] == 0) continue; // No signal - g_signal_flags[sig] = 0; - f(sig); - - if (loop.m_terminate_request) - return; + g_signal_flags[entry.first] = 0; + loop.ProcessSignal(entry.first); } } #endif +MainLoop::MainLoop() { +#if HAVE_SYS_EVENT_H + m_kqueue = kqueue(); + assert(m_kqueue >= 0); +#endif +} MainLoop::~MainLoop() { +#if HAVE_SYS_EVENT_H + close(m_kqueue); +#endif assert(m_read_fds.size() == 0); assert(m_signals.size() == 0); } @@ -298,25 +281,31 @@ MainLoop::RegisterSignal(int signo, const Callback &callback, new_action.sa_flags = SA_SIGINFO; sigemptyset(&new_action.sa_mask); sigaddset(&new_action.sa_mask, signo); - sigset_t old_set; - if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set)) { - error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", - ret); - return nullptr; - } - info.was_blocked = sigismember(&old_set, signo); - if (sigaction(signo, &new_action, &info.old_action) == -1) { - error.SetErrorToErrno(); - if (!info.was_blocked) - pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr); - return nullptr; - } - - m_signals.insert({signo, info}); g_signal_flags[signo] = 0; + // Even if using kqueue, the signal handler will still be invoked, so it's + // important to replace it with our "bening" handler. + int ret = sigaction(signo, &new_action, &info.old_action); + assert(ret == 0 && "sigaction failed"); + +#if HAVE_SYS_EVENT_H + struct kevent ev; + EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); + ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); + assert(ret == 0); +#endif + + // If we're using kqueue, the signal needs to be unblocked in order to recieve + // it. If using pselect/ppoll, we need to block it, and later unblock it as a + // part of the system call. + ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK, + &new_action.sa_mask, &old_set); + assert(ret == 0 && "pthread_sigmask failed"); + info.was_blocked = sigismember(&old_set, signo); + m_signals.insert({signo, info}); + return SignalHandleUP(new SignalHandle(*this, signo)); #endif } @@ -331,7 +320,6 @@ void MainLoop::UnregisterSignal(int signo) { #if SIGNAL_POLLING_UNSUPPORTED Error("Signal polling is not supported on this platform."); #else - // We undo the actions of RegisterSignal on a best-effort basis. auto it = m_signals.find(signo); assert(it != m_signals.end()); @@ -340,8 +328,17 @@ void MainLoop::UnregisterSignal(int signo) { sigset_t set; sigemptyset(&set); sigaddset(&set, signo); - pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, - nullptr); + int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, + &set, nullptr); + assert(ret == 0); + (void)ret; + +#if HAVE_SYS_EVENT_H + struct kevent ev; + EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0); + ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr); + assert(ret == 0); +#endif m_signals.erase(it); #endif @@ -351,32 +348,31 @@ Error MainLoop::Run() { m_terminate_request = false; Error error; - auto impl = RunImpl::Create(*this, error); - if (!impl) - return error; + RunImpl impl(*this); // run until termination or until we run out of things to listen to while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) { - error = impl->Poll(); + error = impl.Poll(); if (error.Fail()) return error; - impl->ForEachSignal([&](int sig) { - auto it = m_signals.find(sig); - if (it != m_signals.end()) - it->second.callback(*this); // Do the work - }); - if (m_terminate_request) - return Error(); + impl.ProcessEvents(); - impl->ForEachReadFD([&](int fd) { - auto it = m_read_fds.find(fd); - if (it != m_read_fds.end()) - it->second(*this); // Do the work - }); if (m_terminate_request) return Error(); } return Error(); } + +void MainLoop::ProcessSignal(int signo) { + auto it = m_signals.find(signo); + if (it != m_signals.end()) + it->second.callback(*this); // Do the work +} + +void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) { + auto it = m_read_fds.find(handle); + if (it != m_read_fds.end()) + it->second(*this); // Do the work +} diff --git a/source/Host/common/UDPSocket.cpp b/source/Host/common/UDPSocket.cpp index a32657aab0a6..ce8d90891b2b 100644 --- a/source/Host/common/UDPSocket.cpp +++ b/source/Host/common/UDPSocket.cpp @@ -28,31 +28,41 @@ const int kDomain = AF_INET; const int kType = SOCK_DGRAM; static const char *g_not_supported_error = "Not supported"; -} // namespace +} + +UDPSocket::UDPSocket(NativeSocket socket) : Socket(ProtocolUdp, true, true) { + m_socket = socket; +} UDPSocket::UDPSocket(bool should_close, bool child_processes_inherit) : Socket(ProtocolUdp, should_close, child_processes_inherit) {} -UDPSocket::UDPSocket(NativeSocket socket, const UDPSocket &listen_socket) - : Socket(ProtocolUdp, listen_socket.m_should_close_fd, - listen_socket.m_child_processes_inherit) { - m_socket = socket; -} - size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { return ::sendto(m_socket, static_cast(buf), num_bytes, 0, m_sockaddr, m_sockaddr.GetLength()); } Error UDPSocket::Connect(llvm::StringRef name) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Listen(llvm::StringRef name, int backlog) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Accept(Socket *&socket) { + return Error("%s", g_not_supported_error); +} + +Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + std::unique_ptr final_socket; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); Error error; - if (error.Fail()) - return error; - std::string host_str; std::string port_str; int32_t port = INT32_MIN; @@ -84,11 +94,12 @@ Error UDPSocket::Connect(llvm::StringRef name) { for (struct addrinfo *service_info_ptr = service_info_list; service_info_ptr != nullptr; service_info_ptr = service_info_ptr->ai_next) { - m_socket = Socket::CreateSocket( + auto send_fd = CreateSocket( service_info_ptr->ai_family, service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, m_child_processes_inherit, error); + service_info_ptr->ai_protocol, child_processes_inherit, error); if (error.Success()) { - m_sockaddr = service_info_ptr; + final_socket.reset(new UDPSocket(send_fd)); + final_socket->m_sockaddr = service_info_ptr; break; } else continue; @@ -96,17 +107,16 @@ Error UDPSocket::Connect(llvm::StringRef name) { ::freeaddrinfo(service_info_list); - if (IsValid()) + if (!final_socket) return error; SocketAddress bind_addr; // Only bind to the loopback address if we are expecting a connection from // localhost to avoid any firewall issues. - const bool bind_addr_success = - (host_str == "127.0.0.1" || host_str == "localhost") - ? bind_addr.SetToLocalhost(kDomain, port) - : bind_addr.SetToAnyAddress(kDomain, port); + const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); if (!bind_addr_success) { error.SetErrorString("Failed to get hostspec to bind for"); @@ -115,37 +125,13 @@ Error UDPSocket::Connect(llvm::StringRef name) { bind_addr.SetPort(0); // Let the source port # be determined dynamically - err = ::bind(m_socket, bind_addr, bind_addr.GetLength()); + err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); + struct sockaddr_in source_info; + socklen_t address_len = sizeof (struct sockaddr_in); + err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); + + socket = final_socket.release(); error.Clear(); return error; } - -Error UDPSocket::Listen(llvm::StringRef name, int backlog) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::Accept(Socket *&socket) { - return Error("%s", g_not_supported_error); -} - -Error UDPSocket::CreateSocket() { - Error error; - if (IsValid()) - error = Close(); - if (error.Fail()) - return error; - m_socket = - Socket::CreateSocket(kDomain, kType, 0, m_child_processes_inherit, error); - return error; -} - -Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, - Socket *&socket) { - std::unique_ptr final_socket( - new UDPSocket(true, child_processes_inherit)); - Error error = final_socket->Connect(name); - if (!error.Fail()) - socket = final_socket.release(); - return error; -} diff --git a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp index 04df0065d7bc..65cbd271e979 100644 --- a/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp +++ b/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp @@ -2362,32 +2362,30 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( if (success) return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); - } else if (type_flags & eTypeIsVector) { + } else if (type_flags & eTypeIsVector && byte_size <= 16) { if (byte_size > 0) { const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0); if (v0_info) { - if (byte_size <= v0_info->byte_size) { - std::unique_ptr heap_data_ap( - new DataBufferHeap(byte_size, 0)); - const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); - RegisterValue reg_value; - if (reg_ctx->ReadRegister(v0_info, reg_value)) { - Error error; - if (reg_value.GetAsMemoryData(v0_info, heap_data_ap->GetBytes(), - heap_data_ap->GetByteSize(), - byte_order, error)) { - DataExtractor data(DataBufferSP(heap_data_ap.release()), - byte_order, - exe_ctx.GetProcessRef().GetAddressByteSize()); - return_valobj_sp = ValueObjectConstResult::Create( - &thread, return_compiler_type, ConstString(""), data); - } + std::unique_ptr heap_data_ap( + new DataBufferHeap(byte_size, 0)); + const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder(); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(v0_info, reg_value)) { + Error error; + if (reg_value.GetAsMemoryData(v0_info, heap_data_ap->GetBytes(), + heap_data_ap->GetByteSize(), byte_order, + error)) { + DataExtractor data(DataBufferSP(heap_data_ap.release()), byte_order, + exe_ctx.GetProcessRef().GetAddressByteSize()); + return_valobj_sp = ValueObjectConstResult::Create( + &thread, return_compiler_type, ConstString(""), data); } } } } - } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) { + } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || + (type_flags & eTypeIsVector && byte_size > 16)) { DataExtractor data; uint32_t NGRN = 0; // Search ABI docs for NGRN diff --git a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index 20260ee5b5c3..c824653b2e93 100644 --- a/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -434,24 +434,25 @@ Error DynamicLoaderMacOS::CanLoadImage() { // Default assumption is that it is OK to load images. // Only say that we cannot load images if we find the symbol in libdyld and it - // indicates that - // we cannot. + // indicates that we cannot. if (symbol_address != LLDB_INVALID_ADDRESS) { { int lock_held = m_process->ReadUnsignedIntegerFromMemory(symbol_address, 4, 0, error); if (lock_held != 0) { - error.SetErrorToGenericError(); + error.SetErrorString("dyld lock held - unsafe to load images."); } } } else { // If we were unable to find _dyld_global_lock_held in any modules, or it is - // not loaded into - // memory yet, we may be at process startup (sitting at _dyld_start) - so we - // should not allow - // dlopen calls. - error.SetErrorToGenericError(); + // not loaded into memory yet, we may be at process startup (sitting + // at _dyld_start) - so we should not allow dlopen calls. + // But if we found more than one module then we are clearly past _dyld_start + // so in that case we'll default to "it's safe". + if (num_modules <= 1) + error.SetErrorString("could not find the dyld library or " + "the dyld lock symbol"); } return error; } diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 8c2fc3d3aa42..ad6af8dfebd5 100644 --- a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1946,7 +1946,9 @@ void SymbolFileDWARF::Index() { std::vector type_index(num_compile_units); std::vector namespace_index(num_compile_units); - std::vector clear_cu_dies(num_compile_units, false); + // std::vector might be implemented using bit test-and-set, so use + // uint8_t instead. + std::vector clear_cu_dies(num_compile_units, false); auto parser_fn = [debug_info, &function_basename_index, &function_fullname_index, &function_method_index, &function_selector_index, &objc_class_selectors_index, @@ -1963,22 +1965,18 @@ void SymbolFileDWARF::Index() { return cu_idx; }; - auto extract_fn = [debug_info](uint32_t cu_idx) { + auto extract_fn = [debug_info, &clear_cu_dies](uint32_t cu_idx) { DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx); if (dwarf_cu) { // dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the // DIEs for a compile unit have already been parsed. - return std::make_pair(cu_idx, dwarf_cu->ExtractDIEsIfNeeded(false) > 1); + if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1) + clear_cu_dies[cu_idx] = true; } - return std::make_pair(cu_idx, false); }; // Create a task runner that extracts dies for each DWARF compile unit in a // separate thread - TaskRunner> task_runner_extract; - for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) - task_runner_extract.AddTask(extract_fn, cu_idx); - //---------------------------------------------------------------------- // First figure out which compile units didn't have their DIEs already // parsed and remember this. If no DIEs were parsed prior to this index @@ -1988,48 +1986,37 @@ void SymbolFileDWARF::Index() { // a DIE in one compile unit refers to another and the indexes accesses // those DIEs. //---------------------------------------------------------------------- - while (true) { - auto f = task_runner_extract.WaitForNextCompletedTask(); - if (!f.valid()) - break; - unsigned cu_idx; - bool clear; - std::tie(cu_idx, clear) = f.get(); - clear_cu_dies[cu_idx] = clear; - } + TaskMapOverInt(0, num_compile_units, extract_fn); // Now create a task runner that can index each DWARF compile unit in a // separate // thread so we can index quickly. - TaskRunner task_runner; - for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) - task_runner.AddTask(parser_fn, cu_idx); + TaskMapOverInt(0, num_compile_units, parser_fn); - while (true) { - std::future f = task_runner.WaitForNextCompletedTask(); - if (!f.valid()) - break; - uint32_t cu_idx = f.get(); + auto finalize_fn = [](NameToDIE &index, std::vector &srcs) { + for (auto &src : srcs) + index.Append(src); + index.Finalize(); + }; - m_function_basename_index.Append(function_basename_index[cu_idx]); - m_function_fullname_index.Append(function_fullname_index[cu_idx]); - m_function_method_index.Append(function_method_index[cu_idx]); - m_function_selector_index.Append(function_selector_index[cu_idx]); - m_objc_class_selectors_index.Append(objc_class_selectors_index[cu_idx]); - m_global_index.Append(global_index[cu_idx]); - m_type_index.Append(type_index[cu_idx]); - m_namespace_index.Append(namespace_index[cu_idx]); - } - - TaskPool::RunTasks([&]() { m_function_basename_index.Finalize(); }, - [&]() { m_function_fullname_index.Finalize(); }, - [&]() { m_function_method_index.Finalize(); }, - [&]() { m_function_selector_index.Finalize(); }, - [&]() { m_objc_class_selectors_index.Finalize(); }, - [&]() { m_global_index.Finalize(); }, - [&]() { m_type_index.Finalize(); }, - [&]() { m_namespace_index.Finalize(); }); + TaskPool::RunTasks( + [&]() { + finalize_fn(m_function_basename_index, function_basename_index); + }, + [&]() { + finalize_fn(m_function_fullname_index, function_fullname_index); + }, + [&]() { finalize_fn(m_function_method_index, function_method_index); }, + [&]() { + finalize_fn(m_function_selector_index, function_selector_index); + }, + [&]() { + finalize_fn(m_objc_class_selectors_index, objc_class_selectors_index); + }, + [&]() { finalize_fn(m_global_index, global_index); }, + [&]() { finalize_fn(m_type_index, type_index); }, + [&]() { finalize_fn(m_namespace_index, namespace_index); }); //---------------------------------------------------------------------- // Keep memory down by clearing DIEs for any compile units if indexing diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp index 679040d09a02..15cbd0baa9a6 100644 --- a/source/Target/ThreadPlanCallUserExpression.cpp +++ b/source/Target/ThreadPlanCallUserExpression.cpp @@ -60,6 +60,12 @@ void ThreadPlanCallUserExpression::GetDescription( ThreadPlanCallFunction::GetDescription(s, level); } +void ThreadPlanCallUserExpression::DidPush() { + ThreadPlanCallFunction::DidPush(); + if (m_user_expression_sp) + m_user_expression_sp->WillStartExecuting(); +} + void ThreadPlanCallUserExpression::WillPop() { ThreadPlanCallFunction::WillPop(); if (m_user_expression_sp) @@ -113,3 +119,8 @@ StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() { return stop_info_sp; } + +void ThreadPlanCallUserExpression::DoTakedown(bool success) { + ThreadPlanCallFunction::DoTakedown(success); + m_user_expression_sp->DidFinishExecuting(); +} diff --git a/source/Utility/TaskPool.cpp b/source/Utility/TaskPool.cpp index 244e64fdb5fb..d8306dc7dc8f 100644 --- a/source/Utility/TaskPool.cpp +++ b/source/Utility/TaskPool.cpp @@ -73,3 +73,26 @@ void TaskPoolImpl::Worker(TaskPoolImpl *pool) { f(); } } + +void TaskMapOverInt(size_t begin, size_t end, + std::function const &func) { + std::atomic idx{begin}; + size_t num_workers = + std::min(end, std::thread::hardware_concurrency()); + + auto wrapper = [&idx, end, &func]() { + while (true) { + size_t i = idx.fetch_add(1); + if (i >= end) + break; + func(i); + } + }; + + std::vector> futures; + futures.reserve(num_workers); + for (size_t i = 0; i < num_workers; i++) + futures.push_back(TaskPool::AddTask(wrapper)); + for (size_t i = 0; i < num_workers; i++) + futures[i].wait(); +} diff --git a/unittests/Host/CMakeLists.txt b/unittests/Host/CMakeLists.txt index 3396f45da4f3..7b2ce3bbfde5 100644 --- a/unittests/Host/CMakeLists.txt +++ b/unittests/Host/CMakeLists.txt @@ -1,6 +1,7 @@ set (FILES FileSpecTest.cpp FileSystemTest.cpp + MainLoopTest.cpp SocketAddressTest.cpp SocketTest.cpp SymbolsTest.cpp diff --git a/unittests/Host/MainLoopTest.cpp b/unittests/Host/MainLoopTest.cpp new file mode 100644 index 000000000000..a2a673d38ca5 --- /dev/null +++ b/unittests/Host/MainLoopTest.cpp @@ -0,0 +1,120 @@ +//===-- MainLoopTest.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/MainLoop.h" +#include "lldb/Host/common/TCPSocket.h" +#include "gtest/gtest.h" +#include + +using namespace lldb_private; + +namespace { +class MainLoopTest : public testing::Test { +public: + static void SetUpTestCase() { +#ifdef _MSC_VER + WSADATA data; + ASSERT_EQ(0, WSAStartup(MAKEWORD(2, 2), &data)); +#endif + } + + static void TearDownTestCase() { +#ifdef _MSC_VER + ASSERT_EQ(0, WSACleanup()); +#endif + } + + void SetUp() override { + bool child_processes_inherit = false; + Error error; + std::unique_ptr listen_socket_up( + new TCPSocket(true, child_processes_inherit)); + ASSERT_TRUE(error.Success()); + error = listen_socket_up->Listen("localhost:0", 5); + ASSERT_TRUE(error.Success()); + + Socket *accept_socket; + std::future accept_error = std::async(std::launch::async, [&] { + return listen_socket_up->Accept(accept_socket); + }); + + std::unique_ptr connect_socket_up( + new TCPSocket(true, child_processes_inherit)); + error = connect_socket_up->Connect( + llvm::formatv("localhost:{0}", listen_socket_up->GetLocalPortNumber()) + .str()); + ASSERT_TRUE(error.Success()); + ASSERT_TRUE(accept_error.get().Success()); + + callback_count = 0; + socketpair[0] = std::move(connect_socket_up); + socketpair[1].reset(accept_socket); + } + + void TearDown() override { + socketpair[0].reset(); + socketpair[1].reset(); + } + +protected: + MainLoop::Callback make_callback() { + return [&](MainLoopBase &loop) { + ++callback_count; + loop.RequestTermination(); + }; + } + std::shared_ptr socketpair[2]; + unsigned callback_count; +}; +} // namespace + +TEST_F(MainLoopTest, ReadObject) { + char X = 'X'; + size_t len = sizeof(X); + ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); + + MainLoop loop; + + Error error; + auto handle = loop.RegisterReadObject(socketpair[1], make_callback(), error); + ASSERT_TRUE(error.Success()); + ASSERT_TRUE(handle); + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(1u, callback_count); +} + +TEST_F(MainLoopTest, TerminatesImmediately) { + char X = 'X'; + size_t len = sizeof(X); + ASSERT_TRUE(socketpair[0]->Write(&X, len).Success()); + ASSERT_TRUE(socketpair[1]->Write(&X, len).Success()); + + MainLoop loop; + Error error; + auto handle0 = loop.RegisterReadObject(socketpair[0], make_callback(), error); + ASSERT_TRUE(error.Success()); + auto handle1 = loop.RegisterReadObject(socketpair[1], make_callback(), error); + ASSERT_TRUE(error.Success()); + + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(1u, callback_count); +} + +#ifdef LLVM_ON_UNIX +TEST_F(MainLoopTest, Signal) { + MainLoop loop; + Error error; + + auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error); + ASSERT_TRUE(error.Success()); + kill(getpid(), SIGUSR1); + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(1u, callback_count); +} +#endif diff --git a/unittests/Utility/TaskPoolTest.cpp b/unittests/Utility/TaskPoolTest.cpp index 172e32a9c6c0..e340a81b27db 100644 --- a/unittests/Utility/TaskPoolTest.cpp +++ b/unittests/Utility/TaskPoolTest.cpp @@ -30,25 +30,14 @@ TEST(TaskPoolTest, RunTasks) { ASSERT_EQ(17, r[3]); } -TEST(TaskPoolTest, TaskRunner) { - auto fn = [](int x) { return std::make_pair(x, x * x); }; +TEST(TaskPoolTest, TaskMap) { + int data[4]; + auto fn = [&data](int x) { data[x] = x * x; }; - TaskRunner> tr; - tr.AddTask(fn, 1); - tr.AddTask(fn, 2); - tr.AddTask(fn, 3); - tr.AddTask(fn, 4); + TaskMapOverInt(0, 4, fn); - int count = 0; - while (true) { - auto f = tr.WaitForNextCompletedTask(); - if (!f.valid()) - break; - - ++count; - std::pair v = f.get(); - ASSERT_EQ(v.first * v.first, v.second); - } - - ASSERT_EQ(4, count); + ASSERT_EQ(data[0], 0); + ASSERT_EQ(data[1], 1); + ASSERT_EQ(data[2], 4); + ASSERT_EQ(data[3], 9); } diff --git a/www/lldb-gdb.html b/www/lldb-gdb.html index 60cd718d5255..69179bd8c07c 100755 --- a/www/lldb-gdb.html +++ b/www/lldb-gdb.html @@ -772,6 +772,27 @@ + List the threads in your program. + + + (gdb) info threads
+ + + (lldb) thread list
+ + + + Select thread 1 as the default thread for subsequent commands. + + + (gdb) thread 1
+ + + (lldb) thread select 1
+ (lldb) t 1
+ + + Show the stack backtrace for the current thread. @@ -1250,6 +1271,16 @@ LLDB + Search command help for a keyword. + + + (gdb) apropos keyword
+ + + (lldb) apropos keyword
+ + + Echo text to the screen.