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