diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common')
23 files changed, 674 insertions, 1854 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp index 1c5c0ffe902b..b157cdb7c110 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp @@ -11,16 +11,19 @@ #include <iostream> #include <limits.h> -#include "lldb/Core/Error.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Core/StringList.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Editline.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/SelectHelper.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StringList.h" +#include "lldb/Utility/Timeout.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Threading.h" using namespace lldb_private; using namespace lldb_private::line_editor; @@ -176,9 +179,7 @@ private: if (m_path.empty() && m_history && !m_prefix.empty()) { FileSpec parent_path{"~/.lldb", true}; char history_path[PATH_MAX]; - if (FileSystem::MakeDirectory(parent_path, - lldb::eFilePermissionsDirectoryDefault) - .Success()) { + if (!llvm::sys::fs::create_directory(parent_path.GetPath())) { snprintf(history_path, sizeof(history_path), "~/.lldb/%s-history", m_prefix.c_str()); } else { @@ -1151,8 +1152,8 @@ Editline::Editline(const char *editline_name, FILE *input_file, if (term_fd != -1) { static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr; static std::set<int> *g_init_terminal_fds_ptr = nullptr; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, [&]() { + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, [&]() { g_init_terminal_fds_mutex_ptr = new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid diff --git a/contrib/llvm/tools/lldb/source/Host/common/File.cpp b/contrib/llvm/tools/lldb/source/Host/common/File.cpp index 4eb9ae15f069..1869a6db49c9 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/File.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/File.cpp @@ -19,17 +19,18 @@ #include "lldb/Host/windows/windows.h" #else #include <sys/ioctl.h> +#include <sys/stat.h> +#include <termios.h> #endif #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" #include "lldb/Host/Config.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/FileSystem.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" using namespace lldb; using namespace lldb_private; @@ -247,14 +248,12 @@ Error File::Open(const char *path, uint32_t options, uint32_t permissions) { uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) { if (file_spec) { - struct stat file_stats; - int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); - if (stat_result == -1) - error.SetErrorToErrno(); - else { - error.Clear(); - return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - } + error.Clear(); + auto Perms = llvm::sys::fs::getPermissions(file_spec.GetPath()); + if (Perms) + return *Perms; + error = Error(Perms.getError()); + return 0; } else error.SetErrorString("empty file spec"); return 0; @@ -308,7 +307,7 @@ void File::Clear() { Error File::GetFileSpec(FileSpec &file_spec) const { Error error; -#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED +#ifdef F_GETPATH if (IsValid()) { char path[PATH_MAX]; if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp deleted file mode 100644 index 7f46d303a5d8..000000000000 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp +++ /dev/null @@ -1,1431 +0,0 @@ -//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef _WIN32 -#include <dirent.h> -#else -#include "lldb/Host/windows/windows.h" -#endif -#include <fcntl.h> -#ifndef _MSC_VER -#include <libgen.h> -#endif -#include <fstream> -#include <set> -#include <string.h> - -#include "lldb/Host/Config.h" // Have to include this before we test the define... -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER -#include <pwd.h> -#endif - -#include "lldb/Core/ArchSpec.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/DataBufferMemoryMap.h" -#include "lldb/Core/RegularExpression.h" -#include "lldb/Core/Stream.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/Host.h" -#include "lldb/Utility/CleanUp.h" - -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { - -bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) { - return (syntax == FileSpec::ePathSyntaxPosix || - (syntax == FileSpec::ePathSyntaxHostNative && - FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); -} - -const char *GetPathSeparators(FileSpec::PathSyntax syntax) { - return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; -} - -char GetPreferredPathSeparator(FileSpec::PathSyntax syntax) { - return GetPathSeparators(syntax)[0]; -} - -bool IsPathSeparator(char value, FileSpec::PathSyntax syntax) { - return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); -} - -void Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) { - if (PathSyntaxIsPosix(syntax)) - return; - - std::replace(path.begin(), path.end(), '\\', '/'); - // Windows path can have \\ slashes which can be changed by replace - // call above to //. Here we remove the duplicate. - auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) { - return (c1 == '/' && c2 == '/'); - }); - path.erase(iter, path.end()); -} - -void Denormalize(llvm::SmallVectorImpl<char> &path, - FileSpec::PathSyntax syntax) { - if (PathSyntaxIsPosix(syntax)) - return; - - std::replace(path.begin(), path.end(), '/', '\\'); -} - -bool GetFileStats(const FileSpec *file_spec, struct stat *stats_ptr) { - char resolved_path[PATH_MAX]; - if (file_spec->GetPath(resolved_path, sizeof(resolved_path))) - return FileSystem::Stat(resolved_path, stats_ptr) == 0; - return false; -} - -size_t FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) { - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return 0; - - if (str.size() > 0 && IsPathSeparator(str.back(), syntax)) - return str.size() - 1; - - size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1); - - if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); - - if (pos == llvm::StringRef::npos || - (pos == 1 && IsPathSeparator(str[0], syntax))) - return 0; - - return pos + 1; -} - -size_t RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) { - // case "c:/" - if (!PathSyntaxIsPosix(syntax) && - (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax))) - return 2; - - // case "//" - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return llvm::StringRef::npos; - - // case "//net" - if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] && - !IsPathSeparator(str[2], syntax)) - return str.find_first_of(GetPathSeparators(syntax), 2); - - // case "/" - if (str.size() > 0 && IsPathSeparator(str[0], syntax)) - return 0; - - return llvm::StringRef::npos; -} - -size_t ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) { - size_t end_pos = FilenamePos(path, syntax); - - bool filename_was_sep = - path.size() > 0 && IsPathSeparator(path[end_pos], syntax); - - // Skip separators except for root dir. - size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax); - - while (end_pos > 0 && (end_pos - 1) != root_dir_pos && - IsPathSeparator(path[end_pos - 1], syntax)) - --end_pos; - - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return llvm::StringRef::npos; - - return end_pos; -} - -} // end anonymous namespace - -// Resolves the username part of a path of the form ~user/other/directories, and -// writes the result into dst_path. This will also resolve "~" to the current -// user. -// If you want to complete "~" to the list of users, pass it to -// ResolvePartialUsername. -void FileSpec::ResolveUsername(llvm::SmallVectorImpl<char> &path) { -#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path.empty() || path[0] != '~') - return; - - llvm::StringRef path_str(path.data(), path.size()); - size_t slash_pos = path_str.find('/', 1); - if (slash_pos == 1 || path.size() == 1) { - // A path of ~/ resolves to the current user's home dir - llvm::SmallString<64> home_dir; - // llvm::sys::path::home_directory() only checks if "HOME" is set in the - // environment and does nothing else to locate the user home directory - if (!llvm::sys::path::home_directory(home_dir)) { - struct passwd *pw = getpwuid(getuid()); - if (pw && pw->pw_dir && pw->pw_dir[0]) { - // Update our environemnt so llvm::sys::path::home_directory() works - // next time - setenv("HOME", pw->pw_dir, 0); - home_dir.assign(llvm::StringRef(pw->pw_dir)); - } else { - return; - } - } - - // Overwrite the ~ with the first character of the homedir, and insert - // the rest. This way we only trigger one move, whereas an insert - // followed by a delete (or vice versa) would trigger two. - path[0] = home_dir[0]; - path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); - return; - } - - auto username_begin = path.begin() + 1; - auto username_end = (slash_pos == llvm::StringRef::npos) - ? path.end() - : (path.begin() + slash_pos); - size_t replacement_length = std::distance(path.begin(), username_end); - - llvm::SmallString<20> username(username_begin, username_end); - struct passwd *user_entry = ::getpwnam(username.c_str()); - if (user_entry != nullptr) { - // Copy over the first n characters of the path, where n is the smaller of - // the length - // of the home directory and the slash pos. - llvm::StringRef homedir(user_entry->pw_dir); - size_t initial_copy_length = std::min(homedir.size(), replacement_length); - auto src_begin = homedir.begin(); - auto src_end = src_begin + initial_copy_length; - std::copy(src_begin, src_end, path.begin()); - if (replacement_length > homedir.size()) { - // We copied the entire home directory, but the ~username portion of the - // path was - // longer, so there's characters that need to be removed. - path.erase(path.begin() + initial_copy_length, username_end); - } else if (replacement_length < homedir.size()) { - // We copied all the way up to the slash in the destination, but there's - // still more - // characters that need to be inserted. - path.insert(username_end, src_end, homedir.end()); - } - } else { - // Unable to resolve username (user doesn't exist?) - path.clear(); - } -#endif -} - -size_t FileSpec::ResolvePartialUsername(llvm::StringRef partial_name, - StringList &matches) { -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - size_t extant_entries = matches.GetSize(); - - setpwent(); - struct passwd *user_entry; - partial_name = partial_name.drop_front(); - std::set<std::string> name_list; - - while ((user_entry = getpwent()) != NULL) { - if (llvm::StringRef(user_entry->pw_name).startswith(partial_name)) { - std::string tmp_buf("~"); - tmp_buf.append(user_entry->pw_name); - tmp_buf.push_back('/'); - name_list.insert(tmp_buf); - } - } - - for (auto &name : name_list) { - matches.AppendString(name); - } - return matches.GetSize() - extant_entries; -#else - // Resolving home directories is not supported, just copy the path... - return 0; -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER -} - -void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) { - if (path.empty()) - return; - -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path[0] == '~') - ResolveUsername(path); -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - - // Save a copy of the original path that's passed in - llvm::SmallString<128> original_path(path.begin(), path.end()); - - llvm::sys::fs::make_absolute(path); - if (!llvm::sys::fs::exists(path)) { - path.clear(); - path.append(original_path.begin(), original_path.end()); - } -} - -FileSpec::FileSpec() : m_syntax(FileSystem::GetNativePathSyntax()) {} - -//------------------------------------------------------------------ -// Default constructor that can take an optional full path to a -// file on disk. -//------------------------------------------------------------------ -FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, PathSyntax syntax) - : m_syntax(syntax) { - SetFile(path, resolve_path, syntax); -} - -FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, ArchSpec arch) - : FileSpec{path, resolve_path, arch.GetTriple().isOSWindows() - ? ePathSyntaxWindows - : ePathSyntaxPosix} {} - -//------------------------------------------------------------------ -// Copy constructor -//------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec &rhs) - : m_directory(rhs.m_directory), m_filename(rhs.m_filename), - m_is_resolved(rhs.m_is_resolved), m_syntax(rhs.m_syntax) {} - -//------------------------------------------------------------------ -// Copy constructor -//------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec *rhs) : m_directory(), m_filename() { - if (rhs) - *this = *rhs; -} - -//------------------------------------------------------------------ -// Virtual destructor in case anyone inherits from this class. -//------------------------------------------------------------------ -FileSpec::~FileSpec() {} - -//------------------------------------------------------------------ -// Assignment operator. -//------------------------------------------------------------------ -const FileSpec &FileSpec::operator=(const FileSpec &rhs) { - if (this != &rhs) { - m_directory = rhs.m_directory; - m_filename = rhs.m_filename; - m_is_resolved = rhs.m_is_resolved; - m_syntax = rhs.m_syntax; - } - return *this; -} - -//------------------------------------------------------------------ -// Update the contents of this object with a new path. The path will -// be split up into a directory and filename and stored as uniqued -// string values for quick comparison and efficient memory usage. -//------------------------------------------------------------------ -void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, - PathSyntax syntax) { - // CLEANUP: Use StringRef for string handling. This function is kind of a - // mess and the unclear semantics of RootDirStart and ParentPathEnd make - // it very difficult to understand this function. There's no reason this - // function should be particularly complicated or difficult to understand. - m_filename.Clear(); - m_directory.Clear(); - m_is_resolved = false; - m_syntax = (syntax == ePathSyntaxHostNative) - ? FileSystem::GetNativePathSyntax() - : syntax; - - if (pathname.empty()) - return; - - llvm::SmallString<64> resolved(pathname); - - if (resolve) { - FileSpec::Resolve(resolved); - m_is_resolved = true; - } - - Normalize(resolved, m_syntax); - - llvm::StringRef resolve_path_ref(resolved.c_str()); - size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax); - if (dir_end == 0) { - m_filename.SetString(resolve_path_ref); - return; - } - - m_directory.SetString(resolve_path_ref.substr(0, dir_end)); - - size_t filename_begin = dir_end; - size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax); - while (filename_begin != llvm::StringRef::npos && - filename_begin < resolve_path_ref.size() && - filename_begin != root_dir_start && - IsPathSeparator(resolve_path_ref[filename_begin], m_syntax)) - ++filename_begin; - m_filename.SetString((filename_begin == llvm::StringRef::npos || - filename_begin >= resolve_path_ref.size()) - ? "." - : resolve_path_ref.substr(filename_begin)); -} - -void FileSpec::SetFile(llvm::StringRef path, bool resolve, ArchSpec arch) { - return SetFile(path, resolve, arch.GetTriple().isOSWindows() - ? ePathSyntaxWindows - : ePathSyntaxPosix); -} - -//---------------------------------------------------------------------- -// Convert to pointer operator. This allows code to check any FileSpec -// objects to see if they contain anything valid using code such as: -// -// if (file_spec) -// {} -//---------------------------------------------------------------------- -FileSpec::operator bool() const { return m_filename || m_directory; } - -//---------------------------------------------------------------------- -// Logical NOT operator. This allows code to check any FileSpec -// objects to see if they are invalid using code such as: -// -// if (!file_spec) -// {} -//---------------------------------------------------------------------- -bool FileSpec::operator!() const { return !m_directory && !m_filename; } - -bool FileSpec::DirectoryEquals(const FileSpec &rhs) const { - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive); -} - -bool FileSpec::FileEquals(const FileSpec &rhs) const { - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive); -} - -//------------------------------------------------------------------ -// Equal to operator -//------------------------------------------------------------------ -bool FileSpec::operator==(const FileSpec &rhs) const { - if (!FileEquals(rhs)) - return false; - if (DirectoryEquals(rhs)) - return true; - - // TODO: determine if we want to keep this code in here. - // The code below was added to handle a case where we were - // trying to set a file and line breakpoint and one path - // was resolved, and the other not and the directory was - // in a mount point that resolved to a more complete path: - // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling - // this out... - if (IsResolved() && rhs.IsResolved()) { - // Both paths are resolved, no need to look further... - return false; - } - - FileSpec resolved_lhs(*this); - - // If "this" isn't resolved, resolve it - if (!IsResolved()) { - if (resolved_lhs.ResolvePath()) { - // This path wasn't resolved but now it is. Check if the resolved - // directory is the same as our unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - m_is_resolved = (m_directory == resolved_lhs.m_directory); - } else - return false; - } - - FileSpec resolved_rhs(rhs); - if (!rhs.IsResolved()) { - if (resolved_rhs.ResolvePath()) { - // rhs's path wasn't resolved but now it is. Check if the resolved - // directory is the same as rhs's unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); - } else - return false; - } - - // If we reach this point in the code we were able to resolve both paths - // and since we only resolve the paths if the basenames are equal, then - // we can just check if both directories are equal... - return DirectoryEquals(rhs); -} - -//------------------------------------------------------------------ -// Not equal to operator -//------------------------------------------------------------------ -bool FileSpec::operator!=(const FileSpec &rhs) const { return !(*this == rhs); } - -//------------------------------------------------------------------ -// Less than operator -//------------------------------------------------------------------ -bool FileSpec::operator<(const FileSpec &rhs) const { - return FileSpec::Compare(*this, rhs, true) < 0; -} - -//------------------------------------------------------------------ -// Dump a FileSpec object to a stream -//------------------------------------------------------------------ -Stream &lldb_private::operator<<(Stream &s, const FileSpec &f) { - f.Dump(&s); - return s; -} - -//------------------------------------------------------------------ -// Clear this object by releasing both the directory and filename -// string values and making them both the empty string. -//------------------------------------------------------------------ -void FileSpec::Clear() { - m_directory.Clear(); - m_filename.Clear(); -} - -//------------------------------------------------------------------ -// Compare two FileSpec objects. If "full" is true, then both -// the directory and the filename must match. If "full" is false, -// then the directory names for "a" and "b" are only compared if -// they are both non-empty. This allows a FileSpec object to only -// contain a filename and it can match FileSpec objects that have -// matching filenames with different paths. -// -// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" -// and "1" if "a" is greater than "b". -//------------------------------------------------------------------ -int FileSpec::Compare(const FileSpec &a, const FileSpec &b, bool full) { - int result = 0; - - // case sensitivity of compare - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - // If full is true, then we must compare both the directory and filename. - - // If full is false, then if either directory is empty, then we match on - // the basename only, and if both directories have valid values, we still - // do a full compare. This allows for matching when we just have a filename - // in one of the FileSpec objects. - - if (full || (a.m_directory && b.m_directory)) { - result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive); - if (result) - return result; - } - return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive); -} - -bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full, - bool remove_backups) { - // case sensitivity of equality test - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) - return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); - - if (remove_backups == false) - return a == b; - - if (a == b) - return true; - - return Equal(a.GetNormalizedPath(), b.GetNormalizedPath(), full, false); -} - -FileSpec FileSpec::GetNormalizedPath() const { - // Fast path. Do nothing if the path is not interesting. - if (!m_directory.GetStringRef().contains(".") && - !m_directory.GetStringRef().contains("//") && - m_filename.GetStringRef() != ".." && m_filename.GetStringRef() != ".") - return *this; - - llvm::SmallString<64> path, result; - const bool normalize = false; - GetPath(path, normalize); - llvm::StringRef rest(path); - - // We will not go below root dir. - size_t root_dir_start = RootDirStart(path, m_syntax); - const bool absolute = root_dir_start != llvm::StringRef::npos; - if (absolute) { - result += rest.take_front(root_dir_start + 1); - rest = rest.drop_front(root_dir_start + 1); - } else { - if (m_syntax == ePathSyntaxWindows && path.size() > 2 && path[1] == ':') { - result += rest.take_front(2); - rest = rest.drop_front(2); - } - } - - bool anything_added = false; - llvm::SmallVector<llvm::StringRef, 0> components, processed; - rest.split(components, '/', -1, false); - processed.reserve(components.size()); - for (auto component : components) { - if (component == ".") - continue; // Skip these. - if (component != "..") { - processed.push_back(component); - continue; // Regular file name. - } - if (!processed.empty()) { - processed.pop_back(); - continue; // Dots. Go one level up if we can. - } - if (absolute) - continue; // We're at the top level. Cannot go higher than that. Skip. - - result += component; // We're a relative path. We need to keep these. - result += '/'; - anything_added = true; - } - for (auto component : processed) { - result += component; - result += '/'; - anything_added = true; - } - if (anything_added) - result.pop_back(); // Pop last '/'. - else if (result.empty()) - result = "."; - - return FileSpec(result, false, m_syntax); -} - -//------------------------------------------------------------------ -// Dump the object to the supplied stream. If the object contains -// a valid directory name, it will be displayed followed by a -// directory delimiter, and the filename. -//------------------------------------------------------------------ -void FileSpec::Dump(Stream *s) const { - if (s) { - std::string path{GetPath(true)}; - s->PutCString(path); - char path_separator = GetPreferredPathSeparator(m_syntax); - if (!m_filename && !path.empty() && path.back() != path_separator) - s->PutChar(path_separator); - } -} - -//------------------------------------------------------------------ -// Returns true if the file exists. -//------------------------------------------------------------------ -bool FileSpec::Exists() const { - struct stat file_stats; - return GetFileStats(this, &file_stats); -} - -bool FileSpec::Readable() const { - const uint32_t permissions = GetPermissions(); - if (permissions & eFilePermissionsEveryoneR) - return true; - return false; -} - -bool FileSpec::ResolveExecutableLocation() { - // CLEANUP: Use StringRef for string handling. - if (!m_directory) { - const char *file_cstr = m_filename.GetCString(); - if (file_cstr) { - const std::string file_str(file_cstr); - llvm::ErrorOr<std::string> error_or_path = - llvm::sys::findProgramByName(file_str); - if (!error_or_path) - return false; - std::string path = error_or_path.get(); - llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - if (!dir_ref.empty()) { - // FindProgramByName returns "." if it can't find the file. - if (strcmp(".", dir_ref.data()) == 0) - return false; - - m_directory.SetCString(dir_ref.data()); - if (Exists()) - return true; - else { - // If FindProgramByName found the file, it returns the directory + - // filename in its return results. - // We need to separate them. - FileSpec tmp_file(dir_ref.data(), false); - if (tmp_file.Exists()) { - m_directory = tmp_file.m_directory; - return true; - } - } - } - } - } - - return false; -} - -bool FileSpec::ResolvePath() { - if (m_is_resolved) - return true; // We have already resolved this path - - char path_buf[PATH_MAX]; - if (!GetPath(path_buf, PATH_MAX, false)) - return false; - // SetFile(...) will set m_is_resolved correctly if it can resolve the path - SetFile(path_buf, true); - return m_is_resolved; -} - -uint64_t FileSpec::GetByteSize() const { - struct stat file_stats; - if (GetFileStats(this, &file_stats)) - return file_stats.st_size; - return 0; -} - -FileSpec::PathSyntax FileSpec::GetPathSyntax() const { return m_syntax; } - -FileSpec::FileType FileSpec::GetFileType() const { - struct stat file_stats; - if (GetFileStats(this, &file_stats)) { - mode_t file_type = file_stats.st_mode & S_IFMT; - switch (file_type) { - case S_IFDIR: - return eFileTypeDirectory; - case S_IFREG: - return eFileTypeRegular; -#ifndef _WIN32 - case S_IFIFO: - return eFileTypePipe; - case S_IFSOCK: - return eFileTypeSocket; - case S_IFLNK: - return eFileTypeSymbolicLink; -#endif - default: - break; - } - return eFileTypeUnknown; - } - return eFileTypeInvalid; -} - -bool FileSpec::IsSymbolicLink() const { - char resolved_path[PATH_MAX]; - if (!GetPath(resolved_path, sizeof(resolved_path))) - return false; - -#ifdef _WIN32 - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) - return false; - auto attrs = ::GetFileAttributesW(wpath.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) - return false; - - return (attrs & FILE_ATTRIBUTE_REPARSE_POINT); -#else - struct stat file_stats; - if (::lstat(resolved_path, &file_stats) != 0) - return false; - - return (file_stats.st_mode & S_IFMT) == S_IFLNK; -#endif -} - -uint32_t FileSpec::GetPermissions() const { - uint32_t file_permissions = 0; - if (*this) - FileSystem::GetFilePermissions(*this, file_permissions); - return file_permissions; -} - -//------------------------------------------------------------------ -// Directory string get accessor. -//------------------------------------------------------------------ -ConstString &FileSpec::GetDirectory() { return m_directory; } - -//------------------------------------------------------------------ -// Directory string const get accessor. -//------------------------------------------------------------------ -const ConstString &FileSpec::GetDirectory() const { return m_directory; } - -//------------------------------------------------------------------ -// Filename string get accessor. -//------------------------------------------------------------------ -ConstString &FileSpec::GetFilename() { return m_filename; } - -//------------------------------------------------------------------ -// Filename string const get accessor. -//------------------------------------------------------------------ -const ConstString &FileSpec::GetFilename() const { return m_filename; } - -//------------------------------------------------------------------ -// Extract the directory and path into a fixed buffer. This is -// needed as the directory and path are stored in separate string -// values. -//------------------------------------------------------------------ -size_t FileSpec::GetPath(char *path, size_t path_max_len, - bool denormalize) const { - if (!path) - return 0; - - std::string result = GetPath(denormalize); - ::snprintf(path, path_max_len, "%s", result.c_str()); - return std::min(path_max_len - 1, result.length()); -} - -std::string FileSpec::GetPath(bool denormalize) const { - llvm::SmallString<64> result; - GetPath(result, denormalize); - return std::string(result.begin(), result.end()); -} - -const char *FileSpec::GetCString(bool denormalize) const { - return ConstString{GetPath(denormalize)}.AsCString(NULL); -} - -void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, - bool denormalize) const { - path.append(m_directory.GetStringRef().begin(), - m_directory.GetStringRef().end()); - if (m_directory && m_filename && - !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - path.insert(path.end(), GetPreferredPathSeparator(m_syntax)); - path.append(m_filename.GetStringRef().begin(), - m_filename.GetStringRef().end()); - Normalize(path, m_syntax); - if (denormalize && !path.empty()) - Denormalize(path, m_syntax); -} - -ConstString FileSpec::GetFileNameExtension() const { - if (m_filename) { - const char *filename = m_filename.GetCString(); - const char *dot_pos = strrchr(filename, '.'); - if (dot_pos && dot_pos[1] != '\0') - return ConstString(dot_pos + 1); - } - return ConstString(); -} - -ConstString FileSpec::GetFileNameStrippingExtension() const { - const char *filename = m_filename.GetCString(); - if (filename == NULL) - return ConstString(); - - const char *dot_pos = strrchr(filename, '.'); - if (dot_pos == NULL) - return m_filename; - - return ConstString(filename, dot_pos - filename); -} - -//------------------------------------------------------------------ -// Returns a shared pointer to a data buffer that contains all or -// part of the contents of a file. The data is memory mapped and -// will lazily page in data from the file as memory is accessed. -// The data that is mapped will start "file_offset" bytes into the -// file, and "file_size" bytes will be mapped. If "file_size" is -// greater than the number of bytes available in the file starting -// at "file_offset", the number of bytes will be appropriately -// truncated. The final number of bytes that get mapped can be -// verified using the DataBuffer::GetByteSize() function. -//------------------------------------------------------------------ -DataBufferSP FileSpec::MemoryMapFileContents(off_t file_offset, - size_t file_size) const { - DataBufferSP data_sp; - std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); - if (mmap_data.get()) { - const size_t mapped_length = - mmap_data->MemoryMapFromFileSpec(this, file_offset, file_size); - if (((file_size == SIZE_MAX) && (mapped_length > 0)) || - (mapped_length >= file_size)) - data_sp.reset(mmap_data.release()); - } - return data_sp; -} - -DataBufferSP FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, - size_t file_size) const { - if (FileSystem::IsLocal(*this)) - return MemoryMapFileContents(file_offset, file_size); - else - return ReadFileContents(file_offset, file_size, NULL); -} - -//------------------------------------------------------------------ -// Return the size in bytes that this object takes in memory. This -// returns the size in bytes of this object, not any shared string -// values it may refer to. -//------------------------------------------------------------------ -size_t FileSpec::MemorySize() const { - return m_filename.MemorySize() + m_directory.MemorySize(); -} - -size_t FileSpec::ReadFileContents(off_t file_offset, void *dst, size_t dst_len, - Error *error_ptr) const { - Error error; - size_t bytes_read = 0; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) { - off_t file_offset_after_seek = file_offset; - bytes_read = dst_len; - error = file.Read(dst, bytes_read, file_offset_after_seek); - } - } else { - error.SetErrorString("invalid file specification"); - } - if (error_ptr) - *error_ptr = error; - return bytes_read; -} - -//------------------------------------------------------------------ -// Returns a shared pointer to a data buffer that contains all or -// part of the contents of a file. The data copies into a heap based -// buffer that lives in the DataBuffer shared pointer object returned. -// The data that is cached will start "file_offset" bytes into the -// file, and "file_size" bytes will be mapped. If "file_size" is -// greater than the number of bytes available in the file starting -// at "file_offset", the number of bytes will be appropriately -// truncated. The final number of bytes that get mapped can be -// verified using the DataBuffer::GetByteSize() function. -//------------------------------------------------------------------ -DataBufferSP FileSpec::ReadFileContents(off_t file_offset, size_t file_size, - Error *error_ptr) const { - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) { - const bool null_terminate = false; - error = file.Read(file_size, file_offset, null_terminate, data_sp); - } - } else { - error.SetErrorString("invalid file specification"); - } - if (error_ptr) - *error_ptr = error; - return data_sp; -} - -DataBufferSP FileSpec::ReadFileContentsAsCString(Error *error_ptr) { - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) { - off_t offset = 0; - size_t length = SIZE_MAX; - const bool null_terminate = true; - error = file.Read(length, offset, null_terminate, data_sp); - } - } else { - error.SetErrorString("invalid file specification"); - } - if (error_ptr) - *error_ptr = error; - return data_sp; -} - -size_t FileSpec::ReadFileLines(STLStringArray &lines) { - lines.clear(); - char path[PATH_MAX]; - if (GetPath(path, sizeof(path))) { - std::ifstream file_stream(path); - - if (file_stream) { - std::string line; - while (getline(file_stream, line)) - lines.push_back(line); - } - } - return lines.size(); -} - -FileSpec::EnumerateDirectoryResult -FileSpec::ForEachItemInDirectory(llvm::StringRef dir_path, - DirectoryCallback const &callback) { - if (dir_path.empty()) - return eEnumerateDirectoryResultNext; - -#ifdef _WIN32 - std::string szDir(dir_path); - szDir += "\\*"; - - std::wstring wszDir; - if (!llvm::ConvertUTF8toWide(szDir, wszDir)) { - return eEnumerateDirectoryResultNext; - } - - WIN32_FIND_DATAW ffd; - HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd); - - if (hFind == INVALID_HANDLE_VALUE) { - return eEnumerateDirectoryResultNext; - } - - do { - FileSpec::FileType file_type = eFileTypeUnknown; - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - size_t len = wcslen(ffd.cFileName); - - if (len == 1 && ffd.cFileName[0] == L'.') - continue; - - if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') - continue; - - file_type = eFileTypeDirectory; - } else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { - file_type = eFileTypeOther; - } else { - file_type = eFileTypeRegular; - } - - std::string fileName; - if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) { - continue; - } - - std::string child_path = llvm::join_items("\\", dir_path, fileName); - // Don't resolve the file type or path - FileSpec child_path_spec(child_path.data(), false); - - EnumerateDirectoryResult result = callback(file_type, child_path_spec); - - switch (result) { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry - // if it is a directory or symlink, - // or next if not - if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == - eEnumerateDirectoryResultQuit) { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory - // at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at - // any level - return eEnumerateDirectoryResultQuit; - } - } while (FindNextFileW(hFind, &ffd) != 0); - - FindClose(hFind); -#else - std::string dir_string(dir_path); - lldb_utility::CleanUp<DIR *, int> dir_path_dir(opendir(dir_string.c_str()), - NULL, closedir); - if (dir_path_dir.is_valid()) { - char dir_path_last_char = dir_path.back(); - - long path_max = fpathconf(dirfd(dir_path_dir.get()), _PC_NAME_MAX); -#if defined(__APPLE_) && defined(__DARWIN_MAXPATHLEN) - if (path_max < __DARWIN_MAXPATHLEN) - path_max = __DARWIN_MAXPATHLEN; -#endif - struct dirent *buf, *dp; - buf = (struct dirent *)malloc(offsetof(struct dirent, d_name) + path_max + - 1); - - while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) { - // Only search directories - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { - size_t len = strlen(dp->d_name); - - if (len == 1 && dp->d_name[0] == '.') - continue; - - if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') - continue; - } - - FileSpec::FileType file_type = eFileTypeUnknown; - - switch (dp->d_type) { - default: - case DT_UNKNOWN: - file_type = eFileTypeUnknown; - break; - case DT_FIFO: - file_type = eFileTypePipe; - break; - case DT_CHR: - file_type = eFileTypeOther; - break; - case DT_DIR: - file_type = eFileTypeDirectory; - break; - case DT_BLK: - file_type = eFileTypeOther; - break; - case DT_REG: - file_type = eFileTypeRegular; - break; - case DT_LNK: - file_type = eFileTypeSymbolicLink; - break; - case DT_SOCK: - file_type = eFileTypeSocket; - break; -#if !defined(__OpenBSD__) - case DT_WHT: - file_type = eFileTypeOther; - break; -#endif - } - - std::string child_path; - // Don't make paths with "/foo//bar", that just confuses everybody. - if (dir_path_last_char == '/') - child_path = llvm::join_items("", dir_path, dp->d_name); - else - child_path = llvm::join_items('/', dir_path, dp->d_name); - - // Don't resolve the file type or path - FileSpec child_path_spec(child_path, false); - - EnumerateDirectoryResult result = - callback(file_type, child_path_spec); - - switch (result) { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry - // if it is a directory or - // symlink, or next if not - if (FileSpec::ForEachItemInDirectory(child_path, callback) == - eEnumerateDirectoryResultQuit) { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - if (buf) - free(buf); - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory - // at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - if (buf) - free(buf); - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at - // any level - if (buf) - free(buf); - return eEnumerateDirectoryResultQuit; - } - } - if (buf) { - free(buf); - } - } -#endif - // By default when exiting a directory, we tell the parent enumeration - // to continue enumerating. - return eEnumerateDirectoryResultNext; -} - -FileSpec::EnumerateDirectoryResult -FileSpec::EnumerateDirectory(llvm::StringRef dir_path, bool find_directories, - bool find_files, bool find_other, - EnumerateDirectoryCallbackType callback, - void *callback_baton) { - return ForEachItemInDirectory( - dir_path, - [&find_directories, &find_files, &find_other, &callback, - &callback_baton](FileType file_type, const FileSpec &file_spec) { - switch (file_type) { - case FileType::eFileTypeDirectory: - if (find_directories) - return callback(callback_baton, file_type, file_spec); - break; - case FileType::eFileTypeRegular: - if (find_files) - return callback(callback_baton, file_type, file_spec); - break; - default: - if (find_other) - return callback(callback_baton, file_type, file_spec); - break; - } - return eEnumerateDirectoryResultNext; - }); -} - -FileSpec -FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const { - FileSpec ret = *this; - ret.AppendPathComponent(component); - return ret; -} - -FileSpec FileSpec::CopyByRemovingLastPathComponent() const { - // CLEANUP: Use StringRef for string handling. - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return FileSpec("", resolve); - if (m_directory.IsEmpty()) - return FileSpec("", resolve); - if (m_filename.IsEmpty()) { - const char *dir_cstr = m_directory.GetCString(); - const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) - return FileSpec("", resolve); - if (last_slash_ptr == dir_cstr) - return FileSpec("/", resolve); - - size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; - ConstString new_path(dir_cstr, last_slash_pos); - return FileSpec(new_path.GetCString(), resolve); - } else - return FileSpec(m_directory.GetCString(), resolve); -} - -ConstString FileSpec::GetLastPathComponent() const { - // CLEANUP: Use StringRef for string handling. - if (m_filename) - return m_filename; - if (m_directory) { - const char *dir_cstr = m_directory.GetCString(); - const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); - if (last_slash_ptr == NULL) - return m_directory; - if (last_slash_ptr == dir_cstr) { - if (last_slash_ptr[1] == 0) - return ConstString(last_slash_ptr); - else - return ConstString(last_slash_ptr + 1); - } - if (last_slash_ptr[1] != 0) - return ConstString(last_slash_ptr + 1); - const char *penultimate_slash_ptr = last_slash_ptr; - while (*penultimate_slash_ptr) { - --penultimate_slash_ptr; - if (penultimate_slash_ptr == dir_cstr) - break; - if (*penultimate_slash_ptr == '/') - break; - } - ConstString result(penultimate_slash_ptr + 1, - last_slash_ptr - penultimate_slash_ptr); - return result; - } - return ConstString(); -} - -void FileSpec::PrependPathComponent(llvm::StringRef component) { - if (component.empty()) - return; - - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) { - SetFile(component, resolve); - return; - } - - char sep = GetPreferredPathSeparator(m_syntax); - std::string result; - if (m_filename.IsEmpty()) - result = llvm::join_items(sep, component, m_directory.GetStringRef()); - else if (m_directory.IsEmpty()) - result = llvm::join_items(sep, component, m_filename.GetStringRef()); - else - result = llvm::join_items(sep, component, m_directory.GetStringRef(), - m_filename.GetStringRef()); - - SetFile(result, resolve); -} - -void FileSpec::PrependPathComponent(const FileSpec &new_path) { - return PrependPathComponent(new_path.GetPath(false)); -} - -void FileSpec::AppendPathComponent(llvm::StringRef component) { - if (component.empty()) - return; - - std::string result; - if (!m_directory.IsEmpty()) { - result += m_directory.GetStringRef(); - if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - result += GetPreferredPathSeparator(m_syntax); - } - - if (!m_filename.IsEmpty()) { - result += m_filename.GetStringRef(); - if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) - result += GetPreferredPathSeparator(m_syntax); - } - - component = component.drop_while( - [this](char c) { return IsPathSeparator(c, m_syntax); }); - - result += component; - - SetFile(result, false, m_syntax); -} - -void FileSpec::AppendPathComponent(const FileSpec &new_path) { - return AppendPathComponent(new_path.GetPath(false)); -} - -void FileSpec::RemoveLastPathComponent() { - // CLEANUP: Use StringRef for string handling. - - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) { - SetFile("", resolve); - return; - } - if (m_directory.IsEmpty()) { - SetFile("", resolve); - return; - } - if (m_filename.IsEmpty()) { - const char *dir_cstr = m_directory.GetCString(); - const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) { - SetFile("", resolve); - return; - } - if (last_slash_ptr == dir_cstr) { - SetFile("/", resolve); - return; - } - size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; - ConstString new_path(dir_cstr, last_slash_pos); - SetFile(new_path.GetCString(), resolve); - } else - SetFile(m_directory.GetCString(), resolve); -} -//------------------------------------------------------------------ -/// Returns true if the filespec represents an implementation source -/// file (files with a ".c", ".cpp", ".m", ".mm" (many more) -/// extension). -/// -/// @return -/// \b true if the filespec represents an implementation source -/// file, \b false otherwise. -//------------------------------------------------------------------ -bool FileSpec::IsSourceImplementationFile() const { - ConstString extension(GetFileNameExtension()); - if (!extension) - return false; - - static RegularExpression g_source_file_regex(llvm::StringRef( - "^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[" - "cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][" - "rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])" - "$")); - return g_source_file_regex.Execute(extension.GetStringRef()); -} - -bool FileSpec::IsRelative() const { - const char *dir = m_directory.GetCString(); - llvm::StringRef directory(dir ? dir : ""); - - if (directory.size() > 0) { - if (PathSyntaxIsPosix(m_syntax)) { - // If the path doesn't start with '/' or '~', return true - switch (directory[0]) { - case '/': - case '~': - return false; - default: - return true; - } - } else { - if (directory.size() >= 2 && directory[1] == ':') - return false; - if (directory[0] == '/') - return false; - return true; - } - } else if (m_filename) { - // No directory, just a basename, return true - return true; - } - return false; -} - -bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); } - -void llvm::format_provider<FileSpec>::format(const FileSpec &F, - raw_ostream &Stream, - StringRef Style) { - assert( - (Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) && - "Invalid FileSpec style!"); - - StringRef dir = F.GetDirectory().GetStringRef(); - StringRef file = F.GetFilename().GetStringRef(); - - if (dir.empty() && file.empty()) { - Stream << "(empty)"; - return; - } - - if (Style.equals_lower("F")) { - Stream << (file.empty() ? "(empty)" : file); - return; - } - - // Style is either D or empty, either way we need to print the directory. - if (!dir.empty()) { - // Directory is stored in normalized form, which might be different - // than preferred form. In order to handle this, we need to cut off - // the filename, then denormalize, then write the entire denorm'ed - // directory. - llvm::SmallString<64> denormalized_dir = dir; - Denormalize(denormalized_dir, F.GetPathSyntax()); - Stream << denormalized_dir; - Stream << GetPreferredPathSeparator(F.GetPathSyntax()); - } - - if (Style.equals_lower("D")) { - // We only want to print the directory, so now just exit. - if (dir.empty()) - Stream << "(empty)"; - return; - } - - if (!file.empty()) - Stream << file; -} diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp index 88f29b46f360..4472aece1daa 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp @@ -10,7 +10,6 @@ #include "lldb/Host/FileSystem.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/MD5.h" #include <algorithm> #include <fstream> @@ -19,79 +18,6 @@ using namespace lldb; using namespace lldb_private; -namespace { - -bool CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, - llvm::MD5::MD5Result &md5_result) { - llvm::MD5 md5_hash; - std::ifstream file(file_spec.GetPath(), std::ios::binary); - if (!file.is_open()) - return false; - - if (offset > 0) - file.seekg(offset, file.beg); - - std::vector<char> read_buf(4096); - uint64_t total_read_bytes = 0; - while (!file.eof()) { - const uint64_t to_read = - (length > 0) ? std::min(static_cast<uint64_t>(read_buf.size()), - length - total_read_bytes) - : read_buf.size(); - if (to_read == 0) - break; - - file.read(&read_buf[0], to_read); - const auto read_bytes = file.gcount(); - if (read_bytes == 0) - break; - - md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes)); - total_read_bytes += read_bytes; - } - - md5_hash.final(md5_result); - return true; -} - -} // namespace - -bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, - uint64_t &high) { - return CalculateMD5(file_spec, 0, 0, low, high); -} - -bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t offset, - uint64_t length, uint64_t &low, uint64_t &high) { - llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, offset, length, md5_result)) - return false; - - const auto uint64_res = reinterpret_cast<const uint64_t *>(md5_result); - high = uint64_res[0]; - low = uint64_res[1]; - - return true; -} - -bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec, - std::string &digest_str) { - return CalculateMD5AsString(file_spec, 0, 0, digest_str); -} - -bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec, - uint64_t offset, uint64_t length, - std::string &digest_str) { - llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, offset, length, md5_result)) - return false; - - llvm::SmallString<32> result_str; - llvm::MD5::stringifyResult(md5_result, result_str); - digest_str = result_str.c_str(); - return true; -} - llvm::sys::TimePoint<> FileSystem::GetModificationTime(const FileSpec &file_spec) { llvm::sys::fs::file_status status; diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp index 6d0ad0175fd8..7754d96ad331 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp @@ -28,7 +28,8 @@ #endif #if defined(__linux__) || defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) + defined(__FreeBSD_kernel__) || defined(__APPLE__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) #if !defined(__ANDROID__) #include <spawn.h> #endif @@ -40,16 +41,16 @@ #include <pthread_np.h> #endif +#if defined(__NetBSD__) +#include <lwp.h> +#endif + // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostProcess.h" @@ -61,14 +62,18 @@ #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/CleanUp.h" +#include "lldb/Utility/DataBufferLLVM.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" #include "lldb/lldb-private-forward.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" -#elif defined(__linux__) -#include "lldb/Host/linux/ProcessLauncherLinux.h" +#elif defined(__linux__) || defined(__NetBSD__) +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" #else #include "lldb/Host/posix/ProcessLauncherPosix.h" #endif @@ -180,7 +185,7 @@ static thread_result_t MonitorChildProcessThreadFunction(void *arg) { delete info; int status = -1; -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #define __WALL 0 #endif const int options = __WALL; @@ -310,25 +315,6 @@ lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); } #ifndef _WIN32 -lldb::tid_t Host::GetCurrentThreadID() { -#if defined(__APPLE__) - // Calling "mach_thread_self()" bumps the reference count on the thread - // port, so we need to deallocate it. mach_task_self() doesn't bump the ref - // count. - thread_port_t thread_self = mach_thread_self(); - mach_port_deallocate(mach_task_self(), thread_self); - return thread_self; -#elif defined(__FreeBSD__) - return lldb::tid_t(pthread_getthreadid_np()); -#elif defined(__ANDROID__) - return lldb::tid_t(gettid()); -#elif defined(__linux__) - return lldb::tid_t(syscall(SYS_gettid)); -#else - return lldb::tid_t(pthread_self()); -#endif -} - lldb::thread_t Host::GetCurrentThread() { return lldb::thread_t(pthread_self()); } @@ -601,23 +587,22 @@ Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir, error.SetErrorStringWithFormat( "shell command output is too large to fit into a std::string"); } else { - std::vector<char> command_output(file_size); - output_file_spec.ReadFileContents(0, command_output.data(), - file_size, &error); + auto Buffer = + DataBufferLLVM::CreateFromPath(output_file_spec.GetPath()); if (error.Success()) - command_output_ptr->assign(command_output.data(), file_size); + command_output_ptr->assign(Buffer->GetChars(), + Buffer->GetByteSize()); } } } } } - if (FileSystem::GetFileExists(output_file_spec)) - FileSystem::Unlink(output_file_spec); + llvm::sys::fs::remove(output_file_spec.GetPath()); return error; } -// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC +// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD, NetBSD and other GLIBC // systems #if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \ @@ -679,10 +664,10 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, posix_spawnattr_t attr; error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_init ( &attr )"); - if (error.Fail()) + if (error.Fail()) { + LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error); return error; + } // Make a quick class that will cleanup the posix spawn attributes in case // we return in the middle of this function. @@ -694,7 +679,7 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, sigemptyset(&no_signals); sigfillset(&all_signals); ::posix_spawnattr_setsigmask(&attr, &no_signals); -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) ::posix_spawnattr_setsigdefault(&attr, &no_signals); #else ::posix_spawnattr_setsigdefault(&attr, &all_signals); @@ -703,11 +688,12 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, short flags = GetPosixspawnFlags(launch_info); error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", - flags); - if (error.Fail()) + if (error.Fail()) { + LLDB_LOG(log, + "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )", + error, flags); return error; + } // posix_spawnattr_setbinpref_np appears to be an Apple extension per: // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ @@ -734,10 +720,10 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, size_t ocount = 0; error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, " - "cpu_type = 0x%8.8x, count => %llu )", - cpu, (uint64_t)ocount); + if (error.Fail()) + LLDB_LOG(log, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " + "cpu_type = {1:x}, count => {2} )", + error, cpu, ocount); if (error.Fail() || ocount != 1) return error; @@ -788,14 +774,14 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, #else if (::getcwd(current_dir, sizeof(current_dir)) == NULL) { error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to save the current directory"); + LLDB_LOG(log, "error: {0}, unable to save the current directory", error); return error; } if (::chdir(working_dir.GetCString()) == -1) { error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to change working directory to %s", - working_dir.GetCString()); + LLDB_LOG(log, "error: {0}, unable to change working directory to {1}", + error, working_dir); return error; } #endif @@ -807,10 +793,12 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, posix_spawn_file_actions_t file_actions; error.SetError(::posix_spawn_file_actions_init(&file_actions), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )"); - if (error.Fail()) + if (error.Fail()) { + LLDB_LOG(log, + "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )", + error); return error; + } // Make a quick class that will cleanup the posix spawn attributes in case // we return in the middle of this function. @@ -832,16 +820,14 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX); - if (error.Fail() || log) { - error.PutToLog( - log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, " - "attr = %p, argv = %p, envp = %p )", - result_pid, exe_path, static_cast<void *>(&file_actions), - static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), - reinterpret_cast<const void *>(envp)); + if (error.Fail()) { + LLDB_LOG(log, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " + "file_actions = {3}, " + "attr = {4}, argv = {5}, envp = {6} )", + error, result_pid, exe_path, &file_actions, &attr, argv, envp); if (log) { for (int ii = 0; argv[ii]; ++ii) - log->Printf("argv[%i] = '%s'", ii, argv[ii]); + LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); } } @@ -850,16 +836,13 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX); - if (error.Fail() || log) { - error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', " - "file_actions = NULL, attr = %p, argv = %p, envp = " - "%p )", - result_pid, exe_path, static_cast<void *>(&attr), - reinterpret_cast<const void *>(argv), - reinterpret_cast<const void *>(envp)); + if (error.Fail()) { + LLDB_LOG(log, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " + "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", + error, result_pid, exe_path, &attr, argv, envp); if (log) { for (int ii = 0; argv[ii]; ++ii) - log->Printf("argv[%i] = '%s'", ii, argv[ii]); + LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); } } } @@ -872,8 +855,9 @@ Error Host::LaunchProcessPosixSpawn(const char *exe_path, #else if (::chdir(current_dir) == -1 && error.Success()) { error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to change current directory back to %s", - current_dir); + LLDB_LOG(log, + "error: {0}, unable to change current directory back to {1}", + error, current_dir); } #endif } @@ -902,10 +886,10 @@ bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, error.SetError( ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX); - if (log && (error.Fail() || log)) - error.PutToLog(log, - "posix_spawn_file_actions_addclose (action=%p, fd=%i)", - static_cast<void *>(file_actions), info->GetFD()); + if (error.Fail()) + LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_addclose " + "(action={1}, fd={2})", + error, file_actions, info->GetFD()); } break; @@ -921,12 +905,10 @@ bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()), eErrorTypePOSIX); - if (log && (error.Fail() || log)) - error.PutToLog( - log, - "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)", - static_cast<void *>(file_actions), info->GetFD(), - info->GetActionArgument()); + if (error.Fail()) + LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_adddup2 " + "(action={1}, fd={2}, dup_fd={3})", + error, file_actions, info->GetFD(), info->GetActionArgument()); } break; @@ -946,11 +928,11 @@ bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, file_actions, info->GetFD(), info->GetPath().str().c_str(), oflag, mode), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "posix_spawn_file_actions_addopen (action=%p, " - "fd=%i, path='%s', oflag=%i, mode=%i)", - static_cast<void *>(file_actions), info->GetFD(), - info->GetPath().str().c_str(), oflag, mode); + if (error.Fail()) + LLDB_LOG( + log, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " + "fd={2}, path='{3}', oflag={4}, mode={5})", + error, file_actions, info->GetFD(), info->GetPath(), oflag, mode); } break; } @@ -969,8 +951,8 @@ Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) { std::unique_ptr<ProcessLauncher> delegate_launcher; #if defined(_WIN32) delegate_launcher.reset(new ProcessLauncherWindows()); -#elif defined(__linux__) - delegate_launcher.reset(new ProcessLauncherLinux()); +#elif defined(__linux__) || defined(__NetBSD__) + delegate_launcher.reset(new ProcessLauncherPosixFork()); #else delegate_launcher.reset(new ProcessLauncherPosix()); #endif diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp index 01ac87047c5d..a6c9e91a98e8 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp @@ -10,21 +10,22 @@ #include "lldb/Host/Config.h" #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/StreamString.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostInfoBase.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" -#include <mutex> // std::once +#include <mutex> #include <thread> using namespace lldb; @@ -45,13 +46,10 @@ struct HostInfoBaseFields { // Remove the LLDB temporary directory if we have one. Set "recurse" to // true to all files that were created for the LLDB process can be cleaned // up. - FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true); + llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath()); } } - uint32_t m_number_cpus; - std::string m_vendor_string; - std::string m_os_string; std::string m_host_triple; ArchSpec m_host_arch_32; @@ -78,37 +76,9 @@ void HostInfoBase::Terminate() { g_fields = nullptr; } -uint32_t HostInfoBase::GetNumberCPUS() { - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_number_cpus = std::thread::hardware_concurrency(); - }); - return g_fields->m_number_cpus; -} - -uint32_t HostInfoBase::GetMaxThreadNameLength() { return 0; } - -llvm::StringRef HostInfoBase::GetVendorString() { - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_vendor_string = - HostInfo::GetArchitecture().GetTriple().getVendorName().str(); - }); - return g_fields->m_vendor_string; -} - -llvm::StringRef HostInfoBase::GetOSString() { - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_os_string = - std::move(HostInfo::GetArchitecture().GetTriple().getOSName()); - }); - return g_fields->m_os_string; -} - llvm::StringRef HostInfoBase::GetTargetTriple() { - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple(); }); @@ -116,8 +86,8 @@ llvm::StringRef HostInfoBase::GetTargetTriple() { } const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); }); @@ -144,9 +114,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { FileSpec *result = nullptr; switch (type) { case lldb::ePathTypeLLDBShlibDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -158,9 +128,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_so_dir; } break; case lldb::ePathTypeSupportExecutableDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeSupportExeDirectory( g_fields->m_lldb_support_exe_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -173,9 +143,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_support_exe_dir; } break; case lldb::ePathTypeHeaderDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) @@ -186,9 +156,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_headers_dir; } break; case lldb::ePathTypePythonDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) @@ -199,9 +169,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_python_dir; } break; case lldb::ePathTypeClangDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -214,9 +184,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_clang_resource_dir; } break; case lldb::ePathTypeLLDBSystemPlugins: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeSystemPluginsDirectory( g_fields->m_lldb_system_plugin_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -229,9 +199,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_system_plugin_dir; } break; case lldb::ePathTypeLLDBUserPlugins: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeUserPluginsDirectory( g_fields->m_lldb_user_plugin_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -244,9 +214,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_user_plugin_dir; } break; case lldb::ePathTypeLLDBTempSystemDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeProcessTempFileDirectory( g_fields->m_lldb_process_tmp_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -259,9 +229,9 @@ bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { result = &g_fields->m_lldb_process_tmp_dir; } break; case lldb::ePathTypeGlobalLLDBTempSystemDir: { - static std::once_flag g_once_flag; + static llvm::once_flag g_once_flag; static bool success = false; - std::call_once(g_once_flag, []() { + llvm::call_once(g_once_flag, []() { success = HostInfo::ComputeGlobalTempFileDirectory( g_fields->m_lldb_global_tmp_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); @@ -313,9 +283,7 @@ bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; temp_file_spec.AppendPathComponent(pid_str); - if (!FileSystem::MakeDirectory(temp_file_spec, - eFilePermissionsDirectoryDefault) - .Success()) + if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) return false; file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); @@ -337,9 +305,7 @@ bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { return false; temp_file_spec.AppendPathComponent("lldb"); - if (!FileSystem::MakeDirectory(temp_file_spec, - eFilePermissionsDirectoryDefault) - .Success()) + if (llvm::sys::fs::create_directory(temp_file_spec.GetPath())) return false; file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp index fd39e0d1e2fe..402d3caacfcb 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp @@ -8,11 +8,12 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/HostNativeThreadBase.h" -#include "lldb/Core/Log.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Host/ThisThread.h" #include "lldb/Host/ThreadLauncher.h" +#include "lldb/Utility/Log.h" + #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Threading.h" using namespace lldb; using namespace lldb_private; @@ -52,7 +53,7 @@ lldb::thread_result_t HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg) { ThreadLauncher::HostThreadCreateInfo *info = (ThreadLauncher::HostThreadCreateInfo *)arg; - ThisThread::SetName(info->thread_name, HostInfo::GetMaxThreadNameLength()); + llvm::set_thread_name(info->thread_name); thread_func_t thread_fptr = info->thread_fptr; thread_arg_t thread_arg = info->thread_arg; diff --git a/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp index ae98cc83379d..2aa6c7f50b66 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp @@ -8,14 +8,16 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/MonitoringProcessLauncher.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostProcess.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/FileSystem.h" using namespace lldb; using namespace lldb_private; @@ -38,8 +40,9 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, FileSpec exe_spec(resolved_info.GetExecutableFile()); - FileSpec::FileType file_type = exe_spec.GetFileType(); - if (file_type != FileSpec::eFileTypeRegular) { + llvm::sys::fs::file_status stats; + status(exe_spec.GetPath(), stats); + if (!is_regular_file(stats)) { ModuleSpec module_spec(exe_spec, arch_spec); lldb::ModuleSP exe_module_sp; error = @@ -48,11 +51,13 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, if (error.Fail()) return HostProcess(); - if (exe_module_sp) + if (exe_module_sp) { exe_spec = exe_module_sp->GetFileSpec(); + status(exe_spec.GetPath(), stats); + } } - if (exe_spec.Exists()) { + if (exists(stats)) { exe_spec.GetPath(exe_path, sizeof(exe_path)); } else { resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp index d61a2f531ac3..8a3ee72179c3 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp @@ -9,8 +9,8 @@ #include "lldb/Host/common/NativeBreakpoint.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Log.h" #include "lldb/lldb-defines.h" using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp index df5bce8079e0..60608a0bbc55 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp @@ -9,7 +9,7 @@ #include "lldb/Host/common/NativeBreakpointList.h" -#include "lldb/Core/Log.h" +#include "lldb/Utility/Log.h" #include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/SoftwareBreakpoint.h" diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp index d77b8b2e9746..9d4149d700ba 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -10,7 +10,6 @@ #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" @@ -20,6 +19,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" #include "lldb/lldb-enumerations.h" using namespace lldb; @@ -46,6 +46,12 @@ lldb_private::Error NativeProcessProtocol::Interrupt() { #endif } +Error NativeProcessProtocol::IgnoreSignals(llvm::ArrayRef<int> signals) { + m_signals_to_ignore.clear(); + m_signals_to_ignore.insert(signals.begin(), signals.end()); + return Error(); +} + lldb_private::Error NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo &range_info) { @@ -139,11 +145,8 @@ NativeProcessProtocol::GetWatchpointMap() const { return m_watchpoint_list.GetWatchpointMap(); } -uint32_t NativeProcessProtocol::GetMaxWatchpoints() const { - // This default implementation will return the number of - // *hardware* breakpoints available. MacOSX and other OS - // implementations that support software breakpoints will want to - // override this correctly for their implementation. +llvm::Optional<std::pair<uint32_t, uint32_t>> +NativeProcessProtocol::GetHardwareDebugSupportInfo() const { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); // get any thread @@ -154,7 +157,7 @@ uint32_t NativeProcessProtocol::GetMaxWatchpoints() const { log->Warning("NativeProcessProtocol::%s (): failed to find a thread to " "grab a NativeRegisterContext!", __FUNCTION__); - return 0; + return llvm::None; } NativeRegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); @@ -163,10 +166,11 @@ uint32_t NativeProcessProtocol::GetMaxWatchpoints() const { log->Warning("NativeProcessProtocol::%s (): failed to get a " "RegisterContextNativeProcess from the first thread!", __FUNCTION__); - return 0; + return llvm::None; } - return reg_ctx_sp->NumSupportedHardwareWatchpoints(); + return std::make_pair(reg_ctx_sp->NumSupportedHardwareBreakpoints(), + reg_ctx_sp->NumSupportedHardwareWatchpoints()); } Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size, @@ -263,6 +267,92 @@ Error NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) { return overall_error.Fail() ? overall_error : error; } +const HardwareBreakpointMap & +NativeProcessProtocol::GetHardwareBreakpointMap() const { + return m_hw_breakpoints_map; +} + +Error NativeProcessProtocol::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + // This default implementation assumes setting a hardware breakpoint for + // this process will require setting same hardware breakpoint for each + // of its existing threads. New thread will do the same once created. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Update the thread list + UpdateThreads(); + + // Exit here if target does not have required hardware breakpoint capability. + auto hw_debug_cap = GetHardwareDebugSupportInfo(); + + if (hw_debug_cap == llvm::None || hw_debug_cap->first == 0 || + hw_debug_cap->first <= m_hw_breakpoints_map.size()) + return Error("Target does not have required no of hardware breakpoints"); + + // Vector below stores all thread pointer for which we have we successfully + // set this hardware breakpoint. If any of the current process threads fails + // to set this hardware breakpoint then roll back and remove this breakpoint + // for all the threads that had already set it successfully. + std::vector<NativeThreadProtocolSP> breakpoint_established_threads; + + // Request to set a hardware breakpoint for each of current process threads. + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + for (auto thread_sp : m_threads) { + assert(thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + Error thread_error = thread_sp->SetHardwareBreakpoint(addr, size); + if (thread_error.Success()) { + // Remember that we set this breakpoint successfully in + // case we need to clear it later. + breakpoint_established_threads.push_back(thread_sp); + } else { + // Unset the breakpoint for each thread we successfully + // set so that we get back to a consistent state of "not + // set" for this hardware breakpoint. + for (auto rollback_thread_sp : breakpoint_established_threads) { + Error remove_error = rollback_thread_sp->RemoveHardwareBreakpoint(addr); + if (remove_error.Fail() && log) { + log->Warning("NativeProcessProtocol::%s (): RemoveHardwareBreakpoint" + " failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s", + __FUNCTION__, GetID(), rollback_thread_sp->GetID(), + remove_error.AsCString()); + } + } + + return thread_error; + } + } + + // Register new hardware breakpoint into hardware breakpoints map of current + // process. + m_hw_breakpoints_map[addr] = {addr, size}; + + return Error(); +} + +Error NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) { + // Update the thread list + UpdateThreads(); + + Error error; + + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + for (auto thread_sp : m_threads) { + assert(thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + error = thread_sp->RemoveHardwareBreakpoint(addr); + } + + // Also remove from hardware breakpoint map of current process. + m_hw_breakpoints_map.erase(addr); + + return error; +} + bool NativeProcessProtocol::RegisterNativeDelegate( NativeDelegate &native_delegate) { std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); @@ -339,8 +429,12 @@ Error NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr, }); } -Error NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr) { - return m_breakpoint_list.DecRef(addr); +Error NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr, + bool hardware) { + if (hardware) + return RemoveHardwareBreakpoint(addr); + else + return m_breakpoint_list.DecRef(addr); } Error NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) { @@ -410,7 +504,7 @@ Error NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid, return Error("failed to retrieve a valid architecture from the exe module"); } -#ifndef __linux__ +#if !defined(__linux__) && !defined(__NetBSD__) // These need to be implemented to support lldb-gdb-server on a given platform. // Stubs are // provided to make the rest of the code link on non-supported platforms. diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp index 73b2629c57c1..3bc0a0d9705c 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp @@ -9,8 +9,8 @@ #include "lldb/Host/common/NativeRegisterContext.h" -#include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Utility/Log.h" #include "lldb/Host/PosixApi.h" #include "lldb/Host/common/NativeProcessProtocol.h" @@ -246,10 +246,20 @@ uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr, return LLDB_INVALID_INDEX32; } +Error NativeRegisterContext::ClearAllHardwareBreakpoints() { + return Error("not implemented"); +} + bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { return false; } +Error NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index, + lldb::addr_t trap_addr) { + bp_index = LLDB_INVALID_INDEX32; + return Error("not implemented"); +} + uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; } uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp deleted file mode 100644 index 5ff596b57693..000000000000 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//===-- NativeRegisterContextRegisterInfo.cpp -------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h" -#include "lldb/lldb-private-forward.h" -#include "lldb/lldb-types.h" - -using namespace lldb_private; - -NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo( - NativeThreadProtocol &thread, uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info_interface) - : NativeRegisterContext(thread, concrete_frame_idx), - m_register_info_interface_up(register_info_interface) { - assert(register_info_interface && "null register_info_interface"); -} - -uint32_t NativeRegisterContextRegisterInfo::GetRegisterCount() const { - return m_register_info_interface_up->GetRegisterCount(); -} - -uint32_t NativeRegisterContextRegisterInfo::GetUserRegisterCount() const { - return m_register_info_interface_up->GetUserRegisterCount(); -} - -const RegisterInfo *NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex( - uint32_t reg_index) const { - if (reg_index <= GetRegisterCount()) - return m_register_info_interface_up->GetRegisterInfo() + reg_index; - else - return nullptr; -} - -const RegisterInfoInterface & -NativeRegisterContextRegisterInfo::GetRegisterInfoInterface() const { - return *m_register_info_interface_up; -} diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp index 5948adf3c8d1..168e5b42b961 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp @@ -9,7 +9,7 @@ #include "lldb/Host/common/NativeWatchpointList.h" -#include "lldb/Core/Log.h" +#include "lldb/Utility/Log.h" using namespace lldb; using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp b/contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp new file mode 100644 index 000000000000..58c32e4a1c4b --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/PseudoTerminal.cpp @@ -0,0 +1,310 @@ +//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/Config.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(TIOCSCTTY) +#include <sys/ioctl.h> +#endif + +#include "lldb/Host/PosixApi.h" + +#if defined(__ANDROID__) +int posix_openpt(int flags); +#endif + +using namespace lldb_utility; + +//---------------------------------------------------------------------- +// PseudoTerminal constructor +//---------------------------------------------------------------------- +PseudoTerminal::PseudoTerminal() + : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} + +//---------------------------------------------------------------------- +// Destructor +// +// The destructor will close the master and slave file descriptors +// if they are valid and ownership has not been released using the +// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() +// member functions. +//---------------------------------------------------------------------- +PseudoTerminal::~PseudoTerminal() { + CloseMasterFileDescriptor(); + CloseSlaveFileDescriptor(); +} + +//---------------------------------------------------------------------- +// Close the master file descriptor if it is valid. +//---------------------------------------------------------------------- +void PseudoTerminal::CloseMasterFileDescriptor() { + if (m_master_fd >= 0) { + ::close(m_master_fd); + m_master_fd = invalid_fd; + } +} + +//---------------------------------------------------------------------- +// Close the slave file descriptor if it is valid. +//---------------------------------------------------------------------- +void PseudoTerminal::CloseSlaveFileDescriptor() { + if (m_slave_fd >= 0) { + ::close(m_slave_fd); + m_slave_fd = invalid_fd; + } +} + +//---------------------------------------------------------------------- +// Open the first available pseudo terminal with OFLAG as the +// permissions. The file descriptor is stored in this object and can +// be accessed with the MasterFileDescriptor() accessor. The +// ownership of the master file descriptor can be released using +// the ReleaseMasterFileDescriptor() accessor. If this object has +// a valid master files descriptor when its destructor is called, it +// will close the master file descriptor, therefore clients must +// call ReleaseMasterFileDescriptor() if they wish to use the master +// file descriptor after this object is out of scope or destroyed. +// +// RETURNS: +// True when successful, false indicating an error occurred. +//---------------------------------------------------------------------- +bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str, + size_t error_len) { + if (error_str) + error_str[0] = '\0'; + +#if !defined(LLDB_DISABLE_POSIX) + // Open the master side of a pseudo terminal + m_master_fd = ::posix_openpt(oflag); + if (m_master_fd < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + return false; + } + + // Grant access to the slave pseudo terminal + if (::grantpt(m_master_fd) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + CloseMasterFileDescriptor(); + return false; + } + + // Clear the lock flag on the slave pseudo terminal + if (::unlockpt(m_master_fd) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + CloseMasterFileDescriptor(); + return false; + } + + return true; +#else + if (error_str) + ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported"); + return false; +#endif +} + +//---------------------------------------------------------------------- +// Open the slave pseudo terminal for the current master pseudo +// terminal. A master pseudo terminal should already be valid prior to +// calling this function (see OpenFirstAvailableMaster()). +// The file descriptor is stored this object's member variables and can +// be accessed via the GetSlaveFileDescriptor(), or released using the +// ReleaseSlaveFileDescriptor() member function. +// +// RETURNS: +// True when successful, false indicating an error occurred. +//---------------------------------------------------------------------- +bool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) { + if (error_str) + error_str[0] = '\0'; + + CloseSlaveFileDescriptor(); + + // Open the master side of a pseudo terminal + const char *slave_name = GetSlaveName(error_str, error_len); + + if (slave_name == nullptr) + return false; + + m_slave_fd = ::open(slave_name, oflag); + + if (m_slave_fd < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + return false; + } + + return true; +} + +//---------------------------------------------------------------------- +// Get the name of the slave pseudo terminal. A master pseudo terminal +// should already be valid prior to calling this function (see +// OpenFirstAvailableMaster()). +// +// RETURNS: +// NULL if no valid master pseudo terminal or if ptsname() fails. +// The name of the slave pseudo terminal as a NULL terminated C string +// that comes from static memory, so a copy of the string should be +// made as subsequent calls can change this value. +//---------------------------------------------------------------------- +const char *PseudoTerminal::GetSlaveName(char *error_str, + size_t error_len) const { + if (error_str) + error_str[0] = '\0'; + + if (m_master_fd < 0) { + if (error_str) + ::snprintf(error_str, error_len, "%s", + "master file descriptor is invalid"); + return nullptr; + } + const char *slave_name = ::ptsname(m_master_fd); + + if (error_str && slave_name == nullptr) + ::strerror_r(errno, error_str, error_len); + + return slave_name; +} + +//---------------------------------------------------------------------- +// Fork a child process and have its stdio routed to a pseudo terminal. +// +// In the parent process when a valid pid is returned, the master file +// descriptor can be used as a read/write access to stdio of the +// child process. +// +// In the child process the stdin/stdout/stderr will already be routed +// to the slave pseudo terminal and the master file descriptor will be +// closed as it is no longer needed by the child process. +// +// This class will close the file descriptors for the master/slave +// when the destructor is called, so be sure to call +// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any +// file descriptors are going to be used past the lifespan of this +// object. +// +// RETURNS: +// in the parent process: the pid of the child, or -1 if fork fails +// in the child process: zero +//---------------------------------------------------------------------- +lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { + if (error_str) + error_str[0] = '\0'; + pid_t pid = LLDB_INVALID_PROCESS_ID; +#if !defined(LLDB_DISABLE_POSIX) + int flags = O_RDWR; + flags |= O_CLOEXEC; + if (OpenFirstAvailableMaster(flags, error_str, error_len)) { + // Successfully opened our master pseudo terminal + + pid = ::fork(); + if (pid < 0) { + // Fork failed + if (error_str) + ::strerror_r(errno, error_str, error_len); + } else if (pid == 0) { + // Child Process + ::setsid(); + + if (OpenSlave(O_RDWR, error_str, error_len)) { + // Successfully opened slave + + // Master FD should have O_CLOEXEC set, but let's close it just in + // case... + CloseMasterFileDescriptor(); + +#if defined(TIOCSCTTY) + // Acquire the controlling terminal + if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + } +#endif + // Duplicate all stdio file descriptors to the slave pseudo terminal + if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + + if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + + if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + } + } else { + // Parent Process + // Do nothing and let the pid get returned! + } + } +#endif + return pid; +} + +//---------------------------------------------------------------------- +// The master file descriptor accessor. This object retains ownership +// of the master file descriptor when this accessor is used. Use +// ReleaseMasterFileDescriptor() if you wish this object to release +// ownership of the master file descriptor. +// +// Returns the master file descriptor, or -1 if the master file +// descriptor is not currently valid. +//---------------------------------------------------------------------- +int PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; } + +//---------------------------------------------------------------------- +// The slave file descriptor accessor. +// +// Returns the slave file descriptor, or -1 if the slave file +// descriptor is not currently valid. +//---------------------------------------------------------------------- +int PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; } + +//---------------------------------------------------------------------- +// Release ownership of the master pseudo terminal file descriptor +// without closing it. The destructor for this class will close the +// master file descriptor if the ownership isn't released using this +// call and the master file descriptor has been opened. +//---------------------------------------------------------------------- +int PseudoTerminal::ReleaseMasterFileDescriptor() { + // Release ownership of the master pseudo terminal file + // descriptor without closing it. (the destructor for this + // class will close it otherwise!) + int fd = m_master_fd; + m_master_fd = invalid_fd; + return fd; +} + +//---------------------------------------------------------------------- +// Release ownership of the slave pseudo terminal file descriptor +// without closing it. The destructor for this class will close the +// slave file descriptor if the ownership isn't released using this +// call and the slave file descriptor has been opened. +//---------------------------------------------------------------------- +int PseudoTerminal::ReleaseSlaveFileDescriptor() { + // Release ownership of the slave pseudo terminal file + // descriptor without closing it (the destructor for this + // class will close it otherwise!) + int fd = m_slave_fd; + m_slave_fd = invalid_fd; + return fd; +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp index 79777c88fa46..2a665ddacb64 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp @@ -9,14 +9,14 @@ #include "lldb/Host/Socket.h" -#include "lldb/Core/Log.h" -#include "lldb/Core/RegularExpression.h" #include "lldb/Host/Config.h" #include "lldb/Host/Host.h" #include "lldb/Host/SocketAddress.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/common/UDPSocket.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegularExpression.h" #ifndef LLDB_DISABLE_POSIX #include "lldb/Host/posix/DomainSocket.h" @@ -38,11 +38,9 @@ #include <asm-generic/errno-base.h> #include <errno.h> #include <linux/tcp.h> -#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC) #include <fcntl.h> #include <sys/syscall.h> #include <unistd.h> -#endif // ANDROID_ARM_BUILD_STATIC || ANDROID_MIPS_BUILD_STATIC #endif // __ANDROID__ using namespace lldb; @@ -174,15 +172,13 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, } Error Socket::UdpConnect(llvm::StringRef host_and_port, - bool child_processes_inherit, Socket *&send_socket, - Socket *&recv_socket) { + bool child_processes_inherit, Socket *&socket) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); - return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket, - recv_socket); + return UDPSocket::Connect(host_and_port, child_processes_inherit, socket); } Error Socket::UnixDomainConnect(llvm::StringRef name, @@ -424,9 +420,13 @@ NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, socklen_t *addrlen, bool child_processes_inherit, Error &error) { error.Clear(); -#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC) - // Temporary workaround for statically linking Android lldb-server with the - // latest API. +#if defined(ANDROID_USE_ACCEPT_WORKAROUND) + // Hack: + // This enables static linking lldb-server to an API 21 libc, but still having + // it run on older devices. It is necessary because API 21 libc's + // implementation of accept() uses the accept4 syscall(), which is not + // available in older kernels. Using an older libc would fix this issue, but + // introduce other ones, as the old libraries were quite buggy. int fd = syscall(__NR_accept, sockfd, addr, addrlen); if (fd >= 0 && !child_processes_inherit) { int flags = ::fcntl(fd, F_GETFD); @@ -441,11 +441,7 @@ NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, if (!child_processes_inherit) { flags |= SOCK_CLOEXEC; } -#if defined(__NetBSD__) - NativeSocket fd = ::paccept(sockfd, addr, addrlen, nullptr, flags); -#else NativeSocket fd = ::accept4(sockfd, addr, addrlen, flags); -#endif #else NativeSocket fd = ::accept(sockfd, addr, addrlen); #endif diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp index 1f5de2e5df18..48c3ec1c48ed 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp @@ -89,6 +89,10 @@ SocketAddress::SocketAddress(const struct sockaddr_storage &s) { m_socket_addr.sa_storage = s; } +SocketAddress::SocketAddress(const struct addrinfo *addr_info) { + *this = addr_info; +} + //---------------------------------------------------------------------- // SocketAddress copy constructor //---------------------------------------------------------------------- @@ -244,6 +248,24 @@ bool SocketAddress::getaddrinfo(const char *host, const char *service, return result; } +std::vector<SocketAddress> SocketAddress::GetAddressInfo(const char *hostname, + const char *servname) { + std::vector<SocketAddress> addr_list; + + struct addrinfo *service_info_list = NULL; + int err = ::getaddrinfo(hostname, servname, NULL, &service_info_list); + if (err == 0 && service_info_list) { + for (struct addrinfo *service_ptr = service_info_list; service_ptr != NULL; + service_ptr = service_ptr->ai_next) { + addr_list.emplace_back(SocketAddress(service_ptr)); + } + } + + if (service_info_list) + ::freeaddrinfo(service_info_list); + return addr_list; +} + bool SocketAddress::SetToLocalhost(sa_family_t family, uint16_t port) { switch (family) { case AF_INET: @@ -287,3 +309,29 @@ bool SocketAddress::SetToAnyAddress(sa_family_t family, uint16_t port) { Clear(); return false; } + +bool SocketAddress::IsAnyAddr() const { + return (GetFamily() == AF_INET) + ? m_socket_addr.sa_ipv4.sin_addr.s_addr == htonl(INADDR_ANY) + : 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, &in6addr_any, 16); +} + +bool SocketAddress::operator==(const SocketAddress &rhs) const { + if (GetFamily() != rhs.GetFamily()) + return false; + if (GetLength() != rhs.GetLength()) + return false; + switch (GetFamily()) { + case AF_INET: + return m_socket_addr.sa_ipv4.sin_addr.s_addr == + rhs.m_socket_addr.sa_ipv4.sin_addr.s_addr; + case AF_INET6: + return 0 == memcmp(&m_socket_addr.sa_ipv6.sin6_addr, + &rhs.m_socket_addr.sa_ipv6.sin6_addr, 16); + } + return false; +} + +bool SocketAddress::operator!=(const SocketAddress &rhs) const { + return !(*this == rhs); +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp index 3d57b7dd6b88..436cb2bb112e 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp @@ -9,9 +9,9 @@ #include "lldb/Host/common/SoftwareBreakpoint.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/Log.h" #include "lldb/Host/Debug.h" +#include "lldb/Utility/Error.h" +#include "lldb/Utility/Log.h" #include "lldb/Host/common/NativeProcessProtocol.h" diff --git a/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp index 461b15a07f84..9e0a3b5bf4df 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp @@ -9,17 +9,17 @@ #include "lldb/Host/Symbols.h" #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/DataBuffer.h" -#include "lldb/Core/DataExtractor.h" -#include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" -#include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" -#include "lldb/Core/UUID.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/SafeMachO.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/UUID.h" #include "llvm/Support/FileSystem.h" @@ -54,7 +54,9 @@ static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) { ModuleSpec spec; for (size_t i = 0; i < module_specs.GetSize(); ++i) { - assert(module_specs.GetModuleSpecAtIndex(i, spec)); + bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); + UNUSED_IF_ASSERT_DISABLED(got_spec); + assert(got_spec); if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch)))) { @@ -210,8 +212,13 @@ FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { debug_file_search_paths.AppendIfUnique(FileSpec(".", true)); #ifndef LLVM_ON_WIN32 +#if defined(__NetBSD__) + // Add /usr/libdata/debug directory. + debug_file_search_paths.AppendIfUnique(FileSpec("/usr/libdata/debug", true)); +#else // Add /usr/lib/debug directory. debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true)); +#endif #endif // LLVM_ON_WIN32 std::string uuid_str; @@ -228,7 +235,7 @@ FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { for (size_t idx = 0; idx < num_directories; ++idx) { FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); dirspec.ResolvePath(); - if (!dirspec.Exists() || !dirspec.IsDirectory()) + if (!llvm::sys::fs::is_directory(dirspec.GetPath())) continue; std::vector<std::string> files; diff --git a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp index 9685ceeeadf1..9a009280a904 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp @@ -13,8 +13,8 @@ #include "lldb/Host/common/TCPSocket.h" -#include "lldb/Core/Log.h" #include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" #ifndef LLDB_DISABLE_POSIX #include <arpa/inet.h> diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp deleted file mode 100644 index b3f9edee2e16..000000000000 --- a/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/ThisThread.h" -#include "lldb/Core/Error.h" -#include "lldb/Host/HostInfo.h" - -#include "llvm/ADT/STLExtras.h" - -#include <algorithm> - -using namespace lldb; -using namespace lldb_private; - -void ThisThread::SetName(llvm::StringRef name, int max_length) { - std::string truncated_name(name.data()); - - // Thread names are coming in like '<lldb.comm.debugger.edit>' and - // '<lldb.comm.debugger.editline>'. So just chopping the end of the string - // off leads to a lot of similar named threads. Go through the thread name - // and search for the last dot and use that. - - if (max_length > 0 && - truncated_name.length() > static_cast<size_t>(max_length)) { - // First see if we can get lucky by removing any initial or final braces. - std::string::size_type begin = truncated_name.find_first_not_of("(<"); - std::string::size_type end = truncated_name.find_last_not_of(")>."); - if (end - begin > static_cast<size_t>(max_length)) { - // We're still too long. Since this is a dotted component, use everything - // after the last - // dot, up to a maximum of |length| characters. - std::string::size_type last_dot = truncated_name.rfind('.'); - if (last_dot != std::string::npos) - begin = last_dot + 1; - - end = std::min(end, begin + max_length); - } - - std::string::size_type count = end - begin + 1; - truncated_name = truncated_name.substr(begin, count); - } - - SetName(truncated_name); -} diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp index b91c2fe9baab..32641efe408a 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp @@ -10,10 +10,9 @@ // lldb Includes #include "lldb/Host/ThreadLauncher.h" -#include "lldb/Core/Log.h" #include "lldb/Host/HostNativeThread.h" #include "lldb/Host/HostThread.h" -#include "lldb/Host/ThisThread.h" +#include "lldb/Utility/Log.h" #if defined(_WIN32) #include "lldb/Host/windows/windows.h" diff --git a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp index 972f87eb73d8..7ca62e7496ba 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp @@ -9,8 +9,8 @@ #include "lldb/Host/common/UDPSocket.h" -#include "lldb/Core/Log.h" #include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" #ifndef LLDB_DISABLE_POSIX #include <arpa/inet.h> @@ -38,7 +38,7 @@ UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, - m_send_sockaddr, m_send_sockaddr.GetLength()); + m_sockaddr, m_sockaddr.GetLength()); } Error UDPSocket::Connect(llvm::StringRef name) { @@ -55,9 +55,8 @@ Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, } Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, - Socket *&send_socket, Socket *&recv_socket) { - std::unique_ptr<UDPSocket> final_send_socket; - std::unique_ptr<UDPSocket> final_recv_socket; + Socket *&socket) { + std::unique_ptr<UDPSocket> final_socket; Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) @@ -70,25 +69,6 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) return error; - // Setup the receiving end of the UDP connection on this localhost - // on port zero. After we bind to port zero we can read the port. - final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); - if (error.Success()) { - // Socket was created, now lets bind to the requested port - SocketAddress addr; - addr.SetToAnyAddress(AF_INET, 0); - - if (::bind(final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == - -1) { - // Bind failed... - SetLastError(error); - } - } - - assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); - if (error.Fail()) - return error; - // At this point we have setup the receive port, now we need to // setup the UDP send socket @@ -118,8 +98,8 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, service_info_ptr->ai_family, service_info_ptr->ai_socktype, service_info_ptr->ai_protocol, child_processes_inherit, error); if (error.Success()) { - final_send_socket.reset(new UDPSocket(send_fd)); - final_send_socket->m_send_sockaddr = service_info_ptr; + final_socket.reset(new UDPSocket(send_fd)); + final_socket->m_sockaddr = service_info_ptr; break; } else continue; @@ -127,11 +107,31 @@ Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, ::freeaddrinfo(service_info_list); - if (!final_send_socket) + if (!final_socket) + return error; + + SocketAddress bind_addr; + + // Only bind to the loopback address if we are expecting a connection from + // localhost to avoid any firewall issues. + const bool bind_addr_success = (host_str == "127.0.0.1" || host_str == "localhost") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); + + if (!bind_addr_success) { + error.SetErrorString("Failed to get hostspec to bind for"); return error; + } + + bind_addr.SetPort(0); // Let the source port # be determined dynamically + + err = ::bind(final_socket->GetNativeSocket(), bind_addr, bind_addr.GetLength()); + + struct sockaddr_in source_info; + socklen_t address_len = sizeof (struct sockaddr_in); + err = ::getsockname(final_socket->GetNativeSocket(), (struct sockaddr *) &source_info, &address_len); - send_socket = final_send_socket.release(); - recv_socket = final_recv_socket.release(); + socket = final_socket.release(); error.Clear(); return error; } |