File: | tools/lldb/source/Target/Platform.cpp |
Warning: | line 1063, column 9 Inner pointer of container used after re/deallocation |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- Platform.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 | // C Includes | |||
11 | // C++ Includes | |||
12 | #include <algorithm> | |||
13 | #include <csignal> | |||
14 | #include <fstream> | |||
15 | #include <vector> | |||
16 | ||||
17 | // Other libraries and framework includes | |||
18 | #include "llvm/Support/FileSystem.h" | |||
19 | #include "llvm/Support/Path.h" | |||
20 | ||||
21 | // Project includes | |||
22 | #include "lldb/Breakpoint/BreakpointIDList.h" | |||
23 | #include "lldb/Breakpoint/BreakpointLocation.h" | |||
24 | #include "lldb/Core/Debugger.h" | |||
25 | #include "lldb/Core/Module.h" | |||
26 | #include "lldb/Core/ModuleSpec.h" | |||
27 | #include "lldb/Core/PluginManager.h" | |||
28 | #include "lldb/Core/StreamFile.h" | |||
29 | #include "lldb/Host/FileSystem.h" | |||
30 | #include "lldb/Host/Host.h" | |||
31 | #include "lldb/Host/HostInfo.h" | |||
32 | #include "lldb/Host/OptionParser.h" | |||
33 | #include "lldb/Interpreter/OptionValueProperties.h" | |||
34 | #include "lldb/Interpreter/Property.h" | |||
35 | #include "lldb/Symbol/ObjectFile.h" | |||
36 | #include "lldb/Target/ModuleCache.h" | |||
37 | #include "lldb/Target/Platform.h" | |||
38 | #include "lldb/Target/Process.h" | |||
39 | #include "lldb/Target/Target.h" | |||
40 | #include "lldb/Target/UnixSignals.h" | |||
41 | #include "lldb/Utility/DataBufferHeap.h" | |||
42 | #include "lldb/Utility/FileSpec.h" | |||
43 | #include "lldb/Utility/Log.h" | |||
44 | #include "lldb/Utility/Status.h" | |||
45 | #include "lldb/Utility/StructuredData.h" | |||
46 | ||||
47 | #include "llvm/Support/FileSystem.h" | |||
48 | ||||
49 | // Define these constants from POSIX mman.h rather than include the file so | |||
50 | // that they will be correct even when compiled on Linux. | |||
51 | #define MAP_PRIVATE2 2 | |||
52 | #define MAP_ANON0x1000 0x1000 | |||
53 | ||||
54 | using namespace lldb; | |||
55 | using namespace lldb_private; | |||
56 | ||||
57 | static uint32_t g_initialize_count = 0; | |||
58 | ||||
59 | // Use a singleton function for g_local_platform_sp to avoid init constructors | |||
60 | // since LLDB is often part of a shared library | |||
61 | static PlatformSP &GetHostPlatformSP() { | |||
62 | static PlatformSP g_platform_sp; | |||
63 | return g_platform_sp; | |||
64 | } | |||
65 | ||||
66 | const char *Platform::GetHostPlatformName() { return "host"; } | |||
67 | ||||
68 | namespace { | |||
69 | ||||
70 | static constexpr PropertyDefinition g_properties[] = { | |||
71 | {"use-module-cache", OptionValue::eTypeBoolean, true, true, nullptr, | |||
72 | {}, "Use module cache."}, | |||
73 | {"module-cache-directory", OptionValue::eTypeFileSpec, true, 0, nullptr, | |||
74 | {}, "Root directory for cached modules."}}; | |||
75 | ||||
76 | enum { ePropertyUseModuleCache, ePropertyModuleCacheDirectory }; | |||
77 | ||||
78 | } // namespace | |||
79 | ||||
80 | ConstString PlatformProperties::GetSettingName() { | |||
81 | static ConstString g_setting_name("platform"); | |||
82 | return g_setting_name; | |||
83 | } | |||
84 | ||||
85 | PlatformProperties::PlatformProperties() { | |||
86 | m_collection_sp.reset(new OptionValueProperties(GetSettingName())); | |||
87 | m_collection_sp->Initialize(g_properties); | |||
88 | ||||
89 | auto module_cache_dir = GetModuleCacheDirectory(); | |||
90 | if (module_cache_dir) | |||
91 | return; | |||
92 | ||||
93 | llvm::SmallString<64> user_home_dir; | |||
94 | if (!llvm::sys::path::home_directory(user_home_dir)) | |||
95 | return; | |||
96 | ||||
97 | module_cache_dir = FileSpec(user_home_dir.c_str(), false); | |||
98 | module_cache_dir.AppendPathComponent(".lldb"); | |||
99 | module_cache_dir.AppendPathComponent("module_cache"); | |||
100 | SetModuleCacheDirectory(module_cache_dir); | |||
101 | } | |||
102 | ||||
103 | bool PlatformProperties::GetUseModuleCache() const { | |||
104 | const auto idx = ePropertyUseModuleCache; | |||
105 | return m_collection_sp->GetPropertyAtIndexAsBoolean( | |||
106 | nullptr, idx, g_properties[idx].default_uint_value != 0); | |||
107 | } | |||
108 | ||||
109 | bool PlatformProperties::SetUseModuleCache(bool use_module_cache) { | |||
110 | return m_collection_sp->SetPropertyAtIndexAsBoolean( | |||
111 | nullptr, ePropertyUseModuleCache, use_module_cache); | |||
112 | } | |||
113 | ||||
114 | FileSpec PlatformProperties::GetModuleCacheDirectory() const { | |||
115 | return m_collection_sp->GetPropertyAtIndexAsFileSpec( | |||
116 | nullptr, ePropertyModuleCacheDirectory); | |||
117 | } | |||
118 | ||||
119 | bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) { | |||
120 | return m_collection_sp->SetPropertyAtIndexAsFileSpec( | |||
121 | nullptr, ePropertyModuleCacheDirectory, dir_spec); | |||
122 | } | |||
123 | ||||
124 | //------------------------------------------------------------------ | |||
125 | /// Get the native host platform plug-in. | |||
126 | /// | |||
127 | /// There should only be one of these for each host that LLDB runs | |||
128 | /// upon that should be statically compiled in and registered using | |||
129 | /// preprocessor macros or other similar build mechanisms. | |||
130 | /// | |||
131 | /// This platform will be used as the default platform when launching | |||
132 | /// or attaching to processes unless another platform is specified. | |||
133 | //------------------------------------------------------------------ | |||
134 | PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); } | |||
135 | ||||
136 | static std::vector<PlatformSP> &GetPlatformList() { | |||
137 | static std::vector<PlatformSP> g_platform_list; | |||
138 | return g_platform_list; | |||
139 | } | |||
140 | ||||
141 | static std::recursive_mutex &GetPlatformListMutex() { | |||
142 | static std::recursive_mutex g_mutex; | |||
143 | return g_mutex; | |||
144 | } | |||
145 | ||||
146 | void Platform::Initialize() { g_initialize_count++; } | |||
147 | ||||
148 | void Platform::Terminate() { | |||
149 | if (g_initialize_count > 0) { | |||
150 | if (--g_initialize_count == 0) { | |||
151 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
152 | GetPlatformList().clear(); | |||
153 | } | |||
154 | } | |||
155 | } | |||
156 | ||||
157 | const PlatformPropertiesSP &Platform::GetGlobalPlatformProperties() { | |||
158 | static const auto g_settings_sp(std::make_shared<PlatformProperties>()); | |||
159 | return g_settings_sp; | |||
160 | } | |||
161 | ||||
162 | void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) { | |||
163 | // The native platform should use its static void Platform::Initialize() | |||
164 | // function to register itself as the native platform. | |||
165 | GetHostPlatformSP() = platform_sp; | |||
166 | ||||
167 | if (platform_sp) { | |||
168 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
169 | GetPlatformList().push_back(platform_sp); | |||
170 | } | |||
171 | } | |||
172 | ||||
173 | Status Platform::GetFileWithUUID(const FileSpec &platform_file, | |||
174 | const UUID *uuid_ptr, FileSpec &local_file) { | |||
175 | // Default to the local case | |||
176 | local_file = platform_file; | |||
177 | return Status(); | |||
178 | } | |||
179 | ||||
180 | FileSpecList | |||
181 | Platform::LocateExecutableScriptingResources(Target *target, Module &module, | |||
182 | Stream *feedback_stream) { | |||
183 | return FileSpecList(); | |||
184 | } | |||
185 | ||||
186 | // PlatformSP | |||
187 | // Platform::FindPlugin (Process *process, const ConstString &plugin_name) | |||
188 | //{ | |||
189 | // PlatformCreateInstance create_callback = nullptr; | |||
190 | // if (plugin_name) | |||
191 | // { | |||
192 | // create_callback = | |||
193 | // PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); | |||
194 | // if (create_callback) | |||
195 | // { | |||
196 | // ArchSpec arch; | |||
197 | // if (process) | |||
198 | // { | |||
199 | // arch = process->GetTarget().GetArchitecture(); | |||
200 | // } | |||
201 | // PlatformSP platform_sp(create_callback(process, &arch)); | |||
202 | // if (platform_sp) | |||
203 | // return platform_sp; | |||
204 | // } | |||
205 | // } | |||
206 | // else | |||
207 | // { | |||
208 | // for (uint32_t idx = 0; (create_callback = | |||
209 | // PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != nullptr; | |||
210 | // ++idx) | |||
211 | // { | |||
212 | // PlatformSP platform_sp(create_callback(process, nullptr)); | |||
213 | // if (platform_sp) | |||
214 | // return platform_sp; | |||
215 | // } | |||
216 | // } | |||
217 | // return PlatformSP(); | |||
218 | //} | |||
219 | ||||
220 | Status Platform::GetSharedModule(const ModuleSpec &module_spec, | |||
221 | Process *process, ModuleSP &module_sp, | |||
222 | const FileSpecList *module_search_paths_ptr, | |||
223 | ModuleSP *old_module_sp_ptr, | |||
224 | bool *did_create_ptr) { | |||
225 | if (IsHost()) | |||
226 | return ModuleList::GetSharedModule( | |||
227 | module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, | |||
228 | did_create_ptr, false); | |||
229 | ||||
230 | // Module resolver lambda. | |||
231 | auto resolver = [&](const ModuleSpec &spec) { | |||
232 | Status error(eErrorTypeGeneric); | |||
233 | ModuleSpec resolved_spec; | |||
234 | // Check if we have sysroot set. | |||
235 | if (m_sdk_sysroot) { | |||
236 | // Prepend sysroot to module spec. | |||
237 | resolved_spec = spec; | |||
238 | resolved_spec.GetFileSpec().PrependPathComponent( | |||
239 | m_sdk_sysroot.GetStringRef()); | |||
240 | // Try to get shared module with resolved spec. | |||
241 | error = ModuleList::GetSharedModule( | |||
242 | resolved_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, | |||
243 | did_create_ptr, false); | |||
244 | } | |||
245 | // If we don't have sysroot or it didn't work then | |||
246 | // try original module spec. | |||
247 | if (!error.Success()) { | |||
248 | resolved_spec = spec; | |||
249 | error = ModuleList::GetSharedModule( | |||
250 | resolved_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, | |||
251 | did_create_ptr, false); | |||
252 | } | |||
253 | if (error.Success() && module_sp) | |||
254 | module_sp->SetPlatformFileSpec(resolved_spec.GetFileSpec()); | |||
255 | return error; | |||
256 | }; | |||
257 | ||||
258 | return GetRemoteSharedModule(module_spec, process, module_sp, resolver, | |||
259 | did_create_ptr); | |||
260 | } | |||
261 | ||||
262 | bool Platform::GetModuleSpec(const FileSpec &module_file_spec, | |||
263 | const ArchSpec &arch, ModuleSpec &module_spec) { | |||
264 | ModuleSpecList module_specs; | |||
265 | if (ObjectFile::GetModuleSpecifications(module_file_spec, 0, 0, | |||
266 | module_specs) == 0) | |||
267 | return false; | |||
268 | ||||
269 | ModuleSpec matched_module_spec; | |||
270 | return module_specs.FindMatchingModuleSpec(ModuleSpec(module_file_spec, arch), | |||
271 | module_spec); | |||
272 | } | |||
273 | ||||
274 | PlatformSP Platform::Find(const ConstString &name) { | |||
275 | if (name) { | |||
276 | static ConstString g_host_platform_name("host"); | |||
277 | if (name == g_host_platform_name) | |||
278 | return GetHostPlatform(); | |||
279 | ||||
280 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
281 | for (const auto &platform_sp : GetPlatformList()) { | |||
282 | if (platform_sp->GetName() == name) | |||
283 | return platform_sp; | |||
284 | } | |||
285 | } | |||
286 | return PlatformSP(); | |||
287 | } | |||
288 | ||||
289 | PlatformSP Platform::Create(const ConstString &name, Status &error) { | |||
290 | PlatformCreateInstance create_callback = nullptr; | |||
291 | lldb::PlatformSP platform_sp; | |||
292 | if (name) { | |||
293 | static ConstString g_host_platform_name("host"); | |||
294 | if (name == g_host_platform_name) | |||
295 | return GetHostPlatform(); | |||
296 | ||||
297 | create_callback = | |||
298 | PluginManager::GetPlatformCreateCallbackForPluginName(name); | |||
299 | if (create_callback) | |||
300 | platform_sp = create_callback(true, nullptr); | |||
301 | else | |||
302 | error.SetErrorStringWithFormat( | |||
303 | "unable to find a plug-in for the platform named \"%s\"", | |||
304 | name.GetCString()); | |||
305 | } else | |||
306 | error.SetErrorString("invalid platform name"); | |||
307 | ||||
308 | if (platform_sp) { | |||
309 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
310 | GetPlatformList().push_back(platform_sp); | |||
311 | } | |||
312 | ||||
313 | return platform_sp; | |||
314 | } | |||
315 | ||||
316 | PlatformSP Platform::Create(const ArchSpec &arch, ArchSpec *platform_arch_ptr, | |||
317 | Status &error) { | |||
318 | lldb::PlatformSP platform_sp; | |||
319 | if (arch.IsValid()) { | |||
320 | // Scope for locker | |||
321 | { | |||
322 | // First try exact arch matches across all platforms already created | |||
323 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
324 | for (const auto &platform_sp : GetPlatformList()) { | |||
325 | if (platform_sp->IsCompatibleArchitecture(arch, true, | |||
326 | platform_arch_ptr)) | |||
327 | return platform_sp; | |||
328 | } | |||
329 | ||||
330 | // Next try compatible arch matches across all platforms already created | |||
331 | for (const auto &platform_sp : GetPlatformList()) { | |||
332 | if (platform_sp->IsCompatibleArchitecture(arch, false, | |||
333 | platform_arch_ptr)) | |||
334 | return platform_sp; | |||
335 | } | |||
336 | } | |||
337 | ||||
338 | PlatformCreateInstance create_callback; | |||
339 | // First try exact arch matches across all platform plug-ins | |||
340 | uint32_t idx; | |||
341 | for (idx = 0; (create_callback = | |||
342 | PluginManager::GetPlatformCreateCallbackAtIndex(idx)); | |||
343 | ++idx) { | |||
344 | if (create_callback) { | |||
345 | platform_sp = create_callback(false, &arch); | |||
346 | if (platform_sp && | |||
347 | platform_sp->IsCompatibleArchitecture(arch, true, | |||
348 | platform_arch_ptr)) { | |||
349 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
350 | GetPlatformList().push_back(platform_sp); | |||
351 | return platform_sp; | |||
352 | } | |||
353 | } | |||
354 | } | |||
355 | // Next try compatible arch matches across all platform plug-ins | |||
356 | for (idx = 0; (create_callback = | |||
357 | PluginManager::GetPlatformCreateCallbackAtIndex(idx)); | |||
358 | ++idx) { | |||
359 | if (create_callback) { | |||
360 | platform_sp = create_callback(false, &arch); | |||
361 | if (platform_sp && | |||
362 | platform_sp->IsCompatibleArchitecture(arch, false, | |||
363 | platform_arch_ptr)) { | |||
364 | std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); | |||
365 | GetPlatformList().push_back(platform_sp); | |||
366 | return platform_sp; | |||
367 | } | |||
368 | } | |||
369 | } | |||
370 | } else | |||
371 | error.SetErrorString("invalid platform name"); | |||
372 | if (platform_arch_ptr) | |||
373 | platform_arch_ptr->Clear(); | |||
374 | platform_sp.reset(); | |||
375 | return platform_sp; | |||
376 | } | |||
377 | ||||
378 | ArchSpec Platform::GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple) { | |||
379 | if (platform) | |||
380 | return platform->GetAugmentedArchSpec(triple); | |||
381 | return HostInfo::GetAugmentedArchSpec(triple); | |||
382 | } | |||
383 | ||||
384 | //------------------------------------------------------------------ | |||
385 | /// Default Constructor | |||
386 | //------------------------------------------------------------------ | |||
387 | Platform::Platform(bool is_host) | |||
388 | : m_is_host(is_host), m_os_version_set_while_connected(false), | |||
389 | m_system_arch_set_while_connected(false), m_sdk_sysroot(), m_sdk_build(), | |||
390 | m_working_dir(), m_remote_url(), m_name(), m_system_arch(), m_mutex(), | |||
391 | m_uid_map(), m_gid_map(), m_max_uid_name_len(0), m_max_gid_name_len(0), | |||
392 | m_supports_rsync(false), m_rsync_opts(), m_rsync_prefix(), | |||
393 | m_supports_ssh(false), m_ssh_opts(), m_ignores_remote_hostname(false), | |||
394 | m_trap_handlers(), m_calculated_trap_handlers(false), | |||
395 | m_module_cache(llvm::make_unique<ModuleCache>()) { | |||
396 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT(1u << 11))); | |||
397 | if (log) | |||
398 | log->Printf("%p Platform::Platform()", static_cast<void *>(this)); | |||
399 | } | |||
400 | ||||
401 | //------------------------------------------------------------------ | |||
402 | /// Destructor. | |||
403 | /// | |||
404 | /// The destructor is virtual since this class is designed to be | |||
405 | /// inherited from by the plug-in instance. | |||
406 | //------------------------------------------------------------------ | |||
407 | Platform::~Platform() { | |||
408 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT(1u << 11))); | |||
409 | if (log) | |||
410 | log->Printf("%p Platform::~Platform()", static_cast<void *>(this)); | |||
411 | } | |||
412 | ||||
413 | void Platform::GetStatus(Stream &strm) { | |||
414 | std::string s; | |||
415 | strm.Printf(" Platform: %s\n", GetPluginName().GetCString()); | |||
416 | ||||
417 | ArchSpec arch(GetSystemArchitecture()); | |||
418 | if (arch.IsValid()) { | |||
419 | if (!arch.GetTriple().str().empty()) { | |||
420 | strm.Printf(" Triple: "); | |||
421 | arch.DumpTriple(strm); | |||
422 | strm.EOL(); | |||
423 | } | |||
424 | } | |||
425 | ||||
426 | llvm::VersionTuple os_version = GetOSVersion(); | |||
427 | if (!os_version.empty()) { | |||
428 | strm.Format("OS Version: {0}", os_version.getAsString()); | |||
429 | ||||
430 | if (GetOSBuildString(s)) | |||
431 | strm.Printf(" (%s)", s.c_str()); | |||
432 | ||||
433 | strm.EOL(); | |||
434 | } | |||
435 | ||||
436 | if (GetOSKernelDescription(s)) | |||
437 | strm.Printf(" Kernel: %s\n", s.c_str()); | |||
438 | ||||
439 | if (IsHost()) { | |||
440 | strm.Printf(" Hostname: %s\n", GetHostname()); | |||
441 | } else { | |||
442 | const bool is_connected = IsConnected(); | |||
443 | if (is_connected) | |||
444 | strm.Printf(" Hostname: %s\n", GetHostname()); | |||
445 | strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); | |||
446 | } | |||
447 | ||||
448 | if (GetWorkingDirectory()) { | |||
449 | strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); | |||
450 | } | |||
451 | if (!IsConnected()) | |||
452 | return; | |||
453 | ||||
454 | std::string specific_info(GetPlatformSpecificConnectionInformation()); | |||
455 | ||||
456 | if (!specific_info.empty()) | |||
457 | strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); | |||
458 | } | |||
459 | ||||
460 | llvm::VersionTuple Platform::GetOSVersion(Process *process) { | |||
461 | std::lock_guard<std::mutex> guard(m_mutex); | |||
462 | ||||
463 | if (IsHost()) { | |||
464 | if (m_os_version.empty()) { | |||
465 | // We have a local host platform | |||
466 | m_os_version = HostInfo::GetOSVersion(); | |||
467 | m_os_version_set_while_connected = !m_os_version.empty(); | |||
468 | } | |||
469 | } else { | |||
470 | // We have a remote platform. We can only fetch the remote | |||
471 | // OS version if we are connected, and we don't want to do it | |||
472 | // more than once. | |||
473 | ||||
474 | const bool is_connected = IsConnected(); | |||
475 | ||||
476 | bool fetch = false; | |||
477 | if (!m_os_version.empty()) { | |||
478 | // We have valid OS version info, check to make sure it wasn't manually | |||
479 | // set prior to connecting. If it was manually set prior to connecting, | |||
480 | // then lets fetch the actual OS version info if we are now connected. | |||
481 | if (is_connected && !m_os_version_set_while_connected) | |||
482 | fetch = true; | |||
483 | } else { | |||
484 | // We don't have valid OS version info, fetch it if we are connected | |||
485 | fetch = is_connected; | |||
486 | } | |||
487 | ||||
488 | if (fetch) | |||
489 | m_os_version_set_while_connected = GetRemoteOSVersion(); | |||
490 | } | |||
491 | ||||
492 | if (!m_os_version.empty()) | |||
493 | return m_os_version; | |||
494 | if (process) { | |||
495 | // Check with the process in case it can answer the question if a process | |||
496 | // was provided | |||
497 | return process->GetHostOSVersion(); | |||
498 | } | |||
499 | return llvm::VersionTuple(); | |||
500 | } | |||
501 | ||||
502 | bool Platform::GetOSBuildString(std::string &s) { | |||
503 | s.clear(); | |||
504 | ||||
505 | if (IsHost()) | |||
506 | #if !defined(__linux__1) | |||
507 | return HostInfo::GetOSBuildString(s); | |||
508 | #else | |||
509 | return false; | |||
510 | #endif | |||
511 | else | |||
512 | return GetRemoteOSBuildString(s); | |||
513 | } | |||
514 | ||||
515 | bool Platform::GetOSKernelDescription(std::string &s) { | |||
516 | if (IsHost()) | |||
517 | #if !defined(__linux__1) | |||
518 | return HostInfo::GetOSKernelDescription(s); | |||
519 | #else | |||
520 | return false; | |||
521 | #endif | |||
522 | else | |||
523 | return GetRemoteOSKernelDescription(s); | |||
524 | } | |||
525 | ||||
526 | void Platform::AddClangModuleCompilationOptions( | |||
527 | Target *target, std::vector<std::string> &options) { | |||
528 | std::vector<std::string> default_compilation_options = { | |||
529 | "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"}; | |||
530 | ||||
531 | options.insert(options.end(), default_compilation_options.begin(), | |||
532 | default_compilation_options.end()); | |||
533 | } | |||
534 | ||||
535 | FileSpec Platform::GetWorkingDirectory() { | |||
536 | if (IsHost()) { | |||
537 | llvm::SmallString<64> cwd; | |||
538 | if (llvm::sys::fs::current_path(cwd)) | |||
539 | return FileSpec{}; | |||
540 | else | |||
541 | return FileSpec(cwd, true); | |||
542 | } else { | |||
543 | if (!m_working_dir) | |||
544 | m_working_dir = GetRemoteWorkingDirectory(); | |||
545 | return m_working_dir; | |||
546 | } | |||
547 | } | |||
548 | ||||
549 | struct RecurseCopyBaton { | |||
550 | const FileSpec &dst; | |||
551 | Platform *platform_ptr; | |||
552 | Status error; | |||
553 | }; | |||
554 | ||||
555 | static FileSpec::EnumerateDirectoryResult | |||
556 | RecurseCopy_Callback(void *baton, llvm::sys::fs::file_type ft, | |||
557 | const FileSpec &src) { | |||
558 | RecurseCopyBaton *rc_baton = (RecurseCopyBaton *)baton; | |||
559 | namespace fs = llvm::sys::fs; | |||
560 | switch (ft) { | |||
561 | case fs::file_type::fifo_file: | |||
562 | case fs::file_type::socket_file: | |||
563 | // we have no way to copy pipes and sockets - ignore them and continue | |||
564 | return FileSpec::eEnumerateDirectoryResultNext; | |||
565 | break; | |||
566 | ||||
567 | case fs::file_type::directory_file: { | |||
568 | // make the new directory and get in there | |||
569 | FileSpec dst_dir = rc_baton->dst; | |||
570 | if (!dst_dir.GetFilename()) | |||
571 | dst_dir.GetFilename() = src.GetLastPathComponent(); | |||
572 | Status error = rc_baton->platform_ptr->MakeDirectory( | |||
573 | dst_dir, lldb::eFilePermissionsDirectoryDefault); | |||
574 | if (error.Fail()) { | |||
575 | rc_baton->error.SetErrorStringWithFormat( | |||
576 | "unable to setup directory %s on remote end", dst_dir.GetCString()); | |||
577 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
578 | } | |||
579 | ||||
580 | // now recurse | |||
581 | std::string src_dir_path(src.GetPath()); | |||
582 | ||||
583 | // Make a filespec that only fills in the directory of a FileSpec so when | |||
584 | // we enumerate we can quickly fill in the filename for dst copies | |||
585 | FileSpec recurse_dst; | |||
586 | recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); | |||
587 | RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr, | |||
588 | Status()}; | |||
589 | FileSpec::EnumerateDirectory(src_dir_path, true, true, true, | |||
590 | RecurseCopy_Callback, &rc_baton2); | |||
591 | if (rc_baton2.error.Fail()) { | |||
592 | rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); | |||
593 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
594 | } | |||
595 | return FileSpec::eEnumerateDirectoryResultNext; | |||
596 | } break; | |||
597 | ||||
598 | case fs::file_type::symlink_file: { | |||
599 | // copy the file and keep going | |||
600 | FileSpec dst_file = rc_baton->dst; | |||
601 | if (!dst_file.GetFilename()) | |||
602 | dst_file.GetFilename() = src.GetFilename(); | |||
603 | ||||
604 | FileSpec src_resolved; | |||
605 | ||||
606 | rc_baton->error = FileSystem::Readlink(src, src_resolved); | |||
607 | ||||
608 | if (rc_baton->error.Fail()) | |||
609 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
610 | ||||
611 | rc_baton->error = | |||
612 | rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved); | |||
613 | ||||
614 | if (rc_baton->error.Fail()) | |||
615 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
616 | ||||
617 | return FileSpec::eEnumerateDirectoryResultNext; | |||
618 | } break; | |||
619 | ||||
620 | case fs::file_type::regular_file: { | |||
621 | // copy the file and keep going | |||
622 | FileSpec dst_file = rc_baton->dst; | |||
623 | if (!dst_file.GetFilename()) | |||
624 | dst_file.GetFilename() = src.GetFilename(); | |||
625 | Status err = rc_baton->platform_ptr->PutFile(src, dst_file); | |||
626 | if (err.Fail()) { | |||
627 | rc_baton->error.SetErrorString(err.AsCString()); | |||
628 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
629 | } | |||
630 | return FileSpec::eEnumerateDirectoryResultNext; | |||
631 | } break; | |||
632 | ||||
633 | default: | |||
634 | rc_baton->error.SetErrorStringWithFormat( | |||
635 | "invalid file detected during copy: %s", src.GetPath().c_str()); | |||
636 | return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out | |||
637 | break; | |||
638 | } | |||
639 | llvm_unreachable("Unhandled file_type!")::llvm::llvm_unreachable_internal("Unhandled file_type!", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , 639); | |||
640 | } | |||
641 | ||||
642 | Status Platform::Install(const FileSpec &src, const FileSpec &dst) { | |||
643 | Status error; | |||
644 | ||||
645 | Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25)); | |||
646 | if (log) | |||
647 | log->Printf("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), | |||
648 | dst.GetPath().c_str()); | |||
649 | FileSpec fixed_dst(dst); | |||
650 | ||||
651 | if (!fixed_dst.GetFilename()) | |||
652 | fixed_dst.GetFilename() = src.GetFilename(); | |||
653 | ||||
654 | FileSpec working_dir = GetWorkingDirectory(); | |||
655 | ||||
656 | if (dst) { | |||
657 | if (dst.GetDirectory()) { | |||
658 | const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; | |||
659 | if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') { | |||
660 | fixed_dst.GetDirectory() = dst.GetDirectory(); | |||
661 | } | |||
662 | // If the fixed destination file doesn't have a directory yet, then we | |||
663 | // must have a relative path. We will resolve this relative path against | |||
664 | // the platform's working directory | |||
665 | if (!fixed_dst.GetDirectory()) { | |||
666 | FileSpec relative_spec; | |||
667 | std::string path; | |||
668 | if (working_dir) { | |||
669 | relative_spec = working_dir; | |||
670 | relative_spec.AppendPathComponent(dst.GetPath()); | |||
671 | fixed_dst.GetDirectory() = relative_spec.GetDirectory(); | |||
672 | } else { | |||
673 | error.SetErrorStringWithFormat( | |||
674 | "platform working directory must be valid for relative path '%s'", | |||
675 | dst.GetPath().c_str()); | |||
676 | return error; | |||
677 | } | |||
678 | } | |||
679 | } else { | |||
680 | if (working_dir) { | |||
681 | fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); | |||
682 | } else { | |||
683 | error.SetErrorStringWithFormat( | |||
684 | "platform working directory must be valid for relative path '%s'", | |||
685 | dst.GetPath().c_str()); | |||
686 | return error; | |||
687 | } | |||
688 | } | |||
689 | } else { | |||
690 | if (working_dir) { | |||
691 | fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); | |||
692 | } else { | |||
693 | error.SetErrorStringWithFormat("platform working directory must be valid " | |||
694 | "when destination directory is empty"); | |||
695 | return error; | |||
696 | } | |||
697 | } | |||
698 | ||||
699 | if (log) | |||
700 | log->Printf("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", | |||
701 | src.GetPath().c_str(), dst.GetPath().c_str(), | |||
702 | fixed_dst.GetPath().c_str()); | |||
703 | ||||
704 | if (GetSupportsRSync()) { | |||
705 | error = PutFile(src, dst); | |||
706 | } else { | |||
707 | namespace fs = llvm::sys::fs; | |||
708 | switch (fs::get_file_type(src.GetPath(), false)) { | |||
709 | case fs::file_type::directory_file: { | |||
710 | llvm::sys::fs::remove(fixed_dst.GetPath()); | |||
711 | uint32_t permissions = src.GetPermissions(); | |||
712 | if (permissions == 0) | |||
713 | permissions = eFilePermissionsDirectoryDefault; | |||
714 | error = MakeDirectory(fixed_dst, permissions); | |||
715 | if (error.Success()) { | |||
716 | // Make a filespec that only fills in the directory of a FileSpec so | |||
717 | // when we enumerate we can quickly fill in the filename for dst copies | |||
718 | FileSpec recurse_dst; | |||
719 | recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); | |||
720 | std::string src_dir_path(src.GetPath()); | |||
721 | RecurseCopyBaton baton = {recurse_dst, this, Status()}; | |||
722 | FileSpec::EnumerateDirectory(src_dir_path, true, true, true, | |||
723 | RecurseCopy_Callback, &baton); | |||
724 | return baton.error; | |||
725 | } | |||
726 | } break; | |||
727 | ||||
728 | case fs::file_type::regular_file: | |||
729 | llvm::sys::fs::remove(fixed_dst.GetPath()); | |||
730 | error = PutFile(src, fixed_dst); | |||
731 | break; | |||
732 | ||||
733 | case fs::file_type::symlink_file: { | |||
734 | llvm::sys::fs::remove(fixed_dst.GetPath()); | |||
735 | FileSpec src_resolved; | |||
736 | error = FileSystem::Readlink(src, src_resolved); | |||
737 | if (error.Success()) | |||
738 | error = CreateSymlink(dst, src_resolved); | |||
739 | } break; | |||
740 | case fs::file_type::fifo_file: | |||
741 | error.SetErrorString("platform install doesn't handle pipes"); | |||
742 | break; | |||
743 | case fs::file_type::socket_file: | |||
744 | error.SetErrorString("platform install doesn't handle sockets"); | |||
745 | break; | |||
746 | default: | |||
747 | error.SetErrorString( | |||
748 | "platform install doesn't handle non file or directory items"); | |||
749 | break; | |||
750 | } | |||
751 | } | |||
752 | return error; | |||
753 | } | |||
754 | ||||
755 | bool Platform::SetWorkingDirectory(const FileSpec &file_spec) { | |||
756 | if (IsHost()) { | |||
757 | Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25)); | |||
758 | LLDB_LOG(log, "{0}", file_spec)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , __func__, "{0}", file_spec); } while (0); | |||
759 | if (std::error_code ec = llvm::sys::fs::set_current_path(file_spec.GetPath())) { | |||
760 | LLDB_LOG(log, "error: {0}", ec.message())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Format("/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , __func__, "error: {0}", ec.message()); } while (0); | |||
761 | return false; | |||
762 | } | |||
763 | return true; | |||
764 | } else { | |||
765 | m_working_dir.Clear(); | |||
766 | return SetRemoteWorkingDirectory(file_spec); | |||
767 | } | |||
768 | } | |||
769 | ||||
770 | Status Platform::MakeDirectory(const FileSpec &file_spec, | |||
771 | uint32_t permissions) { | |||
772 | if (IsHost()) | |||
773 | return llvm::sys::fs::create_directory(file_spec.GetPath(), permissions); | |||
774 | else { | |||
775 | Status error; | |||
776 | error.SetErrorStringWithFormat("remote platform %s doesn't support %s", | |||
777 | GetPluginName().GetCString(), | |||
778 | LLVM_PRETTY_FUNCTION__PRETTY_FUNCTION__); | |||
779 | return error; | |||
780 | } | |||
781 | } | |||
782 | ||||
783 | Status Platform::GetFilePermissions(const FileSpec &file_spec, | |||
784 | uint32_t &file_permissions) { | |||
785 | if (IsHost()) { | |||
786 | auto Value = llvm::sys::fs::getPermissions(file_spec.GetPath()); | |||
787 | if (Value) | |||
788 | file_permissions = Value.get(); | |||
789 | return Status(Value.getError()); | |||
790 | } else { | |||
791 | Status error; | |||
792 | error.SetErrorStringWithFormat("remote platform %s doesn't support %s", | |||
793 | GetPluginName().GetCString(), | |||
794 | LLVM_PRETTY_FUNCTION__PRETTY_FUNCTION__); | |||
795 | return error; | |||
796 | } | |||
797 | } | |||
798 | ||||
799 | Status Platform::SetFilePermissions(const FileSpec &file_spec, | |||
800 | uint32_t file_permissions) { | |||
801 | if (IsHost()) { | |||
802 | auto Perms = static_cast<llvm::sys::fs::perms>(file_permissions); | |||
803 | return llvm::sys::fs::setPermissions(file_spec.GetPath(), Perms); | |||
804 | } else { | |||
805 | Status error; | |||
806 | error.SetErrorStringWithFormat("remote platform %s doesn't support %s", | |||
807 | GetPluginName().GetCString(), | |||
808 | LLVM_PRETTY_FUNCTION__PRETTY_FUNCTION__); | |||
809 | return error; | |||
810 | } | |||
811 | } | |||
812 | ||||
813 | ConstString Platform::GetName() { return GetPluginName(); } | |||
814 | ||||
815 | const char *Platform::GetHostname() { | |||
816 | if (IsHost()) | |||
817 | return "127.0.0.1"; | |||
818 | ||||
819 | if (m_name.empty()) | |||
820 | return nullptr; | |||
821 | return m_name.c_str(); | |||
822 | } | |||
823 | ||||
824 | ConstString Platform::GetFullNameForDylib(ConstString basename) { | |||
825 | return basename; | |||
826 | } | |||
827 | ||||
828 | bool Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) { | |||
829 | Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25)); | |||
830 | if (log) | |||
831 | log->Printf("Platform::SetRemoteWorkingDirectory('%s')", | |||
832 | working_dir.GetCString()); | |||
833 | m_working_dir = working_dir; | |||
834 | return true; | |||
835 | } | |||
836 | ||||
837 | const char *Platform::GetUserName(uint32_t uid) { | |||
838 | #if !defined(LLDB_DISABLE_POSIX) | |||
839 | const char *user_name = GetCachedUserName(uid); | |||
840 | if (user_name) | |||
841 | return user_name; | |||
842 | if (IsHost()) { | |||
843 | std::string name; | |||
844 | if (HostInfo::LookupUserName(uid, name)) | |||
845 | return SetCachedUserName(uid, name.c_str(), name.size()); | |||
846 | } | |||
847 | #endif | |||
848 | return nullptr; | |||
849 | } | |||
850 | ||||
851 | const char *Platform::GetGroupName(uint32_t gid) { | |||
852 | #if !defined(LLDB_DISABLE_POSIX) | |||
853 | const char *group_name = GetCachedGroupName(gid); | |||
854 | if (group_name) | |||
855 | return group_name; | |||
856 | if (IsHost()) { | |||
857 | std::string name; | |||
858 | if (HostInfo::LookupGroupName(gid, name)) | |||
859 | return SetCachedGroupName(gid, name.c_str(), name.size()); | |||
860 | } | |||
861 | #endif | |||
862 | return nullptr; | |||
863 | } | |||
864 | ||||
865 | bool Platform::SetOSVersion(llvm::VersionTuple version) { | |||
866 | if (IsHost()) { | |||
867 | // We don't need anyone setting the OS version for the host platform, we | |||
868 | // should be able to figure it out by calling HostInfo::GetOSVersion(...). | |||
869 | return false; | |||
870 | } else { | |||
871 | // We have a remote platform, allow setting the target OS version if we | |||
872 | // aren't connected, since if we are connected, we should be able to | |||
873 | // request the remote OS version from the connected platform. | |||
874 | if (IsConnected()) | |||
875 | return false; | |||
876 | else { | |||
877 | // We aren't connected and we might want to set the OS version ahead of | |||
878 | // time before we connect so we can peruse files and use a local SDK or | |||
879 | // PDK cache of support files to disassemble or do other things. | |||
880 | m_os_version = version; | |||
881 | return true; | |||
882 | } | |||
883 | } | |||
884 | return false; | |||
885 | } | |||
886 | ||||
887 | Status | |||
888 | Platform::ResolveExecutable(const ModuleSpec &module_spec, | |||
889 | lldb::ModuleSP &exe_module_sp, | |||
890 | const FileSpecList *module_search_paths_ptr) { | |||
891 | Status error; | |||
892 | if (module_spec.GetFileSpec().Exists()) { | |||
893 | if (module_spec.GetArchitecture().IsValid()) { | |||
894 | error = ModuleList::GetSharedModule(module_spec, exe_module_sp, | |||
895 | module_search_paths_ptr, nullptr, | |||
896 | nullptr); | |||
897 | } else { | |||
898 | // No valid architecture was specified, ask the platform for the | |||
899 | // architectures that we should be using (in the correct order) and see | |||
900 | // if we can find a match that way | |||
901 | ModuleSpec arch_module_spec(module_spec); | |||
902 | for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( | |||
903 | idx, arch_module_spec.GetArchitecture()); | |||
904 | ++idx) { | |||
905 | error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp, | |||
906 | module_search_paths_ptr, nullptr, | |||
907 | nullptr); | |||
908 | // Did we find an executable using one of the | |||
909 | if (error.Success() && exe_module_sp) | |||
910 | break; | |||
911 | } | |||
912 | } | |||
913 | } else { | |||
914 | error.SetErrorStringWithFormat("'%s' does not exist", | |||
915 | module_spec.GetFileSpec().GetPath().c_str()); | |||
916 | } | |||
917 | return error; | |||
918 | } | |||
919 | ||||
920 | Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, | |||
921 | FileSpec &sym_file) { | |||
922 | Status error; | |||
923 | if (sym_spec.GetSymbolFileSpec().Exists()) | |||
924 | sym_file = sym_spec.GetSymbolFileSpec(); | |||
925 | else | |||
926 | error.SetErrorString("unable to resolve symbol file"); | |||
927 | return error; | |||
928 | } | |||
929 | ||||
930 | bool Platform::ResolveRemotePath(const FileSpec &platform_path, | |||
931 | FileSpec &resolved_platform_path) { | |||
932 | resolved_platform_path = platform_path; | |||
933 | return resolved_platform_path.ResolvePath(); | |||
934 | } | |||
935 | ||||
936 | const ArchSpec &Platform::GetSystemArchitecture() { | |||
937 | if (IsHost()) { | |||
938 | if (!m_system_arch.IsValid()) { | |||
939 | // We have a local host platform | |||
940 | m_system_arch = HostInfo::GetArchitecture(); | |||
941 | m_system_arch_set_while_connected = m_system_arch.IsValid(); | |||
942 | } | |||
943 | } else { | |||
944 | // We have a remote platform. We can only fetch the remote system | |||
945 | // architecture if we are connected, and we don't want to do it more than | |||
946 | // once. | |||
947 | ||||
948 | const bool is_connected = IsConnected(); | |||
949 | ||||
950 | bool fetch = false; | |||
951 | if (m_system_arch.IsValid()) { | |||
952 | // We have valid OS version info, check to make sure it wasn't manually | |||
953 | // set prior to connecting. If it was manually set prior to connecting, | |||
954 | // then lets fetch the actual OS version info if we are now connected. | |||
955 | if (is_connected && !m_system_arch_set_while_connected) | |||
956 | fetch = true; | |||
957 | } else { | |||
958 | // We don't have valid OS version info, fetch it if we are connected | |||
959 | fetch = is_connected; | |||
960 | } | |||
961 | ||||
962 | if (fetch) { | |||
963 | m_system_arch = GetRemoteSystemArchitecture(); | |||
964 | m_system_arch_set_while_connected = m_system_arch.IsValid(); | |||
965 | } | |||
966 | } | |||
967 | return m_system_arch; | |||
968 | } | |||
969 | ||||
970 | ArchSpec Platform::GetAugmentedArchSpec(llvm::StringRef triple) { | |||
971 | if (triple.empty()) | |||
972 | return ArchSpec(); | |||
973 | llvm::Triple normalized_triple(llvm::Triple::normalize(triple)); | |||
974 | if (!ArchSpec::ContainsOnlyArch(normalized_triple)) | |||
975 | return ArchSpec(triple); | |||
976 | ||||
977 | if (auto kind = HostInfo::ParseArchitectureKind(triple)) | |||
978 | return HostInfo::GetArchitecture(*kind); | |||
979 | ||||
980 | ArchSpec compatible_arch; | |||
981 | ArchSpec raw_arch(triple); | |||
982 | if (!IsCompatibleArchitecture(raw_arch, false, &compatible_arch)) | |||
983 | return raw_arch; | |||
984 | ||||
985 | if (!compatible_arch.IsValid()) | |||
986 | return ArchSpec(normalized_triple); | |||
987 | ||||
988 | const llvm::Triple &compatible_triple = compatible_arch.GetTriple(); | |||
989 | if (normalized_triple.getVendorName().empty()) | |||
990 | normalized_triple.setVendor(compatible_triple.getVendor()); | |||
991 | if (normalized_triple.getOSName().empty()) | |||
992 | normalized_triple.setOS(compatible_triple.getOS()); | |||
993 | if (normalized_triple.getEnvironmentName().empty()) | |||
994 | normalized_triple.setEnvironment(compatible_triple.getEnvironment()); | |||
995 | return ArchSpec(normalized_triple); | |||
996 | } | |||
997 | ||||
998 | Status Platform::ConnectRemote(Args &args) { | |||
999 | Status error; | |||
1000 | if (IsHost()) | |||
1001 | error.SetErrorStringWithFormat("The currently selected platform (%s) is " | |||
1002 | "the host platform and is always connected.", | |||
1003 | GetPluginName().GetCString()); | |||
1004 | else | |||
1005 | error.SetErrorStringWithFormat( | |||
1006 | "Platform::ConnectRemote() is not supported by %s", | |||
1007 | GetPluginName().GetCString()); | |||
1008 | return error; | |||
1009 | } | |||
1010 | ||||
1011 | Status Platform::DisconnectRemote() { | |||
1012 | Status error; | |||
1013 | if (IsHost()) | |||
1014 | error.SetErrorStringWithFormat("The currently selected platform (%s) is " | |||
1015 | "the host platform and is always connected.", | |||
1016 | GetPluginName().GetCString()); | |||
1017 | else | |||
1018 | error.SetErrorStringWithFormat( | |||
1019 | "Platform::DisconnectRemote() is not supported by %s", | |||
1020 | GetPluginName().GetCString()); | |||
1021 | return error; | |||
1022 | } | |||
1023 | ||||
1024 | bool Platform::GetProcessInfo(lldb::pid_t pid, | |||
1025 | ProcessInstanceInfo &process_info) { | |||
1026 | // Take care of the host case so that each subclass can just call this | |||
1027 | // function to get the host functionality. | |||
1028 | if (IsHost()) | |||
1029 | return Host::GetProcessInfo(pid, process_info); | |||
1030 | return false; | |||
1031 | } | |||
1032 | ||||
1033 | uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info, | |||
1034 | ProcessInstanceInfoList &process_infos) { | |||
1035 | // Take care of the host case so that each subclass can just call this | |||
1036 | // function to get the host functionality. | |||
1037 | uint32_t match_count = 0; | |||
1038 | if (IsHost()) | |||
1039 | match_count = Host::FindProcesses(match_info, process_infos); | |||
1040 | return match_count; | |||
1041 | } | |||
1042 | ||||
1043 | Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { | |||
1044 | Status error; | |||
1045 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25))); | |||
1046 | if (log) | |||
1047 | log->Printf("Platform::%s()", __FUNCTION__); | |||
1048 | ||||
1049 | // Take care of the host case so that each subclass can just call this | |||
1050 | // function to get the host functionality. | |||
1051 | if (IsHost()) { | |||
1052 | if (::getenv("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) | |||
1053 | launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); | |||
1054 | ||||
1055 | if (launch_info.GetFlags().Test(eLaunchFlagLaunchInShell)) { | |||
1056 | const bool is_localhost = true; | |||
1057 | const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); | |||
1058 | const bool first_arg_is_full_shell_command = false; | |||
1059 | uint32_t num_resumes = GetResumeCountForLaunchInfo(launch_info); | |||
1060 | if (log) { | |||
1061 | const FileSpec &shell = launch_info.GetShell(); | |||
1062 | const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>"; | |||
1063 | log->Printf( | |||
| ||||
1064 | "Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32"u" | |||
1065 | ", shell is '%s'", | |||
1066 | __FUNCTION__, num_resumes, shell_str); | |||
1067 | } | |||
1068 | ||||
1069 | if (!launch_info.ConvertArgumentsForLaunchingInShell( | |||
1070 | error, is_localhost, will_debug, first_arg_is_full_shell_command, | |||
1071 | num_resumes)) | |||
1072 | return error; | |||
1073 | } else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { | |||
1074 | error = ShellExpandArguments(launch_info); | |||
1075 | if (error.Fail()) { | |||
1076 | error.SetErrorStringWithFormat("shell expansion failed (reason: %s). " | |||
1077 | "consider launching with 'process " | |||
1078 | "launch'.", | |||
1079 | error.AsCString("unknown")); | |||
1080 | return error; | |||
1081 | } | |||
1082 | } | |||
1083 | ||||
1084 | if (log) | |||
1085 | log->Printf("Platform::%s final launch_info resume count: %" PRIu32"u", | |||
1086 | __FUNCTION__, launch_info.GetResumeCount()); | |||
1087 | ||||
1088 | error = Host::LaunchProcess(launch_info); | |||
1089 | } else | |||
1090 | error.SetErrorString( | |||
1091 | "base lldb_private::Platform class can't launch remote processes"); | |||
1092 | return error; | |||
1093 | } | |||
1094 | ||||
1095 | Status Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) { | |||
1096 | if (IsHost()) | |||
1097 | return Host::ShellExpandArguments(launch_info); | |||
1098 | return Status("base lldb_private::Platform class can't expand arguments"); | |||
1099 | } | |||
1100 | ||||
1101 | Status Platform::KillProcess(const lldb::pid_t pid) { | |||
1102 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25))); | |||
1103 | if (log) | |||
1104 | log->Printf("Platform::%s, pid %" PRIu64"l" "u", __FUNCTION__, pid); | |||
1105 | ||||
1106 | // Try to find a process plugin to handle this Kill request. If we can't, | |||
1107 | // fall back to the default OS implementation. | |||
1108 | size_t num_debuggers = Debugger::GetNumDebuggers(); | |||
1109 | for (size_t didx = 0; didx < num_debuggers; ++didx) { | |||
1110 | DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx); | |||
1111 | lldb_private::TargetList &targets = debugger->GetTargetList(); | |||
1112 | for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx) { | |||
1113 | ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP(); | |||
1114 | if (process->GetID() == pid) | |||
1115 | return process->Destroy(true); | |||
1116 | } | |||
1117 | } | |||
1118 | ||||
1119 | if (!IsHost()) { | |||
1120 | return Status( | |||
1121 | "base lldb_private::Platform class can't kill remote processes unless " | |||
1122 | "they are controlled by a process plugin"); | |||
1123 | } | |||
1124 | Host::Kill(pid, SIGTERM15); | |||
1125 | return Status(); | |||
1126 | } | |||
1127 | ||||
1128 | lldb::ProcessSP | |||
1129 | Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, | |||
1130 | Target *target, // Can be nullptr, if nullptr create a | |||
1131 | // new target, else use existing one | |||
1132 | Status &error) { | |||
1133 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25))); | |||
1134 | if (log) | |||
| ||||
1135 | log->Printf("Platform::%s entered (target %p)", __FUNCTION__, | |||
1136 | static_cast<void *>(target)); | |||
1137 | ||||
1138 | ProcessSP process_sp; | |||
1139 | // Make sure we stop at the entry point | |||
1140 | launch_info.GetFlags().Set(eLaunchFlagDebug); | |||
1141 | // We always launch the process we are going to debug in a separate process | |||
1142 | // group, since then we can handle ^C interrupts ourselves w/o having to | |||
1143 | // worry about the target getting them as well. | |||
1144 | launch_info.SetLaunchInSeparateProcessGroup(true); | |||
1145 | ||||
1146 | // Allow any StructuredData process-bound plugins to adjust the launch info | |||
1147 | // if needed | |||
1148 | size_t i = 0; | |||
1149 | bool iteration_complete = false; | |||
1150 | // Note iteration can't simply go until a nullptr callback is returned, as it | |||
1151 | // is valid for a plugin to not supply a filter. | |||
1152 | auto get_filter_func = PluginManager::GetStructuredDataFilterCallbackAtIndex; | |||
1153 | for (auto filter_callback = get_filter_func(i, iteration_complete); | |||
1154 | !iteration_complete; | |||
1155 | filter_callback = get_filter_func(++i, iteration_complete)) { | |||
1156 | if (filter_callback) { | |||
1157 | // Give this ProcessLaunchInfo filter a chance to adjust the launch info. | |||
1158 | error = (*filter_callback)(launch_info, target); | |||
1159 | if (!error.Success()) { | |||
1160 | if (log) | |||
1161 | log->Printf("Platform::%s() StructuredDataPlugin launch " | |||
1162 | "filter failed.", | |||
1163 | __FUNCTION__); | |||
1164 | return process_sp; | |||
1165 | } | |||
1166 | } | |||
1167 | } | |||
1168 | ||||
1169 | error = LaunchProcess(launch_info); | |||
1170 | if (error.Success()) { | |||
1171 | if (log) | |||
1172 | log->Printf("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64"l" "u" | |||
1173 | ")", | |||
1174 | __FUNCTION__, launch_info.GetProcessID()); | |||
1175 | if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID0) { | |||
1176 | ProcessAttachInfo attach_info(launch_info); | |||
1177 | process_sp = Attach(attach_info, debugger, target, error); | |||
1178 | if (process_sp) { | |||
1179 | if (log) | |||
1180 | log->Printf("Platform::%s Attach() succeeded, Process plugin: %s", | |||
1181 | __FUNCTION__, process_sp->GetPluginName().AsCString()); | |||
1182 | launch_info.SetHijackListener(attach_info.GetHijackListener()); | |||
1183 | ||||
1184 | // Since we attached to the process, it will think it needs to detach | |||
1185 | // if the process object just goes away without an explicit call to | |||
1186 | // Process::Kill() or Process::Detach(), so let it know to kill the | |||
1187 | // process if this happens. | |||
1188 | process_sp->SetShouldDetach(false); | |||
1189 | ||||
1190 | // If we didn't have any file actions, the pseudo terminal might have | |||
1191 | // been used where the slave side was given as the file to open for | |||
1192 | // stdin/out/err after we have already opened the master so we can | |||
1193 | // read/write stdin/out/err. | |||
1194 | int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); | |||
1195 | if (pty_fd != PseudoTerminal::invalid_fd) { | |||
1196 | process_sp->SetSTDIOFileDescriptor(pty_fd); | |||
1197 | } | |||
1198 | } else { | |||
1199 | if (log) | |||
1200 | log->Printf("Platform::%s Attach() failed: %s", __FUNCTION__, | |||
1201 | error.AsCString()); | |||
1202 | } | |||
1203 | } else { | |||
1204 | if (log) | |||
1205 | log->Printf("Platform::%s LaunchProcess() returned launch_info with " | |||
1206 | "invalid process id", | |||
1207 | __FUNCTION__); | |||
1208 | } | |||
1209 | } else { | |||
1210 | if (log) | |||
1211 | log->Printf("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, | |||
1212 | error.AsCString()); | |||
1213 | } | |||
1214 | ||||
1215 | return process_sp; | |||
1216 | } | |||
1217 | ||||
1218 | lldb::PlatformSP | |||
1219 | Platform::GetPlatformForArchitecture(const ArchSpec &arch, | |||
1220 | ArchSpec *platform_arch_ptr) { | |||
1221 | lldb::PlatformSP platform_sp; | |||
1222 | Status error; | |||
1223 | if (arch.IsValid()) | |||
1224 | platform_sp = Platform::Create(arch, platform_arch_ptr, error); | |||
1225 | return platform_sp; | |||
1226 | } | |||
1227 | ||||
1228 | //------------------------------------------------------------------ | |||
1229 | /// Lets a platform answer if it is compatible with a given | |||
1230 | /// architecture and the target triple contained within. | |||
1231 | //------------------------------------------------------------------ | |||
1232 | bool Platform::IsCompatibleArchitecture(const ArchSpec &arch, | |||
1233 | bool exact_arch_match, | |||
1234 | ArchSpec *compatible_arch_ptr) { | |||
1235 | // If the architecture is invalid, we must answer true... | |||
1236 | if (arch.IsValid()) { | |||
1237 | ArchSpec platform_arch; | |||
1238 | // Try for an exact architecture match first. | |||
1239 | if (exact_arch_match) { | |||
1240 | for (uint32_t arch_idx = 0; | |||
1241 | GetSupportedArchitectureAtIndex(arch_idx, platform_arch); | |||
1242 | ++arch_idx) { | |||
1243 | if (arch.IsExactMatch(platform_arch)) { | |||
1244 | if (compatible_arch_ptr) | |||
1245 | *compatible_arch_ptr = platform_arch; | |||
1246 | return true; | |||
1247 | } | |||
1248 | } | |||
1249 | } else { | |||
1250 | for (uint32_t arch_idx = 0; | |||
1251 | GetSupportedArchitectureAtIndex(arch_idx, platform_arch); | |||
1252 | ++arch_idx) { | |||
1253 | if (arch.IsCompatibleMatch(platform_arch)) { | |||
1254 | if (compatible_arch_ptr) | |||
1255 | *compatible_arch_ptr = platform_arch; | |||
1256 | return true; | |||
1257 | } | |||
1258 | } | |||
1259 | } | |||
1260 | } | |||
1261 | if (compatible_arch_ptr) | |||
1262 | compatible_arch_ptr->Clear(); | |||
1263 | return false; | |||
1264 | } | |||
1265 | ||||
1266 | Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, | |||
1267 | uint32_t uid, uint32_t gid) { | |||
1268 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25))); | |||
1269 | if (log) | |||
1270 | log->Printf("[PutFile] Using block by block transfer....\n"); | |||
1271 | ||||
1272 | uint32_t source_open_options = | |||
1273 | File::eOpenOptionRead | File::eOpenOptionCloseOnExec; | |||
1274 | namespace fs = llvm::sys::fs; | |||
1275 | if (fs::is_symlink_file(source.GetPath())) | |||
1276 | source_open_options |= File::eOpenOptionDontFollowSymlinks; | |||
1277 | ||||
1278 | File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); | |||
1279 | Status error; | |||
1280 | uint32_t permissions = source_file.GetPermissions(error); | |||
1281 | if (permissions == 0) | |||
1282 | permissions = lldb::eFilePermissionsFileDefault; | |||
1283 | ||||
1284 | if (!source_file.IsValid()) | |||
1285 | return Status("PutFile: unable to open source file"); | |||
1286 | lldb::user_id_t dest_file = OpenFile( | |||
1287 | destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | | |||
1288 | File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec, | |||
1289 | permissions, error); | |||
1290 | if (log) | |||
1291 | log->Printf("dest_file = %" PRIu64"l" "u" "\n", dest_file); | |||
1292 | ||||
1293 | if (error.Fail()) | |||
1294 | return error; | |||
1295 | if (dest_file == UINT64_MAX(18446744073709551615UL)) | |||
1296 | return Status("unable to open target file"); | |||
1297 | lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); | |||
1298 | uint64_t offset = 0; | |||
1299 | for (;;) { | |||
1300 | size_t bytes_read = buffer_sp->GetByteSize(); | |||
1301 | error = source_file.Read(buffer_sp->GetBytes(), bytes_read); | |||
1302 | if (error.Fail() || bytes_read == 0) | |||
1303 | break; | |||
1304 | ||||
1305 | const uint64_t bytes_written = | |||
1306 | WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); | |||
1307 | if (error.Fail()) | |||
1308 | break; | |||
1309 | ||||
1310 | offset += bytes_written; | |||
1311 | if (bytes_written != bytes_read) { | |||
1312 | // We didn't write the correct number of bytes, so adjust the file | |||
1313 | // position in the source file we are reading from... | |||
1314 | source_file.SeekFromStart(offset); | |||
1315 | } | |||
1316 | } | |||
1317 | CloseFile(dest_file, error); | |||
1318 | ||||
1319 | if (uid == UINT32_MAX(4294967295U) && gid == UINT32_MAX(4294967295U)) | |||
1320 | return error; | |||
1321 | ||||
1322 | // TODO: ChownFile? | |||
1323 | ||||
1324 | return error; | |||
1325 | } | |||
1326 | ||||
1327 | Status Platform::GetFile(const FileSpec &source, const FileSpec &destination) { | |||
1328 | Status error("unimplemented"); | |||
1329 | return error; | |||
1330 | } | |||
1331 | ||||
1332 | Status | |||
1333 | Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src | |||
1334 | const FileSpec &dst) // The symlink points to dst | |||
1335 | { | |||
1336 | Status error("unimplemented"); | |||
1337 | return error; | |||
1338 | } | |||
1339 | ||||
1340 | bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) { | |||
1341 | return false; | |||
1342 | } | |||
1343 | ||||
1344 | Status Platform::Unlink(const FileSpec &path) { | |||
1345 | Status error("unimplemented"); | |||
1346 | return error; | |||
1347 | } | |||
1348 | ||||
1349 | MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, | |||
1350 | addr_t length, unsigned prot, | |||
1351 | unsigned flags, addr_t fd, | |||
1352 | addr_t offset) { | |||
1353 | uint64_t flags_platform = 0; | |||
1354 | if (flags & eMmapFlagsPrivate) | |||
1355 | flags_platform |= MAP_PRIVATE2; | |||
1356 | if (flags & eMmapFlagsAnon) | |||
1357 | flags_platform |= MAP_ANON0x1000; | |||
1358 | ||||
1359 | MmapArgList args({addr, length, prot, flags_platform, fd, offset}); | |||
1360 | return args; | |||
1361 | } | |||
1362 | ||||
1363 | lldb_private::Status Platform::RunShellCommand( | |||
1364 | const char *command, // Shouldn't be nullptr | |||
1365 | const FileSpec & | |||
1366 | working_dir, // Pass empty FileSpec to use the current working directory | |||
1367 | int *status_ptr, // Pass nullptr if you don't want the process exit status | |||
1368 | int *signo_ptr, // Pass nullptr if you don't want the signal that caused the | |||
1369 | // process to exit | |||
1370 | std::string | |||
1371 | *command_output, // Pass nullptr if you don't want the command output | |||
1372 | const Timeout<std::micro> &timeout) { | |||
1373 | if (IsHost()) | |||
1374 | return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, | |||
1375 | command_output, timeout); | |||
1376 | else | |||
1377 | return Status("unimplemented"); | |||
1378 | } | |||
1379 | ||||
1380 | bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, | |||
1381 | uint64_t &high) { | |||
1382 | if (!IsHost()) | |||
1383 | return false; | |||
1384 | auto Result = llvm::sys::fs::md5_contents(file_spec.GetPath()); | |||
1385 | if (!Result) | |||
1386 | return false; | |||
1387 | std::tie(high, low) = Result->words(); | |||
1388 | return true; | |||
1389 | } | |||
1390 | ||||
1391 | void Platform::SetLocalCacheDirectory(const char *local) { | |||
1392 | m_local_cache_directory.assign(local); | |||
1393 | } | |||
1394 | ||||
1395 | const char *Platform::GetLocalCacheDirectory() { | |||
1396 | return m_local_cache_directory.c_str(); | |||
1397 | } | |||
1398 | ||||
1399 | static constexpr OptionDefinition g_rsync_option_table[] = { | |||
1400 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "rsync", 'r', OptionParser::eNoArgument, nullptr, | |||
1401 | {}, 0, eArgTypeNone, "Enable rsync."}, | |||
1402 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "rsync-opts", 'R', | |||
1403 | OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, | |||
1404 | "Platform-specific options required for rsync to work."}, | |||
1405 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "rsync-prefix", 'P', | |||
1406 | OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, | |||
1407 | "Platform-specific rsync prefix put before the remote path."}, | |||
1408 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "ignore-remote-hostname", 'i', | |||
1409 | OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, | |||
1410 | "Do not automatically fill in the remote hostname when composing the " | |||
1411 | "rsync command."}, | |||
1412 | }; | |||
1413 | ||||
1414 | static constexpr OptionDefinition g_ssh_option_table[] = { | |||
1415 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "ssh", 's', OptionParser::eNoArgument, nullptr, | |||
1416 | {}, 0, eArgTypeNone, "Enable SSH."}, | |||
1417 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "ssh-opts", 'S', OptionParser::eRequiredArgument, | |||
1418 | nullptr, {}, 0, eArgTypeCommandName, | |||
1419 | "Platform-specific options required for SSH to work."}, | |||
1420 | }; | |||
1421 | ||||
1422 | static constexpr OptionDefinition g_caching_option_table[] = { | |||
1423 | {LLDB_OPT_SET_ALL0xFFFFFFFFU, false, "local-cache-dir", 'c', | |||
1424 | OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePath, | |||
1425 | "Path in which to store local copies of files."}, | |||
1426 | }; | |||
1427 | ||||
1428 | llvm::ArrayRef<OptionDefinition> OptionGroupPlatformRSync::GetDefinitions() { | |||
1429 | return llvm::makeArrayRef(g_rsync_option_table); | |||
1430 | } | |||
1431 | ||||
1432 | void OptionGroupPlatformRSync::OptionParsingStarting( | |||
1433 | ExecutionContext *execution_context) { | |||
1434 | m_rsync = false; | |||
1435 | m_rsync_opts.clear(); | |||
1436 | m_rsync_prefix.clear(); | |||
1437 | m_ignores_remote_hostname = false; | |||
1438 | } | |||
1439 | ||||
1440 | lldb_private::Status | |||
1441 | OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx, | |||
1442 | llvm::StringRef option_arg, | |||
1443 | ExecutionContext *execution_context) { | |||
1444 | Status error; | |||
1445 | char short_option = (char)GetDefinitions()[option_idx].short_option; | |||
1446 | switch (short_option) { | |||
1447 | case 'r': | |||
1448 | m_rsync = true; | |||
1449 | break; | |||
1450 | ||||
1451 | case 'R': | |||
1452 | m_rsync_opts.assign(option_arg); | |||
1453 | break; | |||
1454 | ||||
1455 | case 'P': | |||
1456 | m_rsync_prefix.assign(option_arg); | |||
1457 | break; | |||
1458 | ||||
1459 | case 'i': | |||
1460 | m_ignores_remote_hostname = true; | |||
1461 | break; | |||
1462 | ||||
1463 | default: | |||
1464 | error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); | |||
1465 | break; | |||
1466 | } | |||
1467 | ||||
1468 | return error; | |||
1469 | } | |||
1470 | ||||
1471 | lldb::BreakpointSP | |||
1472 | Platform::SetThreadCreationBreakpoint(lldb_private::Target &target) { | |||
1473 | return lldb::BreakpointSP(); | |||
1474 | } | |||
1475 | ||||
1476 | llvm::ArrayRef<OptionDefinition> OptionGroupPlatformSSH::GetDefinitions() { | |||
1477 | return llvm::makeArrayRef(g_ssh_option_table); | |||
1478 | } | |||
1479 | ||||
1480 | void OptionGroupPlatformSSH::OptionParsingStarting( | |||
1481 | ExecutionContext *execution_context) { | |||
1482 | m_ssh = false; | |||
1483 | m_ssh_opts.clear(); | |||
1484 | } | |||
1485 | ||||
1486 | lldb_private::Status | |||
1487 | OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx, | |||
1488 | llvm::StringRef option_arg, | |||
1489 | ExecutionContext *execution_context) { | |||
1490 | Status error; | |||
1491 | char short_option = (char)GetDefinitions()[option_idx].short_option; | |||
1492 | switch (short_option) { | |||
1493 | case 's': | |||
1494 | m_ssh = true; | |||
1495 | break; | |||
1496 | ||||
1497 | case 'S': | |||
1498 | m_ssh_opts.assign(option_arg); | |||
1499 | break; | |||
1500 | ||||
1501 | default: | |||
1502 | error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); | |||
1503 | break; | |||
1504 | } | |||
1505 | ||||
1506 | return error; | |||
1507 | } | |||
1508 | ||||
1509 | llvm::ArrayRef<OptionDefinition> OptionGroupPlatformCaching::GetDefinitions() { | |||
1510 | return llvm::makeArrayRef(g_caching_option_table); | |||
1511 | } | |||
1512 | ||||
1513 | void OptionGroupPlatformCaching::OptionParsingStarting( | |||
1514 | ExecutionContext *execution_context) { | |||
1515 | m_cache_dir.clear(); | |||
1516 | } | |||
1517 | ||||
1518 | lldb_private::Status OptionGroupPlatformCaching::SetOptionValue( | |||
1519 | uint32_t option_idx, llvm::StringRef option_arg, | |||
1520 | ExecutionContext *execution_context) { | |||
1521 | Status error; | |||
1522 | char short_option = (char)GetDefinitions()[option_idx].short_option; | |||
1523 | switch (short_option) { | |||
1524 | case 'c': | |||
1525 | m_cache_dir.assign(option_arg); | |||
1526 | break; | |||
1527 | ||||
1528 | default: | |||
1529 | error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); | |||
1530 | break; | |||
1531 | } | |||
1532 | ||||
1533 | return error; | |||
1534 | } | |||
1535 | ||||
1536 | Environment Platform::GetEnvironment() { return Environment(); } | |||
1537 | ||||
1538 | const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { | |||
1539 | if (!m_calculated_trap_handlers) { | |||
1540 | std::lock_guard<std::mutex> guard(m_mutex); | |||
1541 | if (!m_calculated_trap_handlers) { | |||
1542 | CalculateTrapHandlerSymbolNames(); | |||
1543 | m_calculated_trap_handlers = true; | |||
1544 | } | |||
1545 | } | |||
1546 | return m_trap_handlers; | |||
1547 | } | |||
1548 | ||||
1549 | Status Platform::GetCachedExecutable( | |||
1550 | ModuleSpec &module_spec, lldb::ModuleSP &module_sp, | |||
1551 | const FileSpecList *module_search_paths_ptr, Platform &remote_platform) { | |||
1552 | const auto platform_spec = module_spec.GetFileSpec(); | |||
1553 | const auto error = LoadCachedExecutable( | |||
1554 | module_spec, module_sp, module_search_paths_ptr, remote_platform); | |||
1555 | if (error.Success()) { | |||
1556 | module_spec.GetFileSpec() = module_sp->GetFileSpec(); | |||
1557 | module_spec.GetPlatformFileSpec() = platform_spec; | |||
1558 | } | |||
1559 | ||||
1560 | return error; | |||
1561 | } | |||
1562 | ||||
1563 | Status Platform::LoadCachedExecutable( | |||
1564 | const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, | |||
1565 | const FileSpecList *module_search_paths_ptr, Platform &remote_platform) { | |||
1566 | return GetRemoteSharedModule(module_spec, nullptr, module_sp, | |||
1567 | [&](const ModuleSpec &spec) { | |||
1568 | return remote_platform.ResolveExecutable( | |||
1569 | spec, module_sp, module_search_paths_ptr); | |||
1570 | }, | |||
1571 | nullptr); | |||
1572 | } | |||
1573 | ||||
1574 | Status Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, | |||
1575 | Process *process, | |||
1576 | lldb::ModuleSP &module_sp, | |||
1577 | const ModuleResolver &module_resolver, | |||
1578 | bool *did_create_ptr) { | |||
1579 | // Get module information from a target. | |||
1580 | ModuleSpec resolved_module_spec; | |||
1581 | bool got_module_spec = false; | |||
1582 | if (process) { | |||
1583 | // Try to get module information from the process | |||
1584 | if (process->GetModuleSpec(module_spec.GetFileSpec(), | |||
1585 | module_spec.GetArchitecture(), | |||
1586 | resolved_module_spec)) { | |||
1587 | if (module_spec.GetUUID().IsValid() == false || | |||
1588 | module_spec.GetUUID() == resolved_module_spec.GetUUID()) { | |||
1589 | got_module_spec = true; | |||
1590 | } | |||
1591 | } | |||
1592 | } | |||
1593 | ||||
1594 | if (module_spec.GetArchitecture().IsValid() == false) { | |||
1595 | Status error; | |||
1596 | // No valid architecture was specified, ask the platform for the | |||
1597 | // architectures that we should be using (in the correct order) and see if | |||
1598 | // we can find a match that way | |||
1599 | ModuleSpec arch_module_spec(module_spec); | |||
1600 | for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( | |||
1601 | idx, arch_module_spec.GetArchitecture()); | |||
1602 | ++idx) { | |||
1603 | error = ModuleList::GetSharedModule(arch_module_spec, module_sp, nullptr, | |||
1604 | nullptr, nullptr); | |||
1605 | // Did we find an executable using one of the | |||
1606 | if (error.Success() && module_sp) | |||
1607 | break; | |||
1608 | } | |||
1609 | if (module_sp) | |||
1610 | got_module_spec = true; | |||
1611 | } | |||
1612 | ||||
1613 | if (!got_module_spec) { | |||
1614 | // Get module information from a target. | |||
1615 | if (!GetModuleSpec(module_spec.GetFileSpec(), module_spec.GetArchitecture(), | |||
1616 | resolved_module_spec)) { | |||
1617 | if (module_spec.GetUUID().IsValid() == false || | |||
1618 | module_spec.GetUUID() == resolved_module_spec.GetUUID()) { | |||
1619 | return module_resolver(module_spec); | |||
1620 | } | |||
1621 | } | |||
1622 | } | |||
1623 | ||||
1624 | // If we are looking for a specific UUID, make sure resolved_module_spec has | |||
1625 | // the same one before we search. | |||
1626 | if (module_spec.GetUUID().IsValid()) { | |||
1627 | resolved_module_spec.GetUUID() = module_spec.GetUUID(); | |||
1628 | } | |||
1629 | ||||
1630 | // Trying to find a module by UUID on local file system. | |||
1631 | const auto error = module_resolver(resolved_module_spec); | |||
1632 | if (error.Fail()) { | |||
1633 | if (GetCachedSharedModule(resolved_module_spec, module_sp, did_create_ptr)) | |||
1634 | return Status(); | |||
1635 | } | |||
1636 | ||||
1637 | return error; | |||
1638 | } | |||
1639 | ||||
1640 | bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec, | |||
1641 | lldb::ModuleSP &module_sp, | |||
1642 | bool *did_create_ptr) { | |||
1643 | if (IsHost() || !GetGlobalPlatformProperties()->GetUseModuleCache() || | |||
1644 | !GetGlobalPlatformProperties()->GetModuleCacheDirectory()) | |||
1645 | return false; | |||
1646 | ||||
1647 | Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM(1u << 25)); | |||
1648 | ||||
1649 | // Check local cache for a module. | |||
1650 | auto error = m_module_cache->GetAndPut( | |||
1651 | GetModuleCacheRoot(), GetCacheHostname(), module_spec, | |||
1652 | [this](const ModuleSpec &module_spec, | |||
1653 | const FileSpec &tmp_download_file_spec) { | |||
1654 | return DownloadModuleSlice( | |||
1655 | module_spec.GetFileSpec(), module_spec.GetObjectOffset(), | |||
1656 | module_spec.GetObjectSize(), tmp_download_file_spec); | |||
1657 | ||||
1658 | }, | |||
1659 | [this](const ModuleSP &module_sp, | |||
1660 | const FileSpec &tmp_download_file_spec) { | |||
1661 | return DownloadSymbolFile(module_sp, tmp_download_file_spec); | |||
1662 | }, | |||
1663 | module_sp, did_create_ptr); | |||
1664 | if (error.Success()) | |||
1665 | return true; | |||
1666 | ||||
1667 | if (log) | |||
1668 | log->Printf("Platform::%s - module %s not found in local cache: %s", | |||
1669 | __FUNCTION__, module_spec.GetUUID().GetAsString().c_str(), | |||
1670 | error.AsCString()); | |||
1671 | return false; | |||
1672 | } | |||
1673 | ||||
1674 | Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec, | |||
1675 | const uint64_t src_offset, | |||
1676 | const uint64_t src_size, | |||
1677 | const FileSpec &dst_file_spec) { | |||
1678 | Status error; | |||
1679 | ||||
1680 | std::error_code EC; | |||
1681 | llvm::raw_fd_ostream dst(dst_file_spec.GetPath(), EC, llvm::sys::fs::F_None); | |||
1682 | if (EC) { | |||
1683 | error.SetErrorStringWithFormat("unable to open destination file: %s", | |||
1684 | dst_file_spec.GetPath().c_str()); | |||
1685 | return error; | |||
1686 | } | |||
1687 | ||||
1688 | auto src_fd = OpenFile(src_file_spec, File::eOpenOptionRead, | |||
1689 | lldb::eFilePermissionsFileDefault, error); | |||
1690 | ||||
1691 | if (error.Fail()) { | |||
1692 | error.SetErrorStringWithFormat("unable to open source file: %s", | |||
1693 | error.AsCString()); | |||
1694 | return error; | |||
1695 | } | |||
1696 | ||||
1697 | std::vector<char> buffer(1024); | |||
1698 | auto offset = src_offset; | |||
1699 | uint64_t total_bytes_read = 0; | |||
1700 | while (total_bytes_read < src_size) { | |||
1701 | const auto to_read = std::min(static_cast<uint64_t>(buffer.size()), | |||
1702 | src_size - total_bytes_read); | |||
1703 | const uint64_t n_read = | |||
1704 | ReadFile(src_fd, offset, &buffer[0], to_read, error); | |||
1705 | if (error.Fail()) | |||
1706 | break; | |||
1707 | if (n_read == 0) { | |||
1708 | error.SetErrorString("read 0 bytes"); | |||
1709 | break; | |||
1710 | } | |||
1711 | offset += n_read; | |||
1712 | total_bytes_read += n_read; | |||
1713 | dst.write(&buffer[0], n_read); | |||
1714 | } | |||
1715 | ||||
1716 | Status close_error; | |||
1717 | CloseFile(src_fd, close_error); // Ignoring close error. | |||
1718 | ||||
1719 | return error; | |||
1720 | } | |||
1721 | ||||
1722 | Status Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp, | |||
1723 | const FileSpec &dst_file_spec) { | |||
1724 | return Status( | |||
1725 | "Symbol file downloading not supported by the default platform."); | |||
1726 | } | |||
1727 | ||||
1728 | FileSpec Platform::GetModuleCacheRoot() { | |||
1729 | auto dir_spec = GetGlobalPlatformProperties()->GetModuleCacheDirectory(); | |||
1730 | dir_spec.AppendPathComponent(GetName().AsCString()); | |||
1731 | return dir_spec; | |||
1732 | } | |||
1733 | ||||
1734 | const char *Platform::GetCacheHostname() { return GetHostname(); } | |||
1735 | ||||
1736 | const UnixSignalsSP &Platform::GetRemoteUnixSignals() { | |||
1737 | static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); | |||
1738 | return s_default_unix_signals_sp; | |||
1739 | } | |||
1740 | ||||
1741 | const UnixSignalsSP &Platform::GetUnixSignals() { | |||
1742 | if (IsHost()) | |||
1743 | return Host::GetUnixSignals(); | |||
1744 | return GetRemoteUnixSignals(); | |||
1745 | } | |||
1746 | ||||
1747 | uint32_t Platform::LoadImage(lldb_private::Process *process, | |||
1748 | const lldb_private::FileSpec &local_file, | |||
1749 | const lldb_private::FileSpec &remote_file, | |||
1750 | lldb_private::Status &error) { | |||
1751 | if (local_file && remote_file) { | |||
1752 | // Both local and remote file was specified. Install the local file to the | |||
1753 | // given location. | |||
1754 | if (IsRemote() || local_file != remote_file) { | |||
1755 | error = Install(local_file, remote_file); | |||
1756 | if (error.Fail()) | |||
1757 | return LLDB_INVALID_IMAGE_TOKEN(4294967295U); | |||
1758 | } | |||
1759 | return DoLoadImage(process, remote_file, nullptr, error); | |||
1760 | } | |||
1761 | ||||
1762 | if (local_file) { | |||
1763 | // Only local file was specified. Install it to the current working | |||
1764 | // directory. | |||
1765 | FileSpec target_file = GetWorkingDirectory(); | |||
1766 | target_file.AppendPathComponent(local_file.GetFilename().AsCString()); | |||
1767 | if (IsRemote() || local_file != target_file) { | |||
1768 | error = Install(local_file, target_file); | |||
1769 | if (error.Fail()) | |||
1770 | return LLDB_INVALID_IMAGE_TOKEN(4294967295U); | |||
1771 | } | |||
1772 | return DoLoadImage(process, target_file, nullptr, error); | |||
1773 | } | |||
1774 | ||||
1775 | if (remote_file) { | |||
1776 | // Only remote file was specified so we don't have to do any copying | |||
1777 | return DoLoadImage(process, remote_file, nullptr, error); | |||
1778 | } | |||
1779 | ||||
1780 | error.SetErrorString("Neither local nor remote file was specified"); | |||
1781 | return LLDB_INVALID_IMAGE_TOKEN(4294967295U); | |||
1782 | } | |||
1783 | ||||
1784 | uint32_t Platform::DoLoadImage(lldb_private::Process *process, | |||
1785 | const lldb_private::FileSpec &remote_file, | |||
1786 | const std::vector<std::string> *paths, | |||
1787 | lldb_private::Status &error, | |||
1788 | lldb_private::FileSpec *loaded_image) { | |||
1789 | error.SetErrorString("LoadImage is not supported on the current platform"); | |||
1790 | return LLDB_INVALID_IMAGE_TOKEN(4294967295U); | |||
1791 | } | |||
1792 | ||||
1793 | uint32_t Platform::LoadImageUsingPaths(lldb_private::Process *process, | |||
1794 | const lldb_private::FileSpec &remote_filename, | |||
1795 | const std::vector<std::string> &paths, | |||
1796 | lldb_private::Status &error, | |||
1797 | lldb_private::FileSpec *loaded_path) | |||
1798 | { | |||
1799 | FileSpec file_to_use; | |||
1800 | if (remote_filename.IsAbsolute()) | |||
1801 | file_to_use = FileSpec(remote_filename.GetFilename().GetStringRef(), | |||
1802 | false, | |||
1803 | remote_filename.GetPathStyle()); | |||
1804 | else | |||
1805 | file_to_use = remote_filename; | |||
1806 | ||||
1807 | return DoLoadImage(process, file_to_use, &paths, error, loaded_path); | |||
1808 | } | |||
1809 | ||||
1810 | Status Platform::UnloadImage(lldb_private::Process *process, | |||
1811 | uint32_t image_token) { | |||
1812 | return Status("UnloadImage is not supported on the current platform"); | |||
1813 | } | |||
1814 | ||||
1815 | lldb::ProcessSP Platform::ConnectProcess(llvm::StringRef connect_url, | |||
1816 | llvm::StringRef plugin_name, | |||
1817 | lldb_private::Debugger &debugger, | |||
1818 | lldb_private::Target *target, | |||
1819 | lldb_private::Status &error) { | |||
1820 | error.Clear(); | |||
1821 | ||||
1822 | if (!target) { | |||
1823 | ArchSpec arch; | |||
1824 | if (target && target->GetArchitecture().IsValid()) | |||
1825 | arch = target->GetArchitecture(); | |||
1826 | else | |||
1827 | arch = Target::GetDefaultArchitecture(); | |||
1828 | ||||
1829 | const char *triple = ""; | |||
1830 | if (arch.IsValid()) | |||
1831 | triple = arch.GetTriple().getTriple().c_str(); | |||
1832 | ||||
1833 | TargetSP new_target_sp; | |||
1834 | error = debugger.GetTargetList().CreateTarget( | |||
1835 | debugger, "", triple, eLoadDependentsNo, nullptr, new_target_sp); | |||
1836 | target = new_target_sp.get(); | |||
1837 | } | |||
1838 | ||||
1839 | if (!target || error.Fail()) | |||
1840 | return nullptr; | |||
1841 | ||||
1842 | debugger.GetTargetList().SetSelectedTarget(target); | |||
1843 | ||||
1844 | lldb::ProcessSP process_sp = | |||
1845 | target->CreateProcess(debugger.GetListener(), plugin_name, nullptr); | |||
1846 | if (!process_sp) | |||
1847 | return nullptr; | |||
1848 | ||||
1849 | error = | |||
1850 | process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url); | |||
1851 | if (error.Fail()) | |||
1852 | return nullptr; | |||
1853 | ||||
1854 | return process_sp; | |||
1855 | } | |||
1856 | ||||
1857 | size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger, | |||
1858 | lldb_private::Status &error) { | |||
1859 | error.Clear(); | |||
1860 | return 0; | |||
1861 | } | |||
1862 | ||||
1863 | size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, | |||
1864 | BreakpointSite *bp_site) { | |||
1865 | ArchSpec arch = target.GetArchitecture(); | |||
1866 | const uint8_t *trap_opcode = nullptr; | |||
1867 | size_t trap_opcode_size = 0; | |||
1868 | ||||
1869 | switch (arch.GetMachine()) { | |||
1870 | case llvm::Triple::aarch64: { | |||
1871 | static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; | |||
1872 | trap_opcode = g_aarch64_opcode; | |||
1873 | trap_opcode_size = sizeof(g_aarch64_opcode); | |||
1874 | } break; | |||
1875 | ||||
1876 | // TODO: support big-endian arm and thumb trap codes. | |||
1877 | case llvm::Triple::arm: { | |||
1878 | // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the | |||
1879 | // linux kernel does otherwise. | |||
1880 | static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; | |||
1881 | static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; | |||
1882 | ||||
1883 | lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); | |||
1884 | AddressClass addr_class = AddressClass::eUnknown; | |||
1885 | ||||
1886 | if (bp_loc_sp) { | |||
1887 | addr_class = bp_loc_sp->GetAddress().GetAddressClass(); | |||
1888 | if (addr_class == AddressClass::eUnknown && | |||
1889 | (bp_loc_sp->GetAddress().GetFileAddress() & 1)) | |||
1890 | addr_class = AddressClass::eCodeAlternateISA; | |||
1891 | } | |||
1892 | ||||
1893 | if (addr_class == AddressClass::eCodeAlternateISA) { | |||
1894 | trap_opcode = g_thumb_breakpoint_opcode; | |||
1895 | trap_opcode_size = sizeof(g_thumb_breakpoint_opcode); | |||
1896 | } else { | |||
1897 | trap_opcode = g_arm_breakpoint_opcode; | |||
1898 | trap_opcode_size = sizeof(g_arm_breakpoint_opcode); | |||
1899 | } | |||
1900 | } break; | |||
1901 | ||||
1902 | case llvm::Triple::mips: | |||
1903 | case llvm::Triple::mips64: { | |||
1904 | static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d}; | |||
1905 | trap_opcode = g_hex_opcode; | |||
1906 | trap_opcode_size = sizeof(g_hex_opcode); | |||
1907 | } break; | |||
1908 | ||||
1909 | case llvm::Triple::mipsel: | |||
1910 | case llvm::Triple::mips64el: { | |||
1911 | static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00}; | |||
1912 | trap_opcode = g_hex_opcode; | |||
1913 | trap_opcode_size = sizeof(g_hex_opcode); | |||
1914 | } break; | |||
1915 | ||||
1916 | case llvm::Triple::systemz: { | |||
1917 | static const uint8_t g_hex_opcode[] = {0x00, 0x01}; | |||
1918 | trap_opcode = g_hex_opcode; | |||
1919 | trap_opcode_size = sizeof(g_hex_opcode); | |||
1920 | } break; | |||
1921 | ||||
1922 | case llvm::Triple::hexagon: { | |||
1923 | static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54}; | |||
1924 | trap_opcode = g_hex_opcode; | |||
1925 | trap_opcode_size = sizeof(g_hex_opcode); | |||
1926 | } break; | |||
1927 | ||||
1928 | case llvm::Triple::ppc: | |||
1929 | case llvm::Triple::ppc64: { | |||
1930 | static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; | |||
1931 | trap_opcode = g_ppc_opcode; | |||
1932 | trap_opcode_size = sizeof(g_ppc_opcode); | |||
1933 | } break; | |||
1934 | ||||
1935 | case llvm::Triple::ppc64le: { | |||
1936 | static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap | |||
1937 | trap_opcode = g_ppc64le_opcode; | |||
1938 | trap_opcode_size = sizeof(g_ppc64le_opcode); | |||
1939 | } break; | |||
1940 | ||||
1941 | case llvm::Triple::x86: | |||
1942 | case llvm::Triple::x86_64: { | |||
1943 | static const uint8_t g_i386_opcode[] = {0xCC}; | |||
1944 | trap_opcode = g_i386_opcode; | |||
1945 | trap_opcode_size = sizeof(g_i386_opcode); | |||
1946 | } break; | |||
1947 | ||||
1948 | default: | |||
1949 | llvm_unreachable(::llvm::llvm_unreachable_internal("Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , 1950) | |||
1950 | "Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode")::llvm::llvm_unreachable_internal("Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , 1950); | |||
1951 | } | |||
1952 | ||||
1953 | assert(bp_site)((bp_site) ? static_cast<void> (0) : __assert_fail ("bp_site" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Target/Platform.cpp" , 1953, __PRETTY_FUNCTION__)); | |||
1954 | if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) | |||
1955 | return trap_opcode_size; | |||
1956 | ||||
1957 | return 0; | |||
1958 | } |