1 //===-- PlatformLinux.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 "PlatformLinux.h" 11 12 // C Includes 13 #include <stdio.h> 14 #include <sys/utsname.h> 15 16 // C++ Includes 17 // Other libraries and framework includes 18 // Project includes 19 #include "lldb/Core/Error.h" 20 #include "lldb/Core/Debugger.h" 21 #include "lldb/Core/Module.h" 22 #include "lldb/Core/ModuleList.h" 23 #include "lldb/Core/PluginManager.h" 24 #include "lldb/Core/StreamString.h" 25 #include "lldb/Host/FileSpec.h" 26 #include "lldb/Host/Host.h" 27 #include "lldb/Target/Target.h" 28 #include "lldb/Target/Process.h" 29 30 using namespace lldb; 31 using namespace lldb_private; 32 33 static uint32_t g_initialize_count = 0; 34 35 Platform * 36 PlatformLinux::CreateInstance () 37 { 38 return new PlatformLinux(true); 39 } 40 41 const char * 42 PlatformLinux::GetPluginNameStatic() 43 { 44 return "plugin.platform.linux"; 45 } 46 47 const char * 48 PlatformLinux::GetShortPluginNameStatic (bool is_host) 49 { 50 if (is_host) 51 return Platform::GetHostPlatformName (); 52 else 53 return "remote-linux"; 54 } 55 56 const char * 57 PlatformLinux::GetPluginDescriptionStatic (bool is_host) 58 { 59 if (is_host) 60 return "Local Linux user platform plug-in."; 61 else 62 return "Remote Linux user platform plug-in."; 63 } 64 65 void 66 PlatformLinux::Initialize () 67 { 68 if (g_initialize_count++ == 0) 69 { 70 #if defined(__linux__) 71 PlatformSP default_platform_sp (new PlatformLinux(true)); 72 default_platform_sp->SetSystemArchitecture (Host::GetArchitecture()); 73 Platform::SetDefaultPlatform (default_platform_sp); 74 #endif 75 PluginManager::RegisterPlugin(PlatformLinux::GetShortPluginNameStatic(false), 76 PlatformLinux::GetPluginDescriptionStatic(false), 77 PlatformLinux::CreateInstance); 78 } 79 } 80 81 void 82 PlatformLinux::Terminate () 83 { 84 if (g_initialize_count > 0) 85 { 86 if (--g_initialize_count == 0) 87 { 88 PluginManager::UnregisterPlugin (PlatformLinux::CreateInstance); 89 } 90 } 91 } 92 93 Error 94 PlatformLinux::ResolveExecutable (const FileSpec &exe_file, 95 const ArchSpec &exe_arch, 96 lldb::ModuleSP &exe_module_sp) 97 { 98 Error error; 99 // Nothing special to do here, just use the actual file and architecture 100 101 char exe_path[PATH_MAX]; 102 FileSpec resolved_exe_file (exe_file); 103 104 if (IsHost()) 105 { 106 // If we have "ls" as the exe_file, resolve the executable location based on 107 // the current path variables 108 if (!resolved_exe_file.Exists()) 109 { 110 exe_file.GetPath(exe_path, sizeof(exe_path)); 111 resolved_exe_file.SetFile(exe_path, true); 112 } 113 114 if (!resolved_exe_file.Exists()) 115 resolved_exe_file.ResolveExecutableLocation (); 116 117 if (resolved_exe_file.Exists()) 118 error.Clear(); 119 else 120 { 121 exe_file.GetPath(exe_path, sizeof(exe_path)); 122 error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path); 123 } 124 } 125 else 126 { 127 if (m_remote_platform_sp) 128 { 129 error = m_remote_platform_sp->ResolveExecutable (exe_file, 130 exe_arch, 131 exe_module_sp); 132 } 133 else 134 { 135 // We may connect to a process and use the provided executable (Don't use local $PATH). 136 137 if (resolved_exe_file.Exists()) 138 error.Clear(); 139 else 140 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); 141 } 142 } 143 144 if (error.Success()) 145 { 146 if (exe_arch.IsValid()) 147 { 148 error = ModuleList::GetSharedModule (resolved_exe_file, 149 exe_arch, 150 NULL, 151 NULL, 152 0, 153 exe_module_sp, 154 NULL, 155 NULL); 156 157 if (exe_module_sp->GetObjectFile() == NULL) 158 { 159 exe_module_sp.reset(); 160 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain the architecture %s", 161 exe_file.GetDirectory().AsCString(""), 162 exe_file.GetDirectory() ? "/" : "", 163 exe_file.GetFilename().AsCString(""), 164 exe_arch.GetArchitectureName()); 165 } 166 } 167 else 168 { 169 // No valid architecture was specified, ask the platform for 170 // the architectures that we should be using (in the correct order) 171 // and see if we can find a match that way 172 StreamString arch_names; 173 ArchSpec platform_arch; 174 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx) 175 { 176 error = ModuleList::GetSharedModule (resolved_exe_file, 177 platform_arch, 178 NULL, 179 NULL, 180 0, 181 exe_module_sp, 182 NULL, 183 NULL); 184 // Did we find an executable using one of the 185 if (error.Success()) 186 { 187 if (exe_module_sp && exe_module_sp->GetObjectFile()) 188 break; 189 else 190 error.SetErrorToGenericError(); 191 } 192 193 if (idx > 0) 194 arch_names.PutCString (", "); 195 arch_names.PutCString (platform_arch.GetArchitectureName()); 196 } 197 198 if (error.Fail() || !exe_module_sp) 199 { 200 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s", 201 exe_file.GetDirectory().AsCString(""), 202 exe_file.GetDirectory() ? "/" : "", 203 exe_file.GetFilename().AsCString(""), 204 GetShortPluginName(), 205 arch_names.GetString().c_str()); 206 } 207 } 208 } 209 210 return error; 211 } 212 213 Error 214 PlatformLinux::GetFile (const FileSpec &platform_file, 215 const UUID *uuid_ptr, FileSpec &local_file) 216 { 217 if (IsRemote()) 218 { 219 if (m_remote_platform_sp) 220 return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file); 221 } 222 223 // Default to the local case 224 local_file = platform_file; 225 return Error(); 226 } 227 228 229 //------------------------------------------------------------------ 230 /// Default Constructor 231 //------------------------------------------------------------------ 232 PlatformLinux::PlatformLinux (bool is_host) : 233 Platform(is_host), // This is the local host platform 234 m_remote_platform_sp () 235 { 236 } 237 238 //------------------------------------------------------------------ 239 /// Destructor. 240 /// 241 /// The destructor is virtual since this class is designed to be 242 /// inherited from by the plug-in instance. 243 //------------------------------------------------------------------ 244 PlatformLinux::~PlatformLinux() 245 { 246 } 247 248 bool 249 PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 250 { 251 bool success = false; 252 if (IsHost()) 253 { 254 success = Platform::GetProcessInfo (pid, process_info); 255 } 256 else 257 { 258 if (m_remote_platform_sp) 259 success = m_remote_platform_sp->GetProcessInfo (pid, process_info); 260 } 261 return success; 262 } 263 264 bool 265 PlatformLinux::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 266 { 267 if (idx == 0) 268 { 269 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 270 return arch.IsValid(); 271 } 272 return false; 273 } 274 275 void 276 PlatformLinux::GetStatus (Stream &strm) 277 { 278 struct utsname un; 279 280 if (uname(&un)) { 281 strm << "Linux"; 282 return; 283 } 284 285 strm << un.sysname << ' ' << un.release << ' ' << un.version << '\n'; 286 } 287 288 size_t 289 PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target, 290 BreakpointSite *bp_site) 291 { 292 ArchSpec arch = target.GetArchitecture(); 293 const uint8_t *trap_opcode = NULL; 294 size_t trap_opcode_size = 0; 295 296 switch (arch.GetCore()) 297 { 298 default: 299 assert(false && "CPU type not supported!"); 300 break; 301 302 case ArchSpec::eCore_x86_32_i386: 303 case ArchSpec::eCore_x86_64_x86_64: 304 { 305 static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC }; 306 trap_opcode = g_i386_breakpoint_opcode; 307 trap_opcode_size = sizeof(g_i386_breakpoint_opcode); 308 } 309 break; 310 } 311 312 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 313 return trap_opcode_size; 314 return 0; 315 } 316 317 Error 318 PlatformLinux::LaunchProcess (ProcessLaunchInfo &launch_info) 319 { 320 Error error; 321 322 if (IsHost()) 323 { 324 if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell)) 325 { 326 const bool is_localhost = true; 327 if (!launch_info.ConvertArgumentsForLaunchingInShell (error, is_localhost)) 328 return error; 329 } 330 error = Platform::LaunchProcess (launch_info); 331 } 332 else 333 { 334 error.SetErrorString ("the platform is not currently connected"); 335 } 336 return error; 337 } 338 339 lldb::ProcessSP 340 PlatformLinux::Attach(ProcessAttachInfo &attach_info, 341 Debugger &debugger, 342 Target *target, 343 Listener &listener, 344 Error &error) 345 { 346 lldb::ProcessSP process_sp; 347 if (IsHost()) 348 { 349 if (target == NULL) 350 { 351 TargetSP new_target_sp; 352 FileSpec emptyFileSpec; 353 ArchSpec emptyArchSpec; 354 355 error = debugger.GetTargetList().CreateTarget (debugger, 356 emptyFileSpec, 357 emptyArchSpec, 358 false, 359 m_remote_platform_sp, 360 new_target_sp); 361 target = new_target_sp.get(); 362 } 363 else 364 error.Clear(); 365 366 if (target && error.Success()) 367 { 368 debugger.GetTargetList().SetSelectedTarget(target); 369 370 process_sp = target->CreateProcess (listener, attach_info.GetProcessPluginName()); 371 372 if (process_sp) 373 error = process_sp->Attach (attach_info); 374 } 375 } 376 else 377 { 378 if (m_remote_platform_sp) 379 process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error); 380 else 381 error.SetErrorString ("the platform is not currently connected"); 382 } 383 return process_sp; 384 } 385