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