[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:56:13 PDT 2016
On Sat, Sep 3, 2016 at 5:44 PM, Todd Fiala <todd.fiala at gmail.com> wrote:
> One of the new tests failed on at least one of the builders (I think
> Android).
>
That's incorrect - it was the Ubuntu, not Android, builder that I first saw.
> I'm going to XFAIL that test and check that in momentarily.
>
>
I XFAILed the failing tests and added a PR to track.
> -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-en
>> titlements.plist
>> lldb/trunk/tools/lldb-server/Darwin/resources/lldb-server-ma
>> cos-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/GDBRemoteCommun
>> icationServerCommon.cpp
>> lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommun
>> icationServerLLGS.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/Pyth
>> on/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInf
>> o.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/Pyth
>> on/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_wor
>> king_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_gdbre
>> mote_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/Pyth
>> on/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/Pyth
>> on/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemote
>> ExitCode.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_gdbre
>> mote_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/Pyth
>> on/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/Pyth
>> on/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/Pyth
>> on/lldbsuite/test/tools/lldb-server/host-info/TestGdbRemote
>> HostInfo.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.GetExecut
>> ableFile(),
>> + 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/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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_des
>> troy);
>> +
>> + // 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().Get
>> ConstArgumentVector();
>> + 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/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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::CatchE
>> xceptionRaise()
>> +// 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.e
>> xception.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.d
>> ata_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_id
>> entity,
>> + // 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.thre
>> ad_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/Plugin
>> s/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/Plugin
>> s/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_de
>> legate))
>> + {
>> + 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_mu
>> tex);
>> + 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)->DoExceptionThre
>> ad();
>> +}
>> +
>> +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_mu
>> tex);
>> + 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_pi
>> d);
>> + 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.GetReadFil
>> eDescriptor(),
>> + 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_mu
>> tex);
>> + 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_mu
>> tex);
>> + 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/Plugin
>> s/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::NativeD
>> elegate
>> + &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/Plugin
>> s/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/Plugin
>> s/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/NativeThreadListDar
>> win.cpp
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugin
>> s/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/Plugin
>> s/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/Plugin
>> s/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/GDBRemoteCommun
>> icationServerCommon.cpp
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugin
>> s/Process/gdb-remote/GDBRemoteCommunicationServerCommon.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/GDBRemoteCommun
>> icationServerLLGS.cpp
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugin
>> s/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.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-In
>> fo.plist
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-se
>> rver/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-en
>> titlements.plist
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-se
>> rver/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-ma
>> cos-entitlements.plist
>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-se
>> rver/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-se
>> rver/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
>
--
-Todd
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20160903/35c8f35f/attachment-0001.html>
More information about the lldb-commits
mailing list