[Lldb-commits] [lldb] r280604 - [NFC] Darwin llgs support from Week of Code
Todd Fiala via lldb-commits
lldb-commits at lists.llvm.org
Sat Sep 3 17:44:42 PDT 2016
One of the new tests failed on at least one of the builders (I think
Android). I'm going to XFAIL that test and check that in momentarily.
-Todd
On Sat, Sep 3, 2016 at 5:18 PM, Todd Fiala via lldb-commits <
lldb-commits at lists.llvm.org> wrote:
> Author: tfiala
> Date: Sat Sep 3 19:18:56 2016
> New Revision: 280604
>
> URL: http://llvm.org/viewvc/llvm-project?rev=280604&view=rev
> Log:
> [NFC] Darwin llgs support from Week of Code
>
> This code represents the Week of Code work I did on bringing up
> lldb-server LLGS support for Darwin. It does not include the
> Xcode project changes needed, as we don't want to throw that switch
> until more support is implemented (i.e. this change is inert, no
> build systems use it yet. I've verified on Ubuntu 16.04, macOS
> Xcode and macOS cmake builds).
>
> This change does some minimal refactoring of code that is shared
> with the Linux LLGS portion, moving it from NativeProcessLinux into
> NativeProcessProtocol. That code is also used by NativeProcessDarwin.
>
> Current state on Darwin:
> * Process launching is implemented. (Attach is not).
> Launching on devices has not yet been tested (FBS/BKS might
> need a bit of work).
> * Inferior waitpid monitoring and communication of exit status
> via MainLoop callback is implemented.
> * Memory read/write, breakpoints, thread register context, etc.
> are not yet implemented. This impacts process stop/resume, as
> the initial launch suspended immediately starts the process
> up and running because it doesn't know it is supposed to remain
> stopped.
> * I implemented the equivalent of MachThreadList as
> NativeThreadListDarwin, in anticipation that we might want to
> factor out common parts into NativeThreadList{Protocol} and share
> some code here. After writing it, though, the fallout from merging
> Mach Task/Process into a single concept plus some other minor
> changes makes the whole NativeThreadListDarwin concept nothing more
> than dead weight. I am likely going to get rid of this class and
> just manage it directly in NativeProcessDarwin, much like I did
> for NativeProcessLinux.
> * There is a stub-out call for starting a STDIO thread. That will
> go away and adopt the MainLoop pselect-based IOObject reading.
>
> I am developing the fully-integrated changes in the following repo,
> which contains the necessary Xcode bits and the glue that enables
> lldb-debugserver on a macOS system:
>
> https://github.com/tfiala/lldb/tree/llgs-darwin
>
> This change also breaks out a few of the lldb-server tests into
> their own directory, and adds some $qHostInfo tests (not sure why
> I didn't write those tests back when I initially implemented that
> on the Linux side).
>
> Added:
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/exit-code/Makefile
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/
> TestGdbRemoteExitCode.py
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/host-info/Makefile
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/
> TestGdbRemoteHostInfo.py
> lldb/trunk/source/Plugins/Process/Darwin/
> lldb/trunk/source/Plugins/Process/Darwin/CFBundle.cpp
> lldb/trunk/source/Plugins/Process/Darwin/CFBundle.h
> lldb/trunk/source/Plugins/Process/Darwin/CFString.cpp
> lldb/trunk/source/Plugins/Process/Darwin/CFString.h
> lldb/trunk/source/Plugins/Process/Darwin/CFUtils.h
> lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
> lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
> lldb/trunk/source/Plugins/Process/Darwin/LaunchFlavor.h
> lldb/trunk/source/Plugins/Process/Darwin/MachException.cpp
> lldb/trunk/source/Plugins/Process/Darwin/MachException.h
> lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
> lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.h
> lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
> lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.h
> lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
> lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
> lldb/trunk/tools/lldb-server/Darwin/
> lldb/trunk/tools/lldb-server/Darwin/resources/
> lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-Info.plist
> lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-
> entitlements.plist
> lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-
> macos-entitlements.plist
> lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
> Modified:
> lldb/trunk/include/lldb/Host/Debug.h
> lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
> lldb/trunk/include/lldb/lldb-private-forward.h
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/
> TestGdbRemoteProcessInfo.py
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/TestLldbGdbServer.py
> lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/gdbremote_testcase.py
> lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
> lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
> lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerCommon.cpp
> lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerLLGS.cpp
> lldb/trunk/source/Target/UnixSignals.cpp
>
> Modified: lldb/trunk/include/lldb/Host/Debug.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/
> lldb/Host/Debug.h?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/include/lldb/Host/Debug.h (original)
> +++ lldb/trunk/include/lldb/Host/Debug.h Sat Sep 3 19:18:56 2016
> @@ -201,7 +201,7 @@ namespace lldb_private {
> {
> uint64_t type;
> uint32_t data_count;
> - lldb::addr_t data[2];
> + lldb::addr_t data[8];
> } exception;
> } details;
> };
>
> Modified: lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/
> lldb/Host/common/NativeProcessProtocol.h?rev=280604&r1=280603&r2=280604&
> view=diff
> ============================================================
> ==================
> --- lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h (original)
> +++ lldb/trunk/include/lldb/Host/common/NativeProcessProtocol.h Sat Sep
> 3 19:18:56 2016
> @@ -37,12 +37,6 @@ namespace lldb_private
>
> public:
>
> - // lldb_private::Host calls should be used to launch a process
> for debugging, and
> - // then the process should be attached to. When attaching to a
> process
> - // lldb_private::Host calls should be used to locate the process
> to attach to,
> - // and then this function should be called.
> - NativeProcessProtocol (lldb::pid_t pid);
> -
> virtual ~NativeProcessProtocol ()
> {
> }
> @@ -379,6 +373,12 @@ namespace lldb_private
> int m_terminal_fd;
> uint32_t m_stop_id;
>
> + // lldb_private::Host calls should be used to launch a process
> for debugging, and
> + // then the process should be attached to. When attaching to a
> process
> + // lldb_private::Host calls should be used to locate the process
> to attach to,
> + // and then this function should be called.
> + NativeProcessProtocol (lldb::pid_t pid);
> +
> // -----------------------------------------------------------
> // Internal interface for state handling
> // -----------------------------------------------------------
> @@ -415,6 +415,12 @@ namespace lldb_private
> NativeThreadProtocolSP
> GetThreadByIDUnlocked (lldb::tid_t tid);
>
> + // -----------------------------------------------------------
> + // Static helper methods for derived classes.
> + // -----------------------------------------------------------
> + static Error
> + ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch);
> +
> private:
>
> void
>
> Modified: lldb/trunk/include/lldb/lldb-private-forward.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/
> lldb/lldb-private-forward.h?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/include/lldb/lldb-private-forward.h (original)
> +++ lldb/trunk/include/lldb/lldb-private-forward.h Sat Sep 3 19:18:56
> 2016
> @@ -24,6 +24,7 @@ namespace lldb_private
> class NativeProcessProtocol;
> class NativeRegisterContext;
> class NativeThreadProtocol;
> + class ResumeActionList;
> class UnixSignals;
>
> // ---------------------------------------------------------------
>
> Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/
> TestGdbRemoteProcessInfo.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py?
> rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py
> (original)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py
> Sat Sep 3 19:18:56 2016
> @@ -155,6 +155,13 @@ class TestGdbRemoteProcessInfo(gdbremote
> self.build()
> self.qProcessInfo_contains_keys(set(['cputype', 'cpusubtype']))
>
> + @skipUnlessDarwin
> + @llgs_test
> + def test_qProcessInfo_contains_cputype_cpusubtype_llgs_darwin(self):
> + self.init_llgs_test()
> + self.build()
> + self.qProcessInfo_contains_keys(set(['cputype', 'cpusubtype']))
> +
> @skipUnlessPlatform(["linux"])
> @llgs_test
> def test_qProcessInfo_contains_triple_llgs_linux(self):
> @@ -169,6 +176,16 @@ class TestGdbRemoteProcessInfo(gdbremote
> self.build()
> # We don't expect to see triple on darwin. If we do, we'll
> prefer triple
> # to cputype/cpusubtype and skip some darwin-based
> ProcessGDBRemote ArchSpec setup
> + # for the remote Host and Process.
> + self.qProcessInfo_does_not_contain_keys(set(['triple']))
> +
> + @skipUnlessDarwin
> + @llgs_test
> + def test_qProcessInfo_does_not_contain_triple_llgs_darwin(self):
> + self.init_llgs_test()
> + self.build()
> + # We don't expect to see triple on darwin. If we do, we'll
> prefer triple
> + # to cputype/cpusubtype and skip some darwin-based
> ProcessGDBRemote ArchSpec setup
> # for the remote Host and Process.
> self.qProcessInfo_does_not_contain_keys(set(['triple']))
>
>
> Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/TestLldbGdbServer.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.
> py?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
> (original)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py
> Sat Sep 3 19:18:56 2016
> @@ -97,101 +97,6 @@ class LldbGdbServerTestCase(gdbremote_te
> self.init_llgs_test()
> self.list_threads_in_stop_reply_supported()
>
> - def install_and_create_launch_args(self):
> - exe_path = os.path.abspath('a.out')
> - if not lldb.remote_platform:
> - return [exe_path]
> - remote_path = lldbutil.append_to_process_
> working_directory(os.path.basename(exe_path))
> - remote_file_spec = lldb.SBFileSpec(remote_path, False)
> - err = lldb.remote_platform.Install(lldb.SBFileSpec(exe_path,
> True), remote_file_spec)
> - if err.Fail():
> - raise Exception("remote_platform.Install('%s', '%s') failed:
> %s" % (exe_path, remote_path, err))
> - return [remote_path]
> -
> - def start_inferior(self):
> - launch_args = self.install_and_create_launch_args()
> -
> - server = self.connect_to_debug_monitor()
> - self.assertIsNotNone(server)
> -
> - self.add_no_ack_remote_stream()
> - self.test_sequence.add_log_lines(
> - ["read packet: %s" % lldbgdbserverutils.build_
> gdbremote_A_packet(launch_args),
> - "send packet: $OK#9a"],
> - True)
> - self.expect_gdbremote_sequence()
> -
> - @debugserver_test
> - def test_start_inferior_debugserver(self):
> - self.init_debugserver_test()
> - self.build()
> - self.start_inferior()
> -
> - @llgs_test
> - def test_start_inferior_llgs(self):
> - self.init_llgs_test()
> - self.build()
> - self.start_inferior()
> -
> - def inferior_exit_0(self):
> - launch_args = self.install_and_create_launch_args()
> -
> - server = self.connect_to_debug_monitor()
> - self.assertIsNotNone(server)
> -
> - self.add_no_ack_remote_stream()
> - self.add_verified_launch_packets(launch_args)
> - self.test_sequence.add_log_lines(
> - ["read packet: $vCont;c#a8",
> - "send packet: $W00#00"],
> - True)
> -
> - self.expect_gdbremote_sequence()
> -
> - @debugserver_test
> - def test_inferior_exit_0_debugserver(self):
> - self.init_debugserver_test()
> - self.build()
> - self.inferior_exit_0()
> -
> - @llgs_test
> - def test_inferior_exit_0_llgs(self):
> - self.init_llgs_test()
> - self.build()
> - self.inferior_exit_0()
> -
> - def inferior_exit_42(self):
> - launch_args = self.install_and_create_launch_args()
> -
> - server = self.connect_to_debug_monitor()
> - self.assertIsNotNone(server)
> -
> - RETVAL = 42
> -
> - # build launch args
> - launch_args += ["retval:%d" % RETVAL]
> -
> - self.add_no_ack_remote_stream()
> - self.add_verified_launch_packets(launch_args)
> - self.test_sequence.add_log_lines(
> - ["read packet: $vCont;c#a8",
> - "send packet: $W{0:02x}#00".format(RETVAL)],
> - True)
> -
> - self.expect_gdbremote_sequence()
> -
> - @debugserver_test
> - def test_inferior_exit_42_debugserver(self):
> - self.init_debugserver_test()
> - self.build()
> - self.inferior_exit_42()
> -
> - @llgs_test
> - def test_inferior_exit_42_llgs(self):
> - self.init_llgs_test()
> - self.build()
> - self.inferior_exit_42()
> -
> def c_packet_works(self):
> launch_args = self.install_and_create_launch_args()
>
>
> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/exit-code/Makefile
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/exit-code/
> Makefile?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile
> (added)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,10 @@
> +LEVEL = ../../../make
> +
> +VPATH = ..
> +
> +override CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
> +ENABLE_THREADS := YES
> +CXX_SOURCES := main.cpp
> +MAKE_DSYM :=NO
> +
> +include $(LEVEL)/Makefile.rules
>
> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/exit-code/TestGdbRemoteExitCode.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/exit-code/
> TestGdbRemoteExitCode.py?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py
> (added)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,124 @@
> +from __future__ import print_function
> +
> +# lldb test suite imports
> +from lldbsuite.test.decorators import *
> +from lldbsuite.test.lldbtest import TestBase
> +
> +# gdb-remote-specific imports
> +import lldbgdbserverutils
> +from gdbremote_testcase import GdbRemoteTestCaseBase
> +
> +
> +class TestGdbRemoteExitCode(GdbRemoteTestCaseBase):
> +
> + mydir = TestBase.compute_mydir(__file__)
> +
> + FAILED_LAUNCH_CODE = "E08"
> +
> + def get_launch_fail_reason(self):
> + self.reset_test_sequence()
> + self.test_sequence.add_log_lines(
> + ["read packet: $qLaunchSuccess#00"],
> + True)
> + self.test_sequence.add_log_lines(
> + [{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
> + "capture": {1: "launch_result"}}],
> + True)
> + context = self.expect_gdbremote_sequence()
> + self.assertIsNotNone(context)
> + return context.get("launch_result")[1:]
> +
> + def start_inferior(self):
> + launch_args = self.install_and_create_launch_args()
> +
> + server = self.connect_to_debug_monitor()
> + self.assertIsNotNone(server)
> +
> + self.add_no_ack_remote_stream()
> + self.test_sequence.add_log_lines(
> + ["read packet: %s" % lldbgdbserverutils.build_
> gdbremote_A_packet(
> + launch_args)],
> + True)
> + self.test_sequence.add_log_lines(
> + [{"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
> + "capture": {1: "A_result"}}],
> + True)
> + context = self.expect_gdbremote_sequence()
> + self.assertIsNotNone(context)
> +
> + launch_result = context.get("A_result")
> + self.assertIsNotNone(launch_result)
> + if launch_result == self.FAILED_LAUNCH_CODE:
> + fail_reason = self.get_launch_fail_reason()
> + self.fail("failed to launch inferior: " + fail_reason)
> +
> + @debugserver_test
> + def test_start_inferior_debugserver(self):
> + self.init_debugserver_test()
> + self.build()
> + self.start_inferior()
> +
> + @llgs_test
> + def test_start_inferior_llgs(self):
> + self.init_llgs_test()
> + self.build()
> + self.start_inferior()
> +
> + def inferior_exit_0(self):
> + launch_args = self.install_and_create_launch_args()
> +
> + server = self.connect_to_debug_monitor()
> + self.assertIsNotNone(server)
> +
> + self.add_no_ack_remote_stream()
> + self.add_verified_launch_packets(launch_args)
> + self.test_sequence.add_log_lines(
> + ["read packet: $vCont;c#a8",
> + "send packet: $W00#00"],
> + True)
> +
> + self.expect_gdbremote_sequence()
> +
> + @debugserver_test
> + def test_inferior_exit_0_debugserver(self):
> + self.init_debugserver_test()
> + self.build()
> + self.inferior_exit_0()
> +
> + @llgs_test
> + def test_inferior_exit_0_llgs(self):
> + self.init_llgs_test()
> + self.build()
> + self.inferior_exit_0()
> +
> + def inferior_exit_42(self):
> + launch_args = self.install_and_create_launch_args()
> +
> + server = self.connect_to_debug_monitor()
> + self.assertIsNotNone(server)
> +
> + RETVAL = 42
> +
> + # build launch args
> + launch_args += ["retval:%d" % RETVAL]
> +
> + self.add_no_ack_remote_stream()
> + self.add_verified_launch_packets(launch_args)
> + self.test_sequence.add_log_lines(
> + ["read packet: $vCont;c#a8",
> + "send packet: $W{0:02x}#00".format(RETVAL)],
> + True)
> +
> + self.expect_gdbremote_sequence()
> +
> + @debugserver_test
> + def test_inferior_exit_42_debugserver(self):
> + self.init_debugserver_test()
> + self.build()
> + self.inferior_exit_42()
> +
> + @llgs_test
> + def test_inferior_exit_42_llgs(self):
> + self.init_llgs_test()
> + self.build()
> + self.inferior_exit_42()
>
> Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/gdbremote_testcase.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/gdbremote_
> testcase.py?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
> (original)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
> Sat Sep 3 19:18:56 2016
> @@ -133,7 +133,7 @@ class GdbRemoteTestCaseBase(TestBase):
> self.debug_monitor_extra_args.append("--log-file=" +
> log_file)
> self.debug_monitor_extra_args.append("--log-channels={}".
> format(":".join(lldbtest_config.channels)))
> else:
> - self.debug_monitor_extra_args = ["--log-file=" +
> self.log_file, "--log-flags=0x800000"]
> + self.debug_monitor_extra_args = ["--log-file=" + log_file,
> "--log-flags=0x800000"]
>
> def get_next_port(self):
> return 12000 + random.randint(0,3999)
> @@ -1370,3 +1370,16 @@ class GdbRemoteTestCaseBase(TestBase):
> def maybe_strict_output_regex(self, regex):
> return '.*'+regex+'.*' if lldbplatformutil.hasChattyStderr(self)
> else '^'+regex+'$'
>
> + def install_and_create_launch_args(self):
> + exe_path = os.path.abspath('a.out')
> + if not lldb.remote_platform:
> + return [exe_path]
> + remote_path = lldbutil.append_to_process_working_directory(
> + os.path.basename(exe_path))
> + remote_file_spec = lldb.SBFileSpec(remote_path, False)
> + err = lldb.remote_platform.Install(lldb.SBFileSpec(exe_path,
> True),
> + remote_file_spec)
> + if err.Fail():
> + raise Exception("remote_platform.Install('%s', '%s') failed:
> %s" %
> + (exe_path, remote_path, err))
> + return [remote_path]
>
> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/host-info/Makefile
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/host-info/
> Makefile?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/Makefile
> (added)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/Makefile
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,10 @@
> +LEVEL = ../../../make
> +
> +VPATH = ..
> +
> +override CFLAGS_EXTRAS += -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS
> +ENABLE_THREADS := YES
> +CXX_SOURCES := main.cpp
> +MAKE_DSYM :=NO
> +
> +include $(LEVEL)/Makefile.rules
>
> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-
> server/host-info/TestGdbRemoteHostInfo.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/
> Python/lldbsuite/test/tools/lldb-server/host-info/
> TestGdbRemoteHostInfo.py?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/TestGdbRemoteHostInfo.py
> (added)
> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/host-info/TestGdbRemoteHostInfo.py
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,125 @@
> +from __future__ import print_function
> +
> +# lldb test suite imports
> +from lldbsuite.test.decorators import *
> +from lldbsuite.test.lldbtest import TestBase
> +
> +# gdb-remote-specific imports
> +import lldbgdbserverutils
> +from gdbremote_testcase import GdbRemoteTestCaseBase
> +
> +
> +class TestGdbRemoteHostInfo(GdbRemoteTestCaseBase):
> +
> + mydir = TestBase.compute_mydir(__file__)
> +
> + KNOWN_HOST_INFO_KEYS = set([
> + "cputype",
> + "cpusubtype",
> + "distribution_id",
> + "endian",
> + "hostname",
> + "ostype",
> + "os_build",
> + "os_kernel",
> + "os_version",
> + "ptrsize",
> + "triple",
> + "vendor",
> + "watchpoint_exceptions_received"
> + ])
> +
> + DARWIN_REQUIRED_HOST_INFO_KEYS = set([
> + "cputype",
> + "cpusubtype",
> + "endian",
> + "ostype",
> + "ptrsize",
> + "vendor",
> + "watchpoint_exceptions_received"
> + ])
> +
> + def add_host_info_collection_packets(self):
> + self.test_sequence.add_log_lines(
> + ["read packet: $qHostInfo#9b",
> + {"direction": "send", "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",
> + "capture": {1: "host_info_raw"}}],
> + True)
> +
> + def parse_host_info_response(self, context):
> + # Ensure we have a host info response.
> + self.assertIsNotNone(context)
> + host_info_raw = context.get("host_info_raw")
> + self.assertIsNotNone(host_info_raw)
> +
> + # Pull out key:value; pairs.
> + host_info_dict = {match.group(1): match.group(2)
> + for match in re.finditer(r"([^:]+):([^;]+);",
> + host_info_raw)}
> +
> + import pprint
> + print("\nqHostInfo response:")
> + pprint.pprint(host_info_dict)
> +
> + # Validate keys are known.
> + for (key, val) in list(host_info_dict.items()):
> + self.assertTrue(key in self.KNOWN_HOST_INFO_KEYS,
> + "unknown qHostInfo key: " + key)
> + self.assertIsNotNone(val)
> +
> + # Return the key:val pairs.
> + return host_info_dict
> +
> + def get_qHostInfo_response(self):
> + # Launch the debug monitor stub, attaching to the inferior.
> + server = self.connect_to_debug_monitor()
> + self.assertIsNotNone(server)
> + self.add_no_ack_remote_stream()
> +
> + # Request qHostInfo and get response
> + self.add_host_info_collection_packets()
> + context = self.expect_gdbremote_sequence()
> + self.assertIsNotNone(context)
> +
> + # Parse qHostInfo response.
> + host_info = self.parse_host_info_response(context)
> + self.assertIsNotNone(host_info)
> + self.assertGreater(len(host_info), 0, "qHostInfo should have
> returned "
> + "at least one key:val pair.")
> + return host_info
> +
> + def validate_darwin_minimum_host_info_keys(self, host_info_dict):
> + self.assertIsNotNone(host_info_dict)
> + missing_keys = [key for key in self.DARWIN_REQUIRED_HOST_
> INFO_KEYS
> + if key not in host_info_dict]
> + self.assertEquals(0, len(missing_keys),
> + "qHostInfo is missing the following required "
> + "keys: " + str(missing_keys))
> +
> + @debugserver_test
> + def test_qHostInfo_returns_at_least_one_key_val_pair_
> debugserver(self):
> + self.init_debugserver_test()
> + self.build()
> + self.get_qHostInfo_response()
> +
> + @llgs_test
> + def test_qHostInfo_returns_at_least_one_key_val_pair_llgs(self):
> + self.init_llgs_test()
> + self.build()
> + self.get_qHostInfo_response()
> +
> + @skipUnlessDarwin
> + @debugserver_test
> + def test_qHostInfo_contains_darwin_required_keys_debugserver(self):
> + self.init_debugserver_test()
> + self.build()
> + host_info_dict = self.get_qHostInfo_response()
> + self.validate_darwin_minimum_host_info_keys(host_info_dict)
> +
> + @skipUnlessDarwin
> + @llgs_test
> + def test_qHostInfo_contains_darwin_required_keys_llgs(self):
> + self.init_llgs_test()
> + self.build()
> + host_info_dict = self.get_qHostInfo_response()
> + self.validate_darwin_minimum_host_info_keys(host_info_dict)
>
> Modified: lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/
> NativeProcessProtocol.cpp?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/source/Host/common/NativeProcessProtocol.cpp (original)
> +++ lldb/trunk/source/Host/common/NativeProcessProtocol.cpp Sat Sep 3
> 19:18:56 2016
> @@ -12,12 +12,15 @@
> #include "lldb/lldb-enumerations.h"
> #include "lldb/Core/ArchSpec.h"
> #include "lldb/Core/Log.h"
> +#include "lldb/Core/ModuleSpec.h"
> #include "lldb/Core/State.h"
> #include "lldb/Host/Host.h"
> #include "lldb/Host/common/NativeRegisterContext.h"
> -
> #include "lldb/Host/common/NativeThreadProtocol.h"
> #include "lldb/Host/common/SoftwareBreakpoint.h"
> +#include "lldb/Symbol/ObjectFile.h"
> +#include "lldb/Target/Process.h"
> +#include "lldb/Utility/LLDBAssert.h"
>
> using namespace lldb;
> using namespace lldb_private;
> @@ -436,6 +439,29 @@ NativeProcessProtocol::DoStopIDBumped (u
> // Default implementation does nothing.
> }
>
> +Error
> +NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
> + ArchSpec &arch)
> +{
> + // Grab process info for the running process.
> + ProcessInstanceInfo process_info;
> + if (!Host::GetProcessInfo(pid, process_info))
> + return Error("failed to get process info");
> +
> + // Resolve the executable module.
> + ModuleSpecList module_specs;
> + if (!ObjectFile::GetModuleSpecifications(process_info.
> GetExecutableFile(),
> + 0, 0, module_specs))
> + return Error("failed to get module specifications");
> + lldbassert(module_specs.GetSize() == 1);
> +
> + arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture();
> + if (arch.IsValid())
> + return Error();
> + else
> + return Error("failed to retrieve a valid architecture from the
> exe module");
> +}
> +
> #ifndef __linux__
> // These need to be implemented to support lldb-gdb-server on a given
> platform. Stubs are
> // provided to make the rest of the code link on non-supported platforms.
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/CFBundle.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/CFBundle.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/CFBundle.cpp (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/CFBundle.cpp Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,97 @@
> +//===-- CFBundle.cpp --------------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 1/16/08.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "CFBundle.h"
> +#include "CFString.h"
> +
> +//----------------------------------------------------------------------
> +// CFBundle constructor
> +//----------------------------------------------------------------------
> +CFBundle::CFBundle(const char *path) :
> + CFReleaser<CFBundleRef>(),
> + m_bundle_url()
> +{
> + if (path && path[0])
> + SetPath(path);
> +}
> +
> +//----------------------------------------------------------------------
> +// CFBundle copy constructor
> +//----------------------------------------------------------------------
> +CFBundle::CFBundle(const CFBundle& rhs) :
> + CFReleaser<CFBundleRef>(rhs),
> + m_bundle_url(rhs.m_bundle_url)
> +{
> +
> +}
> +
> +//----------------------------------------------------------------------
> +// CFBundle copy constructor
> +//----------------------------------------------------------------------
> +CFBundle&
> +CFBundle::operator=(const CFBundle& rhs)
> +{
> + *this = rhs;
> + return *this;
> +}
> +
> +//----------------------------------------------------------------------
> +// Destructor
> +//----------------------------------------------------------------------
> +CFBundle::~CFBundle()
> +{
> +}
> +
> +//----------------------------------------------------------------------
> +// Set the path for a bundle by supplying a
> +//----------------------------------------------------------------------
> +bool
> +CFBundle::SetPath (const char *path)
> +{
> + CFAllocatorRef alloc = kCFAllocatorDefault;
> + // Release our old bundle and ULR
> + reset(); // This class is a CFReleaser<CFBundleRef>
> + m_bundle_url.reset();
> + // Make a CFStringRef from the supplied path
> + CFString cf_path;
> + cf_path.SetFileSystemRepresentation(path);
> + if (cf_path.get())
> + {
> + // Make our Bundle URL
> + m_bundle_url.reset (::CFURLCreateWithFileSystemPath (alloc,
> cf_path.get(), kCFURLPOSIXPathStyle, true));
> + if (m_bundle_url.get())
> + {
> + reset (::CFBundleCreate (alloc, m_bundle_url.get()));
> + }
> + }
> + return get() != NULL;
> +}
> +
> +CFStringRef
> +CFBundle::GetIdentifier () const
> +{
> + CFBundleRef bundle = get();
> + if (bundle != NULL)
> + return ::CFBundleGetIdentifier (bundle);
> + return NULL;
> +}
> +
> +
> +CFURLRef
> +CFBundle::CopyExecutableURL () const
> +{
> + CFBundleRef bundle = get();
> + if (bundle != NULL)
> + return CFBundleCopyExecutableURL(bundle);
> + return NULL;
> +}
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/CFBundle.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/CFBundle.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/CFBundle.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/CFBundle.h Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,43 @@
> +//===-- CFBundle.h ----------------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 1/16/08.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef __CFBundle_h__
> +#define __CFBundle_h__
> +
> +#include "CFUtils.h"
> +
> +class CFBundle : public CFReleaser<CFBundleRef>
> +{
> +public:
> + //------------------------------------------------------------------
> + // Constructors and Destructors
> + //------------------------------------------------------------------
> + CFBundle(const char *path = NULL);
> + CFBundle(const CFBundle& rhs);
> + CFBundle& operator=(const CFBundle& rhs);
> + virtual
> + ~CFBundle();
> + bool
> + SetPath (const char *path);
> +
> + CFStringRef
> + GetIdentifier () const;
> +
> + CFURLRef
> + CopyExecutableURL () const;
> +
> +protected:
> + CFReleaser<CFURLRef> m_bundle_url;
> +};
> +
> +#endif // #ifndef __CFBundle_h__
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/CFString.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/CFString.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/CFString.cpp (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/CFString.cpp Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,201 @@
> +//===-- CFString.cpp --------------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 1/16/08.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "CFString.h"
> +#include <string>
> +#include <glob.h>
> +
> +//----------------------------------------------------------------------
> +// CFString constructor
> +//----------------------------------------------------------------------
> +CFString::CFString(CFStringRef s) :
> + CFReleaser<CFStringRef> (s)
> +{
> +}
> +
> +//----------------------------------------------------------------------
> +// CFString copy constructor
> +//----------------------------------------------------------------------
> +CFString::CFString(const CFString& rhs) :
> + CFReleaser<CFStringRef> (rhs)
> +{
> +
> +}
> +
> +//----------------------------------------------------------------------
> +// CFString copy constructor
> +//----------------------------------------------------------------------
> +CFString&
> +CFString::operator=(const CFString& rhs)
> +{
> + if (this != &rhs)
> + *this = rhs;
> + return *this;
> +}
> +
> +CFString::CFString (const char *cstr, CFStringEncoding cstr_encoding) :
> + CFReleaser<CFStringRef> ()
> +{
> + if (cstr && cstr[0])
> + {
> + reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr,
> cstr_encoding));
> + }
> +}
> +
> +//----------------------------------------------------------------------
> +// Destructor
> +//----------------------------------------------------------------------
> +CFString::~CFString()
> +{
> +}
> +
> +const char *
> +CFString::GetFileSystemRepresentation(std::string& s)
> +{
> + return CFString::FileSystemRepresentation(get(), s);
> +}
> +
> +CFStringRef
> +CFString::SetFileSystemRepresentation (const char *path)
> +{
> + CFStringRef new_value = NULL;
> + if (path && path[0])
> + new_value = ::CFStringCreateWithFileSystemRepresentation
> (kCFAllocatorDefault, path);
> + reset(new_value);
> + return get();
> +}
> +
> +
> +CFStringRef
> +CFString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
> +{
> + CFStringRef new_value = NULL;
> + if (cf_type != NULL)
> + {
> + CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
> +
> + if (cf_type_id == ::CFStringGetTypeID())
> + {
> + // Retain since we are using the existing object
> + new_value = (CFStringRef)::CFRetain(cf_type);
> + }
> + else if (cf_type_id == ::CFURLGetTypeID())
> + {
> + new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type,
> kCFURLPOSIXPathStyle);
> + }
> + }
> + reset(new_value);
> + return get();
> +}
> +
> +CFStringRef
> +CFString::SetFileSystemRepresentationAndExpandTilde (const char *path)
> +{
> + std::string expanded_path;
> + if (CFString::GlobPath(path, expanded_path))
> + SetFileSystemRepresentation(expanded_path.c_str());
> + else
> + reset();
> + return get();
> +}
> +
> +const char *
> +CFString::UTF8(std::string& str)
> +{
> + return CFString::UTF8(get(), str);
> +}
> +
> +// Static function that puts a copy of the UTF8 contents of CF_STR into
> STR
> +// and returns the C string pointer that is contained in STR when
> successful, else
> +// NULL is returned. This allows the std::string parameter to own the
> extracted string,
> +// and also allows that string to be returned as a C string pointer that
> can be used.
> +
> +const char *
> +CFString::UTF8 (CFStringRef cf_str, std::string& str)
> +{
> + if (cf_str)
> + {
> + const CFStringEncoding encoding = kCFStringEncodingUTF8;
> + CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
> + max_utf8_str_len = CFStringGetMaximumSizeForEncoding
> (max_utf8_str_len, encoding);
> + if (max_utf8_str_len > 0)
> + {
> + str.resize(max_utf8_str_len);
> + if (!str.empty())
> + {
> + if (CFStringGetCString (cf_str, &str[0], str.size(),
> encoding))
> + {
> + str.resize(strlen(str.c_str()));
> + return str.c_str();
> + }
> + }
> + }
> + }
> + return NULL;
> +}
> +
> +// Static function that puts a copy of the file system representation of
> CF_STR
> +// into STR and returns the C string pointer that is contained in STR when
> +// successful, else NULL is returned. This allows the std::string
> parameter
> +// to own the extracted string, and also allows that string to be
> returned as
> +// a C string pointer that can be used.
> +
> +const char *
> +CFString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
> +{
> + if (cf_str)
> + {
> + CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation
> (cf_str);
> + if (max_length > 0)
> + {
> + str.resize(max_length);
> + if (!str.empty())
> + {
> + if (::CFStringGetFileSystemRepresentation (cf_str,
> &str[0], str.size()))
> + {
> + str.erase(::strlen(str.c_str()));
> + return str.c_str();
> + }
> + }
> + }
> + }
> + str.erase();
> + return NULL;
> +}
> +
> +
> +CFIndex
> +CFString::GetLength() const
> +{
> + CFStringRef str = get();
> + if (str)
> + return CFStringGetLength (str);
> + return 0;
> +}
> +
> +
> +const char*
> +CFString::GlobPath(const char* path, std::string &expanded_path)
> +{
> + glob_t globbuf;
> + if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
> + {
> + expanded_path = globbuf.gl_pathv[0];
> + ::globfree (&globbuf);
> + }
> + else
> + expanded_path.clear();
> +
> + return expanded_path.c_str();
> +}
> +
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/CFString.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/CFString.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/CFString.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/CFString.h Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,43 @@
> +//===-- CFString.h ----------------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 1/16/08.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef __CFString_h__
> +#define __CFString_h__
> +
> +#include "CFUtils.h"
> +#include <iosfwd>
> +
> +class CFString : public CFReleaser<CFStringRef>
> +{
> +public:
> + //------------------------------------------------------------------
> + // Constructors and Destructors
> + //------------------------------------------------------------------
> + CFString (CFStringRef cf_str = NULL);
> + CFString (const char *s, CFStringEncoding
> encoding = kCFStringEncodingUTF8);
> + CFString (const CFString& rhs);
> + CFString& operator= (const CFString& rhs);
> + virtual ~CFString ();
> +
> + const char * GetFileSystemRepresentation (std::string& str);
> + CFStringRef SetFileSystemRepresentation (const char *path);
> + CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef
> cf_type);
> + CFStringRef SetFileSystemRepresentationAndExpandTilde (const
> char *path);
> + const char * UTF8 (std::string& str);
> + CFIndex GetLength() const;
> + static const char *UTF8 (CFStringRef cf_str, std::string& str);
> + static const char *FileSystemRepresentation (CFStringRef cf_str,
> std::string& str);
> + static const char* GlobPath(const char* path, std::string
> &expanded_path);
> +};
> +
> +#endif // #ifndef __CFString_h__
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/CFUtils.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/CFUtils.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/CFUtils.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/CFUtils.h Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,81 @@
> +//===-- CFUtils.h -----------------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 3/5/07.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef __CFUtils_h__
> +#define __CFUtils_h__
> +
> +#include <CoreFoundation/CoreFoundation.h>
> +
> +#ifdef __cplusplus
> +
> +//----------------------------------------------------------------------
> +// Templatized CF helper class that can own any CF pointer and will
> +// call CFRelease() on any valid pointer it owns unless that pointer is
> +// explicitly released using the release() member function.
> +//----------------------------------------------------------------------
> +template <class T>
> +class CFReleaser
> +{
> +public:
> + // Type names for the avlue
> + typedef T element_type;
> +
> + // Constructors and destructors
> + CFReleaser(T ptr = NULL) : _ptr(ptr) { }
> + CFReleaser(const CFReleaser& copy) : _ptr(copy.get())
> + {
> + if (get())
> + ::CFRetain(get());
> + }
> + virtual ~CFReleaser() { reset(); }
> +
> + // Assignments
> + CFReleaser& operator= (const CFReleaser<T>& copy)
> + {
> + if (copy != *this)
> + {
> + // Replace our owned pointer with the new one
> + reset(copy.get());
> + // Retain the current pointer that we own
> + if (get())
> + ::CFRetain(get());
> + }
> + }
> + // Get the address of the contained type
> + T * ptr_address() { return &_ptr; }
> +
> + // Access the pointer itself
> + const T get() const { return _ptr; }
> + T get() { return _ptr; }
> +
> + // Set a new value for the pointer and CFRelease our old
> + // value if we had a valid one.
> + void reset(T ptr = NULL)
> + {
> + if (ptr != _ptr)
> + {
> + if (_ptr != NULL)
> + ::CFRelease(_ptr);
> + _ptr = ptr;
> + }
> + }
> +
> + // Release ownership without calling CFRelease
> + T release() { T tmp = _ptr; _ptr = NULL; return tmp; }
> +private:
> + element_type _ptr;
> +};
> +
> +#endif // #ifdef __cplusplus
> +#endif // #ifndef __CFUtils_h__
> +
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/DarwinProcessLauncher.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,737 @@
> +//
> +// DarwinProcessLauncher.cpp
> +// lldb
> +//
> +// Created by Todd Fiala on 8/30/16.
> +//
> +//
> +
> +#include "DarwinProcessLauncher.h"
> +
> +// C includes
> +#include <spawn.h>
> +#include <sys/ptrace.h>
> +#include <sys/stat.h>
> +#include <sys/sysctl.h>
> +
> +#ifndef _POSIX_SPAWN_DISABLE_ASLR
> +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
> +#endif
> +
> +// LLDB includes
> +#include "lldb/lldb-enumerations.h"
> +
> +#include "lldb/Core/Error.h"
> +#include "lldb/Core/Log.h"
> +#include "lldb/Core/StreamString.h"
> +#include "lldb/Target/ProcessLaunchInfo.h"
> +#include "lldb/Utility/PseudoTerminal.h"
> +
> +#include "CFBundle.h"
> +#include "CFString.h"
> +
> +using namespace lldb;
> +using namespace lldb_private;
> +using namespace lldb_private::process_darwin;
> +using namespace lldb_private::darwin_process_launcher;
> +
> +namespace
> +{
> + static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
> +}
> +
> +namespace lldb_private
> +{
> +namespace darwin_process_launcher
> +{
> +
> +static uint32_t
> +GetCPUTypeForLocalProcess(::pid_t pid)
> +{
> + int mib[CTL_MAXNAME]={0,};
> + size_t len = CTL_MAXNAME;
> + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
> + return 0;
> +
> + mib[len] = pid;
> + len++;
> +
> + cpu_type_t cpu;
> + size_t cpu_len = sizeof(cpu);
> + if (::sysctl (mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
> + cpu = 0;
> + return cpu;
> +}
> +
> +static bool
> +ResolveExecutablePath(const char *path, char *resolved_path,
> + size_t resolved_path_size)
> +{
> + if (path == NULL || path[0] == '\0')
> + return false;
> +
> + char max_path[PATH_MAX];
> + std::string result;
> + CFString::GlobPath(path, result);
> +
> + if (result.empty())
> + result = path;
> +
> + struct stat path_stat;
> + if (::stat(path, &path_stat) == 0)
> + {
> + if ((path_stat.st_mode & S_IFMT) == S_IFDIR)
> + {
> + CFBundle bundle(path);
> + CFReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
> + if (url.get())
> + {
> + if (::CFURLGetFileSystemRepresentation(url.get(), true,
> +
> (UInt8*)resolved_path,
> +
> resolved_path_size))
> + return true;
> + }
> + }
> + }
> +
> + if (realpath(path, max_path))
> + {
> + // Found the path relatively...
> + ::strncpy(resolved_path, max_path, resolved_path_size);
> + return strlen(resolved_path) + 1 < resolved_path_size;
> + }
> + else
> + {
> + // Not a relative path, check the PATH environment variable if the
> + const char *PATH = getenv("PATH");
> + if (PATH)
> + {
> + const char *curr_path_start = PATH;
> + const char *curr_path_end;
> + while (curr_path_start && *curr_path_start)
> + {
> + curr_path_end = strchr(curr_path_start, ':');
> + if (curr_path_end == NULL)
> + {
> + result.assign(curr_path_start);
> + curr_path_start = NULL;
> + }
> + else if (curr_path_end > curr_path_start)
> + {
> + size_t len = curr_path_end - curr_path_start;
> + result.assign(curr_path_start, len);
> + curr_path_start += len + 1;
> + }
> + else
> + break;
> +
> + result += '/';
> + result += path;
> + struct stat s;
> + if (stat(result.c_str(), &s) == 0)
> + {
> + ::strncpy(resolved_path, result.c_str(),
> + resolved_path_size);
> + return result.size() + 1 < resolved_path_size;
> + }
> + }
> + }
> + }
> + return false;
> +}
> +
> +// TODO check if we have a general purpose fork and exec. We may be
> +// able to get rid of this entirely.
> +static Error
> +ForkChildForPTraceDebugging(const char *path,
> + char const *argv[],
> + char const *envp[],
> + ::pid_t *pid,
> + int *pty_fd)
> +{
> + Error error;
> + if (!path || !argv || !envp || !pid || !pty_fd)
> + {
> + error.SetErrorString("invalid arguments");
> + return error;
> + }
> +
> + // Use a fork that ties the child process's stdin/out/err to a pseudo
> + // terminal so we can read it in our MachProcess::STDIOThread
> + // as unbuffered io.
> + lldb_utility::PseudoTerminal pty;
> + char fork_error[256];
> + memset(fork_error, 0, sizeof(fork_error));
> + *pid = static_cast<::pid_t>(pty.Fork(fork_error,
> sizeof(fork_error)));
> + if (*pid < 0)
> + {
> + //--------------------------------------------------------------
> + // Error during fork.
> + //--------------------------------------------------------------
> + *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
> + error.SetErrorStringWithFormat("%s(): fork failed: %s",
> + __FUNCTION__, fork_error);
> + return error;
> + }
> + else if (pid == 0)
> + {
> + //--------------------------------------------------------------
> + // Child process
> + //--------------------------------------------------------------
> +
> + // Debug this process.
> + ::ptrace(PT_TRACE_ME, 0, 0, 0);
> +
> + // Get BSD signals as mach exceptions.
> + ::ptrace(PT_SIGEXC, 0, 0, 0);
> +
> + // If our parent is setgid, lets make sure we don't inherit those
> + // extra powers due to nepotism.
> + if (::setgid(getgid()) == 0)
> + {
> + // Let the child have its own process group. We need to
> execute
> + // this call in both the child and parent to avoid a race
> + // condition between the two processes.
> +
> + // Set the child process group to match its pid.
> + ::setpgid(0, 0);
> +
> + // Sleep a bit to before the exec call.
> + ::sleep(1);
> +
> + // Turn this process into the given executable.
> + ::execv(path, (char * const *)argv);
> + }
> + // Exit with error code. Child process should have taken
> + // over in above exec call and if the exec fails it will
> + // exit the child process below.
> + ::exit(127);
> + }
> + else
> + {
> + //--------------------------------------------------------------
> + // Parent process
> + //--------------------------------------------------------------
> + // Let the child have its own process group. We need to execute
> + // this call in both the child and parent to avoid a race
> condition
> + // between the two processes.
> +
> + // Set the child process group to match its pid
> + ::setpgid(*pid, *pid);
> + if (pty_fd)
> + {
> + // Release our master pty file descriptor so the pty class
> doesn't
> + // close it and so we can continue to use it in our STDIO
> thread
> + *pty_fd = pty.ReleaseMasterFileDescriptor();
> + }
> + }
> + return error;
> +}
> +
> +static Error
> +CreatePosixSpawnFileAction(const FileAction &action,
> + posix_spawn_file_actions_t *file_actions)
> +{
> + Error error;
> +
> + // Log it.
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> + if (log)
> + {
> + StreamString stream;
> + stream.PutCString("converting file action for posix_spawn(): ");
> + action.Dump(stream);
> + stream.Flush();
> + log->PutCString(stream.GetString().c_str());
> + }
> +
> + // Validate args.
> + if (!file_actions)
> + {
> + error.SetErrorString("mandatory file_actions arg is null");
> + return error;
> + }
> +
> + // Build the posix file action.
> + switch (action.GetAction())
> + {
> + case FileAction::eFileActionOpen:
> + {
> + const int error_code =
> + ::posix_spawn_file_actions_addopen(file_actions,
> + action.GetFD(),
> + action.GetPath(),
> +
> action.GetActionArgument(),
> + 0);
> + if (error_code != 0)
> + {
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> + break;
> + }
> +
> + case FileAction::eFileActionClose:
> + {
> + const int error_code =
> + ::posix_spawn_file_actions_addclose(file_actions,
> + action.GetFD());
> + if (error_code != 0)
> + {
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> + break;
> + }
> +
> + case FileAction::eFileActionDuplicate:
> + {
> + const int error_code =
> + ::posix_spawn_file_actions_adddup2(file_actions,
> + action.GetFD(),
> +
> action.GetActionArgument());
> + if (error_code != 0)
> + {
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> + break;
> + }
> +
> + case FileAction::eFileActionNone:
> + default:
> + if (log)
> + log->Printf("%s(): unsupported file action %u",
> + __FUNCTION__, action.GetAction());
> + break;
> + }
> +
> + return error;
> +}
> +
> +static Error
> +PosixSpawnChildForPTraceDebugging(const char *path,
> + ProcessLaunchInfo &launch_info,
> + ::pid_t *pid,
> + cpu_type_t *actual_cpu_type)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + if (!pid)
> + {
> + error.SetErrorStringWithFormat("%s(): pid arg cannot be null",
> + __FUNCTION__);
> + return error;
> + }
> +
> + posix_spawnattr_t attr;
> + short flags;
> + if (log)
> + {
> + StreamString stream;
> + stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path);
> + launch_info.Dump(stream, nullptr);
> + stream.Flush();
> + log->PutCString(stream.GetString().c_str());
> + }
> +
> + int error_code;
> + if ((error_code = ::posix_spawnattr_init(&attr)) != 0)
> + {
> + if (log)
> + log->Printf("::posix_spawnattr_init(&attr) failed");
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> +
> + // Ensure we clean up the spawnattr structure however we exit this
> + // function.
> + std::unique_ptr<posix_spawnattr_t, int(*)(posix_spawnattr_t*)>
> + spawnattr_up(&attr, ::posix_spawnattr_destroy);
> +
> +
> + flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
> + POSIX_SPAWN_SETSIGMASK;
> + if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
> + flags |= _POSIX_SPAWN_DISABLE_ASLR;
> +
> + sigset_t no_signals;
> + sigset_t all_signals;
> + sigemptyset (&no_signals);
> + sigfillset (&all_signals);
> + ::posix_spawnattr_setsigmask(&attr, &no_signals);
> + ::posix_spawnattr_setsigdefault(&attr, &all_signals);
> +
> + if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0)
> + {
> + if (log)
> + log->Printf("::posix_spawnattr_setflags(&attr, "
> + "POSIX_SPAWN_START_SUSPENDED%s) failed: %s",
> + flags & _POSIX_SPAWN_DISABLE_ASLR ?
> + " | _POSIX_SPAWN_DISABLE_ASLR" : "",
> + strerror(error_code));
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> +
> +#if !defined(__arm__)
> +
> + // We don't need to do this for ARM, and we really shouldn't now that
> we
> + // have multiple CPU subtypes and no posix_spawnattr call that allows
> us
> + // to set which CPU subtype to launch...
> + cpu_type_t desired_cpu_type =
> + launch_info.GetArchitecture().GetMachOCPUType();
> + if (desired_cpu_type != LLDB_INVALID_CPUTYPE)
> + {
> + size_t ocount = 0;
> + error_code = ::posix_spawnattr_setbinpref_np(&attr, 1,
> + &desired_cpu_type,
> + &ocount);
> + if (error_code != 0)
> + {
> + if (log)
> + log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, "
> + "cpu_type = 0x%8.8x, count => %llu): %s",
> + desired_cpu_type, (uint64_t)ocount,
> + strerror(error_code));
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> + if (ocount != 1)
> + {
> + error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np
> "
> + "did not set the expected
> number "
> + "of cpu_type entries: expected
> 1 "
> + "but was %zu", ocount);
> + return error;
> + }
> + }
> +#endif
> +
> + posix_spawn_file_actions_t file_actions;
> + if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) !=
> 0)
> + {
> + if (log)
> + log->Printf("::posix_spawn_file_actions_init(&file_actions) "
> + "failed: %s",
> + strerror(error_code));
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> +
> + // Ensure we clean up file actions however we exit this. When the
> + // file_actions_up below goes out of scope, we'll get our file action
> + // cleanup.
> + std::unique_ptr<posix_spawn_file_actions_t,
> + int(*)(posix_spawn_file_actions_t*)>
> + file_actions_up(&file_actions, ::posix_spawn_file_actions_
> destroy);
> +
> + // We assume the caller has setup the file actions appropriately. We
> + // are not in the business of figuring out what we really need here.
> + // lldb-server will have already called FinalizeFileActions() as well
> + // to button these up properly.
> + const size_t num_actions = launch_info.GetNumFileActions();
> + for (size_t action_index = 0; action_index < num_actions;
> ++action_index)
> + {
> + const FileAction *const action =
> + launch_info.GetFileActionAtIndex(action_index);
> + if (!action)
> + continue;
> +
> + error = CreatePosixSpawnFileAction(*action, &file_actions);
> + if (!error.Success())
> + {
> + if (log)
> + log->Printf("%s(): error converting FileAction to
> posix_spawn "
> + "file action: %s", __FUNCTION__,
> error.AsCString());
> + return error;
> + }
> + }
> +
> + // TODO: Verify if we can set the working directory back immediately
> + // after the posix_spawnp call without creating a race condition???
> + const char *const working_directory =
> + launch_info.GetWorkingDirectory().GetCString();
> + if (working_directory && working_directory[0])
> + ::chdir(working_directory);
> +
> + auto argv = launch_info.GetArguments().GetArgumentVector();
> + auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
> + error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
> + (char * const*)argv, (char * const*)envp);
> + if (error_code != 0)
> + {
> + if (log)
> + log->Printf("::posix_spawnp(pid => %p, path = '%s',
> file_actions "
> + "= %p, attr = %p, argv = %p, envp = %p) failed:
> %s",
> + pid, path, &file_actions, &attr, argv, envp,
> + strerror(error_code));
> + error.SetError(error_code, eErrorTypePOSIX);
> + return error;
> + }
> +
> + // Validate we got a pid.
> + if (pid == LLDB_INVALID_PROCESS_ID)
> + {
> + error.SetErrorString("posix_spawn() did not indicate a failure
> but it "
> + "failed to return a pid, aborting.");
> + return error;
> + }
> +
> + if (actual_cpu_type)
> + {
> + *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
> + if (log)
> + log->Printf("%s(): cpu type for launched process pid=%i: "
> + "cpu_type=0x%8.8x", __FUNCTION__, *pid,
> + *actual_cpu_type);
> + }
> +
> + return error;
> +}
> +
> +Error
> +LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
> + LaunchFlavor *launch_flavor)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + if (!launch_flavor)
> + {
> + error.SetErrorString("mandatory launch_flavor field was null");
> + return error;
> + }
> +
> + if (log)
> + {
> + StreamString stream;
> + stream.Printf("NativeProcessDarwin::%s(): launching with the "
> + "following launch info:", __FUNCTION__);
> + launch_info.Dump(stream, nullptr);
> + stream.Flush();
> + log->PutCString(stream.GetString().c_str());
> + }
> +
> + // Retrieve the binary name given to us.
> + char given_path[PATH_MAX];
> + given_path[0] = '\0';
> + launch_info.GetExecutableFile().GetPath(given_path,
> sizeof(given_path));
> +
> + // Determine the manner in which we'll launch.
> + *launch_flavor = g_launch_flavor;
> + if (*launch_flavor == LaunchFlavor::Default)
> + {
> + // Our default launch method is posix spawn
> + *launch_flavor = LaunchFlavor::PosixSpawn;
> +#if defined WITH_FBS
> + // Check if we have an app bundle, if so launch using BackBoard
> Services.
> + if (strstr(given_path, ".app"))
> + {
> + *launch_flavor = eLaunchFlavorFBS;
> + }
> +#elif defined WITH_BKS
> + // Check if we have an app bundle, if so launch using BackBoard
> Services.
> + if (strstr(given_path, ".app"))
> + {
> + *launch_flavor = eLaunchFlavorBKS;
> + }
> +#elif defined WITH_SPRINGBOARD
> + // Check if we have an app bundle, if so launch using SpringBoard.
> + if (strstr(given_path, ".app"))
> + {
> + *launch_flavor = eLaunchFlavorSpringBoard;
> + }
> +#endif
> + }
> +
> + // Attempt to resolve the binary name to an absolute path.
> + char resolved_path[PATH_MAX];
> + resolved_path[0] = '\0';
> +
> + if (log)
> + log->Printf("%s(): attempting to resolve given binary path:
> \"%s\"",
> + __FUNCTION__, given_path);
> +
> + // If we fail to resolve the path to our executable, then just use
> what we
> + // were given and hope for the best
> + if (!ResolveExecutablePath(given_path, resolved_path,
> + sizeof(resolved_path)) )
> + {
> + if (log)
> + log->Printf("%s(): failed to resolve binary path, using "
> + "what was given verbatim and hoping for the best",
> + __FUNCTION__);
> + ::strncpy(resolved_path, given_path,
> + sizeof(resolved_path));
> + }
> + else
> + {
> + if (log)
> + log->Printf("%s(): resolved given binary path to: \"%s\"",
> + __FUNCTION__, resolved_path);
> + }
> +
> + char launch_err_str[PATH_MAX];
> + launch_err_str[0] = '\0';
> +
> + // TODO figure out how to handle QSetProcessEvent
> + // const char *process_event = ctx.GetProcessEvent();
> +
> + // Ensure the binary is there.
> + struct stat path_stat;
> + if (::stat(resolved_path, &path_stat) == -1)
> + {
> + error.SetErrorToErrno();
> + return error;
> + }
> +
> + // Fork a child process for debugging
> + // state_callback(eStateLaunching);
> +
> + const auto argv = launch_info.GetArguments().
> GetConstArgumentVector();
> + const auto envp =
> + launch_info.GetEnvironmentEntries().GetConstArgumentVector();
> +
> + switch (*launch_flavor)
> + {
> + case LaunchFlavor::ForkExec:
> + {
> + ::pid_t pid = LLDB_INVALID_PROCESS_ID;
> + error = ForkChildForPTraceDebugging(resolved_path, argv,
> envp,
> + &pid, pty_master_fd);
> + if (error.Success())
> + {
> + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
> + }
> + else
> + {
> + // Reset any variables that might have been set during a
> failed
> + // launch attempt.
> + if (pty_master_fd)
> + *pty_master_fd = -1;
> +
> + // We're done.
> + return error;
> + }
> + }
> + break;
> +
> +#ifdef WITH_FBS
> + case LaunchFlavor::FBS:
> + {
> + const char *app_ext = strstr(path, ".app");
> + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/'))
> + {
> + std::string app_bundle_path(path, app_ext +
> strlen(".app"));
> + m_flags |= eMachProcessFlagsUsingFBS;
> + if (BoardServiceLaunchForDebug (app_bundle_path.c_str(),
> argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0)
> + return m_pid; // A successful SBLaunchForDebug()
> returns and assigns a non-zero m_pid.
> + else
> + break; // We tried a FBS launch, but didn't succeed
> lets get out
> + }
> + }
> + break;
> +#endif
> +
> +#ifdef WITH_BKS
> + case LaunchFlavor::BKS:
> + {
> + const char *app_ext = strstr(path, ".app");
> + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/'))
> + {
> + std::string app_bundle_path(path, app_ext +
> strlen(".app"));
> + m_flags |= eMachProcessFlagsUsingBKS;
> + if (BoardServiceLaunchForDebug (app_bundle_path.c_str(),
> argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0)
> + return m_pid; // A successful SBLaunchForDebug()
> returns and assigns a non-zero m_pid.
> + else
> + break; // We tried a BKS launch, but didn't succeed
> lets get out
> + }
> + }
> + break;
> +#endif
> +
> +#ifdef WITH_SPRINGBOARD
> + case LaunchFlavor::SpringBoard:
> + {
> + // .../whatever.app/whatever ?
> + // Or .../com.apple.whatever.app/whatever -- be careful of
> ".app" in "com.apple.whatever" here
> + const char *app_ext = strstr (path, ".app/");
> + if (app_ext == NULL)
> + {
> + // .../whatever.app ?
> + int len = strlen (path);
> + if (len > 5)
> + {
> + if (strcmp (path + len - 4, ".app") == 0)
> + {
> + app_ext = path + len - 4;
> + }
> + }
> + }
> + if (app_ext)
> + {
> + std::string app_bundle_path(path, app_ext +
> strlen(".app"));
> + if (SBLaunchForDebug (app_bundle_path.c_str(), argv,
> envp, no_stdio, disable_aslr, launch_err) != 0)
> + return m_pid; // A successful SBLaunchForDebug()
> returns and assigns a non-zero m_pid.
> + else
> + break; // We tried a springboard launch, but didn't
> succeed lets get out
> + }
> + }
> + break;
> +#endif
> +
> + case LaunchFlavor::PosixSpawn:
> + {
> + ::pid_t pid = LLDB_INVALID_PROCESS_ID;
> +
> + // Retrieve paths for stdin/stdout/stderr.
> + cpu_type_t actual_cpu_type = 0;
> + error = PosixSpawnChildForPTraceDebugging(resolved_path,
> + launch_info,
> + &pid,
> + &actual_cpu_type);
> + if (error.Success())
> + {
> + launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
> + if (pty_master_fd)
> + *pty_master_fd = launch_info.GetPTY().
> + ReleaseMasterFileDescriptor();
> + }
> + else
> + {
> + // Reset any variables that might have been set during a
> failed
> + // launch attempt.
> + if (pty_master_fd)
> + *pty_master_fd = -1;
> +
> + // We're done.
> + return error;
> + }
> + break;
> + }
> +
> + default:
> + // Invalid launch flavor.
> + error.SetErrorStringWithFormat("NativeProcessDarwin::%s():
> unknown "
> + "launch flavor %d",
> __FUNCTION__,
> + (int)*launch_flavor);
> + return error;
> + }
> +
> + if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID)
> + {
> + // If we don't have a valid process ID and no one has set the
> error,
> + // then return a generic error.
> + if (error.Success())
> + error.SetErrorStringWithFormat("%s(): failed to launch, no
> reason "
> + "specified", __FUNCTION__);
> + }
> +
> + // We're done with the launch side of the operation.
> + return error;
> +}
> +
> +}} // namespaces
> +
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/DarwinProcessLauncher.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.h
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.h Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,51 @@
> +//===-- DarwinProcessLauncher.h ---------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef DarwinProcessLauncher_h
> +#define DarwinProcessLauncher_h
> +
> +// C headers
> +#include <mach/machine.h>
> +#include <sys/types.h>
> +
> +// C++ headers
> +#include <functional>
> +
> +// LLDB headers
> +#include "lldb/lldb-enumerations.h"
> +#include "lldb/lldb-forward.h"
> +
> +#include "LaunchFlavor.h"
> +
> +namespace lldb_private
> +{
> +namespace darwin_process_launcher
> +{
> +// ============================================================
> =================
> +/// Launches a process for debugging.
> +///
> +/// @param[inout] launch_info
> +/// Specifies details about the process to launch (e.g. path,
> architecture,
> +/// etc.). On output, includes the launched ProcessID (pid).
> +///
> +/// @param[out] pty_master_fd
> +/// Returns the master side of the pseudo-terminal used to communicate
> +/// with stdin/stdout from the launched process. May be nullptr.
> +///
> +/// @param[out] launch_flavor
> +/// Contains the launch flavor used when launching the process.
> +// ============================================================
> =================
> +Error
> +LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
> + lldb_private::process_darwin::LaunchFlavor
> *launch_flavor);
> +
> +} // darwin_process_launcher
> +} // lldb_private
> +
> +#endif /* DarwinProcessLauncher_h */
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/LaunchFlavor.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/LaunchFlavor.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/LaunchFlavor.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/LaunchFlavor.h Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,34 @@
> +//===-- LaunchFlavor.h ---------------------------------------- -*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef LaunchFlavor_h
> +#define LaunchFlavor_h
> +
> +namespace lldb_private {
> +namespace process_darwin {
> +
> +enum class LaunchFlavor
> +{
> + Default = 0,
> + PosixSpawn = 1,
> + ForkExec = 2,
> +#ifdef WITH_SPRINGBOARD
> + SpringBoard = 3,
> +#endif
> +#ifdef WITH_BKS
> + BKS = 4,
> +#endif
> +#ifdef WITH_FBS
> + FBS = 5
> +#endif
> +};
> +
> +}} // namespaces
> +
> +#endif /* LaunchFlavor_h */
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/MachException.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/MachException.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/MachException.cpp (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/MachException.cpp Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,684 @@
> +//===-- MachException.cpp ---------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 6/18/07.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "MachException.h"
> +
> +// C includes
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <sys/ptrace.h>
> +
> +// C++ includes
> +#include <mutex>
> +
> +// LLDB includes
> +#include "lldb/Core/Error.h"
> +#include "lldb/Core/Log.h"
> +#include "lldb/Core/Stream.h"
> +#include "lldb/Target/UnixSignals.h"
> +#include "lldb/Utility/LLDBAssert.h"
> +
> +using namespace lldb;
> +using namespace lldb_private;
> +using namespace lldb_private::process_darwin;
> +
> +// Routine mach_exception_raise
> +extern "C"
> +kern_return_t catch_mach_exception_raise
> +(
> + mach_port_t exception_port,
> + mach_port_t thread,
> + mach_port_t task,
> + exception_type_t exception,
> + mach_exception_data_t code,
> + mach_msg_type_number_t codeCnt
> +);
> +
> +extern "C"
> +kern_return_t catch_mach_exception_raise_state
> +(
> + mach_port_t exception_port,
> + exception_type_t exception,
> + const mach_exception_data_t code,
> + mach_msg_type_number_t codeCnt,
> + int *flavor,
> + const thread_state_t old_state,
> + mach_msg_type_number_t old_stateCnt,
> + thread_state_t new_state,
> + mach_msg_type_number_t *new_stateCnt
> +);
> +
> +// Routine mach_exception_raise_state_identity
> +extern "C"
> +kern_return_t catch_mach_exception_raise_state_identity
> +(
> + mach_port_t exception_port,
> + mach_port_t thread,
> + mach_port_t task,
> + exception_type_t exception,
> + mach_exception_data_t code,
> + mach_msg_type_number_t codeCnt,
> + int *flavor,
> + thread_state_t old_state,
> + mach_msg_type_number_t old_stateCnt,
> + thread_state_t new_state,
> + mach_msg_type_number_t *new_stateCnt
> +);
> +
> +extern "C" boolean_t mach_exc_server(
> + mach_msg_header_t *InHeadP,
> + mach_msg_header_t *OutHeadP);
> +
> +// Any access to the g_message variable should be done by locking the
> +// g_message_mutex first, using the g_message variable, then unlocking
> +// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
> +// for sample code.
> +
> +static MachException::Data *g_message = NULL;
> +
> +
> +extern "C"
> +kern_return_t
> +catch_mach_exception_raise_state
> +(
> + mach_port_t exc_port,
> + exception_type_t exc_type,
> + const mach_exception_data_t exc_data,
> + mach_msg_type_number_t exc_data_count,
> + int * flavor,
> + const thread_state_t old_state,
> + mach_msg_type_number_t old_stateCnt,
> + thread_state_t new_state,
> + mach_msg_type_number_t * new_stateCnt
> +)
> +{
> + // TODO change to LIBLLDB_LOG_EXCEPTION
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (log)
> + {
> + log->Printf("::%s(exc_port = 0x%4.4x, exc_type = %d (%s), "
> + "exc_data = 0x%llx, exc_data_count = %d)",
> + __FUNCTION__, exc_port, exc_type,
> + MachException::Name(exc_type), (uint64_t)exc_data,
> + exc_data_count);
> + }
> + return KERN_FAILURE;
> +}
> +
> +extern "C"
> +kern_return_t
> +catch_mach_exception_raise_state_identity
> +(
> + mach_port_t exc_port,
> + mach_port_t thread_port,
> + mach_port_t task_port,
> + exception_type_t exc_type,
> + mach_exception_data_t exc_data,
> + mach_msg_type_number_t exc_data_count,
> + int * flavor,
> + thread_state_t old_state,
> + mach_msg_type_number_t old_stateCnt,
> + thread_state_t new_state,
> + mach_msg_type_number_t *new_stateCnt
> +)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (log)
> + {
> + log->Printf("::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, "
> + "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d]
> = "
> + "{ 0x%llx, 0x%llx })", __FUNCTION__, exc_port,
> thread_port,
> + task_port, exc_type, MachException::Name(exc_type),
> + exc_data_count,
> + (uint64_t)(exc_data_count > 0 ? exc_data[0] :
> 0xBADDBADD),
> + (uint64_t)(exc_data_count > 1 ? exc_data[1] :
> 0xBADDBADD));
> + }
> + mach_port_deallocate (mach_task_self(), task_port);
> + mach_port_deallocate (mach_task_self(), thread_port);
> +
> + return KERN_FAILURE;
> +}
> +
> +extern "C"
> +kern_return_t
> +catch_mach_exception_raise
> +(
> + mach_port_t exc_port,
> + mach_port_t thread_port,
> + mach_port_t task_port,
> + exception_type_t exc_type,
> + mach_exception_data_t exc_data,
> + mach_msg_type_number_t exc_data_count)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (log)
> + {
> + log->Printf("::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, "
> + "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d]
> "
> + "= { 0x%llx, 0x%llx })", __FUNCTION__, exc_port,
> + thread_port, task_port, exc_type,
> + MachException::Name(exc_type), exc_data_count,
> + (uint64_t)(exc_data_count > 0 ? exc_data[0] :
> 0xBADDBADD),
> + (uint64_t)(exc_data_count > 1 ? exc_data[1] :
> 0xBADDBADD));
> + }
> +
> + if (task_port == g_message->task_port)
> + {
> + g_message->task_port = task_port;
> + g_message->thread_port = thread_port;
> + g_message->exc_type = exc_type;
> + g_message->exc_data.resize(exc_data_count);
> + ::memcpy(&g_message->exc_data[0], exc_data,
> + g_message->exc_data.size() *
> + sizeof (mach_exception_data_type_t));
> + return KERN_SUCCESS;
> + }
> + return KERN_FAILURE;
> +}
> +
> +#if 0
> +void
> +MachException::Message::Dump(Stream &stream) const
> +{
> + stream.Printf("exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = "
> + "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x "
> + "id = 0x%8.8x }\n",
> + exc_msg.hdr.msgh_bits,
> + exc_msg.hdr.msgh_size,
> + exc_msg.hdr.msgh_remote_port,
> + exc_msg.hdr.msgh_local_port,
> + exc_msg.hdr.msgh_reserved,
> + exc_msg.hdr.msgh_id);
> +
> + stream.Printf("reply_msg { bits = 0x%8.8x size = 0x%8.8x remote-port "
> + "= 0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x "
> + "id = 0x%8.8x }",
> + reply_msg.hdr.msgh_bits,
> + reply_msg.hdr.msgh_size,
> + reply_msg.hdr.msgh_remote_port,
> + reply_msg.hdr.msgh_local_port,
> + reply_msg.hdr.msgh_reserved,
> + reply_msg.hdr.msgh_id);
> + stream.Flush();
> +}
> +#endif
> +
> +bool
> +MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info,
> + const UnixSignals &signals,
> + Stream &stream) const
> +{
> + if (!stop_info)
> + return false;
> +
> + // Zero out the structure.
> + memset(stop_info, 0, sizeof(struct ThreadStopInfo));
> +
> + if (exc_type == 0)
> + {
> + stop_info->reason = eStopReasonInvalid;
> + return true;
> + }
> +
> + // We always stop with a mach exception.
> + stop_info->reason = eStopReasonException;
> + // Save the EXC_XXXX exception type.
> + stop_info->details.exception.type = exc_type;
> +
> + // Fill in a text description
> + const char * exc_name = MachException::Name(exc_type);
> + if (exc_name)
> + stream.Printf("%s", exc_name);
> + else
> + stream.Printf("%i", exc_type);
> +
> + stop_info->details.exception.data_count = exc_data.size();
> +
> + int soft_signal = SoftSignal();
> + if (soft_signal)
> + {
> + const char *sig_str = signals.GetSignalAsCString(soft_signal);
> + stream.Printf(" EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal,
> + sig_str ? sig_str : "unknown signal");
> + }
> + else
> + {
> + // No special disassembly for exception data, just print it.
> + size_t idx;
> + stream.Printf(" data[%llu] = {",
> + (uint64_t)stop_info->details.exception.data_count);
> +
> + for (idx = 0; idx < stop_info->details.exception.data_count;
> ++idx)
> + {
> + stream.Printf("0x%llx%c", (uint64_t)exc_data[idx],
> + ((idx + 1 == stop_info->details.exception.
> data_count)
> + ? '}' : ','));
> + }
> + }
> +
> + // Copy the exception data
> + for (size_t i = 0; i < stop_info->details.exception.data_count; i++)
> + stop_info->details.exception.data[i] = exc_data[i];
> +
> + return true;
> +}
> +
> +Error
> +MachException::Message::Receive(mach_port_t port, mach_msg_option_t
> options,
> + mach_msg_timeout_t timeout,
> + mach_port_t notify_port)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + mach_msg_timeout_t mach_msg_timeout =
> + options & MACH_RCV_TIMEOUT ? timeout : 0;
> + if (log && ((options & MACH_RCV_TIMEOUT) == 0))
> + {
> + // Dump this log message if we have no timeout in case it never
> returns
> + log->Printf("::mach_msg(msg->{bits = %#x, size = %u remote_port
> = %#x, "
> + "local_port = %#x, reserved = 0x%x, id = 0x%x}, "
> + "option = %#x, send_size = 0, rcv_size = %llu, "
> + "rcv_name = %#x, timeout = %u, notify = %#x)",
> + exc_msg.hdr.msgh_bits,
> + exc_msg.hdr.msgh_size,
> + exc_msg.hdr.msgh_remote_port,
> + exc_msg.hdr.msgh_local_port,
> + exc_msg.hdr.msgh_reserved,
> + exc_msg.hdr.msgh_id,
> + options,
> + (uint64_t)sizeof (exc_msg.data),
> + port,
> + mach_msg_timeout,
> + notify_port);
> + }
> +
> + mach_msg_return_t mach_err =
> + ::mach_msg (&exc_msg.hdr,
> + options, // options
> + 0, // Send size
> + sizeof (exc_msg.data), // Receive size
> + port, // exception port to watch
> for
> + // exception on
> + mach_msg_timeout, // timeout in msec (obeyed
> only
> + // if MACH_RCV_TIMEOUT is
> ORed
> + // into the options
> parameter)
> + notify_port);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> +
> + // Dump any errors we get
> + if (error.Fail() && log)
> + {
> + log->Printf("::mach_msg(msg->{bits = %#x, size = %u remote_port
> = %#x, "
> + "local_port = %#x, reserved = 0x%x, id = 0x%x}, "
> + "option = %#x, send_size = %u, rcv_size = %lu,
> rcv_name "
> + "= %#x, timeout = %u, notify = %#x) failed: %s",
> + exc_msg.hdr.msgh_bits,
> + exc_msg.hdr.msgh_size,
> + exc_msg.hdr.msgh_remote_port,
> + exc_msg.hdr.msgh_local_port,
> + exc_msg.hdr.msgh_reserved,
> + exc_msg.hdr.msgh_id,
> + options,
> + 0,
> + sizeof(exc_msg.data),
> + port,
> + mach_msg_timeout,
> + notify_port,
> + error.AsCString());
> + }
> + return error;
> +}
> +
> +void
> +MachException::Message::Dump(Stream &stream) const
> +{
> + stream.Printf(" exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port
> = "
> + "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = "
> + "0x%8.8x }\n",
> + exc_msg.hdr.msgh_bits,
> + exc_msg.hdr.msgh_size,
> + exc_msg.hdr.msgh_remote_port,
> + exc_msg.hdr.msgh_local_port,
> + exc_msg.hdr.msgh_reserved,
> + exc_msg.hdr.msgh_id);
> +
> + stream.Printf(" reply_msg { bits = 0x%8.8x size = 0x%8.8x
> remote-port = "
> + "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = "
> + "0x%8.8x }",
> + reply_msg.hdr.msgh_bits,
> + reply_msg.hdr.msgh_size,
> + reply_msg.hdr.msgh_remote_port,
> + reply_msg.hdr.msgh_local_port,
> + reply_msg.hdr.msgh_reserved,
> + reply_msg.hdr.msgh_id);
> +}
> +
> +bool
> +MachException::Message::CatchExceptionRaise(task_t task)
> +{
> + bool success = false;
> + // locker will keep a mutex locked until it goes out of scope
> +// PThreadMutex::Locker locker(&g_message_mutex);
> + // DNBLogThreaded("calling mach_exc_server");
> + state.task_port = task;
> + g_message = &state;
> + // The exc_server function is the MIG generated server handling
> function
> + // to handle messages from the kernel relating to the occurrence of an
> + // exception in a thread. Such messages are delivered to the
> exception port
> + // set via thread_set_exception_ports or task_set_exception_ports.
> When an
> + // exception occurs in a thread, the thread sends an exception
> message to
> + // its exception port, blocking in the kernel waiting for the receipt
> of a
> + // reply. The exc_server function performs all necessary argument
> handling
> + // for this kernel message and calls catch_exception_raise,
> + // catch_exception_raise_state or catch_exception_raise_state_
> identity,
> + // which should handle the exception. If the called routine returns
> + // KERN_SUCCESS, a reply message will be sent, allowing the thread to
> + // continue from the point of the exception; otherwise, no reply
> message
> + // is sent and the called routine must have dealt with the exception
> + // thread directly.
> + if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr))
> + {
> + success = true;
> + }
> + else
> + {
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (log)
> + log->Printf("MachException::Message::%s(): mach_exc_server "
> + "returned zero...", __FUNCTION__);
> + }
> + g_message = NULL;
> + return success;
> +}
> +
> +Error
> +MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task,
> + int signal)
> +{
> + // Reply to the exception...
> + Error error;
> +
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + // If we had a soft signal, we need to update the thread first so it
> can
> + // continue without signaling
> + int soft_signal = state.SoftSignal();
> + if (soft_signal)
> + {
> + int state_pid = -1;
> + if (inferior_task == state.task_port)
> + {
> + // This is our task, so we can update the signal to send to it
> + state_pid = inferior_pid;
> + soft_signal = signal;
> + }
> + else
> + {
> + auto mach_err = ::pid_for_task(state.task_port, &state_pid);
> + if (mach_err)
> + {
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (log)
> + log->Printf("MachException::Message::%s():
> pid_for_task() "
> + "failed: %s", __FUNCTION__,
> error.AsCString());
> + return error;
> + }
> + }
> +
> + lldbassert(state_pid != -1);
> + if (state_pid != -1)
> + {
> + errno = 0;
> + caddr_t thread_port_caddr = (caddr_t)(uintptr_t)state.
> thread_port;
> + if (::ptrace(PT_THUPDATE, state_pid, thread_port_caddr,
> soft_signal)
> + != 0)
> + error.SetError(errno, eErrorTypePOSIX);
> +
> + if (!error.Success())
> + {
> + if (log)
> + log->Printf("::ptrace(request = PT_THUPDATE, pid = "
> + "0x%4.4x, tid = 0x%4.4x, signal = %i)",
> + state_pid, state.thread_port,
> soft_signal);
> + return error;
> + }
> + }
> + }
> +
> + if (log)
> + log->Printf("::mach_msg ( msg->{bits = %#x, size = %u,
> remote_port "
> + "= %#x, local_port = %#x, reserved = 0x%x, id =
> 0x%x}, "
> + "option = %#x, send_size = %u, rcv_size = %u,
> rcv_name "
> + "= %#x, timeout = %u, notify = %#x)",
> + reply_msg.hdr.msgh_bits,
> + reply_msg.hdr.msgh_size,
> + reply_msg.hdr.msgh_remote_port,
> + reply_msg.hdr.msgh_local_port,
> + reply_msg.hdr.msgh_reserved,
> + reply_msg.hdr.msgh_id,
> + MACH_SEND_MSG | MACH_SEND_INTERRUPT,
> + reply_msg.hdr.msgh_size,
> + 0,
> + MACH_PORT_NULL,
> + MACH_MSG_TIMEOUT_NONE,
> + MACH_PORT_NULL);
> +
> + auto mach_err = ::mach_msg(&reply_msg.hdr,
> + MACH_SEND_MSG | MACH_SEND_INTERRUPT,
> + reply_msg.hdr.msgh_size,
> + 0,
> + MACH_PORT_NULL,
> + MACH_MSG_TIMEOUT_NONE,
> + MACH_PORT_NULL);
> + if (mach_err)
> + error.SetError(mach_err, eErrorTypeMachKernel);
> +
> + // Log our error if we have one.
> + if (error.Fail() && log)
> + {
> + if (error.GetError() == MACH_SEND_INTERRUPTED)
> + {
> + log->PutCString("::mach_msg() - send interrupted");
> + // TODO: keep retrying to reply???
> + }
> + else if (state.task_port == inferior_task)
> + {
> + log->Printf("mach_msg(): returned an error when replying "
> + "to a mach exception: error = %u (%s)",
> + error.GetError(), error.AsCString());
> + }
> + else
> + {
> + log->Printf("::mach_msg() - failed (child of task): %u (%s)",
> + error.GetError(), error.AsCString());
> + }
> + }
> +
> + return error;
> +}
> +
> +#define PREV_EXC_MASK_ALL (EXC_MASK_BAD_ACCESS | \
> + EXC_MASK_BAD_INSTRUCTION | \
> + EXC_MASK_ARITHMETIC | \
> + EXC_MASK_EMULATION | \
> + EXC_MASK_SOFTWARE | \
> + EXC_MASK_BREAKPOINT | \
> + EXC_MASK_SYSCALL | \
> + EXC_MASK_MACH_SYSCALL | \
> + EXC_MASK_RPC_ALERT | \
> + EXC_MASK_MACHINE)
> +
> +// Don't listen for EXC_RESOURCE, it should really get handled by the
> system handler.
> +
> +#ifndef EXC_RESOURCE
> +#define EXC_RESOURCE 11
> +#endif
> +
> +#ifndef EXC_MASK_RESOURCE
> +#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE)
> +#endif
> +
> +#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE)
> +
> +Error
> +MachException::PortInfo::Save(task_t task)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + if (log)
> + log->Printf("MachException::PortInfo::%s(task = 0x%4.4x)",
> + __FUNCTION__, task);
> +
> + // Be careful to be able to have debugserver built on a newer OS than
> what
> + // it is currently running on by being able to start with all
> exceptions
> + // and back off to just what is supported on the current system
> + mask = LLDB_EXC_MASK;
> +
> + count = (sizeof(ports) / sizeof(ports[0]));
> + auto mach_err = ::task_get_exception_ports(task, mask, masks,
> &count, ports,
> + behaviors, flavors);
> + if (mach_err)
> + error.SetError(mach_err, eErrorTypeMachKernel);
> +
> + if (log)
> + {
> + if (error.Success())
> + {
> + log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask
> = "
> + "0x%x, maskCnt => %u, ports, behaviors, flavors)",
> + task, mask, count);
> + }
> + else
> + {
> + log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask
> = 0x%x, "
> + "maskCnt => %u, ports, behaviors, flavors) error:
> %u (%s)",
> + task, mask, count, error.GetError(),
> error.AsCString());
> + }
> + }
> +
> + if ((error.GetError() == KERN_INVALID_ARGUMENT) &&
> + (mask != PREV_EXC_MASK_ALL))
> + {
> + mask = PREV_EXC_MASK_ALL;
> + count = (sizeof(ports) / sizeof(ports[0]));
> + mach_err = ::task_get_exception_ports(task, mask, masks, &count,
> ports,
> + behaviors, flavors);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (log)
> + {
> + if (error.Success())
> + {
> + log->Printf("::task_get_exception_ports(task = 0x%4.4x, "
> + "mask = 0x%x, maskCnt => %u, ports,
> behaviors, "
> + "flavors)", task, mask, count);
> + }
> + else
> + {
> + log->Printf("::task_get_exception_ports(task = 0x%4.4x,
> mask = "
> + "0x%x, maskCnt => %u, ports, behaviors,
> flavors) "
> + "error: %u (%s)", task, mask, count,
> + error.GetError(), error.AsCString());
> + }
> + }
> + }
> + if (error.Fail())
> + {
> + mask = 0;
> + count = 0;
> + }
> + return error;
> +}
> +
> +Error
> +MachException::PortInfo::Restore(task_t task)
> +{
> + Error error;
> +
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + if (log)
> + log->Printf("MachException::PortInfo::Restore(task = 0x%4.4x)",
> task);
> +
> + uint32_t i = 0;
> + if (count > 0)
> + {
> + for (i = 0; i < count; i++)
> + {
> + auto mach_err = ::task_set_exception_ports(task, masks[i],
> ports[i],
> + behaviors[i],
> + flavors[i]);
> + if (mach_err)
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (log)
> + {
> + if (error.Success())
> + {
> + log->Printf("::task_set_exception_ports(task =
> 0x%4.4x, "
> + "exception_mask = 0x%8.8x, new_port =
> 0x%4.4x, "
> + "behavior = 0x%8.8x, new_flavor =
> 0x%8.8x)",
> + task, masks[i], ports[i], behaviors[i],
> + flavors[i]);
> + }
> + else
> + {
> + log->Printf("::task_set_exception_ports(task =
> 0x%4.4x, "
> + "exception_mask = 0x%8.8x, new_port =
> 0x%4.4x, "
> + "behavior = 0x%8.8x, new_flavor =
> 0x%8.8x): "
> + "error %u (%s)", task, masks[i], ports[i],
> + behaviors[i], flavors[i],
> error.GetError(),
> + error.AsCString());
> + }
> + }
> +
> + // Bail if we encounter any errors
> + if (error.Fail())
> + break;
> + }
> + }
> +
> + count = 0;
> + return error;
> +}
> +
> +const char *
> +MachException::Name(exception_type_t exc_type)
> +{
> + switch (exc_type)
> + {
> + case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS";
> + case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
> + case EXC_ARITHMETIC: return "EXC_ARITHMETIC";
> + case EXC_EMULATION: return "EXC_EMULATION";
> + case EXC_SOFTWARE: return "EXC_SOFTWARE";
> + case EXC_BREAKPOINT: return "EXC_BREAKPOINT";
> + case EXC_SYSCALL: return "EXC_SYSCALL";
> + case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL";
> + case EXC_RPC_ALERT: return "EXC_RPC_ALERT";
> +#ifdef EXC_CRASH
> + case EXC_CRASH: return "EXC_CRASH";
> +#endif
> + default:
> + break;
> + }
> + return NULL;
> +}
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/MachException.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/MachException.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/MachException.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/MachException.h Sat Sep 3
> 19:18:56 2016
> @@ -0,0 +1,163 @@
> +//===-- MachException.h -----------------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 6/18/07.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +
> +#ifndef __MachException_h__
> +#define __MachException_h__
> +
> +#include <mach/mach.h>
> +#include <vector>
> +
> +#include "lldb/lldb-private-forward.h"
> +#include "lldb/lldb-types.h"
> +#include "lldb/Host/Debug.h"
> +
> +namespace lldb_private
> +{
> +namespace process_darwin
> +{
> +
> +typedef union MachMessageTag
> +{
> + mach_msg_header_t hdr;
> + char data[1024];
> +} MachMessage;
> +
> +
> +class MachException
> +{
> +public:
> +
> + struct PortInfo
> + {
> + exception_mask_t mask; // the exception mask for this
> device which may be a subset of EXC_MASK_ALL...
> + exception_mask_t masks[EXC_TYPES_COUNT];
> + mach_port_t ports[EXC_TYPES_COUNT];
> + exception_behavior_t behaviors[EXC_TYPES_COUNT];
> + thread_state_flavor_t flavors[EXC_TYPES_COUNT];
> + mach_msg_type_number_t count;
> +
> + Error
> + Save(task_t task);
> +
> + Error
> + Restore(task_t task);
> + };
> +
> + struct Data
> + {
> + task_t task_port;
> + thread_t thread_port;
> + exception_type_t exc_type;
> + std::vector<mach_exception_data_type_t> exc_data;
> + Data() :
> + task_port(TASK_NULL),
> + thread_port(THREAD_NULL),
> + exc_type(0),
> + exc_data()
> + {
> + }
> +
> + void
> + Clear()
> + {
> + task_port = TASK_NULL;
> + thread_port = THREAD_NULL;
> + exc_type = 0;
> + exc_data.clear();
> + }
> +
> + bool
> + IsValid() const
> + {
> + return task_port != TASK_NULL &&
> + thread_port != THREAD_NULL &&
> + exc_type != 0;
> + }
> +
> + // Return the SoftSignal for this MachException data, or zero if
> there is none
> + int
> + SoftSignal() const
> + {
> + if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 &&
> exc_data[0] == EXC_SOFT_SIGNAL)
> + return static_cast<int>(exc_data[1]);
> + return 0;
> + }
> +
> + bool
> + IsBreakpoint() const
> + {
> + return (exc_type == EXC_BREAKPOINT || ((exc_type ==
> EXC_SOFTWARE) && exc_data[0] == 1));
> + }
> +
> + bool
> + GetStopInfo(ThreadStopInfo *stop_info, const UnixSignals &signals,
> + Stream &stream) const;
> + };
> +
> + struct Message
> + {
> + MachMessage exc_msg;
> + MachMessage reply_msg;
> + Data state;
> +
> + Message() :
> + state()
> + {
> + memset(&exc_msg, 0, sizeof(exc_msg));
> + memset(&reply_msg, 0, sizeof(reply_msg));
> + }
> +
> + bool
> + CatchExceptionRaise(task_t task);
> +
> + Error
> + Reply(::pid_t inferior_pid, task_t inferior_task, int signal);
> +
> + Error
> + Receive(mach_port_t receive_port,
> + mach_msg_option_t options,
> + mach_msg_timeout_t timeout,
> + mach_port_t notify_port = MACH_PORT_NULL);
> +
> + void
> + Dump(Stream &stream) const;
> +
> + typedef std::vector<Message> collection;
> + typedef collection::iterator iterator;
> + typedef collection::const_iterator const_iterator;
> + };
> +
> + enum
> + {
> + e_actionForward, // Forward signal to inferior process
> + e_actionStop, // Stop when this signal is received
> + };
> + struct Action
> + {
> + task_t task_port; // Set to TASK_NULL for any TASK
> + thread_t thread_port; // Set to THREAD_NULL for any thread
> + exception_type_t exc_mask; // Mach exception mask to watch for
> + std::vector<mach_exception_data_type_t> exc_data_mask; //
> Mask to apply to exception data, or empty to ignore exc_data value for
> exception
> + std::vector<mach_exception_data_type_t> exc_data_value; //
> Value to compare to exception data after masking, or empty to ignore
> exc_data value for exception
> + uint8_t flags; // Action flags describing what to
> do with the exception
> + };
> +
> + static const char*
> + Name(exception_type_t exc_type);
> +};
> +
> +} // namespace process_darwin
> +} // namespace lldb_private
> +
> +#endif
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeProcessDarwin.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,1825 @@
> +//===-- NativeProcessDarwin.cpp ---------------------------------*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "NativeProcessDarwin.h"
> +
> +// C includes
> +#include <mach/mach_init.h>
> +#include <mach/mach_traps.h>
> +#include <sys/ptrace.h>
> +#include <sys/stat.h>
> +#include <sys/sysctl.h>
> +#include <sys/types.h>
> +
> +// C++ includes
> +// LLDB includes
> +#include "lldb/Core/Log.h"
> +#include "lldb/Core/State.h"
> +#include "lldb/Core/StreamString.h"
> +#include "lldb/Target/ProcessLaunchInfo.h"
> +#include "lldb/Utility/PseudoTerminal.h"
> +
> +#include "CFBundle.h"
> +#include "CFString.h"
> +#include "DarwinProcessLauncher.h"
> +
> +#include "MachException.h"
> +
> +using namespace lldb;
> +using namespace lldb_private;
> +using namespace lldb_private::process_darwin;
> +using namespace lldb_private::darwin_process_launcher;
> +
> +// ------------------------------------------------------------
> -----------------
> +// Hidden Impl
> +// ------------------------------------------------------------
> -----------------
> +
> +namespace
> +{
> + struct hack_task_dyld_info {
> + mach_vm_address_t all_image_info_addr;
> + mach_vm_size_t all_image_info_size;
> + };
> +}
> +
> +// ------------------------------------------------------------
> -----------------
> +// Public Static Methods
> +// ------------------------------------------------------------
> -----------------
> +
> +Error
> +NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info,
> + NativeProcessProtocol::NativeDelegate
> + &native_delegate,
> + MainLoop &mainloop,
> + NativeProcessProtocolSP &native_process_sp)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + Error error;
> +
> + // Verify the working directory is valid if one was specified.
> + FileSpec working_dir(launch_info.GetWorkingDirectory());
> + if (working_dir &&
> + (!working_dir.ResolvePath() ||
> + working_dir.GetFileType() != FileSpec::eFileTypeDirectory))
> + {
> + error.SetErrorStringWithFormat("No such file or directory: %s",
> + working_dir.GetCString());
> + return error;
> + }
> +
> + // Launch the inferior.
> + int pty_master_fd = -1;
> + LaunchFlavor launch_flavor = LaunchFlavor::Default;
> +
> + error = LaunchInferior(launch_info, &pty_master_fd, &launch_flavor);
> +
> + // Handle launch failure.
> + if (!error.Success())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() failed to launch
> process: "
> + "%s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> +
> + // Handle failure to return a pid.
> + if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() launch succeeded but
> no "
> + "pid was returned! Aborting.", __FUNCTION__);
> + return error;
> + }
> +
> + // Create the Darwin native process impl.
> + std::shared_ptr<NativeProcessDarwin>
> + np_darwin_sp(new NativeProcessDarwin(launch_info.GetProcessID(),
> + pty_master_fd));
> + if (!np_darwin_sp->RegisterNativeDelegate(native_delegate))
> + {
> + native_process_sp.reset ();
> + error.SetErrorStringWithFormat ("failed to register the native
> delegate");
> + return error;
> + }
> +
> + // Finalize the processing needed to debug the launched process with
> + // a NativeProcessDarwin instance.
> + error = np_darwin_sp->FinalizeLaunch(launch_flavor, mainloop);
> + if (!error.Success())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() aborting, failed to
> finalize"
> + " the launching of the process: %s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> +
> + // Return the process and process id to the caller through the launch
> args.
> + native_process_sp = np_darwin_sp;
> + return error;
> +}
> +
> +Error
> +NativeProcessProtocol::Attach(lldb::pid_t pid,
> + NativeProcessProtocol::NativeDelegate
> + &native_delegate,
> + MainLoop &mainloop,
> + NativeProcessProtocolSP &native_process_sp)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> + if (log)
> + log->Printf ("NativeProcessDarwin::%s(pid = %" PRIi64 ")",
> __FUNCTION__,
> + pid);
> +
> + // Retrieve the architecture for the running process.
> + ArchSpec process_arch;
> + Error error = ResolveProcessArchitecture(pid, process_arch);
> + if (!error.Success())
> + return error;
> +
> + // TODO get attach to return this value.
> + const int pty_master_fd = -1;
> + std::shared_ptr<NativeProcessDarwin> native_process_darwin_sp(
> + new NativeProcessDarwin(pid,
> pty_master_fd));
> +
> + if (!native_process_darwin_sp->RegisterNativeDelegate(native_
> delegate))
> + {
> + error.SetErrorStringWithFormat("failed to register the native "
> + "delegate");
> + return error;
> + }
> +
> + native_process_darwin_sp->AttachToInferior(mainloop, pid, error);
> + if (!error.Success())
> + return error;
> +
> + native_process_sp = native_process_darwin_sp;
> + return error;
> +}
> +
> +// ------------------------------------------------------------
> -----------------
> +// ctor/dtor
> +// ------------------------------------------------------------
> -----------------
> +
> +NativeProcessDarwin::NativeProcessDarwin(lldb::pid_t pid, int
> pty_master_fd) :
> + NativeProcessProtocol(pid),
> + m_task(TASK_NULL),
> + m_did_exec(false),
> + m_cpu_type(0),
> + m_exception_port(MACH_PORT_NULL),
> + m_exc_port_info(),
> + m_exception_thread(nullptr),
> + m_exception_messages_mutex(),
> + m_sent_interrupt_signo(0),
> + m_auto_resume_signo(0),
> + m_thread_list(),
> + m_thread_actions(),
> + m_waitpid_pipe(),
> + m_waitpid_thread(nullptr),
> + m_waitpid_reader_handle()
> +{
> + // TODO add this to the NativeProcessProtocol constructor.
> + m_terminal_fd = pty_master_fd;
> +}
> +
> +NativeProcessDarwin::~NativeProcessDarwin()
> +{
> +}
> +
> +// ------------------------------------------------------------
> -----------------
> +// Instance methods
> +// ------------------------------------------------------------
> -----------------
> +
> +Error
> +NativeProcessDarwin::FinalizeLaunch(LaunchFlavor launch_flavor,
> + MainLoop &main_loop)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> +#if 0
> + m_path = path;
> + size_t i;
> + char const *arg;
> + for (i=0; (arg = argv[i]) != NULL; i++)
> + m_args.push_back(arg);
> +#endif
> +
> + error = StartExceptionThread();
> + if (!error.Success())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failure starting the
> "
> + "mach exception port monitor thread: %s",
> + __FUNCTION__, error.AsCString());
> +
> + // Terminate the inferior process. There's nothing meaningful we
> can
> + // do if we can't receive signals and exceptions. Since we
> launched
> + // the process, it's fair game for us to kill it.
> + ::ptrace(PT_KILL, m_pid, 0, 0);
> + SetState(eStateExited);
> +
> + return error;
> + }
> +
> + StartSTDIOThread();
> +
> + if (launch_flavor == LaunchFlavor::PosixSpawn)
> + {
> + SetState(eStateAttaching);
> + errno = 0;
> + int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0);
> + if (err == 0)
> + {
> + // m_flags |= eMachProcessFlagsAttached;
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): successfully
> spawned "
> + "process with pid %" PRIu64, __FUNCTION__,
> m_pid);
> + }
> + else
> + {
> + error.SetErrorToErrno();
> + SetState(eStateExited);
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): error: failed to
> "
> + "attach to spawned pid %" PRIu64 " (error=%d
> (%s))",
> + __FUNCTION__, m_pid, (int)error.GetError(),
> + error.AsCString());
> + return error;
> + }
> + }
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): new pid is %" PRIu64
> "...",
> + __FUNCTION__, m_pid);
> +
> + // Spawn a thread to reap our child inferior process...
> + error = StartWaitpidThread(main_loop);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to start
> waitpid() "
> + "thread: %s", __FUNCTION__, error.AsCString());
> + kill(SIGKILL, static_cast<::pid_t>(m_pid));
> + return error;
> + }
> +
> + if (TaskPortForProcessID(error) == TASK_NULL)
> + {
> + // We failed to get the task for our process ID which is bad.
> + // Kill our process; otherwise, it will be stopped at the entry
> + // point and get reparented to someone else and never go away.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): could not get task
> port "
> + "for process, sending SIGKILL and exiting: %s",
> + __FUNCTION__, error.AsCString());
> + kill(SIGKILL, static_cast<::pid_t>(m_pid));
> + return error;
> + }
> +
> + // Indicate that we're stopped, as we always launch suspended.
> + SetState(eStateStopped);
> +
> + // Success.
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::SaveExceptionPortInfo()
> +{
> + return m_exc_port_info.Save(m_task);
> +}
> +
> +bool
> +NativeProcessDarwin::ProcessUsingSpringBoard() const
> +{
> + // TODO implement flags
> + // return (m_flags & eMachProcessFlagsUsingSBS) != 0;
> + return false;
> +}
> +
> +bool
> +NativeProcessDarwin::ProcessUsingBackBoard() const
> +{
> + // TODO implement flags
> + // return (m_flags & eMachProcessFlagsUsingBKS) != 0;
> + return false;
> +}
> +
> +// Called by the exception thread when an exception has been received from
> +// our process. The exception message is completely filled and the
> exception
> +// data has already been copied.
> +void
> +NativeProcessDarwin::ExceptionMessageReceived(const
> MachException::Message&
> + message)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_
> mutex);
> + if (m_exception_messages.empty())
> + {
> + // Suspend the task the moment we receive our first exception
> message.
> + SuspendTask();
> + }
> +
> + // Use a locker to automatically unlock our mutex in case of
> exceptions
> + // Add the exception to our internal exception stack
> + m_exception_messages.push_back(message);
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): new queued message
> count: %lu",
> + __FUNCTION__, m_exception_messages.size());
> +}
> +
> +void*
> +NativeProcessDarwin::ExceptionThread(void *arg)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (!arg)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): cannot run mach
> exception "
> + "thread, mandatory process arg was null",
> __FUNCTION__);
> + return nullptr;
> + }
> +
> + return reinterpret_cast<NativeProcessDarwin*>(arg)->
> DoExceptionThread();
> +}
> +
> +void*
> +NativeProcessDarwin::DoExceptionThread()
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(arg=%p) starting thread...",
> + __FUNCTION__, this);
> +
> + pthread_setname_np("exception monitoring thread");
> +
> + // Ensure we don't get CPU starved.
> + MaybeRaiseThreadPriority();
> +
> + // We keep a count of the number of consecutive exceptions received so
> + // we know to grab all exceptions without a timeout. We do this to
> get a
> + // bunch of related exceptions on our exception port so we can process
> + // then together. When we have multiple threads, we can get an
> exception
> + // per thread and they will come in consecutively. The main loop in
> this
> + // thread can stop periodically if needed to service things related
> to this
> + // process.
> + //
> + // [did we lose some words here?]
> + //
> + // flag set in the options, so we will wait forever for an exception
> on
> + //0 our exception port. After we get one exception, we then will use
> the
> + // MACH_RCV_TIMEOUT option with a zero timeout to grab all other
> current
> + // exceptions for our process. After we have received the last pending
> + // exception, we will get a timeout which enables us to then notify
> + // our main thread that we have an exception bundle available. We
> then wait
> + // for the main thread to tell this exception thread to start trying
> to get
> + // exceptions messages again and we start again with a mach_msg read
> with
> + // infinite timeout.
> + //
> + // We choose to park a thread on this, rather than polling, because
> the
> + // polling is expensive. On devices, we need to minimize overhead
> caused
> + // by the process monitor.
> + uint32_t num_exceptions_received = 0;
> + Error error;
> + task_t task = m_task;
> + mach_msg_timeout_t periodic_timeout = 0;
> +
> +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
> + mach_msg_timeout_t watchdog_elapsed = 0;
> + mach_msg_timeout_t watchdog_timeout = 60 * 1000;
> + ::pid_t pid = (::pid_t)process->GetID();
> + CFReleaser<SBSWatchdogAssertionRef> watchdog;
> +
> + if (process->ProcessUsingSpringBoard())
> + {
> + // Request a renewal for every 60 seconds if we attached using
> + // SpringBoard.
> + watchdog.reset(::SBSWatchdogAssertionCreateForPID(nullptr, pid,
> 60));
> + if (log)
> + log->Printf("::SBSWatchdogAssertionCreateForPID(NULL, %4.4x,
> 60) "
> + "=> %p", pid, watchdog.get());
> +
> + if (watchdog.get())
> + {
> + ::SBSWatchdogAssertionRenew (watchdog.get());
> +
> + CFTimeInterval watchdogRenewalInterval =
> + ::SBSWatchdogAssertionGetRenewalInterval
> (watchdog.get());
> + if (log)
> + log->Printf("::SBSWatchdogAssertionGetRenewalInterval(%p)
> => "
> + "%g seconds", watchdog.get(),
> + watchdogRenewalInterval);
> + if (watchdogRenewalInterval > 0.0)
> + {
> + watchdog_timeout =
> + (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
> + if (watchdog_timeout > 3000)
> + {
> + // Give us a second to renew our timeout.
> + watchdog_timeout -= 1000;
> + }
> + else if (watchdog_timeout > 1000)
> + {
> + // Give us a quarter of a second to renew our timeout.
> + watchdog_timeout -= 250;
> + }
> + }
> + }
> + if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
> + periodic_timeout = watchdog_timeout;
> + }
> +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
> +
> +#ifdef WITH_BKS
> + CFReleaser<BKSWatchdogAssertionRef> watchdog;
> + if (process->ProcessUsingBackBoard())
> + {
> + ::pid_t pid = process->GetID();
> + CFAllocatorRef alloc = kCFAllocatorDefault;
> + watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid));
> + }
> +#endif // #ifdef WITH_BKS
> +
> + // Do we want to use a weak pointer to the NativeProcessDarwin here,
> in
> + // which case we can guarantee we don't whack the process monitor if
> we
> + // race between this thread and the main one on shutdown?
> + while (IsExceptionPortValid())
> + {
> + ::pthread_testcancel();
> +
> + MachException::Message exception_message;
> +
> + if (num_exceptions_received > 0)
> + {
> + // We don't want a timeout here, just receive as many
> exceptions as
> + // we can since we already have one. We want to get all
> currently
> + // available exceptions for this task at once.
> + error = exception_message.Receive(GetExceptionPort(),
> + MACH_RCV_MSG |
> MACH_RCV_INTERRUPT
> + | MACH_RCV_TIMEOUT, 0);
> + }
> + else if (periodic_timeout > 0)
> + {
> + // We need to stop periodically in this loop, so try and get
> a mach
> + // message with a valid timeout (ms).
> + error = exception_message.Receive(GetExceptionPort(),
> + MACH_RCV_MSG |
> MACH_RCV_INTERRUPT
> + | MACH_RCV_TIMEOUT,
> + periodic_timeout);
> + }
> + else
> + {
> + // We don't need to parse all current exceptions or stop
> + // periodically, just wait for an exception forever.
> + error = exception_message.Receive(GetExceptionPort(),
> + MACH_RCV_MSG |
> MACH_RCV_INTERRUPT,
> + 0);
> + }
> +
> + if (error.Success())
> + {
> + // We successfully received an exception.
> + if (exception_message.CatchExceptionRaise(task))
> + {
> + ++num_exceptions_received;
> + ExceptionMessageReceived(exception_message);
> + }
> + }
> + else
> + {
> + if (error.GetError() == MACH_RCV_INTERRUPTED)
> + {
> + // We were interrupted.
> +
> + // If we have no task port we should exit this thread, as
> it implies
> + // the inferior went down.
> + if (!IsExceptionPortValid())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): the
> inferior "
> + "exception port is no longer valid, "
> + "canceling exception thread...",
> __FUNCTION__);
> + // Should we be setting a process state here?
> + break;
> + }
> +
> + // Make sure the inferior task is still valid.
> + if (IsTaskValid())
> + {
> + // Task is still ok.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s():
> interrupted, but "
> + "the inferior task iss till valid, "
> + "continuing...", __FUNCTION__);
> + continue;
> + }
> + else
> + {
> + // The inferior task is no longer valid. Time to
> exit as
> + // the process has gone away.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): the
> inferior task "
> + "has exited, and so will we...",
> __FUNCTION__);
> + // Does this race at all with our waitpid()?
> + SetState(eStateExited);
> + break;
> + }
> + }
> + else if (error.GetError() == MACH_RCV_TIMED_OUT)
> + {
> + // We timed out when waiting for exceptions.
> +
> + if (num_exceptions_received > 0)
> + {
> + // We were receiving all current exceptions with a
> timeout of
> + // zero. It is time to go back to our normal looping
> mode.
> + num_exceptions_received = 0;
> +
> + // Notify our main thread we have a complete
> exception message
> + // bundle available. Get the possibly updated task
> port back
> + // from the process in case we exec'ed and our task
> port
> + // changed.
> + task = ExceptionMessageBundleComplete();
> +
> + // In case we use a timeout value when getting
> exceptions,
> + // make sure our task is still valid.
> + if (IsTaskValid(task))
> + {
> + // Task is still ok.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): got
> a timeout, "
> + "continuing...", __FUNCTION__);
> + continue;
> + }
> + else
> + {
> + // The inferior task is no longer valid. Time to
> exit as
> + // the process has gone away.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): the
> inferior "
> + "task has exited, and so will
> we...",
> + __FUNCTION__);
> + // Does this race at all with our waitpid()?
> + SetState(eStateExited);
> + break;
> + }
> + }
> +
> +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
> + if (watchdog.get())
> + {
> + watchdog_elapsed += periodic_timeout;
> + if (watchdog_elapsed >= watchdog_timeout)
> + {
> + if (log)
> + log->Printf("SBSWatchdogAssertionRenew(%p)",
> + watchdog.get());
> + ::SBSWatchdogAssertionRenew (watchdog.get());
> + watchdog_elapsed = 0;
> + }
> + }
> +#endif
> + }
> + else
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): continuing
> after "
> + "receiving an unexpected error: %u (%s)",
> + __FUNCTION__, error.GetError(),
> error.AsCString());
> + // TODO: notify of error?
> + }
> + }
> + }
> +
> +#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
> + if (watchdog.get())
> + {
> + // TODO: change SBSWatchdogAssertionRelease to
> SBSWatchdogAssertionCancel when we
> + // all are up and running on systems that support it. The SBS
> framework has a #define
> + // that will forward SBSWatchdogAssertionRelease to
> SBSWatchdogAssertionCancel for now
> + // so it should still build either way.
> + DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)",
> watchdog.get());
> + ::SBSWatchdogAssertionRelease (watchdog.get());
> + }
> +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS)
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(%p): thread exiting...",
> + __FUNCTION__, this);
> + return nullptr;
> +}
> +
> +Error
> +NativeProcessDarwin::StartExceptionThread()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__);
> +
> + // Make sure we've looked up the inferior port.
> + TaskPortForProcessID(error);
> +
> + // Ensure the inferior task is valid.
> + if (!IsTaskValid())
> + {
> + error.SetErrorStringWithFormat("cannot start exception thread: "
> + "task 0x%4.4x is not valid",
> m_task);
> + return error;
> + }
> +
> + // Get the mach port for the process monitor.
> + mach_port_t task_self = mach_task_self();
> +
> + // Allocate an exception port that we will use to track our child
> process
> + auto mach_err = ::mach_port_allocate(task_self,
> MACH_PORT_RIGHT_RECEIVE,
> + &m_exception_port);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): mach_port_allocate("
> + "task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, "
> + "&m_exception_port) failed: %u (%s)",
> __FUNCTION__,
> + task_self, error.GetError(), error.AsCString());
> + return error;
> + }
> +
> + // Add the ability to send messages on the new exception port
> + mach_err = ::mach_port_insert_right(task_self, m_exception_port,
> + m_exception_port,
> MACH_MSG_TYPE_MAKE_SEND);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s():
> mach_port_insert_right("
> + "task_self=0x%4.4x, m_exception_port=0x%4.4x, "
> + "m_exception_port=0x%4.4x,
> MACH_MSG_TYPE_MAKE_SEND) "
> + "failed: %u (%s)", __FUNCTION__,
> + task_self, m_exception_port, m_exception_port,
> + error.GetError(), error.AsCString());
> + return error;
> + }
> +
> + // Save the original state of the exception ports for our child
> process.
> + error = SaveExceptionPortInfo();
> + if (error.Fail() || (m_exc_port_info.mask == 0))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s():
> SaveExceptionPortInfo() "
> + "failed, cannot install exception handler: %s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> +
> + // Set the ability to get all exceptions on this port.
> + mach_err = ::task_set_exception_ports(m_task, m_exc_port_info.mask,
> + m_exception_port,
> + EXCEPTION_DEFAULT |
> + MACH_EXCEPTION_CODES,
> + THREAD_STATE_NONE);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("::task_set_exception_ports (task = 0x%4.4x, "
> + "exception_mask = 0x%8.8x, new_port = 0x%4.4x, "
> + "behavior = 0x%8.8x, new_flavor = 0x%8.8x)
> failed: "
> + "%u (%s)", m_task, m_exc_port_info.mask,
> + m_exception_port, (EXCEPTION_DEFAULT |
> + MACH_EXCEPTION_CODES),
> + THREAD_STATE_NONE, error.GetError(),
> + error.AsCString());
> + return error;
> + }
> +
> + // Create the exception thread.
> + auto pthread_err = ::pthread_create(&m_exception_thread, nullptr,
> + ExceptionThread, this);
> + error.SetError(pthread_err, eErrorTypePOSIX);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to create
> Mach "
> + "exception-handling thread: %u (%s)",
> __FUNCTION__,
> + error.GetError(), error.AsCString());
> + }
> +
> + return error;
> +}
> +
> +lldb::addr_t
> +NativeProcessDarwin::GetDYLDAllImageInfosAddress(Error &error) const
> +{
> + error.Clear();
> +
> + struct hack_task_dyld_info dyld_info;
> + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
> + // Make sure that COUNT isn't bigger than our hacked up struct
> + // hack_task_dyld_info. If it is, then make COUNT smaller to match.
> + if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)))
> + {
> + count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t));
> + }
> +
> + TaskPortForProcessID(error);
> + if (error.Fail())
> + return LLDB_INVALID_ADDRESS;
> +
> + auto mach_err = ::task_info(m_task, TASK_DYLD_INFO,
> (task_info_t)&dyld_info,
> + &count);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Success())
> + {
> + // We now have the address of the all image infos structure.
> + return dyld_info.all_image_info_addr;
> + }
> +
> + // We don't have it.
> + return LLDB_INVALID_ADDRESS;
> +}
> +
> +uint32_t
> +NativeProcessDarwin::GetCPUTypeForLocalProcess(::pid_t pid)
> +{
> + int mib[CTL_MAXNAME] = {0, };
> + size_t len = CTL_MAXNAME;
> +
> + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
> + return 0;
> +
> + mib[len] = pid;
> + len++;
> +
> + cpu_type_t cpu;
> + size_t cpu_len = sizeof(cpu);
> + if (::sysctl (mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
> + cpu = 0;
> + return cpu;
> +}
> +
> +uint32_t
> +NativeProcessDarwin::GetCPUType() const
> +{
> + if (m_cpu_type == 0 && m_pid != 0)
> + m_cpu_type = GetCPUTypeForLocalProcess(m_pid);
> + return m_cpu_type;
> +}
> +
> +task_t
> +NativeProcessDarwin::ExceptionMessageBundleComplete()
> +{
> + // We have a complete bundle of exceptions for our child process.
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_
> mutex);
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): processing %lu exception
> "
> + "messages.", __FUNCTION__,
> m_exception_messages.size());
> +
> + if (m_exception_messages.empty())
> + {
> + // Not particularly useful...
> + return m_task;
> + }
> +
> + bool auto_resume = false;
> + m_did_exec = false;
> +
> + // First check for any SIGTRAP and make sure we didn't exec
> + const task_t task = m_task;
> + size_t i;
> + if (m_pid != 0)
> + {
> + bool received_interrupt = false;
> + uint32_t num_task_exceptions = 0;
> + for (i = 0; i < m_exception_messages.size(); ++i)
> + {
> + if (m_exception_messages[i].state.task_port != task)
> + {
> + // This is an exception that is not for our inferior,
> ignore.
> + continue;
> + }
> +
> + // This is an exception for the inferior.
> + ++num_task_exceptions;
> + const int signo = m_exception_messages[i].state.SoftSignal();
> + if (signo == SIGTRAP)
> + {
> + // SIGTRAP could mean that we exec'ed. We need to check
> the
> + // dyld all_image_infos.infoArray to see if it is NULL
> and if
> + // so, say that we exec'ed.
> + const addr_t aii_addr =
> + GetDYLDAllImageInfosAddress(error);
> + if (aii_addr == LLDB_INVALID_ADDRESS)
> + break;
> +
> + const addr_t info_array_count_addr = aii_addr + 4;
> + uint32_t info_array_count = 0;
> + size_t bytes_read = 0;
> + Error read_error;
> + read_error = ReadMemory(info_array_count_addr, //
> source addr
> + &info_array_count, // dest
> addr
> + 4, // byte
> count
> + bytes_read); //
> #bytes read
> + if (read_error.Success() && (bytes_read == 4))
> + {
> + if (info_array_count == 0)
> + {
> + // We got the all infos address, and there are
> zero
> + // entries. We think we exec'd.
> + m_did_exec = true;
> +
> + // Force the task port to update itself in case
> the
> + // task port changed after exec
> + const task_t old_task = m_task;
> + const bool force_update = true;
> + const task_t new_task =
> + TaskPortForProcessID(error, force_update);
> + if (old_task != new_task)
> + {
> + if (log)
> + log->Printf("exec: inferior task port
> changed "
> + "from 0x%4.4x to 0x%4.4x",
> old_task,
> + new_task);
> + }
> + }
> + }
> + else
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() warning: "
> + "failed to read all_image_infos."
> + "infoArrayCount from 0x%8.8llx",
> + __FUNCTION__, info_array_count_addr);
> + }
> + }
> + else if ((m_sent_interrupt_signo != 0) &&
> + (signo == m_sent_interrupt_signo))
> + {
> + // We just received the interrupt that we sent to
> ourselves.
> + received_interrupt = true;
> + }
> + }
> +
> + if (m_did_exec)
> + {
> + cpu_type_t process_cpu_type = GetCPUTypeForLocalProcess(m_
> pid);
> + if (m_cpu_type != process_cpu_type)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): arch changed
> from "
> + "0x%8.8x to 0x%8.8x", __FUNCTION__,
> m_cpu_type,
> + process_cpu_type);
> + m_cpu_type = process_cpu_type;
> + // TODO figure out if we need to do something here.
> + // DNBArchProtocol::SetArchitecture (process_cpu_type);
> + }
> + m_thread_list.Clear();
> +
> + // TODO hook up breakpoints.
> + // m_breakpoints.DisableAll();
> + }
> +
> + if (m_sent_interrupt_signo != 0)
> + {
> + if (received_interrupt)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): process "
> + "successfully interrupted with signal %i",
> + __FUNCTION__, m_sent_interrupt_signo);
> +
> + // Mark that we received the interrupt signal
> + m_sent_interrupt_signo = 0;
> + // Now check if we had a case where:
> + // 1 - We called NativeProcessDarwin::Interrupt() but we
> stopped
> + // for another reason.
> + // 2 - We called NativeProcessDarwin::Resume() (but still
> + // haven't gotten the interrupt signal).
> + // 3 - We are now incorrectly stopped because we are
> handling
> + // the interrupt signal we missed.
> + // 4 - We might need to resume if we stopped only with the
> + // interrupt signal that we never handled.
> + if (m_auto_resume_signo != 0)
> + {
> + // Only auto_resume if we stopped with _only_ the
> interrupt
> + // signal.
> + if (num_task_exceptions == 1)
> + {
> + auto_resume = true;
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): auto
> "
> + "resuming due to unhandled
> interrupt "
> + "signal %i", __FUNCTION__,
> + m_auto_resume_signo);
> + }
> + m_auto_resume_signo = 0;
> + }
> + }
> + else
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): didn't get
> signal "
> + "%i after MachProcess::Interrupt()",
> + __FUNCTION__, m_sent_interrupt_signo);
> + }
> + }
> + }
> +
> + // Let all threads recover from stopping and do any clean up based
> + // on the previous thread state (if any).
> + m_thread_list.ProcessDidStop(*this);
> +
> + // Let each thread know of any exceptions
> + for (i = 0; i < m_exception_messages.size(); ++i)
> + {
> + // Let the thread list forward all exceptions on down to each
> thread.
> + if (m_exception_messages[i].state.task_port == task)
> + {
> + // This exception is for our inferior.
> + m_thread_list.NotifyException(m_exception_messages[i].state);
> + }
> +
> + if (log)
> + {
> + StreamString stream;
> + m_exception_messages[i].Dump(stream);
> + stream.Flush();
> + log->PutCString(stream.GetString().c_str());
> + }
> + }
> +
> + if (log)
> + {
> + StreamString stream;
> + m_thread_list.Dump(stream);
> + stream.Flush();
> + log->PutCString(stream.GetString().c_str());
> + }
> +
> + bool step_more = false;
> + if (m_thread_list.ShouldStop(step_more) && (auto_resume == false))
> + {
> + // TODO - need to hook up event system here. !!!!
> +#if 0
> + // Wait for the eEventProcessRunningStateChanged event to be
> reset
> + // before changing state to stopped to avoid race condition with
> + // very fast start/stops.
> + struct timespec timeout;
> +
> + //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait
> for 250 ms
> + DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms
> + m_events.WaitForEventsToReset(eEventProcessRunningStateChanged,
> + &timeout);
> +#endif
> + SetState(eStateStopped);
> + }
> + else
> + {
> + // Resume without checking our current state.
> + PrivateResume();
> + }
> +
> + return m_task;
> +}
> +
> +void
> +NativeProcessDarwin::StartSTDIOThread()
> +{
> + // TODO implement
> +}
> +
> +Error
> +NativeProcessDarwin::StartWaitpidThread(MainLoop &main_loop)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + // Strategy: create a thread that sits on waitpid(), waiting for the
> + // inferior process to die, reaping it in the process. Arrange for
> + // the thread to have a pipe file descriptor that it can send a byte
> + // over when the waitpid completes. Have the main loop have a read
> + // object for the other side of the pipe, and have the callback for
> + // the read do the process termination message sending.
> +
> + // Create a single-direction communication channel.
> + const bool child_inherits = false;
> + error = m_waitpid_pipe.CreateNew(child_inherits);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to create
> waitpid "
> + "communication pipe: %s", __FUNCTION__,
> + error.AsCString());
> + return error;
> + }
> +
> + // Hook up the waitpid reader callback.
> +
> + // TODO make PipePOSIX derive from IOObject. This is goofy here.
> + const bool transfer_ownership = false;
> + auto io_sp = IOObjectSP(new File(m_waitpid_pipe.
> GetReadFileDescriptor(),
> + transfer_ownership));
> + m_waitpid_reader_handle =
> + main_loop.RegisterReadObject(
> + io_sp,
> + [this](MainLoopBase &){ HandleWaitpidResult();
> },
> + error);
> +
> + // Create the thread.
> + auto pthread_err = ::pthread_create(&m_waitpid_thread, nullptr,
> + WaitpidThread, this);
> + error.SetError(pthread_err, eErrorTypePOSIX);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to create
> waitpid "
> + "handling thread: %u (%s)", __FUNCTION__,
> + error.GetError(), error.AsCString());
> + return error;
> + }
> +
> + return error;
> +}
> +
> +void*
> +NativeProcessDarwin::WaitpidThread(void *arg)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> + if (!arg)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): cannot run waitpid "
> + "thread, mandatory process arg was null",
> __FUNCTION__);
> + return nullptr;
> + }
> +
> + return reinterpret_cast<NativeProcessDarwin*>(arg)->
> DoWaitpidThread();
> +}
> +
> +void
> +NativeProcessDarwin::MaybeRaiseThreadPriority()
> +{
> +#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
> + struct sched_param thread_param;
> + int thread_sched_policy;
> + if (pthread_getschedparam(pthread_self(), &thread_sched_policy,
> + &thread_param) == 0)
> + {
> + thread_param.sched_priority = 47;
> + pthread_setschedparam(pthread_self(), thread_sched_policy,
> + &thread_param);
> + }
> +#endif
> +}
> +
> +void*
> +NativeProcessDarwin::DoWaitpidThread()
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + if (m_pid == LLDB_INVALID_PROCESS_ID)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): inferior process ID
> is "
> + "not set, cannot waitpid on it", __FUNCTION__);
> + return nullptr;
> + }
> +
> + // Name the thread.
> + pthread_setname_np("waitpid thread");
> +
> + // Ensure we don't get CPU starved.
> + MaybeRaiseThreadPriority();
> +
> + Error error;
> + int status = -1;
> +
> + while (1)
> + {
> + // Do a waitpid.
> + ::pid_t child_pid = ::waitpid(m_pid, &status, 0);
> + if (child_pid < 0)
> + error.SetErrorToErrno();
> + if (error.Fail())
> + {
> + if (error.GetError() == EINTR)
> + {
> + // This is okay, we can keep going.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): waitpid(pid
> = %"
> + PRIu64 ", &status, 0) interrupted,
> continuing",
> + __FUNCTION__, m_pid);
> + continue;
> + }
> +
> + // This error is not okay, abort.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %"
> PRIu64
> + ", &status, 0) aborting due to error: %u
> (%s)",
> + __FUNCTION__, m_pid, error.GetError(),
> + error.AsCString());
> + break;
> + }
> +
> + // Log the successful result.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %"
> PRIu64
> + ", &status, 0) => %i, status = %i",
> __FUNCTION__,
> + m_pid, child_pid, status);
> +
> + // Handle the result.
> + if (WIFSTOPPED(status))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): waitpid(pid = %"
> PRIu64
> + ") received a stop, continuing waitpid()
> loop",
> + __FUNCTION__, m_pid);
> + continue;
> + }
> + else // if (WIFEXITED(status) || WIFSIGNALED(status))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(pid = %" PRIu64 "):
> "
> + "waitpid thread is setting exit status for
> pid = "
> + "%i to %i", __FUNCTION__, m_pid,
> + child_pid, status);
> +
> + error = SendInferiorExitStatusToMainLoop(child_pid, status);
> + return nullptr;
> + }
> + }
> +
> + // We should never exit as long as our child process is alive. If we
> + // get here, something completely unexpected went wrong and we should
> exit.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): internal error: waitpid
> thread "
> + "exited out of its main loop in an unexpected way.
> pid = %"
> + PRIu64 ". Sending exit status of -1.", __FUNCTION__,
> m_pid);
> +
> + error = SendInferiorExitStatusToMainLoop((::pid_t)m_pid, -1);
> + return nullptr;
> +}
> +
> +Error
> +NativeProcessDarwin::SendInferiorExitStatusToMainLoop(::pid_t pid, int
> status)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + size_t bytes_written = 0;
> +
> + // Send the pid.
> + error = m_waitpid_pipe.Write(&pid, sizeof(pid), bytes_written);
> + if (error.Fail() || (bytes_written < sizeof(pid)))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() - failed to write "
> + "waitpid exiting pid to the pipe. Client will
> not "
> + "hear about inferior exit status!",
> + __FUNCTION__);
> + return error;
> + }
> +
> + // Send the status.
> + bytes_written = 0;
> + error = m_waitpid_pipe.Write(&status, sizeof(status), bytes_written);
> + if (error.Fail() || (bytes_written < sizeof(status)))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() - failed to write "
> + "waitpid exit result to the pipe. Client will
> not "
> + "hear about inferior exit status!",
> + __FUNCTION__);
> + }
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::HandleWaitpidResult()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + // Read the pid.
> + const bool notify_status = true;
> +
> + ::pid_t pid = -1;
> + size_t bytes_read = 0;
> + error = m_waitpid_pipe.Read(&pid, sizeof(pid), bytes_read);
> + if (error.Fail() || (bytes_read < sizeof(pid)))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() - failed to read "
> + "waitpid exiting pid from the pipe. Will notify "
> + "as if parent process died with exit status -1.",
> + __FUNCTION__);
> + SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid
> result",
> + notify_status);
> + return error;
> + }
> +
> + // Read the status.
> + int status = -1;
> + error = m_waitpid_pipe.Read(&status, sizeof(status), bytes_read);
> + if (error.Fail() || (bytes_read < sizeof(status)))
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() - failed to read "
> + "waitpid exit status from the pipe. Will notify "
> + "as if parent process died with exit status -1.",
> + __FUNCTION__);
> + SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid
> result",
> + notify_status);
> + return error;
> + }
> +
> + // Notify the monitor that our state has changed.
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): main loop received
> waitpid "
> + "exit status info: pid=%i (%s), status=%i",
> + __FUNCTION__, pid,
> + (pid == m_pid) ? "the inferior" : "not the inferior",
> + status);
> +
> + ExitType exit_type = eExitTypeInvalid;
> + int exit_status = -1;
> +
> + if (WIFEXITED(status))
> + {
> + exit_type = eExitTypeExit;
> + exit_status = WEXITSTATUS(status);
> + }
> + else if (WIFSIGNALED(status))
> + {
> + exit_type = eExitTypeSignal;
> + exit_status = WTERMSIG(status);
> + }
> +
> + SetExitStatus(exit_type, exit_status, nullptr, notify_status);
> + return error;
> +}
> +
> +task_t
> +NativeProcessDarwin::TaskPortForProcessID(Error &error, bool force) const
> +{
> + if ((m_task == TASK_NULL) || force)
> + {
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> + if (m_pid == LLDB_INVALID_PROCESS_ID)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): cannot get task
> due "
> + "to invalid pid", __FUNCTION__);
> + return TASK_NULL;
> + }
> +
> + const uint32_t num_retries = 10;
> + const uint32_t usec_interval = 10000;
> +
> + mach_port_t task_self = mach_task_self();
> + task_t task = TASK_NULL;
> +
> + for (uint32_t i = 0; i < num_retries; i++)
> + {
> + kern_return_t err = ::task_for_pid(task_self, m_pid, &task);
> + if (err == 0)
> + {
> + // Succeeded. Save and return it.
> + error.Clear();
> + m_task = task;
> + log->Printf("NativeProcessDarwin::%s(): ::task_for_pid("
> + "stub_port = 0x%4.4x, pid = %llu, &task) "
> + "succeeded: inferior task port = 0x%4.4x",
> + __FUNCTION__, task_self, m_pid, m_task);
> + return m_task;
> + }
> + else
> + {
> + // Failed to get the task for the inferior process.
> + error.SetError(err, eErrorTypeMachKernel);
> + if (log)
> + {
> + log->Printf("NativeProcessDarwin::%s():
> ::task_for_pid("
> + "stub_port = 0x%4.4x, pid = %llu, &task) "
> + "failed, err = 0x%8.8x (%s)",
> + __FUNCTION__, task_self,
> + m_pid,
> + err,
> + error.AsCString());
> + }
> + }
> +
> + // Sleep a bit and try again
> + ::usleep (usec_interval);
> + }
> +
> + // We failed to get the task for the inferior process.
> + // Ensure that it is cleared out.
> + m_task = TASK_NULL;
> + }
> + return m_task;
> +}
> +
> +void
> +NativeProcessDarwin::AttachToInferior(MainLoop &mainloop, lldb::pid_t
> pid,
> + Error &error)
> +{
> + error.SetErrorString("TODO: implement");
> +}
> +
> +Error
> +NativeProcessDarwin::PrivateResume()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_
> mutex);
> + m_auto_resume_signo = m_sent_interrupt_signo;
> +
> + if (log)
> + {
> + if (m_auto_resume_signo)
> + log->Printf("NativeProcessDarwin::%s(): task 0x%x resuming
> (with "
> + "unhandled interrupt signal %i)...", __FUNCTION__,
> + m_task, m_auto_resume_signo);
> + else
> + log->Printf("NativeProcessDarwin::%s(): task 0x%x
> resuming...",
> + __FUNCTION__, m_task);
> + }
> +
> + error = ReplyToAllExceptions();
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): aborting, failed to "
> + "reply to exceptions: %s", __FUNCTION__,
> + error.AsCString());
> + return error;
> + }
> + // bool stepOverBreakInstruction = step;
> +
> + // Let the thread prepare to resume and see if any threads want us to
> + // step over a breakpoint instruction (ProcessWillResume will modify
> + // the value of stepOverBreakInstruction).
> + m_thread_list.ProcessWillResume(*this, m_thread_actions);
> +
> + // Set our state accordingly
> + if (m_thread_actions.NumActionsWithState(eStateStepping))
> + SetState(eStateStepping);
> + else
> + SetState(eStateRunning);
> +
> + // Now resume our task.
> + error = ResumeTask();
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::ReplyToAllExceptions()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> +
> + TaskPortForProcessID(error);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): no task port,
> aborting",
> + __FUNCTION__);
> + return error;
> + }
> +
> + std::lock_guard<std::recursive_mutex> locker(m_exception_messages_
> mutex);
> + if (m_exception_messages.empty())
> + {
> + // We're done.
> + return error;
> + }
> +
> + size_t index = 0;
> + for (auto &message : m_exception_messages)
> + {
> + if (log)
> + {
> + log->Printf("NativeProcessDarwin::%s(): replying to
> exception "
> + "%zu...", __FUNCTION__, index++);
> + }
> +
> + int thread_reply_signal = 0;
> +
> + const tid_t tid =
> + m_thread_list.GetThreadIDByMachPortNumber(message.state
> + .thread_port);
> + const ResumeAction *action = nullptr;
> + if (tid != LLDB_INVALID_THREAD_ID)
> + action = m_thread_actions.GetActionForThread (tid, false);
> +
> + if (action)
> + {
> + thread_reply_signal = action->signal;
> + if (thread_reply_signal)
> + m_thread_actions.SetSignalHandledForThread(tid);
> + }
> +
> + error = message.Reply(m_pid, m_task, thread_reply_signal);
> + if (error.Fail() && log)
> + {
> + // We log any error here, but we don't stop the exception
> + // response handling.
> + log->Printf("NativeProcessDarwin::%s(): failed to reply to "
> + "exception: %s", __FUNCTION__, error.AsCString());
> + error.Clear();
> + }
> + }
> +
> + // Erase all exception message as we should have used and replied
> + // to them all already.
> + m_exception_messages.clear();
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::ResumeTask()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + TaskPortForProcessID(error);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to get task
> port "
> + "for process when attempting to resume: %s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> + if (m_task == TASK_NULL)
> + {
> + error.SetErrorString("task port retrieval succeeded but task port
> is "
> + "null when attempting to resume the task");
> + return error;
> + }
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): requesting resume of
> task "
> + "0x%4.4x", __FUNCTION__, m_task);
> +
> + // Get the BasicInfo struct to verify that we're suspended before we
> try
> + // to resume the task.
> + struct task_basic_info task_info;
> + error = GetTaskBasicInfo(m_task, &task_info);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): failed to get task "
> + "BasicInfo when attempting to resume: %s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> +
> + // task_resume isn't counted like task_suspend calls are, so if the
> + // task is not suspended, don't try and resume it since it is already
> + // running
> + if (task_info.suspend_count > 0)
> + {
> + auto mach_err = ::task_resume(m_task);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (log)
> + {
> + if (error.Success())
> + log->Printf("::task_resume(target_task = 0x%4.4x):
> success",
> + m_task);
> + else
> + log->Printf("::task_resume(target_task = 0x%4.4x) error:
> %s",
> + m_task, error.AsCString());
> + }
> + }
> + else
> + {
> + if (log)
> + log->Printf("::task_resume(target_task = 0x%4.4x): ignored, "
> + "already running", m_task);
> + }
> +
> + return error;
> +}
> +
> +bool
> +NativeProcessDarwin::IsTaskValid() const
> +{
> + if (m_task == TASK_NULL)
> + return false;
> +
> + struct task_basic_info task_info;
> + return GetTaskBasicInfo(m_task, &task_info).Success();
> +}
> +
> +bool
> +NativeProcessDarwin::IsTaskValid(task_t task) const
> +{
> + if (task == TASK_NULL)
> + return false;
> +
> + struct task_basic_info task_info;
> + return GetTaskBasicInfo(task, &task_info).Success();
> +}
> +
> +mach_port_t
> +NativeProcessDarwin::GetExceptionPort() const
> +{
> + return m_exception_port;
> +}
> +
> +bool
> +NativeProcessDarwin::IsExceptionPortValid () const
> +{
> + return MACH_PORT_VALID(m_exception_port);
> +}
> +
> +Error
> +NativeProcessDarwin::GetTaskBasicInfo(task_t task,
> + struct task_basic_info *info) const
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + // Validate args.
> + if (info == NULL)
> + {
> + error.SetErrorStringWithFormat("NativeProcessDarwin::%s():
> mandatory "
> + "info arg is null", __FUNCTION__);
> + return error;
> + }
> +
> + // Grab the task if we don't already have it.
> + if (task == TASK_NULL)
> + {
> + error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): given
> task "
> + "is invalid", __FUNCTION__);
> + }
> +
> + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
> + auto err = ::task_info(m_task, TASK_BASIC_INFO, (task_info_t)info,
> &count);
> + error.SetError(err, eErrorTypeMachKernel);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("::task_info(target_task = 0x%4.4x, "
> + "flavor = TASK_BASIC_INFO, task_info_out => %p, "
> + "task_info_outCnt => %u) failed: %u (%s)",
> m_task, info,
> + count, error.GetError(), error.AsCString());
> + return error;
> + }
> +
> + Log *verbose_log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS |
> + LIBLLDB_LOG_VERBOSE));
> + if (verbose_log)
> + {
> + float user = (float)info->user_time.seconds +
> + (float)info->user_time.microseconds / 1000000.0f;
> + float system = (float)info->user_time.seconds +
> + (float)info->user_time.microseconds / 1000000.0f;
> + verbose_log->Printf("task_basic_info = { suspend_count = %i, "
> + "virtual_size = 0x%8.8llx, resident_size = "
> + "0x%8.8llx, user_time = %f, system_time = %f
> }",
> + info->suspend_count,
> + (uint64_t)info->virtual_size,
> + (uint64_t)info->resident_size,
> + user, system);
> + }
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::SuspendTask()
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + if (m_task == TASK_NULL)
> + {
> + error.SetErrorString("task port is null, cannot suspend task");
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() failed: %s",
> + __FUNCTION__, error.AsCString());
> + return error;
> + }
> +
> + auto mach_err = ::task_suspend(m_task);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Fail() && log)
> + log->Printf("::task_suspend(target_task = 0x%4.4x)", m_task);
> +
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Resume(const ResumeActionList &resume_actions)
> +{
> + Error error;
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
> +
> + if (log)
> + log->Printf("NativeProcessDarwin::%s() called", __FUNCTION__);
> +
> + if (CanResume())
> + {
> + m_thread_actions = resume_actions;
> + error = PrivateResume();
> + return error;
> + }
> +
> + auto state = GetState();
> + if (state == eStateRunning)
> + {
> + if (log)
> + log->Printf("NativeProcessDarwin::%s(): task 0x%x is already
> "
> + "running, ignoring...", __FUNCTION__,
> + TaskPortForProcessID(error));
> + return error;
> + }
> +
> + // We can't resume from this state.
> + error.SetErrorStringWithFormat("task 0x%x has state %s, can't
> resume",
> + TaskPortForProcessID(error),
> + StateAsCString(state));
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Halt()
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Detach()
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Signal(int signo)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Interrupt()
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::Kill()
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::GetMemoryRegionInfo(lldb::addr_t load_addr,
> + MemoryRegionInfo &range_info)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::ReadMemory(lldb::addr_t addr, void *buf, size_t
> size,
> + size_t &bytes_read)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf,
> + size_t size, size_t
> &bytes_read)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::WriteMemory(lldb::addr_t addr, const void *buf,
> + size_t size, size_t &bytes_written)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::AllocateMemory(size_t size, uint32_t permissions,
> + lldb::addr_t &addr)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::DeallocateMemory(lldb::addr_t addr)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +lldb::addr_t
> +NativeProcessDarwin::GetSharedLibraryInfoAddress()
> +{
> + return LLDB_INVALID_ADDRESS;
> +}
> +
> +size_t
> +NativeProcessDarwin::UpdateThreads()
> +{
> + return 0;
> +}
> +
> +bool
> +NativeProcessDarwin::GetArchitecture(ArchSpec &arch) const
> +{
> + return false;
> +}
> +
> +Error
> +NativeProcessDarwin::SetBreakpoint(lldb::addr_t addr, uint32_t size,
> + bool hardware)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +void
> +NativeProcessDarwin::DoStopIDBumped(uint32_t newBumpId)
> +{
> +}
> +
> +Error
> +NativeProcessDarwin::GetLoadedModuleFileSpec(const char* module_path,
> + FileSpec& file_spec)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +Error
> +NativeProcessDarwin::GetFileLoadAddress(const llvm::StringRef& file_name,
> + lldb::addr_t& load_addr)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
> +
> +// -----------------------------------------------------------------
> +// NativeProcessProtocol protected interface
> +// -----------------------------------------------------------------
> +Error
> +NativeProcessDarwin::GetSoftwareBreakpointTrapOpcode(size_t
> +
> trap_opcode_size_hint,
> + size_t
> &actual_opcode_size,
> + const uint8_t
> + *&trap_opcode_bytes)
> +{
> + Error error;
> + error.SetErrorString("TODO: implement");
> + return error;
> +}
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeProcessDarwin.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.h Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,479 @@
> +//===-- NativeProcessDarwin.h --------------------------------- -*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef NativeProcessDarwin_h
> +#define NativeProcessDarwin_h
> +
> +// NOTE: this code should only be compiled on Apple Darwin systems. It is
> +// not cross-platform code and is not intended to build on any other
> platform.
> +// Therefore, platform-specific headers and code are okay here.
> +
> +// C includes
> +#include <mach/mach_types.h>
> +
> +// C++ includes
> +#include <mutex>
> +#include <unordered_set>
> +
> +// Other libraries and framework includes
> +#include "lldb/Core/ArchSpec.h"
> +#include "lldb/lldb-types.h"
> +#include "lldb/Host/common/NativeProcessProtocol.h"
> +#include "lldb/Host/Debug.h"
> +#include "lldb/Host/FileSpec.h"
> +#include "lldb/Host/HostThread.h"
> +#include "lldb/Host/Pipe.h"
> +#include "lldb/Target/MemoryRegionInfo.h"
> +
> +#include "NativeThreadListDarwin.h"
> +#include "LaunchFlavor.h"
> +#include "MachException.h"
> +#include "NativeThreadDarwin.h"
> +
> +namespace lldb_private {
> + class Error;
> + class Scalar;
> +
> + namespace process_darwin {
> +
> + /// @class NativeProcessDarwin
> + /// @brief Manages communication with the inferior (debugee)
> process.
> + ///
> + /// Upon construction, this class prepares and launches an
> inferior
> + /// process for debugging.
> + ///
> + /// Changes in the inferior process state are broadcasted.
> + class NativeProcessDarwin: public NativeProcessProtocol
> + {
> + friend Error
> + NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info,
> + NativeDelegate &native_delegate,
> + MainLoop &mainloop,
> + NativeProcessProtocolSP
> &process_sp);
> +
> + friend Error
> + NativeProcessProtocol::Attach(lldb::pid_t pid,
> + NativeProcessProtocol::
> NativeDelegate
> + &native_delegate,
> + MainLoop &mainloop,
> + NativeProcessProtocolSP
> &process_sp);
> +
> + public:
> +
> + ~NativeProcessDarwin() override;
> +
> + // ------------------------------
> -----------------------------------
> + // NativeProcessProtocol Interface
> + // ------------------------------
> -----------------------------------
> + Error
> + Resume(const ResumeActionList &resume_actions) override;
> +
> + Error
> + Halt() override;
> +
> + Error
> + Detach() override;
> +
> + Error
> + Signal(int signo) override;
> +
> + Error
> + Interrupt() override;
> +
> + Error
> + Kill() override;
> +
> + Error
> + GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo
> + &range_info) override;
> +
> + Error
> + ReadMemory(lldb::addr_t addr, void *buf, size_t size,
> + size_t &bytes_read) override;
> +
> + Error
> + ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t
> size,
> + size_t &bytes_read) override;
> +
> + Error
> + WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
> + size_t &bytes_written) override;
> +
> + Error
> + AllocateMemory(size_t size, uint32_t permissions,
> + lldb::addr_t &addr) override;
> +
> + Error
> + DeallocateMemory(lldb::addr_t addr) override;
> +
> + lldb::addr_t
> + GetSharedLibraryInfoAddress() override;
> +
> + size_t
> + UpdateThreads() override;
> +
> + bool
> + GetArchitecture(ArchSpec &arch) const override;
> +
> + Error
> + SetBreakpoint(lldb::addr_t addr, uint32_t size,
> + bool hardware) override;
> +
> + void
> + DoStopIDBumped(uint32_t newBumpId) override;
> +
> + Error
> + GetLoadedModuleFileSpec(const char* module_path,
> + FileSpec& file_spec) override;
> +
> + Error
> + GetFileLoadAddress(const llvm::StringRef& file_name,
> + lldb::addr_t& load_addr) override;
> +
> + NativeThreadDarwinSP
> + GetThreadByID(lldb::tid_t id);
> +
> + task_t
> + GetTask() const
> + {
> + return m_task;
> + }
> +
> + // ------------------------------
> -----------------------------------
> + // Interface used by NativeRegisterContext-derived classes.
> + // ------------------------------
> -----------------------------------
> + static Error
> + PtraceWrapper(int req,
> + lldb::pid_t pid,
> + void *addr = nullptr,
> + void *data = nullptr,
> + size_t data_size = 0,
> + long *result = nullptr);
> +
> + bool
> + SupportHardwareSingleStepping() const;
> +
> + protected:
> + // ------------------------------
> -----------------------------------
> + // NativeProcessProtocol protected interface
> + // ------------------------------
> -----------------------------------
> + Error
> + GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint,
> + size_t &actual_opcode_size,
> + const uint8_t
> *&trap_opcode_bytes)
> + override;
> +
> + private:
> +
> + // ------------------------------
> -----------------------------------
> + /// Mach task-related Member Variables
> + // ------------------------------
> -----------------------------------
> +
> + // The task port for the inferior process.
> + mutable task_t m_task;
> +
> + // True if the inferior process did an exec since we started
> + // monitoring it.
> + bool m_did_exec;
> +
> + // The CPU type of this process.
> + mutable cpu_type_t m_cpu_type;
> +
> + // ------------------------------
> -----------------------------------
> + /// Exception/Signal Handling Member Variables
> + // ------------------------------
> -----------------------------------
> +
> + // Exception port on which we will receive child exceptions
> + mach_port_t m_exception_port;
> +
> + // Saved state of the child exception port prior to us
> installing
> + // our own intercepting port.
> + MachException::PortInfo m_exc_port_info;
> +
> + // The thread that runs the Mach exception read and reply
> handler.
> + pthread_t m_exception_thread;
> +
> + // TODO see if we can remove this if we get the exception
> collection
> + // and distribution to happen in a single-threaded fashion.
> + std::recursive_mutex m_exception_messages_mutex;
> +
> + // A collection of exception messages caught when listening
> to the
> + // exception port.
> + MachException::Message::collection m_exception_messages;
> +
> + // When we call MachProcess::Interrupt(), we want to send this
> + // signal (if non-zero).
> + int m_sent_interrupt_signo;
> +
> + // If we resume the process and still haven't received our
> + // interrupt signal (if this is non-zero).
> + int m_auto_resume_signo;
> +
> + // ------------------------------
> -----------------------------------
> + /// Thread-related Member Variables
> + // ------------------------------
> -----------------------------------
> + NativeThreadListDarwin m_thread_list;
> + ResumeActionList m_thread_actions;
> +
> + // ------------------------------
> -----------------------------------
> + /// Process Lifetime Member Variable
> + // ------------------------------
> -----------------------------------
> +
> + // The pipe over which the waitpid thread and the main loop
> will
> + // communicate.
> + Pipe m_waitpid_pipe;
> +
> + // The thread that runs the waitpid handler.
> + pthread_t m_waitpid_thread;
> +
> + // waitpid reader callback handle.
> + MainLoop::ReadHandleUP m_waitpid_reader_handle;
> +
> +#if 0
> + ArchSpec m_arch;
> +
> + LazyBool m_supports_mem_region;
> + std::vector<MemoryRegionInfo> m_mem_region_cache;
> +
> + lldb::tid_t m_pending_notification_tid;
> +
> + // List of thread ids stepping with a breakpoint with the
> address of
> + // the relevan breakpoint
> + std::map<lldb::tid_t, lldb::addr_t>
> + m_threads_stepping_with_breakpoint;
> +#endif
> +
> + // ------------------------------
> -----------------------------------
> + // Private Instance Methods
> + // ------------------------------
> -----------------------------------
> + NativeProcessDarwin(lldb::pid_t pid, int pty_master_fd);
> +
> + // ------------------------------
> -----------------------------------
> + /// Finalize the launch.
> + ///
> + /// This method associates the NativeProcessDarwin instance
> with
> + /// the host process that was just launched. It peforms
> actions
> + /// like attaching a listener to the inferior exception port,
> + /// ptracing the process, and the like.
> + ///
> + /// @param[in] launch_flavor
> + /// The launch flavor that was used to launch the process.
> + ///
> + /// @param[in] main_loop
> + /// The main loop that will run the process monitor. Work
> + /// that needs to be done (e.g. reading files) gets
> registered
> + /// here along with callbacks to process the work.
> + ///
> + /// @return
> + /// Any error that occurred during the aforementioned
> + /// operations. Failure here will force termination of
> the
> + /// launched process and debugging session.
> + // ------------------------------
> -----------------------------------
> + Error
> + FinalizeLaunch(LaunchFlavor launch_flavor, MainLoop
> &main_loop);
> +
> + Error
> + SaveExceptionPortInfo();
> +
> + void
> + ExceptionMessageReceived(const MachException::Message
> &message);
> +
> + void
> + MaybeRaiseThreadPriority();
> +
> + Error
> + StartExceptionThread();
> +
> + Error
> + SendInferiorExitStatusToMainLoop(::pid_t pid, int status);
> +
> + Error
> + HandleWaitpidResult();
> +
> + bool
> + ProcessUsingSpringBoard() const;
> +
> + bool
> + ProcessUsingBackBoard() const;
> +
> + static void*
> + ExceptionThread(void *arg);
> +
> + void*
> + DoExceptionThread();
> +
> + lldb::addr_t
> + GetDYLDAllImageInfosAddress(Error &error) const;
> +
> + static uint32_t
> + GetCPUTypeForLocalProcess(::pid_t pid);
> +
> + uint32_t
> + GetCPUType() const;
> +
> + task_t
> + ExceptionMessageBundleComplete();
> +
> + void
> + StartSTDIOThread();
> +
> + Error
> + StartWaitpidThread(MainLoop &main_loop);
> +
> + static void*
> + WaitpidThread(void *arg);
> +
> + void*
> + DoWaitpidThread();
> +
> + task_t
> + TaskPortForProcessID(Error &error, bool force = false) const;
> +
> + /// Attaches to an existing process. Forms the
> + /// implementation of Process::DoAttach.
> + void
> + AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Error
> &error);
> +
> + ::pid_t
> + Attach(lldb::pid_t pid, Error &error);
> +
> + Error
> + PrivateResume();
> +
> + Error
> + ReplyToAllExceptions();
> +
> + Error
> + ResumeTask();
> +
> + bool
> + IsTaskValid() const;
> +
> + bool
> + IsTaskValid(task_t task) const;
> +
> + mach_port_t
> + GetExceptionPort() const;
> +
> + bool
> + IsExceptionPortValid () const;
> +
> + Error
> + GetTaskBasicInfo(task_t task, struct task_basic_info *info)
> const;
> +
> + Error
> + SuspendTask();
> +
> + static Error
> + SetDefaultPtraceOpts(const lldb::pid_t);
> +
> + static void *
> + MonitorThread(void *baton);
> +
> + void
> + MonitorCallback(lldb::pid_t pid, bool exited, int signal,
> + int status);
> +
> + void
> + WaitForNewThread(::pid_t tid);
> +
> + void
> + MonitorSIGTRAP(const siginfo_t &info, NativeThreadDarwin
> &thread);
> +
> + void
> + MonitorTrace(NativeThreadDarwin &thread);
> +
> + void
> + MonitorBreakpoint(NativeThreadDarwin &thread);
> +
> + void
> + MonitorWatchpoint(NativeThreadDarwin &thread, uint32_t
> wp_index);
> +
> + void
> + MonitorSignal(const siginfo_t &info, NativeThreadDarwin
> &thread,
> + bool exited);
> +
> + Error
> + SetupSoftwareSingleStepping(NativeThreadDarwin &thread);
> +
> +#if 0
> + static ::ProcessMessage::CrashReason
> + GetCrashReasonForSIGSEGV(const siginfo_t *info);
> +
> + static ::ProcessMessage::CrashReason
> + GetCrashReasonForSIGILL(const siginfo_t *info);
> +
> + static ::ProcessMessage::CrashReason
> + GetCrashReasonForSIGFPE(const siginfo_t *info);
> +
> + static ::ProcessMessage::CrashReason
> + GetCrashReasonForSIGBUS(const siginfo_t *info);
> +#endif
> +
> + bool
> + HasThreadNoLock(lldb::tid_t thread_id);
> +
> + bool
> + StopTrackingThread(lldb::tid_t thread_id);
> +
> + NativeThreadDarwinSP
> + AddThread(lldb::tid_t thread_id);
> +
> + Error
> + GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size);
> +
> + Error
> + FixupBreakpointPCAsNeeded(NativeThreadDarwin &thread);
> +
> + /// Writes a siginfo_t structure corresponding to the given
> thread
> + /// ID to the memory region pointed to by @p siginfo.
> + Error
> + GetSignalInfo(lldb::tid_t tid, void *siginfo);
> +
> + /// Writes the raw event message code (vis-a-vis
> PTRACE_GETEVENTMSG)
> + /// corresponding to the given thread ID to the memory
> pointed to
> + /// by @p message.
> + Error
> + GetEventMessage(lldb::tid_t tid, unsigned long *message);
> +
> + void
> + NotifyThreadDeath(lldb::tid_t tid);
> +
> + Error
> + Detach(lldb::tid_t tid);
> +
> +
> + // This method is requests a stop on all threads which are
> still
> + // running. It sets up a deferred delegate notification,
> which will
> + // fire once threads report as stopped. The triggerring_tid
> will be
> + // set as the current thread (main stop reason).
> + void
> + StopRunningThreads(lldb::tid_t triggering_tid);
> +
> + // Notify the delegate if all threads have stopped.
> + void SignalIfAllThreadsStopped();
> +
> + // Resume the given thread, optionally passing it the given
> signal.
> + // The type of resume operation (continue, single-step)
> depends on
> + // the state parameter.
> + Error
> + ResumeThread(NativeThreadDarwin &thread, lldb::StateType
> state,
> + int signo);
> +
> + void
> + ThreadWasCreated(NativeThreadDarwin &thread);
> +
> + void
> + SigchldHandler();
> + };
> +
> + } // namespace process_darwin
> +} // namespace lldb_private
> +
> +#endif /* NativeProcessDarwin_h */
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeThreadDarwin.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.cpp Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,324 @@
> +//===-- NativeThreadDarwin.cpp -------------------------------- -*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "NativeThreadDarwin.h"
> +
> +// C includes
> +#include <libproc.h>
> +
> +// LLDB includes
> +#include "lldb/Core/Stream.h"
> +
> +#include "NativeProcessDarwin.h"
> +
> +using namespace lldb;
> +using namespace lldb_private;
> +using namespace lldb_private::process_darwin;
> +
> +uint64_t
> +NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID(
> + ::thread_t
> mach_port_id)
> +{
> + thread_identifier_info_data_t tident;
> + mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
> +
> + auto mach_err = ::thread_info(mach_port_id, THREAD_IDENTIFIER_INFO,
> + (thread_info_t) &tident, &tident_count);
> + if (mach_err != KERN_SUCCESS)
> + {
> + // When we fail to get thread info for the supposed port, assume
> it is
> + // really a globally unique thread id already, or return the best
> thing
> + // we can, which is the thread port.
> + return mach_port_id;
> + }
> + return tident.thread_id;
> +}
> +
> +NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process,
> + bool is_64_bit,
> + lldb::tid_t unique_thread_id,
> + ::thread_t mach_thread_port) :
> + NativeThreadProtocol(process, unique_thread_id),
> + m_mach_thread_port(mach_thread_port),
> + m_basic_info(),
> + m_proc_threadinfo()
> +{
> +}
> +
> +bool
> +NativeThreadDarwin::GetIdentifierInfo()
> +{
> + // Don't try to get the thread info once and cache it for the life of
> the thread. It changes over time, for instance
> + // if the thread name changes, then the thread_handle also
> changes... So you have to refetch it every time.
> + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
> + kern_return_t kret = ::thread_info(m_mach_thread_port,
> + THREAD_IDENTIFIER_INFO,
> + (thread_info_t) &m_ident_info,
> &count);
> + return kret == KERN_SUCCESS;
> +
> + return false;
> +}
> +
> +std::string
> +NativeThreadDarwin::GetName()
> +{
> + std::string name;
> +
> + if (GetIdentifierInfo())
> + {
> + auto process_sp = GetProcess();
> + if (!process_sp)
> + {
> + name = "<unavailable>";
> + return name;
> + }
> +
> + int len = ::proc_pidinfo(process_sp->GetID(), PROC_PIDTHREADINFO,
> + m_ident_info.thread_handle,
> &m_proc_threadinfo,
> + sizeof(m_proc_threadinfo));
> +
> + if (len && m_proc_threadinfo.pth_name[0])
> + name = m_proc_threadinfo.pth_name;
> + }
> + return name;
> +}
> +
> +lldb::StateType
> +NativeThreadDarwin::GetState()
> +{
> + // TODO implement
> + return eStateInvalid;
> +}
> +
> +bool
> +NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info,
> + std::string& description)
> +{
> + // TODO implement
> + return false;
> +}
> +
> +NativeRegisterContextSP
> +NativeThreadDarwin::GetRegisterContext()
> +{
> + // TODO implement
> + return NativeRegisterContextSP();
> +}
> +
> +Error
> +NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size,
> + uint32_t watch_flags, bool hardware)
> +{
> + Error error;
> + error.SetErrorString("not yet implemented");
> + return error;
> +}
> +
> +Error
> +NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr)
> +{
> + Error error;
> + error.SetErrorString("not yet implemented");
> + return error;
> +}
> +
> +void
> +NativeThreadDarwin::Dump(Stream &stream) const
> +{
> + // This is what we really want once we have the thread class wired up.
> +#if 0
> + DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16"
> PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu:
> %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d
> (current %2d), sleep_time: %d",
> + index,
> + m_seq_id,
> + m_unique_id,
> + GetPC(INVALID_NUB_ADDRESS),
> + GetSP(INVALID_NUB_ADDRESS),
> + m_basic_info.user_time.seconds,
> m_basic_info.user_time.microseconds,
> + m_basic_info.system_time.seconds,
> m_basic_info.system_time.microseconds,
> + m_basic_info.cpu_usage,
> + m_basic_info.policy,
> + m_basic_info.run_state,
> + thread_run_state,
> + m_basic_info.flags,
> + m_basic_info.suspend_count, m_suspend_count,
> + m_basic_info.sleep_time);
> +
> +#else
> + // Here's all we have right now.
> + stream.Printf("tid: 0x%8.8" PRIx64 ", thread port: 0x%4.4x",
> + GetID(), m_mach_thread_port);
> +#endif
> +}
> +
> +bool
> +NativeThreadDarwin::NotifyException(MachException::Data &exc)
> +{
> + // TODO implement this.
> +#if 0
> + // Allow the arch specific protocol to process (MachException::Data
> &)exc
> + // first before possible reassignment of m_stop_exception with exc.
> + // See also MachThread::GetStopException().
> + bool handled = m_arch_ap->NotifyException(exc);
> +
> + if (m_stop_exception.IsValid())
> + {
> + // We may have more than one exception for a thread, but we need
> to
> + // only remember the one that we will say is the reason we
> stopped.
> + // We may have been single stepping and also gotten a signal
> exception,
> + // so just remember the most pertinent one.
> + if (m_stop_exception.IsBreakpoint())
> + m_stop_exception = exc;
> + }
> + else
> + {
> + m_stop_exception = exc;
> + }
> +
> + return handled;
> +#else
> + // Pretend we handled it.
> + return true;
> +#endif
> +}
> +
> +bool
> +NativeThreadDarwin::ShouldStop(bool &step_more) const
> +{
> + // TODO: implement this
> +#if 0
> + // See if this thread is at a breakpoint?
> + DNBBreakpoint *bp = CurrentBreakpoint();
> +
> + if (bp)
> + {
> + // This thread is sitting at a breakpoint, ask the breakpoint
> + // if we should be stopping here.
> + return true;
> + }
> + else
> + {
> + if (m_arch_ap->StepNotComplete())
> + {
> + step_more = true;
> + return false;
> + }
> + // The thread state is used to let us know what the thread was
> + // trying to do. MachThread::ThreadWillResume() will set the
> + // thread state to various values depending if the thread was
> + // the current thread and if it was to be single stepped, or
> + // resumed.
> + if (GetState() == eStateRunning)
> + {
> + // If our state is running, then we should continue as we are
> in
> + // the process of stepping over a breakpoint.
> + return false;
> + }
> + else
> + {
> + // Stop if we have any kind of valid exception for this
> + // thread.
> + if (GetStopException().IsValid())
> + return true;
> + }
> + }
> + return false;
> +#else
> + return false;
> +#endif
> +}
> +
> +void
> +NativeThreadDarwin::ThreadDidStop()
> +{
> + // TODO implement this.
> +#if 0
> + // This thread has existed prior to resuming under debug nub control,
> + // and has just been stopped. Do any cleanup that needs to be done
> + // after running.
> +
> + // The thread state and breakpoint will still have the same values
> + // as they had prior to resuming the thread, so it makes it easy to
> check
> + // if we were trying to step a thread, or we tried to resume while
> being
> + // at a breakpoint.
> +
> + // When this method gets called, the process state is still in the
> + // state it was in while running so we can act accordingly.
> + m_arch_ap->ThreadDidStop();
> +
> +
> + // We may have suspended this thread so the primary thread could step
> + // without worrying about race conditions, so lets restore our suspend
> + // count.
> + RestoreSuspendCountAfterStop();
> +
> + // Update the basic information for a thread
> + MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info);
> +
> + if (m_basic_info.suspend_count > 0)
> + SetState(eStateSuspended);
> + else
> + SetState(eStateStopped);
> +#endif
> +}
> +
> +bool
> +NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread)
> +{
> + return thread != (::thread_t)(0);
> +}
> +
> +const struct thread_basic_info *
> +NativeThreadDarwin::GetBasicInfo() const
> +{
> + if (GetBasicInfo(m_mach_thread_port, &m_basic_info))
> + return &m_basic_info;
> + return NULL;
> +}
> +
> +bool
> +NativeThreadDarwin::GetBasicInfo(::thread_t thread,
> + struct thread_basic_info *basicInfoPtr)
> +{
> + if (MachPortNumberIsValid(thread))
> + {
> + unsigned int info_count = THREAD_BASIC_INFO_COUNT;
> + kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO,
> (thread_info_t) basicInfoPtr, &info_count);
> + if (err == KERN_SUCCESS)
> + return true;
> + }
> + ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
> + return false;
> +}
> +
> +bool
> +NativeThreadDarwin::IsUserReady() const
> +{
> + if (m_basic_info.run_state == 0)
> + GetBasicInfo();
> +
> + switch (m_basic_info.run_state)
> + {
> + default:
> + case TH_STATE_UNINTERRUPTIBLE:
> + break;
> +
> + case TH_STATE_RUNNING:
> + case TH_STATE_STOPPED:
> + case TH_STATE_WAITING:
> + case TH_STATE_HALTED:
> + return true;
> + }
> + return false;
> +}
> +
> +NativeProcessDarwinSP
> +NativeThreadDarwin::GetNativeProcessDarwinSP()
> +{
> + return std::static_pointer_cast<NativeProcessDarwin>(GetProcess());
> +}
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeThreadDarwin.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.h (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeThreadDarwin.h Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,216 @@
> +//===-- NativeThreadDarwin.h ---------------------------------- -*- C++
> -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef NativeThreadDarwin_H
> +#define NativeThreadDarwin_H
> +
> +// C includes
> +#include <mach/mach_types.h>
> +#include <sched.h>
> +#include <sys/proc_info.h>
> +
> +// C++ includes
> +#include <map>
> +#include <memory>
> +#include <string>
> +
> +// LLDB includes
> +#include "lldb/lldb-private-forward.h"
> +#include "lldb/Host/common/NativeThreadProtocol.h"
> +
> +#include "MachException.h"
> +
> +namespace lldb_private {
> +namespace process_darwin {
> +
> +class NativeProcessDarwin;
> +using NativeProcessDarwinSP = std::shared_ptr<NativeProcessDarwin>;
> +
> +class NativeThreadListDarwin;
> +
> +class NativeThreadDarwin : public NativeThreadProtocol
> +{
> + friend class NativeProcessDarwin;
> + friend class NativeThreadListDarwin;
> +
> +public:
> +
> + static uint64_t
> + GetGloballyUniqueThreadIDForMachPortID(::thread_t mach_port_id);
> +
> + NativeThreadDarwin(NativeProcessDarwin *process, bool is_64_bit,
> + lldb::tid_t unique_thread_id = 0,
> + ::thread_t mach_thread_port = 0);
> +
> + // -----------------------------------------------------------------
> + // NativeThreadProtocol Interface
> + // -----------------------------------------------------------------
> + std::string
> + GetName() override;
> +
> + lldb::StateType
> + GetState () override;
> +
> + bool
> + GetStopReason(ThreadStopInfo &stop_info,
> + std::string& description) override;
> +
> + NativeRegisterContextSP
> + GetRegisterContext() override;
> +
> + Error
> + SetWatchpoint(lldb::addr_t addr, size_t size,
> + uint32_t watch_flags, bool hardware) override;
> +
> + Error
> + RemoveWatchpoint(lldb::addr_t addr) override;
> +
> + // -----------------------------------------------------------------
> + // New methods that are fine for others to call.
> + // -----------------------------------------------------------------
> + void
> + Dump(Stream &stream) const;
> +
> +private:
> + // -----------------------------------------------------------------
> + // Interface for friend classes
> + // -----------------------------------------------------------------
> +
> + /// Resumes the thread. If @p signo is anything but
> + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
> + Error
> + Resume(uint32_t signo);
> +
> + /// Single steps the thread. If @p signo is anything but
> + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
> + Error
> + SingleStep(uint32_t signo);
> +
> + bool
> + NotifyException(MachException::Data &exc);
> +
> + bool
> + ShouldStop(bool &step_more) const;
> +
> + void
> + ThreadDidStop();
> +
> + void
> + SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
> +
> + /// Return true if the thread is stopped.
> + /// If stopped by a signal, indicate the signo in the signo
> + /// argument. Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
> + bool
> + IsStopped (int *signo);
> +
> + const struct thread_basic_info *
> + GetBasicInfo() const;
> +
> + static bool
> + GetBasicInfo(::thread_t thread, struct thread_basic_info
> *basicInfoPtr);
> +
> + bool
> + IsUserReady() const;
> +
> + void
> + SetStoppedByExec ();
> +
> + void
> + SetStoppedByBreakpoint ();
> +
> + void
> + SetStoppedByWatchpoint (uint32_t wp_index);
> +
> + bool
> + IsStoppedAtBreakpoint ();
> +
> + bool
> + IsStoppedAtWatchpoint ();
> +
> + void
> + SetStoppedByTrace ();
> +
> + void
> + SetStoppedWithNoReason ();
> +
> + void
> + SetExited ();
> +
> + Error
> + RequestStop ();
> +
> + // ------------------------------------------------------------
> -------------
> + /// Return the mach thread port number for this thread.
> + ///
> + /// @return
> + /// The mach port number for this thread. Returns NULL_THREAD
> + /// when the thread is invalid.
> + // ------------------------------------------------------------
> -------------
> + thread_t
> + GetMachPortNumber() const
> + {
> + return m_mach_thread_port;
> + }
> +
> + static bool
> + MachPortNumberIsValid(::thread_t thread);
> +
> + // ------------------------------------------------------------
> ---------
> + // Private interface
> + // ------------------------------------------------------------
> ---------
> + bool
> + GetIdentifierInfo();
> +
> + void
> + MaybeLogStateChange (lldb::StateType new_state);
> +
> + NativeProcessDarwinSP
> + GetNativeProcessDarwinSP();
> +
> + void
> + SetStopped();
> +
> + inline void
> + MaybePrepareSingleStepWorkaround();
> +
> + inline void
> + MaybeCleanupSingleStepWorkaround();
> +
> + // -----------------------------------------------------------------
> + // Member Variables
> + // -----------------------------------------------------------------
> +
> + // The mach thread port for the thread.
> + ::thread_t m_mach_thread_port;
> +
> + // The most recently-retrieved thread basic info.
> + mutable ::thread_basic_info m_basic_info;
> +
> + struct proc_threadinfo m_proc_threadinfo;
> +
> + thread_identifier_info_data_t m_ident_info;
> +
> +#if 0
> + lldb::StateType m_state;
> + ThreadStopInfo m_stop_info;
> + NativeRegisterContextSP m_reg_context_sp;
> + std::string m_stop_description;
> + using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
> + WatchpointIndexMap m_watchpoint_index_map;
> + // cpu_set_t m_original_cpu_set; // For single-step workaround.
> +#endif
> +};
> +
> +typedef std::shared_ptr<NativeThreadDarwin> NativeThreadDarwinSP;
> +
> +} // namespace process_darwin
> +} // namespace lldb_private
> +
> +#endif // #ifndef NativeThreadDarwin_H
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeThreadListDarwin.cpp?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,745 @@
> +//===-- NativeThreadListDarwin.cpp ------------------------------------*-
> C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 6/19/07.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "NativeThreadListDarwin.h"
> +
> +// C includes
> +#include <inttypes.h>
> +#include <mach/vm_map.h>
> +#include <sys/sysctl.h>
> +
> +// LLDB includes
> +#include "lldb/Core/Error.h"
> +#include "lldb/Core/Log.h"
> +#include "lldb/Core/Stream.h"
> +#include "lldb/lldb-enumerations.h"
> +
> +#include "NativeProcessDarwin.h"
> +#include "NativeThreadDarwin.h"
> +
> +using namespace lldb;
> +using namespace lldb_private;
> +using namespace lldb_private::process_darwin;
> +
> +NativeThreadListDarwin::NativeThreadListDarwin() :
> + m_threads(),
> + m_threads_mutex(),
> + m_is_64_bit(false)
> +{
> +}
> +
> +NativeThreadListDarwin::~NativeThreadListDarwin()
> +{
> +}
> +
> +// These methods will be accessed directly from NativeThreadDarwin
> +#if 0
> +nub_state_t
> +NativeThreadListDarwin::GetState(nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetState();
> + return eStateInvalid;
> +}
> +
> +const char *
> +NativeThreadListDarwin::GetName (nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetName();
> + return NULL;
> +}
> +#endif
> +
> +// TODO: figure out if we need to add this to NativeThreadDarwin yet.
> +#if 0
> +ThreadInfo::QoS
> +NativeThreadListDarwin::GetRequestedQoS (nub_thread_t tid, nub_addr_t
> tsd, uint64_t dti_qos_class_index)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index);
> + return ThreadInfo::QoS();
> +}
> +
> +nub_addr_t
> +NativeThreadListDarwin::GetPThreadT (nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetPThreadT();
> + return INVALID_NUB_ADDRESS;
> +}
> +
> +nub_addr_t
> +NativeThreadListDarwin::GetDispatchQueueT (nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetDispatchQueueT();
> + return INVALID_NUB_ADDRESS;
> +}
> +
> +nub_addr_t
> +NativeThreadListDarwin::GetTSDAddressForThread (nub_thread_t tid,
> uint64_t plo_pthread_tsd_base_address_offset, uint64_t
> plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetTSDAddressForThread(plo_
> pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset,
> plo_pthread_tsd_entry_size);
> + return INVALID_NUB_ADDRESS;
> +}
> +#endif
> +
> +// TODO implement these
> +#if 0
> +nub_thread_t
> +NativeThreadListDarwin::SetCurrentThread(nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + {
> + m_current_thread = thread_sp;
> + return tid;
> + }
> + return INVALID_NUB_THREAD;
> +}
> +
> +
> +bool
> +NativeThreadListDarwin::GetThreadStoppedReason(nub_thread_t tid, struct
> DNBThreadStopInfo *stop_info) const
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetStopException().GetStopInfo(stop_info);
> + return false;
> +}
> +
> +bool
> +NativeThreadListDarwin::GetIdentifierInfo (nub_thread_t tid,
> thread_identifier_info_data_t *ident_info)
> +{
> + thread_t mach_port_number = GetMachPortNumberByThreadID (tid);
> +
> + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
> + return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO,
> (thread_info_t)ident_info, &count) == KERN_SUCCESS;
> +}
> +
> +void
> +NativeThreadListDarwin::DumpThreadStoppedReason (nub_thread_t tid) const
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + thread_sp->GetStopException().DumpStopReason();
> +}
> +
> +const char *
> +NativeThreadListDarwin::GetThreadInfo (nub_thread_t tid) const
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetBasicInfoAsString();
> + return NULL;
> +}
> +
> +#endif
> +
> +NativeThreadDarwinSP
> +NativeThreadListDarwin::GetThreadByID(lldb::tid_t tid) const
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp && (thread_sp->GetID() == tid))
> + return thread_sp;
> + }
> + return NativeThreadDarwinSP();
> +}
> +
> +NativeThreadDarwinSP
> +NativeThreadListDarwin::GetThreadByMachPortNumber(::thread_t
> mach_port_number)
> + const
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp && (thread_sp->GetMachPortNumber() ==
> mach_port_number))
> + return thread_sp;
> + }
> + return NativeThreadDarwinSP();
> +}
> +
> +lldb::tid_t
> +NativeThreadListDarwin::GetThreadIDByMachPortNumber(::thread_t
> mach_port_number)
> + const
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp && (thread_sp->GetMachPortNumber() ==
> mach_port_number))
> + return thread_sp->GetID();
> + }
> + return LLDB_INVALID_THREAD_ID;
> +}
> +
> +// TODO implement
> +#if 0
> +thread_t
> +NativeThreadListDarwin::GetMachPortNumberByThreadID (nub_thread_t
> globally_unique_id) const
> +{
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + MachThreadSP thread_sp;
> + const size_t num_threads = m_threads.size();
> + for (size_t idx = 0; idx < num_threads; ++idx)
> + {
> + if (m_threads[idx]->ThreadID() == globally_unique_id)
> + {
> + return m_threads[idx]->MachPortNumber();
> + }
> + }
> + return 0;
> +}
> +
> +bool
> +NativeThreadListDarwin::GetRegisterValue (nub_thread_t tid, uint32_t
> set, uint32_t reg, DNBRegisterValue *reg_value ) const
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetRegisterValue(set, reg, reg_value);
> +
> + return false;
> +}
> +
> +bool
> +NativeThreadListDarwin::SetRegisterValue (nub_thread_t tid, uint32_t
> set, uint32_t reg, const DNBRegisterValue *reg_value ) const
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->SetRegisterValue(set, reg, reg_value);
> +
> + return false;
> +}
> +
> +nub_size_t
> +NativeThreadListDarwin::GetRegisterContext (nub_thread_t tid, void *buf,
> size_t buf_len)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->GetRegisterContext (buf, buf_len);
> + return 0;
> +}
> +
> +nub_size_t
> +NativeThreadListDarwin::SetRegisterContext (nub_thread_t tid, const void
> *buf, size_t buf_len)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->SetRegisterContext (buf, buf_len);
> + return 0;
> +}
> +
> +uint32_t
> +NativeThreadListDarwin::SaveRegisterState (nub_thread_t tid)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->SaveRegisterState ();
> + return 0;
> +}
> +
> +bool
> +NativeThreadListDarwin::RestoreRegisterState (nub_thread_t tid, uint32_t
> save_id)
> +{
> + MachThreadSP thread_sp (GetThreadByID (tid));
> + if (thread_sp)
> + return thread_sp->RestoreRegisterState (save_id);
> + return 0;
> +}
> +#endif
> +
> +size_t
> +NativeThreadListDarwin::GetNumberOfThreads() const
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + return static_cast<size_t>(m_threads.size());
> +}
> +
> +// TODO implement
> +#if 0
> +nub_thread_t
> +NativeThreadListDarwin::ThreadIDAtIndex (nub_size_t idx) const
> +{
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + if (idx < m_threads.size())
> + return m_threads[idx]->ThreadID();
> + return INVALID_NUB_THREAD;
> +}
> +
> +nub_thread_t
> +NativeThreadListDarwin::CurrentThreadID ( )
> +{
> + MachThreadSP thread_sp;
> + CurrentThread(thread_sp);
> + if (thread_sp.get())
> + return thread_sp->ThreadID();
> + return INVALID_NUB_THREAD;
> +}
> +
> +#endif
> +
> +bool
> +NativeThreadListDarwin::NotifyException(MachException::Data &exc)
> +{
> + auto thread_sp = GetThreadByMachPortNumber(exc.thread_port);
> + if (thread_sp)
> + {
> + thread_sp->NotifyException(exc);
> + return true;
> + }
> + return false;
> +}
> +
> +void
> +NativeThreadListDarwin::Clear()
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + m_threads.clear();
> +}
> +
> +uint32_t
> +NativeThreadListDarwin::UpdateThreadList(NativeProcessDarwin &process,
> + bool update,
> + collection *new_threads)
> +{
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
> +
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + if (log)
> + log->Printf("NativeThreadListDarwin::%s() (pid = %" PRIu64 ",
> update = "
> + "%u) process stop count = %u", __FUNCTION__,
> + process.GetID(), update, process.GetStopID());
> +
> + if (process.GetStopID() == 0)
> + {
> + // On our first stop, we'll record details like 32/64 bitness and
> + // select the proper architecture implementation.
> + //
> + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
> + (int)process.GetID() };
> +
> + struct kinfo_proc processInfo;
> + size_t bufsize = sizeof(processInfo);
> + if ((sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)),
> &processInfo,
> + &bufsize, NULL, 0) == 0) && (bufsize > 0))
> + {
> + if (processInfo.kp_proc.p_flag & P_LP64)
> + m_is_64_bit = true;
> + }
> +
> +// TODO implement architecture selection and abstraction.
> +#if 0
> +#if defined (__i386__) || defined (__x86_64__)
> + if (m_is_64_bit)
> + DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64);
> + else
> + DNBArchProtocol::SetArchitecture(CPU_TYPE_I386);
> +#elif defined (__arm__) || defined (__arm64__) || defined (__aarch64__)
> + if (m_is_64_bit)
> + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64);
> + else
> + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM);
> +#endif
> +#endif
> + }
> +
> + if (m_threads.empty() || update)
> + {
> + thread_array_t thread_list = nullptr;
> + mach_msg_type_number_t thread_list_count = 0;
> + task_t task = process.GetTask();
> +
> + Error error;
> + auto mach_err = ::task_threads(task, &thread_list,
> &thread_list_count);
> + error.SetError(mach_err, eErrorTypeMachKernel);
> + if (error.Fail())
> + {
> + if (log)
> + log->Printf("::task_threads(task = 0x%4.4x, thread_list
> => %p, "
> + "thread_list_count => %u) failed: %u (%s)",
> task,
> + thread_list, thread_list_count,
> error.GetError(),
> + error.AsCString());
> + return 0;
> + }
> +
> + if (thread_list_count > 0)
> + {
> + collection currThreads;
> + size_t idx;
> + // Iterator through the current thread list and see which
> threads
> + // we already have in our list (keep them), which ones we
> don't
> + // (add them), and which ones are not around anymore (remove
> them).
> + for (idx = 0; idx < thread_list_count; ++idx)
> + {
> + // Get the Mach thread port.
> + const ::thread_t mach_port_num = thread_list[idx];
> +
> + // Get the unique thread id for the mach port number.
> + uint64_t unique_thread_id =
> + NativeThreadDarwin::
> + GetGloballyUniqueThreadIDForMa
> chPortID(mach_port_num);
> +
> + // Retrieve the thread if it exists.
> + auto thread_sp = GetThreadByID(unique_thread_id);
> + if (thread_sp)
> + {
> + // We are already tracking it. Keep the existing
> native
> + // thread instance.
> + currThreads.push_back(thread_sp);
> + }
> + else
> + {
> + // We don't have a native thread instance for this
> thread.
> + // Create it now.
> + thread_sp.reset(new NativeThreadDarwin(&process,
> + m_is_64_bit,
> +
> unique_thread_id,
> +
> mach_port_num));
> +
> + // Add the new thread regardless of its is user ready
> state.
> + // Make sure the thread is ready to be displayed and
> shown
> + // to users before we add this thread to our list...
> + if (thread_sp->IsUserReady())
> + {
> + if (new_threads)
> + new_threads->push_back(thread_sp);
> +
> + currThreads.push_back(thread_sp);
> + }
> + }
> + }
> +
> + m_threads.swap(currThreads);
> + m_current_thread.reset();
> +
> + // Free the vm memory given to us by ::task_threads()
> + vm_size_t thread_list_size = (vm_size_t) (thread_list_count *
> + sizeof
> (::thread_t));
> + ::vm_deallocate(::mach_task_self(),
> + (vm_address_t)thread_list,
> + thread_list_size);
> + }
> + }
> + return static_cast<uint32_t>(m_threads.size());
> +}
> +
> +// TODO implement
> +#if 0
> +
> +void
> +NativeThreadListDarwin::CurrentThread (MachThreadSP& thread_sp)
> +{
> + // locker will keep a mutex locked until it goes out of scope
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + if (m_current_thread.get() == NULL)
> + {
> + // Figure out which thread is going to be our current thread.
> + // This is currently done by finding the first thread in the list
> + // that has a valid exception.
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + {
> + if (m_threads[idx]->GetStopException().IsValid())
> + {
> + m_current_thread = m_threads[idx];
> + break;
> + }
> + }
> + }
> + thread_sp = m_current_thread;
> +}
> +
> +#endif
> +
> +void
> +NativeThreadListDarwin::Dump(Stream &stream) const
> +{
> + bool first = true;
> +
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp)
> + {
> + // Handle newlines between thread entries.
> + if (first)
> + first = false;
> + else
> + stream.PutChar('\n');
> + thread_sp->Dump(stream);
> + }
> + }
> +}
> +
> +void
> +NativeThreadListDarwin::ProcessWillResume(NativeProcessDarwin &process,
> + const ResumeActionList
> &thread_actions)
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> +
> + // Update our thread list, because sometimes libdispatch or the kernel
> + // will spawn threads while a task is suspended.
> + NativeThreadListDarwin::collection new_threads;
> +
> + // TODO implement this.
> +#if 0
> + // First figure out if we were planning on running only one thread,
> and if
> + // so, force that thread to resume.
> + bool run_one_thread;
> + thread_t solo_thread = THREAD_NULL;
> + if ((thread_actions.GetSize() > 0) &&
> + (thread_actions.NumActionsWithState(eStateStepping) +
> + thread_actions.NumActionsWithState (eStateRunning) == 1))
> + {
> + run_one_thread = true;
> + const DNBThreadResumeAction *action_ptr =
> thread_actions.GetFirst();
> + size_t num_actions = thread_actions.GetSize();
> + for (size_t i = 0; i < num_actions; i++, action_ptr++)
> + {
> + if (action_ptr->state == eStateStepping || action_ptr->state
> == eStateRunning)
> + {
> + solo_thread = action_ptr->tid;
> + break;
> + }
> + }
> + }
> + else
> + run_one_thread = false;
> +#endif
> +
> + UpdateThreadList(process, true, &new_threads);
> +
> +#if 0
> + DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0,
> INVALID_NUB_ADDRESS };
> + // If we are planning to run only one thread, any new threads should
> be suspended.
> + if (run_one_thread)
> + resume_new_threads.state = eStateSuspended;
> +
> + const size_t num_new_threads = new_threads.size();
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + {
> + MachThread *thread = m_threads[idx].get();
> + bool handled = false;
> + for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx)
> + {
> + if (thread == new_threads[new_idx].get())
> + {
> + thread->ThreadWillResume(&resume_new_threads);
> + handled = true;
> + break;
> + }
> + }
> +
> + if (!handled)
> + {
> + const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread
> (thread->ThreadID(), true);
> + // There must always be a thread action for every thread.
> + assert (thread_action);
> + bool others_stopped = false;
> + if (solo_thread == thread->ThreadID())
> + others_stopped = true;
> + thread->ThreadWillResume (thread_action, others_stopped);
> + }
> + }
> +
> + if (new_threads.size())
> + {
> + for (uint32_t idx = 0; idx < num_new_threads; ++idx)
> + {
> + DNBLogThreadedIf (LOG_THREAD, "NativeThreadListDarwin::ProcessWillResume
> (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64
> ", thread-is-user-ready=%i)",
> + process->ProcessID(),
> + process->StopCount(),
> + new_threads[idx]->ThreadID(),
> + new_threads[idx]->IsUserReady());
> + }
> + }
> +#endif
> +}
> +
> +uint32_t
> +NativeThreadListDarwin::ProcessDidStop(NativeProcessDarwin &process)
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> +
> + // Update our thread list.
> + UpdateThreadList(process, true);
> +
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp)
> + thread_sp->ThreadDidStop();
> + }
> + return (uint32_t)m_threads.size();
> +}
> +
> +//----------------------------------------------------------------------
> +// Check each thread in our thread list to see if we should notify our
> +// client of the current halt in execution.
> +//
> +// Breakpoints can have callback functions associated with them than
> +// can return true to stop, or false to continue executing the inferior.
> +//
> +// RETURNS
> +// true if we should stop and notify our clients
> +// false if we should resume our child process and skip notification
> +//----------------------------------------------------------------------
> +bool
> +NativeThreadListDarwin::ShouldStop(bool &step_more)
> +{
> + std::lock_guard<std::recursive_mutex> locker(m_threads_mutex);
> + for (auto thread_sp : m_threads)
> + {
> + if (thread_sp && thread_sp->ShouldStop(step_more))
> + return true;
> + }
> + return false;
> +}
> +
> +// Implement.
> +#if 0
> +
> +void
> +NativeThreadListDarwin::NotifyBreakpointChanged (const DNBBreakpoint *bp)
> +{
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + {
> + m_threads[idx]->NotifyBreakpointChanged(bp);
> + }
> +}
> +
> +
> +uint32_t
> +NativeThreadListDarwin::EnableHardwareBreakpoint (const DNBBreakpoint*
> bp) const
> +{
> + if (bp != NULL)
> + {
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + m_threads[idx]->EnableHardwareBreakpoint(bp);
> + }
> + return INVALID_NUB_HW_INDEX;
> +}
> +
> +bool
> +NativeThreadListDarwin::DisableHardwareBreakpoint (const DNBBreakpoint*
> bp) const
> +{
> + if (bp != NULL)
> + {
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + m_threads[idx]->DisableHardwareBreakpoint(bp);
> + }
> + return false;
> +}
> +
> +// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() ->
> MachProcess::EnableWatchpoint()
> +// -> NativeThreadListDarwin::EnableHardwareWatchpoint().
> +uint32_t
> +NativeThreadListDarwin::EnableHardwareWatchpoint (const DNBBreakpoint*
> wp) const
> +{
> + uint32_t hw_index = INVALID_NUB_HW_INDEX;
> + if (wp != NULL)
> + {
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + const size_t num_threads = m_threads.size();
> + // On Mac OS X we have to prime the control registers for new
> threads. We do this
> + // using the control register data for the first thread, for lack
> of a better way of choosing.
> + bool also_set_on_task = true;
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + {
> + if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp,
> also_set_on_task)) == INVALID_NUB_HW_INDEX)
> + {
> + // We know that idx failed for some reason. Let's
> rollback the transaction for [0, idx).
> + for (uint32_t i = 0; i < idx; ++i)
> + m_threads[i]->RollbackTransForHWP();
> + return INVALID_NUB_HW_INDEX;
> + }
> + also_set_on_task = false;
> + }
> + // Notify each thread to commit the pending transaction.
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + m_threads[idx]->FinishTransForHWP();
> +
> + }
> + return hw_index;
> +}
> +
> +bool
> +NativeThreadListDarwin::DisableHardwareWatchpoint (const DNBBreakpoint*
> wp) const
> +{
> + if (wp != NULL)
> + {
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + const size_t num_threads = m_threads.size();
> +
> + // On Mac OS X we have to prime the control registers for new
> threads. We do this
> + // using the control register data for the first thread, for lack
> of a better way of choosing.
> + bool also_set_on_task = true;
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + {
> + if (!m_threads[idx]->DisableHardwareWatchpoint(wp,
> also_set_on_task))
> + {
> + // We know that idx failed for some reason. Let's
> rollback the transaction for [0, idx).
> + for (uint32_t i = 0; i < idx; ++i)
> + m_threads[i]->RollbackTransForHWP();
> + return false;
> + }
> + also_set_on_task = false;
> + }
> + // Notify each thread to commit the pending transaction.
> + for (uint32_t idx = 0; idx < num_threads; ++idx)
> + m_threads[idx]->FinishTransForHWP();
> +
> + return true;
> + }
> + return false;
> +}
> +
> +uint32_t
> +NativeThreadListDarwin::NumSupportedHardwareWatchpoints () const
> +{
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + const size_t num_threads = m_threads.size();
> + // Use an arbitrary thread to retrieve the number of supported
> hardware watchpoints.
> + if (num_threads)
> + return m_threads[0]->NumSupportedHardwareWatchpoints();
> + return 0;
> +}
> +
> +uint32_t
> +NativeThreadListDarwin::GetThreadIndexForThreadStoppedWithSignal (const
> int signo) const
> +{
> + PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex);
> + uint32_t should_stop = false;
> + const size_t num_threads = m_threads.size();
> + for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx)
> + {
> + if (m_threads[idx]->GetStopException().SoftSignal () == signo)
> + return idx;
> + }
> + return UINT32_MAX;
> +}
> +
> +#endif
>
> Added: lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Darwin/NativeThreadListDarwin.h?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.h
> (added)
> +++ lldb/trunk/source/Plugins/Process/Darwin/NativeThreadListDarwin.h Sat
> Sep 3 19:18:56 2016
> @@ -0,0 +1,162 @@
> +//===-- NativeThreadListDarwin.h --------------------------------------*-
> C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +//
> +// Created by Greg Clayton on 6/19/07.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef __NativeThreadListDarwin_h__
> +#define __NativeThreadListDarwin_h__
> +
> +#include <memory>
> +#include <mutex>
> +#include <vector>
> +
> +#include "lldb/lldb-private-forward.h"
> +#include "lldb/lldb-types.h"
> +
> +#include "MachException.h"
> +
> +// #include "ThreadInfo.h"
> +
> +namespace lldb_private {
> +namespace process_darwin {
> +
> +class NativeBreakpointDarwin;
> +class NativeProcessDarwin;
> +
> +class NativeThreadDarwin;
> +using NativeThreadDarwinSP = std::shared_ptr<NativeThreadDarwin>;
> +
> +class NativeThreadListDarwin
> +{
> +public:
> + NativeThreadListDarwin();
> + ~NativeThreadListDarwin();
> +
> + void
> + Clear();
> +
> + void
> + Dump(Stream &stream) const;
> +
> + // These methods will be accessed directly from NativeThreadDarwin
> +#if 0
> + bool GetRegisterValue (nub_thread_t tid, uint32_t set,
> uint32_t reg, DNBRegisterValue *reg_value) const;
> + bool SetRegisterValue (nub_thread_t tid, uint32_t set,
> uint32_t reg, const DNBRegisterValue *reg_value) const;
> + nub_size_t GetRegisterContext (nub_thread_t tid, void *buf,
> size_t buf_len);
> + nub_size_t SetRegisterContext (nub_thread_t tid, const void
> *buf, size_t buf_len);
> + uint32_t SaveRegisterState (nub_thread_t tid);
> + bool RestoreRegisterState (nub_thread_t tid, uint32_t
> save_id);
> +#endif
> +
> + const char *
> + GetThreadInfo(lldb::tid_t tid) const;
> +
> + void
> + ProcessWillResume(NativeProcessDarwin &process,
> + const ResumeActionList &thread_actions);
> +
> + uint32_t
> + ProcessDidStop(NativeProcessDarwin &process);
> +
> + bool
> + NotifyException(MachException::Data& exc);
> +
> + bool
> + ShouldStop(bool &step_more);
> +
> + // These methods will be accessed directly from NativeThreadDarwin
> +#if 0
> + const char * GetName (nub_thread_t tid);
> + nub_state_t GetState (nub_thread_t tid);
> + nub_thread_t SetCurrentThread (nub_thread_t tid);
> +#endif
> +
> + // TODO: figure out if we need to add this to NativeThreadDarwin yet.
> +#if 0
> + ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd,
> uint64_t dti_qos_class_index);
> + nub_addr_t GetPThreadT (nub_thread_t tid);
> + nub_addr_t GetDispatchQueueT (nub_thread_t tid);
> + nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t
> plo_pthread_tsd_base_address_offset, uint64_t
> plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
> +#endif
> +
> + // These methods will be accessed directly from NativeThreadDarwin
> +#if 0
> + bool GetThreadStoppedReason (nub_thread_t tid, struct
> DNBThreadStopInfo *stop_info) const;
> + void DumpThreadStoppedReason (nub_thread_t tid) const;
> + bool GetIdentifierInfo (nub_thread_t tid,
> thread_identifier_info_data_t *ident_info);
> +#endif
> +
> + size_t
> + GetNumberOfThreads() const;
> +
> + lldb::tid_t
> + ThreadIDAtIndex(size_t idx) const;
> +
> + lldb::tid_t
> + GetCurrentThreadID();
> +
> + NativeThreadDarwinSP
> + GetCurrentThread();
> +
> + void
> + NotifyBreakpointChanged(const NativeBreakpointDarwin *bp);
> +
> + uint32_t
> + EnableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const;
> +
> + bool
> + DisableHardwareBreakpoint(const NativeBreakpointDarwin *bp) const;
> +
> + uint32_t
> + EnableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const;
> +
> + bool
> + DisableHardwareWatchpoint(const NativeBreakpointDarwin *wp) const;
> +
> + uint32_t
> + GetNumberOfSupportedHardwareWatchpoints() const;
> +
> + size_t
> + GetThreadIndexForThreadStoppedWithSignal(const int signo) const;
> +
> + NativeThreadDarwinSP
> + GetThreadByID(lldb::tid_t tid) const;
> +
> + NativeThreadDarwinSP
> + GetThreadByMachPortNumber(::thread_t mach_port_number) const;
> +
> + lldb::tid_t
> + GetThreadIDByMachPortNumber(::thread_t mach_port_number) const;
> +
> + thread_t
> + GetMachPortNumberByThreadID(lldb::tid_t globally_unique_id) const;
> +
> +protected:
> + typedef std::vector<NativeThreadDarwinSP> collection;
> + typedef collection::iterator iterator;
> + typedef collection::const_iterator const_iterator;
> +
> + // Consider having this return an lldb_private::Error.
> + uint32_t
> + UpdateThreadList (NativeProcessDarwin &process, bool update,
> + collection *num_threads = nullptr);
> +
> + collection m_threads;
> + mutable std::recursive_mutex m_threads_mutex;
> + NativeThreadDarwinSP m_current_thread;
> + bool m_is_64_bit;
> +};
> +
> +} // namespace process_darwin
> +} // namespace lldb_private
> +
> +#endif // #ifndef __NativeThreadListDarwin_h__
> +
>
> Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/Linux/NativeProcessLinux.cpp?rev=
> 280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
> (original)
> +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Sat
> Sep 3 19:18:56 2016
> @@ -108,27 +108,6 @@ static bool ProcessVmReadvSupported()
>
> namespace
> {
> -Error
> -ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch)
> -{
> - // Grab process info for the running process.
> - ProcessInstanceInfo process_info;
> - if (!Host::GetProcessInfo(pid, process_info))
> - return Error("failed to get process info");
> -
> - // Resolve the executable module.
> - ModuleSpecList module_specs;
> - if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(),
> 0, 0, module_specs))
> - return Error("failed to get module specifications");
> - assert(module_specs.GetSize() == 1);
> -
> - arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture();
> - if (arch.IsValid())
> - return Error();
> - else
> - return Error("failed to retrieve a valid architecture from the
> exe module");
> -}
> -
> void
> MaybeLogLaunchInfo(const ProcessLaunchInfo &info)
> {
>
> Modified: lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerCommon.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCo
> mmon.cpp?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerCommon.cpp (original)
> +++ lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerCommon.cpp Sat Sep 3 19:18:56 2016
> @@ -12,6 +12,11 @@
> #include <errno.h>
>
> // C Includes
> +
> +#ifdef __APPLE__
> +#include <TargetConditionals.h>
> +#endif
> +
> // C++ Includes
> #include <cstring>
> #include <chrono>
> @@ -169,8 +174,11 @@ GDBRemoteCommunicationServerCommon::Hand
> response.PutCString(";");
> }
>
> - // Only send out MachO info when lldb-platform/llgs is running on a
> MachO host.
> #if defined(__APPLE__)
> + // For parity with debugserver, we'll include the vendor key.
> + response.PutCString("vendor:apple;");
> +
> + // Send out MachO info.
> uint32_t cpu = host_arch.GetMachOCPUType();
> uint32_t sub = host_arch.GetMachOCPUSubType();
> if (cpu != LLDB_INVALID_CPUTYPE)
> @@ -179,9 +187,26 @@ GDBRemoteCommunicationServerCommon::Hand
> response.Printf ("cpusubtype:%u;", sub);
>
> if (cpu == ArchSpec::kCore_arm_any)
> - response.Printf("watchpoint_exceptions_received:before;"); //
> On armv7 we use "synchronous" watchpoints which means the exception is
> delivered before the instruction executes.
> + {
> + // Indicate the OS type.
> +#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
> + response.PutCString("ostype:tvos;");
> +#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
> + response.PutCString("ostype:watchos;");
> +#else
> + response.PutCString("ostype:ios;");
> +#endif
> +
> + // On arm, we use "synchronous" watchpoints which means the
> exception is
> + // delivered before the instruction executes.
> + response.PutCString("watchpoint_exceptions_received:before;");
> + }
> else
> + {
> + response.PutCString("ostype:macosx;");
> response.Printf("watchpoint_exceptions_received:after;");
> + }
> +
> #else
> if (host_arch.GetMachine() == llvm::Triple::aarch64 ||
> host_arch.GetMachine() == llvm::Triple::aarch64_be ||
>
> Modified: lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerLLGS.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLL
> GS.cpp?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerLLGS.cpp (original)
> +++ lldb/trunk/source/Plugins/Process/gdb-remote/
> GDBRemoteCommunicationServerLLGS.cpp Sat Sep 3 19:18:56 2016
> @@ -216,7 +216,8 @@ GDBRemoteCommunicationServerLLGS::Launch
> Error error;
> {
> std::lock_guard<std::recursive_mutex> guard(m_debugged_process_
> mutex);
> - assert (!m_debugged_process_sp && "lldb-gdbserver creating
> debugged process but one already exists");
> + assert (!m_debugged_process_sp && "lldb-server creating debugged "
> + "process but one already exists");
> error = NativeProcessProtocol::Launch(
> m_process_launch_info,
> *this,
>
> Modified: lldb/trunk/source/Target/UnixSignals.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/
> Target/UnixSignals.cpp?rev=280604&r1=280603&r2=280604&view=diff
> ============================================================
> ==================
> --- lldb/trunk/source/Target/UnixSignals.cpp (original)
> +++ lldb/trunk/source/Target/UnixSignals.cpp Sat Sep 3 19:18:56 2016
> @@ -89,6 +89,8 @@ UnixSignals::Reset ()
> // This builds one standard set of Unix Signals. If yours aren't
> quite in this
> // order, you can either subclass this class, and use Add & Remove to
> change them
> // or you can subclass and build them afresh in your constructor;
> + //
> + // Note: the signals below are the Darwin signals. Do not change
> these!
> m_signals.clear();
> // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
> // ====== ============ ======== ====== ======
> ===================================================
>
> Added: lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-
> Info.plist
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-
> server/Darwin/resources/lldb-server-Info.plist?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-Info.plist
> (added)
> +++ lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-Info.plist
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,21 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "
> http://www.apple.com/DTDs/PropertyList-1.0.dtd">
> +<plist version="1.0">
> +<dict>
> + <key>CFBundleDevelopmentRegion</key>
> + <string>English</string>
> + <key>CFBundleIdentifier</key>
> + <string>com.apple.lldb-server</string>
> + <key>CFBundleInfoDictionaryVersion</key>
> + <string>6.0</string>
> + <key>CFBundleName</key>
> + <string>lldb-server</string>
> + <key>CFBundleVersion</key>
> + <string>2</string>
> + <key>SecTaskAccess</key>
> + <array>
> + <string>allowed</string>
> + <string>debug</string>
> + </array>
> +</dict>
> +</plist>
>
> Added: lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-
> entitlements.plist
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-
> server/Darwin/resources/lldb-server-entitlements.plist?rev=
> 280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist
> (added)
> +++ lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,28 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "
> http://www.apple.com/DTDs/PropertyList-1.0.dtd">
> +<plist version="1.0">
> +<dict>
> + <key>com.apple.springboard.debugapplications</key>
> + <true/>
> + <key>com.apple.backboardd.launchapplications</key>
> + <true/>
> + <key>com.apple.backboardd.debugapplications</key>
> + <true/>
> + <key>com.apple.frontboard.launchapplications</key>
> + <true/>
> + <key>com.apple.frontboard.debugapplications</key>
> + <true/>
> + <key>run-unsigned-code</key>
> + <true/>
> + <key>seatbelt-profiles</key>
> + <array>
> + <string>debugserver</string>
> + </array>
> + <key>com.apple.diagnosticd.diagnostic</key>
> + <true/>
> + <key>com.apple.security.network.server</key>
> + <true/>
> + <key>com.apple.security.network.client</key>
> + <true/>
> +</dict>
> +</plist>
>
> Added: lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-
> macos-entitlements.plist
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-
> server/Darwin/resources/lldb-server-macos-entitlements.
> plist?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist
> (added)
> +++ lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,8 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "
> http://www.apple.com/DTDs/PropertyList-1.0.dtd">
> +<plist version="1.0">
> +<dict>
> + <key>com.apple.diagnosticd.diagnostic</key>
> + <true/>
> +</dict>
> +</plist>
>
> Added: lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-
> server/Darwin/resources/lldb-server-mig.defs?rev=280604&view=auto
> ============================================================
> ==================
> --- lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
> (added)
> +++ lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-mig.defs
> Sat Sep 3 19:18:56 2016
> @@ -0,0 +1,5 @@
> +/*
> + * nub.defs
> + */
> +
> +#import <mach/mach_exc.defs>
>
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
>
--
-Todd
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20160903/7b765c15/attachment-0001.html>
More information about the lldb-commits
mailing list