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