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