]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Core/ConnectionMachPort.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / source / Core / ConnectionMachPort.cpp
1 //===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #if defined(__APPLE__)
10
11 #include "lldb/Core/ConnectionMachPort.h"
12
13 // C Includes
14 #include <mach/mach.h>
15 #include <servers/bootstrap.h>
16
17 // C++ Includes
18 // Other libraries and framework includes
19 // Project includes
20 #include "lldb/lldb-private-log.h"
21 #include "lldb/Core/Communication.h"
22 #include "lldb/Core/Log.h"
23
24 using namespace lldb;
25 using namespace lldb_private;
26
27 struct MessageType
28 {
29     mach_msg_header_t head;
30     ConnectionMachPort::PayloadType payload;
31 };
32
33
34
35 ConnectionMachPort::ConnectionMachPort () :
36     Connection(),
37     m_task(mach_task_self()),
38     m_port(MACH_PORT_TYPE_NONE)
39 {
40 }
41
42 ConnectionMachPort::~ConnectionMachPort ()
43 {
44     Disconnect (NULL);
45 }
46
47 bool
48 ConnectionMachPort::IsConnected () const
49 {
50     return  m_port != MACH_PORT_TYPE_NONE;
51 }
52
53 ConnectionStatus
54 ConnectionMachPort::Connect (const char *s, Error *error_ptr)
55 {
56     if (IsConnected())
57     {
58         if (error_ptr)
59             error_ptr->SetErrorString ("already connected");
60         return eConnectionStatusError;
61     }
62     
63     if (s == NULL || s[0] == '\0')
64     {
65         if (error_ptr)
66             error_ptr->SetErrorString ("empty connect URL");
67         return eConnectionStatusError;
68     }
69     
70     ConnectionStatus status = eConnectionStatusError;
71     
72     if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
73     {
74         s += strlen("bootstrap-checkin://");
75         
76         if (*s)
77         {
78             status = BootstrapCheckIn (s, error_ptr);
79         }
80         else
81         {
82             if (error_ptr)
83                 error_ptr->SetErrorString ("bootstrap port name is empty");
84         }
85     }
86     else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
87     {
88         s += strlen("bootstrap-lookup://");
89         if (*s)
90         {
91             status = BootstrapLookup (s, error_ptr);
92         }
93         else
94         {
95             if (error_ptr)
96                 error_ptr->SetErrorString ("bootstrap port name is empty");
97         }
98     }
99     else
100     {
101         if (error_ptr)
102             error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);   
103     }
104
105
106     if (status == eConnectionStatusSuccess)
107     {
108         if (error_ptr)
109             error_ptr->Clear();
110     }
111     else
112     {
113         Disconnect(NULL);
114     }
115         
116     return status;
117 }
118
119 ConnectionStatus
120 ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
121 {
122     mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
123     
124     /* Getting bootstrap server port */
125     kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
126     if (kret == KERN_SUCCESS) 
127     {
128         name_t port_name;
129         int len = snprintf(port_name, sizeof(port_name), "%s", port);
130         if (len < sizeof(port_name))
131         {
132             kret = ::bootstrap_check_in (bootstrap_port, 
133                                          port_name, 
134                                          &m_port);
135         }
136         else
137         {
138             Disconnect(NULL);
139             if (error_ptr)
140                 error_ptr->SetErrorString ("bootstrap is too long");
141             return eConnectionStatusError;
142         }
143     }
144     
145     if (kret != KERN_SUCCESS)
146     {
147         Disconnect(NULL);
148         if (error_ptr)
149             error_ptr->SetError (kret, eErrorTypeMachKernel);
150         return eConnectionStatusError;
151     }
152     return eConnectionStatusSuccess;
153 }
154
155 lldb::ConnectionStatus
156 ConnectionMachPort::BootstrapLookup (const char *port, 
157                                      Error *error_ptr)
158 {
159     name_t port_name;
160
161     if (port && port[0])
162     {
163         if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
164         {
165             if (error_ptr)
166                 error_ptr->SetErrorString ("port netname is too long");
167             return eConnectionStatusError;
168         }
169     }
170     else
171     {
172         if (error_ptr)
173             error_ptr->SetErrorString ("empty port netname");
174         return eConnectionStatusError;
175     }
176
177     mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
178     
179     /* Getting bootstrap server port */
180     kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
181     if (kret == KERN_SUCCESS) 
182     {
183         kret = ::bootstrap_look_up (bootstrap_port, 
184                                     port_name, 
185                                     &m_port);
186     }
187
188     if (kret != KERN_SUCCESS)
189     {
190         if (error_ptr)
191             error_ptr->SetError (kret, eErrorTypeMachKernel);
192         return eConnectionStatusError;
193     }
194
195     return eConnectionStatusSuccess;
196 }
197
198 ConnectionStatus
199 ConnectionMachPort::Disconnect (Error *error_ptr)
200 {
201     kern_return_t kret;
202     
203     // TODO: verify if we need to netname_check_out for
204     // either or both 
205     if (m_port != MACH_PORT_TYPE_NONE)
206     {
207         kret = ::mach_port_deallocate (m_task, m_port);       
208         if (error_ptr)
209             error_ptr->SetError (kret, eErrorTypeMachKernel);
210         m_port = MACH_PORT_TYPE_NONE;
211     }
212
213     return eConnectionStatusSuccess;
214 }
215
216 size_t
217 ConnectionMachPort::Read (void *dst, 
218                           size_t dst_len, 
219                           uint32_t timeout_usec,
220                           ConnectionStatus &status, 
221                           Error *error_ptr)
222 {
223     PayloadType payload;
224     
225     kern_return_t kret = Receive (payload);
226     if (kret == KERN_SUCCESS)
227     {
228         memcpy (dst, payload.data, payload.data_length);
229         status = eConnectionStatusSuccess;
230         return payload.data_length;
231     }
232     
233     if (error_ptr)
234         error_ptr->SetError (kret, eErrorTypeMachKernel);
235     status = eConnectionStatusError;
236     return 0;
237 }
238
239 size_t
240 ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
241 {
242     PayloadType payload;
243     payload.command = 0;
244     payload.data_length = src_len;
245     const size_t max_payload_size = sizeof(payload.data);
246     if (src_len > max_payload_size)
247         payload.data_length = max_payload_size;
248     memcpy (payload.data, src, payload.data_length);
249     
250     if (Send (payload) == KERN_SUCCESS)
251     {
252         status = eConnectionStatusSuccess;
253         return payload.data_length;
254     }
255     status = eConnectionStatusError;
256     return 0;
257 }
258
259 ConnectionStatus
260 ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
261 {
262     return eConnectionStatusLostConnection;
263 }
264
265 kern_return_t 
266 ConnectionMachPort::Send (const PayloadType &payload)
267 {
268         struct MessageType message;
269     
270         /* (i) Form the message : */
271     
272         /* (i.a) Fill the header fields : */
273         message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) | 
274                              MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
275         message.head.msgh_size = sizeof(MessageType);
276         message.head.msgh_local_port = MACH_PORT_NULL;
277         message.head.msgh_remote_port = m_port;
278     
279         /* (i.b) Explain the message type ( an integer ) */
280     //  message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
281     //  message.type.msgt_size = 32;
282     //  message.type.msgt_number = 1;
283     //  message.type.msgt_inline = TRUE;
284     //  message.type.msgt_longform = FALSE;
285     //  message.type.msgt_deallocate = FALSE;
286         /* message.type.msgt_unused = 0; */ /* not needed, I think */
287     
288         /* (i.c) Fill the message with the given integer : */
289         message.payload = payload;
290     
291         /* (ii) Send the message : */
292         kern_return_t kret = ::mach_msg (&message.head, 
293                                      MACH_SEND_MSG, 
294                                      message.head.msgh_size, 
295                                      0, 
296                                      MACH_PORT_NULL, 
297                                      MACH_MSG_TIMEOUT_NONE, 
298                                      MACH_PORT_NULL);
299     
300         return kret;
301 }
302
303 kern_return_t 
304 ConnectionMachPort::Receive (PayloadType &payload)
305 {
306         MessageType message;
307         message.head.msgh_size = sizeof(MessageType);
308     
309         kern_return_t kret = ::mach_msg (&message.head, 
310                                      MACH_RCV_MSG, 
311                                      0, 
312                                      sizeof(MessageType), 
313                                      m_port,
314                                      MACH_MSG_TIMEOUT_NONE, 
315                                      MACH_PORT_NULL);
316     
317     if (kret == KERN_SUCCESS)
318         payload = message.payload;
319
320         return kret;
321 }
322
323
324 #endif // #if defined(__APPLE__)