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 23using namespace lldb; 24using namespace lldb_private; 25 26struct MessageType 27{ 28 mach_msg_header_t head; 29 ConnectionMachPort::PayloadType payload; 30}; 31 32 33 34ConnectionMachPort::ConnectionMachPort () : 35 Connection(), 36 m_task(mach_task_self()), 37 m_port(MACH_PORT_TYPE_NONE) 38{ 39} 40 41ConnectionMachPort::~ConnectionMachPort () 42{ 43 Disconnect (NULL); 44} 45 46bool 47ConnectionMachPort::IsConnected () const 48{ 49 return m_port != MACH_PORT_TYPE_NONE; 50} 51 52ConnectionStatus 53ConnectionMachPort::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 118ConnectionStatus 119ConnectionMachPort::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 154lldb::ConnectionStatus 155ConnectionMachPort::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 197ConnectionStatus 198ConnectionMachPort::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 215size_t 216ConnectionMachPort::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 238size_t 239ConnectionMachPort::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 258ConnectionStatus 259ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) 260{ 261 return eConnectionStatusLostConnection; 262} 263 264kern_return_t 265ConnectionMachPort::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 302kern_return_t 303ConnectionMachPort::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__) 324