aboutsummaryrefslogtreecommitdiffstats
path: root/source/Host
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:50:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:50:09 +0000
commitf3fbd1c0586ff6ec7895991e6c28f61a503c36a8 (patch)
tree48d008fd3df8c0e73271a4b18474e0aac6dbfe33 /source/Host
parent2fc5d2d1dfaf623ce4e24cd8590565902f8c557c (diff)
downloadsrc-f3fbd1c0586ff6ec7895991e6c28f61a503c36a8.tar.gz
src-f3fbd1c0586ff6ec7895991e6c28f61a503c36a8.zip
Vendor import of lldb release_39 branch r276489:vendor/lldb/lldb-release_39-r276489
Notes
Notes: svn path=/vendor/lldb/dist/; revision=303241 svn path=/vendor/lldb/lldb-release_39-r276489/; revision=303242; tag=vendor/lldb/lldb-release_39-r276489
Diffstat (limited to 'source/Host')
-rw-r--r--source/Host/Makefile65
-rw-r--r--source/Host/android/LibcGlue.cpp5
-rw-r--r--source/Host/common/Editline.cpp246
-rw-r--r--source/Host/common/File.cpp81
-rw-r--r--source/Host/common/FileSpec.cpp358
-rw-r--r--source/Host/common/Host.cpp71
-rw-r--r--source/Host/common/HostInfoBase.cpp34
-rw-r--r--source/Host/common/HostProcess.cpp4
-rw-r--r--source/Host/common/MonitoringProcessLauncher.cpp4
-rw-r--r--source/Host/common/NativeBreakpointList.cpp13
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp56
-rw-r--r--source/Host/common/OptionParser.cpp6
-rw-r--r--source/Host/common/Socket.cpp2
-rw-r--r--source/Host/common/SocketAddress.cpp6
-rw-r--r--source/Host/common/SoftwareBreakpoint.cpp1
-rw-r--r--source/Host/common/TCPSocket.cpp3
-rw-r--r--source/Host/common/UDPSocket.cpp8
-rw-r--r--source/Host/linux/Host.cpp20
-rw-r--r--source/Host/linux/HostInfoLinux.cpp2
-rw-r--r--source/Host/macosx/Host.mm43
-rw-r--r--source/Host/macosx/HostInfoMacOSX.mm6
-rw-r--r--source/Host/macosx/ThisThread.cpp18
-rw-r--r--source/Host/netbsd/Makefile14
-rw-r--r--source/Host/posix/ConnectionFileDescriptorPosix.cpp57
-rw-r--r--source/Host/posix/DomainSocket.cpp2
-rw-r--r--source/Host/posix/FileSystem.cpp46
-rw-r--r--source/Host/posix/HostInfoPosix.cpp11
-rw-r--r--source/Host/posix/HostProcessPosix.cpp4
-rw-r--r--source/Host/posix/HostThreadPosix.cpp20
-rw-r--r--source/Host/windows/ConnectionGenericFileWindows.cpp11
-rw-r--r--source/Host/windows/FileSystem.cpp120
-rw-r--r--source/Host/windows/Host.cpp48
-rw-r--r--source/Host/windows/HostInfoWindows.cpp52
-rw-r--r--source/Host/windows/HostProcessWindows.cpp21
-rw-r--r--source/Host/windows/PipeWindows.cpp10
-rw-r--r--source/Host/windows/ProcessLauncherWindows.cpp49
-rw-r--r--source/Host/windows/Windows.cpp157
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