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