diff options
Diffstat (limited to 'gnu/llvm/lldb/packages/Python/lldbsuite/test/api')
28 files changed, 1306 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/Makefile new file mode 100644 index 00000000000..99998b20bcb --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py new file mode 100644 index 00000000000..6f95cd7959e --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py @@ -0,0 +1,69 @@ +"""Test the integrity of the lldb public api directory containing SB*.h headers. + +There should be nothing unwanted there and a simpe main.cpp which includes SB*.h +should compile and link with the LLDB framework.""" + +from __future__ import print_function + + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class SBDirCheckerCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + self.source = 'main.cpp' + self.generateSource(self.source) + + @skipIfNoSBHeaders + def test_sb_api_directory(self): + """Test the SB API directory and make sure there's no unwanted stuff.""" + + # Only proceed if this is an Apple OS, "x86_64", and local platform. + if not (self.platformIsDarwin() and self.getArchitecture() == "x86_64"): + self.skipTest("This test is only for LLDB.framework built 64-bit") + if self.getArchitecture() == "i386": + self.skipTest( + "LLDB is 64-bit and cannot be linked to 32-bit test program.") + + exe_name = self.getBuildArtifact("a.out") + self.buildDriver(self.source, exe_name) + self.sanity_check_executable(exe_name) + + def sanity_check_executable(self, exe_name): + """Sanity check executable compiled from the auto-generated program.""" + exe_name = self.getBuildArtifact("a.out") + exe = self.getBuildArtifact(exe_name) + self.runCmd("file %s" % exe, CURRENT_EXECUTABLE_SET) + + # This test uses a generated source file, so it's in the build directory. + self.line_to_break = line_number( + self.getBuildArtifact(self.source), '// Set breakpoint here.') + + env_cmd = "settings set target.env-vars %s=%s" % ( + self.dylibPath, self.getLLDBLibraryEnvVal()) + if self.TraceOn(): + print("Set environment to: ", env_cmd) + self.runCmd(env_cmd) + self.addTearDownHook( + lambda: self.dbg.HandleCommand( + "settings remove target.env-vars %s" % + self.dylibPath)) + + lldbutil.run_break_set_by_file_and_line( + self, self.source, self.line_to_break, num_expected_locations=-1) + + 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']) + + self.runCmd('frame variable') diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/main.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/main.cpp.template new file mode 100644 index 00000000000..7fced85cd3a --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/check_public_api_headers/main.cpp.template @@ -0,0 +1,23 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> +%include_SB_APIs% + +using namespace lldb; +int +main(int argc, char const *argv[]) +{ + SBDebugger::Initialize(); + SBDebugger dbg = SBDebugger::Create(); + + printf("Hello SBDebugger %llu\n", dbg.GetID()); // Set breakpoint here. + + SBDebugger::Terminate(); + return 0; +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/Makefile new file mode 100644 index 00000000000..99998b20bcb --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/TestSBCommandReturnObject.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/TestSBCommandReturnObject.py new file mode 100644 index 00000000000..c7aa2eced83 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/TestSBCommandReturnObject.py @@ -0,0 +1,34 @@ +"""Test the lldb public C++ api for returning SBCommandReturnObject.""" + +from __future__ import print_function + + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestSBCommandReturnObject(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfNoSBHeaders + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr43570") + def test_sb_command_return_object(self): + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} + + self.driver_exe = self.getBuildArtifact("command-return-object") + self.buildDriver('main.cpp', self.driver_exe) + self.addTearDownHook(lambda: os.remove(self.driver_exe)) + self.signBinary(self.driver_exe) + + if self.TraceOn(): + print("Running test %s" % self.driver_exe) + check_call([self.driver_exe, self.driver_exe], env=env) + else: + with open(os.devnull, 'w') as fnull: + check_call([self.driver_exe, self.driver_exe], + env=env, stdout=fnull, stderr=fnull) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/main.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/main.cpp new file mode 100644 index 00000000000..c1d4d246a43 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/command-return-object/main.cpp @@ -0,0 +1,33 @@ +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBDebugger.h" + +using namespace lldb; + +static SBCommandReturnObject subcommand(SBDebugger &dbg, const char *cmd) { + SBCommandReturnObject Result; + dbg.GetCommandInterpreter().HandleCommand(cmd, Result); + return Result; +} + +class CommandCrasher : public SBCommandPluginInterface { +public: + bool DoExecute(SBDebugger dbg, char **command, + SBCommandReturnObject &result) { + // Test assignment from a different SBCommandReturnObject instance. + result = subcommand(dbg, "help"); + // Test also whether self-assignment is handled correctly. + result = result; + return result.Succeeded(); + } +}; + +int main() { + SBDebugger::Initialize(); + SBDebugger dbg = SBDebugger::Create(false /*source_init_files*/); + SBCommandInterpreter interp = dbg.GetCommandInterpreter(); + static CommandCrasher crasher; + interp.AddCommand("crasher", &crasher, nullptr /*help*/); + SBCommandReturnObject Result; + dbg.GetCommandInterpreter().HandleCommand("crasher", Result); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/Makefile new file mode 100644 index 00000000000..692ba173228 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c + +include Makefile.rules + diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/TestListener.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/TestListener.py new file mode 100644 index 00000000000..480041b3e1f --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/TestListener.py @@ -0,0 +1,63 @@ +""" +Test that we can listen to modules loaded events. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +import six + + +class ListenToModuleLoadedEvents (TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test_receiving_breakpoint_added(self): + """Test that we get breakpoint added events, waiting on event classes on the debugger""" + self.build() + + my_listener = lldb.SBListener("test_listener") + + my_listener.StartListeningForEventClass( + self.dbg, + lldb.SBTarget.GetBroadcasterClassName(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) + + exe = self.getBuildArtifact("a.out") + + target = self.dbg.CreateTarget(exe) + + bkpt = target.BreakpointCreateByName("main") + + event = lldb.SBEvent() + my_listener.WaitForEvent(1, event) + + self.assertTrue(event.IsValid(), "Got a valid event.") + self.assertTrue( + lldb.SBBreakpoint.EventIsBreakpointEvent(event), + "It is a breakpoint event.") + self.assertTrue(lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent( + event) == lldb.eBreakpointEventTypeAdded, "It is a breakpoint added event.") + self.assertTrue( + bkpt == lldb.SBBreakpoint.GetBreakpointFromEvent(event), + "It is our breakpoint.") + + # Now make sure if we stop listening for events we don't get them: + + my_listener.StopListeningForEventClass( + self.dbg, + lldb.SBTarget.GetBroadcasterClassName(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) + my_listener.StopListeningForEvents( + target.GetBroadcaster(), + lldb.SBTarget.eBroadcastBitBreakpointChanged) + + bkpt2 = target.BreakpointCreateByName("main") + my_listener.WaitForEvent(1, event) + self.assertTrue( + not event.IsValid(), + "We don't get events we aren't listening to.") diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/main.c b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/main.c new file mode 100644 index 00000000000..f930e511915 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/listeners/main.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int +main() +{ + printf ("Hello there.\n"); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/log/TestAPILog.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/log/TestAPILog.py new file mode 100644 index 00000000000..c0ffa2c6f50 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/log/TestAPILog.py @@ -0,0 +1,51 @@ +""" +Test API logging. +""" + +import re + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class APILogTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_api_log(self): + """Test API logging""" + logfile = os.path.join(self.getBuildDir(), "api-log.txt") + + def cleanup(): + if os.path.exists(logfile): + os.unlink(logfile) + + self.addTearDownHook(cleanup) + self.expect("log enable lldb api -f {}".format(logfile)) + + self.dbg.SetDefaultArchitecture(None) + self.dbg.GetScriptingLanguage(None) + target = self.dbg.CreateTarget(None) + + print(logfile) + with open(logfile, 'r') as f: + log = f.read() + + # Find the SBDebugger's address. + debugger_addr = re.findall( + r"lldb::SBDebugger::GetScriptingLanguage\([^)]*\) \(0x([0-9a-fA-F]+),", + log) + + # Make sure we've found a match. + self.assertTrue(debugger_addr, log) + + # Make sure the GetScriptingLanguage matches. + self.assertTrue(re.search(r'lldb::SBDebugger::GetScriptingLanguage\([^)]*\) \(0x{}, ""\)'.format( + debugger_addr[0]), log), log) + + # Make sure the address matches. + self.assertTrue(re.search(r'lldb::SBDebugger::CreateTarget\([^)]*\) \(0x{}, ""\)'.format( + debugger_addr[0]), log), log) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/.categories b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/.categories new file mode 100644 index 00000000000..6e70196ccd7 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/.categories @@ -0,0 +1 @@ +stresstest diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/Makefile new file mode 100644 index 00000000000..f40386a5227 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/Makefile @@ -0,0 +1,6 @@ +MAKE_DSYM := NO + +ENABLE_THREADS := YES +CXX_SOURCES := multi-process-driver.cpp testprog.cpp + +include Makefile.rules diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py new file mode 100644 index 00000000000..1447bbdfe42 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py @@ -0,0 +1,43 @@ +"""Test the lldb public C++ api when doing multiple debug sessions simultaneously.""" + +from __future__ import print_function + + +import os + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestMultipleSimultaneousDebuggers(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # This test case fails non-deterministically. + @skipIfNoSBHeaders + @expectedFailureAll(bugnumber="llvm.org/pr20282") + def test_multiple_debuggers(self): + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} + + self.driver_exe = self.getBuildArtifact("multi-process-driver") + self.buildDriver('multi-process-driver.cpp', self.driver_exe) + self.addTearDownHook(lambda: os.remove(self.driver_exe)) + self.signBinary(self.driver_exe) + + self.inferior_exe = self.getBuildArtifact("testprog") + self.buildDriver('testprog.cpp', self.inferior_exe) + self.addTearDownHook(lambda: os.remove(self.inferior_exe)) + +# check_call will raise a CalledProcessError if multi-process-driver doesn't return +# exit code 0 to indicate success. We can let this exception go - the test harness +# will recognize it as a test failure. + + if self.TraceOn(): + print("Running test %s" % self.driver_exe) + check_call([self.driver_exe, self.inferior_exe], env=env) + else: + with open(os.devnull, 'w') as fnull: + check_call([self.driver_exe, self.inferior_exe], + env=env, stdout=fnull, stderr=fnull) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp new file mode 100644 index 00000000000..15170a3e5eb --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp @@ -0,0 +1,287 @@ + +// This program creates NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS of pthreads, +// creates an lldb Debugger on each thread, creates targets, inserts two +// breakpoints, runs to the first breakpoint, backtraces, runs to the second +// breakpoint, backtraces, kills the inferior process, closes down the +// debugger. + +// The main thread keeps track of which pthreads have completed and which +// pthreads have completed successfully, and exits when all pthreads have +// completed successfully, or our time limit has been exceeded. + +// This test file helps to uncover race conditions and locking mistakes +// that are hit when lldb is being used to debug multiple processes +// simultaneously. + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lldb/API/LLDB.h" +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBDebugger.h" + +#include <chrono> +#include <thread> + +#define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 10 + +#define DEBUG 0 + +using namespace lldb; + +bool *completed_threads_array = 0; +bool *successful_threads_array = 0; + +const char *inferior_process_name = "testprog"; + +bool +wait_for_stop_event (SBProcess process, SBListener listener) +{ + bool stopped = false; + while (!stopped) + { + SBEvent event; + bool waitfor_ret = listener.WaitForEvent (2, event); + if (event.GetType() == SBProcess::eBroadcastBitStateChanged) + { + if (process.GetState() == StateType::eStateStopped + || process.GetState() == StateType::eStateCrashed + || process.GetState() == StateType::eStateDetached + || process.GetState() == StateType::eStateExited) + { + stopped = true; + } + } + } + return stopped; +} + +bool +walk_stack_to_main (SBThread thread) +{ + if (thread.IsValid() == 0) + { + return false; + } + + bool found_main = false; + uint32_t curr_frame = 0; + const uint32_t framecount = thread.GetNumFrames(); + while (!found_main && curr_frame < framecount) + { + SBFrame frame = thread.GetFrameAtIndex (curr_frame); + if (strcmp (frame.GetFunctionName(), "main") == 0) + { + found_main = true; + break; + } + curr_frame += 1; + } + return found_main; +} + +void *do_one_debugger (void *in) +{ + uint64_t threadnum = (uint64_t) in; + +#if defined (__APPLE__) + char *threadname; + asprintf (&threadname, "thread #%lld", threadnum); + pthread_setname_np (threadname); + free (threadname); +#endif + +#if DEBUG == 1 + printf ("#%lld: Starting debug session\n", threadnum); +#endif + + SBDebugger debugger = lldb::SBDebugger::Create (false); + if (debugger.IsValid ()) + { + debugger.SetAsync (true); + SBTarget target = debugger.CreateTargetWithFileAndArch(inferior_process_name, "x86_64"); + SBCommandInterpreter command_interp = debugger.GetCommandInterpreter(); + if (target.IsValid()) + { + SBBreakpoint bar_br = target.BreakpointCreateByName ("bar", "testprog"); + if (!bar_br.IsValid()) + { + printf ("#%lld: failed to set breakpoint on bar, exiting.\n", threadnum); + exit (1); + } + SBBreakpoint foo_br = target.BreakpointCreateByName ("foo", "testprog"); + if (!foo_br.IsValid()) + { + printf ("#%lld: Failed to set breakpoint on foo()\n", threadnum); + } + + SBLaunchInfo launch_info (NULL); + SBError error; + SBProcess process = target.Launch (launch_info, error); + if (process.IsValid()) + { + SBListener listener = debugger.GetListener(); + SBBroadcaster broadcaster = process.GetBroadcaster(); + uint32_t rc = broadcaster.AddListener (listener, SBProcess::eBroadcastBitStateChanged); + if (rc == 0) + { + printf ("adding listener failed\n"); + exit (1); + } + + wait_for_stop_event (process, listener); + + if (!walk_stack_to_main (process.GetThreadAtIndex(0))) + { + printf ("#%lld: backtrace while @ foo() failed\n", threadnum); + completed_threads_array[threadnum] = true; + return (void *) 1; + } + + if (strcmp (process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName(), "foo") != 0) + { +#if DEBUG == 1 + printf ("#%lld: First breakpoint did not stop at foo(), instead stopped at '%s'\n", threadnum, process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName()); +#endif + completed_threads_array[threadnum] = true; + return (void*) 1; + } + + process.Continue(); + + wait_for_stop_event (process, listener); + + if (process.GetState() == StateType::eStateExited) + { + printf ("#%lld: Process exited\n", threadnum); + completed_threads_array[threadnum] = true; + return (void *) 1; + } + + + if (!walk_stack_to_main (process.GetThreadAtIndex(0))) + { + printf ("#%lld: backtrace while @ bar() failed\n", threadnum); + completed_threads_array[threadnum] = true; + return (void *) 1; + } + + if (strcmp (process.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName(), "bar") != 0) + { + printf ("#%lld: First breakpoint did not stop at bar()\n", threadnum); + completed_threads_array[threadnum] = true; + return (void*) 1; + } + + process.Kill(); + + wait_for_stop_event (process, listener); + + SBDebugger::Destroy(debugger); + +#if DEBUG == 1 + printf ("#%lld: All good!\n", threadnum); +#endif + successful_threads_array[threadnum] = true; + completed_threads_array[threadnum] = true; + return (void*) 0; + } + else + { + printf("#%lld: process failed to launch\n", threadnum); + successful_threads_array[threadnum] = false; + completed_threads_array[threadnum] = true; + return (void*) 0; + } + } + else + { + printf ("#%lld: did not get valid target\n", threadnum); + successful_threads_array[threadnum] = false; + completed_threads_array[threadnum] = true; + return (void*) 0; + } + } + else + { + printf ("#%lld: did not get debugger\n", threadnum); + successful_threads_array[threadnum] = false; + completed_threads_array[threadnum] = true; + return (void*) 0; + } + completed_threads_array[threadnum] = true; + return (void*) 1; +} + +int main (int argc, char **argv) +{ +#if !defined(_MSC_VER) + signal(SIGPIPE, SIG_IGN); +#endif + + SBDebugger::Initialize(); + + completed_threads_array = (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); + memset (completed_threads_array, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); + successful_threads_array = (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); + memset (successful_threads_array, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); + + if (argc > 1 && argv[1] != NULL) + { + inferior_process_name = argv[1]; + } + + std::thread threads[NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS]; + for (uint64_t i = 0; i< NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS; i++) + { + threads[i] = std::move(std::thread(do_one_debugger, (void*)i)); + } + + + int max_time_to_wait = 20; // 20 iterations, or 60 seconds + int iter = 0; + while (1) + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + bool all_done = true; + int successful_threads = 0; + int total_completed_threads = 0; + for (uint64_t i = 0; i < NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS; i++) + { + if (successful_threads_array[i] == true) + successful_threads++; + if (completed_threads_array[i] == true) + total_completed_threads++; + if (completed_threads_array[i] == false) + { + all_done = false; + } + } + if (all_done) + { +#if DEBUG == 1 + printf ("All threads completed.\n"); + printf ("%d threads completed successfully out of %d\n", successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); +#endif + SBDebugger::Terminate(); + exit(0); + } + else + { +#if DEBUG == 1 + printf ("%d threads completed so far (%d successfully), out of %d\n", total_completed_threads, successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); +#endif + } + if (iter++ == max_time_to_wait) + { + printf ("reached maximum timeout but only %d threads have completed so far (%d successfully), out of %d. Exiting.\n", total_completed_threads, successful_threads, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS); + break; + } + } + + + SBDebugger::Terminate(); + exit (1); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/testprog.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/testprog.cpp new file mode 100644 index 00000000000..c9d1ea14f17 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-debuggers/testprog.cpp @@ -0,0 +1,12 @@ +int bar () +{ + return 5; +} +int foo () +{ + return bar() + 5; +} +int main () +{ + return foo(); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/Makefile new file mode 100644 index 00000000000..3316b59b623 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/Makefile @@ -0,0 +1,6 @@ +MAKE_DSYM := NO + +ENABLE_THREADS := YES +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py new file mode 100644 index 00000000000..1268ff9306a --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py @@ -0,0 +1,42 @@ +"""Test the lldb public C++ api when creating multiple targets simultaneously.""" + +from __future__ import print_function + + +import os + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestMultipleTargets(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfNoSBHeaders + @skipIfHostIncompatibleWithRemote + @expectedFailureAll( + oslist=["windows", "freebsd"], + bugnumber="llvm.org/pr20282") + def test_multiple_targets(self): + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} + + self.driver_exe = self.getBuildArtifact("multi-target") + self.buildDriver('main.cpp', self.driver_exe) + self.addTearDownHook(lambda: os.remove(self.driver_exe)) + self.signBinary(self.driver_exe) + +# check_call will raise a CalledProcessError if multi-process-driver doesn't return +# exit code 0 to indicate success. We can let this exception go - the test harness +# will recognize it as a test failure. + + if self.TraceOn(): + print("Running test %s" % self.driver_exe) + check_call([self.driver_exe, self.driver_exe], env=env) + else: + with open(os.devnull, 'w') as fnull: + check_call([self.driver_exe, self.driver_exe], + env=env, stdout=fnull, stderr=fnull) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp new file mode 100644 index 00000000000..35fb4e0d613 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multiple-targets/main.cpp @@ -0,0 +1,31 @@ +#include <thread> + +#include "lldb/API/LLDB.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBTarget.h" + +using namespace lldb; +int main (int argc, char **argv) +{ + // We are expecting the program path and a path to an executable to load + if (argc != 2) + return 1; + const char *program_file = argv[1]; + SBDebugger::Initialize(); + SBDebugger debugger = SBDebugger::Create(false); + auto lambda = [&](){ + SBError error; + SBTarget target = debugger.CreateTarget(program_file, nullptr, nullptr, + false, error); + }; + + // Create 3 targets at the same time and make sure we don't crash. + std::thread thread1(lambda); + std::thread thread2(lambda); + std::thread thread3(lambda); + thread1.join(); + thread2.join(); + thread3.join(); + SBDebugger::Terminate(); + return 0; +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/Makefile b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/Makefile new file mode 100644 index 00000000000..81767219067 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/Makefile @@ -0,0 +1,7 @@ +ENABLE_THREADS := YES +CXX_SOURCES := main.cpp + +include Makefile.rules + +clean:: + rm -rf $(wildcard *.o *.d *.dSYM) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py new file mode 100644 index 00000000000..436f645e652 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py @@ -0,0 +1,109 @@ +"""Test the lldb public C++ api breakpoint callbacks.""" + +from __future__ import print_function + +# __package__ = "lldbsuite.test" + + +import os +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class SBBreakpointCallbackCase(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + self.generateSource('driver.cpp') + self.generateSource('listener_test.cpp') + self.generateSource('test_breakpoint_callback.cpp') + self.generateSource('test_listener_event_description.cpp') + self.generateSource('test_listener_event_process_state.cpp') + self.generateSource('test_listener_resume.cpp') + + mydir = TestBase.compute_mydir(__file__) + + @skipIfRemote + @skipIfNoSBHeaders + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows + def test_breakpoint_callback(self): + """Test the that SBBreakpoint callback is invoked when a breakpoint is hit. """ + self.build_and_test('driver.cpp test_breakpoint_callback.cpp', + 'test_breakpoint_callback') + + @skipIfRemote + @skipIfNoSBHeaders + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows + @expectedFlakeyFreeBSD + def test_sb_api_listener_event_description(self): + """ Test the description of an SBListener breakpoint event is valid.""" + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_event_description.cpp', + 'test_listener_event_description') + + @skipIfRemote + @skipIfNoSBHeaders + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows + @expectedFlakeyFreeBSD + def test_sb_api_listener_event_process_state(self): + """ Test that a registered SBListener receives events when a process + changes state. + """ + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_event_process_state.cpp', + 'test_listener_event_process_state') + + @skipIfRemote + @skipIfNoSBHeaders + # clang-cl does not support throw or catch (llvm.org/pr24538) + @skipIfWindows + @expectedFlakeyFreeBSD + @skipIf(oslist=["linux"]) # flakey + def test_sb_api_listener_resume(self): + """ Test that a process can be resumed from a non-main thread. """ + self.build_and_test( + 'driver.cpp listener_test.cpp test_listener_resume.cpp', + 'test_listener_resume') + + def build_and_test(self, sources, test_name, args=None): + """ Build LLDB test from sources, and run expecting 0 exit code """ + + # These tests link against host lldb API. + # Compiler's target triple must match liblldb triple + # because remote is disabled, we can assume that the os is the same + # still need to check architecture + if self.getLldbArchitecture() != self.getArchitecture(): + self.skipTest( + "This test is only run if the target arch is the same as the lldb binary arch") + + self.inferior = 'inferior_program' + self.buildProgram('inferior.cpp', self.inferior) + self.addTearDownHook(lambda: + os.remove(self.getBuildArtifact(self.inferior))) + + self.buildDriver(sources, test_name) + self.addTearDownHook(lambda: + os.remove(self.getBuildArtifact(test_name))) + + test_exe = self.getBuildArtifact(test_name) + self.signBinary(test_exe) + exe = [test_exe, self.getBuildArtifact(self.inferior)] + + env = {self.dylibPath: self.getLLDBLibraryEnvVal()} + if 'LLDB_DEBUGSERVER_PATH' in os.environ: + env['LLDB_DEBUGSERVER_PATH'] = os.environ['LLDB_DEBUGSERVER_PATH'] + if self.TraceOn(): + print("Running test %s" % " ".join(exe)) + check_call(exe, env=env) + else: + with open(os.devnull, 'w') as fnull: + check_call(exe, env=env, stdout=fnull, stderr=fnull) + + def build_program(self, sources, program): + return self.buildDriver(sources, program) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/common.h b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/common.h new file mode 100644 index 00000000000..bd40bdd421a --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/common.h @@ -0,0 +1,68 @@ +#ifndef LLDB_TEST_API_COMMON_H +#define LLDB_TEST_API_COMMON_H + +#include <condition_variable> +#include <chrono> +#include <exception> +#include <iostream> +#include <mutex> +#include <string> +#include <queue> + +#include <unistd.h> + +/// Simple exception class with a message +struct Exception : public std::exception +{ + std::string s; + Exception(std::string ss) : s(ss) {} + virtual ~Exception() throw () { } + const char* what() const throw() { return s.c_str(); } +}; + +// Synchronized data structure for listener to send events through +template<typename T> +class multithreaded_queue { + std::condition_variable m_condition; + std::mutex m_mutex; + std::queue<T> m_data; + bool m_notified; + +public: + + void push(T e) { + std::lock_guard<std::mutex> lock(m_mutex); + m_data.push(e); + m_notified = true; + m_condition.notify_all(); + } + + T pop(int timeout_seconds, bool &success) { + int count = 0; + while (count < timeout_seconds) { + std::unique_lock<std::mutex> lock(m_mutex); + if (!m_data.empty()) { + m_notified = false; + T ret = m_data.front(); + m_data.pop(); + success = true; + return ret; + } else if (!m_notified) + m_condition.wait_for(lock, std::chrono::seconds(1)); + count ++; + } + success = false; + return T(); + } +}; + +/// Allocates a char buffer with the current working directory +inline char* get_working_dir() { +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + return getwd(0); +#else + return get_current_dir_name(); +#endif +} + +#endif // LLDB_TEST_API_COMMON_H diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template new file mode 100644 index 00000000000..32459425c88 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template @@ -0,0 +1,51 @@ + +/// LLDB C API Test Driver + +#include <algorithm> +#include <iostream> +#include <iterator> +#include <string> +#include <vector> +#if !defined(_MSC_VER) + #include <signal.h> +#endif + +%include_SB_APIs% + +#include "common.h" + +using namespace std; +using namespace lldb; + +void test(SBDebugger &dbg, std::vector<string> args); + +int main(int argc, char** argv) { + +// Ignore SIGPIPE. The lldb driver does this as well, +// because we seem to get spurious SIGPIPES on some +// Unixen that take the driver down. +#if !defined(_MSC_VER) + signal(SIGPIPE, SIG_IGN); +#endif + int code = 0; + + SBDebugger::Initialize(); + SBDebugger dbg = SBDebugger::Create(); + dbg.HandleCommand("settings set symbols.enable-external-lookup false"); + dbg.HandleCommand( + "settings set plugin.process.gdb-remote.packet-timeout 60"); + + try { + if (!dbg.IsValid()) + throw Exception("invalid debugger"); + vector<string> args(argv + 1, argv + argc); + + test(dbg, args); + } catch (Exception &e) { + cout << "ERROR: " << e.what() << endl; + code = 1; + } + + SBDebugger::Destroy(dbg); + return code; +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/inferior.cpp b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/inferior.cpp new file mode 100644 index 00000000000..9dbb289f98b --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/inferior.cpp @@ -0,0 +1,17 @@ + +#include <iostream> + +using namespace std; + +int next() { + static int i = 0; + cout << "incrementing " << i << endl; + return ++i; +} + +int main() { + int i = 0; + while (i < 5) + i = next(); + return 0; +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template new file mode 100644 index 00000000000..e305d1af489 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template @@ -0,0 +1,74 @@ +// LLDB test snippet that registers a listener with a process that hits +// a breakpoint. + +#include <atomic> +#include <iostream> +#include <string> +#include <thread> +#include <vector> + +%include_SB_APIs% +#include "common.h" + +using namespace lldb; +using namespace std; + +void listener_func(); +void check_listener(SBDebugger &dbg); + +// Listener thread and related variables +atomic<bool> g_done; +SBListener g_listener("test-listener"); +thread g_listener_thread; + +void shutdown_listener() { + g_done.store(true); + if (g_listener_thread.joinable()) + g_listener_thread.join(); +} + +void test(SBDebugger &dbg, std::vector<string> args) { + try { + g_done.store(false); + SBTarget target = dbg.CreateTarget(args.at(0).c_str()); + if (!target.IsValid()) throw Exception("invalid target"); + + SBBreakpoint breakpoint = target.BreakpointCreateByName("next"); + if (!breakpoint.IsValid()) throw Exception("invalid breakpoint"); + + std::unique_ptr<char> working_dir(get_working_dir()); + + SBError error; + SBProcess process = target.Launch(g_listener, + 0, 0, 0, 0, 0, + working_dir.get(), + 0, + false, + error); + if (!error.Success()) + throw Exception("Error launching process."); + + /* FIXME: the approach below deadlocks + SBProcess process = target.LaunchSimple (0, 0, working_dir.get()); + + // get debugger listener (which is attached to process by default) + g_listener = dbg.GetListener(); + */ + + // FIXME: because a listener is attached to the process at launch-time, + // registering the listener below results in two listeners being attached, + // which is not supported by LLDB. + // register listener + // process.GetBroadcaster().AddListener(g_listener, + // SBProcess::eBroadcastBitStateChanged); + + // start listener thread + g_listener_thread = thread(listener_func); + check_listener(dbg); + + } catch (Exception &e) { + shutdown_listener(); + throw e; + } + shutdown_listener(); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template new file mode 100644 index 00000000000..4133025aa49 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template @@ -0,0 +1,49 @@ + +// LLDB C++ API Test: verify that the function registered with +// SBBreakpoint.SetCallback() is invoked when a breakpoint is hit. + +#include <mutex> +#include <iostream> +#include <vector> +#include <string> + +%include_SB_APIs% + +#include "common.h" + +using namespace std; +using namespace lldb; + +mutex g_mutex; +condition_variable g_condition; +int g_breakpoint_hit_count = 0; + +bool BPCallback (void *baton, + SBProcess &process, + SBThread &thread, + SBBreakpointLocation &location) { + lock_guard<mutex> lock(g_mutex); + g_breakpoint_hit_count += 1; + g_condition.notify_all(); + return true; +} + +void test(SBDebugger &dbg, vector<string> args) { + dbg.SetAsync(false); + SBTarget target = dbg.CreateTarget(args.at(0).c_str()); + if (!target.IsValid()) throw Exception("invalid target"); + + SBBreakpoint breakpoint = target.BreakpointCreateByName("next"); + if (!breakpoint.IsValid()) throw Exception("invalid breakpoint"); + breakpoint.SetCallback(BPCallback, 0); + + std::unique_ptr<char> working_dir(get_working_dir()); + SBProcess process = target.LaunchSimple (0, 0, working_dir.get()); + + { + unique_lock<mutex> lock(g_mutex); + g_condition.wait_for(lock, chrono::seconds(5)); + if (g_breakpoint_hit_count != 1) + throw Exception("Breakpoint hit count expected to be 1"); + } +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template new file mode 100644 index 00000000000..63e3f3631e5 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template @@ -0,0 +1,97 @@ + +// LLDB C++ API Test: verify the event description that is received by an +// SBListener object registered with a process with a breakpoint. + +#include <atomic> +#include <array> +#include <iostream> +#include <string> +#include <thread> + +%include_SB_APIs% + +#include "common.h" + +using namespace lldb; +using namespace std; + +// listener thread control +extern atomic<bool> g_done; +extern SBListener g_listener; + +multithreaded_queue<string> g_event_descriptions; +string g_error_desc; + +void listener_func() { + while (!g_done) { + SBEvent event; + bool got_event = g_listener.WaitForEvent(1, event); + + if (got_event) { + if (!event.IsValid()) + throw Exception("event is not valid in listener thread"); + + SBStream description; + event.GetDescription(description); + string str(description.GetData()); + g_event_descriptions.push(str); + } + } +} + +bool check_state(string &state, string &desc, bool got_description) +{ + g_error_desc.clear(); + + if(!got_description) + { + g_error_desc.append("Did not get expected event description"); + return false; + } + + if (desc.find("state-changed") == desc.npos) + g_error_desc.append("Event description incorrect: missing 'state-changed' "); + + if (desc.find("pid = ") == desc.npos) + g_error_desc.append("Event description incorrect: missing process pid "); + + string state_search_str = "state = " + state; + if (desc.find(state_search_str) == desc.npos) + { + string errString = ("Event description incorrect: expected state " + + state + + " but desc was " + + desc); + g_error_desc.append(errString); + } + + if (g_error_desc.length() > 0) + return false; + + cout << "check_state: " << state << " OK\n"; + return true; +} + +void check_listener(SBDebugger &dbg) +{ + bool got_description; + string state; + + // check for "launching" state, this may or may not be present + string desc = g_event_descriptions.pop(5, got_description); + state = "launching"; + if (check_state(state, desc, got_description)) + { + // found a 'launching' state, pop next one from queue + desc = g_event_descriptions.pop(5, got_description); + } + + state = "running"; + if( !check_state(state, desc, got_description) ) + throw Exception(g_error_desc); + + desc = g_event_descriptions.pop(5, got_description); + state = "stopped"; + if( !check_state(state, desc, got_description) ) + throw Exception(g_error_desc); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template new file mode 100644 index 00000000000..2926ece4d8d --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template @@ -0,0 +1,63 @@ + +// LLDB C++ API Test: verify the event description as obtained by calling +// SBEvent::GetCStringFromEvent that is received by an +// SBListener object registered with a process with a breakpoint. + +#include <atomic> +#include <iostream> +#include <string> +#include <thread> + +%include_SB_APIs% + +#include "common.h" + +using namespace lldb; +using namespace std; + +// listener thread control +extern atomic<bool> g_done; + +multithreaded_queue<string> g_frame_functions; + +extern SBListener g_listener; + +void listener_func() { + while (!g_done) { + SBEvent event; + bool got_event = g_listener.WaitForEvent(1, event); + if (got_event) { + if (!event.IsValid()) + throw Exception("event is not valid in listener thread"); + // send process description + SBProcess process = SBProcess::GetProcessFromEvent(event); + if (!process.IsValid()) + throw Exception("process is not valid"); + if (SBProcess::GetStateFromEvent(event) != lldb::eStateStopped || SBProcess::GetRestartedFromEvent(event)) + continue; // Only interested in "stopped" events. + + SBStream description; + + for (int i = 0; i < process.GetNumThreads(); ++i) { + // send each thread description + SBThread thread = process.GetThreadAtIndex(i); + // send each frame function name + uint32_t num_frames = thread.GetNumFrames(); + for(int j = 0; j < num_frames; ++j) { + const char* function_name = thread.GetFrameAtIndex(j).GetSymbol().GetName(); + if (function_name) + g_frame_functions.push(string(function_name)); + } + } + } + } +} + +void check_listener(SBDebugger &dbg) { + // check thread description + bool got_description = false; + string func_name = g_frame_functions.pop(5, got_description); + + if(got_description == false) + throw Exception("Expected at least one frame function"); +} diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template new file mode 100644 index 00000000000..4adc9b33887 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template @@ -0,0 +1,53 @@ + +// LLDB C++ API Test: verify the event description as obtained by calling +// SBEvent::GetCStringFromEvent that is received by an +// SBListener object registered with a process with a breakpoint. + +#include <atomic> +#include <iostream> +#include <string> +#include <thread> + +%include_SB_APIs% + +#include "common.h" + +using namespace lldb; +using namespace std; + +// listener thread control +extern atomic<bool> g_done; + +// used by listener thread to communicate a successful process continue command +// back to the checking thread. + +multithreaded_queue<bool> g_process_started; + +extern SBListener g_listener; + +void listener_func() { + while (!g_done) { + SBEvent event; + bool got_event = g_listener.WaitForEvent(1, event); + if (got_event) { + if (!event.IsValid()) + throw Exception("event is not valid in listener thread"); + + SBProcess process = SBProcess::GetProcessFromEvent(event); + if (process.GetState() == eStateStopped) { + SBError error = process.Continue(); + if (!error.Success()) + throw Exception(string("Cannot continue process from listener thread: ") + + error.GetCString()); + g_process_started.push(true); + } + } + } +} + +void check_listener(SBDebugger &dbg) { + bool got_message = false; + while (!got_message) + g_process_started.pop(5, got_message); + g_done = true; +} |