diff options
Diffstat (limited to 'source/Host')
37 files changed, 990 insertions, 684 deletions
diff --git a/source/Host/Makefile b/source/Host/Makefile deleted file mode 100644 index da90c8c364a3..000000000000 --- a/source/Host/Makefile +++ /dev/null @@ -1,65 +0,0 @@ -##===- source/Host/Makefile --------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../.. -LEVEL := $(LLDB_LEVEL)/../.. - -include $(LEVEL)/Makefile.config - -define DIR_SOURCES -SOURCES += $$(addprefix $(1)/,$$(notdir $$(wildcard $$(PROJ_SRC_DIR)/$(1)/*.cpp \ - $$(PROJ_SRC_DIR)/*.cc $$(PROJ_SRC_DIR)/$(1)/*.c $$(PROJ_SRC_DIR)/$(1)/*.mm))) -endef - -$(eval $(call DIR_SOURCES,common)) - -ifeq ($(HOST_OS),Darwin) -$(eval $(call DIR_SOURCES,posix)) -$(eval $(call DIR_SOURCES,macosx)) -CFCPP_SOURCES = \ - $(addprefix macosx/cfcpp/,$(notdir $(wildcard $(PROJ_SRC_DIR)/macosx/cfcpp/*.cpp))) -SOURCES += $(CFCPP_SOURCES) - -CFCPP_BaseNameSources := $(sort $(basename $(CFCPP_SOURCES))) -CFCPP_OBJECTS := $(CFCPP_BaseNameSources:%=$(ObjDir)/%.o) - -# Make sure the cfcpp output directory exists -$(CFCPP_OBJECTS): $(ObjDir)/cfcpp/.dir -endif - -ifeq ($(HOST_OS),Linux) -$(eval $(call DIR_SOURCES,posix)) -$(eval $(call DIR_SOURCES,linux)) -endif - -ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD)) -$(eval $(call DIR_SOURCES,posix)) -$(eval $(call DIR_SOURCES,freebsd)) -endif - -ifeq ($(HOST_OS),NetBSD) -$(eval $(call DIR_SOURCES,posix)) -$(eval $(call DIR_SOURCES,netbsd)) -endif - -ifeq ($(HOST_OS),MingW) -$(eval $(call DIR_SOURCES,windows)) -SOURCES += posix/ConnectionFileDescriptorPosix.cpp -endif - -ifeq ($(HOST_OS),Android) -$(eval $(call DIR_SOURCES,posix)) -$(eval $(call DIR_SOURCES,linux)) -$(eval $(call DIR_SOURCES,android)) -endif - -LIBRARYNAME := lldbHost -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile diff --git a/source/Host/android/LibcGlue.cpp b/source/Host/android/LibcGlue.cpp index 3842fb6c2a8e..091c11d15535 100644 --- a/source/Host/android/LibcGlue.cpp +++ b/source/Host/android/LibcGlue.cpp @@ -27,11 +27,6 @@ time_t timegm(struct tm* t) return (time_t) timegm64(t); } -int signalfd (int fd, const sigset_t *mask, int flags) -{ - return syscall(__NR_signalfd4, fd, mask, _NSIG / 8, flags); -} - int posix_openpt(int flags) { return open("/dev/ptmx", flags); diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp index 4640154c6cb1..d7209feb46db 100644 --- a/source/Host/common/Editline.cpp +++ b/source/Host/common/Editline.cpp @@ -19,7 +19,6 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" -#include "lldb/Host/Mutex.h" #include "lldb/Utility/LLDBAssert.h" using namespace lldb_private; @@ -227,9 +226,9 @@ namespace lldb_private GetHistory (const std::string &prefix) { typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap; - static Mutex g_mutex (Mutex::eMutexTypeRecursive); + static std::recursive_mutex g_mutex; static WeakHistoryMap g_weak_map; - Mutex::Locker locker (g_mutex); + std::lock_guard<std::recursive_mutex> guard(g_mutex); WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix); EditlineHistorySP history_sp; if (pos != g_weak_map.end()) @@ -587,9 +586,9 @@ Editline::GetCharacter (EditLineCharType * c) // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance // for someone to interrupt us. After Read returns, immediately lock the mutex again and // check if we were interrupted. - m_output_mutex.Unlock(); + m_output_mutex.unlock(); int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL); - m_output_mutex.Lock(); + m_output_mutex.lock(); if (m_editor_status == EditorStatus::Interrupted) { while (read_count > 0 && status == lldb::eConnectionStatusSuccess) @@ -658,41 +657,9 @@ Editline::BreakLineCommand (int ch) // Establish the new cursor position at the start of a line when inserting a line break m_revert_cursor_index = 0; - // Don't perform end of input detection or automatic formatting when pasting + // Don't perform automatic formatting when pasting if (!IsInputPending (m_input_file)) { - // If this is the end of the last line, treat this as a potential exit - if (m_current_line_index == m_input_lines.size() - 1 && new_line_fragment.length() == 0) - { - bool end_of_input = true; - if (m_is_input_complete_callback) - { - SaveEditedLine(); - auto lines = GetInputAsStringList(); - end_of_input = m_is_input_complete_callback (this, lines, m_is_input_complete_callback_baton); - - // The completion test is allowed to change the input lines when complete - if (end_of_input) - { - m_input_lines.clear(); - for (unsigned index = 0; index < lines.GetSize(); index++) - { -#if LLDB_EDITLINE_USE_WCHAR - m_input_lines.insert (m_input_lines.end(), m_utf8conv.from_bytes (lines[index])); -#else - m_input_lines.insert (m_input_lines.end(), lines[index]); -#endif - } - } - } - if (end_of_input) - { - fprintf (m_output_file, "\n"); - m_editor_status = EditorStatus::Complete; - return CC_NEWLINE; - } - } - // Apply smart indentation if (m_fix_indentation_callback) { @@ -721,7 +688,49 @@ Editline::BreakLineCommand (int ch) } unsigned char -Editline::DeleteNextCharCommand (int ch) +Editline::EndOrAddLineCommand(int ch) +{ + // Don't perform end of input detection when pasting, always treat this as a line break + if (IsInputPending(m_input_file)) + { + return BreakLineCommand(ch); + } + + // Save any edits to this line + SaveEditedLine(); + + // If this is the end of the last line, consider whether to add a line instead + const LineInfoW *info = el_wline(m_editline); + if (m_current_line_index == m_input_lines.size() - 1 && info->cursor == info->lastchar) + { + if (m_is_input_complete_callback) + { + auto lines = GetInputAsStringList(); + if (!m_is_input_complete_callback(this, lines, m_is_input_complete_callback_baton)) + { + return BreakLineCommand(ch); + } + + // The completion test is allowed to change the input lines when complete + m_input_lines.clear(); + for (unsigned index = 0; index < lines.GetSize(); index++) + { +#if LLDB_EDITLINE_USE_WCHAR + m_input_lines.insert(m_input_lines.end(), m_utf8conv.from_bytes(lines[index])); +#else + m_input_lines.insert(m_input_lines.end(), lines[index]); +#endif + } + } + } + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); + fprintf(m_output_file, "\n"); + m_editor_status = EditorStatus::Complete; + return CC_NEWLINE; +} + +unsigned char +Editline::DeleteNextCharCommand(int ch) { LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); @@ -861,7 +870,23 @@ Editline::NextLineCommand (int ch) } unsigned char -Editline::FixIndentationCommand (int ch) +Editline::PreviousHistoryCommand(int ch) +{ + SaveEditedLine(); + + return RecallHistory(true); +} + +unsigned char +Editline::NextHistoryCommand(int ch) +{ + SaveEditedLine(); + + return RecallHistory(false); +} + +unsigned char +Editline::FixIndentationCommand(int ch) { if (!m_fix_indentation_callback) return CC_NORM; @@ -1075,36 +1100,46 @@ Editline::ConfigureEditor (bool multiline) })); // Commands used for multiline support, registered whether or not they're used - el_set (m_editline, EL_ADDFN, "lldb-break-line", "Insert a line break", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->BreakLineCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-delete-next-char", "Delete next character", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->DeleteNextCharCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-delete-previous-char", "Delete previous character", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->DeletePreviousCharCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-previous-line", "Move to previous line", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->PreviousLineCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-next-line", "Move to next line", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->NextLineCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-buffer-start", "Move to start of buffer", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->BufferStartCommand (ch); - })); - el_set (m_editline, EL_ADDFN, "lldb-buffer-end", "Move to end of buffer", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->BufferEndCommand (ch); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), EditLineConstString("Insert a line break"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BreakLineCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"), + EditLineConstString("End editing or continue when incomplete"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"), + EditLineConstString("Delete next character"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"), + EditLineConstString("Delete previous character"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch); })); - el_set (m_editline, EL_ADDFN, "lldb-fix-indentation", "Fix line indentation", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"), + EditLineConstString("Move to previous line"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousLineCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), EditLineConstString("Move to next line"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextLineCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"), + EditLineConstString("Move to previous history"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), EditLineConstString("Move to next history"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextHistoryCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"), + EditLineConstString("Move to start of buffer"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferStartCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"), EditLineConstString("Move to end of buffer"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferEndCommand(ch); })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"), + EditLineConstString("Fix line indentation"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { return Editline::InstanceFor (editline)->FixIndentationCommand (ch); })); @@ -1115,9 +1150,11 @@ Editline::ConfigureEditor (bool multiline) EditlineCommandCallbackType complete_callback = [] (EditLine * editline, int ch) { return Editline::InstanceFor (editline)->TabCommand (ch); }; - el_set (m_editline, EL_ADDFN, "lldb-complete", "Invoke completion", complete_callback); - el_set (m_editline, EL_ADDFN, "lldb_complete", "Invoke completion", complete_callback); - + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"), EditLineConstString("Invoke completion"), + complete_callback); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"), EditLineConstString("Invoke completion"), + complete_callback); + // General bindings we don't mind being overridden if (!multiline) { el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string @@ -1129,10 +1166,10 @@ Editline::ConfigureEditor (bool multiline) el_source (m_editline, NULL); // Register an internal binding that external developers shouldn't use - el_set (m_editline, EL_ADDFN, "lldb-revert-line", "Revert line to saved state", - (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->RevertLineCommand (ch); - })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"), + EditLineConstString("Revert line to saved state"), + (EditlineCommandCallbackType)( + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->RevertLineCommand(ch); })); // Register keys that perform auto-indent correction if (m_fix_indentation_callback && m_fix_indentation_callback_chars) @@ -1150,8 +1187,10 @@ Editline::ConfigureEditor (bool multiline) // Multi-line editor bindings if (multiline) { - el_set (m_editline, EL_BIND, "\n", "lldb-break-line", NULL); - el_set (m_editline, EL_BIND, "\r", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL); el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL); el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL); el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL); @@ -1166,6 +1205,10 @@ Editline::ConfigureEditor (bool multiline) el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL); el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL); el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL); } else { @@ -1209,6 +1252,32 @@ Editline::Editline (const char * editline_name, FILE * input_file, FILE * output // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; m_history_sp = EditlineHistory::GetHistory (m_editor_name); + +#ifdef USE_SETUPTERM_WORKAROUND + if (m_output_file) + { + const int term_fd = fileno(m_output_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, [&]() { + 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 C++ destructor chain issues + }); + + // We must make sure to initialize the terminal a given file descriptor + // only once. If we do this multiple times, we start leaking memory. + std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr); + if (g_init_terminal_fds_ptr->find(term_fd) == g_init_terminal_fds_ptr->end()) + { + g_init_terminal_fds_ptr->insert(term_fd); + setupterm((char *)0, term_fd, (int *)0); + } + } + } +#endif } Editline::~Editline() @@ -1284,7 +1353,7 @@ bool Editline::Interrupt() { bool result = true; - Mutex::Locker locker(m_output_mutex); + std::lock_guard<std::mutex> guard(m_output_mutex); if (m_editor_status == EditorStatus::Editing) { fprintf(m_output_file, "^C\n"); result = m_input_connection.InterruptRead(); @@ -1297,7 +1366,7 @@ bool Editline::Cancel() { bool result = true; - Mutex::Locker locker(m_output_mutex); + std::lock_guard<std::mutex> guard(m_output_mutex); if (m_editor_status == EditorStatus::Editing) { MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); fprintf(m_output_file, ANSI_CLEAR_BELOW); @@ -1338,8 +1407,8 @@ Editline::GetLine (std::string &line, bool &interrupted) ConfigureEditor (false); m_input_lines = std::vector<EditLineStringType>(); m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); - - Mutex::Locker locker(m_output_mutex); + + std::lock_guard<std::mutex> guard(m_output_mutex); lldbassert(m_editor_status != EditorStatus::Editing); if (m_editor_status == EditorStatus::Interrupted) @@ -1354,10 +1423,6 @@ Editline::GetLine (std::string &line, bool &interrupted) m_editor_status = EditorStatus::Editing; m_revert_cursor_index = -1; -#ifdef USE_SETUPTERM_WORKAROUND - setupterm((char *)0, fileno(m_output_file), (int *)0); -#endif - int count; auto input = el_wgets (m_editline, &count); @@ -1392,8 +1457,8 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) SetBaseLineNumber (first_line_number); m_input_lines = std::vector<EditLineStringType>(); m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); - - Mutex::Locker locker(m_output_mutex); + + std::lock_guard<std::mutex> guard(m_output_mutex); // Begin the line editing loop DisplayInput(); SetCurrentLine (0); @@ -1404,9 +1469,6 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) m_revert_cursor_index = -1; while (m_editor_status == EditorStatus::Editing) { -#ifdef USE_SETUPTERM_WORKAROUND - setupterm((char *)0, fileno(m_output_file), (int *)0); -#endif int count; m_current_line_rows = -1; el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content @@ -1427,7 +1489,7 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) void Editline::PrintAsync (Stream *stream, const char *s, size_t len) { - Mutex::Locker locker(m_output_mutex); + std::lock_guard<std::mutex> guard(m_output_mutex); if (m_editor_status == EditorStatus::Editing) { MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index 71a6149cd614..9d4ab3d9c55e 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -14,7 +14,6 @@ #include <limits.h> #include <stdarg.h> #include <stdio.h> -#include <sys/stat.h> #ifdef _WIN32 #include "lldb/Host/windows/windows.h" @@ -22,6 +21,7 @@ #include <sys/ioctl.h> #endif +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() #include "lldb/Core/DataBufferHeap.h" @@ -29,6 +29,7 @@ #include "lldb/Core/Log.h" #include "lldb/Host/Config.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" using namespace lldb; using namespace lldb_private; @@ -109,27 +110,6 @@ File::File (const FileSpec& filespec, } } -File::File (const File &rhs) : - IOObject(eFDTypeFile, false), - m_descriptor (kInvalidDescriptor), - m_stream (kInvalidStream), - m_options (0), - m_own_stream (false), - m_is_interactive (eLazyBoolCalculate), - m_is_real_terminal (eLazyBoolCalculate) -{ - Duplicate (rhs); -} - - -File & -File::operator = (const File &rhs) -{ - if (this != &rhs) - Duplicate (rhs); - return *this; -} - File::~File() { Close (); @@ -191,7 +171,7 @@ File::GetStream () #ifdef _WIN32 m_descriptor = ::_dup(GetDescriptor()); #else - m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD); + m_descriptor = dup(GetDescriptor()); #endif m_should_close_fd = true; } @@ -215,7 +195,6 @@ File::GetStream () return m_stream; } - void File::SetStream (FILE *fh, bool transfer_ownership) { @@ -226,35 +205,6 @@ File::SetStream (FILE *fh, bool transfer_ownership) } Error -File::Duplicate (const File &rhs) -{ - Error error; - if (IsValid ()) - Close(); - - if (rhs.DescriptorIsValid()) - { -#ifdef _WIN32 - m_descriptor = ::_dup(rhs.GetDescriptor()); -#else - m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD); -#endif - if (!DescriptorIsValid()) - error.SetErrorToErrno(); - else - { - m_options = rhs.m_options; - m_should_close_fd = true; - } - } - else - { - error.SetErrorString ("invalid file to duplicate"); - } - return error; -} - -Error File::Open (const char *path, uint32_t options, uint32_t permissions) { Error error; @@ -288,7 +238,7 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) oflag |= O_RDONLY; #ifndef _WIN32 - if (options & eOpenoptionDontFollowSymlinks) + if (options & eOpenOptionDontFollowSymlinks) oflag |= O_NOFOLLOW; #endif } @@ -318,7 +268,18 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) do { +#ifdef _WIN32 + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) + { + m_descriptor = -1; + error.SetErrorString("Error converting path to UTF-16"); + return error; + } + ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode); +#else m_descriptor = ::open(path, oflag, mode); +#endif } while (m_descriptor < 0 && errno == EINTR); if (!DescriptorIsValid()) @@ -338,7 +299,8 @@ File::GetPermissions(const FileSpec &file_spec, Error &error) if (file_spec) { struct stat file_stats; - if (::stat(file_spec.GetCString(), &file_stats) == -1) + int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); + if (stat_result == -1) error.SetErrorToErrno(); else { @@ -399,6 +361,15 @@ File::Close () return error; } +void +File::Clear () +{ + m_stream = nullptr; + m_descriptor = -1; + m_options = 0; + m_own_stream = false; + m_is_interactive = m_supports_colors = m_is_real_terminal = eLazyBoolCalculate; +} Error File::GetFileSpec (FileSpec &file_spec) const diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp index 8885a791d88c..53c0ab40e676 100644 --- a/source/Host/common/FileSpec.cpp +++ b/source/Host/common/FileSpec.cpp @@ -17,7 +17,6 @@ #ifndef _MSC_VER #include <libgen.h> #endif -#include <sys/stat.h> #include <set> #include <string.h> #include <fstream> @@ -40,6 +39,7 @@ #include "lldb/Utility/CleanUp.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" @@ -57,10 +57,22 @@ PathSyntaxIsPosix(FileSpec::PathSyntax syntax) FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); } +const char * +GetPathSeparators(FileSpec::PathSyntax syntax) +{ + return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; +} + char -GetPathSeparator(FileSpec::PathSyntax syntax) +GetPrefferedPathSeparator(FileSpec::PathSyntax syntax) +{ + return GetPathSeparators(syntax)[0]; +} + +bool +IsPathSeparator(char value, FileSpec::PathSyntax syntax) { - return PathSyntaxIsPosix(syntax) ? '/' : '\\'; + return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); } void @@ -90,12 +102,73 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) { char resolved_path[PATH_MAX]; if (file_spec->GetPath (resolved_path, sizeof(resolved_path))) - return ::stat (resolved_path, stats_ptr) == 0; + 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. @@ -112,8 +185,22 @@ FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) { // 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)) - return; + { + 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 @@ -206,15 +293,10 @@ FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER // Save a copy of the original path that's passed in - llvm::SmallString<PATH_MAX> original_path(path.begin(), path.end()); + llvm::SmallString<128> original_path(path.begin(), path.end()); llvm::sys::fs::make_absolute(path); - - - path.push_back(0); // Be sure we have a nul terminated string - path.pop_back(); - struct stat file_stats; - if (::stat (path.data(), &file_stats) != 0) + if (!llvm::sys::fs::exists(path)) { path.clear(); path.append(original_path.begin(), original_path.end()); @@ -318,30 +400,34 @@ FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) if (pathname == NULL || pathname[0] == '\0') return; - llvm::SmallString<64> normalized(pathname); + llvm::SmallString<64> resolved(pathname); if (resolve) { - FileSpec::Resolve (normalized); + FileSpec::Resolve (resolved); m_is_resolved = true; } - // Only normalize after resolving the path. Resolution will modify the path - // string, potentially adding wrong kinds of slashes to the path, that need - // to be re-normalized. - Normalize(normalized, syntax); + Normalize(resolved, syntax); - llvm::StringRef resolve_path_ref(normalized.c_str()); - llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref); - if (!filename_ref.empty()) + llvm::StringRef resolve_path_ref(resolved.c_str()); + size_t dir_end = ParentPathEnd(resolve_path_ref, syntax); + if (dir_end == 0) { - m_filename.SetString (filename_ref); - llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref); - if (!directory_ref.empty()) - m_directory.SetString(directory_ref); + m_filename.SetString(resolve_path_ref); + return; } - else - m_directory.SetCString(normalized.c_str()); + + 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, syntax); + while (filename_begin != llvm::StringRef::npos && filename_begin < resolve_path_ref.size() && + filename_begin != root_dir_start && IsPathSeparator(resolve_path_ref[filename_begin], syntax)) + ++filename_begin; + m_filename.SetString((filename_begin == llvm::StringRef::npos || filename_begin >= resolve_path_ref.size()) + ? "." + : resolve_path_ref.substr(filename_begin)); } void @@ -390,66 +476,78 @@ 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 (m_filename == rhs.m_filename) + 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()) { - if (m_directory == rhs.m_directory) - 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); + // Both paths are resolved, no need to look further... + return false; + } - // If "this" isn't resolved, resolve it - if (!IsResolved()) + FileSpec resolved_lhs(*this); + + // If "this" isn't resolved, resolve it + if (!IsResolved()) + { + if (resolved_lhs.ResolvePath()) { - 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; + // 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); } - - FileSpec resolved_rhs(rhs); - if (!rhs.IsResolved()) + else + return false; + } + + FileSpec resolved_rhs(rhs); + if (!rhs.IsResolved()) + { + if (resolved_rhs.ResolvePath()) { - 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; + // 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); } - - // 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 resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory(); + else + return false; } - 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); } //------------------------------------------------------------------ @@ -507,6 +605,9 @@ 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 @@ -516,32 +617,35 @@ FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) if (full || (a.m_directory && b.m_directory)) { - result = ConstString::Compare(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); + 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 a.m_filename == b.m_filename; + return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); else if (remove_backups == false) return a == b; else { - if (a.m_filename != b.m_filename) + if (!ConstString::Equals(a.m_filename, b.m_filename, case_sensitive)) return false; - if (a.m_directory == b.m_directory) + if (ConstString::Equals(a.m_directory, b.m_directory, case_sensitive)) return true; ConstString a_without_dots; ConstString b_without_dots; RemoveBackupDots (a.m_directory, a_without_dots); RemoveBackupDots (b.m_directory, b_without_dots); - return a_without_dots == b_without_dots; + return ConstString::Equals(a_without_dots, b_without_dots, case_sensitive); } } @@ -670,7 +774,7 @@ FileSpec::Dump(Stream *s) const { std::string path{GetPath(true)}; s->PutCString(path.c_str()); - char path_separator = GetPathSeparator(m_syntax); + char path_separator = GetPrefferedPathSeparator(m_syntax); if (!m_filename && !path.empty() && path.back() != path_separator) s->PutChar(path_separator); } @@ -797,7 +901,10 @@ FileSpec::IsSymbolicLink () const return false; #ifdef _WIN32 - auto attrs = ::GetFileAttributes (resolved_path); + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) + return false; + auto attrs = ::GetFileAttributesW(wpath.c_str()); if (attrs == INVALID_FILE_ATTRIBUTES) return false; @@ -900,11 +1007,10 @@ void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const { path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end()); - if (m_directory) - path.insert(path.end(), '/'); + if (m_directory && m_filename && !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + path.insert(path.end(), GetPrefferedPathSeparator(m_syntax)); path.append(m_filename.GetStringRef().begin(), m_filename.GetStringRef().end()); Normalize(path, m_syntax); - if (path.size() > 1 && path.back() == '/') path.pop_back(); if (denormalize && !path.empty()) Denormalize(path, m_syntax); } @@ -1096,12 +1202,18 @@ FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const { if (dir_path && dir_path[0]) { -#if _WIN32 +#ifdef _WIN32 std::string szDir(dir_path); szDir += "\\*"; - WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd); + 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) { @@ -1113,12 +1225,12 @@ FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const FileSpec::FileType file_type = eFileTypeUnknown; if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - size_t len = strlen(ffd.cFileName); + size_t len = wcslen(ffd.cFileName); - if (len == 1 && ffd.cFileName[0] == '.') + if (len == 1 && ffd.cFileName[0] == L'.') continue; - if (len == 2 && ffd.cFileName[0] == '.' && ffd.cFileName[1] == '.') + if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') continue; file_type = eFileTypeDirectory; @@ -1132,12 +1244,19 @@ FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const file_type = eFileTypeRegular; } - char child_path[MAX_PATH]; - const int child_path_len = ::snprintf (child_path, sizeof(child_path), "%s\\%s", dir_path, ffd.cFileName); - if (child_path_len < (int)(sizeof(child_path) - 1)) + std::string fileName; + if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) + { + continue; + } + + std::vector<char> child_path(PATH_MAX); + const int child_path_len = + ::snprintf(child_path.data(), child_path.size(), "%s\\%s", dir_path, fileName.c_str()); + if (child_path_len < (int)(child_path.size() - 1)) { // Don't resolve the file type or path - FileSpec child_path_spec (child_path, false); + FileSpec child_path_spec(child_path.data(), false); EnumerateDirectoryResult result = callback (file_type, child_path_spec); @@ -1150,7 +1269,8 @@ FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const 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) + if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == + eEnumerateDirectoryResultQuit) { // The subdirectory returned Quit, which means to // stop all directory enumerations at all levels. @@ -1167,7 +1287,7 @@ FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const return eEnumerateDirectoryResultQuit; } } - } while (FindNextFile(hFind, &ffd) != 0); + } while (FindNextFileW(hFind, &ffd) != 0); FindClose(hFind); #else @@ -1313,17 +1433,9 @@ FileSpec::EnumerateDirectory FileSpec FileSpec::CopyByAppendingPathComponent (const char *new_path) const { - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return FileSpec(new_path,resolve); - StreamString stream; - if (m_filename.IsEmpty()) - stream.Printf("%s/%s",m_directory.GetCString(),new_path); - else if (m_directory.IsEmpty()) - stream.Printf("%s/%s",m_filename.GetCString(),new_path); - else - stream.Printf("%s/%s/%s",m_directory.GetCString(), m_filename.GetCString(),new_path); - return FileSpec(stream.GetData(),resolve); + FileSpec ret = *this; + ret.AppendPathComponent(new_path); + return ret; } FileSpec @@ -1424,20 +1536,26 @@ void FileSpec::AppendPathComponent(const char *new_path) { if (!new_path) return; - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) + + StreamString stream; + if (!m_directory.IsEmpty()) { - SetFile(new_path, resolve); - return; + stream.PutCString(m_directory.GetCString()); + if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + stream.PutChar(GetPrefferedPathSeparator(m_syntax)); } - StreamString stream; - if (m_filename.IsEmpty() || (m_filename.GetLength() == 1 && m_filename.GetCString()[0] == '.')) - stream.Printf("%s/%s", m_directory.GetCString(), new_path); - else if (m_directory.IsEmpty()) - stream.Printf("%s/%s", m_filename.GetCString(), new_path); - else - stream.Printf("%s/%s/%s", m_directory.GetCString(), m_filename.GetCString(), new_path); - SetFile(stream.GetData(), resolve); + + if (!m_filename.IsEmpty()) + { + stream.PutCString(m_filename.GetCString()); + if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) + stream.PutChar(GetPrefferedPathSeparator(m_syntax)); + } + + stream.PutCString(new_path); + + const bool resolve = false; + SetFile(stream.GetData(), resolve, m_syntax); } void diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index e89f4def478c..656caa5e0d19 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -39,8 +39,10 @@ #include <pthread_np.h> #endif -// C++ includes -#include <limits> +// C++ Includes + +// Other libraries and framework includes +// Project includes #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" @@ -91,7 +93,6 @@ struct MonitorInfo { lldb::pid_t pid; // The process ID to monitor Host::MonitorChildProcessCallback callback; // The callback function to call when "pid" exits or signals - void *callback_baton; // The callback baton for the callback function bool monitor_signals; // If true, call the callback when "pid" gets signaled. }; @@ -99,13 +100,13 @@ static thread_result_t MonitorChildProcessThreadFunction (void *arg); HostThread -Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals) +Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, + bool monitor_signals) { MonitorInfo * info_ptr = new MonitorInfo(); info_ptr->pid = pid; info_ptr->callback = callback; - info_ptr->callback_baton = callback_baton; info_ptr->monitor_signals = monitor_signals; char thread_name[256]; @@ -182,7 +183,6 @@ MonitorChildProcessThreadFunction (void *arg) MonitorInfo *info = (MonitorInfo *)arg; const Host::MonitorChildProcessCallback callback = info->callback; - void * const callback_baton = info->callback_baton; const bool monitor_signals = info->monitor_signals; assert (info->pid <= UINT32_MAX); @@ -283,8 +283,8 @@ MonitorChildProcessThreadFunction (void *arg) { bool callback_return = false; if (callback) - callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status); - + callback_return = callback(wait_pid, exited, signal, exit_status); + // If our process exited, then this thread should exit if (exited && wait_pid == abs(pid)) { @@ -498,7 +498,6 @@ struct ShellInfo { ShellInfo () : process_reaped (false), - can_delete (false), pid (LLDB_INVALID_PROCESS_ID), signo(-1), status(-1) @@ -506,33 +505,23 @@ struct ShellInfo } lldb_private::Predicate<bool> process_reaped; - lldb_private::Predicate<bool> can_delete; lldb::pid_t pid; int signo; int status; }; static bool -MonitorShellCommand (void *callback_baton, - lldb::pid_t pid, - bool exited, // True if the process did exit - int signo, // Zero for no signal - int status) // Exit value of process if signal is zero +MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid, + bool exited, // True if the process did exit + int signo, // Zero for no signal + int status) // Exit value of process if signal is zero { - ShellInfo *shell_info = (ShellInfo *)callback_baton; shell_info->pid = pid; shell_info->signo = signo; shell_info->status = status; // Let the thread running Host::RunShellCommand() know that the process // exited and that ShellInfo has been filled in by broadcasting to it - shell_info->process_reaped.SetValue(1, eBroadcastAlways); - // Now wait for a handshake back from that thread running Host::RunShellCommand - // so we know that we can delete shell_info_ptr - shell_info->can_delete.WaitForValueEqualTo(true); - // Sleep a bit to allow the shell_info->can_delete.SetValue() to complete... - usleep(1000); - // Now delete the shell info that was passed into this function - delete shell_info; + shell_info->process_reaped.SetValue(true, eBroadcastAlways); return true; } @@ -615,13 +604,14 @@ Host::RunShellCommand(const Args &args, launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); } - - // The process monitor callback will delete the 'shell_info_ptr' below... - std::unique_ptr<ShellInfo> shell_info_ap (new ShellInfo()); - + + std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo()); const bool monitor_signals = false; - launch_info.SetMonitorProcessCallback(MonitorShellCommand, shell_info_ap.get(), monitor_signals); - + launch_info.SetMonitorProcessCallback(std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4), + monitor_signals); + error = LaunchProcess (launch_info); const lldb::pid_t pid = launch_info.GetProcessID(); @@ -630,11 +620,6 @@ Host::RunShellCommand(const Args &args, if (error.Success()) { - // The process successfully launched, so we can defer ownership of - // "shell_info" to the MonitorShellCommand callback function that will - // get called when the process dies. We release the unique pointer as it - // doesn't need to delete the ShellInfo anymore. - ShellInfo *shell_info = shell_info_ap.release(); TimeValue *timeout_ptr = nullptr; TimeValue timeout_time(TimeValue::Now()); if (timeout_sec > 0) { @@ -642,7 +627,7 @@ Host::RunShellCommand(const Args &args, timeout_ptr = &timeout_time; } bool timed_out = false; - shell_info->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out); + shell_info_sp->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out); if (timed_out) { error.SetErrorString("timed out waiting for shell command to complete"); @@ -653,16 +638,16 @@ Host::RunShellCommand(const Args &args, timeout_time = TimeValue::Now(); timeout_time.OffsetWithSeconds(1); timed_out = false; - shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out); + shell_info_sp->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out); } else { if (status_ptr) - *status_ptr = shell_info->status; - + *status_ptr = shell_info_sp->status; + if (signo_ptr) - *signo_ptr = shell_info->signo; - + *signo_ptr = shell_info_sp->signo; + if (command_output_ptr) { command_output_ptr->clear(); @@ -683,14 +668,10 @@ Host::RunShellCommand(const Args &args, } } } - shell_info->can_delete.SetValue(true, eBroadcastAlways); } if (FileSystem::GetFileExists(output_file_spec)) FileSystem::Unlink(output_file_spec); - // Handshake with the monitor thread, or just let it know in advance that - // it can delete "shell_info" in case we timed out and were not able to kill - // the process... return error; } diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp index f7ba755b5bab..2bff4d9a670f 100644 --- a/source/Host/common/HostInfoBase.cpp +++ b/source/Host/common/HostInfoBase.cpp @@ -31,19 +31,6 @@ using namespace lldb_private; namespace { - void - CleanupProcessSpecificLLDBTempDir() - { - // Get the process specific LLDB temporary directory and delete it. - FileSpec tmpdir_file_spec; - if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) - return; - - // 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(tmpdir_file_spec, true); - } - //---------------------------------------------------------------------- // The HostInfoBaseFields is a work around for windows not supporting // static variables correctly in a thread safe way. Really each of the @@ -54,6 +41,16 @@ namespace struct HostInfoBaseFields { + ~HostInfoBaseFields() + { + if (m_lldb_process_tmp_dir.Exists()) + { + // 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); + } + } + uint32_t m_number_cpus; std::string m_vendor_string; std::string m_os_string; @@ -82,6 +79,13 @@ HostInfoBase::Initialize() g_fields = new HostInfoBaseFields(); } +void +HostInfoBase::Terminate() +{ + delete g_fields; + g_fields = nullptr; +} + uint32_t HostInfoBase::GetNumberCPUS() { @@ -335,9 +339,6 @@ HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) return false; - // Make an atexit handler to clean up the process specify LLDB temp dir - // and all of its contents. - ::atexit(CleanupProcessSpecificLLDBTempDir); file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); return true; } @@ -419,6 +420,7 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6 case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::sparcv9: + case llvm::Triple::systemz: arch_64.SetTriple(triple); break; } diff --git a/source/Host/common/HostProcess.cpp b/source/Host/common/HostProcess.cpp index 58a214693a52..0262e1c03c20 100644 --- a/source/Host/common/HostProcess.cpp +++ b/source/Host/common/HostProcess.cpp @@ -49,9 +49,9 @@ bool HostProcess::IsRunning() const } HostThread -HostProcess::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +HostProcess::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { - return m_native_process->StartMonitoring(callback, callback_baton, monitor_signals); + return m_native_process->StartMonitoring(callback, monitor_signals); } HostNativeProcessBase &HostProcess::GetNativeProcess() diff --git a/source/Host/common/MonitoringProcessLauncher.cpp b/source/Host/common/MonitoringProcessLauncher.cpp index 0fad44a9ec08..2845155987e3 100644 --- a/source/Host/common/MonitoringProcessLauncher.cpp +++ b/source/Host/common/MonitoringProcessLauncher.cpp @@ -75,12 +75,10 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, E Host::MonitorChildProcessCallback callback = launch_info.GetMonitorProcessCallback(); - void *baton = nullptr; bool monitor_signals = false; if (callback) { // If the ProcessLaunchInfo specified a callback, use that. - baton = launch_info.GetMonitorProcessBaton(); monitor_signals = launch_info.GetMonitorSignals(); } else @@ -88,7 +86,7 @@ MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, E callback = Process::SetProcessExitStatus; } - process.StartMonitoring(callback, baton, monitor_signals); + process.StartMonitoring(callback, monitor_signals); if (log) log->PutCString("started monitoring child process."); } diff --git a/source/Host/common/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp index 52b9baf5f537..67873a06dd27 100644 --- a/source/Host/common/NativeBreakpointList.cpp +++ b/source/Host/common/NativeBreakpointList.cpp @@ -17,8 +17,7 @@ using namespace lldb; using namespace lldb_private; -NativeBreakpointList::NativeBreakpointList () : - m_mutex (Mutex::eMutexTypeRecursive) +NativeBreakpointList::NativeBreakpointList() : m_mutex() { } @@ -29,7 +28,7 @@ NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware if (log) log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false"); - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); // Check if the breakpoint is already set. auto iter = m_breakpoints.find (addr); @@ -72,7 +71,7 @@ NativeBreakpointList::DecRef (lldb::addr_t addr) if (log) log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); // Check if the breakpoint is already set. auto iter = m_breakpoints.find (addr); @@ -136,7 +135,7 @@ NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr) if (log) log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); // Ensure we have said breakpoint. auto iter = m_breakpoints.find (addr); @@ -159,7 +158,7 @@ NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr) if (log) log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); // Ensure we have said breakpoint. auto iter = m_breakpoints.find (addr); @@ -182,7 +181,7 @@ NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &brea if (log) log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); // Ensure we have said breakpoint. auto iter = m_breakpoints.find (addr); diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp index 7d2f4012bf85..dfac0cb5645c 100644 --- a/source/Host/common/NativeProcessProtocol.cpp +++ b/source/Host/common/NativeProcessProtocol.cpp @@ -26,22 +26,22 @@ using namespace lldb_private; // NativeProcessProtocol Members // ----------------------------------------------------------------------------- -NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) : - m_pid (pid), - m_threads (), - m_current_thread_id (LLDB_INVALID_THREAD_ID), - m_threads_mutex (Mutex::eMutexTypeRecursive), - m_state (lldb::eStateInvalid), - m_state_mutex (Mutex::eMutexTypeRecursive), - m_exit_type (eExitTypeInvalid), - m_exit_status (0), - m_exit_description (), - m_delegates_mutex (Mutex::eMutexTypeRecursive), - m_delegates (), - m_breakpoint_list (), - m_watchpoint_list (), - m_terminal_fd (-1), - m_stop_id (0) +NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid) + : m_pid(pid), + m_threads(), + m_current_thread_id(LLDB_INVALID_THREAD_ID), + m_threads_mutex(), + m_state(lldb::eStateInvalid), + m_state_mutex(), + m_exit_type(eExitTypeInvalid), + m_exit_status(0), + m_exit_description(), + m_delegates_mutex(), + m_delegates(), + m_breakpoint_list(), + m_watchpoint_list(), + m_terminal_fd(-1), + m_stop_id(0) { } @@ -117,7 +117,7 @@ NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char NativeThreadProtocolSP NativeProcessProtocol::GetThreadAtIndex (uint32_t idx) { - Mutex::Locker locker (m_threads_mutex); + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); if (idx < m_threads.size ()) return m_threads[idx]; return NativeThreadProtocolSP (); @@ -137,7 +137,7 @@ NativeProcessProtocol::GetThreadByIDUnlocked (lldb::tid_t tid) NativeThreadProtocolSP NativeProcessProtocol::GetThreadByID (lldb::tid_t tid) { - Mutex::Locker locker (m_threads_mutex); + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); return GetThreadByIDUnlocked (tid); } @@ -221,7 +221,7 @@ NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t w // conceivable that if there are more threads than hardware // watchpoints available, some of the threads will fail to set // hardware watchpoints while software ones may be available. - Mutex::Locker locker (m_threads_mutex); + 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!"); @@ -276,7 +276,7 @@ NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) Error overall_error; - Mutex::Locker locker (m_threads_mutex); + 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!"); @@ -300,7 +300,7 @@ NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) bool NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate) { - Mutex::Locker locker (m_delegates_mutex); + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ()) return false; @@ -312,7 +312,7 @@ NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate) bool NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate) { - Mutex::Locker locker (m_delegates_mutex); + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); const auto initial_size = m_delegates.size (); m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ()); @@ -327,7 +327,7 @@ NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType s { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - Mutex::Locker locker (m_delegates_mutex); + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); for (auto native_delegate: m_delegates) native_delegate->ProcessStateChanged (this, state); @@ -354,7 +354,7 @@ NativeProcessProtocol::NotifyDidExec () log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__); { - Mutex::Locker locker (m_delegates_mutex); + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); for (auto native_delegate: m_delegates) native_delegate->DidExec (this); } @@ -394,14 +394,14 @@ NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr) lldb::StateType NativeProcessProtocol::GetState () const { - Mutex::Locker locker (m_state_mutex); + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); return m_state; } void NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) { - Mutex::Locker locker (m_state_mutex); + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); if (state == m_state) return; @@ -426,8 +426,8 @@ NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) uint32_t NativeProcessProtocol::GetStopID () const { - Mutex::Locker locker (m_state_mutex); - return m_stop_id; + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); + return m_stop_id; } void diff --git a/source/Host/common/OptionParser.cpp b/source/Host/common/OptionParser.cpp index a9784592a738..16a29a1583d5 100644 --- a/source/Host/common/OptionParser.cpp +++ b/source/Host/common/OptionParser.cpp @@ -16,10 +16,10 @@ using namespace lldb_private; void -OptionParser::Prepare(Mutex::Locker &locker) +OptionParser::Prepare(std::unique_lock<std::mutex> &lock) { - static Mutex g_mutex(Mutex::eMutexTypeNormal); - locker.Lock(g_mutex); + static std::mutex g_mutex; + lock = std::unique_lock<std::mutex>(g_mutex); #ifdef __GLIBC__ optind = 0; #else diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp index 91a5e37424e6..ea049ae6933e 100644 --- a/source/Host/common/Socket.cpp +++ b/source/Host/common/Socket.cpp @@ -268,7 +268,7 @@ Socket::DecodeHostAndPort(llvm::StringRef host_and_port, { bool ok = false; port = StringConvert::ToUInt32 (port_str.c_str(), UINT32_MAX, 10, &ok); - if (ok && port < UINT16_MAX) + if (ok && port <= UINT16_MAX) { if (error_ptr) error_ptr->Clear(); diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp index c8b1687c378e..1dc43ea6294c 100644 --- a/source/Host/common/SocketAddress.cpp +++ b/source/Host/common/SocketAddress.cpp @@ -185,14 +185,12 @@ SocketAddress::GetIPAddress () const { case AF_INET: if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, sizeof(str))) - { return str; - } + break; case AF_INET6: if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, sizeof(str))) - { return str; - } + break; } return ""; } diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp index 5a6f78372b3f..51cb34ffe6dd 100644 --- a/source/Host/common/SoftwareBreakpoint.cpp +++ b/source/Host/common/SoftwareBreakpoint.cpp @@ -12,7 +12,6 @@ #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Host/Debug.h" -#include "lldb/Host/Mutex.h" #include "lldb/Host/common/NativeProcessProtocol.h" diff --git a/source/Host/common/TCPSocket.cpp b/source/Host/common/TCPSocket.cpp index b23055ee7d87..07b0cdf908f5 100644 --- a/source/Host/common/TCPSocket.cpp +++ b/source/Host/common/TCPSocket.cpp @@ -112,9 +112,6 @@ TCPSocket::Connect(llvm::StringRef name) if (!DecodeHostAndPort (name, host_str, port_str, port, &error)) return error; - // Enable local address reuse - SetOptionReuseAddress(); - struct sockaddr_in sa; ::memset (&sa, 0, sizeof (sa)); sa.sin_family = kDomain; diff --git a/source/Host/common/UDPSocket.cpp b/source/Host/common/UDPSocket.cpp index 8297232ae723..9a2028e97a40 100644 --- a/source/Host/common/UDPSocket.cpp +++ b/source/Host/common/UDPSocket.cpp @@ -27,7 +27,7 @@ namespace { const int kDomain = AF_INET; const int kType = SOCK_DGRAM; -const Error kNotSupported("Not supported"); +static const char *g_not_supported_error = "Not supported"; } @@ -55,19 +55,19 @@ UDPSocket::Send(const void *buf, const size_t num_bytes) Error UDPSocket::Connect(llvm::StringRef name) { - return kNotSupported; + return Error("%s", g_not_supported_error); } Error UDPSocket::Listen(llvm::StringRef name, int backlog) { - return kNotSupported; + return Error("%s", g_not_supported_error); } Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) { - return kNotSupported; + return Error("%s", g_not_supported_error); } Error diff --git a/source/Host/linux/Host.cpp b/source/Host/linux/Host.cpp index cb7369fe7aec..62bf5362de01 100644 --- a/source/Host/linux/Host.cpp +++ b/source/Host/linux/Host.cpp @@ -8,12 +8,14 @@ //===----------------------------------------------------------------------===// // C Includes -#include <stdio.h> -#include <sys/utsname.h> -#include <sys/types.h> -#include <sys/stat.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> // C++ Includes // Other libraries and framework includes @@ -291,15 +293,25 @@ GetProcessAndStatInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info, Proce ::memset (&stat_info, 0, sizeof(stat_info)); stat_info.ppid = LLDB_INVALID_PROCESS_ID; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + // Use special code here because proc/[pid]/exe is a symbolic link. char link_path[PATH_MAX]; char exe_path[PATH_MAX] = ""; if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", pid) <= 0) + { + if (log) + log->Printf("%s: failed to sprintf pid %" PRIu64, __FUNCTION__, pid); return false; + } ssize_t len = readlink (link_path, exe_path, sizeof(exe_path) - 1); if (len <= 0) + { + if (log) + log->Printf("%s: failed to read link %s: %s", __FUNCTION__, link_path, strerror(errno)); return false; + } // readlink does not append a null byte. exe_path[len] = 0; diff --git a/source/Host/linux/HostInfoLinux.cpp b/source/Host/linux/HostInfoLinux.cpp index 4732a2a571b6..0d0ba3323d6c 100644 --- a/source/Host/linux/HostInfoLinux.cpp +++ b/source/Host/linux/HostInfoLinux.cpp @@ -235,7 +235,7 @@ HostInfoLinux::ComputeSupportExeDirectory(FileSpec &file_spec) bool HostInfoLinux::ComputeSystemPluginsDirectory(FileSpec &file_spec) { - FileSpec temp_file("/usr/lib/lldb", true); + FileSpec temp_file("/usr/lib/lldb/plugins", true); file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str()); return true; } diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm index 2db27a276e4a..8bd2e2f2b257 100644 --- a/source/Host/macosx/Host.mm +++ b/source/Host/macosx/Host.mm @@ -556,10 +556,10 @@ LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &lau // On MacOSX CrashReporter will display a string for each shared library if // the shared library has an exported symbol named "__crashreporter_info__". -static Mutex& -GetCrashReporterMutex () +static std::mutex & +GetCrashReporterMutex() { - static Mutex g_mutex; + static std::mutex g_mutex; return g_mutex; } @@ -573,8 +573,8 @@ void Host::SetCrashDescriptionWithFormat (const char *format, ...) { static StreamString g_crash_description; - Mutex::Locker locker (GetCrashReporterMutex ()); - + std::lock_guard<std::mutex> guard(GetCrashReporterMutex()); + if (format) { va_list args; @@ -593,7 +593,7 @@ Host::SetCrashDescriptionWithFormat (const char *format, ...) void Host::SetCrashDescription (const char *cstr) { - Mutex::Locker locker (GetCrashReporterMutex ()); + std::lock_guard<std::mutex> guard(GetCrashReporterMutex()); static std::string g_crash_description; if (cstr) { @@ -1334,7 +1334,6 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) callback = Process::SetProcessExitStatus; StartMonitoringChildProcess (callback, - NULL, pid, monitor_signals); } @@ -1449,7 +1448,8 @@ Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) } HostThread -Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals) +Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, + bool monitor_signals) { unsigned long mask = DISPATCH_PROC_EXIT; if (monitor_signals) @@ -1458,26 +1458,25 @@ Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, vo Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); - dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC, - pid, - mask, + dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC, + pid, + mask, ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0)); if (log) - log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n", - callback, - callback_baton, - (int)pid, - monitor_signals, - source); + log->Printf("Host::StartMonitoringChildProcess " + "(callback, pid=%i, monitor_signals=%i) " + "source = %p\n", + static_cast<int>(pid), monitor_signals, reinterpret_cast<void *>(source)); if (source) { + Host::MonitorChildProcessCallback callback_copy = callback; ::dispatch_source_set_cancel_handler (source, ^{ ::dispatch_release (source); }); ::dispatch_source_set_event_handler (source, ^{ - + int status= 0; int wait_pid = 0; bool cancel = false; @@ -1523,10 +1522,10 @@ Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, vo status_cstr, signal, exit_status); - - if (callback) - cancel = callback (callback_baton, pid, exited, signal, exit_status); - + + if (callback_copy) + cancel = callback_copy(pid, exited, signal, exit_status); + if (exited || cancel) { ::dispatch_source_cancel(source); diff --git a/source/Host/macosx/HostInfoMacOSX.mm b/source/Host/macosx/HostInfoMacOSX.mm index f5a0540e8774..8b664f0a44bd 100644 --- a/source/Host/macosx/HostInfoMacOSX.mm +++ b/source/Host/macosx/HostInfoMacOSX.mm @@ -370,3 +370,9 @@ HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch } } } + +uint32_t +HostInfoMacOSX::GetMaxThreadNameLength() +{ + return 64; +} diff --git a/source/Host/macosx/ThisThread.cpp b/source/Host/macosx/ThisThread.cpp index 95c7f2bf1e38..6f1c88f67309 100644 --- a/source/Host/macosx/ThisThread.cpp +++ b/source/Host/macosx/ThisThread.cpp @@ -10,30 +10,20 @@ #include "lldb/Host/ThisThread.h" #include <pthread.h> +#include "llvm/ADT/SmallVector.h" using namespace lldb_private; void ThisThread::SetName(llvm::StringRef name) { -#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 - ::pthread_setname_np(name); +#if defined (__APPLE__) + ::pthread_setname_np(name.str().c_str()); #endif } void ThisThread::GetName(llvm::SmallVectorImpl<char> &name) { -#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 - char pthread_name[1024]; - dispatch_queue_t current_queue = ::dispatch_get_current_queue(); - if (current_queue != NULL) - { - const char *queue_name = dispatch_queue_get_label(current_queue); - if (queue_name && queue_name[0]) - { - name = queue_name; - } - } -#endif + // FIXME - implement this. } diff --git a/source/Host/netbsd/Makefile b/source/Host/netbsd/Makefile deleted file mode 100644 index 2502cc49c15b..000000000000 --- a/source/Host/netbsd/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -##===- source/Host/netbsd/Makefile --------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../../.. -LIBRARYNAME := lldbHostNetBSD -BUILD_ARCHIVE = 1 - -include $(LLDB_LEVEL)/Makefile diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index dbbd5a1dcc3c..52d65b1e9a97 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -79,12 +79,12 @@ GetURLAddress(const char *url, const char *scheme) } ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) - : Connection() - , m_pipe() - , m_mutex(Mutex::eMutexTypeRecursive) - , m_shutting_down(false) - , m_waiting_for_accept(false) - , m_child_processes_inherit(child_processes_inherit) + : Connection(), + m_pipe(), + m_mutex(), + m_shutting_down(false), + m_waiting_for_accept(false), + m_child_processes_inherit(child_processes_inherit) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); if (log) @@ -92,30 +92,30 @@ ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) } ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd) - : Connection() - , m_pipe() - , m_mutex(Mutex::eMutexTypeRecursive) - , m_shutting_down(false) - , m_waiting_for_accept(false) - , m_child_processes_inherit(false) + : Connection(), + m_pipe(), + m_mutex(), + m_shutting_down(false), + m_waiting_for_accept(false), + m_child_processes_inherit(false) { m_write_sp.reset(new File(fd, owns_fd)); m_read_sp.reset(new File(fd, false)); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); if (log) - log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", static_cast<void *>(this), fd, - owns_fd); + log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", + static_cast<void *>(this), fd, owns_fd); OpenCommandPipe(); } -ConnectionFileDescriptor::ConnectionFileDescriptor(Socket* socket) - : Connection() - , m_pipe() - , m_mutex(Mutex::eMutexTypeRecursive) - , m_shutting_down(false) - , m_waiting_for_accept(false) - , m_child_processes_inherit(false) +ConnectionFileDescriptor::ConnectionFileDescriptor(Socket *socket) + : Connection(), + m_pipe(), + m_mutex(), + m_shutting_down(false), + m_waiting_for_accept(false), + m_child_processes_inherit(false) { InitializeSocket(socket); } @@ -170,7 +170,7 @@ ConnectionFileDescriptor::IsConnected() const ConnectionStatus ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); if (log) log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s); @@ -374,10 +374,8 @@ ConnectionFileDescriptor::Disconnect(Error *error_ptr) m_shutting_down = true; - Mutex::Locker locker; - bool got_lock = locker.TryLock(m_mutex); - - if (!got_lock) + std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); + if (!locker.try_lock()) { if (m_pipe.CanWrite()) { @@ -392,7 +390,7 @@ ConnectionFileDescriptor::Disconnect(Error *error_ptr) log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.", static_cast<void *>(this)); } - locker.Lock(m_mutex); + locker.lock(); } Error error = m_read_sp->Close(); @@ -415,9 +413,8 @@ ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - Mutex::Locker locker; - bool got_lock = locker.TryLock(m_mutex); - if (!got_lock) + std::unique_lock<std::recursive_mutex> locker(m_mutex, std::defer_lock); + if (!locker.try_lock()) { if (log) log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this)); diff --git a/source/Host/posix/DomainSocket.cpp b/source/Host/posix/DomainSocket.cpp index b4427e305f3e..9dc147196c08 100644 --- a/source/Host/posix/DomainSocket.cpp +++ b/source/Host/posix/DomainSocket.cpp @@ -21,7 +21,7 @@ using namespace lldb_private; #ifdef __ANDROID__ // Android does not have SUN_LEN #ifndef SUN_LEN -#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path)) +#define SUN_LEN(ptr) (offsetof(struct sockaddr_un, sun_path) + strlen((ptr)->sun_path)) #endif #endif // #ifdef __ANDROID__ diff --git a/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp index 1f2e7db0e1e4..c8fa1bc9cf47 100644 --- a/source/Host/posix/FileSystem.cpp +++ b/source/Host/posix/FileSystem.cpp @@ -54,30 +54,32 @@ FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) switch (error.GetError()) { case ENOENT: - { - // Parent directory doesn't exist, so lets make it if we can - // Make the parent directory and try again - FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false}; - error = MakeDirectory(parent_file_spec, file_permissions); - if (error.Fail()) - return error; - // Try and make the directory again now that the parent directory was made successfully - if (::mkdir(file_spec.GetCString(), file_permissions) == -1) { - error.SetErrorToErrno(); + // Parent directory doesn't exist, so lets make it if we can + // Make the parent directory and try again + FileSpec parent_file_spec{file_spec.GetDirectory().GetCString(), false}; + error = MakeDirectory(parent_file_spec, file_permissions); + if (error.Fail()) + return error; + // Try and make the directory again now that the parent directory was made successfully + if (::mkdir(file_spec.GetCString(), file_permissions) == -1) + { + error.SetErrorToErrno(); + } return error; } - } + break; case EEXIST: - { - if (file_spec.IsDirectory()) - return Error{}; // It is a directory and it already exists - } + { + if (file_spec.IsDirectory()) + return Error(); // It is a directory and it already exists + } + break; } } return error; } - return Error{"empty path"}; + return Error("empty path"); } Error @@ -297,3 +299,15 @@ FileSystem::IsLocal(const FileSpec &spec) return false; } #endif + +FILE * +FileSystem::Fopen(const char *path, const char *mode) +{ + return ::fopen(path, mode); +} + +int +FileSystem::Stat(const char *path, struct stat *stats) +{ + return ::stat(path, stats); +} diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp index cfdbf5635ad1..d0ef2ca37061 100644 --- a/source/Host/posix/HostInfoPosix.cpp +++ b/source/Host/posix/HostInfoPosix.cpp @@ -242,3 +242,14 @@ HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec) return false; #endif } + +bool +HostInfoPosix::GetEnvironmentVar(const std::string &var_name, std::string &var) +{ + if (const char *pvar = ::getenv(var_name.c_str())) + { + var = std::string(pvar); + return true; + } + return false; +} diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp index 5761a79da27f..93844d9b99d3 100644 --- a/source/Host/posix/HostProcessPosix.cpp +++ b/source/Host/posix/HostProcessPosix.cpp @@ -107,7 +107,7 @@ bool HostProcessPosix::IsRunning() const } HostThread -HostProcessPosix::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +HostProcessPosix::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { - return Host::StartMonitoringChildProcess(callback, callback_baton, m_process, monitor_signals); + return Host::StartMonitoringChildProcess(callback, m_process, monitor_signals); } diff --git a/source/Host/posix/HostThreadPosix.cpp b/source/Host/posix/HostThreadPosix.cpp index 9c4892431938..f1a6d6f83142 100644 --- a/source/Host/posix/HostThreadPosix.cpp +++ b/source/Host/posix/HostThreadPosix.cpp @@ -53,13 +53,18 @@ Error HostThreadPosix::Cancel() { Error error; + if (IsJoinable()) + { #ifndef __ANDROID__ - int err = ::pthread_cancel(m_thread); - error.SetError(err, eErrorTypePOSIX); +#ifndef __FreeBSD__ + assert(false && "someone is calling HostThread::Cancel()"); +#endif + int err = ::pthread_cancel(m_thread); + error.SetError(err, eErrorTypePOSIX); #else - error.SetErrorString("HostThreadPosix::Cancel() not supported on Android"); + error.SetErrorString("HostThreadPosix::Cancel() not supported on Android"); #endif - + } return error; } @@ -67,8 +72,11 @@ Error HostThreadPosix::Detach() { Error error; - int err = ::pthread_detach(m_thread); - error.SetError(err, eErrorTypePOSIX); + if (IsJoinable()) + { + int err = ::pthread_detach(m_thread); + error.SetError(err, eErrorTypePOSIX); + } Reset(); return error; } diff --git a/source/Host/windows/ConnectionGenericFileWindows.cpp b/source/Host/windows/ConnectionGenericFileWindows.cpp index eebf3d4f633c..9743ed48b8ef 100644 --- a/source/Host/windows/ConnectionGenericFileWindows.cpp +++ b/source/Host/windows/ConnectionGenericFileWindows.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ConvertUTF.h" using namespace lldb; using namespace lldb_private; @@ -138,7 +139,15 @@ ConnectionGenericFile::Connect(const char *s, Error *error_ptr) // Open the file for overlapped access. If it does not exist, create it. We open it overlapped // so that we can issue asynchronous reads and then use WaitForMultipleObjects to allow the read // to be interrupted by an event object. - m_file = ::CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) + { + if (error_ptr) + error_ptr->SetError(1, eErrorTypeGeneric); + return eConnectionStatusError; + } + m_file = ::CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, + FILE_FLAG_OVERLAPPED, NULL); if (m_file == INVALID_HANDLE_VALUE) { if (error_ptr) diff --git a/source/Host/windows/FileSystem.cpp b/source/Host/windows/FileSystem.cpp index 2cca12b92711..3e881f5d9b2b 100644 --- a/source/Host/windows/FileSystem.cpp +++ b/source/Host/windows/FileSystem.cpp @@ -15,6 +15,8 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/windows/AutoHandle.h" + +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" using namespace lldb_private; @@ -22,6 +24,8 @@ using namespace lldb_private; const char * FileSystem::DEV_NULL = "nul"; +const char *FileSystem::PATH_CONVERSION_ERROR = "Error converting path between UTF-8 and native encoding"; + FileSpec::PathSyntax FileSystem::GetNativePathSyntax() { @@ -47,25 +51,32 @@ Error FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse) { Error error; + std::wstring path_buffer; + if (!llvm::ConvertUTF8toWide(file_spec.GetPath(), path_buffer)) + { + error.SetErrorString(PATH_CONVERSION_ERROR); + return error; + } if (!recurse) { - BOOL result = ::RemoveDirectory(file_spec.GetCString()); + BOOL result = ::RemoveDirectoryW(path_buffer.c_str()); if (!result) error.SetError(::GetLastError(), lldb::eErrorTypeWin32); } else { // SHFileOperation() accepts a list of paths, and so must be double-null-terminated to - // indicate the end of the list. - std::string path_buffer{file_spec.GetPath()}; + // indicate the end of the list. The first null terminator is there only in the backing + // store but not the actual vector contents, and so we need to push twice. + path_buffer.push_back(0); path_buffer.push_back(0); - SHFILEOPSTRUCT shfos = {0}; + SHFILEOPSTRUCTW shfos = {0}; shfos.wFunc = FO_DELETE; - shfos.pFrom = path_buffer.c_str(); + shfos.pFrom = (LPCWSTR)path_buffer.data(); shfos.fFlags = FOF_NO_UI; - int result = ::SHFileOperation(&shfos); + int result = ::SHFileOperationW(&shfos); // TODO(zturner): Correctly handle the intricacies of SHFileOperation return values. if (result != 0) error.SetErrorStringWithFormat("SHFileOperation failed"); @@ -121,7 +132,10 @@ Error FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) { Error error; - if (!::CreateHardLink(src.GetCString(), dst.GetCString(), nullptr)) + std::wstring wsrc, wdst; + if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) + error.SetErrorString(PATH_CONVERSION_ERROR); + else if (!::CreateHardLinkW(wsrc.c_str(), wdst.c_str(), nullptr)) error.SetError(::GetLastError(), lldb::eErrorTypeWin32); return error; } @@ -129,13 +143,12 @@ FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst) int FileSystem::GetHardlinkCount(const FileSpec &file_spec) { - HANDLE file_handle = ::CreateFile(file_spec.GetCString(), - FILE_READ_ATTRIBUTES, - FILE_SHARE_READ, - nullptr, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - nullptr); + std::wstring path; + if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) + return -1; + + HANDLE file_handle = ::CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr); if (file_handle == INVALID_HANDLE_VALUE) return -1; @@ -152,7 +165,12 @@ Error FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { Error error; - DWORD attrib = ::GetFileAttributes(dst.GetCString()); + std::wstring wsrc, wdst; + if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) + error.SetErrorString(PATH_CONVERSION_ERROR); + if (error.Fail()) + return error; + DWORD attrib = ::GetFileAttributesW(wdst.c_str()); if (attrib == INVALID_FILE_ATTRIBUTES) { error.SetError(::GetLastError(), lldb::eErrorTypeWin32); @@ -160,7 +178,7 @@ FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) } bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; - BOOL result = ::CreateSymbolicLink(src.GetCString(), dst.GetCString(), flag); + BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag); if (!result) error.SetError(::GetLastError(), lldb::eErrorTypeWin32); return error; @@ -170,7 +188,13 @@ Error FileSystem::Unlink(const FileSpec &file_spec) { Error error; - BOOL result = ::DeleteFile(file_spec.GetCString()); + std::wstring path; + if (!llvm::ConvertUTF8toWide(file_spec.GetCString(), path)) + { + error.SetErrorString(PATH_CONVERSION_ERROR); + return error; + } + BOOL result = ::DeleteFileW(path.c_str()); if (!result) error.SetError(::GetLastError(), lldb::eErrorTypeWin32); return error; @@ -180,23 +204,31 @@ Error FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { Error error; - HANDLE h = ::CreateFile(src.GetCString(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT, NULL); + std::wstring wsrc; + if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) + { + error.SetErrorString(PATH_CONVERSION_ERROR); + return error; + } + + HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, NULL); if (h == INVALID_HANDLE_VALUE) { error.SetError(::GetLastError(), lldb::eErrorTypeWin32); return error; } - char buf[PATH_MAX]; + std::vector<wchar_t> buf(PATH_MAX + 1); // Subtract 1 from the path length since this function does not add a null terminator. - DWORD result = ::GetFinalPathNameByHandle(h, buf, sizeof(buf) - 1, - FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + DWORD result = ::GetFinalPathNameByHandleW(h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + std::string path; if (result == 0) error.SetError(::GetLastError(), lldb::eErrorTypeWin32); + else if (!llvm::convertWideToUTF8(buf.data(), path)) + error.SetErrorString(PATH_CONVERSION_ERROR); else - dst.SetFile(buf, false); + dst.SetFile(path, false); ::CloseHandle(h); return error; @@ -219,3 +251,43 @@ FileSystem::IsLocal(const FileSpec &spec) return false; } + +FILE * +FileSystem::Fopen(const char *path, const char *mode) +{ + std::wstring wpath, wmode; + if (!llvm::ConvertUTF8toWide(path, wpath)) + return nullptr; + if (!llvm::ConvertUTF8toWide(mode, wmode)) + return nullptr; + FILE *file; + if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0) + return nullptr; + return file; +} + +int +FileSystem::Stat(const char *path, struct stat *stats) +{ + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) + { + errno = EINVAL; + return -EINVAL; + } + int stat_result; +#ifdef _USE_32BIT_TIME_T + struct _stat32 file_stats; + stat_result = ::_wstat32(wpath.c_str(), &file_stats); +#else + struct _stat64i32 file_stats; + stat_result = ::_wstat64i32(wpath.c_str(), &file_stats); +#endif + if (stat_result == 0) + { + static_assert(sizeof(struct stat) == sizeof(file_stats), + "stat and _stat32/_stat64i32 must have the same layout"); + *stats = *reinterpret_cast<struct stat *>(&file_stats); + } + return stat_result; +} diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp index 2c9a139df256..1b4eeb8d4f60 100644 --- a/source/Host/windows/Host.cpp +++ b/source/Host/windows/Host.cpp @@ -26,6 +26,8 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredData.h" +#include "llvm/Support/ConvertUTF.h" + // Windows includes #include <TlHelp32.h> @@ -68,12 +70,11 @@ namespace bool GetExecutableForProcess(const AutoHandle &handle, std::string &path) { // Get the process image path. MAX_PATH isn't long enough, paths can actually be up to 32KB. - std::vector<char> buffer(32768); + std::vector<wchar_t> buffer(PATH_MAX); DWORD dwSize = buffer.size(); - if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize)) + if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize)) return false; - path.assign(&buffer[0]); - return true; + return llvm::convertWideToUTF8(buffer.data(), path); } void GetProcessExecutableAndTriple(const AutoHandle &handle, ProcessInstanceInfo &process) @@ -156,15 +157,17 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr) if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)host_addr, &hmodule)) return module_filespec; - std::vector<char> buffer(MAX_PATH); + std::vector<wchar_t> buffer(PATH_MAX); DWORD chars_copied = 0; do { - chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size()); + chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size()); if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) buffer.resize(buffer.size() * 2); } while (chars_copied >= buffer.size()); - - module_filespec.SetFile(&buffer[0], false); + std::string path; + if (!llvm::convertWideToUTF8(buffer.data(), path)) + return module_filespec; + module_filespec.SetFile(path, false); return module_filespec; } @@ -177,23 +180,25 @@ Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstance if (!snapshot.IsValid()) return 0; - PROCESSENTRY32 pe = {0}; - pe.dwSize = sizeof(PROCESSENTRY32); - if (Process32First(snapshot.get(), &pe)) + PROCESSENTRY32W pe = {0}; + pe.dwSize = sizeof(PROCESSENTRY32W); + if (Process32FirstW(snapshot.get(), &pe)) { do { AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr); ProcessInstanceInfo process; - process.SetExecutableFile(FileSpec(pe.szExeFile, false), true); + std::string exeFile; + llvm::convertWideToUTF8(pe.szExeFile, exeFile); + process.SetExecutableFile(FileSpec(exeFile, false), true); process.SetProcessID(pe.th32ProcessID); process.SetParentProcessID(pe.th32ParentProcessID); GetProcessExecutableAndTriple(handle, process); if (match_info.MatchAllProcesses() || match_info.Matches(process)) process_infos.Append(process); - } while (Process32Next(snapshot.get(), &pe)); + } while (Process32NextW(snapshot.get(), &pe)); } return process_infos.GetSize(); } @@ -216,7 +221,8 @@ Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) } HostThread -Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals) +Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, + bool monitor_signals) { return HostThread(); } @@ -312,15 +318,21 @@ Host::GetEnvironment(StringList &env) { // The environment block on Windows is a contiguous buffer of NULL terminated strings, // where the end of the environment block is indicated by two consecutive NULLs. - LPCH environment_block = ::GetEnvironmentStrings(); + LPWCH environment_block = ::GetEnvironmentStringsW(); env.Clear(); - while (*environment_block != '\0') + while (*environment_block != L'\0') { - llvm::StringRef current_var(environment_block); + std::string current_var; + auto current_var_size = wcslen(environment_block) + 1; + if (!llvm::convertWideToUTF8(environment_block, current_var)) + { + environment_block += current_var_size; + continue; + } if (current_var[0] != '=') env.AppendString(current_var); - environment_block += current_var.size()+1; + environment_block += current_var_size; } return env.GetSize(); } diff --git a/source/Host/windows/HostInfoWindows.cpp b/source/Host/windows/HostInfoWindows.cpp index 6dce71d9172a..6b2190294081 100644 --- a/source/Host/windows/HostInfoWindows.cpp +++ b/source/Host/windows/HostInfoWindows.cpp @@ -9,18 +9,35 @@ #include "lldb/Host/windows/windows.h" +#include <objbase.h> + #include <mutex> // std::once #include "lldb/Host/windows/HostInfoWindows.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" using namespace lldb_private; FileSpec HostInfoWindows::m_program_filespec; +void +HostInfoWindows::Initialize() +{ + ::CoInitializeEx(nullptr, COINIT_MULTITHREADED); + HostInfoBase::Initialize(); +} + +void +HostInfoWindows::Terminate() +{ + HostInfoBase::Terminate(); + ::CoUninitialize(); +} + size_t HostInfoWindows::GetPageSize() { @@ -76,23 +93,24 @@ HostInfoWindows::GetOSKernelDescription(std::string &s) bool HostInfoWindows::GetHostname(std::string &s) { - char buffer[MAX_COMPUTERNAME_LENGTH + 1]; + wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; - if (!::GetComputerName(buffer, &dwSize)) + if (!::GetComputerNameW(buffer, &dwSize)) return false; - s.assign(buffer, buffer + dwSize); - return true; + return llvm::convertWideToUTF8(buffer, s); } FileSpec HostInfoWindows::GetProgramFileSpec() { static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - char buffer[PATH_MAX]; - ::GetModuleFileName(NULL, buffer, sizeof(buffer)); - m_program_filespec.SetFile(buffer, false); + std::call_once(g_once_flag, []() { + std::vector<wchar_t> buffer(PATH_MAX); + ::GetModuleFileNameW(NULL, buffer.data(), buffer.size()); + std::string path; + llvm::convertWideToUTF8(buffer.data(), path); + m_program_filespec.SetFile(path, false); }); return m_program_filespec; } @@ -100,7 +118,9 @@ HostInfoWindows::GetProgramFileSpec() FileSpec HostInfoWindows::GetDefaultShell() { - return FileSpec(::getenv("ComSpec"), false); + std::string shell; + GetEnvironmentVar("ComSpec", shell); + return FileSpec(shell, false); } bool @@ -116,3 +136,15 @@ HostInfoWindows::ComputePythonDirectory(FileSpec &file_spec) file_spec.GetDirectory().SetString(path.c_str()); return true; } + +bool +HostInfoWindows::GetEnvironmentVar(const std::string &var_name, std::string &var) +{ + std::wstring wvar_name; + if (!llvm::ConvertUTF8toWide(var_name, wvar_name)) + return false; + + if (const wchar_t *wvar = _wgetenv(wvar_name.c_str())) + return llvm::convertWideToUTF8(wvar, var); + return false; +} diff --git a/source/Host/windows/HostProcessWindows.cpp b/source/Host/windows/HostProcessWindows.cpp index 0f81c18d34af..2878171cbe77 100644 --- a/source/Host/windows/HostProcessWindows.cpp +++ b/source/Host/windows/HostProcessWindows.cpp @@ -14,6 +14,7 @@ #include "lldb/Host/windows/HostProcessWindows.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ConvertUTF.h" #include <Psapi.h> @@ -23,8 +24,7 @@ namespace { struct MonitorInfo { - HostProcess::MonitorCallback callback; - void *baton; + Host::MonitorChildProcessCallback callback; HANDLE process_handle; }; } @@ -70,9 +70,15 @@ Error HostProcessWindows::GetMainModule(FileSpec &file_spec) const if (m_process == nullptr) error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32); - char path[MAX_PATH] = { 0 }; - if (::GetProcessImageFileName(m_process, path, llvm::array_lengthof(path))) - file_spec.SetFile(path, false); + std::vector<wchar_t> wpath(PATH_MAX); + if (::GetProcessImageFileNameW(m_process, wpath.data(), wpath.size())) + { + std::string path; + if (llvm::convertWideToUTF8(wpath.data(), path)) + file_spec.SetFile(path, false); + else + error.SetErrorString("Error converting path to UTF-8"); + } else error.SetError(::GetLastError(), lldb::eErrorTypeWin32); @@ -97,12 +103,11 @@ bool HostProcessWindows::IsRunning() const } HostThread -HostProcessWindows::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals) +HostProcessWindows::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { HostThread monitor_thread; MonitorInfo *info = new MonitorInfo; info->callback = callback; - info->baton = callback_baton; // Since the life of this HostProcessWindows instance and the life of the process may be different, duplicate the handle so that // the monitor thread can have ownership over its own copy of the handle. @@ -122,7 +127,7 @@ HostProcessWindows::MonitorThread(void *thread_arg) { ::WaitForSingleObject(info->process_handle, INFINITE); ::GetExitCodeProcess(info->process_handle, &exit_code); - info->callback(info->baton, ::GetProcessId(info->process_handle), true, 0, exit_code); + info->callback(::GetProcessId(info->process_handle), true, 0, exit_code); ::CloseHandle(info->process_handle); delete (info); } diff --git a/source/Host/windows/PipeWindows.cpp b/source/Host/windows/PipeWindows.cpp index d4afd6e74943..6ed8d0e83f3c 100644 --- a/source/Host/windows/PipeWindows.cpp +++ b/source/Host/windows/PipeWindows.cpp @@ -73,8 +73,8 @@ PipeWindows::CreateNew(llvm::StringRef name, bool child_process_inherit) // Always open for overlapped i/o. We implement blocking manually in Read and Write. DWORD read_mode = FILE_FLAG_OVERLAPPED; - m_read = - ::CreateNamedPipe(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL); + m_read = ::CreateNamedPipeA(pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, + 1024, 120 * 1000, NULL); if (INVALID_HANDLE_VALUE == m_read) return Error(::GetLastError(), eErrorTypeWin32); m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY); @@ -153,7 +153,8 @@ PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, boo if (is_read) { - m_read = ::CreateFile(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + m_read = + ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == m_read) return Error(::GetLastError(), eErrorTypeWin32); @@ -164,7 +165,8 @@ PipeWindows::OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, boo } else { - m_write = ::CreateFile(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + m_write = + ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == m_write) return Error(::GetLastError(), eErrorTypeWin32); diff --git a/source/Host/windows/ProcessLauncherWindows.cpp b/source/Host/windows/ProcessLauncherWindows.cpp index 355dd40544f9..caf0fc71e121 100644 --- a/source/Host/windows/ProcessLauncherWindows.cpp +++ b/source/Host/windows/ProcessLauncherWindows.cpp @@ -11,12 +11,38 @@ #include "lldb/Host/windows/ProcessLauncherWindows.h" #include "lldb/Target/ProcessLaunchInfo.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ConvertUTF.h" + #include <string> #include <vector> using namespace lldb; using namespace lldb_private; +namespace +{ +void +CreateEnvironmentBuffer(const Args &env, std::vector<char> &buffer) +{ + if (env.GetArgumentCount() == 0) + return; + + // Environment buffer is a null terminated list of null terminated strings + for (int i = 0; i < env.GetArgumentCount(); ++i) + { + std::wstring warg; + if (llvm::ConvertUTF8toWide(env.GetArgumentAtIndex(i), warg)) + { + buffer.insert(buffer.end(), (char *)warg.c_str(), (char *)(warg.c_str() + warg.size() + 1)); + } + } + // One null wchar_t (to end the block) is two null bytes + buffer.push_back(0); + buffer.push_back(0); +} +} + HostProcess ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) { @@ -45,14 +71,27 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, Erro startupinfo.wShowWindow = SW_HIDE; } - DWORD flags = CREATE_NEW_CONSOLE; + DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; if (launch_info.GetFlags().Test(eLaunchFlagDebug)) flags |= DEBUG_ONLY_THIS_PROCESS; + auto &env = const_cast<Args &>(launch_info.GetEnvironmentEntries()); + LPVOID env_block = nullptr; + ::CreateEnvironmentBuffer(env, environment); + if (!environment.empty()) + env_block = environment.data(); + executable = launch_info.GetExecutableFile().GetPath(); launch_info.GetArguments().GetQuotedCommandString(commandLine); - BOOL result = ::CreateProcessA(executable.c_str(), const_cast<char *>(commandLine.c_str()), NULL, NULL, TRUE, flags, NULL, - launch_info.GetWorkingDirectory().GetCString(), &startupinfo, &pi); + + std::wstring wexecutable, wcommandLine, wworkingDirectory; + llvm::ConvertUTF8toWide(executable, wexecutable); + llvm::ConvertUTF8toWide(commandLine, wcommandLine); + llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), wworkingDirectory); + + wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because CreateProcessW can modify it + BOOL result = ::CreateProcessW(wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block, + wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), &startupinfo, &pi); if (result) { // Do not call CloseHandle on pi.hProcess, since we want to pass that back through the HostProcess. @@ -100,6 +139,8 @@ ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, int flags = FILE_FLAG_WRITE_THROUGH; } - HANDLE result = ::CreateFile(path, access, share, &secattr, create, flags, NULL); + std::wstring wpath; + llvm::ConvertUTF8toWide(path, wpath); + HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, flags, NULL); return (result == INVALID_HANDLE_VALUE) ? NULL : result; } diff --git a/source/Host/windows/Windows.cpp b/source/Host/windows/Windows.cpp index 71bff7a9d2e2..2aebb10bcdd9 100644 --- a/source/Host/windows/Windows.cpp +++ b/source/Host/windows/Windows.cpp @@ -12,6 +12,9 @@ #include "lldb/Host/windows/windows.h" #include "lldb/Host/windows/win32.h" +#include "llvm/Support/ConvertUTF.h" + +#include <assert.h> #include <stdio.h> #include <stdarg.h> #include <string.h> @@ -27,6 +30,29 @@ extern "C" int _chdir(const char *path); } +namespace +{ +bool +utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize) +{ + const UTF8 *sourceStart = reinterpret_cast<const UTF8 *>(utf8); + size_t sourceLen = strlen(utf8) + 1 /* convert null too */; + UTF16 *target = reinterpret_cast<UTF16 *>(buf); + ConversionFlags flags = strictConversion; + return ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK; +} + +bool +wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize) +{ + const UTF16 *sourceStart = reinterpret_cast<const UTF16 *>(wide); + size_t sourceLen = wcslen(wide) + 1 /* convert null too */; + UTF8 *target = reinterpret_cast<UTF8 *>(buf); + ConversionFlags flags = strictConversion; + return ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, target + bufSize, flags) == conversionOK; +} +} + int vasprintf(char **ret, const char *fmt, va_list ap) { char *buf; @@ -75,81 +101,90 @@ char* strcasestr(const char *s, const char* find) char* realpath(const char * name, char * resolved) { - char *retname = NULL; /* we will return this, if we fail */ + char *retname = NULL; /* SUSv3 says we must set `errno = EINVAL', and return NULL, * if `name' is passed as a NULL pointer. */ - if (name == NULL) + { errno = EINVAL; + return NULL; + } /* Otherwise, `name' must refer to a readable filesystem object, * if we are going to resolve its absolute path name. */ - - else if (access(name, 4) == 0) + wchar_t wideNameBuffer[PATH_MAX]; + wchar_t *wideName = wideNameBuffer; + if (!utf8ToWide(name, wideName, PATH_MAX)) { - /* If `name' didn't point to an existing entity, - * then we don't get to here; we simply fall past this block, - * returning NULL, with `errno' appropriately set by `access'. - * - * When we _do_ get to here, then we can use `_fullpath' to - * resolve the full path for `name' into `resolved', but first, - * check that we have a suitable buffer, in which to return it. - */ + errno = EINVAL; + return NULL; + } - if ((retname = resolved) == NULL) - { - /* Caller didn't give us a buffer, so we'll exercise the - * option granted by SUSv3, and allocate one. - * - * `_fullpath' would do this for us, but it uses `malloc', and - * Microsoft's implementation doesn't set `errno' on failure. - * If we don't do this explicitly ourselves, then we will not - * know if `_fullpath' fails on `malloc' failure, or for some - * other reason, and we want to set `errno = ENOMEM' for the - * `malloc' failure case. - */ - - retname = (char*) malloc(_MAX_PATH); - } + if (_waccess(wideName, 4) != 0) + return NULL; + + /* If `name' didn't point to an existing entity, + * then we don't get to here; we simply fall past this block, + * returning NULL, with `errno' appropriately set by `access'. + * + * When we _do_ get to here, then we can use `_fullpath' to + * resolve the full path for `name' into `resolved', but first, + * check that we have a suitable buffer, in which to return it. + */ - /* By now, we should have a valid buffer. - * If we don't, then we know that `malloc' failed, - * so we can set `errno = ENOMEM' appropriately. + if ((retname = resolved) == NULL) + { + /* Caller didn't give us a buffer, so we'll exercise the + * option granted by SUSv3, and allocate one. + * + * `_fullpath' would do this for us, but it uses `malloc', and + * Microsoft's implementation doesn't set `errno' on failure. + * If we don't do this explicitly ourselves, then we will not + * know if `_fullpath' fails on `malloc' failure, or for some + * other reason, and we want to set `errno = ENOMEM' for the + * `malloc' failure case. */ + retname = (char *)malloc(PATH_MAX); if (retname == NULL) + { errno = ENOMEM; + return NULL; + } + } - /* Otherwise, when we do have a valid buffer, - * `_fullpath' should only fail if the path name is too long. - */ + /* Otherwise, when we do have a valid buffer, + * `_fullpath' should only fail if the path name is too long. + */ - else if ((retname = _fullpath(retname, name, _MAX_PATH)) == NULL) - errno = ENAMETOOLONG; + wchar_t wideFullPathBuffer[PATH_MAX]; + wchar_t *wideFullPath; + if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == NULL) + { + errno = ENAMETOOLONG; + return NULL; } - /* By the time we get to here, - * `retname' either points to the required resolved path name, - * or it is NULL, with `errno' set appropriately, either of which - * is our required return condition. - */ + // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS + // FIXME: Check for failure + size_t initialLength = wcslen(wideFullPath); + GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX); + GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1); - if (retname != NULL) + // Convert back to UTF-8 + if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX)) { - // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS - int initialLength = strlen(retname); - TCHAR buffer[MAX_PATH]; - GetShortPathName(retname, buffer, MAX_PATH); - GetLongPathName(buffer, retname, initialLength + 1); - - // Force drive to be upper case - if (retname[1] == ':') - retname[0] = toupper(retname[0]); + errno = EINVAL; + return NULL; } + // Force drive to be upper case + if (retname[1] == ':') + retname[0] = toupper(retname[0]); + return retname; } @@ -167,7 +202,27 @@ char* basename(char *path) // use _getcwd() instead of GetCurrentDirectory() because it updates errno char* getcwd(char* path, int max) { - return _getcwd(path, max); + assert(path == NULL || max <= PATH_MAX); + wchar_t wpath[PATH_MAX]; + if (wchar_t *wresult = _wgetcwd(wpath, PATH_MAX)) + { + // Caller is allowed to pass in NULL for `path`. + // In that case, we're supposed to allocate a + // buffer on the caller's behalf. + if (path == NULL) + { + max = UNI_MAX_UTF8_BYTES_PER_CODE_POINT * wcslen(wresult) + 1; + path = (char *)malloc(max); + if (path == NULL) + { + errno = ENOMEM; + return NULL; + } + } + if (wideToUtf8(wresult, path, max)) + return path; + } + return NULL; } // use _chdir() instead of SetCurrentDirectory() because it updates errno |