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