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