[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