1 //===-- PlatformRemoteGDBServer.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 10 #include "lldb/lldb-python.h" 11 12 #include "PlatformRemoteGDBServer.h" 13 14 // C Includes 15 #include <sys/sysctl.h> 16 17 // C++ Includes 18 // Other libraries and framework includes 19 // Project includes 20 #include "lldb/Breakpoint/BreakpointLocation.h" 21 #include "lldb/Core/ConnectionFileDescriptor.h" 22 #include "lldb/Core/Debugger.h" 23 #include "lldb/Core/Error.h" 24 #include "lldb/Core/Module.h" 25 #include "lldb/Core/ModuleList.h" 26 #include "lldb/Core/PluginManager.h" 27 #include "lldb/Core/StreamString.h" 28 #include "lldb/Host/FileSpec.h" 29 #include "lldb/Host/Host.h" 30 #include "lldb/Target/Process.h" 31 #include "lldb/Target/Target.h" 32 33 using namespace lldb; 34 using namespace lldb_private; 35 36 static bool g_initialized = false; 37 38 void 39 PlatformRemoteGDBServer::Initialize () 40 { 41 if (g_initialized == false) 42 { 43 g_initialized = true; 44 PluginManager::RegisterPlugin (PlatformRemoteGDBServer::GetShortPluginNameStatic(), 45 PlatformRemoteGDBServer::GetDescriptionStatic(), 46 PlatformRemoteGDBServer::CreateInstance); 47 } 48 } 49 50 void 51 PlatformRemoteGDBServer::Terminate () 52 { 53 if (g_initialized) 54 { 55 g_initialized = false; 56 PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance); 57 } 58 } 59 60 Platform* 61 PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch) 62 { 63 bool create = force; 64 if (!create) 65 { 66 create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified(); 67 } 68 if (create) 69 return new PlatformRemoteGDBServer (); 70 return NULL; 71 } 72 73 74 const char * 75 PlatformRemoteGDBServer::GetShortPluginNameStatic() 76 { 77 return "remote-gdb-server"; 78 } 79 80 const char * 81 PlatformRemoteGDBServer::GetDescriptionStatic() 82 { 83 return "A platform that uses the GDB remote protocol as the communication transport."; 84 } 85 86 const char * 87 PlatformRemoteGDBServer::GetDescription () 88 { 89 if (m_platform_description.empty()) 90 { 91 if (IsConnected()) 92 { 93 // Send the get description packet 94 } 95 } 96 97 if (!m_platform_description.empty()) 98 return m_platform_description.c_str(); 99 return GetDescriptionStatic(); 100 } 101 102 Error 103 PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file, 104 const ArchSpec &exe_arch, 105 lldb::ModuleSP &exe_module_sp, 106 const FileSpecList *module_search_paths_ptr) 107 { 108 Error error; 109 error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented"); 110 return error; 111 } 112 113 Error 114 PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file, 115 const UUID *uuid_ptr, 116 FileSpec &local_file) 117 { 118 // Default to the local case 119 local_file = platform_file; 120 return Error(); 121 } 122 123 //------------------------------------------------------------------ 124 /// Default Constructor 125 //------------------------------------------------------------------ 126 PlatformRemoteGDBServer::PlatformRemoteGDBServer () : 127 Platform(false), // This is a remote platform 128 m_gdb_client(true) 129 { 130 } 131 132 //------------------------------------------------------------------ 133 /// Destructor. 134 /// 135 /// The destructor is virtual since this class is designed to be 136 /// inherited from by the plug-in instance. 137 //------------------------------------------------------------------ 138 PlatformRemoteGDBServer::~PlatformRemoteGDBServer() 139 { 140 } 141 142 bool 143 PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 144 { 145 return false; 146 } 147 148 size_t 149 PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) 150 { 151 // This isn't needed if the z/Z packets are supported in the GDB remote 152 // server. But we might need a packet to detect this. 153 return 0; 154 } 155 156 bool 157 PlatformRemoteGDBServer::GetRemoteOSVersion () 158 { 159 uint32_t major, minor, update; 160 if (m_gdb_client.GetOSVersion (major, minor, update)) 161 { 162 m_major_os_version = major; 163 m_minor_os_version = minor; 164 m_update_os_version = update; 165 return true; 166 } 167 return false; 168 } 169 170 bool 171 PlatformRemoteGDBServer::GetRemoteOSBuildString (std::string &s) 172 { 173 return m_gdb_client.GetOSBuildString (s); 174 } 175 176 bool 177 PlatformRemoteGDBServer::GetRemoteOSKernelDescription (std::string &s) 178 { 179 return m_gdb_client.GetOSKernelDescription (s); 180 } 181 182 // Remote Platform subclasses need to override this function 183 ArchSpec 184 PlatformRemoteGDBServer::GetRemoteSystemArchitecture () 185 { 186 return m_gdb_client.GetSystemArchitecture(); 187 } 188 189 bool 190 PlatformRemoteGDBServer::IsConnected () const 191 { 192 return m_gdb_client.IsConnected(); 193 } 194 195 Error 196 PlatformRemoteGDBServer::ConnectRemote (Args& args) 197 { 198 Error error; 199 if (IsConnected()) 200 { 201 error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection", 202 GetHostname()); 203 } 204 else 205 { 206 if (args.GetArgumentCount() == 1) 207 { 208 const char *url = args.GetArgumentAtIndex(0); 209 m_gdb_client.SetConnection (new ConnectionFileDescriptor()); 210 const ConnectionStatus status = m_gdb_client.Connect(url, &error); 211 if (status == eConnectionStatusSuccess) 212 { 213 if (m_gdb_client.HandshakeWithServer(&error)) 214 { 215 m_gdb_client.QueryNoAckModeSupported(); 216 m_gdb_client.GetHostInfo(); 217 #if 0 218 m_gdb_client.TestPacketSpeed(10000); 219 #endif 220 } 221 else 222 { 223 m_gdb_client.Disconnect(); 224 } 225 } 226 } 227 else 228 { 229 error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>"); 230 } 231 } 232 233 return error; 234 } 235 236 Error 237 PlatformRemoteGDBServer::DisconnectRemote () 238 { 239 Error error; 240 m_gdb_client.Disconnect(&error); 241 return error; 242 } 243 244 const char * 245 PlatformRemoteGDBServer::GetHostname () 246 { 247 m_gdb_client.GetHostname (m_name); 248 if (m_name.empty()) 249 return NULL; 250 return m_name.c_str(); 251 } 252 253 const char * 254 PlatformRemoteGDBServer::GetUserName (uint32_t uid) 255 { 256 // Try and get a cache user name first 257 const char *cached_user_name = Platform::GetUserName(uid); 258 if (cached_user_name) 259 return cached_user_name; 260 std::string name; 261 if (m_gdb_client.GetUserName(uid, name)) 262 return SetCachedUserName(uid, name.c_str(), name.size()); 263 264 SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets 265 return NULL; 266 } 267 268 const char * 269 PlatformRemoteGDBServer::GetGroupName (uint32_t gid) 270 { 271 const char *cached_group_name = Platform::GetGroupName(gid); 272 if (cached_group_name) 273 return cached_group_name; 274 std::string name; 275 if (m_gdb_client.GetGroupName(gid, name)) 276 return SetCachedGroupName(gid, name.c_str(), name.size()); 277 278 SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets 279 return NULL; 280 } 281 282 uint32_t 283 PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info, 284 ProcessInstanceInfoList &process_infos) 285 { 286 return m_gdb_client.FindProcesses (match_info, process_infos); 287 } 288 289 bool 290 PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 291 { 292 return m_gdb_client.GetProcessInfo (pid, process_info); 293 } 294 295 296 Error 297 PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) 298 { 299 Error error; 300 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; 301 302 m_gdb_client.SetSTDIN ("/dev/null"); 303 m_gdb_client.SetSTDOUT ("/dev/null"); 304 m_gdb_client.SetSTDERR ("/dev/null"); 305 m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)); 306 307 const char *working_dir = launch_info.GetWorkingDirectory(); 308 if (working_dir && working_dir[0]) 309 { 310 m_gdb_client.SetWorkingDir (working_dir); 311 } 312 313 // Send the environment and the program + arguments after we connect 314 const char **argv = launch_info.GetArguments().GetConstArgumentVector(); 315 const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector(); 316 317 if (envp) 318 { 319 const char *env_entry; 320 for (int i=0; (env_entry = envp[i]); ++i) 321 { 322 if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0) 323 break; 324 } 325 } 326 const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5); 327 int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv); 328 m_gdb_client.SetPacketTimeout (old_packet_timeout); 329 if (arg_packet_err == 0) 330 { 331 std::string error_str; 332 if (m_gdb_client.GetLaunchSuccess (error_str)) 333 { 334 pid = m_gdb_client.GetCurrentProcessID (); 335 if (pid != LLDB_INVALID_PROCESS_ID) 336 launch_info.SetProcessID (pid); 337 } 338 else 339 { 340 error.SetErrorString (error_str.c_str()); 341 } 342 } 343 else 344 { 345 error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err); 346 } 347 return error; 348 } 349 350 lldb::ProcessSP 351 PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, 352 Debugger &debugger, 353 Target *target, // Can be NULL, if NULL create a new target, else use existing one 354 Listener &listener, 355 Error &error) 356 { 357 lldb::ProcessSP process_sp; 358 if (IsRemote()) 359 { 360 if (IsConnected()) 361 { 362 uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(); 363 364 if (port == 0) 365 { 366 error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); 367 } 368 else 369 { 370 if (target == NULL) 371 { 372 TargetSP new_target_sp; 373 374 error = debugger.GetTargetList().CreateTarget (debugger, 375 NULL, 376 NULL, 377 false, 378 NULL, 379 new_target_sp); 380 target = new_target_sp.get(); 381 } 382 else 383 error.Clear(); 384 385 if (target && error.Success()) 386 { 387 debugger.GetTargetList().SetSelectedTarget(target); 388 389 // The darwin always currently uses the GDB remote debugger plug-in 390 // so even when debugging locally we are debugging remotely! 391 process_sp = target->CreateProcess (listener, "gdb-remote", NULL); 392 393 if (process_sp) 394 { 395 char connect_url[256]; 396 const int connect_url_len = ::snprintf (connect_url, 397 sizeof(connect_url), 398 "connect://%s:%u", 399 GetHostname (), 400 port); 401 assert (connect_url_len < sizeof(connect_url)); 402 error = process_sp->ConnectRemote (NULL, connect_url); 403 if (error.Success()) 404 error = process_sp->Attach(attach_info); 405 } 406 } 407 } 408 } 409 else 410 { 411 error.SetErrorString("not connected to remote gdb server"); 412 } 413 } 414 return process_sp; 415 } 416 417 418