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