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 const FileSpecList *module_search_paths_ptr) 98 { 99 Error error; 100 // Nothing special to do here, just use the actual file and architecture 101 102 char exe_path[PATH_MAX]; 103 FileSpec resolved_exe_file (exe_file); 104 105 if (IsHost()) 106 { 107 // If we have "ls" as the exe_file, resolve the executable location based on 108 // the current path variables 109 if (!resolved_exe_file.Exists()) 110 { 111 exe_file.GetPath(exe_path, sizeof(exe_path)); 112 resolved_exe_file.SetFile(exe_path, true); 113 } 114 115 if (!resolved_exe_file.Exists()) 116 resolved_exe_file.ResolveExecutableLocation (); 117 118 if (resolved_exe_file.Exists()) 119 error.Clear(); 120 else 121 { 122 exe_file.GetPath(exe_path, sizeof(exe_path)); 123 error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path); 124 } 125 } 126 else 127 { 128 if (m_remote_platform_sp) 129 { 130 error = m_remote_platform_sp->ResolveExecutable (exe_file, 131 exe_arch, 132 exe_module_sp, 133 NULL); 134 } 135 else 136 { 137 // We may connect to a process and use the provided executable (Don't use local $PATH). 138 139 if (resolved_exe_file.Exists()) 140 error.Clear(); 141 else 142 error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path); 143 } 144 } 145 146 if (error.Success()) 147 { 148 ModuleSpec module_spec (resolved_exe_file, exe_arch); 149 if (exe_arch.IsValid()) 150 { 151 error = ModuleList::GetSharedModule (module_spec, 152 exe_module_sp, 153 NULL, 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 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx) 174 { 175 error = ModuleList::GetSharedModule (module_spec, 176 exe_module_sp, 177 NULL, 178 NULL, 179 NULL); 180 // Did we find an executable using one of the 181 if (error.Success()) 182 { 183 if (exe_module_sp && exe_module_sp->GetObjectFile()) 184 break; 185 else 186 error.SetErrorToGenericError(); 187 } 188 189 if (idx > 0) 190 arch_names.PutCString (", "); 191 arch_names.PutCString (module_spec.GetArchitecture().GetArchitectureName()); 192 } 193 194 if (error.Fail() || !exe_module_sp) 195 { 196 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s", 197 exe_file.GetDirectory().AsCString(""), 198 exe_file.GetDirectory() ? "/" : "", 199 exe_file.GetFilename().AsCString(""), 200 GetShortPluginName(), 201 arch_names.GetString().c_str()); 202 } 203 } 204 } 205 206 return error; 207 } 208 209 Error 210 PlatformLinux::GetFile (const FileSpec &platform_file, 211 const UUID *uuid_ptr, FileSpec &local_file) 212 { 213 if (IsRemote()) 214 { 215 if (m_remote_platform_sp) 216 return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file); 217 } 218 219 // Default to the local case 220 local_file = platform_file; 221 return Error(); 222 } 223 224 225 //------------------------------------------------------------------ 226 /// Default Constructor 227 //------------------------------------------------------------------ 228 PlatformLinux::PlatformLinux (bool is_host) : 229 Platform(is_host), // This is the local host platform 230 m_remote_platform_sp () 231 { 232 } 233 234 //------------------------------------------------------------------ 235 /// Destructor. 236 /// 237 /// The destructor is virtual since this class is designed to be 238 /// inherited from by the plug-in instance. 239 //------------------------------------------------------------------ 240 PlatformLinux::~PlatformLinux() 241 { 242 } 243 244 bool 245 PlatformLinux::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 246 { 247 bool success = false; 248 if (IsHost()) 249 { 250 success = Platform::GetProcessInfo (pid, process_info); 251 } 252 else 253 { 254 if (m_remote_platform_sp) 255 success = m_remote_platform_sp->GetProcessInfo (pid, process_info); 256 } 257 return success; 258 } 259 260 bool 261 PlatformLinux::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 262 { 263 if (idx == 0) 264 { 265 arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture); 266 return arch.IsValid(); 267 } 268 return false; 269 } 270 271 void 272 PlatformLinux::GetStatus (Stream &strm) 273 { 274 struct utsname un; 275 276 if (uname(&un)) { 277 strm << "Linux"; 278 return; 279 } 280 281 strm << un.sysname << ' ' << un.release << ' ' << un.version << '\n'; 282 } 283 284 size_t 285 PlatformLinux::GetSoftwareBreakpointTrapOpcode (Target &target, 286 BreakpointSite *bp_site) 287 { 288 ArchSpec arch = target.GetArchitecture(); 289 const uint8_t *trap_opcode = NULL; 290 size_t trap_opcode_size = 0; 291 292 switch (arch.GetCore()) 293 { 294 default: 295 assert(false && "CPU type not supported!"); 296 break; 297 298 case ArchSpec::eCore_x86_32_i386: 299 case ArchSpec::eCore_x86_64_x86_64: 300 { 301 static const uint8_t g_i386_breakpoint_opcode[] = { 0xCC }; 302 trap_opcode = g_i386_breakpoint_opcode; 303 trap_opcode_size = sizeof(g_i386_breakpoint_opcode); 304 } 305 break; 306 } 307 308 if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) 309 return trap_opcode_size; 310 return 0; 311 } 312 313 Error 314 PlatformLinux::LaunchProcess (ProcessLaunchInfo &launch_info) 315 { 316 Error error; 317 318 if (IsHost()) 319 { 320 if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell)) 321 { 322 const bool is_localhost = true; 323 if (!launch_info.ConvertArgumentsForLaunchingInShell (error, is_localhost)) 324 return error; 325 } 326 error = Platform::LaunchProcess (launch_info); 327 } 328 else 329 { 330 error.SetErrorString ("the platform is not currently connected"); 331 } 332 return error; 333 } 334 335 lldb::ProcessSP 336 PlatformLinux::Attach(ProcessAttachInfo &attach_info, 337 Debugger &debugger, 338 Target *target, 339 Listener &listener, 340 Error &error) 341 { 342 lldb::ProcessSP process_sp; 343 if (IsHost()) 344 { 345 if (target == NULL) 346 { 347 TargetSP new_target_sp; 348 FileSpec emptyFileSpec; 349 ArchSpec emptyArchSpec; 350 351 error = debugger.GetTargetList().CreateTarget (debugger, 352 emptyFileSpec, 353 emptyArchSpec, 354 false, 355 m_remote_platform_sp, 356 new_target_sp); 357 target = new_target_sp.get(); 358 } 359 else 360 error.Clear(); 361 362 if (target && error.Success()) 363 { 364 debugger.GetTargetList().SetSelectedTarget(target); 365 366 process_sp = target->CreateProcess (listener, 367 attach_info.GetProcessPluginName(), 368 NULL); 369 370 if (process_sp) 371 error = process_sp->Attach (attach_info); 372 } 373 } 374 else 375 { 376 if (m_remote_platform_sp) 377 process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error); 378 else 379 error.SetErrorString ("the platform is not currently connected"); 380 } 381 return process_sp; 382 } 383