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