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