summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Host
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host')
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Condition.cpp108
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Editline.cpp1443
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/File.cpp1090
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp127
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp1554
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp103
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/GetOptInc.cpp473
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Host.cpp1082
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp425
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp82
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp65
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp78
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp14
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp124
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp102
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp398
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp116
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp221
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp461
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp516
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp75
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp35
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp116
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp27
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/ProcessRunLock.cpp71
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Socket.cpp489
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp369
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp317
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/StringConvert.cpp117
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp327
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp288
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp323
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp52
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp84
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/TimeValue.cpp222
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp158
-rw-r--r--contrib/llvm/tools/lldb/source/Host/common/XML.cpp691
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp283
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp91
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp79
-rw-r--r--contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp39
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp287
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp112
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp50
-rw-r--r--contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp30
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp914
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp133
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp299
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp244
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp113
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp74
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp77
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp193
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp437
-rw-r--r--contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp33
56 files changed, 15881 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp b/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp
new file mode 100644
index 0000000..1c1afb4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp
@@ -0,0 +1,108 @@
+//===-- Condition.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Condition.h"
+#include "lldb/Host/TimeValue.h"
+
+
+using namespace lldb_private;
+
+#ifndef _WIN32
+
+//----------------------------------------------------------------------
+// Default constructor
+//
+// The default constructor will initialize a new pthread condition
+// and maintain the condition in the object state.
+//----------------------------------------------------------------------
+Condition::Condition () :
+ m_condition()
+{
+ ::pthread_cond_init (&m_condition, NULL);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Destroys the pthread condition that the object owns.
+//----------------------------------------------------------------------
+Condition::~Condition ()
+{
+ ::pthread_cond_destroy (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// Unblock all threads waiting for a condition variable
+//----------------------------------------------------------------------
+int
+Condition::Broadcast ()
+{
+ return ::pthread_cond_broadcast (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// Unblocks one thread waiting for the condition variable
+//----------------------------------------------------------------------
+int
+Condition::Signal ()
+{
+ return ::pthread_cond_signal (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// The Wait() function atomically blocks the current thread
+// waiting on the owned condition variable, and unblocks the mutex
+// specified by "mutex". The waiting thread unblocks only after
+// another thread calls Signal(), or Broadcast() with the same
+// condition variable, or if "abstime" is valid (non-NULL) this
+// function will return when the system time reaches the time
+// specified in "abstime". If "abstime" is NULL this function will
+// wait for an infinite amount of time for the condition variable
+// to be signaled or broadcasted.
+//
+// The current thread re-acquires the lock on "mutex".
+//----------------------------------------------------------------------
+int
+Condition::Wait (Mutex &mutex, const TimeValue *abstime, bool *timed_out)
+{
+ int err = 0;
+ do
+ {
+ if (abstime && abstime->IsValid())
+ {
+ struct timespec abstime_ts = abstime->GetAsTimeSpec();
+ err = ::pthread_cond_timedwait (&m_condition, mutex.GetMutex(), &abstime_ts);
+ }
+ else
+ err = ::pthread_cond_wait (&m_condition, mutex.GetMutex());
+ } while (err == EINTR);
+
+ if (timed_out != NULL)
+ {
+ if (err == ETIMEDOUT)
+ *timed_out = true;
+ else
+ *timed_out = false;
+ }
+
+ return err;
+}
+
+#endif
+
+//----------------------------------------------------------------------
+// Get accessor to the pthread condition object
+//----------------------------------------------------------------------
+lldb::condition_t *
+Condition::GetCondition()
+{
+ return &m_condition;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp
new file mode 100644
index 0000000..4640154
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp
@@ -0,0 +1,1443 @@
+//===-- Editline.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <iomanip>
+#include <iostream>
+#include <limits.h>
+
+#include "lldb/Host/Editline.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/StreamString.h"
+#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;
+using namespace lldb_private::line_editor;
+
+// Workaround for what looks like an OS X-specific issue, but other platforms
+// may benefit from something similar if issues arise. The libedit library
+// doesn't explicitly initialize the curses termcap library, which it gets away
+// with until TERM is set to VT100 where it stumbles over an implementation
+// assumption that may not exist on other platforms. The setupterm() function
+// would normally require headers that don't work gracefully in this context, so
+// the function declaraction has been hoisted here.
+#if defined(__APPLE__)
+extern "C" {
+ int setupterm(char *term, int fildes, int *errret);
+}
+#define USE_SETUPTERM_WORKAROUND
+#endif
+
+// Editline uses careful cursor management to achieve the illusion of editing a multi-line block of text
+// with a single line editor. Preserving this illusion requires fairly careful management of cursor
+// state. Read and understand the relationship between DisplayInput(), MoveCursor(), SetCurrentLine(),
+// and SaveEditedLine() before making changes.
+
+#define ESCAPE "\x1b"
+#define ANSI_FAINT ESCAPE "[2m"
+#define ANSI_UNFAINT ESCAPE "[22m"
+#define ANSI_CLEAR_BELOW ESCAPE "[J"
+#define ANSI_CLEAR_RIGHT ESCAPE "[K"
+#define ANSI_SET_COLUMN_N ESCAPE "[%dG"
+#define ANSI_UP_N_ROWS ESCAPE "[%dA"
+#define ANSI_DOWN_N_ROWS ESCAPE "[%dB"
+
+#if LLDB_EDITLINE_USE_WCHAR
+
+#define EditLineConstString(str) L##str
+#define EditLineStringFormatSpec "%ls"
+
+#else
+
+#define EditLineConstString(str) str
+#define EditLineStringFormatSpec "%s"
+
+// use #defines so wide version functions and structs will resolve to old versions
+// for case of libedit not built with wide char support
+#define history_w history
+#define history_winit history_init
+#define history_wend history_end
+#define HistoryW History
+#define HistEventW HistEvent
+#define LineInfoW LineInfo
+
+#define el_wgets el_gets
+#define el_wgetc el_getc
+#define el_wpush el_push
+#define el_wparse el_parse
+#define el_wset el_set
+#define el_wget el_get
+#define el_wline el_line
+#define el_winsertstr el_insertstr
+#define el_wdeletestr el_deletestr
+
+#endif // #if LLDB_EDITLINE_USE_WCHAR
+
+bool
+IsOnlySpaces (const EditLineStringType & content)
+{
+ for (wchar_t ch : content)
+ {
+ if (ch != EditLineCharType(' '))
+ return false;
+ }
+ return true;
+}
+
+EditLineStringType
+CombineLines (const std::vector<EditLineStringType> & lines)
+{
+ EditLineStringStreamType combined_stream;
+ for (EditLineStringType line : lines)
+ {
+ combined_stream << line.c_str() << "\n";
+ }
+ return combined_stream.str();
+}
+
+std::vector<EditLineStringType>
+SplitLines (const EditLineStringType & input)
+{
+ std::vector<EditLineStringType> result;
+ size_t start = 0;
+ while (start < input.length())
+ {
+ size_t end = input.find ('\n', start);
+ if (end == std::string::npos)
+ {
+ result.insert (result.end(), input.substr (start));
+ break;
+ }
+ result.insert (result.end(), input.substr (start, end - start));
+ start = end + 1;
+ }
+ return result;
+}
+
+EditLineStringType
+FixIndentation (const EditLineStringType & line, int indent_correction)
+{
+ if (indent_correction == 0)
+ return line;
+ if (indent_correction < 0)
+ return line.substr (-indent_correction);
+ return EditLineStringType (indent_correction, EditLineCharType(' ')) + line;
+}
+
+int
+GetIndentation (const EditLineStringType & line)
+{
+ int space_count = 0;
+ for (EditLineCharType ch : line)
+ {
+ if (ch != EditLineCharType(' '))
+ break;
+ ++space_count;
+ }
+ return space_count;
+}
+
+bool
+IsInputPending (FILE * file)
+{
+ // FIXME: This will be broken on Windows if we ever re-enable Editline. You can't use select
+ // on something that isn't a socket. This will have to be re-written to not use a FILE*, but
+ // instead use some kind of yet-to-be-created abstraction that select-like functionality on
+ // non-socket objects.
+ const int fd = fileno (file);
+ fd_set fds;
+ FD_ZERO (&fds);
+ FD_SET (fd, &fds);
+ timeval timeout = { 0, 0 };
+ return select (fd + 1, &fds, NULL, NULL, &timeout);
+}
+
+namespace lldb_private
+{
+ namespace line_editor
+ {
+ typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name.
+
+ class EditlineHistory
+ {
+ private:
+ // Use static GetHistory() function to get a EditlineHistorySP to one of these objects
+ EditlineHistory (const std::string &prefix, uint32_t size, bool unique_entries) :
+ m_history (NULL),
+ m_event (),
+ m_prefix (prefix),
+ m_path ()
+ {
+ m_history = history_winit();
+ history_w (m_history, &m_event, H_SETSIZE, size);
+ if (unique_entries)
+ history_w (m_history, &m_event, H_SETUNIQUE, 1);
+ }
+
+ const char *
+ GetHistoryFilePath()
+ {
+ if (m_path.empty() && m_history && !m_prefix.empty())
+ {
+ FileSpec parent_path{"~/.lldb", true};
+ char history_path[PATH_MAX];
+ if (FileSystem::MakeDirectory(parent_path, lldb::eFilePermissionsDirectoryDefault).Success())
+ {
+ snprintf (history_path, sizeof (history_path), "~/.lldb/%s-history", m_prefix.c_str());
+ }
+ else
+ {
+ snprintf (history_path, sizeof (history_path), "~/%s-widehistory", m_prefix.c_str());
+ }
+ m_path = FileSpec (history_path, true).GetPath();
+ }
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+ }
+
+ public:
+
+ ~EditlineHistory()
+ {
+ Save();
+
+ if (m_history)
+ {
+ history_wend (m_history);
+ m_history = NULL;
+ }
+ }
+
+ static EditlineHistorySP
+ GetHistory (const std::string &prefix)
+ {
+ typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
+ static Mutex g_mutex (Mutex::eMutexTypeRecursive);
+ static WeakHistoryMap g_weak_map;
+ Mutex::Locker locker (g_mutex);
+ WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix);
+ EditlineHistorySP history_sp;
+ if (pos != g_weak_map.end())
+ {
+ history_sp = pos->second.lock();
+ if (history_sp)
+ return history_sp;
+ g_weak_map.erase (pos);
+ }
+ history_sp.reset (new EditlineHistory (prefix, 800, true));
+ g_weak_map[prefix] = history_sp;
+ return history_sp;
+ }
+
+ bool IsValid() const
+ {
+ return m_history != NULL;
+ }
+
+ HistoryW *
+ GetHistoryPtr ()
+ {
+ return m_history;
+ }
+
+ void
+ Enter (const EditLineCharType *line_cstr)
+ {
+ if (m_history)
+ history_w (m_history, &m_event, H_ENTER, line_cstr);
+ }
+
+ bool
+ Load ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ history_w (m_history, &m_event, H_LOAD, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ Save ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ history_w (m_history, &m_event, H_SAVE, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ HistoryW * m_history; // The history object
+ HistEventW m_event; // The history event needed to contain all history events
+ std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history
+ std::string m_path; // Path to the history file
+ };
+ }
+}
+
+//------------------------------------------------------------------
+// Editline private methods
+//------------------------------------------------------------------
+
+void
+Editline::SetBaseLineNumber (int line_number)
+{
+ std::stringstream line_number_stream;
+ line_number_stream << line_number;
+ m_base_line_number = line_number;
+ m_line_number_digits = std::max (3, (int)line_number_stream.str().length() + 1);
+}
+
+std::string
+Editline::PromptForIndex (int line_index)
+{
+ bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0;
+ std::string prompt = m_set_prompt;
+ if (use_line_numbers && prompt.length() == 0)
+ {
+ prompt = ": ";
+ }
+ std::string continuation_prompt = prompt;
+ if (m_set_continuation_prompt.length() > 0)
+ {
+ continuation_prompt = m_set_continuation_prompt;
+
+ // Ensure that both prompts are the same length through space padding
+ while (continuation_prompt.length() < prompt.length())
+ {
+ continuation_prompt += ' ';
+ }
+ while (prompt.length() < continuation_prompt.length())
+ {
+ prompt += ' ';
+ }
+ }
+
+ if (use_line_numbers)
+ {
+ StreamString prompt_stream;
+ prompt_stream.Printf("%*d%s", m_line_number_digits, m_base_line_number + line_index,
+ (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str());
+ return std::move (prompt_stream.GetString());
+ }
+ return (line_index == 0) ? prompt : continuation_prompt;
+}
+
+void
+Editline::SetCurrentLine (int line_index)
+{
+ m_current_line_index = line_index;
+ m_current_prompt = PromptForIndex (line_index);
+}
+
+int
+Editline::GetPromptWidth()
+{
+ return (int)PromptForIndex (0).length();
+}
+
+bool
+Editline::IsEmacs()
+{
+ const char * editor;
+ el_get (m_editline, EL_EDITOR, &editor);
+ return editor[0] == 'e';
+}
+
+bool
+Editline::IsOnlySpaces()
+{
+ const LineInfoW * info = el_wline (m_editline);
+ for (const EditLineCharType * character = info->buffer; character < info->lastchar; character++)
+ {
+ if (*character != ' ')
+ return false;
+ }
+ return true;
+}
+
+int
+Editline::GetLineIndexForLocation (CursorLocation location, int cursor_row)
+{
+ int line = 0;
+ if (location == CursorLocation::EditingPrompt || location == CursorLocation::BlockEnd ||
+ location == CursorLocation::EditingCursor)
+ {
+ for (unsigned index = 0; index < m_current_line_index; index++)
+ {
+ line += CountRowsForLine (m_input_lines[index]);
+ }
+ if (location == CursorLocation::EditingCursor)
+ {
+ line += cursor_row;
+ }
+ else if (location == CursorLocation::BlockEnd)
+ {
+ for (unsigned index = m_current_line_index; index < m_input_lines.size(); index++)
+ {
+ line += CountRowsForLine (m_input_lines[index]);
+ }
+ --line;
+ }
+ }
+ return line;
+}
+
+void
+Editline::MoveCursor (CursorLocation from, CursorLocation to)
+{
+ const LineInfoW * info = el_wline (m_editline);
+ int editline_cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int editline_cursor_row = editline_cursor_position / m_terminal_width;
+
+ // Determine relative starting and ending lines
+ int fromLine = GetLineIndexForLocation (from, editline_cursor_row);
+ int toLine = GetLineIndexForLocation (to, editline_cursor_row);
+ if (toLine != fromLine)
+ {
+ fprintf (m_output_file, (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs (toLine - fromLine));
+ }
+
+ // Determine target column
+ int toColumn = 1;
+ if (to == CursorLocation::EditingCursor)
+ {
+ toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
+ }
+ else if (to == CursorLocation::BlockEnd)
+ {
+ toColumn = ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % 80) + 1;
+ }
+ fprintf (m_output_file, ANSI_SET_COLUMN_N, toColumn);
+}
+
+void
+Editline::DisplayInput (int firstIndex)
+{
+ fprintf (m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1);
+ int line_count = (int)m_input_lines.size();
+ const char *faint = m_color_prompts ? ANSI_FAINT : "";
+ const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
+
+ for (int index = firstIndex; index < line_count; index++)
+ {
+ fprintf (m_output_file, "%s" "%s" "%s" EditLineStringFormatSpec " ",
+ faint,
+ PromptForIndex (index).c_str(),
+ unfaint,
+ m_input_lines[index].c_str());
+ if (index < line_count - 1)
+ fprintf (m_output_file, "\n");
+ }
+}
+
+
+int
+Editline::CountRowsForLine (const EditLineStringType & content)
+{
+ auto prompt = PromptForIndex (0); // Prompt width is constant during an edit session
+ int line_length = (int)(content.length() + prompt.length());
+ return (line_length / m_terminal_width) + 1;
+}
+
+void
+Editline::SaveEditedLine()
+{
+ const LineInfoW * info = el_wline (m_editline);
+ m_input_lines[m_current_line_index] = EditLineStringType (info->buffer, info->lastchar - info->buffer);
+}
+
+StringList
+Editline::GetInputAsStringList(int line_count)
+{
+ StringList lines;
+ for (EditLineStringType line : m_input_lines)
+ {
+ if (line_count == 0)
+ break;
+#if LLDB_EDITLINE_USE_WCHAR
+ lines.AppendString (m_utf8conv.to_bytes (line));
+#else
+ lines.AppendString(line);
+#endif
+ --line_count;
+ }
+ return lines;
+}
+
+unsigned char
+Editline::RecallHistory (bool earlier)
+{
+ if (!m_history_sp || !m_history_sp->IsValid())
+ return CC_ERROR;
+
+ HistoryW * pHistory = m_history_sp->GetHistoryPtr();
+ HistEventW history_event;
+ std::vector<EditLineStringType> new_input_lines;
+
+ // Treat moving from the "live" entry differently
+ if (!m_in_history)
+ {
+ if (earlier == false)
+ return CC_ERROR; // Can't go newer than the "live" entry
+ if (history_w (pHistory, &history_event, H_FIRST) == -1)
+ return CC_ERROR;
+
+ // Save any edits to the "live" entry in case we return by moving forward in history
+ // (it would be more bash-like to save over any current entry, but libedit doesn't
+ // offer the ability to add entries anywhere except the end.)
+ SaveEditedLine();
+ m_live_history_lines = m_input_lines;
+ m_in_history = true;
+ }
+ else
+ {
+ if (history_w (pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1)
+ {
+ // Can't move earlier than the earliest entry
+ if (earlier)
+ return CC_ERROR;
+
+ // ... but moving to newer than the newest yields the "live" entry
+ new_input_lines = m_live_history_lines;
+ m_in_history = false;
+ }
+ }
+
+ // If we're pulling the lines from history, split them apart
+ if (m_in_history)
+ new_input_lines = SplitLines (history_event.str);
+
+ // Erase the current edit session and replace it with a new one
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ m_input_lines = new_input_lines;
+ DisplayInput();
+
+ // Prepare to edit the last line when moving to previous entry, or the first line
+ // when moving to next entry
+ SetCurrentLine (m_current_line_index = earlier ? (int)m_input_lines.size() - 1 : 0);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
+}
+
+int
+Editline::GetCharacter (EditLineCharType * c)
+{
+ const LineInfoW * info = el_wline (m_editline);
+
+ // Paint a faint version of the desired prompt over the version libedit draws
+ // (will only be requested if colors are supported)
+ if (m_needs_prompt_repaint)
+ {
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ fprintf (m_output_file, "%s" "%s" "%s", ANSI_FAINT, Prompt(), ANSI_UNFAINT);
+ MoveCursor (CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
+ m_needs_prompt_repaint = false;
+ }
+
+ if (m_multiline_enabled)
+ {
+ // Detect when the number of rows used for this input line changes due to an edit
+ int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ int new_line_rows = (lineLength / m_terminal_width) + 1;
+ if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows)
+ {
+ // Respond by repainting the current state from this line on
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ SaveEditedLine();
+ DisplayInput (m_current_line_index);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+ m_current_line_rows = new_line_rows;
+ }
+
+ // Read an actual character
+ while (true)
+ {
+ lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
+ char ch = 0;
+
+ // This mutex is locked by our caller (GetLine). Unlock it while we read a character
+ // (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();
+ int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ m_output_mutex.Lock();
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
+ read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ lldbassert(status == lldb::eConnectionStatusInterrupted);
+ return 0;
+ }
+
+ if (read_count)
+ {
+#if LLDB_EDITLINE_USE_WCHAR
+ // After the initial interruptible read, this is guaranteed not to block
+ ungetc (ch, m_input_file);
+ *c = fgetwc (m_input_file);
+ if (*c != WEOF)
+ return 1;
+#else
+ *c = ch;
+ if(ch != (char)EOF)
+ return 1;
+#endif
+ }
+ else
+ {
+ switch (status)
+ {
+ case lldb::eConnectionStatusSuccess: // Success
+ break;
+
+ case lldb::eConnectionStatusInterrupted:
+ lldbassert(0 && "Interrupts should have been handled above.");
+
+ case lldb::eConnectionStatusError: // Check GetError() for details
+ case lldb::eConnectionStatusTimedOut: // Request timed out
+ case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
+ case lldb::eConnectionStatusNoConnection: // No connection
+ case lldb::eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ m_editor_status = EditorStatus::EndOfInput;
+ return 0;
+ }
+ }
+ }
+}
+
+const char *
+Editline::Prompt()
+{
+ if (m_color_prompts)
+ m_needs_prompt_repaint = true;
+ return m_current_prompt.c_str();
+}
+
+unsigned char
+Editline::BreakLineCommand (int ch)
+{
+ // Preserve any content beyond the cursor, truncate and save the current line
+ const LineInfoW * info = el_wline (m_editline);
+ auto current_line = EditLineStringType (info->buffer, info->cursor - info->buffer);
+ auto new_line_fragment = EditLineStringType (info->cursor, info->lastchar - info->cursor);
+ m_input_lines[m_current_line_index] = current_line;
+
+ // Ignore whitespace-only extra fragments when breaking a line
+ if (::IsOnlySpaces (new_line_fragment))
+ new_line_fragment = EditLineConstString("");
+
+ // 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
+ 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)
+ {
+ StringList lines = GetInputAsStringList (m_current_line_index + 1);
+#if LLDB_EDITLINE_USE_WCHAR
+ lines.AppendString (m_utf8conv.to_bytes (new_line_fragment));
+#else
+ lines.AppendString (new_line_fragment);
+#endif
+
+ int indent_correction = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
+ new_line_fragment = FixIndentation(new_line_fragment, indent_correction);
+ m_revert_cursor_index = GetIndentation(new_line_fragment);
+ }
+ }
+
+ // Insert the new line and repaint everything from the split line on down
+ m_input_lines.insert (m_input_lines.begin() + m_current_line_index + 1, new_line_fragment);
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ DisplayInput (m_current_line_index);
+
+ // Reposition the cursor to the right line and prepare to edit the new line
+ SetCurrentLine (m_current_line_index + 1);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::DeleteNextCharCommand (int ch)
+{
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
+
+ // Just delete the next character normally if possible
+ if (info->cursor < info->lastchar)
+ {
+ info->cursor++;
+ el_deletestr (m_editline, 1);
+ return CC_REFRESH;
+ }
+
+ // Fail when at the end of the last line, except when ^D is pressed on
+ // the line is empty, in which case it is treated as EOF
+ if (m_current_line_index == m_input_lines.size() - 1)
+ {
+ if (ch == 4 && info->buffer == info->lastchar)
+ {
+ fprintf (m_output_file, "^D\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ return CC_EOF;
+ }
+ return CC_ERROR;
+ }
+
+ // Prepare to combine this line with the one below
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Insert the next line of text at the cursor and restore the cursor position
+ const EditLineCharType * cursor = info->cursor;
+ el_winsertstr (m_editline, m_input_lines[m_current_line_index + 1].c_str());
+ info->cursor = cursor;
+ SaveEditedLine();
+
+ // Delete the extra line
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index + 1);
+
+ // Clear and repaint from this line on down
+ DisplayInput (m_current_line_index);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ return CC_REFRESH;
+}
+
+unsigned char
+Editline::DeletePreviousCharCommand (int ch)
+{
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
+
+ // Just delete the previous character normally when not at the start of a line
+ if (info->cursor > info->buffer)
+ {
+ el_deletestr (m_editline, 1);
+ return CC_REFRESH;
+ }
+
+ // No prior line and no prior character? Let the user know
+ if (m_current_line_index == 0)
+ return CC_ERROR;
+
+ // No prior character, but prior line? Combine with the line above
+ SaveEditedLine();
+ SetCurrentLine (m_current_line_index - 1);
+ auto priorLine = m_input_lines[m_current_line_index];
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
+ m_input_lines[m_current_line_index] = priorLine + m_input_lines[m_current_line_index];
+
+ // Repaint from the new line down
+ fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine (priorLine), 1);
+ DisplayInput (m_current_line_index);
+
+ // Put the cursor back where libedit expects it to be before returning to editing
+ // by telling libedit about the newly inserted text
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ el_winsertstr (m_editline, priorLine.c_str());
+ return CC_REDISPLAY;
+}
+
+unsigned char
+Editline::PreviousLineCommand (int ch)
+{
+ SaveEditedLine();
+
+ if (m_current_line_index == 0) {
+ return RecallHistory (true);
+ }
+
+ // Start from a known location
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Treat moving up from a blank last line as a deletion of that line
+ if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces())
+ {
+ m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
+ fprintf (m_output_file, ANSI_CLEAR_BELOW);
+ }
+
+ SetCurrentLine (m_current_line_index - 1);
+ fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
+ CountRowsForLine (m_input_lines[m_current_line_index]), 1);
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::NextLineCommand (int ch)
+{
+ SaveEditedLine();
+
+ // Handle attempts to move down from the last line
+ if (m_current_line_index == m_input_lines.size() - 1)
+ {
+ // Don't add an extra line if the existing last line is blank, move through history instead
+ if (IsOnlySpaces())
+ {
+ return RecallHistory (false);
+ }
+
+ // Determine indentation for the new line
+ int indentation = 0;
+ if (m_fix_indentation_callback)
+ {
+ StringList lines = GetInputAsStringList();
+ lines.AppendString("");
+ indentation = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
+ }
+ m_input_lines.insert (m_input_lines.end(), EditLineStringType (indentation, EditLineCharType(' ')));
+ }
+
+ // Move down past the current line using newlines to force scrolling if needed
+ SetCurrentLine (m_current_line_index + 1);
+ const LineInfoW * info = el_wline (m_editline);
+ int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int cursor_row = cursor_position / m_terminal_width;
+ for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++)
+ {
+ fprintf (m_output_file, "\n");
+ }
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::FixIndentationCommand (int ch)
+{
+ if (!m_fix_indentation_callback)
+ return CC_NORM;
+
+ // Insert the character typed before proceeding
+ EditLineCharType inserted[] = { (EditLineCharType)ch, 0 };
+ el_winsertstr (m_editline, inserted);
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
+ int cursor_position = info->cursor - info->buffer;
+
+ // Save the edits and determine the correct indentation level
+ SaveEditedLine();
+ StringList lines = GetInputAsStringList (m_current_line_index + 1);
+ int indent_correction = m_fix_indentation_callback (this, lines, cursor_position, m_fix_indentation_callback_baton);
+
+ // If it is already correct no special work is needed
+ if (indent_correction == 0)
+ return CC_REFRESH;
+
+ // Change the indentation level of the line
+ std::string currentLine = lines.GetStringAtIndex (m_current_line_index);
+ if (indent_correction > 0)
+ {
+ currentLine = currentLine.insert (0, indent_correction, ' ');
+ }
+ else
+ {
+ currentLine = currentLine.erase (0, -indent_correction);
+ }
+#if LLDB_EDITLINE_USE_WCHAR
+ m_input_lines[m_current_line_index] = m_utf8conv.from_bytes (currentLine);
+#else
+ m_input_lines[m_current_line_index] = currentLine;
+#endif
+
+ // Update the display to reflect the change
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ DisplayInput (m_current_line_index);
+
+ // Reposition the cursor back on the original line and prepare to restart editing
+ // with a new cursor position
+ SetCurrentLine (m_current_line_index);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ m_revert_cursor_index = cursor_position + indent_correction;
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::RevertLineCommand (int ch)
+{
+ el_winsertstr (m_editline, m_input_lines[m_current_line_index].c_str());
+ if (m_revert_cursor_index >= 0)
+ {
+ LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
+ info->cursor = info->buffer + m_revert_cursor_index;
+ if (info->cursor > info->lastchar)
+ {
+ info->cursor = info->lastchar;
+ }
+ m_revert_cursor_index = -1;
+ }
+ return CC_REFRESH;
+}
+
+unsigned char
+Editline::BufferStartCommand (int ch)
+{
+ SaveEditedLine();
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ SetCurrentLine (0);
+ m_revert_cursor_index = 0;
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::BufferEndCommand (int ch)
+{
+ SaveEditedLine();
+ MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockEnd);
+ SetCurrentLine ((int)m_input_lines.size() - 1);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
+}
+
+unsigned char
+Editline::TabCommand (int ch)
+{
+ if (m_completion_callback == nullptr)
+ return CC_ERROR;
+
+ const LineInfo *line_info = el_line (m_editline);
+ StringList completions;
+ int page_size = 40;
+
+ const int num_completions = m_completion_callback (line_info->buffer,
+ line_info->cursor,
+ line_info->lastchar,
+ 0, // Don't skip any matches (start at match zero)
+ -1, // Get all the matches
+ completions,
+ m_completion_callback_baton);
+
+ if (num_completions == 0)
+ return CC_ERROR;
+ // if (num_completions == -1)
+ // {
+ // el_insertstr (m_editline, m_completion_key);
+ // return CC_REDISPLAY;
+ // }
+ // else
+ if (num_completions == -2)
+ {
+ // Replace the entire line with the first string...
+ el_deletestr (m_editline, line_info->cursor - line_info->buffer);
+ el_insertstr (m_editline, completions.GetStringAtIndex (0));
+ return CC_REDISPLAY;
+ }
+
+ // If we get a longer match display that first.
+ const char *completion_str = completions.GetStringAtIndex (0);
+ if (completion_str != nullptr && *completion_str != '\0')
+ {
+ el_insertstr (m_editline, completion_str);
+ return CC_REDISPLAY;
+ }
+
+ if (num_completions > 1)
+ {
+ int num_elements = num_completions + 1;
+ fprintf (m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:");
+ if (num_completions < page_size)
+ {
+ for (int i = 1; i < num_elements; i++)
+ {
+ completion_str = completions.GetStringAtIndex (i);
+ fprintf (m_output_file, "\n\t%s", completion_str);
+ }
+ fprintf (m_output_file, "\n");
+ }
+ else
+ {
+ int cur_pos = 1;
+ char reply;
+ int got_char;
+ while (cur_pos < num_elements)
+ {
+ int endpoint = cur_pos + page_size;
+ if (endpoint > num_elements)
+ endpoint = num_elements;
+ for (; cur_pos < endpoint; cur_pos++)
+ {
+ completion_str = completions.GetStringAtIndex (cur_pos);
+ fprintf (m_output_file, "\n\t%s", completion_str);
+ }
+
+ if (cur_pos >= num_elements)
+ {
+ fprintf (m_output_file, "\n");
+ break;
+ }
+
+ fprintf (m_output_file, "\nMore (Y/n/a): ");
+ reply = 'n';
+ got_char = el_getc(m_editline, &reply);
+ if (got_char == -1 || reply == 'n')
+ break;
+ if (reply == 'a')
+ page_size = num_elements - cur_pos;
+ }
+ }
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+ return CC_REDISPLAY;
+}
+
+void
+Editline::ConfigureEditor (bool multiline)
+{
+ if (m_editline && m_multiline_enabled == multiline)
+ return;
+ m_multiline_enabled = multiline;
+
+ if (m_editline)
+ {
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set (m_editline, EL_EDITMODE, 0);
+ el_end (m_editline);
+ }
+
+ m_editline = el_init (m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
+ TerminalSizeChanged();
+
+ if (m_history_sp && m_history_sp->IsValid())
+ {
+ m_history_sp->Load();
+ el_wset (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
+ }
+ el_set (m_editline, EL_CLIENTDATA, this);
+ el_set (m_editline, EL_SIGNAL, 0);
+ el_set (m_editline, EL_EDITOR, "emacs");
+ el_set (m_editline, EL_PROMPT, (EditlinePromptCallbackType)([] (EditLine *editline) {
+ return Editline::InstanceFor (editline)->Prompt();
+ }));
+
+ el_wset (m_editline, EL_GETCFN,
+ (EditlineGetCharCallbackType)([] (EditLine * editline, EditLineCharType * c) {
+ return Editline::InstanceFor (editline)->GetCharacter (c);
+ }));
+
+ // 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_set (m_editline, EL_ADDFN, "lldb-fix-indentation", "Fix line indentation",
+ (EditlineCommandCallbackType)([] (EditLine * editline, int ch) {
+ return Editline::InstanceFor (editline)->FixIndentationCommand (ch);
+ }));
+
+ // Register the complete callback under two names for compatibility with older clients using
+ // custom .editrc files (largely becuase libedit has a bad bug where if you have a bind command
+ // that tries to bind to a function name that doesn't exist, it can corrupt the heap and
+ // crash your process later.)
+ 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);
+
+ // 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
+ }
+ el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode
+ el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to auto complete
+
+ // Allow user-specific customization prior to registering bindings we absolutely require
+ 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);
+ }));
+
+ // Register keys that perform auto-indent correction
+ if (m_fix_indentation_callback && m_fix_indentation_callback_chars)
+ {
+ char bind_key[2] = { 0, 0 };
+ const char * indent_chars = m_fix_indentation_callback_chars;
+ while (*indent_chars)
+ {
+ bind_key[0] = *indent_chars;
+ el_set (m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL);
+ ++indent_chars;
+ }
+ }
+
+ // 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, "^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);
+ el_set (m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL);
+
+ // Editor-specific bindings
+ if (IsEmacs())
+ {
+ el_set (m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL);
+ 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);
+ }
+ else
+ {
+ el_set (m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL);
+
+ el_set (m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL);
+ el_set (m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", NULL);
+ el_set (m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", NULL);
+
+ // Escape is absorbed exiting edit mode, so re-register important sequences
+ // without the prefix
+ el_set (m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL);
+ el_set (m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL);
+ }
+ }
+}
+
+//------------------------------------------------------------------
+// Editline public methods
+//------------------------------------------------------------------
+
+Editline *
+Editline::InstanceFor (EditLine * editline)
+{
+ Editline * editor;
+ el_get (editline, EL_CLIENTDATA, &editor);
+ return editor;
+}
+
+Editline::Editline (const char * editline_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts) :
+ m_editor_status (EditorStatus::Complete),
+ m_color_prompts(color_prompts),
+ m_input_file (input_file),
+ m_output_file (output_file),
+ m_error_file (error_file),
+ m_input_connection (fileno(input_file), false)
+{
+ // Get a shared history instance
+ m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
+ m_history_sp = EditlineHistory::GetHistory (m_editor_name);
+}
+
+Editline::~Editline()
+{
+ if (m_editline)
+ {
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set (m_editline, EL_EDITMODE, 0);
+ el_end (m_editline);
+ m_editline = nullptr;
+ }
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. So just release
+ // our shared pointer and if we are the last owner, it will save the
+ // history to the history save file automatically.
+ m_history_sp.reset();
+}
+
+void
+Editline::SetPrompt (const char * prompt)
+{
+ m_set_prompt = prompt == nullptr ? "" : prompt;
+}
+
+void
+Editline::SetContinuationPrompt (const char * continuation_prompt)
+{
+ m_set_continuation_prompt = continuation_prompt == nullptr ? "" : continuation_prompt;
+}
+
+void
+Editline::TerminalSizeChanged()
+{
+ if (m_editline != nullptr)
+ {
+ el_resize (m_editline);
+ int columns;
+ // Despite the man page claiming non-zero indicates success, it's actually zero
+ if (el_get (m_editline, EL_GETTC, "co", &columns) == 0)
+ {
+ m_terminal_width = columns;
+ if (m_current_line_rows != -1)
+ {
+ const LineInfoW * info = el_wline (m_editline);
+ int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ m_current_line_rows = (lineLength / columns) + 1;
+ }
+ }
+ else
+ {
+ m_terminal_width = INT_MAX;
+ m_current_line_rows = 1;
+ }
+ }
+}
+
+const char *
+Editline::GetPrompt()
+{
+ return m_set_prompt.c_str();
+}
+
+uint32_t
+Editline::GetCurrentLine()
+{
+ return m_current_line_index;
+}
+
+bool
+Editline::Interrupt()
+{
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ fprintf(m_output_file, "^C\n");
+ result = m_input_connection.InterruptRead();
+ }
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
+}
+
+bool
+Editline::Cancel()
+{
+ bool result = true;
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ result = m_input_connection.InterruptRead();
+ }
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
+}
+
+void
+Editline::SetAutoCompleteCallback (CompleteCallbackType callback, void * baton)
+{
+ m_completion_callback = callback;
+ m_completion_callback_baton = baton;
+}
+
+void
+Editline::SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton)
+{
+ m_is_input_complete_callback = callback;
+ m_is_input_complete_callback_baton = baton;
+}
+
+bool
+Editline::SetFixIndentationCallback (FixIndentationCallbackType callback,
+ void * baton,
+ const char * indent_chars)
+{
+ m_fix_indentation_callback = callback;
+ m_fix_indentation_callback_baton = baton;
+ m_fix_indentation_callback_chars = indent_chars;
+ return false;
+}
+
+bool
+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);
+
+ lldbassert(m_editor_status != EditorStatus::Editing);
+ if (m_editor_status == EditorStatus::Interrupted)
+ {
+ m_editor_status = EditorStatus::Complete;
+ interrupted = true;
+ return true;
+ }
+
+ SetCurrentLine (0);
+ m_in_history = false;
+ 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);
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted)
+ {
+ if (input == nullptr)
+ {
+ fprintf (m_output_file, "\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ }
+ else
+ {
+ m_history_sp->Enter (input);
+#if LLDB_EDITLINE_USE_WCHAR
+ line = m_utf8conv.to_bytes (SplitLines (input)[0]);
+#else
+ line = SplitLines (input)[0];
+#endif
+ m_editor_status = EditorStatus::Complete;
+ }
+ }
+ return m_editor_status != EditorStatus::EndOfInput;
+}
+
+bool
+Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
+{
+ ConfigureEditor (true);
+
+ // Print the initial input lines, then move the cursor back up to the start of input
+ 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);
+ // Begin the line editing loop
+ DisplayInput();
+ SetCurrentLine (0);
+ MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart);
+ m_editor_status = EditorStatus::Editing;
+ m_in_history = false;
+
+ 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
+ el_wgets (m_editline, &count);
+ }
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted)
+ {
+ // Save the completed entry in history before returning
+ m_history_sp->Enter (CombineLines (m_input_lines).c_str());
+
+ lines = GetInputAsStringList();
+ }
+ return m_editor_status != EditorStatus::EndOfInput;
+}
+
+void
+Editline::PrintAsync (Stream *stream, const char *s, size_t len)
+{
+ Mutex::Locker locker(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ }
+ stream->Write (s, len);
+ stream->Flush();
+ if (m_editor_status == EditorStatus::Editing)
+ {
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/File.cpp b/contrib/llvm/tools/lldb/source/Host/common/File.cpp
new file mode 100644
index 0000000..71a6149
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/File.cpp
@@ -0,0 +1,1090 @@
+//===-- File.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/File.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include "lldb/Host/windows/windows.h"
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors()
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *
+GetStreamOpenModeFromOptions (uint32_t options)
+{
+ if (options & File::eOpenOptionAppend)
+ {
+ if (options & File::eOpenOptionRead)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "a+x";
+ else
+ return "a+";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "ax";
+ else
+ return "a";
+ }
+ }
+ else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreate)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "w+x";
+ else
+ return "w+";
+ }
+ else
+ return "r+";
+ }
+ else if (options & File::eOpenOptionRead)
+ {
+ return "r";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ return "w";
+ }
+ return NULL;
+}
+
+int File::kInvalidDescriptor = -1;
+FILE * File::kInvalidStream = NULL;
+
+File::File(const char *path, uint32_t options, uint32_t permissions) :
+ IOObject(eFDTypeFile, false),
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (),
+ m_own_stream (false),
+ m_is_interactive (eLazyBoolCalculate),
+ m_is_real_terminal (eLazyBoolCalculate)
+{
+ Open (path, options, permissions);
+}
+
+File::File (const FileSpec& filespec,
+ uint32_t options,
+ uint32_t permissions) :
+ 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)
+
+{
+ if (filespec)
+ {
+ Open (filespec.GetPath().c_str(), options, permissions);
+ }
+}
+
+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 ();
+}
+
+
+int
+File::GetDescriptor() const
+{
+ if (DescriptorIsValid())
+ return m_descriptor;
+
+ // Don't open the file descriptor if we don't need to, just get it from the
+ // stream if we have one.
+ if (StreamIsValid())
+ {
+#if defined(LLVM_ON_WIN32)
+ return _fileno(m_stream);
+#else
+ return fileno(m_stream);
+#endif
+ }
+
+ // Invalid descriptor and invalid stream, return invalid descriptor.
+ return kInvalidDescriptor;
+}
+
+IOObject::WaitableHandle
+File::GetWaitableHandle()
+{
+ return m_descriptor;
+}
+
+
+void
+File::SetDescriptor (int fd, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_descriptor = fd;
+ m_should_close_fd = transfer_ownership;
+}
+
+
+FILE *
+File::GetStream ()
+{
+ if (!StreamIsValid())
+ {
+ if (DescriptorIsValid())
+ {
+ const char *mode = GetStreamOpenModeFromOptions (m_options);
+ if (mode)
+ {
+ if (!m_should_close_fd)
+ {
+ // We must duplicate the file descriptor if we don't own it because
+ // when you call fdopen, the stream will own the fd
+#ifdef _WIN32
+ m_descriptor = ::_dup(GetDescriptor());
+#else
+ m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
+#endif
+ m_should_close_fd = true;
+ }
+
+ do
+ {
+ m_stream = ::fdopen (m_descriptor, mode);
+ } while (m_stream == NULL && errno == EINTR);
+
+ // If we got a stream, then we own the stream and should no
+ // longer own the descriptor because fclose() will close it for us
+
+ if (m_stream)
+ {
+ m_own_stream = true;
+ m_should_close_fd = false;
+ }
+ }
+ }
+ }
+ return m_stream;
+}
+
+
+void
+File::SetStream (FILE *fh, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_stream = fh;
+ m_own_stream = 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;
+ if (IsValid())
+ Close ();
+
+ int oflag = 0;
+ const bool read = options & eOpenOptionRead;
+ const bool write = options & eOpenOptionWrite;
+ if (write)
+ {
+ if (read)
+ oflag |= O_RDWR;
+ else
+ oflag |= O_WRONLY;
+
+ if (options & eOpenOptionAppend)
+ oflag |= O_APPEND;
+
+ if (options & eOpenOptionTruncate)
+ oflag |= O_TRUNC;
+
+ if (options & eOpenOptionCanCreate)
+ oflag |= O_CREAT;
+
+ if (options & eOpenOptionCanCreateNewOnly)
+ oflag |= O_CREAT | O_EXCL;
+ }
+ else if (read)
+ {
+ oflag |= O_RDONLY;
+
+#ifndef _WIN32
+ if (options & eOpenoptionDontFollowSymlinks)
+ oflag |= O_NOFOLLOW;
+#endif
+ }
+
+#ifndef _WIN32
+ if (options & eOpenOptionNonBlocking)
+ oflag |= O_NONBLOCK;
+ if (options & eOpenOptionCloseOnExec)
+ oflag |= O_CLOEXEC;
+#else
+ oflag |= O_BINARY;
+#endif
+
+ mode_t mode = 0;
+ if (oflag & O_CREAT)
+ {
+ if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR;
+ if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR;
+ if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR;
+ if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP;
+ if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP;
+ if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP;
+ if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH;
+ if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH;
+ if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH;
+ }
+
+ do
+ {
+ m_descriptor = ::open(path, oflag, mode);
+ } while (m_descriptor < 0 && errno == EINTR);
+
+ if (!DescriptorIsValid())
+ error.SetErrorToErrno();
+ else
+ {
+ m_should_close_fd = true;
+ m_options = options;
+ }
+
+ return error;
+}
+
+uint32_t
+File::GetPermissions(const FileSpec &file_spec, Error &error)
+{
+ if (file_spec)
+ {
+ struct stat file_stats;
+ if (::stat(file_spec.GetCString(), &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ }
+ else
+ error.SetErrorString ("empty file spec");
+ return 0;
+}
+
+uint32_t
+File::GetPermissions(Error &error) const
+{
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ error.Clear();
+ return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid file descriptor");
+ }
+ return 0;
+}
+
+
+Error
+File::Close ()
+{
+ Error error;
+ if (StreamIsValid() && m_own_stream)
+ {
+ if (::fclose (m_stream) == EOF)
+ error.SetErrorToErrno();
+ }
+
+ if (DescriptorIsValid() && m_should_close_fd)
+ {
+ if (::close (m_descriptor) != 0)
+ error.SetErrorToErrno();
+ }
+ m_descriptor = kInvalidDescriptor;
+ m_stream = kInvalidStream;
+ m_options = 0;
+ m_own_stream = false;
+ m_should_close_fd = false;
+ m_is_interactive = eLazyBoolCalculate;
+ m_is_real_terminal = eLazyBoolCalculate;
+ return error;
+}
+
+
+Error
+File::GetFileSpec (FileSpec &file_spec) const
+{
+ Error error;
+#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
+ if (IsValid ())
+ {
+ char path[PATH_MAX];
+ if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
+ error.SetErrorToErrno();
+ else
+ file_spec.SetFile (path, false);
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+#elif defined(__linux__)
+ char proc[64];
+ char path[PATH_MAX];
+ if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
+ error.SetErrorString ("cannot resolve file descriptor");
+ else
+ {
+ ssize_t len;
+ if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ path[len] = '\0';
+ file_spec.SetFile (path, false);
+ }
+ }
+#else
+ error.SetErrorString ("File::GetFileSpec is not supported on this platform");
+#endif
+
+ if (error.Fail())
+ file_spec.Clear();
+ return error;
+}
+
+off_t
+File::SeekFromStart (off_t offset, Error *error_ptr)
+{
+ off_t result = 0;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromCurrent (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromEnd (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+Error
+File::Flush ()
+{
+ Error error;
+ if (StreamIsValid())
+ {
+ int err = 0;
+ do
+ {
+ err = ::fflush (m_stream);
+ } while (err == EOF && errno == EINTR);
+
+ if (err == EOF)
+ error.SetErrorToErrno();
+ }
+ else if (!DescriptorIsValid())
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+
+Error
+File::Sync ()
+{
+ Error error;
+ if (DescriptorIsValid())
+ {
+#ifdef _WIN32
+ int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor));
+ if (err == 0)
+ error.SetErrorToGenericError();
+#else
+ int err = 0;
+ do
+ {
+ err = ::fsync (m_descriptor);
+ } while (err == -1 && errno == EINTR);
+
+ if (err == -1)
+ error.SetErrorToErrno();
+#endif
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+#if defined (__APPLE__)
+// Darwin kernels only can read/write <= INT_MAX bytes
+#define MAX_READ_SIZE INT_MAX
+#define MAX_WRITE_SIZE INT_MAX
+#endif
+
+Error
+File::Read (void *buf, size_t &num_bytes)
+{
+ Error error;
+
+#if defined (MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE)
+ {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read (p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ ssize_t bytes_read = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_read = ::read (m_descriptor, buf, num_bytes);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_read = ::fread (buf, 1, num_bytes, m_stream);
+
+ if (bytes_read == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes)
+{
+ Error error;
+
+#if defined (MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE)
+ {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write (p + num_bytes, curr_num_bytes);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ ssize_t bytes_written = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_written = ::write (m_descriptor, buf, num_bytes);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
+
+ if (bytes_written == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+
+ return error;
+}
+
+
+Error
+File::Read (void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+
+#if defined (MAX_READ_SIZE)
+ if (num_bytes > MAX_READ_SIZE)
+ {
+ uint8_t *p = (uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes read to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_READ_SIZE)
+ curr_num_bytes = MAX_READ_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Read (p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+#ifndef _WIN32
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ ssize_t bytes_read = -1;
+ do
+ {
+ bytes_read = ::pread (fd, buf, num_bytes, offset);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_read;
+ num_bytes = bytes_read;
+ }
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+#else
+ long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
+ SeekFromStart(offset);
+ error = Read(buf, num_bytes);
+ if (!error.Fail())
+ SeekFromStart(cur);
+#endif
+ return error;
+}
+
+Error
+File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
+{
+ Error error;
+
+ if (num_bytes > 0)
+ {
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == 0)
+ {
+ if (file_stats.st_size > offset)
+ {
+ const size_t bytes_left = file_stats.st_size - offset;
+ if (num_bytes > bytes_left)
+ num_bytes = bytes_left;
+
+ size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0);
+ std::unique_ptr<DataBufferHeap> data_heap_ap;
+ data_heap_ap.reset(new DataBufferHeap());
+ data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
+
+ if (data_heap_ap.get())
+ {
+ error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
+ if (error.Success())
+ {
+ // Make sure we read exactly what we asked for and if we got
+ // less, adjust the array
+ if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize())
+ data_heap_ap->SetByteSize(num_bytes_plus_nul_char);
+ data_buffer_sp.reset(data_heap_ap.release());
+ return error;
+ }
+ }
+ }
+ else
+ error.SetErrorString("file is empty");
+ }
+ else
+ error.SetErrorToErrno();
+ }
+ else
+ error.SetErrorString("invalid file handle");
+ }
+ else
+ error.SetErrorString("invalid file handle");
+
+ num_bytes = 0;
+ data_buffer_sp.reset();
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+
+#if defined (MAX_WRITE_SIZE)
+ if (num_bytes > MAX_WRITE_SIZE)
+ {
+ const uint8_t *p = (const uint8_t *)buf;
+ size_t bytes_left = num_bytes;
+ // Init the num_bytes written to zero
+ num_bytes = 0;
+
+ while (bytes_left > 0)
+ {
+ size_t curr_num_bytes;
+ if (bytes_left > MAX_WRITE_SIZE)
+ curr_num_bytes = MAX_WRITE_SIZE;
+ else
+ curr_num_bytes = bytes_left;
+
+ error = Write (p + num_bytes, curr_num_bytes, offset);
+
+ // Update how many bytes were read
+ num_bytes += curr_num_bytes;
+ if (bytes_left < curr_num_bytes)
+ bytes_left = 0;
+ else
+ bytes_left -= curr_num_bytes;
+
+ if (error.Fail())
+ break;
+ }
+ return error;
+ }
+#endif
+
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+#ifndef _WIN32
+ ssize_t bytes_written = -1;
+ do
+ {
+ bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_written;
+ num_bytes = bytes_written;
+ }
+#else
+ long cur = ::lseek(m_descriptor, 0, SEEK_CUR);
+ error = Write(buf, num_bytes);
+ long after = ::lseek(m_descriptor, 0, SEEK_CUR);
+
+ if (!error.Fail())
+ SeekFromStart(cur);
+
+ offset = after;
+#endif
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::Printf (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ size_t result = PrintfVarArg (format, args);
+ va_end (args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::PrintfVarArg (const char *format, va_list args)
+{
+ size_t result = 0;
+ if (DescriptorIsValid())
+ {
+ char *s = NULL;
+ result = vasprintf(&s, format, args);
+ if (s != NULL)
+ {
+ if (result > 0)
+ {
+ size_t s_len = result;
+ Write (s, s_len);
+ result = s_len;
+ }
+ free (s);
+ }
+ }
+ else if (StreamIsValid())
+ {
+ result = ::vfprintf (m_stream, format, args);
+ }
+ return result;
+}
+
+mode_t
+File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
+{
+ mode_t mode = 0;
+ if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
+ mode |= O_RDWR;
+ else if (open_options & eOpenOptionWrite)
+ mode |= O_WRONLY;
+
+ if (open_options & eOpenOptionAppend)
+ mode |= O_APPEND;
+
+ if (open_options & eOpenOptionTruncate)
+ mode |= O_TRUNC;
+
+ if (open_options & eOpenOptionNonBlocking)
+ mode |= O_NONBLOCK;
+
+ if (open_options & eOpenOptionCanCreateNewOnly)
+ mode |= O_CREAT | O_EXCL;
+ else if (open_options & eOpenOptionCanCreate)
+ mode |= O_CREAT;
+
+ return mode;
+}
+
+void
+File::CalculateInteractiveAndTerminal ()
+{
+ const int fd = GetDescriptor();
+ if (fd >= 0)
+ {
+ m_is_interactive = eLazyBoolNo;
+ m_is_real_terminal = eLazyBoolNo;
+#if (defined(_WIN32) || defined(__ANDROID_NDK__))
+ if (_isatty(fd))
+ {
+ m_is_interactive = eLazyBoolYes;
+ m_is_real_terminal = eLazyBoolYes;
+ }
+#else
+ if (isatty(fd))
+ {
+ m_is_interactive = eLazyBoolYes;
+ struct winsize window_size;
+ if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0)
+ {
+ if (window_size.ws_col > 0)
+ {
+ m_is_real_terminal = eLazyBoolYes;
+ if (llvm::sys::Process::FileDescriptorHasColors(fd))
+ m_supports_colors = eLazyBoolYes;
+ }
+ }
+ }
+#endif
+ }
+}
+
+bool
+File::GetIsInteractive ()
+{
+ if (m_is_interactive == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal ();
+ return m_is_interactive == eLazyBoolYes;
+}
+
+bool
+File::GetIsRealTerminal ()
+{
+ if (m_is_real_terminal == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal();
+ return m_is_real_terminal == eLazyBoolYes;
+}
+
+bool
+File::GetIsTerminalWithColors ()
+{
+ if (m_supports_colors == eLazyBoolCalculate)
+ CalculateInteractiveAndTerminal();
+ return m_supports_colors == eLazyBoolYes;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp
new file mode 100644
index 0000000..96b2a2e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp
@@ -0,0 +1,127 @@
+//===-- FileCache.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/FileCache.h"
+
+#include "lldb/Host/File.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FileCache *FileCache::m_instance = nullptr;
+
+FileCache &
+FileCache::GetInstance()
+{
+ if (m_instance == nullptr)
+ m_instance = new FileCache();
+
+ return *m_instance;
+}
+
+lldb::user_id_t
+FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags, uint32_t mode, Error &error)
+{
+ std::string path(file_spec.GetPath());
+ if (path.empty())
+ {
+ error.SetErrorString("empty path");
+ return UINT64_MAX;
+ }
+ FileSP file_sp(new File());
+ error = file_sp->Open(path.c_str(), flags, mode);
+ if (file_sp->IsValid() == false)
+ return UINT64_MAX;
+ lldb::user_id_t fd = file_sp->GetDescriptor();
+ m_cache[fd] = file_sp;
+ return fd;
+}
+
+bool
+FileCache::CloseFile(lldb::user_id_t fd, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return false;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return false;
+ }
+ error = file_sp->Close();
+ m_cache.erase(pos);
+ return error.Success();
+}
+
+uint64_t
+FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_written = src_len;
+ error = file_sp->Write(src, bytes_written);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_written;
+}
+
+uint64_t
+FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Error &error)
+{
+ if (fd == UINT64_MAX)
+ {
+ error.SetErrorString("invalid file descriptor");
+ return UINT64_MAX;
+ }
+ FDToFileMap::iterator pos = m_cache.find(fd);
+ if (pos == m_cache.end())
+ {
+ error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
+ return false;
+ }
+ FileSP file_sp = pos->second;
+ if (!file_sp)
+ {
+ error.SetErrorString("invalid host backing file");
+ return UINT64_MAX;
+ }
+ if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail())
+ return UINT64_MAX;
+ size_t bytes_read = dst_len;
+ error = file_sp->Read(dst, bytes_read);
+ if (error.Fail())
+ return UINT64_MAX;
+ return bytes_read;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp
new file mode 100644
index 0000000..8885a79
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp
@@ -0,0 +1,1554 @@
+//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef _WIN32
+#include <dirent.h>
+#else
+#include "lldb/Host/windows/windows.h"
+#endif
+#include <fcntl.h>
+#ifndef _MSC_VER
+#include <libgen.h>
+#endif
+#include <sys/stat.h>
+#include <set>
+#include <string.h>
+#include <fstream>
+
+#include "lldb/Host/Config.h" // Have to include this before we test the define...
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+#include <pwd.h>
+#endif
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/CleanUp.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+bool
+PathSyntaxIsPosix(FileSpec::PathSyntax syntax)
+{
+ return (syntax == FileSpec::ePathSyntaxPosix ||
+ (syntax == FileSpec::ePathSyntaxHostNative &&
+ FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix));
+}
+
+char
+GetPathSeparator(FileSpec::PathSyntax syntax)
+{
+ return PathSyntaxIsPosix(syntax) ? '/' : '\\';
+}
+
+void
+Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax)
+{
+ if (PathSyntaxIsPosix(syntax)) return;
+
+ std::replace(path.begin(), path.end(), '\\', '/');
+ // Windows path can have \\ slashes which can be changed by replace
+ // call above to //. Here we remove the duplicate.
+ auto iter = std::unique ( path.begin(), path.end(),
+ []( char &c1, char &c2 ){
+ return (c1 == '/' && c2 == '/');});
+ path.erase(iter, path.end());
+}
+
+void
+Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax)
+{
+ if (PathSyntaxIsPosix(syntax)) return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
+bool
+GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
+{
+ char resolved_path[PATH_MAX];
+ if (file_spec->GetPath (resolved_path, sizeof(resolved_path)))
+ return ::stat (resolved_path, stats_ptr) == 0;
+ return false;
+}
+
+}
+
+// Resolves the username part of a path of the form ~user/other/directories, and
+// writes the result into dst_path. This will also resolve "~" to the current user.
+// If you want to complete "~" to the list of users, pass it to ResolvePartialUsername.
+void
+FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
+{
+#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ if (path.empty() || path[0] != '~')
+ return;
+
+ llvm::StringRef path_str(path.data(), path.size());
+ size_t slash_pos = path_str.find('/', 1);
+ if (slash_pos == 1 || path.size() == 1)
+ {
+ // A path of ~/ resolves to the current user's home dir
+ llvm::SmallString<64> home_dir;
+ if (!llvm::sys::path::home_directory(home_dir))
+ return;
+
+ // Overwrite the ~ with the first character of the homedir, and insert
+ // the rest. This way we only trigger one move, whereas an insert
+ // followed by a delete (or vice versa) would trigger two.
+ path[0] = home_dir[0];
+ path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end());
+ return;
+ }
+
+ auto username_begin = path.begin()+1;
+ auto username_end = (slash_pos == llvm::StringRef::npos)
+ ? path.end()
+ : (path.begin() + slash_pos);
+ size_t replacement_length = std::distance(path.begin(), username_end);
+
+ llvm::SmallString<20> username(username_begin, username_end);
+ struct passwd *user_entry = ::getpwnam(username.c_str());
+ if (user_entry != nullptr)
+ {
+ // Copy over the first n characters of the path, where n is the smaller of the length
+ // of the home directory and the slash pos.
+ llvm::StringRef homedir(user_entry->pw_dir);
+ size_t initial_copy_length = std::min(homedir.size(), replacement_length);
+ auto src_begin = homedir.begin();
+ auto src_end = src_begin + initial_copy_length;
+ std::copy(src_begin, src_end, path.begin());
+ if (replacement_length > homedir.size())
+ {
+ // We copied the entire home directory, but the ~username portion of the path was
+ // longer, so there's characters that need to be removed.
+ path.erase(path.begin() + initial_copy_length, username_end);
+ }
+ else if (replacement_length < homedir.size())
+ {
+ // We copied all the way up to the slash in the destination, but there's still more
+ // characters that need to be inserted.
+ path.insert(username_end, src_end, homedir.end());
+ }
+ }
+ else
+ {
+ // Unable to resolve username (user doesn't exist?)
+ path.clear();
+ }
+#endif
+}
+
+size_t
+FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches)
+{
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ size_t extant_entries = matches.GetSize();
+
+ setpwent();
+ struct passwd *user_entry;
+ const char *name_start = partial_name + 1;
+ std::set<std::string> name_list;
+
+ while ((user_entry = getpwent()) != NULL)
+ {
+ if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name)
+ {
+ std::string tmp_buf("~");
+ tmp_buf.append(user_entry->pw_name);
+ tmp_buf.push_back('/');
+ name_list.insert(tmp_buf);
+ }
+ }
+ std::set<std::string>::iterator pos, end = name_list.end();
+ for (pos = name_list.begin(); pos != end; pos++)
+ {
+ matches.AppendString((*pos).c_str());
+ }
+ return matches.GetSize() - extant_entries;
+#else
+ // Resolving home directories is not supported, just copy the path...
+ return 0;
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+}
+
+void
+FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
+{
+ if (path.empty())
+ return;
+
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ if (path[0] == '~')
+ ResolveUsername(path);
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+
+ // Save a copy of the original path that's passed in
+ llvm::SmallString<PATH_MAX> 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)
+ {
+ path.clear();
+ path.append(original_path.begin(), original_path.end());
+ }
+}
+
+FileSpec::FileSpec() :
+ m_directory(),
+ m_filename(),
+ m_syntax(FileSystem::GetNativePathSyntax())
+{
+}
+
+//------------------------------------------------------------------
+// Default constructor that can take an optional full path to a
+// file on disk.
+//------------------------------------------------------------------
+FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
+ m_directory(),
+ m_filename(),
+ m_is_resolved(false),
+ m_syntax(syntax)
+{
+ if (pathname && pathname[0])
+ SetFile(pathname, resolve_path, syntax);
+}
+
+FileSpec::FileSpec(const char *pathname, bool resolve_path, ArchSpec arch) :
+ FileSpec{pathname, resolve_path, arch.GetTriple().isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix}
+{
+}
+
+FileSpec::FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax) :
+ FileSpec{path.c_str(), resolve_path, syntax}
+{
+}
+
+FileSpec::FileSpec(const std::string &path, bool resolve_path, ArchSpec arch) :
+ FileSpec{path.c_str(), resolve_path, arch}
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec& rhs) :
+ m_directory (rhs.m_directory),
+ m_filename (rhs.m_filename),
+ m_is_resolved (rhs.m_is_resolved),
+ m_syntax (rhs.m_syntax)
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec* rhs) :
+ m_directory(),
+ m_filename()
+{
+ if (rhs)
+ *this = *rhs;
+}
+
+//------------------------------------------------------------------
+// Virtual destructor in case anyone inherits from this class.
+//------------------------------------------------------------------
+FileSpec::~FileSpec()
+{
+}
+
+//------------------------------------------------------------------
+// Assignment operator.
+//------------------------------------------------------------------
+const FileSpec&
+FileSpec::operator= (const FileSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_directory = rhs.m_directory;
+ m_filename = rhs.m_filename;
+ m_is_resolved = rhs.m_is_resolved;
+ m_syntax = rhs.m_syntax;
+ }
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Update the contents of this object with a new path. The path will
+// be split up into a directory and filename and stored as uniqued
+// string values for quick comparison and efficient memory usage.
+//------------------------------------------------------------------
+void
+FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax)
+{
+ m_filename.Clear();
+ m_directory.Clear();
+ m_is_resolved = false;
+ m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax;
+
+ if (pathname == NULL || pathname[0] == '\0')
+ return;
+
+ llvm::SmallString<64> normalized(pathname);
+
+ if (resolve)
+ {
+ FileSpec::Resolve (normalized);
+ 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);
+
+ llvm::StringRef resolve_path_ref(normalized.c_str());
+ llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
+ if (!filename_ref.empty())
+ {
+ 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);
+ }
+ else
+ m_directory.SetCString(normalized.c_str());
+}
+
+void
+FileSpec::SetFile(const char *pathname, bool resolve, ArchSpec arch)
+{
+ return SetFile(pathname, resolve,
+ arch.GetTriple().isOSWindows()
+ ? ePathSyntaxWindows
+ : ePathSyntaxPosix);
+}
+
+void
+FileSpec::SetFile(const std::string &pathname, bool resolve, PathSyntax syntax)
+{
+ return SetFile(pathname.c_str(), resolve, syntax);
+}
+
+void
+FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch)
+{
+ return SetFile(pathname.c_str(), resolve, arch);
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any FileSpec
+// objects to see if they contain anything valid using code such as:
+//
+// if (file_spec)
+// {}
+//----------------------------------------------------------------------
+FileSpec::operator bool() const
+{
+ return m_filename || m_directory;
+}
+
+//----------------------------------------------------------------------
+// Logical NOT operator. This allows code to check any FileSpec
+// objects to see if they are invalid using code such as:
+//
+// if (!file_spec)
+// {}
+//----------------------------------------------------------------------
+bool
+FileSpec::operator!() const
+{
+ return !m_directory && !m_filename;
+}
+
+//------------------------------------------------------------------
+// Equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator== (const FileSpec& rhs) const
+{
+ if (m_filename == rhs.m_filename)
+ {
+ 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);
+
+ // If "this" isn't resolved, resolve it
+ if (!IsResolved())
+ {
+ if (resolved_lhs.ResolvePath())
+ {
+ // This path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as our unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ m_is_resolved = (m_directory == resolved_lhs.m_directory);
+ }
+ else
+ return false;
+ }
+
+ FileSpec resolved_rhs(rhs);
+ if (!rhs.IsResolved())
+ {
+ if (resolved_rhs.ResolvePath())
+ {
+ // rhs's path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as rhs's unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
+ }
+ else
+ return false;
+ }
+
+ // If we reach this point in the code we were able to resolve both paths
+ // and since we only resolve the paths if the basenames are equal, then
+ // we can just check if both directories are equal...
+ return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory();
+ }
+ return false;
+}
+
+//------------------------------------------------------------------
+// Not equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator!= (const FileSpec& rhs) const
+{
+ return !(*this == rhs);
+}
+
+//------------------------------------------------------------------
+// Less than operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator< (const FileSpec& rhs) const
+{
+ return FileSpec::Compare(*this, rhs, true) < 0;
+}
+
+//------------------------------------------------------------------
+// Dump a FileSpec object to a stream
+//------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream &s, const FileSpec& f)
+{
+ f.Dump(&s);
+ return s;
+}
+
+//------------------------------------------------------------------
+// Clear this object by releasing both the directory and filename
+// string values and making them both the empty string.
+//------------------------------------------------------------------
+void
+FileSpec::Clear()
+{
+ m_directory.Clear();
+ m_filename.Clear();
+}
+
+//------------------------------------------------------------------
+// Compare two FileSpec objects. If "full" is true, then both
+// the directory and the filename must match. If "full" is false,
+// then the directory names for "a" and "b" are only compared if
+// they are both non-empty. This allows a FileSpec object to only
+// contain a filename and it can match FileSpec objects that have
+// matching filenames with different paths.
+//
+// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
+// and "1" if "a" is greater than "b".
+//------------------------------------------------------------------
+int
+FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
+{
+ int result = 0;
+
+ // If full is true, then we must compare both the directory and filename.
+
+ // If full is false, then if either directory is empty, then we match on
+ // the basename only, and if both directories have valid values, we still
+ // do a full compare. This allows for matching when we just have a filename
+ // in one of the FileSpec objects.
+
+ if (full || (a.m_directory && b.m_directory))
+ {
+ result = ConstString::Compare(a.m_directory, b.m_directory);
+ if (result)
+ return result;
+ }
+ return ConstString::Compare (a.m_filename, b.m_filename);
+}
+
+bool
+FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups)
+{
+ if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
+ return a.m_filename == b.m_filename;
+ else if (remove_backups == false)
+ return a == b;
+ else
+ {
+ if (a.m_filename != b.m_filename)
+ return false;
+ if (a.m_directory == b.m_directory)
+ 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;
+ }
+}
+
+void
+FileSpec::NormalizePath ()
+{
+ ConstString normalized_directory;
+ FileSpec::RemoveBackupDots(m_directory, normalized_directory);
+ m_directory = normalized_directory;
+}
+
+void
+FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str)
+{
+ const char *input = input_const_str.GetCString();
+ result_const_str.Clear();
+ if (!input || input[0] == '\0')
+ return;
+
+ const char win_sep = '\\';
+ const char unix_sep = '/';
+ char found_sep;
+ const char *win_backup = "\\..";
+ const char *unix_backup = "/..";
+
+ bool is_win = false;
+
+ // Determine the platform for the path (win or unix):
+
+ if (input[0] == win_sep)
+ is_win = true;
+ else if (input[0] == unix_sep)
+ is_win = false;
+ else if (input[1] == ':')
+ is_win = true;
+ else if (strchr(input, unix_sep) != nullptr)
+ is_win = false;
+ else if (strchr(input, win_sep) != nullptr)
+ is_win = true;
+ else
+ {
+ // No separators at all, no reason to do any work here.
+ result_const_str = input_const_str;
+ return;
+ }
+
+ llvm::StringRef backup_sep;
+ if (is_win)
+ {
+ found_sep = win_sep;
+ backup_sep = win_backup;
+ }
+ else
+ {
+ found_sep = unix_sep;
+ backup_sep = unix_backup;
+ }
+
+ llvm::StringRef input_ref(input);
+ llvm::StringRef curpos(input);
+
+ bool had_dots = false;
+ std::string result;
+
+ while (1)
+ {
+ // Start of loop
+ llvm::StringRef before_sep;
+ std::pair<llvm::StringRef, llvm::StringRef> around_sep = curpos.split(backup_sep);
+
+ before_sep = around_sep.first;
+ curpos = around_sep.second;
+
+ if (curpos.empty())
+ {
+ if (had_dots)
+ {
+ while (before_sep.startswith("//"))
+ before_sep = before_sep.substr(1);
+ if (!before_sep.empty())
+ {
+ result.append(before_sep.data(), before_sep.size());
+ }
+ }
+ break;
+ }
+ had_dots = true;
+
+ unsigned num_backups = 1;
+ while (curpos.startswith(backup_sep))
+ {
+ num_backups++;
+ curpos = curpos.slice(backup_sep.size(), curpos.size());
+ }
+
+ size_t end_pos = before_sep.size();
+ while (num_backups-- > 0)
+ {
+ end_pos = before_sep.rfind(found_sep, end_pos);
+ if (end_pos == llvm::StringRef::npos)
+ {
+ result_const_str = input_const_str;
+ return;
+ }
+ }
+ result.append(before_sep.data(), end_pos);
+ }
+
+ if (had_dots)
+ result_const_str.SetCString(result.c_str());
+ else
+ result_const_str = input_const_str;
+
+ return;
+}
+
+//------------------------------------------------------------------
+// Dump the object to the supplied stream. If the object contains
+// a valid directory name, it will be displayed followed by a
+// directory delimiter, and the filename.
+//------------------------------------------------------------------
+void
+FileSpec::Dump(Stream *s) const
+{
+ if (s)
+ {
+ std::string path{GetPath(true)};
+ s->PutCString(path.c_str());
+ char path_separator = GetPathSeparator(m_syntax);
+ if (!m_filename && !path.empty() && path.back() != path_separator)
+ s->PutChar(path_separator);
+ }
+}
+
+//------------------------------------------------------------------
+// Returns true if the file exists.
+//------------------------------------------------------------------
+bool
+FileSpec::Exists () const
+{
+ struct stat file_stats;
+ return GetFileStats (this, &file_stats);
+}
+
+bool
+FileSpec::Readable () const
+{
+ const uint32_t permissions = GetPermissions();
+ if (permissions & eFilePermissionsEveryoneR)
+ return true;
+ return false;
+}
+
+bool
+FileSpec::ResolveExecutableLocation ()
+{
+ if (!m_directory)
+ {
+ const char *file_cstr = m_filename.GetCString();
+ if (file_cstr)
+ {
+ const std::string file_str (file_cstr);
+ llvm::ErrorOr<std::string> error_or_path = llvm::sys::findProgramByName (file_str);
+ if (!error_or_path)
+ return false;
+ std::string path = error_or_path.get();
+ llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
+ if (!dir_ref.empty())
+ {
+ // FindProgramByName returns "." if it can't find the file.
+ if (strcmp (".", dir_ref.data()) == 0)
+ return false;
+
+ m_directory.SetCString (dir_ref.data());
+ if (Exists())
+ return true;
+ else
+ {
+ // If FindProgramByName found the file, it returns the directory + filename in its return results.
+ // We need to separate them.
+ FileSpec tmp_file (dir_ref.data(), false);
+ if (tmp_file.Exists())
+ {
+ m_directory = tmp_file.m_directory;
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+FileSpec::ResolvePath ()
+{
+ if (m_is_resolved)
+ return true; // We have already resolved this path
+
+ char path_buf[PATH_MAX];
+ if (!GetPath (path_buf, PATH_MAX, false))
+ return false;
+ // SetFile(...) will set m_is_resolved correctly if it can resolve the path
+ SetFile (path_buf, true);
+ return m_is_resolved;
+}
+
+uint64_t
+FileSpec::GetByteSize() const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ return file_stats.st_size;
+ return 0;
+}
+
+FileSpec::PathSyntax
+FileSpec::GetPathSyntax() const
+{
+ return m_syntax;
+}
+
+FileSpec::FileType
+FileSpec::GetFileType () const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ {
+ mode_t file_type = file_stats.st_mode & S_IFMT;
+ switch (file_type)
+ {
+ case S_IFDIR: return eFileTypeDirectory;
+ case S_IFREG: return eFileTypeRegular;
+#ifndef _WIN32
+ case S_IFIFO: return eFileTypePipe;
+ case S_IFSOCK: return eFileTypeSocket;
+ case S_IFLNK: return eFileTypeSymbolicLink;
+#endif
+ default:
+ break;
+ }
+ return eFileTypeUnknown;
+ }
+ return eFileTypeInvalid;
+}
+
+bool
+FileSpec::IsSymbolicLink () const
+{
+ char resolved_path[PATH_MAX];
+ if (!GetPath (resolved_path, sizeof (resolved_path)))
+ return false;
+
+#ifdef _WIN32
+ auto attrs = ::GetFileAttributes (resolved_path);
+ if (attrs == INVALID_FILE_ATTRIBUTES)
+ return false;
+
+ return (attrs & FILE_ATTRIBUTE_REPARSE_POINT);
+#else
+ struct stat file_stats;
+ if (::lstat (resolved_path, &file_stats) != 0)
+ return false;
+
+ return (file_stats.st_mode & S_IFMT) == S_IFLNK;
+#endif
+}
+
+uint32_t
+FileSpec::GetPermissions () const
+{
+ uint32_t file_permissions = 0;
+ if (*this)
+ FileSystem::GetFilePermissions(*this, file_permissions);
+ return file_permissions;
+}
+
+TimeValue
+FileSpec::GetModificationTime () const
+{
+ TimeValue mod_time;
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ mod_time.OffsetWithSeconds(file_stats.st_mtime);
+ return mod_time;
+}
+
+//------------------------------------------------------------------
+// Directory string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetDirectory()
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Directory string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetDirectory() const
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Filename string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetFilename()
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Filename string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetFilename() const
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Extract the directory and path into a fixed buffer. This is
+// needed as the directory and path are stored in separate string
+// values.
+//------------------------------------------------------------------
+size_t
+FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const
+{
+ if (!path)
+ return 0;
+
+ std::string result = GetPath(denormalize);
+ ::snprintf(path, path_max_len, "%s", result.c_str());
+ return std::min(path_max_len-1, result.length());
+}
+
+std::string
+FileSpec::GetPath(bool denormalize) const
+{
+ llvm::SmallString<64> result;
+ GetPath(result, denormalize);
+ return std::string(result.begin(), result.end());
+}
+
+const char *
+FileSpec::GetCString(bool denormalize) const
+{
+ return ConstString{GetPath(denormalize)}.AsCString(NULL);
+}
+
+void
+FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const
+{
+ path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end());
+ if (m_directory)
+ path.insert(path.end(), '/');
+ 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);
+}
+
+ConstString
+FileSpec::GetFileNameExtension () const
+{
+ if (m_filename)
+ {
+ const char *filename = m_filename.GetCString();
+ const char* dot_pos = strrchr(filename, '.');
+ if (dot_pos && dot_pos[1] != '\0')
+ return ConstString(dot_pos+1);
+ }
+ return ConstString();
+}
+
+ConstString
+FileSpec::GetFileNameStrippingExtension () const
+{
+ const char *filename = m_filename.GetCString();
+ if (filename == NULL)
+ return ConstString();
+
+ const char* dot_pos = strrchr(filename, '.');
+ if (dot_pos == NULL)
+ return m_filename;
+
+ return ConstString(filename, dot_pos-filename);
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data is memory mapped and
+// will lazily page in data from the file as memory is accessed.
+// The data that is mapped will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
+{
+ DataBufferSP data_sp;
+ std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
+ if (mmap_data.get())
+ {
+ const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size);
+ if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size))
+ data_sp.reset(mmap_data.release());
+ }
+ return data_sp;
+}
+
+DataBufferSP
+FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const
+{
+ if (FileSystem::IsLocal(*this))
+ return MemoryMapFileContents(file_offset, file_size);
+ else
+ return ReadFileContents(file_offset, file_size, NULL);
+}
+
+
+//------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. This
+// returns the size in bytes of this object, not any shared string
+// values it may refer to.
+//------------------------------------------------------------------
+size_t
+FileSpec::MemorySize() const
+{
+ return m_filename.MemorySize() + m_directory.MemorySize();
+}
+
+
+size_t
+FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const
+{
+ Error error;
+ size_t bytes_read = 0;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ off_t file_offset_after_seek = file_offset;
+ bytes_read = dst_len;
+ error = file.Read(dst, bytes_read, file_offset_after_seek);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return bytes_read;
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data copies into a heap based
+// buffer that lives in the DataBuffer shared pointer object returned.
+// The data that is cached will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const
+{
+ Error error;
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ const bool null_terminate = false;
+ error = file.Read (file_size, file_offset, null_terminate, data_sp);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return data_sp;
+}
+
+DataBufferSP
+FileSpec::ReadFileContentsAsCString(Error *error_ptr)
+{
+ Error error;
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ off_t offset = 0;
+ size_t length = SIZE_MAX;
+ const bool null_terminate = true;
+ error = file.Read (length, offset, null_terminate, data_sp);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return data_sp;
+}
+
+size_t
+FileSpec::ReadFileLines (STLStringArray &lines)
+{
+ lines.clear();
+ char path[PATH_MAX];
+ if (GetPath(path, sizeof(path)))
+ {
+ std::ifstream file_stream (path);
+
+ if (file_stream)
+ {
+ std::string line;
+ while (getline (file_stream, line))
+ lines.push_back (line);
+ }
+ }
+ return lines.size();
+}
+
+FileSpec::EnumerateDirectoryResult
+FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback)
+{
+ if (dir_path && dir_path[0])
+ {
+#if _WIN32
+ std::string szDir(dir_path);
+ szDir += "\\*";
+
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ return eEnumerateDirectoryResultNext;
+ }
+
+ do
+ {
+ FileSpec::FileType file_type = eFileTypeUnknown;
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ size_t len = strlen(ffd.cFileName);
+
+ if (len == 1 && ffd.cFileName[0] == '.')
+ continue;
+
+ if (len == 2 && ffd.cFileName[0] == '.' && ffd.cFileName[1] == '.')
+ continue;
+
+ file_type = eFileTypeDirectory;
+ }
+ else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE)
+ {
+ file_type = eFileTypeOther;
+ }
+ else
+ {
+ 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))
+ {
+ // Don't resolve the file type or path
+ FileSpec child_path_spec (child_path, false);
+
+ EnumerateDirectoryResult result = callback (file_type, child_path_spec);
+
+ switch (result)
+ {
+ case eEnumerateDirectoryResultNext:
+ // Enumerate next entry in the current directory. We just
+ // exit this switch and will continue enumerating the
+ // current directory as we currently are...
+ break;
+
+ case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
+ if (FileSpec::ForEachItemInDirectory(child_path, callback) == eEnumerateDirectoryResultQuit)
+ {
+ // The subdirectory returned Quit, which means to
+ // stop all directory enumerations at all levels.
+ return eEnumerateDirectoryResultQuit;
+ }
+ break;
+
+ case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
+ // Exit from this directory level and tell parent to
+ // keep enumerating.
+ return eEnumerateDirectoryResultNext;
+
+ case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
+ return eEnumerateDirectoryResultQuit;
+ }
+ }
+ } while (FindNextFile(hFind, &ffd) != 0);
+
+ FindClose(hFind);
+#else
+ lldb_utility::CleanUp <DIR *, int> dir_path_dir(opendir(dir_path), NULL, closedir);
+ if (dir_path_dir.is_valid())
+ {
+ char dir_path_last_char = dir_path[strlen(dir_path) - 1];
+
+ long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX);
+#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN)
+ if (path_max < __DARWIN_MAXPATHLEN)
+ path_max = __DARWIN_MAXPATHLEN;
+#endif
+ struct dirent *buf, *dp;
+ buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1);
+
+ while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp)
+ {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
+ {
+ size_t len = strlen(dp->d_name);
+
+ if (len == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ FileSpec::FileType file_type = eFileTypeUnknown;
+
+ switch (dp->d_type)
+ {
+ default:
+ case DT_UNKNOWN: file_type = eFileTypeUnknown; break;
+ case DT_FIFO: file_type = eFileTypePipe; break;
+ case DT_CHR: file_type = eFileTypeOther; break;
+ case DT_DIR: file_type = eFileTypeDirectory; break;
+ case DT_BLK: file_type = eFileTypeOther; break;
+ case DT_REG: file_type = eFileTypeRegular; break;
+ case DT_LNK: file_type = eFileTypeSymbolicLink; break;
+ case DT_SOCK: file_type = eFileTypeSocket; break;
+#if !defined(__OpenBSD__)
+ case DT_WHT: file_type = eFileTypeOther; break;
+#endif
+ }
+
+ char child_path[PATH_MAX];
+
+ // Don't make paths with "/foo//bar", that just confuses everybody.
+ int child_path_len;
+ if (dir_path_last_char == '/')
+ child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name);
+ else
+ child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name);
+
+ if (child_path_len < (int)(sizeof(child_path) - 1))
+ {
+ // Don't resolve the file type or path
+ FileSpec child_path_spec (child_path, false);
+
+ EnumerateDirectoryResult result = callback (file_type, child_path_spec);
+
+ switch (result)
+ {
+ case eEnumerateDirectoryResultNext:
+ // Enumerate next entry in the current directory. We just
+ // exit this switch and will continue enumerating the
+ // current directory as we currently are...
+ break;
+
+ case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
+ if (FileSpec::ForEachItemInDirectory (child_path, callback) == eEnumerateDirectoryResultQuit)
+ {
+ // The subdirectory returned Quit, which means to
+ // stop all directory enumerations at all levels.
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultQuit;
+ }
+ break;
+
+ case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
+ // Exit from this directory level and tell parent to
+ // keep enumerating.
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultNext;
+
+ case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultQuit;
+ }
+ }
+ }
+ if (buf)
+ {
+ free (buf);
+ }
+ }
+#endif
+ }
+ // By default when exiting a directory, we tell the parent enumeration
+ // to continue enumerating.
+ return eEnumerateDirectoryResultNext;
+}
+
+FileSpec::EnumerateDirectoryResult
+FileSpec::EnumerateDirectory
+(
+ const char *dir_path,
+ bool find_directories,
+ bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton
+)
+{
+ return ForEachItemInDirectory(dir_path,
+ [&find_directories, &find_files, &find_other, &callback, &callback_baton]
+ (FileType file_type, const FileSpec &file_spec) {
+ switch (file_type)
+ {
+ case FileType::eFileTypeDirectory:
+ if (find_directories)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ case FileType::eFileTypeRegular:
+ if (find_files)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ default:
+ if (find_other)
+ return callback(callback_baton, file_type, file_spec);
+ break;
+ }
+ return eEnumerateDirectoryResultNext;
+ });
+}
+
+FileSpec
+FileSpec::CopyByAppendingPathComponent (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
+FileSpec::CopyByRemovingLastPathComponent () const
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_directory.IsEmpty())
+ return FileSpec("",resolve);
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ return FileSpec("",resolve);
+ if (last_slash_ptr == dir_cstr)
+ return FileSpec("/",resolve);
+
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ return FileSpec(new_path.GetCString(),resolve);
+ }
+ else
+ return FileSpec(m_directory.GetCString(),resolve);
+}
+
+ConstString
+FileSpec::GetLastPathComponent () const
+{
+ if (m_filename)
+ return m_filename;
+ if (m_directory)
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+ if (last_slash_ptr == NULL)
+ return m_directory;
+ if (last_slash_ptr == dir_cstr)
+ {
+ if (last_slash_ptr[1] == 0)
+ return ConstString(last_slash_ptr);
+ else
+ return ConstString(last_slash_ptr+1);
+ }
+ if (last_slash_ptr[1] != 0)
+ return ConstString(last_slash_ptr+1);
+ const char* penultimate_slash_ptr = last_slash_ptr;
+ while (*penultimate_slash_ptr)
+ {
+ --penultimate_slash_ptr;
+ if (penultimate_slash_ptr == dir_cstr)
+ break;
+ if (*penultimate_slash_ptr == '/')
+ break;
+ }
+ ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr);
+ return result;
+ }
+ return ConstString();
+}
+
+void
+FileSpec::PrependPathComponent(const char *new_path)
+{
+ if (!new_path) return;
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile(new_path, resolve);
+ return;
+ }
+ StreamString stream;
+ if (m_filename.IsEmpty())
+ stream.Printf("%s/%s", new_path, m_directory.GetCString());
+ else if (m_directory.IsEmpty())
+ stream.Printf("%s/%s", new_path, m_filename.GetCString());
+ else
+ stream.Printf("%s/%s/%s", new_path, m_directory.GetCString(), m_filename.GetCString());
+ SetFile(stream.GetData(), resolve);
+}
+
+void
+FileSpec::PrependPathComponent(const std::string &new_path)
+{
+ return PrependPathComponent(new_path.c_str());
+}
+
+void
+FileSpec::PrependPathComponent(const FileSpec &new_path)
+{
+ return PrependPathComponent(new_path.GetPath(false));
+}
+
+void
+FileSpec::AppendPathComponent(const char *new_path)
+{
+ if (!new_path) return;
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile(new_path, resolve);
+ return;
+ }
+ 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);
+}
+
+void
+FileSpec::AppendPathComponent(const std::string &new_path)
+{
+ return AppendPathComponent(new_path.c_str());
+}
+
+void
+FileSpec::AppendPathComponent(const FileSpec &new_path)
+{
+ return AppendPathComponent(new_path.GetPath(false));
+}
+
+void
+FileSpec::RemoveLastPathComponent ()
+{
+ const bool resolve = false;
+ if (m_filename.IsEmpty() && m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_directory.IsEmpty())
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (m_filename.IsEmpty())
+ {
+ const char* dir_cstr = m_directory.GetCString();
+ const char* last_slash_ptr = ::strrchr(dir_cstr, '/');
+
+ // check for obvious cases before doing the full thing
+ if (!last_slash_ptr)
+ {
+ SetFile("",resolve);
+ return;
+ }
+ if (last_slash_ptr == dir_cstr)
+ {
+ SetFile("/",resolve);
+ return;
+ }
+ size_t last_slash_pos = last_slash_ptr - dir_cstr+1;
+ ConstString new_path(dir_cstr,last_slash_pos);
+ SetFile(new_path.GetCString(),resolve);
+ }
+ else
+ SetFile(m_directory.GetCString(),resolve);
+}
+//------------------------------------------------------------------
+/// Returns true if the filespec represents an implementation source
+/// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
+/// extension).
+///
+/// @return
+/// \b true if the filespec represents an implementation source
+/// file, \b false otherwise.
+//------------------------------------------------------------------
+bool
+FileSpec::IsSourceImplementationFile () const
+{
+ ConstString extension (GetFileNameExtension());
+ if (extension)
+ {
+ static RegularExpression g_source_file_regex ("^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])$");
+ return g_source_file_regex.Execute (extension.GetCString());
+ }
+ return false;
+}
+
+bool
+FileSpec::IsRelative() const
+{
+ const char *dir = m_directory.GetCString();
+ llvm::StringRef directory(dir ? dir : "");
+
+ if (directory.size() > 0)
+ {
+ if (PathSyntaxIsPosix(m_syntax))
+ {
+ // If the path doesn't start with '/' or '~', return true
+ switch (directory[0])
+ {
+ case '/':
+ case '~':
+ return false;
+ default:
+ return true;
+ }
+ }
+ else
+ {
+ if (directory.size() >= 2 && directory[1] == ':')
+ return false;
+ if (directory[0] == '/')
+ return false;
+ return true;
+ }
+ }
+ else if (m_filename)
+ {
+ // No directory, just a basename, return true
+ return true;
+ }
+ return false;
+}
+
+bool
+FileSpec::IsAbsolute() const
+{
+ return !FileSpec::IsRelative();
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp
new file mode 100644
index 0000000..5a5dbc7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/FileSystem.cpp
@@ -0,0 +1,103 @@
+//===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/FileSystem.h"
+
+#include "llvm/Support/MD5.h"
+
+#include <algorithm>
+#include <fstream>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+bool
+CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, llvm::MD5::MD5Result &md5_result)
+{
+ llvm::MD5 md5_hash;
+ std::ifstream file(file_spec.GetPath(), std::ios::binary);
+ if (!file.is_open())
+ return false;
+
+ if (offset > 0)
+ file.seekg(offset, file.beg);
+
+ std::vector<char> read_buf(4096);
+ uint64_t total_read_bytes = 0;
+ while (!file.eof())
+ {
+ const uint64_t to_read = (length > 0) ?
+ std::min(static_cast<uint64_t>(read_buf.size()), length - total_read_bytes) :
+ read_buf.size();
+ if (to_read == 0)
+ break;
+
+ file.read(&read_buf[0], to_read);
+ const auto read_bytes = file.gcount();
+ if (read_bytes == 0)
+ break;
+
+ md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes));
+ total_read_bytes += read_bytes;
+ }
+
+ md5_hash.final(md5_result);
+ return true;
+}
+
+} // namespace
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+{
+ return CalculateMD5(file_spec, 0, 0, low, high);
+}
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ uint64_t &low,
+ uint64_t &high)
+{
+ llvm::MD5::MD5Result md5_result;
+ if (!CalcMD5(file_spec, offset, length, md5_result))
+ return false;
+
+ const auto uint64_res = reinterpret_cast<const uint64_t*>(md5_result);
+ high = uint64_res[0];
+ low = uint64_res[1];
+
+ return true;
+}
+
+bool
+FileSystem::CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str)
+{
+ return CalculateMD5AsString(file_spec, 0, 0, digest_str);
+}
+
+bool
+FileSystem::CalculateMD5AsString(const FileSpec &file_spec,
+ uint64_t offset,
+ uint64_t length,
+ std::string& digest_str)
+{
+ llvm::MD5::MD5Result md5_result;
+ if (!CalcMD5(file_spec, offset, length, md5_result))
+ return false;
+
+ llvm::SmallString<32> result_str;
+ llvm::MD5::stringifyResult(md5_result, result_str);
+ digest_str = result_str.c_str();
+ return true;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/GetOptInc.cpp b/contrib/llvm/tools/lldb/source/Host/common/GetOptInc.cpp
new file mode 100644
index 0000000..7689f36
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/GetOptInc.cpp
@@ -0,0 +1,473 @@
+#include "lldb/Host/common/GetOptInc.h"
+
+#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || defined(REPLACE_GETOPT_LONG_ONLY)
+
+// getopt.cpp
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(REPLACE_GETOPT)
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#endif
+
+#define PRINT_ERROR ((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
+#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static int getopt_internal(int, char * const *, const char *,
+ const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+ const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static const char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/*
+* Compute the greatest common divisor of a and b.
+*/
+static int
+gcd(int a, int b)
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+static void pass() {}
+#define warnx(a, ...) pass();
+
+/*
+* Exchange the block from nonopt_start to nonopt_end with the block
+* from nonopt_end to opt_end (keeping the same order of arguments
+* in each block).
+*/
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+char * const *nargv)
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end + i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ /* LINTED const cast */
+ ((char **)nargv)[pos] = nargv[cstart];
+ /* LINTED const cast */
+ ((char **)nargv)[cstart] = swap;
+ }
+ }
+}
+
+/*
+* parse_long_options --
+* Parse long options in argc/argv argument vector.
+* Returns -1 if short_too is set and the option does not match long_options.
+*/
+static int
+parse_long_options(char * const *nargv, const char *options,
+const struct option *long_options, int *idx, int short_too)
+{
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, match;
+
+ current_argv = const_cast<char*>(place);
+ match = -1;
+
+ optind++;
+
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ }
+ else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) == current_argv_len) {
+ /* exact match */
+ match = i;
+ break;
+ }
+ /*
+ * If this is a known short option, don't allow
+ * a partial match of a single character.
+ */
+ if (short_too && current_argv_len == 1)
+ continue;
+
+ if (match == -1) /* partial match */
+ match = i;
+ else {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return (BADARG);
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':' indicates no error
+ * should be generated.
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return (BADARG);
+ }
+ }
+ else { /* unknown option */
+ if (short_too) {
+ --optind;
+ return (-1);
+ }
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return (BADCH);
+ }
+ if (idx)
+ *idx = match;
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ return (0);
+ }
+ else
+ return (long_options[match].val);
+}
+
+/*
+* getopt_internal --
+* Parse argc/argv argument vector. Called by user level routines.
+*/
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+const struct option *long_options, int *idx, int flags)
+{
+ const char *oli; /* option letter list index */
+ int optchar, short_too;
+ static int posixly_correct = -1;
+
+ if (options == NULL)
+ return (-1);
+
+ /*
+ * XXX Some GNU programs (like cvs) set optind to 0 instead of
+ * XXX using optreset. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = optreset = 1;
+
+ /*
+ * Disable GNU extensions if POSIXLY_CORRECT is set or options
+ * string begins with a '+'.
+ */
+ if (posixly_correct == -1 || optreset)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+ if (*options == '-')
+ flags |= FLAG_ALLARGS;
+ else if (posixly_correct || *options == '+')
+ flags &= ~FLAG_PERMUTE;
+ if (*options == '+' || *options == '-')
+ options++;
+
+ optarg = NULL;
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ if (*(place = nargv[optind]) != '-' ||
+ (place[1] == '\0' && strchr(options, '-') == NULL)) {
+ place = EMSG; /* found non-option */
+ if (flags & FLAG_ALLARGS) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return (INORDER);
+ }
+ if (!(flags & FLAG_PERMUTE)) {
+ /*
+ * If no permutation wanted, stop parsing
+ * at first non-option.
+ */
+ return (-1);
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+
+ /*
+ * If we have "-" do nothing, if "--" we are done.
+ */
+ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+ optind++;
+ place = EMSG;
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return (-1);
+ }
+ }
+
+ /*
+ * Check long options if:
+ * 1) we were passed some
+ * 2) the arg is not just "-"
+ * 3) either the arg starts with -- we are getopt_long_only()
+ */
+ if (long_options != NULL && place != nargv[optind] &&
+ (*place == '-' || (flags & FLAG_LONGONLY))) {
+ short_too = 0;
+ if (*place == '-')
+ place++; /* --foo long option */
+ else if (*place != ':' && strchr(options, *place) != NULL)
+ short_too = 1; /* could be short option too */
+
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, short_too);
+ if (optchar != -1) {
+ place = EMSG;
+ return (optchar);
+ }
+ }
+
+ if ((optchar = (int)*place++) == (int)':' ||
+ (optchar == (int)'-' && *place != '\0') ||
+ (oli = strchr(options, optchar)) == NULL) {
+ /*
+ * If the user specified "-" and '-' isn't listed in
+ * options, return -1 (non-option) as per POSIX.
+ * Otherwise, it is an unknown option character (or ':').
+ */
+ if (optchar == (int)'-' && *place == '\0')
+ return (-1);
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return (BADCH);
+ }
+ if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+ /* -W long-option */
+ if (*place) /* no space */
+ /* NOTHING */;
+ else if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ }
+ else /* white space */
+ place = nargv[optind];
+ optchar = parse_long_options(nargv, options, long_options,
+ idx, 0);
+ place = EMSG;
+ return (optchar);
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ }
+ else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = const_cast<char*>(place);
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return (BADARG);
+ }
+ else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return (optchar);
+}
+
+/*
+* getopt --
+* Parse argc/argv argument vector.
+*
+* [eventually this will replace the BSD getopt]
+*/
+#if defined(REPLACE_GETOPT)
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+ /*
+ * We don't pass FLAG_PERMUTE to getopt_internal() since
+ * the BSD getopt(3) (unlike GNU) has never done this.
+ *
+ * Furthermore, since many privileged programs call getopt()
+ * before dropping privileges it makes sense to keep things
+ * as simple (and bug-free) as possible.
+ */
+ return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif
+
+/*
+* getopt_long --
+* Parse argc/argv argument vector.
+*/
+#if defined(REPLACE_GETOPT_LONG)
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+const struct option *long_options, int *idx)
+{
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE));
+}
+#endif
+
+/*
+* getopt_long_only --
+* Parse argc/argv argument vector.
+*/
+#if defined(REPLACE_GETOPT_LONG_ONLY)
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+const struct option *long_options, int *idx)
+{
+
+ return (getopt_internal(nargc, nargv, options, long_options, idx,
+ FLAG_PERMUTE | FLAG_LONGONLY));
+}
+#endif
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp
new file mode 100644
index 0000000..e89f4de
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp
@@ -0,0 +1,1082 @@
+//===-- Host.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C includes
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <dlfcn.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#endif
+
+#if defined (__APPLE__)
+#include <mach/mach_port.h>
+#include <mach/mach_init.h>
+#include <mach-o/dyld.h>
+#endif
+
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__)
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#include <spawn.h>
+#endif
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#endif
+
+#if defined (__FreeBSD__)
+#include <pthread_np.h>
+#endif
+
+// C++ includes
+#include <limits>
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/MonitoringProcessLauncher.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/ProcessLauncher.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/lldb-private-forward.h"
+#include "llvm/Support/FileSystem.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/SmallString.h"
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/ProcessLauncherWindows.h"
+#elif defined(__ANDROID__) || defined(__ANDROID_NDK__)
+#include "lldb/Host/android/ProcessLauncherAndroid.h"
+#else
+#include "lldb/Host/posix/ProcessLauncherPosix.h"
+#endif
+
+#if defined (__APPLE__)
+#ifndef _POSIX_SPAWN_DISABLE_ASLR
+#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
+#endif
+
+extern "C"
+{
+ int __pthread_chdir(const char *path);
+ int __pthread_fchdir (int fildes);
+}
+
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if !defined (__APPLE__) && !defined (_WIN32)
+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.
+};
+
+static thread_result_t
+MonitorChildProcessThreadFunction (void *arg);
+
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, 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];
+ ::snprintf(thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+ return ThreadLauncher::LaunchThread(thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL);
+}
+
+#ifndef __linux__
+//------------------------------------------------------------------
+// Scoped class that will disable thread canceling when it is
+// constructed, and exception safely restore the previous value it
+// when it goes out of scope.
+//------------------------------------------------------------------
+class ScopedPThreadCancelDisabler
+{
+public:
+ ScopedPThreadCancelDisabler()
+ {
+ // Disable the ability for this thread to be cancelled
+ int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state);
+ if (err != 0)
+ m_old_state = -1;
+ }
+
+ ~ScopedPThreadCancelDisabler()
+ {
+ // Restore the ability for this thread to be cancelled to what it
+ // previously was.
+ if (m_old_state != -1)
+ ::pthread_setcancelstate (m_old_state, 0);
+ }
+private:
+ int m_old_state; // Save the old cancelability state.
+};
+#endif // __linux__
+
+#ifdef __linux__
+#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
+static __thread volatile sig_atomic_t g_usr1_called;
+#else
+static thread_local volatile sig_atomic_t g_usr1_called;
+#endif
+
+static void
+SigUsr1Handler (int)
+{
+ g_usr1_called = 1;
+}
+#endif // __linux__
+
+static bool
+CheckForMonitorCancellation()
+{
+#ifdef __linux__
+ if (g_usr1_called)
+ {
+ g_usr1_called = 0;
+ return true;
+ }
+#else
+ ::pthread_testcancel ();
+#endif
+ return false;
+}
+
+static thread_result_t
+MonitorChildProcessThreadFunction (void *arg)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ const char *function = __FUNCTION__;
+ if (log)
+ log->Printf ("%s (arg = %p) thread starting...", function, 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);
+ const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid;
+
+ delete info;
+
+ int status = -1;
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+ #define __WALL 0
+#endif
+ const int options = __WALL;
+
+#ifdef __linux__
+ // This signal is only used to interrupt the thread from waitpid
+ struct sigaction sigUsr1Action;
+ memset(&sigUsr1Action, 0, sizeof(sigUsr1Action));
+ sigUsr1Action.sa_handler = SigUsr1Handler;
+ ::sigaction(SIGUSR1, &sigUsr1Action, nullptr);
+#endif // __linux__
+
+ while (1)
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options);
+
+ if (CheckForMonitorCancellation ())
+ break;
+
+ // Get signals from all children with same process group of pid
+ const ::pid_t wait_pid = ::waitpid (pid, &status, options);
+
+ if (CheckForMonitorCancellation ())
+ break;
+
+ if (wait_pid == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because waitpid failed (%s)...", __FUNCTION__, arg, strerror(errno));
+ break;
+ }
+ }
+ else if (wait_pid > 0)
+ {
+ bool exited = false;
+ int signal = 0;
+ int exit_status = 0;
+ const char *status_cstr = NULL;
+ if (WIFSTOPPED(status))
+ {
+ signal = WSTOPSIG(status);
+ status_cstr = "STOPPED";
+ }
+ else if (WIFEXITED(status))
+ {
+ exit_status = WEXITSTATUS(status);
+ status_cstr = "EXITED";
+ exited = true;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ signal = WTERMSIG(status);
+ status_cstr = "SIGNALED";
+ if (wait_pid == abs(pid)) {
+ exited = true;
+ exit_status = -1;
+ }
+ }
+ else
+ {
+ status_cstr = "(\?\?\?)";
+ }
+
+ // Scope for pthread_cancel_disabler
+ {
+#ifndef __linux__
+ ScopedPThreadCancelDisabler pthread_cancel_disabler;
+#endif
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i) => pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",
+ function,
+ pid,
+ options,
+ wait_pid,
+ status,
+ status_cstr,
+ signal,
+ exit_status);
+
+ if (exited || (signal != 0 && monitor_signals))
+ {
+ bool callback_return = false;
+ if (callback)
+ callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status);
+
+ // If our process exited, then this thread should exit
+ if (exited && wait_pid == abs(pid))
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg);
+ break;
+ }
+ // If the callback returns true, it means this process should
+ // exit
+ if (callback_return)
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+#endif // #if !defined (__APPLE__) && !defined (_WIN32)
+
+#if !defined (__APPLE__)
+
+void
+Host::SystemLog (SystemLogType type, const char *format, va_list args)
+{
+ vfprintf (stderr, format, args);
+}
+
+#endif
+
+void
+Host::SystemLog (SystemLogType type, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ SystemLog (type, format, args);
+ va_end (args);
+}
+
+lldb::pid_t
+Host::GetCurrentProcessID()
+{
+ return ::getpid();
+}
+
+#ifndef _WIN32
+
+lldb::tid_t
+Host::GetCurrentThreadID()
+{
+#if defined (__APPLE__)
+ // Calling "mach_thread_self()" bumps the reference count on the thread
+ // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
+ // count.
+ thread_port_t thread_self = mach_thread_self();
+ mach_port_deallocate(mach_task_self(), thread_self);
+ return thread_self;
+#elif defined(__FreeBSD__)
+ return lldb::tid_t(pthread_getthreadid_np());
+#elif defined(__ANDROID_NDK__)
+ return lldb::tid_t(gettid());
+#elif defined(__linux__)
+ return lldb::tid_t(syscall(SYS_gettid));
+#else
+ return lldb::tid_t(pthread_self());
+#endif
+}
+
+lldb::thread_t
+Host::GetCurrentThread ()
+{
+ return lldb::thread_t(pthread_self());
+}
+
+const char *
+Host::GetSignalAsCString (int signo)
+{
+ switch (signo)
+ {
+ case SIGHUP: return "SIGHUP"; // 1 hangup
+ case SIGINT: return "SIGINT"; // 2 interrupt
+ case SIGQUIT: return "SIGQUIT"; // 3 quit
+ case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught)
+ case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught)
+ case SIGABRT: return "SIGABRT"; // 6 abort()
+#if defined(SIGPOLL)
+#if !defined(SIGIO) || (SIGPOLL != SIGIO)
+// Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to
+// fail with 'multiple define cases with same value'
+ case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
+#endif
+#endif
+#if defined(SIGEMT)
+ case SIGEMT: return "SIGEMT"; // 7 EMT instruction
+#endif
+ case SIGFPE: return "SIGFPE"; // 8 floating point exception
+ case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored)
+ case SIGBUS: return "SIGBUS"; // 10 bus error
+ case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation
+ case SIGSYS: return "SIGSYS"; // 12 bad argument to system call
+ case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it
+ case SIGALRM: return "SIGALRM"; // 14 alarm clock
+ case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill
+ case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel
+ case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty
+ case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty
+ case SIGCONT: return "SIGCONT"; // 19 continue a stopped process
+ case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit
+ case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read
+ case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local&LTOSTOP)
+#if defined(SIGIO)
+ case SIGIO: return "SIGIO"; // 23 input/output possible signal
+#endif
+ case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit
+ case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit
+ case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm
+ case SIGPROF: return "SIGPROF"; // 27 profiling time alarm
+#if defined(SIGWINCH)
+ case SIGWINCH: return "SIGWINCH"; // 28 window size changes
+#endif
+#if defined(SIGINFO)
+ case SIGINFO: return "SIGINFO"; // 29 information request
+#endif
+ case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1
+ case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2
+ default:
+ break;
+ }
+ return NULL;
+}
+
+#endif
+
+#ifndef _WIN32
+
+lldb::thread_key_t
+Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback)
+{
+ pthread_key_t key;
+ ::pthread_key_create (&key, callback);
+ return key;
+}
+
+void*
+Host::ThreadLocalStorageGet(lldb::thread_key_t key)
+{
+ return ::pthread_getspecific (key);
+}
+
+void
+Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value)
+{
+ ::pthread_setspecific (key, value);
+}
+
+#endif
+
+#if !defined (__APPLE__) // see Host.mm
+
+bool
+Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle)
+{
+ bundle.Clear();
+ return false;
+}
+
+bool
+Host::ResolveExecutableInBundle (FileSpec &file)
+{
+ return false;
+}
+#endif
+
+#ifndef _WIN32
+
+FileSpec
+Host::GetModuleFileSpecForHostAddress (const void *host_addr)
+{
+ FileSpec module_filespec;
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+ Dl_info info;
+ if (::dladdr (host_addr, &info))
+ {
+ if (info.dli_fname)
+ module_filespec.SetFile(info.dli_fname, true);
+ }
+#endif
+ return module_filespec;
+}
+
+#endif
+
+#if !defined(__linux__)
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+ return false;
+}
+#endif
+
+struct ShellInfo
+{
+ ShellInfo () :
+ process_reaped (false),
+ can_delete (false),
+ pid (LLDB_INVALID_PROCESS_ID),
+ signo(-1),
+ status(-1)
+ {
+ }
+
+ 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
+{
+ 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;
+ return true;
+}
+
+Error
+Host::RunShellCommand(const char *command,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec,
+ bool run_in_default_shell)
+{
+ return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, command_output_ptr, timeout_sec, run_in_default_shell);
+}
+
+Error
+Host::RunShellCommand(const Args &args,
+ const FileSpec &working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec,
+ bool run_in_default_shell)
+{
+ Error error;
+ ProcessLaunchInfo launch_info;
+ launch_info.SetArchitecture(HostInfo::GetArchitecture());
+ if (run_in_default_shell)
+ {
+ // Run the command in a shell
+ launch_info.SetShell(HostInfo::GetDefaultShell());
+ launch_info.GetArguments().AppendArguments(args);
+ const bool localhost = true;
+ const bool will_debug = false;
+ const bool first_arg_is_full_shell_command = false;
+ launch_info.ConvertArgumentsForLaunchingInShell (error,
+ localhost,
+ will_debug,
+ first_arg_is_full_shell_command,
+ 0);
+ }
+ else
+ {
+ // No shell, just run it
+ const bool first_arg_is_executable = true;
+ launch_info.SetArguments(args, first_arg_is_executable);
+ }
+
+ if (working_dir)
+ launch_info.SetWorkingDirectory(working_dir);
+ llvm::SmallString<PATH_MAX> output_file_path;
+
+ if (command_output_ptr)
+ {
+ // Create a temporary file to get the stdout/stderr and redirect the
+ // output of the command into this file. We will later read this file
+ // if all goes well and fill the data into "command_output_ptr"
+ FileSpec tmpdir_file_spec;
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ {
+ tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%");
+ llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), output_file_path);
+ }
+ else
+ {
+ llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", output_file_path);
+ }
+ }
+
+ FileSpec output_file_spec{output_file_path.c_str(), false};
+
+ launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
+ if (output_file_spec)
+ {
+ launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false, true);
+ launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
+ }
+ else
+ {
+ 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());
+
+ const bool monitor_signals = false;
+ launch_info.SetMonitorProcessCallback(MonitorShellCommand, shell_info_ap.get(), monitor_signals);
+
+ error = LaunchProcess (launch_info);
+ const lldb::pid_t pid = launch_info.GetProcessID();
+
+ if (error.Success() && pid == LLDB_INVALID_PROCESS_ID)
+ error.SetErrorString("failed to get process ID");
+
+ 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) {
+ timeout_time.OffsetWithSeconds(timeout_sec);
+ timeout_ptr = &timeout_time;
+ }
+ bool timed_out = false;
+ shell_info->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out);
+ if (timed_out)
+ {
+ error.SetErrorString("timed out waiting for shell command to complete");
+
+ // Kill the process since it didn't complete within the timeout specified
+ Kill (pid, SIGKILL);
+ // Wait for the monitor callback to get the message
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(1);
+ timed_out = false;
+ shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out);
+ }
+ else
+ {
+ if (status_ptr)
+ *status_ptr = shell_info->status;
+
+ if (signo_ptr)
+ *signo_ptr = shell_info->signo;
+
+ if (command_output_ptr)
+ {
+ command_output_ptr->clear();
+ uint64_t file_size = output_file_spec.GetByteSize();
+ if (file_size > 0)
+ {
+ if (file_size > command_output_ptr->max_size())
+ {
+ error.SetErrorStringWithFormat("shell command output is too large to fit into a std::string");
+ }
+ else
+ {
+ std::vector<char> command_output(file_size);
+ output_file_spec.ReadFileContents(0, command_output.data(), file_size, &error);
+ if (error.Success())
+ command_output_ptr->assign(command_output.data(), file_size);
+ }
+ }
+ }
+ }
+ 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;
+}
+
+// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
+// systems
+
+#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
+#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+// this method needs to be visible to macosx/Host.cpp and
+// common/Host.cpp.
+
+short
+Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info)
+{
+ short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
+
+#if defined (__APPLE__)
+ if (launch_info.GetFlags().Test (eLaunchFlagExec))
+ flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetFlags().Test (eLaunchFlagDebug))
+ flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
+ flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
+
+ if (launch_info.GetLaunchInSeparateProcessGroup())
+ flags |= POSIX_SPAWN_SETPGROUP;
+
+#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
+#if defined (__APPLE__) && (defined (__x86_64__) || defined (__i386__))
+ static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
+ if (g_use_close_on_exec_flag == eLazyBoolCalculate)
+ {
+ g_use_close_on_exec_flag = eLazyBoolNo;
+
+ uint32_t major, minor, update;
+ if (HostInfo::GetOSVersion(major, minor, update))
+ {
+ // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier
+ if (major > 10 || (major == 10 && minor > 7))
+ {
+ // Only enable for 10.8 and later OS versions
+ g_use_close_on_exec_flag = eLazyBoolYes;
+ }
+ }
+ }
+#else
+ static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
+#endif
+ // Close all files exception those with file actions if this is supported.
+ if (g_use_close_on_exec_flag == eLazyBoolYes)
+ flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
+#endif
+#endif // #if defined (__APPLE__)
+ return flags;
+}
+
+Error
+Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
+{
+ Error error;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ posix_spawnattr_t attr;
+ error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX);
+
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_init ( &attr )");
+ if (error.Fail())
+ return error;
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy);
+
+ sigset_t no_signals;
+ sigset_t all_signals;
+ sigemptyset (&no_signals);
+ sigfillset (&all_signals);
+ ::posix_spawnattr_setsigmask(&attr, &no_signals);
+#if defined (__linux__) || defined (__FreeBSD__)
+ ::posix_spawnattr_setsigdefault(&attr, &no_signals);
+#else
+ ::posix_spawnattr_setsigdefault(&attr, &all_signals);
+#endif
+
+ short flags = GetPosixspawnFlags(launch_info);
+
+ error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags);
+ if (error.Fail())
+ return error;
+
+ // posix_spawnattr_setbinpref_np appears to be an Apple extension per:
+ // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
+#if defined (__APPLE__) && !defined (__arm__)
+
+ // Don't set the binpref if a shell was provided. After all, that's only going to affect what version of the shell
+ // is launched, not what fork of the binary is launched. We insert "arch --arch <ARCH> as part of the shell invocation
+ // to do that job on OSX.
+
+ if (launch_info.GetShell() == nullptr)
+ {
+ // We don't need to do this for ARM, and we really shouldn't now that we
+ // have multiple CPU subtypes and no posix_spawnattr call that allows us
+ // to set which CPU subtype to launch...
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+ cpu_type_t cpu = arch_spec.GetMachOCPUType();
+ cpu_type_t sub = arch_spec.GetMachOCPUSubType();
+ if (cpu != 0 &&
+ cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
+ cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
+ !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail
+ {
+ size_t ocount = 0;
+ error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount);
+
+ if (error.Fail() || ocount != 1)
+ return error;
+ }
+ }
+
+#endif
+
+ const char *tmp_argv[2];
+ char * const *argv = const_cast<char * const*>(launch_info.GetArguments().GetConstArgumentVector());
+ char * const *envp = const_cast<char * const*>(launch_info.GetEnvironmentEntries().GetConstArgumentVector());
+ if (argv == NULL)
+ {
+ // posix_spawn gets very unhappy if it doesn't have at least the program
+ // name in argv[0]. One of the side affects I have noticed is the environment
+ // variables don't make it into the child process if "argv == NULL"!!!
+ tmp_argv[0] = exe_path;
+ tmp_argv[1] = NULL;
+ argv = const_cast<char * const*>(tmp_argv);
+ }
+
+#if !defined (__APPLE__)
+ // manage the working directory
+ char current_dir[PATH_MAX];
+ current_dir[0] = '\0';
+#endif
+
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
+ if (working_dir)
+ {
+#if defined (__APPLE__)
+ // Set the working directory on this thread only
+ if (__pthread_chdir(working_dir.GetCString()) < 0) {
+ if (errno == ENOENT) {
+ error.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
+ } else if (errno == ENOTDIR) {
+ error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
+ working_dir.GetCString());
+ } else {
+ error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution.");
+ }
+ return error;
+ }
+#else
+ if (::getcwd(current_dir, sizeof(current_dir)) == NULL)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log, "unable to save the current directory");
+ return error;
+ }
+
+ if (::chdir(working_dir.GetCString()) == -1)
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log, "unable to change working directory to %s",
+ working_dir.GetCString());
+ return error;
+ }
+#endif
+ }
+
+ ::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
+ const size_t num_file_actions = launch_info.GetNumFileActions ();
+ if (num_file_actions > 0)
+ {
+ posix_spawn_file_actions_t file_actions;
+ error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )");
+ if (error.Fail())
+ return error;
+
+ // Make a quick class that will cleanup the posix spawn attributes in case
+ // we return in the middle of this function.
+ lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy);
+
+ for (size_t i=0; i<num_file_actions; ++i)
+ {
+ const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+ if (launch_file_action)
+ {
+ if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error))
+ return error;
+ }
+ }
+
+ error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX);
+
+ if (error.Fail() || log)
+ {
+ error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid,
+ exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
+ reinterpret_cast<const void *>(envp));
+ if (log)
+ {
+ for (int ii=0; argv[ii]; ++ii)
+ log->Printf("argv[%i] = '%s'", ii, argv[ii]);
+ }
+ }
+
+ }
+ else
+ {
+ error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX);
+
+ if (error.Fail() || log)
+ {
+ error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
+ result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv),
+ reinterpret_cast<const void *>(envp));
+ if (log)
+ {
+ for (int ii=0; argv[ii]; ++ii)
+ log->Printf("argv[%i] = '%s'", ii, argv[ii]);
+ }
+ }
+ }
+ pid = result_pid;
+
+ if (working_dir)
+ {
+#if defined (__APPLE__)
+ // No more thread specific current working directory
+ __pthread_fchdir (-1);
+#else
+ if (::chdir(current_dir) == -1 && error.Success())
+ {
+ error.SetError(errno, eErrorTypePOSIX);
+ error.LogIfError(log, "unable to change current directory back to %s",
+ current_dir);
+ }
+#endif
+ }
+
+ return error;
+}
+
+bool
+Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error)
+{
+ if (info == NULL)
+ return false;
+
+ posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
+
+ switch (info->GetAction())
+ {
+ case FileAction::eFileActionNone:
+ error.Clear();
+ break;
+
+ case FileAction::eFileActionClose:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd for posix_spawn_file_actions_addclose(...)");
+ else
+ {
+ error.SetError(::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
+ static_cast<void *>(file_actions), info->GetFD());
+ }
+ break;
+
+ case FileAction::eFileActionDuplicate:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd for posix_spawn_file_actions_adddup2(...)");
+ else if (info->GetActionArgument() == -1)
+ error.SetErrorString("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
+ else
+ {
+ error.SetError(
+ ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()),
+ eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
+ static_cast<void *>(file_actions), info->GetFD(), info->GetActionArgument());
+ }
+ break;
+
+ case FileAction::eFileActionOpen:
+ if (info->GetFD() == -1)
+ error.SetErrorString("invalid fd in posix_spawn_file_actions_addopen(...)");
+ else
+ {
+ int oflag = info->GetActionArgument();
+
+ mode_t mode = 0;
+
+ if (oflag & O_CREAT)
+ mode = 0640;
+
+ error.SetError(
+ ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(), info->GetPath(), oflag, mode),
+ eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log,
+ "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
+ static_cast<void *>(file_actions), info->GetFD(), info->GetPath(), oflag, mode);
+ }
+ break;
+ }
+ return error.Success();
+}
+#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__)
+#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) || defined(_WIN32)
+// The functions below implement process launching via posix_spawn() for Linux,
+// FreeBSD and NetBSD.
+
+Error
+Host::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ std::unique_ptr<ProcessLauncher> delegate_launcher;
+#if defined(_WIN32)
+ delegate_launcher.reset(new ProcessLauncherWindows());
+#elif defined(__ANDROID__) || defined(__ANDROID_NDK__)
+ delegate_launcher.reset(new ProcessLauncherAndroid());
+#else
+ delegate_launcher.reset(new ProcessLauncherPosix());
+#endif
+ MonitoringProcessLauncher launcher(std::move(delegate_launcher));
+
+ Error error;
+ HostProcess process = launcher.LaunchProcess(launch_info, error);
+
+ // TODO(zturner): It would be better if the entire HostProcess were returned instead of writing
+ // it into this structure.
+ launch_info.SetProcessID(process.GetProcessId());
+
+ return error;
+}
+#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+
+#ifndef _WIN32
+void
+Host::Kill(lldb::pid_t pid, int signo)
+{
+ ::kill(pid, signo);
+}
+
+#endif
+
+#if !defined (__APPLE__)
+bool
+Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
+{
+ return false;
+}
+
+void
+Host::SetCrashDescriptionWithFormat (const char *format, ...)
+{
+}
+
+void
+Host::SetCrashDescription (const char *description)
+{
+}
+
+#endif
+
+const UnixSignalsSP &
+Host::GetUnixSignals()
+{
+ static const auto s_unix_signals_sp = UnixSignals::Create(HostInfo::GetArchitecture());
+ return s_unix_signals_sp;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp
new file mode 100644
index 0000000..f7ba755
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp
@@ -0,0 +1,425 @@
+//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostInfoBase.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <thread>
+#include <mutex> // std::once
+
+using namespace lldb;
+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
+ // variables in HostInfoBaseFields should live in the functions in which
+ // they are used and each one should be static, but the work around is
+ // in place to avoid this restriction. Ick.
+ //----------------------------------------------------------------------
+
+ struct HostInfoBaseFields
+ {
+ uint32_t m_number_cpus;
+ std::string m_vendor_string;
+ std::string m_os_string;
+ std::string m_host_triple;
+
+ ArchSpec m_host_arch_32;
+ ArchSpec m_host_arch_64;
+
+ FileSpec m_lldb_so_dir;
+ FileSpec m_lldb_support_exe_dir;
+ FileSpec m_lldb_headers_dir;
+ FileSpec m_lldb_python_dir;
+ FileSpec m_lldb_clang_resource_dir;
+ FileSpec m_lldb_system_plugin_dir;
+ FileSpec m_lldb_user_plugin_dir;
+ FileSpec m_lldb_process_tmp_dir;
+ FileSpec m_lldb_global_tmp_dir;
+ };
+
+ HostInfoBaseFields *g_fields = nullptr;
+}
+
+void
+HostInfoBase::Initialize()
+{
+ g_fields = new HostInfoBaseFields();
+}
+
+uint32_t
+HostInfoBase::GetNumberCPUS()
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_fields->m_number_cpus = std::thread::hardware_concurrency();
+ });
+ return g_fields->m_number_cpus;
+}
+
+uint32_t
+HostInfoBase::GetMaxThreadNameLength()
+{
+ return 0;
+}
+
+llvm::StringRef
+HostInfoBase::GetVendorString()
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_fields->m_vendor_string = HostInfo::GetArchitecture().GetTriple().getVendorName().str();
+ });
+ return g_fields->m_vendor_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetOSString()
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName());
+ });
+ return g_fields->m_os_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetTargetTriple()
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple();
+ });
+ return g_fields->m_host_triple;
+}
+
+const ArchSpec &
+HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
+{
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
+ });
+
+ // If an explicit 32 or 64-bit architecture was requested, return that.
+ if (arch_kind == eArchKind32)
+ return g_fields->m_host_arch_32;
+ if (arch_kind == eArchKind64)
+ return g_fields->m_host_arch_64;
+
+ // Otherwise prefer the 64-bit architecture if it is valid.
+ return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32;
+}
+
+bool
+HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec)
+{
+ file_spec.Clear();
+
+#if defined(LLDB_DISABLE_PYTHON)
+ if (type == lldb::ePathTypePythonDir)
+ return false;
+#endif
+
+ FileSpec *result = nullptr;
+ switch (type)
+ {
+ case lldb::ePathTypeLLDBShlibDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_so_dir;
+ }
+ break;
+ case lldb::ePathTypeSupportExecutableDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
+ g_fields->m_lldb_support_exe_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_support_exe_dir;
+ }
+ break;
+ case lldb::ePathTypeHeaderDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_headers_dir;
+ }
+ break;
+ case lldb::ePathTypePythonDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_python_dir;
+ }
+ break;
+ case lldb::ePathTypeClangDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_clang_resource_dir;
+ }
+ break;
+ case lldb::ePathTypeLLDBSystemPlugins:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
+ g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_system_plugin_dir;
+ }
+ break;
+ case lldb::ePathTypeLLDBUserPlugins:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
+ g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_user_plugin_dir;
+ }
+ break;
+ case lldb::ePathTypeLLDBTempSystemDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_process_tmp_dir;
+ }
+ break;
+ case lldb::ePathTypeGlobalLLDBTempSystemDir:
+ {
+ static std::once_flag g_once_flag;
+ static bool success = false;
+ std::call_once(g_once_flag, []() {
+ success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir);
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
+ });
+ if (success)
+ result = &g_fields->m_lldb_global_tmp_dir;
+ }
+ break;
+ }
+
+ if (!result)
+ return false;
+ file_spec = *result;
+ return true;
+}
+
+bool
+HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec)
+{
+ // To get paths related to LLDB we get the path to the executable that
+ // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
+ // on linux this is assumed to be the "lldb" main executable. If LLDB on
+ // linux is actually in a shared library (liblldb.so) then this function will
+ // need to be modified to "do the right thing".
+
+ FileSpec lldb_file_spec(
+ Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
+
+ // This is necessary because when running the testsuite the shlib might be a symbolic link inside the Python resource dir.
+ FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
+
+ // Remove the filename so that this FileSpec only represents the directory.
+ file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
+
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
+}
+
+bool
+HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file_spec;
+ if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
+ return false;
+
+ std::string pid_str{std::to_string(Host::GetCurrentProcessID())};
+ temp_file_spec.AppendPathComponent(pid_str);
+ 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;
+}
+
+bool
+HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec)
+{
+ llvm::SmallVector<char, 16> tmpdir;
+ llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
+ file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
+ return true;
+}
+
+bool
+HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec)
+{
+ file_spec.Clear();
+
+ FileSpec temp_file_spec;
+ if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
+ return false;
+
+ temp_file_spec.AppendPathComponent("lldb");
+ if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success())
+ return false;
+
+ file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
+ return true;
+}
+
+bool
+HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the header directory for all platforms.
+ return false;
+}
+
+bool
+HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the system plugins directory for all platforms.
+ return false;
+}
+
+bool
+HostInfoBase::ComputeClangDirectory(FileSpec &file_spec)
+{
+ return false;
+}
+
+bool
+HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec)
+{
+ // TODO(zturner): Figure out how to compute the user plugins directory for all platforms.
+ return false;
+}
+
+void
+HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ llvm::Triple triple(llvm::sys::getProcessTriple());
+
+ arch_32.Clear();
+ arch_64.Clear();
+
+ switch (triple.getArch())
+ {
+ default:
+ arch_32.SetTriple(triple);
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::x86_64:
+ arch_64.SetTriple(triple);
+ arch_32.SetTriple(triple.get32BitArchVariant());
+ break;
+
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::sparcv9:
+ arch_64.SetTriple(triple);
+ break;
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp
new file mode 100644
index 0000000..9fea54d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostNativeThreadBase.cpp
@@ -0,0 +1,82 @@
+//===-- HostNativeThreadBase.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Log.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/HostNativeThreadBase.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostNativeThreadBase::HostNativeThreadBase()
+ : m_thread(LLDB_INVALID_HOST_THREAD)
+ , m_result(0)
+{
+}
+
+HostNativeThreadBase::HostNativeThreadBase(thread_t thread)
+ : m_thread(thread)
+ , m_result(0)
+{
+}
+
+lldb::thread_t
+HostNativeThreadBase::GetSystemHandle() const
+{
+ return m_thread;
+}
+
+lldb::thread_result_t
+HostNativeThreadBase::GetResult() const
+{
+ return m_result;
+}
+
+bool
+HostNativeThreadBase::IsJoinable() const
+{
+ return m_thread != LLDB_INVALID_HOST_THREAD;
+}
+
+void
+HostNativeThreadBase::Reset()
+{
+ m_thread = LLDB_INVALID_HOST_THREAD;
+ m_result = 0;
+}
+
+lldb::thread_t
+HostNativeThreadBase::Release()
+{
+ lldb::thread_t result = m_thread;
+ m_thread = LLDB_INVALID_HOST_THREAD;
+ m_result = 0;
+
+ return result;
+}
+
+lldb::thread_result_t
+HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg)
+{
+ ThreadLauncher::HostThreadCreateInfo *info = (ThreadLauncher::HostThreadCreateInfo *)arg;
+ ThisThread::SetName(info->thread_name.c_str(), HostInfo::GetMaxThreadNameLength());
+
+ thread_func_t thread_fptr = info->thread_fptr;
+ thread_arg_t thread_arg = info->thread_arg;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf("thread created");
+
+ delete info;
+ return thread_fptr(thread_arg);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp
new file mode 100644
index 0000000..58a2146
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostProcess.cpp
@@ -0,0 +1,65 @@
+//===-- HostProcess.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/HostNativeProcess.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/HostThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostProcess::HostProcess()
+ : m_native_process(new HostNativeProcess)
+{
+}
+
+HostProcess::HostProcess(lldb::process_t process)
+ : m_native_process(new HostNativeProcess(process))
+{
+}
+
+HostProcess::~HostProcess()
+{
+}
+
+Error HostProcess::Terminate()
+{
+ return m_native_process->Terminate();
+}
+
+Error HostProcess::GetMainModule(FileSpec &file_spec) const
+{
+ return m_native_process->GetMainModule(file_spec);
+}
+
+lldb::pid_t HostProcess::GetProcessId() const
+{
+ return m_native_process->GetProcessId();
+}
+
+bool HostProcess::IsRunning() const
+{
+ return m_native_process->IsRunning();
+}
+
+HostThread
+HostProcess::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+{
+ return m_native_process->StartMonitoring(callback, callback_baton, monitor_signals);
+}
+
+HostNativeProcessBase &HostProcess::GetNativeProcess()
+{
+ return *m_native_process;
+}
+
+const HostNativeProcessBase &HostProcess::GetNativeProcess() const
+{
+ return *m_native_process;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp
new file mode 100644
index 0000000..7757477
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/HostThread.cpp
@@ -0,0 +1,78 @@
+//===-- HostThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/HostThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThread::HostThread()
+ : m_native_thread(new HostNativeThread)
+{
+}
+
+HostThread::HostThread(lldb::thread_t thread)
+ : m_native_thread(new HostNativeThread(thread))
+{
+}
+
+Error
+HostThread::Join(lldb::thread_result_t *result)
+{
+ return m_native_thread->Join(result);
+}
+
+Error
+HostThread::Cancel()
+{
+ return m_native_thread->Cancel();
+}
+
+void
+HostThread::Reset()
+{
+ return m_native_thread->Reset();
+}
+
+lldb::thread_t
+HostThread::Release()
+{
+ return m_native_thread->Release();
+}
+
+bool
+HostThread::IsJoinable() const
+{
+ return m_native_thread->IsJoinable();
+}
+
+HostNativeThread &
+HostThread::GetNativeThread()
+{
+ return static_cast<HostNativeThread &>(*m_native_thread);
+}
+
+const HostNativeThread &
+HostThread::GetNativeThread() const
+{
+ return static_cast<const HostNativeThread &>(*m_native_thread);
+}
+
+lldb::thread_result_t
+HostThread::GetResult() const
+{
+ return m_native_thread->GetResult();
+}
+
+bool
+HostThread::EqualsThread(lldb::thread_t thread) const
+{
+ return m_native_thread->GetSystemHandle() == thread;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp b/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp
new file mode 100644
index 0000000..6f7de44
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp
@@ -0,0 +1,14 @@
+//===-- IOObject.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/IOObject.h"
+
+using namespace lldb_private;
+
+const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1;
diff --git a/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp
new file mode 100644
index 0000000..f746945
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/LockFileBase.cpp
@@ -0,0 +1,124 @@
+//===-- LockFileBase.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/LockFileBase.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+Error
+AlreadyLocked ()
+{
+ return Error ("Already locked");
+}
+
+Error
+NotLocked ()
+{
+ return Error ("Not locked");
+}
+
+}
+
+LockFileBase::LockFileBase (int fd) :
+ m_fd (fd),
+ m_locked (false),
+ m_start (0),
+ m_len (0)
+{
+
+}
+
+bool
+LockFileBase::IsLocked () const
+{
+ return m_locked;
+}
+
+Error
+LockFileBase::WriteLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoWriteLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::TryWriteLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoTryWriteLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::ReadLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoReadLock (start, len);
+ }, start, len);
+}
+
+Error
+LockFileBase::TryReadLock (const uint64_t start, const uint64_t len)
+{
+ return DoLock ([&] (const uint64_t start, const uint64_t len)
+ {
+ return DoTryReadLock (start, len);
+ }, start, len);
+
+}
+
+Error
+LockFileBase::Unlock ()
+{
+ if (!IsLocked ())
+ return NotLocked ();
+
+ const auto error = DoUnlock ();
+ if (error.Success ())
+ {
+ m_locked = false;
+ m_start = 0;
+ m_len = 0;
+ }
+ return error;
+}
+
+bool
+LockFileBase::IsValidFile () const
+{
+ return m_fd != -1;
+}
+
+Error
+LockFileBase::DoLock (const Locker &locker, const uint64_t start, const uint64_t len)
+{
+ if (!IsValidFile ())
+ return Error("File is invalid");
+
+ if (IsLocked ())
+ return AlreadyLocked ();
+
+ const auto error = locker (start, len);
+ if (error.Success ())
+ {
+ m_locked = true;
+ m_start = start;
+ m_len = len;
+ }
+
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp
new file mode 100644
index 0000000..0fad44a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/MonitoringProcessLauncher.cpp
@@ -0,0 +1,102 @@
+//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/MonitoringProcessLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MonitoringProcessLauncher::MonitoringProcessLauncher(std::unique_ptr<ProcessLauncher> delegate_launcher)
+ : m_delegate_launcher(std::move(delegate_launcher))
+{
+}
+
+HostProcess
+MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ ProcessLaunchInfo resolved_info(launch_info);
+
+ error.Clear();
+ char exe_path[PATH_MAX];
+
+ PlatformSP host_platform_sp(Platform::GetHostPlatform());
+
+ const ArchSpec &arch_spec = resolved_info.GetArchitecture();
+
+ FileSpec exe_spec(resolved_info.GetExecutableFile());
+
+ FileSpec::FileType file_type = exe_spec.GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ ModuleSpec module_spec(exe_spec, arch_spec);
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL);
+
+ if (error.Fail())
+ return HostProcess();
+
+ if (exe_module_sp)
+ exe_spec = exe_module_sp->GetFileSpec();
+ }
+
+ if (exe_spec.Exists())
+ {
+ exe_spec.GetPath(exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path);
+ return HostProcess();
+ }
+
+ resolved_info.SetExecutableFile(exe_spec, false);
+ assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY));
+
+ HostProcess process = m_delegate_launcher->LaunchProcess(resolved_info, error);
+
+ if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ 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
+ {
+ callback = Process::SetProcessExitStatus;
+ }
+
+ process.StartMonitoring(callback, baton, monitor_signals);
+ if (log)
+ log->PutCString("started monitoring child process.");
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString("process launch failed for unknown reasons");
+ }
+ return process;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp b/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp
new file mode 100644
index 0000000..98f5321
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp
@@ -0,0 +1,398 @@
+//===-- Mutex.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Host.h"
+
+#ifndef _WIN32
+#include <pthread.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+
+#if 0
+// This logging is way too verbose to enable even for a log channel.
+// This logging can be enabled by changing the "#if 0", but should be
+// reverted prior to checking in.
+#include <cstdio>
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+// Enable extra mutex error checking
+#if 0 // LLDB_CONFIGURATION_DEBUG
+#define ENABLE_MUTEX_ERROR_CHECKING 1
+#include <inttypes.h>
+#endif
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+#include <set>
+
+enum MutexAction
+{
+ eMutexActionInitialized,
+ eMutexActionDestroyed,
+ eMutexActionAssertInitialized
+};
+
+static bool
+error_check_mutex (pthread_mutex_t *m, MutexAction action)
+{
+ typedef std::set<pthread_mutex_t *> mutex_set;
+ static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static mutex_set g_initialized_mutex_set;
+ static mutex_set g_destroyed_mutex_set;
+
+ bool success = true;
+ int err;
+ // Manually call lock so we don't to any of this error checking
+ err = ::pthread_mutex_lock (&g_mutex_set_mutex);
+ assert(err == 0);
+ switch (action)
+ {
+ case eMutexActionInitialized:
+ // Make sure this isn't already in our initialized mutex set...
+ assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end());
+ // Remove this from the destroyed set in case it was ever in there
+ g_destroyed_mutex_set.erase(m);
+ // Add the mutex to the initialized set
+ g_initialized_mutex_set.insert(m);
+ break;
+
+ case eMutexActionDestroyed:
+ // Make sure this isn't already in our destroyed mutex set...
+ assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end());
+ // Remove this from the initialized so we can put it into the destroyed set
+ g_initialized_mutex_set.erase(m);
+ // Add the mutex to the destroyed set
+ g_destroyed_mutex_set.insert(m);
+ break;
+ case eMutexActionAssertInitialized:
+ // This function will return true if "m" is in the initialized mutex set
+ success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end();
+ assert (success);
+ break;
+ }
+ // Manually call unlock so we don't to any of this error checking
+ err = ::pthread_mutex_unlock (&g_mutex_set_mutex);
+ assert(err == 0);
+ return success;
+}
+
+#endif
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// This will create a scoped mutex locking object that doesn't have
+// a mutex to lock. One will need to be provided using the Reset()
+// method.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker () :
+ m_mutex_ptr(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor with a Mutex object.
+//
+// This will create a scoped mutex locking object that extracts the
+// mutex owned by "m" and locks it.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker (Mutex& m) :
+ m_mutex_ptr(NULL)
+{
+ Lock (m);
+}
+
+//----------------------------------------------------------------------
+// Constructor with a Mutex object pointer.
+//
+// This will create a scoped mutex locking object that extracts the
+// mutex owned by "m" and locks it.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker (Mutex* m) :
+ m_mutex_ptr(NULL)
+{
+ if (m)
+ Lock (m);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Unlocks any owned mutex object (if it is valid).
+//----------------------------------------------------------------------
+Mutex::Locker::~Locker ()
+{
+ Unlock();
+}
+
+//----------------------------------------------------------------------
+// Unlock the current mutex in this object (if this owns a valid
+// mutex) and lock the new "mutex" object if it is non-NULL.
+//----------------------------------------------------------------------
+void
+Mutex::Locker::Lock (Mutex &mutex)
+{
+ // We already have this mutex locked or both are NULL...
+ if (m_mutex_ptr == &mutex)
+ return;
+
+ Unlock ();
+
+ m_mutex_ptr = &mutex;
+ m_mutex_ptr->Lock();
+}
+
+void
+Mutex::Locker::Unlock ()
+{
+ if (m_mutex_ptr)
+ {
+ m_mutex_ptr->Unlock ();
+ m_mutex_ptr = NULL;
+ }
+}
+
+bool
+Mutex::Locker::TryLock (Mutex &mutex, const char *failure_message)
+{
+ // We already have this mutex locked!
+ if (m_mutex_ptr == &mutex)
+ return true;
+
+ Unlock ();
+
+ if (mutex.TryLock(failure_message) == 0)
+ m_mutex_ptr = &mutex;
+
+ return m_mutex_ptr != NULL;
+}
+
+#ifndef _WIN32
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with no attributes.
+//----------------------------------------------------------------------
+Mutex::Mutex () :
+ m_mutex()
+{
+ int err;
+ err = ::pthread_mutex_init (&m_mutex, NULL);
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionInitialized);
+#endif
+ assert(err == 0);
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with "type" as the mutex type.
+//----------------------------------------------------------------------
+Mutex::Mutex (Mutex::Type type) :
+ m_mutex()
+{
+ int err;
+ ::pthread_mutexattr_t attr;
+ err = ::pthread_mutexattr_init (&attr);
+ assert(err == 0);
+ switch (type)
+ {
+ case eMutexTypeNormal:
+#if ENABLE_MUTEX_ERROR_CHECKING
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
+#else
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
+#endif
+ break;
+
+ case eMutexTypeRecursive:
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ break;
+ }
+ assert(err == 0);
+ err = ::pthread_mutex_init (&m_mutex, &attr);
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionInitialized);
+#endif
+ assert(err == 0);
+ err = ::pthread_mutexattr_destroy (&attr);
+ assert(err == 0);
+}
+
+//----------------------------------------------------------------------
+// Destructor.
+//
+// Destroys the mutex owned by this object.
+//----------------------------------------------------------------------
+Mutex::~Mutex()
+{
+#if ENABLE_MUTEX_ERROR_CHECKING
+ int err = ::pthread_mutex_destroy (&m_mutex);
+ assert(err == 0);
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionDestroyed);
+ else
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err));
+ assert(err == 0);
+ }
+ memset (&m_mutex, '\xba', sizeof(m_mutex));
+#else
+ ::pthread_mutex_destroy (&m_mutex);
+#endif
+}
+
+//----------------------------------------------------------------------
+// Locks the mutex owned by this object, if the mutex is already
+// locked, the calling thread will block until the mutex becomes
+// available.
+//
+// RETURNS
+// The error code from the pthread_mutex_lock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Lock()
+{
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex);
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_lock (&m_mutex);
+
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err)
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
+ assert(err == 0);
+ }
+#endif
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+//----------------------------------------------------------------------
+// Attempts to lock the mutex owned by this object without blocking.
+// If the mutex is already locked, TryLock() will not block waiting
+// for the mutex, but will return an error condition.
+//
+// RETURNS
+// The error code from the pthread_mutex_trylock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::TryLock(const char *failure_message)
+{
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_trylock (&m_mutex);
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+//----------------------------------------------------------------------
+// If the current thread holds the lock on the owned mutex, then
+// Unlock() will unlock the mutex. Calling Unlock() on this object
+// that the calling thread does not hold will result in undefined
+// behavior.
+//
+// RETURNS
+// The error code from the pthread_mutex_unlock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Unlock()
+{
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_unlock (&m_mutex);
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err)
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
+ assert(err == 0);
+ }
+#endif
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+#endif
+
+//----------------------------------------------------------------------
+// Mutex get accessor.
+//----------------------------------------------------------------------
+lldb::mutex_t *
+Mutex::GetMutex()
+{
+ return &m_mutex;
+}
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+int
+TrackingMutex::Unlock ()
+{
+ if (!m_failure_message.empty())
+ Host::SetCrashDescriptionWithFormat ("Unlocking lock (on thread %p) that thread: %p failed to get: %s",
+ pthread_self(),
+ m_thread_that_tried,
+ m_failure_message.c_str());
+ assert (m_failure_message.empty());
+ return Mutex::Unlock();
+}
+
+int
+LoggingMutex::Lock ()
+{
+ printf("locking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::Lock();
+ m_locked = true;
+ printf("%d\n",x);
+ return x;
+}
+
+int
+LoggingMutex::Unlock ()
+{
+ printf("unlocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::Unlock();
+ m_locked = false;
+ printf("%d\n",x);
+ return x;
+}
+
+int
+LoggingMutex::TryLock (const char *failure_message)
+{
+ printf("trylocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::TryLock(failure_message);
+ if (x == 0)
+ m_locked = true;
+ printf("%d\n",x);
+ return x;
+}
+
+#endif
+
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp
new file mode 100644
index 0000000..622b4ea
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp
@@ -0,0 +1,116 @@
+//===-- NativeBreakpoint.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeBreakpoint.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+NativeBreakpoint::NativeBreakpoint (lldb::addr_t addr) :
+ m_addr (addr),
+ m_ref_count (1),
+ m_enabled (true)
+{
+ assert (addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address");
+}
+
+NativeBreakpoint::~NativeBreakpoint ()
+{
+}
+
+void
+NativeBreakpoint::AddRef ()
+{
+ ++m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " bumped up, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+}
+
+int32_t
+NativeBreakpoint::DecRef ()
+{
+ --m_ref_count;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " ref count decremented, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);
+
+ return m_ref_count;
+}
+
+Error
+NativeBreakpoint::Enable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_enabled)
+ {
+ // We're already enabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already enabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and enable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...", __FUNCTION__, m_addr);
+
+ Error error = DoEnable ();
+ if (error.Success ())
+ {
+ m_enabled = true;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
+
+Error
+NativeBreakpoint::Disable ()
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (!m_enabled)
+ {
+ // We're already disabled. Just log and exit.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already disabled, ignoring.", __FUNCTION__, m_addr);
+ return Error ();
+ }
+
+ // Log and disable.
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...", __FUNCTION__, m_addr);
+
+ Error error = DoDisable ();
+ if (error.Success ())
+ {
+ m_enabled = false;
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.", __FUNCTION__, m_addr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+ }
+
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp
new file mode 100644
index 0000000..52b9baf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp
@@ -0,0 +1,221 @@
+//===-- NativeBreakpointList.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeBreakpointList.h"
+
+#include "lldb/Core/Log.h"
+
+#include "lldb/Host/common/NativeBreakpoint.h"
+#include "lldb/Host/common/SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeBreakpointList::NativeBreakpointList () :
+ m_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+Error
+NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ 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);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter != m_breakpoints.end ())
+ {
+ // Yes - bump up ref count.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already enabled, upping ref count", __FUNCTION__, addr);
+
+ iter->second->AddRef ();
+ return Error ();
+ }
+
+ // Create a new breakpoint using the given create func.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+ NativeBreakpointSP breakpoint_sp;
+ Error error = create_func (addr, size_hint, hardware, breakpoint_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s -- FAILED: %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false", error.AsCString ());
+ return error;
+ }
+
+ // Remember the breakpoint.
+ assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint");
+ m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp));
+
+ return error;
+}
+
+Error
+NativeBreakpointList::DecRef (lldb::addr_t addr)
+{
+ Error error;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Check if the breakpoint is already set.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ error.SetErrorString ("breakpoint not found");
+ return error;
+ }
+
+ // Decrement ref count.
+ const int32_t new_ref_count = iter->second->DecRef ();
+ assert (new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
+
+ if (new_ref_count > 0)
+ {
+ // Still references to this breakpoint. Leave it alone.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- new breakpoint ref count %" PRIu32, __FUNCTION__, addr, new_ref_count);
+ return error;
+ }
+
+ // Breakpoint has no more references. Disable it if it's not
+ // already disabled.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removing due to no remaining references", __FUNCTION__, addr);
+
+ // If it's enabled, we need to disable it.
+ if (iter->second->IsEnabled ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- currently enabled, now disabling", __FUNCTION__, addr);
+ error = iter->second->Disable ();
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removal FAILED: %s", __FUNCTION__, addr, error.AsCString ());
+ // Continue since we still want to take it out of the breakpoint list.
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already disabled, nothing to do", __FUNCTION__, addr);
+ }
+
+ // Take the breakpoint out of the list.
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr);
+
+ m_breakpoints.erase (iter);
+ return error;
+}
+
+Error
+NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Enable it.
+ return iter->second->Enable ();
+}
+
+Error
+NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ return iter->second->Disable ();
+}
+
+Error
+NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ Mutex::Locker locker (m_mutex);
+
+ // Ensure we have said breakpoint.
+ auto iter = m_breakpoints.find (addr);
+ if (iter == m_breakpoints.end ())
+ {
+ // Not found!
+ breakpoint_sp.reset ();
+ return Error ("breakpoint not found");
+ }
+
+ // Disable it.
+ breakpoint_sp = iter->second;
+ return Error ();
+}
+
+Error
+NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const
+{
+ for (const auto &map : m_breakpoints)
+ {
+ lldb::addr_t bp_addr = map.first;
+ // Breapoint not in range, ignore
+ if (bp_addr < addr || addr + size <= bp_addr)
+ continue;
+ const auto &bp_sp = map.second;
+ // Not software breakpoint, ignore
+ if (!bp_sp->IsSoftwareBreakpoint())
+ continue;
+ auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp);
+ auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr;
+ auto saved_opcodes = software_bp_sp->m_saved_opcodes;
+ auto opcode_size = software_bp_sp->m_opcode_size;
+ ::memcpy(opcode_addr, saved_opcodes, opcode_size);
+ }
+ return Error();
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp
new file mode 100644
index 0000000..7d2f401
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp
@@ -0,0 +1,461 @@
+//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+#include "lldb/Host/common/SoftwareBreakpoint.h"
+
+using namespace lldb;
+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)
+{
+}
+
+lldb_private::Error
+NativeProcessProtocol::Interrupt ()
+{
+ Error error;
+#if !defined (SIGSTOP)
+ error.SetErrorString ("local host does not support signaling");
+ return error;
+#else
+ return Signal (SIGSTOP);
+#endif
+}
+
+lldb_private::Error
+NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+ // Default: not implemented.
+ return Error ("not implemented");
+}
+
+bool
+NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description)
+{
+ if (m_state == lldb::eStateExited)
+ {
+ *exit_type = m_exit_type;
+ *status = m_exit_status;
+ exit_description = m_exit_description;
+ return true;
+ }
+
+ *status = 0;
+ return false;
+}
+
+bool
+NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange)
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
+ __FUNCTION__,
+ exit_type,
+ status,
+ exit_description ? exit_description : "nullptr",
+ bNotifyStateChange ? "true" : "false");
+
+ // Exit status already set
+ if (m_state == lldb::eStateExited)
+ {
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status);
+ return false;
+ }
+
+ m_state = lldb::eStateExited;
+
+ m_exit_type = exit_type;
+ m_exit_status = status;
+ if (exit_description && exit_description[0])
+ m_exit_description = exit_description;
+ else
+ m_exit_description.clear();
+
+ if (bNotifyStateChange)
+ SynchronouslyNotifyProcessStateChanged (lldb::eStateExited);
+
+ return true;
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ if (idx < m_threads.size ())
+ return m_threads[idx];
+ return NativeThreadProtocolSP ();
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByIDUnlocked (lldb::tid_t tid)
+{
+ for (auto thread_sp : m_threads)
+ {
+ if (thread_sp->GetID() == tid)
+ return thread_sp;
+ }
+ return NativeThreadProtocolSP ();
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ return GetThreadByIDUnlocked (tid);
+}
+
+bool
+NativeProcessProtocol::IsAlive () const
+{
+ return m_state != eStateDetached
+ && m_state != eStateExited
+ && m_state != eStateInvalid
+ && m_state != eStateUnloaded;
+}
+
+bool
+NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const
+{
+ ArchSpec process_arch;
+ if (!GetArchitecture (process_arch))
+ return false;
+ byte_order = process_arch.GetByteOrder ();
+ return true;
+}
+
+const NativeWatchpointList::WatchpointMap&
+NativeProcessProtocol::GetWatchpointMap () const
+{
+ return m_watchpoint_list.GetWatchpointMap();
+}
+
+uint32_t
+NativeProcessProtocol::GetMaxWatchpoints () const
+{
+ // This default implementation will return the number of
+ // *hardware* breakpoints available. MacOSX and other OS
+ // implementations that support software breakpoints will want to
+ // override this correctly for their implementation.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // get any thread
+ NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0));
+ if (!thread_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__);
+ return 0;
+ }
+
+ NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ());
+ if (!reg_ctx_sp)
+ {
+ if (log)
+ log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__);
+ return 0;
+ }
+
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints ();
+}
+
+Error
+NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ // This default implementation assumes setting the watchpoint for
+ // the process will require setting the watchpoint for each of the
+ // threads. Furthermore, it will track watchpoints set for the
+ // process and will add them to each thread that is attached to
+ // via the (FIXME implement) OnThreadAttached () method.
+
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Update the thread list
+ UpdateThreads ();
+
+ // Keep track of the threads we successfully set the watchpoint
+ // for. If one of the thread watchpoint setting operations fails,
+ // back off and remove the watchpoint for all the threads that
+ // were successfully set so we get back to a consistent state.
+ std::vector<NativeThreadProtocolSP> watchpoint_established_threads;
+
+ // Tell each thread to set a watchpoint. In the event that
+ // hardware watchpoints are requested but the SetWatchpoint fails,
+ // try to set a software watchpoint as a fallback. It's
+ // 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);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware);
+ if (thread_error.Fail () && hardware)
+ {
+ // Try software watchpoints since we failed on hardware watchpoint setting
+ // and we may have just run out of hardware watchpoints.
+ thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false);
+ if (thread_error.Success ())
+ {
+ if (log)
+ log->Warning ("hardware watchpoint requested but software watchpoint set");
+ }
+ }
+
+ if (thread_error.Success ())
+ {
+ // Remember that we set this watchpoint successfully in
+ // case we need to clear it later.
+ watchpoint_established_threads.push_back (thread_sp);
+ }
+ else
+ {
+ // Unset the watchpoint for each thread we successfully
+ // set so that we get back to a consistent state of "not
+ // set" for the watchpoint.
+ for (auto unwatch_thread_sp : watchpoint_established_threads)
+ {
+ Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr);
+ if (remove_error.Fail () && log)
+ {
+ log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+ __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ());
+ }
+ }
+
+ return thread_error;
+ }
+ }
+ return m_watchpoint_list.Add (addr, size, watch_flags, hardware);
+}
+
+Error
+NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // Update the thread list
+ UpdateThreads ();
+
+ Error overall_error;
+
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ assert (thread_sp && "thread list should not have a NULL thread!");
+ if (!thread_sp)
+ continue;
+
+ const Error thread_error = thread_sp->RemoveWatchpoint (addr);
+ if (thread_error.Fail ())
+ {
+ // Keep track of the first thread error if any threads
+ // fail. We want to try to remove the watchpoint from
+ // every thread, though, even if one or more have errors.
+ if (!overall_error.Fail ())
+ overall_error = thread_error;
+ }
+ }
+ const Error error = m_watchpoint_list.Remove(addr);
+ return overall_error.Fail() ? overall_error : error;
+}
+
+bool
+NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (m_delegates_mutex);
+ if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ())
+ return false;
+
+ m_delegates.push_back (&native_delegate);
+ native_delegate.InitializeDelegate (this);
+ return true;
+}
+
+bool
+NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate)
+{
+ Mutex::Locker locker (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 ());
+
+ // We removed the delegate if the count of delegates shrank after
+ // removing all copies of the given native_delegate from the vector.
+ return m_delegates.size () < initial_size;
+}
+
+void
+NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ Mutex::Locker locker (m_delegates_mutex);
+ for (auto native_delegate: m_delegates)
+ native_delegate->ProcessStateChanged (this, state);
+
+ if (log)
+ {
+ if (!m_delegates.empty ())
+ {
+ log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64,
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ else
+ {
+ log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates",
+ __FUNCTION__, lldb_private::StateAsCString (state), GetID ());
+ }
+ }
+}
+
+void
+NativeProcessProtocol::NotifyDidExec ()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__);
+
+ {
+ Mutex::Locker locker (m_delegates_mutex);
+ for (auto native_delegate: m_delegates)
+ native_delegate->DidExec (this);
+ }
+}
+
+
+Error
+NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ return m_breakpoint_list.AddRef (addr, size_hint, false,
+ [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error
+ { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); });
+}
+
+Error
+NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DecRef (addr);
+}
+
+Error
+NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.EnableBreakpoint (addr);
+}
+
+Error
+NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr)
+{
+ return m_breakpoint_list.DisableBreakpoint (addr);
+}
+
+lldb::StateType
+NativeProcessProtocol::GetState () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_state;
+}
+
+void
+NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates)
+{
+ Mutex::Locker locker (m_state_mutex);
+
+ if (state == m_state)
+ return;
+
+ m_state = state;
+
+ if (StateIsStoppedState (state, false))
+ {
+ ++m_stop_id;
+
+ // Give process a chance to do any stop id bump processing, such as
+ // clearing cached data that is invalidated each time the process runs.
+ // Note if/when we support some threads running, we'll end up needing
+ // to manage this per thread and per process.
+ DoStopIDBumped (m_stop_id);
+ }
+
+ // Optionally notify delegates of the state change.
+ if (notify_delegates)
+ SynchronouslyNotifyProcessStateChanged (state);
+}
+
+uint32_t NativeProcessProtocol::GetStopID () const
+{
+ Mutex::Locker locker (m_state_mutex);
+ return m_stop_id;
+}
+
+void
+NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */)
+{
+ // Default implementation does nothing.
+}
+
+#ifndef __linux__
+// These need to be implemented to support lldb-gdb-server on a given platform. Stubs are
+// provided to make the rest of the code link on non-supported platforms.
+
+Error
+NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &process_sp)
+{
+ llvm_unreachable("Platform has no NativeProcessProtocol support");
+}
+
+Error
+NativeProcessProtocol::Attach (lldb::pid_t pid,
+ NativeDelegate &native_delegate,
+ MainLoop &mainloop,
+ NativeProcessProtocolSP &process_sp)
+{
+ llvm_unreachable("Platform has no NativeProcessProtocol support");
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp
new file mode 100644
index 0000000..e67c079
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContext.cpp
@@ -0,0 +1,516 @@
+//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeRegisterContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) :
+ m_thread (thread),
+ m_concrete_frame_idx (concrete_frame_idx)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+NativeRegisterContext::~NativeRegisterContext()
+{
+}
+
+// FIXME revisit invalidation, process stop ids, etc. Right now we don't
+// support caching in NativeRegisterContext. We can do this later by
+// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
+// NativeRegisterContext.
+
+// void
+// NativeRegisterContext::InvalidateIfNeeded (bool force)
+// {
+// ProcessSP process_sp (m_thread.GetProcess());
+// bool invalidate = force;
+// uint32_t process_stop_id = UINT32_MAX;
+
+// if (process_sp)
+// process_stop_id = process_sp->GetStopID();
+// else
+// invalidate = true;
+
+// if (!invalidate)
+// invalidate = process_stop_id != GetStopID();
+
+// if (invalidate)
+// {
+// InvalidateAllRegisters ();
+// SetStopID (process_stop_id);
+// }
+// }
+
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+ if (reg_name && reg_name[0])
+ {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+ if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+ {
+ return reg_info;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+{
+ const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return nullptr;
+ return GetRegisterInfoAtIndex (reg_num);
+}
+
+const char *
+NativeRegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return nullptr;
+}
+
+const char*
+NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const
+{
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return nullptr;
+
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index)
+ {
+ const RegisterSet *const reg_set = GetRegisterSet (set_index);
+ if (!reg_set)
+ continue;
+
+ for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index)
+ {
+ const uint32_t reg_num = reg_set->registers[reg_num_index];
+ // FIXME double check we're checking the right register kind here.
+ if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num)
+ {
+ // The given register is a member of this register set. Return the register set name.
+ return reg_set->name;
+ }
+ }
+ }
+
+ // Didn't find it.
+ return nullptr;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPC (lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (log)
+ log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value);
+
+ const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value);
+
+ if (log)
+ log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval);
+
+ return retval;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPCfromBreakpointLocation (lldb::addr_t fail_value)
+{
+ return GetPC (fail_value);
+}
+
+Error
+NativeRegisterContext::SetPC (lldb::addr_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return WriteRegisterFromUnsigned (reg, pc);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetSP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetSP (lldb::addr_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetFP (lldb::addr_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFlags (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+lldb::addr_t
+NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+ return fail_value;
+}
+
+uint64_t
+NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (reg_info)
+ {
+ RegisterValue value;
+ Error error = ReadRegister (reg_info, value);
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64());
+ return value.GetAsUInt64();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__);
+ }
+ return fail_value;
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+ return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+ assert (reg_info);
+ if (!reg_info)
+ return Error ("reg_info is nullptr");
+
+ RegisterValue value;
+ if (!value.SetUInt(uval, reg_info->byte_size))
+ return Error ("RegisterValue::SetUInt () failed");
+
+ return WriteRegister (reg_info, value);
+}
+
+lldb::tid_t
+NativeRegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+Error
+NativeRegisterContext::ClearAllHardwareWatchpoints ()
+{
+ return Error ("not implemented");
+}
+
+Error
+NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit)
+{
+ is_hit = false;
+ return Error ("not implemented");
+}
+
+Error
+NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr)
+{
+ wp_index = LLDB_INVALID_INDEX32;
+ return Error ("not implemented");
+}
+
+Error
+NativeRegisterContext::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant)
+{
+ is_vacant = false;
+ return Error ("not implemented");
+}
+
+lldb::addr_t
+NativeRegisterContext::GetWatchpointAddress (uint32_t wp_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetWatchpointHitAddress (uint32_t wp_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+NativeRegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Error
+NativeRegisterContext::ReadRegisterValueFromMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ size_t src_len,
+ RegisterValue &reg_value)
+{
+ Error error;
+ if (reg_info == nullptr)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return error;
+ }
+
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > RegisterValue::kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("register too small to receive memory data");
+ return error;
+ }
+
+ const size_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)",
+ static_cast<uint64_t>(src_len), reg_info->name, static_cast<uint64_t>(dst_len));
+ return error;
+ }
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString("invalid process");
+ return error;
+ }
+
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ size_t bytes_read;
+ error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
+ if (error.Fail ())
+ return error;
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes",
+ static_cast<uint64_t>(bytes_read), static_cast<uint64_t>(src_len));
+ return error;
+ }
+
+ // We now have a memory buffer that contains the part or all of the register
+ // value. Set the register value using this memory data.
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed");
+ return error;
+ }
+
+ reg_value.SetFromMemoryData (
+ reg_info,
+ src,
+ src_len,
+ byte_order,
+ error);
+
+ return error;
+}
+
+Error
+NativeRegisterContext::WriteRegisterValueToMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t dst_addr,
+ size_t dst_len,
+ const RegisterValue &reg_value)
+{
+
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (process_sp)
+ {
+
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ return Error ("NativeProcessProtocol::GetByteOrder () failed");
+
+ const size_t bytes_copied = reg_value.GetAsMemoryData (
+ reg_info,
+ dst,
+ dst_len,
+ byte_order,
+ error);
+
+ if (error.Success())
+ {
+ if (bytes_copied == 0)
+ {
+ error.SetErrorString("byte copy failed.");
+ }
+ else
+ {
+ size_t bytes_written;
+ error = process_sp->WriteMemory(dst_addr, dst, bytes_copied, bytes_written);
+ if (error.Fail ())
+ return error;
+
+ if (bytes_written != bytes_copied)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes",
+ static_cast<uint64_t>(bytes_written), static_cast<uint64_t>(bytes_copied));
+ }
+ }
+ }
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+uint32_t
+NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp
new file mode 100644
index 0000000..0d7c6ec
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeRegisterContextRegisterInfo.cpp
@@ -0,0 +1,50 @@
+//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface) :
+ NativeRegisterContext (thread, concrete_frame_idx),
+ m_register_info_interface_up (register_info_interface)
+{
+ assert (register_info_interface && "null register_info_interface");
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetRegisterCount () const
+{
+ return m_register_info_interface_up->GetRegisterCount ();
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetUserRegisterCount () const
+{
+ return m_register_info_interface_up->GetUserRegisterCount ();
+}
+
+const RegisterInfo *
+NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const
+{
+ if (reg_index <= GetRegisterCount ())
+ return m_register_info_interface_up->GetRegisterInfo () + reg_index;
+ else
+ return nullptr;
+}
+
+const RegisterInfoInterface&
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const
+{
+ return *m_register_info_interface_up;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp
new file mode 100644
index 0000000..ea406e9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp
@@ -0,0 +1,75 @@
+//===-- NativeThreadProtocol.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/common/SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeThreadProtocol::NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
+ m_process_wp (process->shared_from_this ()),
+ m_tid (tid)
+{
+}
+
+Error
+NativeThreadProtocol::ReadRegister (uint32_t reg, RegisterValue &reg_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->ReadRegister (reg_info, reg_value);;
+}
+
+Error
+NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue &reg_value)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+
+ const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+ if (!reg_info)
+ return Error ("no register info for reg num %" PRIu32, reg);
+
+ return register_context_sp->WriteRegister (reg_info, reg_value);
+}
+
+Error
+NativeThreadProtocol::SaveAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->WriteAllRegisterValues (data_sp);
+}
+
+Error
+NativeThreadProtocol::RestoreAllRegisters (lldb::DataBufferSP &data_sp)
+{
+ NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+ if (!register_context_sp)
+ return Error ("no register context");
+ return register_context_sp->ReadAllRegisterValues (data_sp);
+}
+
+NativeProcessProtocolSP
+NativeThreadProtocol::GetProcess ()
+{
+ return m_process_wp.lock ();
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp
new file mode 100644
index 0000000..209d213
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/NativeWatchpointList.cpp
@@ -0,0 +1,35 @@
+//===-- NativeWatchpointList.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/NativeWatchpointList.h"
+
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error
+NativeWatchpointList::Add (addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+ m_watchpoints[addr] = {addr, size, watch_flags, hardware};
+ return Error ();
+}
+
+Error
+NativeWatchpointList::Remove (addr_t addr)
+{
+ m_watchpoints.erase(addr);
+ return Error ();
+}
+
+const NativeWatchpointList::WatchpointMap&
+NativeWatchpointList::GetWatchpointMap () const
+{
+ return m_watchpoints;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp
new file mode 100644
index 0000000..a978459
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp
@@ -0,0 +1,116 @@
+//===-- source/Host/common/OptionParser.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/OptionParser.h"
+#include "lldb/Host/HostGetOpt.h"
+#include "lldb/lldb-private-types.h"
+
+#include <vector>
+
+using namespace lldb_private;
+
+void
+OptionParser::Prepare(Mutex::Locker &locker)
+{
+ static Mutex g_mutex(Mutex::eMutexTypeNormal);
+ locker.Lock(g_mutex);
+#ifdef __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+}
+
+void
+OptionParser::EnableError(bool error)
+{
+ opterr = error ? 1 : 0;
+}
+
+int
+OptionParser::Parse (int argc,
+ char * const argv [],
+ const char *optstring,
+ const Option *longopts,
+ int *longindex)
+{
+ std::vector<option> opts;
+ while (longopts->definition != nullptr)
+ {
+ option opt;
+ opt.flag = longopts->flag;
+ opt.val = longopts->val;
+ opt.name = longopts->definition->long_option;
+ opt.has_arg = longopts->definition->option_has_arg;
+ opts.push_back(opt);
+ ++longopts;
+ }
+ opts.push_back(option());
+ return getopt_long_only(argc, argv, optstring, &opts[0], longindex);
+}
+
+char*
+OptionParser::GetOptionArgument()
+{
+ return optarg;
+}
+
+int
+OptionParser::GetOptionIndex()
+{
+ return optind;
+}
+
+int
+OptionParser::GetOptionErrorCause()
+{
+ return optopt;
+}
+
+std::string
+OptionParser::GetShortOptionString(struct option *long_options)
+{
+ std::string s;
+ int i=0;
+ bool done = false;
+ while (!done)
+ {
+ if (long_options[i].name == 0 &&
+ long_options[i].has_arg == 0 &&
+ long_options[i].flag == 0 &&
+ long_options[i].val == 0)
+ {
+ done = true;
+ }
+ else
+ {
+ if (long_options[i].flag == NULL &&
+ isalpha(long_options[i].val))
+ {
+ s.append(1, (char)long_options[i].val);
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+
+ case optional_argument:
+ s.append(2, ':');
+ break;
+ case required_argument:
+ s.append(1, ':');
+ break;
+ }
+ }
+ ++i;
+ }
+ }
+ return s;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp
new file mode 100644
index 0000000..a9d6e6f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/PipeBase.cpp
@@ -0,0 +1,27 @@
+//===-- source/Host/common/PipeBase.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/PipeBase.h"
+
+using namespace lldb_private;
+
+
+PipeBase::~PipeBase() = default;
+
+Error
+PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit)
+{
+ return OpenAsWriterWithTimeout(name, child_process_inherit, std::chrono::microseconds::zero());
+}
+
+Error
+PipeBase::Read(void *buf, size_t size, size_t &bytes_read)
+{
+ return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(), bytes_read);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/ProcessRunLock.cpp b/contrib/llvm/tools/lldb/source/Host/common/ProcessRunLock.cpp
new file mode 100644
index 0000000..669a96d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/ProcessRunLock.cpp
@@ -0,0 +1,71 @@
+#ifndef _WIN32
+
+#include "lldb/Host/ProcessRunLock.h"
+
+namespace lldb_private {
+
+ ProcessRunLock::ProcessRunLock()
+ : m_running(false)
+ {
+ int err = ::pthread_rwlock_init(&m_rwlock, NULL); (void) err;
+ //#if LLDB_CONFIGURATION_DEBUG
+ // assert(err == 0);
+ //#endif
+ }
+
+ ProcessRunLock::~ProcessRunLock()
+ {
+ int err = ::pthread_rwlock_destroy(&m_rwlock); (void) err;
+ //#if LLDB_CONFIGURATION_DEBUG
+ // assert(err == 0);
+ //#endif
+ }
+
+ bool ProcessRunLock::ReadTryLock()
+ {
+ ::pthread_rwlock_rdlock(&m_rwlock);
+ if (m_running == false)
+ {
+ return true;
+ }
+ ::pthread_rwlock_unlock(&m_rwlock);
+ return false;
+ }
+
+ bool ProcessRunLock::ReadUnlock()
+ {
+ return ::pthread_rwlock_unlock(&m_rwlock) == 0;
+ }
+
+ bool ProcessRunLock::SetRunning()
+ {
+ ::pthread_rwlock_wrlock(&m_rwlock);
+ m_running = true;
+ ::pthread_rwlock_unlock(&m_rwlock);
+ return true;
+ }
+
+ bool ProcessRunLock::TrySetRunning()
+ {
+ bool r;
+
+ if (::pthread_rwlock_trywrlock(&m_rwlock) == 0)
+ {
+ r = !m_running;
+ m_running = true;
+ ::pthread_rwlock_unlock(&m_rwlock);
+ return r;
+ }
+ return false;
+ }
+
+ bool ProcessRunLock::SetStopped()
+ {
+ ::pthread_rwlock_wrlock(&m_rwlock);
+ m_running = false;
+ ::pthread_rwlock_unlock(&m_rwlock);
+ return true;
+ }
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp
new file mode 100644
index 0000000..91a5e37
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp
@@ -0,0 +1,489 @@
+//===-- Socket.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Socket.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/SocketAddress.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/common/UDPSocket.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include "lldb/Host/posix/DomainSocket.h"
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#ifdef __linux__
+#include "lldb/Host/linux/AbstractSocket.h"
+#endif
+
+#ifdef __ANDROID_NDK__
+#include <linux/tcp.h>
+#include <bits/error_constants.h>
+#include <asm-generic/errno-base.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC)
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
+#endif // ANDROID_ARM_BUILD_STATIC || ANDROID_MIPS_BUILD_STATIC
+#endif // __ANDROID_NDK__
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if defined(_WIN32)
+typedef const char * set_socket_option_arg_type;
+typedef char * get_socket_option_arg_type;
+const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET;
+#else // #if defined(_WIN32)
+typedef const void * set_socket_option_arg_type;
+typedef void * get_socket_option_arg_type;
+const NativeSocket Socket::kInvalidSocketValue = -1;
+#endif // #if defined(_WIN32)
+
+namespace {
+
+bool IsInterrupted()
+{
+#if defined(_WIN32)
+ return ::WSAGetLastError() == WSAEINTR;
+#else
+ return errno == EINTR;
+#endif
+}
+
+}
+
+Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
+ : IOObject(eFDTypeSocket, should_close)
+ , m_protocol(protocol)
+ , m_socket(socket)
+{
+
+}
+
+Socket::~Socket()
+{
+ Close();
+}
+
+std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, bool child_processes_inherit, Error &error)
+{
+ error.Clear();
+
+ std::unique_ptr<Socket> socket_up;
+ switch (protocol)
+ {
+ case ProtocolTcp:
+ socket_up.reset(new TCPSocket(child_processes_inherit, error));
+ break;
+ case ProtocolUdp:
+ socket_up.reset(new UDPSocket(child_processes_inherit, error));
+ break;
+ case ProtocolUnixDomain:
+#ifndef LLDB_DISABLE_POSIX
+ socket_up.reset(new DomainSocket(child_processes_inherit, error));
+#else
+ error.SetErrorString("Unix domain sockets are not supported on this platform.");
+#endif
+ break;
+ case ProtocolUnixAbstract:
+#ifdef __linux__
+ socket_up.reset(new AbstractSocket(child_processes_inherit, error));
+#else
+ error.SetErrorString("Abstract domain sockets are not supported on this platform.");
+#endif
+ break;
+ }
+
+ if (error.Fail())
+ socket_up.reset();
+
+ return socket_up;
+}
+
+Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
+ if (log)
+ log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data());
+
+ Error error;
+ std::unique_ptr<Socket> connect_socket(Create(ProtocolTcp, child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = connect_socket->Connect(host_and_port);
+ if (error.Success())
+ socket = connect_socket.release();
+
+ return error;
+}
+
+Error
+Socket::TcpListen (llvm::StringRef host_and_port,
+ bool child_processes_inherit,
+ Socket *&socket,
+ Predicate<uint16_t>* predicate,
+ int backlog)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("Socket::%s (%s)", __FUNCTION__, host_and_port.data());
+
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ std::unique_ptr<TCPSocket> listen_socket(new TCPSocket(child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = listen_socket->Listen(host_and_port, backlog);
+ if (error.Success())
+ {
+ // We were asked to listen on port zero which means we
+ // must now read the actual port that was given to us
+ // as port zero is a special code for "find an open port
+ // for me".
+ if (port == 0)
+ port = listen_socket->GetLocalPortNumber();
+
+ // Set the port predicate since when doing a listen://<host>:<port>
+ // it often needs to accept the incoming connection which is a blocking
+ // system call. Allowing access to the bound port using a predicate allows
+ // us to wait for the port predicate to be set to a non-zero value from
+ // another thread in an efficient manor.
+ if (predicate)
+ predicate->SetValue (port, eBroadcastAlways);
+ socket = listen_socket.release();
+ }
+
+ return error;
+}
+
+Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data());
+
+ return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket, recv_socket);
+}
+
+Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ Error error;
+ std::unique_ptr<Socket> connect_socket(Create(ProtocolUnixDomain, child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = connect_socket->Connect(name);
+ if (error.Success())
+ socket = connect_socket.release();
+
+ return error;
+}
+
+Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ Error error;
+ std::unique_ptr<Socket> listen_socket(Create(ProtocolUnixDomain, child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = listen_socket->Listen(name, 5);
+ if (error.Fail())
+ return error;
+
+ error = listen_socket->Accept(name, child_processes_inherit, socket);
+ return error;
+}
+
+Error
+Socket::UnixAbstractConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ Error error;
+ std::unique_ptr<Socket> connect_socket(Create(ProtocolUnixAbstract, child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = connect_socket->Connect(name);
+ if (error.Success())
+ socket = connect_socket.release();
+ return error;
+}
+
+Error
+Socket::UnixAbstractAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ Error error;
+ std::unique_ptr<Socket> listen_socket(Create(ProtocolUnixAbstract,child_processes_inherit, error));
+ if (error.Fail())
+ return error;
+
+ error = listen_socket->Listen(name, 5);
+ if (error.Fail())
+ return error;
+
+ error = listen_socket->Accept(name, child_processes_inherit, socket);
+ return error;
+}
+
+bool
+Socket::DecodeHostAndPort(llvm::StringRef host_and_port,
+ std::string &host_str,
+ std::string &port_str,
+ int32_t& port,
+ Error *error_ptr)
+{
+ static RegularExpression g_regex ("([^:]+):([0-9]+)");
+ RegularExpression::Match regex_match(2);
+ if (g_regex.Execute (host_and_port.data(), &regex_match))
+ {
+ if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) &&
+ regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str))
+ {
+ bool ok = false;
+ port = StringConvert::ToUInt32 (port_str.c_str(), UINT32_MAX, 10, &ok);
+ if (ok && port < UINT16_MAX)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ // port is too large
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data());
+ return false;
+ }
+ }
+
+ // If this was unsuccessful, then check if it's simply a signed 32-bit integer, representing
+ // a port with an empty host.
+ host_str.clear();
+ port_str.clear();
+ bool ok = false;
+ port = StringConvert::ToUInt32 (host_and_port.data(), UINT32_MAX, 10, &ok);
+ if (ok && port < UINT16_MAX)
+ {
+ port_str = host_and_port;
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data());
+ return false;
+}
+
+IOObject::WaitableHandle Socket::GetWaitableHandle()
+{
+ // TODO: On Windows, use WSAEventSelect
+ return m_socket;
+}
+
+Error Socket::Read (void *buf, size_t &num_bytes)
+{
+ Error error;
+ int bytes_received = 0;
+ do
+ {
+ bytes_received = ::recv (m_socket, static_cast<char *>(buf), num_bytes, 0);
+ } while (bytes_received < 0 && IsInterrupted ());
+
+ if (bytes_received < 0)
+ {
+ SetLastError (error);
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_received;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
+ if (log)
+ {
+ log->Printf ("%p Socket::Read() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_socket),
+ buf,
+ static_cast<uint64_t>(num_bytes),
+ static_cast<int64_t>(bytes_received),
+ error.AsCString());
+ }
+
+ return error;
+}
+
+Error Socket::Write (const void *buf, size_t &num_bytes)
+{
+ Error error;
+ int bytes_sent = 0;
+ do
+ {
+ bytes_sent = Send(buf, num_bytes);
+ } while (bytes_sent < 0 && IsInterrupted ());
+
+ if (bytes_sent < 0)
+ {
+ SetLastError (error);
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_sent;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
+ if (log)
+ {
+ log->Printf ("%p Socket::Write() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ static_cast<void*>(this),
+ static_cast<uint64_t>(m_socket),
+ buf,
+ static_cast<uint64_t>(num_bytes),
+ static_cast<int64_t>(bytes_sent),
+ error.AsCString());
+ }
+
+ return error;
+}
+
+Error Socket::PreDisconnect()
+{
+ Error error;
+ return error;
+}
+
+Error Socket::Close()
+{
+ Error error;
+ if (!IsValid() || !m_should_close_fd)
+ return error;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p Socket::Close (fd = %i)", static_cast<void*>(this), m_socket);
+
+#if defined(_WIN32)
+ bool success = !!closesocket(m_socket);
+#else
+ bool success = !!::close (m_socket);
+#endif
+ // A reference to a FD was passed in, set it to an invalid value
+ m_socket = kInvalidSocketValue;
+ if (!success)
+ {
+ SetLastError (error);
+ }
+
+ return error;
+}
+
+
+int Socket::GetOption(int level, int option_name, int &option_value)
+{
+ get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
+ socklen_t option_value_size = sizeof(int);
+ return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size);
+}
+
+int Socket::SetOption(int level, int option_name, int option_value)
+{
+ set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value);
+ return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value));
+}
+
+size_t Socket::Send(const void *buf, const size_t num_bytes)
+{
+ return ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0);
+}
+
+void Socket::SetLastError(Error &error)
+{
+#if defined(_WIN32)
+ error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32);
+#else
+ error.SetErrorToErrno();
+#endif
+}
+
+NativeSocket
+Socket::CreateSocket(const int domain,
+ const int type,
+ const int protocol,
+ bool child_processes_inherit,
+ Error& error)
+{
+ error.Clear();
+ auto socketType = type;
+#ifdef SOCK_CLOEXEC
+ if (!child_processes_inherit)
+ socketType |= SOCK_CLOEXEC;
+#endif
+ auto sock = ::socket (domain, socketType, protocol);
+ if (sock == kInvalidSocketValue)
+ SetLastError(error);
+
+ return sock;
+}
+
+NativeSocket
+Socket::AcceptSocket(NativeSocket sockfd,
+ struct sockaddr *addr,
+ socklen_t *addrlen,
+ bool child_processes_inherit,
+ Error& error)
+{
+ error.Clear();
+#if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC)
+ // Temporary workaround for statically linking Android lldb-server with the
+ // latest API.
+ int fd = syscall(__NR_accept, sockfd, addr, addrlen);
+ if (fd >= 0 && !child_processes_inherit)
+ {
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1)
+ return fd;
+ SetLastError(error);
+ close(fd);
+ }
+ return fd;
+#elif defined(SOCK_CLOEXEC)
+ int flags = 0;
+ if (!child_processes_inherit) {
+ flags |= SOCK_CLOEXEC;
+ }
+#if defined(__NetBSD__)
+ NativeSocket fd = ::paccept (sockfd, addr, addrlen, nullptr, flags);
+#else
+ NativeSocket fd = ::accept4 (sockfd, addr, addrlen, flags);
+#endif
+#else
+ NativeSocket fd = ::accept (sockfd, addr, addrlen);
+#endif
+ if (fd == kInvalidSocketValue)
+ SetLastError(error);
+ return fd;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp
new file mode 100644
index 0000000..c8b1687
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp
@@ -0,0 +1,369 @@
+//===-- SocketAddress.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/SocketAddress.h"
+#include <stddef.h>
+#include <stdio.h>
+
+// C Includes
+#if !defined(_WIN32)
+#include <arpa/inet.h>
+#else
+#include "lldb/Host/windows/win32.h"
+#endif
+#include <assert.h>
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+// WindowsXP needs an inet_ntop implementation
+#ifdef _WIN32
+
+#ifndef INET6_ADDRSTRLEN // might not be defined in older Windows SDKs
+#define INET6_ADDRSTRLEN 46
+#endif
+
+// TODO: implement shortened form "::" for runs of zeros
+const char* inet_ntop(int af, const void * src,
+ char * dst, socklen_t size)
+{
+ if (size==0)
+ {
+ return nullptr;
+ }
+
+ switch (af)
+ {
+ case AF_INET:
+ {
+ {
+ const char* formatted = inet_ntoa(*static_cast<const in_addr*>(src));
+ if (formatted && strlen(formatted) < size)
+ {
+ return ::strcpy(dst, formatted);
+ }
+ }
+ return nullptr;
+ case AF_INET6:
+ {
+ char tmp[INET6_ADDRSTRLEN] = {0};
+ const uint16_t* src16 = static_cast<const uint16_t*>(src);
+ int full_size = ::snprintf(tmp, sizeof(tmp),
+ "%x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(src16[0]), ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]),
+ ntohs(src16[4]), ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7])
+ );
+ if (full_size < static_cast<int>(size))
+ {
+ return ::strcpy(dst, tmp);
+ }
+ return nullptr;
+ }
+ }
+ }
+ return nullptr;
+}
+#endif
+
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SocketAddress constructor
+//----------------------------------------------------------------------
+SocketAddress::SocketAddress ()
+{
+ Clear ();
+}
+
+SocketAddress::SocketAddress (const struct sockaddr &s)
+{
+ m_socket_addr.sa = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_in &s)
+{
+ m_socket_addr.sa_ipv4 = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_in6 &s)
+{
+ m_socket_addr.sa_ipv6 = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_storage &s)
+{
+ m_socket_addr.sa_storage = s;
+}
+
+//----------------------------------------------------------------------
+// SocketAddress copy constructor
+//----------------------------------------------------------------------
+SocketAddress::SocketAddress (const SocketAddress& rhs) :
+ m_socket_addr (rhs.m_socket_addr)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SocketAddress::~SocketAddress()
+{
+}
+
+void
+SocketAddress::Clear ()
+{
+ memset (&m_socket_addr, 0, sizeof(m_socket_addr));
+}
+
+bool
+SocketAddress::IsValid () const
+{
+ return GetLength () != 0;
+}
+
+static socklen_t
+GetFamilyLength (sa_family_t family)
+{
+ switch (family)
+ {
+ case AF_INET: return sizeof(struct sockaddr_in);
+ case AF_INET6: return sizeof(struct sockaddr_in6);
+ }
+ assert(0 && "Unsupported address family");
+ return 0;
+}
+
+socklen_t
+SocketAddress::GetLength () const
+{
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ return m_socket_addr.sa.sa_len;
+#else
+ return GetFamilyLength (GetFamily());
+#endif
+}
+
+socklen_t
+SocketAddress::GetMaxLength ()
+{
+ return sizeof (sockaddr_t);
+}
+
+sa_family_t
+SocketAddress::GetFamily () const
+{
+ return m_socket_addr.sa.sa_family;
+}
+
+void
+SocketAddress::SetFamily (sa_family_t family)
+{
+ m_socket_addr.sa.sa_family = family;
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ m_socket_addr.sa.sa_len = GetFamilyLength (family);
+#endif
+}
+
+std::string
+SocketAddress::GetIPAddress () const
+{
+ char str[INET6_ADDRSTRLEN] = {0};
+ switch (GetFamily())
+ {
+ case AF_INET:
+ if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, sizeof(str)))
+ {
+ return str;
+ }
+ case AF_INET6:
+ if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, sizeof(str)))
+ {
+ return str;
+ }
+ }
+ return "";
+}
+
+uint16_t
+SocketAddress::GetPort () const
+{
+ switch (GetFamily())
+ {
+ case AF_INET: return ntohs(m_socket_addr.sa_ipv4.sin_port);
+ case AF_INET6: return ntohs(m_socket_addr.sa_ipv6.sin6_port);
+ }
+ return 0;
+}
+
+bool
+SocketAddress::SetPort (uint16_t port)
+{
+ switch (GetFamily())
+ {
+ case AF_INET:
+ m_socket_addr.sa_ipv4.sin_port = htons(port);
+ return true;
+
+ case AF_INET6:
+ m_socket_addr.sa_ipv6.sin6_port = htons(port);
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// SocketAddress assignment operator
+//----------------------------------------------------------------------
+const SocketAddress&
+SocketAddress::operator=(const SocketAddress& rhs)
+{
+ if (this != &rhs)
+ m_socket_addr = rhs.m_socket_addr;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct addrinfo *addr_info)
+{
+ Clear();
+ if (addr_info &&
+ addr_info->ai_addr &&
+ addr_info->ai_addrlen > 0&&
+ addr_info->ai_addrlen <= sizeof m_socket_addr)
+ {
+ ::memcpy (&m_socket_addr,
+ addr_info->ai_addr,
+ addr_info->ai_addrlen);
+ }
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr &s)
+{
+ m_socket_addr.sa = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_in &s)
+{
+ m_socket_addr.sa_ipv4 = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_in6 &s)
+{
+ m_socket_addr.sa_ipv6 = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_storage &s)
+{
+ m_socket_addr.sa_storage = s;
+ return *this;
+}
+
+bool
+SocketAddress::getaddrinfo (const char *host,
+ const char *service,
+ int ai_family,
+ int ai_socktype,
+ int ai_protocol,
+ int ai_flags)
+{
+ Clear ();
+
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai_family;
+ hints.ai_socktype = ai_socktype;
+ hints.ai_protocol = ai_protocol;
+ hints.ai_flags = ai_flags;
+
+ bool result = false;
+ struct addrinfo *service_info_list = NULL;
+ int err = ::getaddrinfo (host, service, &hints, &service_info_list);
+ if (err == 0 && service_info_list)
+ {
+ *this = service_info_list;
+ result = IsValid ();
+ }
+
+ if (service_info_list)
+ ::freeaddrinfo(service_info_list);
+
+ return result;
+}
+
+
+bool
+SocketAddress::SetToLocalhost (sa_family_t family, uint16_t port)
+{
+ switch (family)
+ {
+ case AF_INET:
+ SetFamily (AF_INET);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ return true;
+ }
+ break;
+
+ case AF_INET6:
+ SetFamily (AF_INET6);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback;
+ return true;
+ }
+ break;
+
+ }
+ Clear();
+ return false;
+}
+
+bool
+SocketAddress::SetToAnyAddress (sa_family_t family, uint16_t port)
+{
+ switch (family)
+ {
+ case AF_INET:
+ SetFamily (AF_INET);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY);
+ return true;
+ }
+ break;
+
+ case AF_INET6:
+ SetFamily (AF_INET6);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv6.sin6_addr = in6addr_any;
+ return true;
+ }
+ break;
+
+ }
+ Clear();
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp
new file mode 100644
index 0000000..5a6f783
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp
@@ -0,0 +1,317 @@
+//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/SoftwareBreakpoint.h"
+
+#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"
+
+using namespace lldb_private;
+
+// -------------------------------------------------------------------
+// static members
+// -------------------------------------------------------------------
+
+Error
+SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Validate the address.
+ if (addr == LLDB_INVALID_ADDRESS)
+ return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);
+
+ // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site.
+ size_t bp_opcode_size = 0;
+ const uint8_t *bp_opcode_bytes = NULL;
+ Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Validate size of trap opcode.
+ if (bp_opcode_size == 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+ }
+
+ // Validate that we received opcodes.
+ if (!bp_opcode_bytes)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
+ return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+ }
+
+ // Enable the breakpoint.
+ uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
+ return error;
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ // Set the breakpoint and verified it was written properly. Now
+ // create a breakpoint remover that understands how to undo this
+ // breakpoint.
+ breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
+ return Error ();
+}
+
+Error
+SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
+{
+ assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
+ assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
+ assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+ // Save the original opcodes by reading them so we can restore later.
+ size_t bytes_read = 0;
+
+ Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many bytes as we expected.
+ if (bytes_read != bp_opcode_size)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read);
+ }
+
+ // Log what we read.
+ if (log)
+ {
+ int i = 0;
+ for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte)
+ {
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
+ " ovewriting byte index %d (was 0x%hhx)",
+ __FUNCTION__, addr, i++, *read_byte);
+ }
+ }
+
+ // Write a software breakpoint in place of the original opcode.
+ size_t bytes_written = 0;
+ error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we wrote as many bytes as we expected.
+ if (bytes_written != bp_opcode_size)
+ {
+ error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_written);
+ if (log)
+ log->PutCString (error.AsCString ());
+ return error;
+ }
+
+ uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ size_t verify_bytes_read = 0;
+ error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
+ return error;
+ }
+
+ // Ensure we read as many verification bytes as we expected.
+ if (verify_bytes_read != bp_opcode_size)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read);
+ return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read);
+ }
+
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
+ {
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+ }
+
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+ return Error ();
+}
+
+// -------------------------------------------------------------------
+// instance-level members
+// -------------------------------------------------------------------
+
+SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
+ NativeBreakpoint (addr),
+ m_process (process),
+ m_saved_opcodes (),
+ m_trap_opcodes (),
+ m_opcode_size (opcode_size)
+{
+ assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
+ assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE && "trap opcode size too large");
+
+ ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
+ ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
+}
+
+Error
+SoftwareBreakpoint::DoEnable ()
+{
+ return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
+}
+
+Error
+SoftwareBreakpoint::DoDisable ()
+{
+ Error error;
+ assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);
+
+ assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");
+
+ if (m_opcode_size > 0)
+ {
+ // Clear a software breakpoint instruction
+ uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
+ bool break_op_found = false;
+ assert (m_opcode_size <= sizeof (curr_break_op));
+
+ // Read the breakpoint opcode
+ size_t bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
+ if (error.Success() && bytes_read < m_opcode_size)
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_read);
+ }
+ if (error.Success ())
+ {
+ bool verify = false;
+ // Make sure the breakpoint opcode exists at this address
+ if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ size_t bytes_written = 0;
+ error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
+ if (error.Success() && bytes_written < m_opcode_size)
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_written);
+ }
+ if (error.Success ())
+ {
+ verify = true;
+ }
+ }
+ else
+ {
+ error.SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
+ assert (m_opcode_size <= sizeof (verify_opcode));
+ // Verify that our original opcode made it back to the inferior
+
+ size_t verify_bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
+ if (error.Success() && verify_bytes_read < m_opcode_size)
+ {
+ error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)verify_bytes_read);
+ }
+ if (error.Success ())
+ {
+ // compare the memory we just read with the original opcode
+ if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
+ {
+ // SUCCESS
+ if (log)
+ {
+ int i = 0;
+ for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte)
+ {
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64
+ " replaced byte index %d with 0x%hhx",
+ __FUNCTION__, m_addr, i++, *verify_byte);
+ }
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
+ }
+ return error;
+ }
+ else
+ {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ }
+
+ if (log && error.Fail ())
+ log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
+ __FUNCTION__,
+ m_addr,
+ error.AsCString());
+ return error;
+}
+
+bool
+SoftwareBreakpoint::IsSoftwareBreakpoint () const
+{
+ return true;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/StringConvert.cpp b/contrib/llvm/tools/lldb/source/Host/common/StringConvert.cpp
new file mode 100644
index 0000000..c4ff675
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/StringConvert.cpp
@@ -0,0 +1,117 @@
+//===-- StringConvert.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/StringConvert.h"
+
+namespace lldb_private
+{
+ namespace StringConvert
+ {
+
+ int32_t
+ ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ const long sval = ::strtol (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
+ return (int32_t)sval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+ }
+
+ uint32_t
+ ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ const unsigned long uval = ::strtoul (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = (uval <= UINT32_MAX);
+ return (uint32_t)uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+ }
+
+ int64_t
+ ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ int64_t uval = ::strtoll (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+ }
+
+ uint64_t
+ ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ uint64_t uval = ::strtoull (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+ }
+
+ double
+ ToDouble (const char *s, double fail_value, bool *success_ptr)
+ {
+ if (s && s[0])
+ {
+ char *end = nullptr;
+ double val = strtod (s, &end);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return val; // All characters were used, return the result
+ }
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
new file mode 100644
index 0000000..60e1dc6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
@@ -0,0 +1,327 @@
+//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Symbols.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/SafeMachO.h"
+
+#include "llvm/Support/FileSystem.h"
+
+// From MacOSX system header "mach/machine.h"
+typedef int cpu_type_t;
+typedef int cpu_subtype_t;
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+#if defined(__APPLE__)
+
+// Forward declaration of method defined in source/Host/macosx/Symbols.cpp
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ ModuleSpec &return_module_spec
+);
+
+#else
+
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ ModuleSpec &return_module_spec
+) {
+ // Cannot find MacOSX files using debug symbols on non MacOSX.
+ return 0;
+}
+
+#endif
+
+static bool
+FileAtPathContainsArchAndUUID (const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid)
+{
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs))
+ {
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i)
+ {
+ assert(module_specs.GetModuleSpecAtIndex(i, spec));
+ if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ if (exec_fspec)
+ {
+ char path[PATH_MAX];
+ if (exec_fspec->GetPath(path, sizeof(path)))
+ {
+ // Make sure the module isn't already just a dSYM file...
+ if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
+ {
+ if (log)
+ {
+ if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid())
+ {
+ log->Printf ("Searching for dSYM bundle next to executable %s, UUID %s", path, module_spec.GetUUIDPtr()->GetAsString().c_str());
+ }
+ else
+ {
+ log->Printf ("Searching for dSYM bundle next to executable %s", path);
+ }
+ }
+ size_t obj_file_path_length = strlen(path);
+ ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
+ ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
+
+ dsym_fspec.SetFile(path, false);
+
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ if (dsym_fspec.Exists() &&
+ FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
+ {
+ if (log)
+ {
+ log->Printf ("dSYM with matching UUID & arch found at %s", path);
+ }
+ return true;
+ }
+ else
+ {
+ path[obj_file_path_length] = '\0';
+
+ char *last_dot = strrchr(path, '.');
+ while (last_dot != NULL && last_dot[0])
+ {
+ char *next_slash = strchr(last_dot, '/');
+ if (next_slash != NULL)
+ {
+ *next_slash = '\0';
+ ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
+ ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
+ dsym_fspec.SetFile(path, false);
+ if (dsym_fspec.Exists() &&
+ FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
+ {
+ if (log)
+ {
+ log->Printf ("dSYM with matching UUID & arch found at %s", path);
+ }
+ return true;
+ }
+ else
+ {
+ *last_dot = '\0';
+ char *prev_slash = strrchr(path, '/');
+ if (prev_slash != NULL)
+ *prev_slash = '\0';
+ else
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return false;
+}
+
+FileSpec
+LocateExecutableSymbolFileDsym (const ModuleSpec &module_spec)
+{
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+ const UUID *uuid = module_spec.GetUUIDPtr();
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->GetArchitectureName() : "<NULL>",
+ (const void*)uuid);
+
+ FileSpec symbol_fspec;
+ ModuleSpec dsym_module_spec;
+ // First try and find the dSYM in the same directory as the executable or in
+ // an appropriate parent directory
+ if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false)
+ {
+ // We failed to easily find the dSYM above, so use DebugSymbols
+ LocateMacOSXFilesUsingDebugSymbols (module_spec, dsym_module_spec);
+ }
+ else
+ {
+ dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
+ }
+ return dsym_module_spec.GetSymbolFileSpec();
+}
+
+ModuleSpec
+Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
+{
+ ModuleSpec result;
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+ const UUID *uuid = module_spec.GetUUIDPtr();
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
+ arch ? arch->GetArchitectureName() : "<NULL>",
+ (const void*)uuid);
+
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ if (exec_fspec &&
+ ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ {
+ result.GetFileSpec() = exec_fspec;
+ }
+ else
+ {
+ LocateMacOSXFilesUsingDebugSymbols (module_spec, result);
+ }
+ return result;
+}
+
+FileSpec
+Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
+{
+ FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
+ if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists())
+ return symbol_file_spec;
+
+ const char *symbol_filename = symbol_file_spec.GetFilename().AsCString();
+ if (symbol_filename && symbol_filename[0])
+ {
+ FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
+
+ // Add module directory.
+ const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
+ debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
+
+ // Add current working directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
+
+#ifndef LLVM_ON_WIN32
+ // Add /usr/lib/debug directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
+#endif // LLVM_ON_WIN32
+
+ std::string uuid_str;
+ const UUID &module_uuid = module_spec.GetUUID();
+ if (module_uuid.IsValid())
+ {
+ // Some debug files are stored in the .build-id directory like this:
+ // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
+ uuid_str = module_uuid.GetAsString("");
+ uuid_str.insert (2, 1, '/');
+ uuid_str = uuid_str + ".debug";
+ }
+
+ size_t num_directories = debug_file_search_paths.GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx)
+ {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
+ dirspec.ResolvePath();
+ if (!dirspec.Exists() || !dirspec.IsDirectory())
+ continue;
+
+ std::vector<std::string> files;
+ std::string dirname = dirspec.GetPath();
+
+ files.push_back (dirname + "/" + symbol_filename);
+ files.push_back (dirname + "/.debug/" + symbol_filename);
+ files.push_back (dirname + "/.build-id/" + uuid_str);
+
+ // Some debug files may stored in the module directory like this:
+ // /usr/lib/debug/usr/lib/library.so.debug
+ if (!file_dir.IsEmpty())
+ files.push_back (dirname + file_dir.AsCString() + "/" + symbol_filename);
+
+ const uint32_t num_files = files.size();
+ for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
+ {
+ const std::string &filename = files[idx_file];
+ FileSpec file_spec (filename.c_str(), true);
+
+ if (llvm::sys::fs::equivalent (file_spec.GetPath(), module_spec.GetFileSpec().GetPath()))
+ continue;
+
+ if (file_spec.Exists())
+ {
+ lldb_private::ModuleSpecList specs;
+ const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
+ assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
+ if (num_specs == 1)
+ {
+ ModuleSpec mspec;
+ if (specs.GetModuleSpecAtIndex (0, mspec))
+ {
+ if (mspec.GetUUID() == module_uuid)
+ return file_spec;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return LocateExecutableSymbolFileDsym(module_spec);
+}
+
+#if !defined (__APPLE__)
+
+FileSpec
+Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch)
+{
+ // FIXME
+ return FileSpec();
+}
+
+bool
+Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
+{
+ // Fill in the module_spec.GetFileSpec() for the object file and/or the
+ // module_spec.GetSymbolFileSpec() for the debug symbols file.
+ return false;
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp
new file mode 100644
index 0000000..b23055e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/TCPSocket.cpp
@@ -0,0 +1,288 @@
+//===-- TcpSocket.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/TCPSocket.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Config.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+const int kDomain = AF_INET;
+const int kType = SOCK_STREAM;
+
+}
+
+TCPSocket::TCPSocket(NativeSocket socket, bool should_close)
+ : Socket(socket, ProtocolTcp, should_close)
+{
+
+}
+
+TCPSocket::TCPSocket(bool child_processes_inherit, Error &error)
+ : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, child_processes_inherit, error), true)
+{
+}
+
+
+// Return the port number that is being used by the socket.
+uint16_t
+TCPSocket::GetLocalPortNumber() const
+{
+ if (m_socket != kInvalidSocketValue)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+ }
+ return 0;
+}
+
+std::string
+TCPSocket::GetLocalIPAddress() const
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ if (m_socket != kInvalidSocketValue)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetIPAddress ();
+ }
+ return "";
+}
+
+uint16_t
+TCPSocket::GetRemotePortNumber() const
+{
+ if (m_socket != kInvalidSocketValue)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+ }
+ return 0;
+}
+
+std::string
+TCPSocket::GetRemoteIPAddress () const
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ if (m_socket != kInvalidSocketValue)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetIPAddress ();
+ }
+ return "";
+}
+
+Error
+TCPSocket::Connect(llvm::StringRef name)
+{
+ if (m_socket == kInvalidSocketValue)
+ return Error("Invalid socket");
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
+ if (log)
+ log->Printf ("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
+
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ 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;
+ sa.sin_port = htons (port);
+
+ int inet_pton_result = ::inet_pton (kDomain, host_str.c_str(), &sa.sin_addr);
+
+ if (inet_pton_result <= 0)
+ {
+ struct hostent *host_entry = gethostbyname (host_str.c_str());
+ if (host_entry)
+ host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
+ inet_pton_result = ::inet_pton (kDomain, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0)
+ {
+ if (inet_pton_result == -1)
+ SetLastError(error);
+ else
+ error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
+
+ return error;
+ }
+ }
+
+ if (-1 == ::connect (GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ SetLastError (error);
+ return error;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ SetOptionNoDelay();
+ error.Clear();
+ return error;
+}
+
+Error
+TCPSocket::Listen(llvm::StringRef name, int backlog)
+{
+ Error error;
+
+ // enable local address reuse
+ SetOptionReuseAddress();
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("TCPSocket::%s (%s)", __FUNCTION__, name.data());
+
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (name, host_str, port_str, port, &error))
+ return error;
+
+ SocketAddress bind_addr;
+
+ // Only bind to the loopback address if we are expecting a connection from
+ // localhost to avoid any firewall issues.
+ const bool bind_addr_success = (host_str == "127.0.0.1") ?
+ bind_addr.SetToLocalhost (kDomain, port) :
+ bind_addr.SetToAnyAddress (kDomain, port);
+
+ if (!bind_addr_success)
+ {
+ error.SetErrorString("Failed to bind port");
+ return error;
+ }
+
+ int err = ::bind (GetNativeSocket(), bind_addr, bind_addr.GetLength());
+ if (err != -1)
+ err = ::listen (GetNativeSocket(), backlog);
+
+ if (err == -1)
+ SetLastError (error);
+
+ return error;
+}
+
+Error
+TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&conn_socket)
+{
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ if (!DecodeHostAndPort(name, host_str, port_str, port, &error))
+ return error;
+
+ const sa_family_t family = kDomain;
+ const int socktype = kType;
+ const int protocol = IPPROTO_TCP;
+ SocketAddress listen_addr;
+ if (host_str.empty())
+ listen_addr.SetToLocalhost(family, port);
+ else if (host_str.compare("*") == 0)
+ listen_addr.SetToAnyAddress(family, port);
+ else
+ {
+ if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol))
+ {
+ error.SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str());
+ return error;
+ }
+ }
+
+ bool accept_connection = false;
+ std::unique_ptr<TCPSocket> accepted_socket;
+
+ // Loop until we are happy with our connection
+ while (!accept_connection)
+ {
+ struct sockaddr_in accept_addr;
+ ::memset (&accept_addr, 0, sizeof accept_addr);
+#if !(defined (__linux__) || defined(_WIN32))
+ accept_addr.sin_len = sizeof accept_addr;
+#endif
+ socklen_t accept_addr_len = sizeof accept_addr;
+
+ int sock = AcceptSocket (GetNativeSocket(),
+ (struct sockaddr *)&accept_addr,
+ &accept_addr_len,
+ child_processes_inherit,
+ error);
+
+ if (error.Fail())
+ break;
+
+ bool is_same_addr = true;
+#if !(defined(__linux__) || (defined(_WIN32)))
+ is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len);
+#endif
+ if (is_same_addr)
+ is_same_addr = (accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr);
+
+ if (is_same_addr || (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY))
+ {
+ accept_connection = true;
+ accepted_socket.reset(new TCPSocket(sock, true));
+ }
+ else
+ {
+ const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
+ const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
+ ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
+ accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
+ listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
+ accepted_socket.reset();
+ }
+ }
+
+ if (!accepted_socket)
+ return error;
+
+ // Keep our TCP packets coming without any delays.
+ accepted_socket->SetOptionNoDelay();
+ error.Clear();
+ conn_socket = accepted_socket.release();
+ return error;
+}
+
+int
+TCPSocket::SetOptionNoDelay()
+{
+ return SetOption (IPPROTO_TCP, TCP_NODELAY, 1);
+}
+
+int
+TCPSocket::SetOptionReuseAddress()
+{
+ return SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp b/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp
new file mode 100644
index 0000000..9f3abb7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp
@@ -0,0 +1,323 @@
+//===-- Terminal.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Terminal.h"
+#include "llvm/ADT/STLExtras.h"
+
+#include <fcntl.h>
+#include <signal.h>
+
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+#include <termios.h>
+#endif
+
+
+using namespace lldb_private;
+
+bool
+Terminal::IsATerminal () const
+{
+
+ return m_fd >= 0 && ::isatty (m_fd);
+}
+
+
+bool
+Terminal::SetEcho (bool enabled)
+{
+ if (FileDescriptorIsValid())
+ {
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (IsATerminal ())
+ {
+ struct termios fd_termios;
+ if (::tcgetattr(m_fd, &fd_termios) == 0)
+ {
+ bool set_corectly = false;
+ if (enabled)
+ {
+ if (fd_termios.c_lflag & ECHO)
+ set_corectly = true;
+ else
+ fd_termios.c_lflag |= ECHO;
+ }
+ else
+ {
+ if (fd_termios.c_lflag & ECHO)
+ fd_termios.c_lflag &= ~ECHO;
+ else
+ set_corectly = true;
+ }
+
+ if (set_corectly)
+ return true;
+ return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
+ }
+ }
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ }
+ return false;
+}
+
+bool
+Terminal::SetCanonical (bool enabled)
+{
+ if (FileDescriptorIsValid())
+ {
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (IsATerminal ())
+ {
+ struct termios fd_termios;
+ if (::tcgetattr(m_fd, &fd_termios) == 0)
+ {
+ bool set_corectly = false;
+ if (enabled)
+ {
+ if (fd_termios.c_lflag & ICANON)
+ set_corectly = true;
+ else
+ fd_termios.c_lflag |= ICANON;
+ }
+ else
+ {
+ if (fd_termios.c_lflag & ICANON)
+ fd_termios.c_lflag &= ~ICANON;
+ else
+ set_corectly = true;
+ }
+
+ if (set_corectly)
+ return true;
+ return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
+ }
+ }
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+TerminalState::TerminalState() :
+ m_tty(),
+ m_tflags(-1),
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ m_termios_ap(),
+#endif
+ m_process_group(-1)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TerminalState::~TerminalState()
+{
+}
+
+void
+TerminalState::Clear ()
+{
+ m_tty.Clear();
+ m_tflags = -1;
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ m_termios_ap.reset();
+#endif
+ m_process_group = -1;
+}
+
+//----------------------------------------------------------------------
+// Save the current state of the TTY for the file descriptor "fd"
+// and if "save_process_group" is true, attempt to save the process
+// group info for the TTY.
+//----------------------------------------------------------------------
+bool
+TerminalState::Save (int fd, bool save_process_group)
+{
+ m_tty.SetFileDescriptor(fd);
+ if (m_tty.IsATerminal())
+ {
+#ifndef LLDB_DISABLE_POSIX
+ m_tflags = ::fcntl (fd, F_GETFL, 0);
+#endif
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (m_termios_ap.get() == NULL)
+ m_termios_ap.reset (new struct termios);
+ int err = ::tcgetattr (fd, m_termios_ap.get());
+ if (err != 0)
+ m_termios_ap.reset();
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+#ifndef LLDB_DISABLE_POSIX
+ if (save_process_group)
+ m_process_group = ::tcgetpgrp (0);
+ else
+ m_process_group = -1;
+#endif
+ }
+ else
+ {
+ m_tty.Clear();
+ m_tflags = -1;
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ m_termios_ap.reset();
+#endif
+ m_process_group = -1;
+ }
+ return IsValid();
+}
+
+//----------------------------------------------------------------------
+// Restore the state of the TTY using the cached values from a
+// previous call to Save().
+//----------------------------------------------------------------------
+bool
+TerminalState::Restore () const
+{
+#ifndef LLDB_DISABLE_POSIX
+ if (IsValid())
+ {
+ const int fd = m_tty.GetFileDescriptor();
+ if (TFlagsIsValid())
+ fcntl (fd, F_SETFL, m_tflags);
+
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (TTYStateIsValid())
+ tcsetattr (fd, TCSANOW, m_termios_ap.get());
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+
+ if (ProcessGroupIsValid())
+ {
+ // Save the original signal handler.
+ void (*saved_sigttou_callback) (int) = NULL;
+ saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
+ // Set the process group
+ tcsetpgrp (fd, m_process_group);
+ // Restore the original signal handler.
+ signal (SIGTTOU, saved_sigttou_callback);
+ }
+ return true;
+ }
+#endif
+ return false;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Returns true if this object has valid saved TTY state settings
+// that can be used to restore a previous state.
+//----------------------------------------------------------------------
+bool
+TerminalState::IsValid() const
+{
+ return m_tty.FileDescriptorIsValid () && (TFlagsIsValid() || TTYStateIsValid());
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_tflags is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::TFlagsIsValid() const
+{
+ return m_tflags != -1;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_ttystate is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::TTYStateIsValid() const
+{
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ return m_termios_ap.get() != 0;
+#else
+ return false;
+#endif
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_process_group is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::ProcessGroupIsValid() const
+{
+ return static_cast<int32_t>(m_process_group) != -1;
+}
+
+//------------------------------------------------------------------
+// Constructor
+//------------------------------------------------------------------
+TerminalStateSwitcher::TerminalStateSwitcher () :
+ m_currentState(UINT32_MAX)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+TerminalStateSwitcher::~TerminalStateSwitcher ()
+{
+}
+
+//------------------------------------------------------------------
+// Returns the number of states that this switcher contains
+//------------------------------------------------------------------
+uint32_t
+TerminalStateSwitcher::GetNumberOfStates() const
+{
+ return llvm::array_lengthof(m_ttystates);
+}
+
+//------------------------------------------------------------------
+// Restore the state at index "idx".
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TerminalStateSwitcher::Restore (uint32_t idx) const
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx >= num_states)
+ return false;
+
+ // See if we already are in this state?
+ if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid())
+ return true;
+
+ // Set the state to match the index passed in and only update the
+ // current state if there are no errors.
+ if (m_ttystates[idx].Restore())
+ {
+ m_currentState = idx;
+ return true;
+ }
+
+ // We failed to set the state. The tty state was invalid or not
+ // initialized.
+ return false;
+}
+
+//------------------------------------------------------------------
+// Save the state at index "idx" for file descriptor "fd" and
+// save the process group if requested.
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TerminalStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group)
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx < num_states)
+ return m_ttystates[idx].Save(fd, save_process_group);
+ return false;
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp
new file mode 100644
index 0000000..7637014
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/ThisThread.cpp
@@ -0,0 +1,52 @@
+//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name, int max_length)
+{
+ std::string truncated_name(name.data());
+
+ // Thread names are coming in like '<lldb.comm.debugger.edit>' and
+ // '<lldb.comm.debugger.editline>'. So just chopping the end of the string
+ // off leads to a lot of similar named threads. Go through the thread name
+ // and search for the last dot and use that.
+
+ if (max_length > 0 && truncated_name.length() > static_cast<size_t>(max_length))
+ {
+ // First see if we can get lucky by removing any initial or final braces.
+ std::string::size_type begin = truncated_name.find_first_not_of("(<");
+ std::string::size_type end = truncated_name.find_last_not_of(")>.");
+ if (end - begin > static_cast<size_t>(max_length))
+ {
+ // We're still too long. Since this is a dotted component, use everything after the last
+ // dot, up to a maximum of |length| characters.
+ std::string::size_type last_dot = truncated_name.rfind('.');
+ if (last_dot != std::string::npos)
+ begin = last_dot + 1;
+
+ end = std::min(end, begin + max_length);
+ }
+
+ std::string::size_type count = end - begin + 1;
+ truncated_name = truncated_name.substr(begin, count);
+ }
+
+ SetName(truncated_name.c_str());
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp
new file mode 100644
index 0000000..c19a233
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/ThreadLauncher.cpp
@@ -0,0 +1,84 @@
+//===-- ThreadLauncher.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// lldb Includes
+#include "lldb/Core/Log.h"
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/ThisThread.h"
+#include "lldb/Host/ThreadLauncher.h"
+
+#if defined(_WIN32)
+#include "lldb/Host/windows/windows.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThread
+ThreadLauncher::LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function, lldb::thread_arg_t thread_arg, Error *error_ptr, size_t min_stack_byte_size)
+{
+ Error error;
+ if (error_ptr)
+ error_ptr->Clear();
+
+ // Host::ThreadCreateTrampoline will delete this pointer for us.
+ HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo(name.data(), thread_function, thread_arg);
+ lldb::thread_t thread;
+#ifdef _WIN32
+ thread =
+ (lldb::thread_t)::_beginthreadex(0, (unsigned)min_stack_byte_size, HostNativeThread::ThreadCreateTrampoline, info_ptr, 0, NULL);
+ if (thread == (lldb::thread_t)(-1L))
+ error.SetError(::GetLastError(), eErrorTypeWin32);
+#else
+
+
+ // ASAN instrumentation adds a lot of bookkeeping overhead on stack frames.
+#if __has_feature(address_sanitizer)
+ const size_t eight_megabytes = 8 * 1024 * 1024;
+ if (min_stack_byte_size < eight_megabytes)
+ {
+ min_stack_byte_size += eight_megabytes;
+ }
+#endif
+
+ pthread_attr_t *thread_attr_ptr = NULL;
+ pthread_attr_t thread_attr;
+ bool destroy_attr = false;
+ if (min_stack_byte_size > 0)
+ {
+ if (::pthread_attr_init (&thread_attr) == 0)
+ {
+ destroy_attr = true;
+ size_t default_min_stack_byte_size = 0;
+ if (::pthread_attr_getstacksize(&thread_attr, &default_min_stack_byte_size) == 0)
+ {
+ if (default_min_stack_byte_size < min_stack_byte_size)
+ {
+ if (::pthread_attr_setstacksize (&thread_attr, min_stack_byte_size) == 0)
+ thread_attr_ptr = &thread_attr;
+ }
+ }
+
+ }
+ }
+ int err = ::pthread_create(&thread, thread_attr_ptr, HostNativeThread::ThreadCreateTrampoline, info_ptr);
+
+ if (destroy_attr)
+ ::pthread_attr_destroy(&thread_attr);
+
+ error.SetError(err, eErrorTypePOSIX);
+#endif
+ if (error_ptr)
+ *error_ptr = error;
+ if (!error.Success())
+ thread = LLDB_INVALID_HOST_THREAD;
+
+ return HostThread(thread);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/TimeValue.cpp b/contrib/llvm/tools/lldb/source/Host/common/TimeValue.cpp
new file mode 100644
index 0000000..b471a3d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/TimeValue.cpp
@@ -0,0 +1,222 @@
+//===-- TimeValue.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/Config.h"
+
+// C Includes
+#include <stddef.h>
+#include <time.h>
+#include <cstring>
+
+#ifdef _MSC_VER
+#include "lldb/Host/windows/windows.h"
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// TimeValue constructor
+//----------------------------------------------------------------------
+TimeValue::TimeValue() :
+ m_nano_seconds (0)
+{
+}
+
+//----------------------------------------------------------------------
+// TimeValue copy constructor
+//----------------------------------------------------------------------
+TimeValue::TimeValue(const TimeValue& rhs) :
+ m_nano_seconds (rhs.m_nano_seconds)
+{
+}
+
+TimeValue::TimeValue(const struct timespec& ts) :
+ m_nano_seconds ((uint64_t) ts.tv_sec * NanoSecPerSec + ts.tv_nsec)
+{
+}
+
+TimeValue::TimeValue(uint32_t seconds, uint32_t nanos) :
+ m_nano_seconds((uint64_t) seconds * NanoSecPerSec + nanos)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TimeValue::~TimeValue()
+{
+}
+
+
+uint64_t
+TimeValue::GetAsNanoSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds;
+}
+
+uint64_t
+TimeValue::GetAsMicroSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds / NanoSecPerMicroSec;
+}
+
+uint64_t
+TimeValue::GetAsSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds / NanoSecPerSec;
+}
+
+
+
+struct timespec
+TimeValue::GetAsTimeSpec () const
+{
+ struct timespec ts;
+ ts.tv_sec = m_nano_seconds / NanoSecPerSec;
+ ts.tv_nsec = m_nano_seconds % NanoSecPerSec;
+ return ts;
+}
+
+void
+TimeValue::Clear ()
+{
+ m_nano_seconds = 0;
+}
+
+bool
+TimeValue::IsValid () const
+{
+ return m_nano_seconds != 0;
+}
+
+void
+TimeValue::OffsetWithSeconds (uint64_t sec)
+{
+ m_nano_seconds += sec * NanoSecPerSec;
+}
+
+void
+TimeValue::OffsetWithMicroSeconds (uint64_t usec)
+{
+ m_nano_seconds += usec * NanoSecPerMicroSec;
+}
+
+void
+TimeValue::OffsetWithNanoSeconds (uint64_t nsec)
+{
+ m_nano_seconds += nsec;
+}
+
+TimeValue
+TimeValue::Now()
+{
+ uint32_t seconds, nanoseconds;
+#if _MSC_VER
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ nanoseconds = st.wMilliseconds * 1000000;
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+
+ seconds = ((((uint64_t)ft.dwHighDateTime) << 32 | ft.dwLowDateTime) / 10000000) - 11644473600ULL;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ seconds = tv.tv_sec;
+ nanoseconds = tv.tv_usec * NanoSecPerMicroSec;
+#endif
+ TimeValue now(seconds, nanoseconds);
+ return now;
+}
+
+//----------------------------------------------------------------------
+// TimeValue assignment operator
+//----------------------------------------------------------------------
+const TimeValue&
+TimeValue::operator=(const TimeValue& rhs)
+{
+ m_nano_seconds = rhs.m_nano_seconds;
+ return *this;
+}
+
+void
+TimeValue::Dump (Stream *s, uint32_t width) const
+{
+ if (s == NULL)
+ return;
+
+#ifndef LLDB_DISABLE_POSIX
+ char time_buf[32];
+ time_t time = GetAsSecondsSinceJan1_1970();
+ char *time_cstr = ::ctime_r(&time, time_buf);
+ if (time_cstr)
+ {
+ char *newline = ::strpbrk(time_cstr, "\n\r");
+ if (newline)
+ *newline = '\0';
+ if (width > 0)
+ s->Printf("%-*s", width, time_cstr);
+ else
+ s->PutCString(time_cstr);
+ }
+ else if (width > 0)
+ s->Printf("%-*s", width, "");
+#endif
+}
+
+bool
+lldb_private::operator == (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() == rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator != (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() != rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator < (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() < rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator <= (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() <= rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator > (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() > rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator >= (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() >= rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+uint64_t
+lldb_private::operator - (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() - rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp
new file mode 100644
index 0000000..8297232
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/UDPSocket.cpp
@@ -0,0 +1,158 @@
+//===-- UdpSocket.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/common/UDPSocket.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Config.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#endif
+
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+const int kDomain = AF_INET;
+const int kType = SOCK_DGRAM;
+
+const Error kNotSupported("Not supported");
+
+}
+
+UDPSocket::UDPSocket(NativeSocket socket)
+ : Socket(socket, ProtocolUdp, true)
+{
+}
+
+UDPSocket::UDPSocket(bool child_processes_inherit, Error &error)
+ : UDPSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error))
+{
+}
+
+size_t
+UDPSocket::Send(const void *buf, const size_t num_bytes)
+{
+ return ::sendto (m_socket,
+ static_cast<const char*>(buf),
+ num_bytes,
+ 0,
+ m_send_sockaddr,
+ m_send_sockaddr.GetLength());
+}
+
+Error
+UDPSocket::Connect(llvm::StringRef name)
+{
+ return kNotSupported;
+}
+
+Error
+UDPSocket::Listen(llvm::StringRef name, int backlog)
+{
+ return kNotSupported;
+}
+
+Error
+UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ return kNotSupported;
+}
+
+Error
+UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket)
+{
+ std::unique_ptr<UDPSocket> final_send_socket;
+ std::unique_ptr<UDPSocket> final_recv_socket;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data());
+
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (name, host_str, port_str, port, &error))
+ return error;
+
+ // Setup the receiving end of the UDP connection on this localhost
+ // on port zero. After we bind to port zero we can read the port.
+ final_recv_socket.reset(new UDPSocket(child_processes_inherit, error));
+ if (error.Success())
+ {
+ // Socket was created, now lets bind to the requested port
+ SocketAddress addr;
+ addr.SetToAnyAddress (AF_INET, 0);
+
+ if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1)
+ {
+ // Bind failed...
+ SetLastError (error);
+ }
+ }
+
+ assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid()));
+ if (error.Fail())
+ return error;
+
+ // At this point we have setup the receive port, now we need to
+ // setup the UDP send socket
+
+ struct addrinfo hints;
+ struct addrinfo *service_info_list = nullptr;
+
+ ::memset (&hints, 0, sizeof(hints));
+ hints.ai_family = kDomain;
+ hints.ai_socktype = kType;
+ int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
+ if (err != 0)
+ {
+ error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
+ host_str.c_str(),
+ port_str.c_str(),
+ err,
+ gai_strerror(err));
+ return error;
+ }
+
+ for (struct addrinfo *service_info_ptr = service_info_list;
+ service_info_ptr != nullptr;
+ service_info_ptr = service_info_ptr->ai_next)
+ {
+ auto send_fd = CreateSocket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol,
+ child_processes_inherit,
+ error);
+ if (error.Success())
+ {
+ final_send_socket.reset(new UDPSocket(send_fd));
+ final_send_socket->m_send_sockaddr = service_info_ptr;
+ break;
+ }
+ else
+ continue;
+ }
+
+ :: freeaddrinfo (service_info_list);
+
+ if (!final_send_socket)
+ return error;
+
+ send_socket = final_send_socket.release();
+ recv_socket = final_recv_socket.release();
+ error.Clear();
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/common/XML.cpp b/contrib/llvm/tools/lldb/source/Host/common/XML.cpp
new file mode 100644
index 0000000..dc9cb0b
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/common/XML.cpp
@@ -0,0 +1,691 @@
+//===-- XML.cpp -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h> /* atof */
+
+#include "lldb/Host/XML.h"
+#include "lldb/Host/StringConvert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+#pragma mark -- XMLDocument
+
+XMLDocument::XMLDocument () :
+ m_document (nullptr)
+{
+}
+
+XMLDocument::~XMLDocument ()
+{
+ Clear();
+}
+
+void
+XMLDocument::Clear()
+{
+#if defined( LIBXML2_DEFINED )
+ if (m_document)
+ {
+ xmlDocPtr doc = m_document;
+ m_document = nullptr;
+ xmlFreeDoc(doc);
+ }
+#endif
+}
+
+bool
+XMLDocument::IsValid() const
+{
+ return m_document != nullptr;
+}
+
+void
+XMLDocument::ErrorCallback (void *ctx, const char *format, ...)
+{
+ XMLDocument *document = (XMLDocument *)ctx;
+ va_list args;
+ va_start (args, format);
+ document->m_errors.PrintfVarArg(format, args);
+ document->m_errors.EOL();
+ va_end (args);
+}
+
+bool
+XMLDocument::ParseFile (const char *path)
+{
+#if defined( LIBXML2_DEFINED )
+ Clear();
+ xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback );
+ m_document = xmlParseFile(path);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+#endif
+ return IsValid();
+}
+
+bool
+XMLDocument::ParseMemory (const char *xml, size_t xml_length, const char *url)
+{
+#if defined( LIBXML2_DEFINED )
+ Clear();
+ xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback );
+ m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+#endif
+ return IsValid();
+
+}
+
+XMLNode
+XMLDocument::GetRootElement(const char *required_name)
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ XMLNode root_node(xmlDocGetRootElement(m_document));
+ if (required_name)
+ {
+ llvm::StringRef actual_name = root_node.GetName();
+ if (actual_name == required_name)
+ return root_node;
+ }
+ else
+ {
+ return root_node;
+ }
+ }
+#endif
+ return XMLNode();
+}
+
+const std::string &
+XMLDocument::GetErrors() const
+{
+ return m_errors.GetString();
+}
+
+bool
+XMLDocument::XMLEnabled ()
+{
+#if defined( LIBXML2_DEFINED )
+ return true;
+#else
+ return false;
+#endif
+}
+
+#pragma mark -- XMLNode
+
+XMLNode::XMLNode() :
+ m_node(nullptr)
+{
+}
+
+XMLNode::XMLNode(XMLNodeImpl node) :
+ m_node(node)
+{
+}
+
+XMLNode::~XMLNode()
+{
+
+}
+
+void
+XMLNode::Clear()
+{
+ m_node = nullptr;
+}
+
+XMLNode
+XMLNode::GetParent() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return XMLNode(m_node->parent);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+XMLNode
+XMLNode::GetSibling() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return XMLNode(m_node->next);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+XMLNode
+XMLNode::GetChild () const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ return XMLNode(m_node->children);
+ else
+ return XMLNode();
+#else
+ return XMLNode();
+#endif
+
+}
+
+llvm::StringRef
+XMLNode::GetAttributeValue(const char *name, const char *fail_value) const
+{
+ const char *attr_value = NULL;
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name);
+ else
+ attr_value = fail_value;
+#else
+ attr_value = fail_value;
+#endif
+ if (attr_value)
+ return llvm::StringRef(attr_value);
+ else
+ return llvm::StringRef();
+}
+
+
+
+
+void
+XMLNode::ForEachChildNode (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ GetChild().ForEachSiblingNode(callback);
+#endif
+}
+
+void
+XMLNode::ForEachChildElement (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ XMLNode child = GetChild();
+ if (child)
+ child.ForEachSiblingElement(callback);
+#endif
+}
+
+void
+XMLNode::ForEachChildElementWithName (const char *name, NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+ XMLNode child = GetChild();
+ if (child)
+ child.ForEachSiblingElementWithName(name, callback);
+#endif
+}
+
+void
+XMLNode::ForEachAttribute (AttributeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ for (xmlAttrPtr attr = m_node->properties; attr != nullptr; attr=attr->next)
+ {
+ // check if name matches
+ if (attr->name)
+ {
+ // check child is a text node
+ xmlNodePtr child = attr->children;
+ if (child->type == XML_TEXT_NODE)
+ {
+ llvm::StringRef attr_value;
+ if (child->content)
+ attr_value = llvm::StringRef((const char *)child->content);
+ if (callback(llvm::StringRef((const char *)attr->name), attr_value) == false)
+ return;
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+void
+XMLNode::ForEachSiblingNode (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+void
+XMLNode::ForEachSiblingElement (NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ // we are looking for element nodes only
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+void
+XMLNode::ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // iterate through all siblings
+ for (xmlNodePtr node = m_node; node; node=node->next)
+ {
+ // we are looking for element nodes only
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+
+ // If name is nullptr, we take all nodes of type "t", else
+ // just the ones whose name matches
+ if (name)
+ {
+ if (strcmp((const char *)node->name, name) != 0)
+ continue; // Name mismatch, ignore this one
+ }
+ else
+ {
+ if (node->name)
+ continue; // nullptr name specified and this element has a name, ignore this one
+ }
+
+ if (callback(XMLNode(node)) == false)
+ return;
+ }
+ }
+#endif
+}
+
+llvm::StringRef
+XMLNode::GetName() const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ if (m_node->name)
+ return llvm::StringRef((const char *)m_node->name);
+ }
+#endif
+ return llvm::StringRef();
+}
+
+bool
+XMLNode::GetElementText (std::string &text) const
+{
+ text.clear();
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ bool success = false;
+ if (m_node->type == XML_ELEMENT_NODE)
+ {
+ // check child is a text node
+ for (xmlNodePtr node = m_node->children;
+ node != nullptr;
+ node = node->next)
+ {
+ if (node->type == XML_TEXT_NODE)
+ {
+ text.append((const char *)node->content);
+ success = true;
+ }
+ }
+ }
+ return success;
+ }
+#endif
+ return false;
+}
+
+
+bool
+XMLNode::GetElementTextAsUnsigned (uint64_t &value, uint64_t fail_value, int base) const
+{
+ bool success = false;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ std::string text;
+ if (GetElementText(text))
+ value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success);
+ }
+#endif
+ if (!success)
+ value = fail_value;
+ return success;
+}
+
+bool
+XMLNode::GetElementTextAsFloat (double &value, double fail_value) const
+{
+ bool success = false;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ std::string text;
+ if (GetElementText(text))
+ {
+ value = atof(text.c_str());
+ success = true;
+ }
+ }
+#endif
+ if (!success)
+ value = fail_value;
+ return success;
+}
+
+
+
+bool
+XMLNode::NameIs (const char *name) const
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ // In case we are looking for a nullptr name or an exact pointer match
+ if (m_node->name == (const xmlChar *)name)
+ return true;
+ if (m_node->name)
+ return strcmp((const char *)m_node->name, name) == 0;
+ }
+#endif
+ return false;
+}
+
+XMLNode
+XMLNode::FindFirstChildElementWithName (const char *name) const
+{
+ XMLNode result_node;
+
+#if defined( LIBXML2_DEFINED )
+ ForEachChildElementWithName(name, [&result_node, name](const XMLNode& node) -> bool {
+ result_node = node;
+ // Stop iterating, we found the node we wanted
+ return false;
+ });
+#endif
+
+ return result_node;
+}
+
+bool
+XMLNode::IsValid() const
+{
+ return m_node != nullptr;
+}
+
+bool
+XMLNode::IsElement () const
+{
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ return m_node->type == XML_ELEMENT_NODE;
+#endif
+ return false;
+}
+
+
+XMLNode
+XMLNode::GetElementForPath (const NamePath &path)
+{
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ if (path.empty())
+ return *this;
+ else
+ {
+ XMLNode node = FindFirstChildElementWithName(path[0].c_str());
+ const size_t n = path.size();
+ for (size_t i=1; node && i<n; ++i)
+ node = node.FindFirstChildElementWithName(path[i].c_str());
+ return node;
+ }
+ }
+#endif
+
+ return XMLNode();
+}
+
+
+#pragma mark -- ApplePropertyList
+
+ApplePropertyList::ApplePropertyList() :
+ m_xml_doc(),
+ m_dict_node()
+{
+
+}
+
+ApplePropertyList::ApplePropertyList (const char *path) :
+ m_xml_doc(),
+ m_dict_node()
+{
+ ParseFile(path);
+}
+
+ApplePropertyList::~ApplePropertyList()
+{
+}
+
+const std::string &
+ApplePropertyList::GetErrors() const
+{
+ return m_xml_doc.GetErrors();
+}
+
+
+bool
+ApplePropertyList::ParseFile (const char *path)
+{
+ if (m_xml_doc.ParseFile(path))
+ {
+ XMLNode plist = m_xml_doc.GetRootElement("plist");
+ if (plist)
+ {
+ plist.ForEachChildElementWithName("dict", [this](const XMLNode &dict) -> bool {
+ this->m_dict_node = dict;
+ return false; // Stop iterating
+ });
+ return (bool)m_dict_node;
+ }
+ }
+ return false;
+}
+
+bool
+ApplePropertyList::IsValid() const
+{
+ return (bool)m_dict_node;
+}
+
+bool
+ApplePropertyList::GetValueAsString (const char *key, std::string &value) const
+{
+ XMLNode value_node = GetValueNode (key);
+ if (value_node)
+ return ApplePropertyList::ExtractStringFromValueNode(value_node, value);
+ return false;
+}
+
+XMLNode
+ApplePropertyList::GetValueNode (const char *key) const
+{
+ XMLNode value_node;
+#if defined( LIBXML2_DEFINED )
+
+ if (IsValid())
+ {
+ m_dict_node.ForEachChildElementWithName("key", [key, &value_node](const XMLNode &key_node) -> bool {
+ std::string key_name;
+ if (key_node.GetElementText(key_name))
+ {
+ if (key_name.compare(key) == 0)
+ {
+ value_node = key_node.GetSibling();
+ while (value_node && !value_node.IsElement())
+ value_node = value_node.GetSibling();
+ return false; // Stop iterating
+ }
+ }
+ return true; // Keep iterating
+ });
+ }
+#endif
+ return value_node;
+}
+
+bool
+ApplePropertyList::ExtractStringFromValueNode (const XMLNode &node, std::string &value)
+{
+ value.clear();
+#if defined( LIBXML2_DEFINED )
+ if (node.IsValid())
+ {
+ llvm::StringRef element_name = node.GetName();
+ if (element_name == "true" || element_name == "false")
+ {
+ // The text value _is_ the element name itself...
+ value = element_name.str();
+ return true;
+ }
+ else if (element_name == "dict" || element_name == "array")
+ return false; // dictionaries and arrays have no text value, so we fail
+ else
+ return node.GetElementText(value);
+ }
+#endif
+ return false;
+}
+
+#if defined( LIBXML2_DEFINED )
+
+namespace {
+
+ StructuredData::ObjectSP
+ CreatePlistValue (XMLNode node)
+ {
+ llvm::StringRef element_name = node.GetName();
+ if (element_name == "array")
+ {
+ std::shared_ptr<StructuredData::Array> array_sp(new StructuredData::Array());
+ node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool {
+ array_sp->AddItem(CreatePlistValue(node));
+ return true; // Keep iterating through all child elements of the array
+ });
+ return array_sp;
+ }
+ else if (element_name == "dict")
+ {
+ XMLNode key_node;
+ std::shared_ptr<StructuredData::Dictionary> dict_sp(new StructuredData::Dictionary());
+ node.ForEachChildElement([&key_node, &dict_sp](const XMLNode &node) -> bool {
+ if (node.NameIs("key"))
+ {
+ // This is a "key" element node
+ key_node = node;
+ }
+ else
+ {
+ // This is a value node
+ if (key_node)
+ {
+ std::string key_name;
+ key_node.GetElementText(key_name);
+ dict_sp->AddItem(key_name, CreatePlistValue(node));
+ key_node.Clear();
+ }
+ }
+ return true; // Keep iterating through all child elements of the dictionary
+ });
+ return dict_sp;
+ }
+ else if (element_name == "real")
+ {
+ double value = 0.0;
+ node.GetElementTextAsFloat(value);
+ return StructuredData::ObjectSP(new StructuredData::Float(value));
+ }
+ else if (element_name == "integer")
+ {
+ uint64_t value = 0;
+ node.GetElementTextAsUnsigned(value, 0, 0);
+ return StructuredData::ObjectSP(new StructuredData::Integer(value));
+ }
+ else if ((element_name == "string") || (element_name == "data") || (element_name == "date"))
+ {
+ std::string text;
+ node.GetElementText(text);
+ return StructuredData::ObjectSP(new StructuredData::String(std::move(text)));
+ }
+ else if (element_name == "true")
+ {
+ return StructuredData::ObjectSP(new StructuredData::Boolean(true));
+ }
+ else if (element_name == "false")
+ {
+ return StructuredData::ObjectSP(new StructuredData::Boolean(false));
+ }
+ return StructuredData::ObjectSP(new StructuredData::Null());
+ }
+}
+#endif
+
+StructuredData::ObjectSP
+ApplePropertyList::GetStructuredData()
+{
+ StructuredData::ObjectSP root_sp;
+#if defined( LIBXML2_DEFINED )
+ if (IsValid())
+ {
+ return CreatePlistValue(m_dict_node);
+ }
+#endif
+ return root_sp;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
new file mode 100644
index 0000000..cf53cda
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
@@ -0,0 +1,283 @@
+//===-- source/Host/freebsd/Host.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+
+#include <sys/ptrace.h>
+#include <sys/exec.h>
+#include <machine/elf.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Platform.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/NameMatches.h"
+
+#include "llvm/Support/Host.h"
+
+extern "C" {
+ extern char **environ;
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char *v;
+ char **var = environ;
+ for (; var != NULL && *var != NULL; ++var)
+ {
+ v = strchr(*var, (int)'-');
+ if (v == NULL)
+ continue;
+ env.AppendString(v);
+ }
+ return env.GetSize();
+}
+
+static bool
+GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
+
+ char arg_data[8192];
+ size_t arg_data_size = sizeof(arg_data);
+ if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
+ {
+ DataExtractor data (arg_data, arg_data_size, endian::InlHostByteOrder(), sizeof(void *));
+ lldb::offset_t offset = 0;
+ const char *cstr;
+
+ cstr = data.GetCStr (&offset);
+ if (cstr)
+ {
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (!(match_info_ptr == NULL ||
+ NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName())))
+ return false;
+
+ Args &proc_args = process_info.GetArguments();
+ while (1)
+ {
+ const uint8_t *p = data.PeekData(offset, 1);
+ while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
+ {
+ ++offset;
+ p = data.PeekData(offset, 1);
+ }
+ if (p == NULL || offset >= arg_data_size)
+ return true;
+
+ cstr = data.GetCStr(&offset);
+ if (cstr)
+ proc_args.AppendArgument(cstr);
+ else
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ return true;
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool
+GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
+{
+ struct kinfo_proc proc_kinfo;
+ size_t proc_kinfo_size;
+
+ if (process_info.ProcessIDIsValid())
+ {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
+ (int)process_info.GetProcessID() };
+ proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
+ {
+ if (proc_kinfo_size > 0)
+ {
+ process_info.SetParentProcessID (proc_kinfo.ki_ppid);
+ process_info.SetUserID (proc_kinfo.ki_ruid);
+ process_info.SetGroupID (proc_kinfo.ki_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
+ if (proc_kinfo.ki_ngroups > 0)
+ process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID (UINT32_MAX);
+ process_info.SetGroupID (UINT32_MAX);
+ process_info.SetEffectiveUserID (UINT32_MAX);
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return false;
+}
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ size_t pid_data_size = 0;
+ if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize (estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const ::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (size_t i = 0; i < actual_pid_count; i++)
+ {
+ const struct kinfo_proc &kinfo = kinfos[i];
+ const bool kinfo_user_matches = (all_users ||
+ (kinfo.ki_ruid == our_uid) ||
+ // Special case, if lldb is being run as root we can attach to anything.
+ (our_uid == 0)
+ );
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ kinfo.ki_pid == our_pid || // Skip this process
+ kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.ki_flag & P_TRACED || // Being debugged?
+ kinfo.ki_flag & P_WEXIT) // Working on exiting
+ continue;
+
+ // Every thread is a process in FreeBSD, but all the threads of a single process
+ // have the same pid. Do not store the process info in the result list if a process
+ // with given identifier is already registered there.
+ bool already_registered = false;
+ for (uint32_t pi = 0;
+ !already_registered &&
+ (const int)kinfo.ki_numthreads > 1 &&
+ pi < (const uint32_t)process_infos.GetSize(); pi++)
+ already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
+
+ if (already_registered)
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (kinfo.ki_pid);
+ process_info.SetParentProcessID (kinfo.ki_ppid);
+ process_info.SetUserID (kinfo.ki_ruid);
+ process_info.SetGroupID (kinfo.ki_rgid);
+ process_info.SetEffectiveUserID (kinfo.ki_svuid);
+ process_info.SetEffectiveGroupID (kinfo.ki_svgid);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info) &&
+ GetFreeBSDProcessArgs (&match_info, process_info))
+ {
+ GetFreeBSDProcessCPUType (process_info);
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.SetProcessID(pid);
+
+ if (GetFreeBSDProcessArgs(NULL, process_info))
+ {
+ // should use libprocstat instead of going right into sysctl?
+ GetFreeBSDProcessCPUType(process_info);
+ GetFreeBSDProcessUserAndGroup(process_info);
+ return true;
+ }
+
+ process_info.Clear();
+ return false;
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_AUXV, 0 };
+ size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
+ DataBufferSP buf_sp;
+
+ std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(auxv_size, 0));
+
+ mib[3] = process->GetID();
+ if (::sysctl(mib, 4, buf_ap->GetBytes(), &auxv_size, NULL, 0) == 0) {
+ buf_sp.reset(buf_ap.release());
+ } else {
+ perror("sysctl failed on auxv");
+ }
+
+ return buf_sp;
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ return Error("unimplemented");
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp
new file mode 100644
index 0000000..d511093
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp
@@ -0,0 +1,91 @@
+//===-- HostInfoFreeBSD.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/freebsd/HostInfoFreeBSD.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+using namespace lldb_private;
+
+uint32_t
+HostInfoFreeBSD::GetMaxThreadNameLength()
+{
+ return 16;
+}
+
+bool
+HostInfoFreeBSD::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ if (uname(&un) < 0)
+ return false;
+
+ int status = sscanf(un.release, "%u.%u", &major, &minor);
+ return status == 2;
+}
+
+bool
+HostInfoFreeBSD::GetOSBuildString(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_OSREV};
+ char osrev_str[12];
+ uint32_t osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
+ {
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
+ s.assign(osrev_str);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoFreeBSD::GetOSKernelDescription(std::string &s)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(utsname));
+ s.clear();
+
+ if (uname(&un) < 0)
+ return false;
+
+ s.assign(un.version);
+
+ return true;
+}
+
+FileSpec
+HostInfoFreeBSD::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+ if (!g_program_filespec)
+ {
+ int exe_path_mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid()};
+ size_t exe_path_size;
+ if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0)
+ {
+ char *exe_path = new char[exe_path_size];
+ if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0)
+ g_program_filespec.SetFile(exe_path, false);
+ delete[] exe_path;
+ }
+ }
+ return g_program_filespec;
+} \ No newline at end of file
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp
new file mode 100644
index 0000000..a4302a9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/HostThreadFreeBSD.cpp
@@ -0,0 +1,79 @@
+//===-- HostThreadFreeBSD.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// lldb Includes
+#include "lldb/Host/freebsd/HostThreadFreeBSD.h"
+#include "lldb/Host/Host.h"
+
+// C includes
+#include <errno.h>
+#include <pthread.h>
+#if defined (__FreeBSD__)
+#include <pthread_np.h>
+#endif
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// C++ includes
+#include <string>
+
+using namespace lldb_private;
+
+HostThreadFreeBSD::HostThreadFreeBSD()
+{
+}
+
+HostThreadFreeBSD::HostThreadFreeBSD(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+void
+HostThreadFreeBSD::GetName(lldb::tid_t tid, llvm::SmallVectorImpl<char> &name)
+{
+ name.clear();
+ int pid = Host::GetCurrentProcessID();
+
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)pid};
+
+ while (1)
+ {
+ error = sysctl(ctl, 4, kp, &len, nullptr, 0);
+ if (kp == nullptr || (error != 0 && errno == ENOMEM))
+ {
+ // Add extra space in case threads are added before next call.
+ len += sizeof(*kp) + len / 10;
+ nkp = (struct kinfo_proc *)realloc(kp, len);
+ if (nkp == nullptr)
+ {
+ free(kp);
+ return;
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
+ for (size_t i = 0; i < len / sizeof(*kp); i++)
+ {
+ if (kp[i].ki_tid == (lwpid_t)tid)
+ {
+ name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
+ break;
+ }
+ }
+ free(kp);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp
new file mode 100644
index 0000000..e524fd4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/freebsd/ThisThread.cpp
@@ -0,0 +1,39 @@
+//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <pthread.h>
+#if defined (__FreeBSD__)
+#include <pthread_np.h>
+#endif
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+#if defined (__FreeBSD__) // Kfreebsd does not have a simple alternative
+ ::pthread_set_name_np(::pthread_self(), name.data());
+#endif
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+#if defined (__FreeBSD__)
+ HostNativeThread::GetName(::pthread_getthreadid_np(), name);
+#else
+// Kfreebsd
+ HostNativeThread::GetName((unsigned)pthread_self(), name);
+#endif
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
new file mode 100644
index 0000000..8742850
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/Host.cpp
@@ -0,0 +1,287 @@
+//===-- source/Host/netbsd/Host.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+
+#include <limits.h>
+
+#include <sys/ptrace.h>
+#include <sys/exec.h>
+#include <elf.h>
+#include <kvm.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Platform.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/NameMatches.h"
+
+#include "llvm/Support/Host.h"
+
+extern "C" {
+ extern char **environ;
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char *v;
+ char **var = environ;
+ for (; var != NULL && *var != NULL; ++var)
+ {
+ v = ::strchr(*var, (int)'-');
+ if (v == NULL)
+ continue;
+ env.AppendString(v);
+ }
+ return env.GetSize();
+}
+
+static bool
+GetNetBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info)
+{
+ if (!process_info.ProcessIDIsValid())
+ return false;
+
+ int pid = process_info.GetProcessID();
+
+ int mib[4] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV };
+
+ char arg_data[8192];
+ size_t arg_data_size = sizeof(arg_data);
+ if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) != 0)
+ return false;
+
+ DataExtractor data (arg_data, arg_data_size, endian::InlHostByteOrder(), sizeof(void *));
+ lldb::offset_t offset = 0;
+ const char *cstr;
+
+ cstr = data.GetCStr (&offset);
+ if (!cstr)
+ return false;
+
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (!(match_info_ptr == NULL ||
+ NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName())))
+ return false;
+
+ Args &proc_args = process_info.GetArguments();
+ while (1)
+ {
+ const uint8_t *p = data.PeekData(offset, 1);
+ while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
+ {
+ ++offset;
+ p = data.PeekData(offset, 1);
+ }
+ if (p == NULL || offset >= arg_data_size)
+ break;
+
+ cstr = data.GetCStr(&offset);
+ if (!cstr)
+ break;
+
+ proc_args.AppendArgument(cstr);
+ }
+
+ return true;
+}
+
+static bool
+GetNetBSDProcessCPUType (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
+ return true;
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool
+GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
+{
+ ::kvm_t *kdp;
+ char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
+
+ struct ::kinfo_proc2 *proc_kinfo;
+ const int pid = process_info.GetProcessID();
+ int nproc;
+
+ if (!process_info.ProcessIDIsValid())
+ goto error;
+
+ if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
+ goto error;
+
+ if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
+ sizeof(struct ::kinfo_proc2),
+ &nproc)) == NULL) {
+ ::kvm_close(kdp);
+ goto error;
+ }
+
+ if (nproc < 1) {
+ ::kvm_close(kdp); /* XXX: we don't check for error here */
+ goto error;
+ }
+
+ process_info.SetParentProcessID (proc_kinfo->p_ppid);
+ process_info.SetUserID (proc_kinfo->p_ruid);
+ process_info.SetGroupID (proc_kinfo->p_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo->p_uid);
+ process_info.SetEffectiveGroupID (proc_kinfo->p_gid);
+
+ ::kvm_close(kdp); /* XXX: we don't check for error here */
+
+ return true;
+
+error:
+ process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID (UINT32_MAX);
+ process_info.SetGroupID (UINT32_MAX);
+ process_info.SetEffectiveUserID (UINT32_MAX);
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return false;
+}
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ const ::pid_t our_pid = ::getpid();
+ const ::uid_t our_uid = ::getuid();
+
+ const bool all_users = match_info.GetMatchAllUsers() ||
+ // Special case, if lldb is being run as root we can attach to anything
+ (our_uid == 0);
+
+ kvm_t *kdp;
+ char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
+ if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
+ return 0;
+
+ struct ::kinfo_proc2 *proc_kinfo;
+ int nproc;
+ if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
+ sizeof(struct ::kinfo_proc2),
+ &nproc)) == NULL) {
+ ::kvm_close(kdp);
+ return 0;
+ }
+
+ for (int i = 0; i < nproc; i++) {
+ if (proc_kinfo[i].p_pid < 1)
+ continue; /* not valid */
+ /* Make sure the user is acceptable */
+ if (!all_users && proc_kinfo[i].p_ruid != our_uid)
+ continue;
+
+ if (proc_kinfo[i].p_pid == our_pid || // Skip this process
+ proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0)
+ proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad
+ proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
+ proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting
+ continue;
+
+
+ // Every thread is a process in NetBSD, but all the threads of a single
+ // process have the same pid. Do not store the process info in the
+ // result list if a process with given identifier is already registered
+ // there.
+ if (proc_kinfo[i].p_nlwps > 1) {
+ bool already_registered = false;
+ for (size_t pi = 0; pi < process_infos.GetSize(); pi++) {
+ if (process_infos.GetProcessIDAtIndex(pi) ==
+ proc_kinfo[i].p_pid) {
+ already_registered = true;
+ break;
+ }
+ }
+
+ if (already_registered)
+ continue;
+ }
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (proc_kinfo[i].p_pid);
+ process_info.SetParentProcessID (proc_kinfo[i].p_ppid);
+ process_info.SetUserID (proc_kinfo[i].p_ruid);
+ process_info.SetGroupID (proc_kinfo[i].p_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo[i].p_uid);
+ process_info.SetEffectiveGroupID (proc_kinfo[i].p_gid);
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info) &&
+ GetNetBSDProcessArgs (&match_info, process_info))
+ {
+ GetNetBSDProcessCPUType (process_info);
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+
+ kvm_close(kdp); /* XXX: we don't check for error here */
+
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.SetProcessID(pid);
+
+ if (GetNetBSDProcessArgs(NULL, process_info))
+ {
+ GetNetBSDProcessCPUType(process_info);
+ GetNetBSDProcessUserAndGroup(process_info);
+ return true;
+ }
+
+ process_info.Clear();
+ return false;
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return lldb::DataBufferSP();
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ return Error("unimplemented");
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp
new file mode 100644
index 0000000..aadda76
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/HostInfoNetBSD.cpp
@@ -0,0 +1,112 @@
+//===-- HostInfoNetBSD.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/netbsd/HostInfoNetBSD.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <inttypes.h>
+
+
+using namespace lldb_private;
+
+uint32_t
+HostInfoNetBSD::GetMaxThreadNameLength()
+{
+ return PTHREAD_MAX_NAMELEN_NP;
+}
+
+bool
+HostInfoNetBSD::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(un));
+ if (::uname(&un) < 0)
+ return false;
+
+ /* Accept versions like 7.99.21 and 6.1_STABLE */
+ int status = ::sscanf(un.release, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &update);
+ switch(status) {
+ case 0:
+ return false;
+ case 1:
+ minor = 0;
+ /* FALLTHROUGH */
+ case 2:
+ update = 0;
+ /* FALLTHROUGH */
+ case 3:
+ default:
+ return true;
+ }
+}
+
+bool
+HostInfoNetBSD::GetOSBuildString(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_OSREV};
+ char osrev_str[12];
+ int osrev = 0;
+ size_t osrev_len = sizeof(osrev);
+
+ if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
+ {
+ ::snprintf(osrev_str, sizeof(osrev_str), "%-10.10d", osrev);
+ s.assign(osrev_str);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoNetBSD::GetOSKernelDescription(std::string &s)
+{
+ struct utsname un;
+
+ ::memset(&un, 0, sizeof(un));
+ s.clear();
+
+ if (::uname(&un) < 0)
+ return false;
+
+ s.assign(un.version);
+
+ return true;
+}
+
+FileSpec
+HostInfoNetBSD::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+
+ if (!g_program_filespec)
+ {
+ ssize_t len;
+ static char buf[PATH_MAX];
+ char name[PATH_MAX];
+
+ ::snprintf(name, PATH_MAX, "/proc/%d/exe", ::getpid());
+ len = ::readlink(name, buf, PATH_MAX - 1);
+ if (len != -1)
+ {
+ buf[len] = '\0';
+ g_program_filespec.SetFile(buf, false);
+ }
+ }
+ return g_program_filespec;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp
new file mode 100644
index 0000000..06bc502
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/HostThreadNetBSD.cpp
@@ -0,0 +1,50 @@
+//===-- HostThreadNetBSD.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// lldb Includes
+#include "lldb/Host/netbsd/HostThreadNetBSD.h"
+#include "lldb/Host/Host.h"
+
+// C includes
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+// C++ includes
+#include <string>
+
+using namespace lldb_private;
+
+HostThreadNetBSD::HostThreadNetBSD()
+{
+}
+
+HostThreadNetBSD::HostThreadNetBSD(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+void
+HostThreadNetBSD::SetName(lldb::thread_t thread, llvm::StringRef &name)
+{
+ ::pthread_setname_np(thread, "%s", const_cast<char*>(name.data()));
+}
+
+void
+HostThreadNetBSD::GetName(lldb::thread_t thread, llvm::SmallVectorImpl<char> &name)
+{
+ char buf[PTHREAD_MAX_NAMELEN_NP];
+ ::pthread_getname_np(thread, buf, PTHREAD_MAX_NAMELEN_NP);
+
+ name.clear();
+ name.append(buf, buf + strlen(buf));
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp b/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp
new file mode 100644
index 0000000..dff5d9e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/netbsd/ThisThread.cpp
@@ -0,0 +1,30 @@
+//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/ThisThread.h"
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <pthread.h>
+#include <string.h>
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+ HostNativeThread::SetName(::pthread_self(), name);
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+ HostNativeThread::GetName(::pthread_self(), name);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
new file mode 100644
index 0000000..dbbd5a1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -0,0 +1,914 @@
+//===-- ConnectionFileDescriptorPosix.cpp -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/IOObject.h"
+#include "lldb/Host/SocketAddress.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/StringConvert.h"
+
+// C Includes
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#ifndef LLDB_DISABLE_POSIX
+#include <termios.h>
+#endif
+
+// C++ Includes
+#include <sstream>
+
+// Other libraries and framework includes
+#include "llvm/Support/ErrorHandling.h"
+#if defined(__APPLE__)
+#include "llvm/ADT/SmallVector.h"
+#endif
+// Project includes
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char* ConnectionFileDescriptor::LISTEN_SCHEME = "listen";
+const char* ConnectionFileDescriptor::ACCEPT_SCHEME = "accept";
+const char* ConnectionFileDescriptor::UNIX_ACCEPT_SCHEME = "unix-accept";
+const char* ConnectionFileDescriptor::CONNECT_SCHEME = "connect";
+const char* ConnectionFileDescriptor::TCP_CONNECT_SCHEME = "tcp-connect";
+const char* ConnectionFileDescriptor::UDP_SCHEME = "udp";
+const char* ConnectionFileDescriptor::UNIX_CONNECT_SCHEME = "unix-connect";
+const char* ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME = "unix-abstract-connect";
+const char* ConnectionFileDescriptor::FD_SCHEME = "fd";
+const char* ConnectionFileDescriptor::FILE_SCHEME = "file";
+
+namespace {
+
+const char*
+GetURLAddress(const char *url, const char *scheme)
+{
+ const auto prefix = std::string(scheme) + "://";
+ if (strstr(url, prefix.c_str()) != url)
+ return nullptr;
+
+ return url + prefix.size();
+}
+
+}
+
+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)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", static_cast<void *>(this));
+}
+
+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)
+{
+ 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);
+ 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)
+{
+ InitializeSocket(socket);
+}
+
+ConnectionFileDescriptor::~ConnectionFileDescriptor()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", static_cast<void *>(this));
+ Disconnect(NULL);
+ CloseCommandPipe();
+}
+
+void
+ConnectionFileDescriptor::OpenCommandPipe()
+{
+ CloseCommandPipe();
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ // Make the command file descriptor here:
+ Error result = m_pipe.CreateNew(m_child_processes_inherit);
+ if (!result.Success())
+ {
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe () - could not make pipe: %s", static_cast<void *>(this),
+ result.AsCString());
+ }
+ else
+ {
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::OpenCommandPipe() - success readfd=%d writefd=%d", static_cast<void *>(this),
+ m_pipe.GetReadFileDescriptor(), m_pipe.GetWriteFileDescriptor());
+ }
+}
+
+void
+ConnectionFileDescriptor::CloseCommandPipe()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::CloseCommandPipe()", static_cast<void *>(this));
+
+ m_pipe.Close();
+}
+
+bool
+ConnectionFileDescriptor::IsConnected() const
+{
+ return (m_read_sp && m_read_sp->IsValid()) || (m_write_sp && m_write_sp->IsValid());
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr)
+{
+ Mutex::Locker locker(m_mutex);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Connect (url = '%s')", static_cast<void *>(this), s);
+
+ OpenCommandPipe();
+
+ if (s && s[0])
+ {
+ const char *addr = nullptr;
+ if ((addr = GetURLAddress(s, LISTEN_SCHEME)))
+ {
+ // listen://HOST:PORT
+ return SocketListenAndAccept(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, ACCEPT_SCHEME)))
+ {
+ // unix://SOCKNAME
+ return NamedSocketAccept(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, UNIX_ACCEPT_SCHEME)))
+ {
+ // unix://SOCKNAME
+ return NamedSocketAccept(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, CONNECT_SCHEME)))
+ {
+ return ConnectTCP(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, TCP_CONNECT_SCHEME)))
+ {
+ return ConnectTCP(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, UDP_SCHEME)))
+ {
+ return ConnectUDP(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, UNIX_CONNECT_SCHEME)))
+ {
+ // unix-connect://SOCKNAME
+ return NamedSocketConnect(addr, error_ptr);
+ }
+ else if ((addr = GetURLAddress(s, UNIX_ABSTRACT_CONNECT_SCHEME)))
+ {
+ // unix-abstract-connect://SOCKNAME
+ return UnixAbstractSocketConnect(addr, error_ptr);
+ }
+#ifndef LLDB_DISABLE_POSIX
+ else if ((addr = GetURLAddress(s, FD_SCHEME)))
+ {
+ // Just passing a native file descriptor within this current process
+ // that is already opened (possibly from a service or other source).
+ bool success = false;
+ int fd = StringConvert::ToSInt32(addr, -1, 0, &success);
+
+ if (success)
+ {
+ // We have what looks to be a valid file descriptor, but we
+ // should make sure it is. We currently are doing this by trying to
+ // get the flags from the file descriptor and making sure it
+ // isn't a bad fd.
+ errno = 0;
+ int flags = ::fcntl(fd, F_GETFL, 0);
+ if (flags == -1 || errno == EBADF)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("stale file descriptor: %s", s);
+ m_read_sp.reset();
+ m_write_sp.reset();
+ return eConnectionStatusError;
+ }
+ else
+ {
+ // Don't take ownership of a file descriptor that gets passed
+ // to us since someone else opened the file descriptor and
+ // handed it to us.
+ // TODO: Since are using a URL to open connection we should
+ // eventually parse options using the web standard where we
+ // have "fd://123?opt1=value;opt2=value" and we can have an
+ // option be "owns=1" or "owns=0" or something like this to
+ // allow us to specify this. For now, we assume we must
+ // assume we don't own it.
+
+ std::unique_ptr<TCPSocket> tcp_socket;
+ tcp_socket.reset(new TCPSocket(fd, false));
+ // Try and get a socket option from this file descriptor to
+ // see if this is a socket and set m_is_socket accordingly.
+ int resuse;
+ bool is_socket = !!tcp_socket->GetOption(SOL_SOCKET, SO_REUSEADDR, resuse);
+ if (is_socket)
+ {
+ m_read_sp = std::move(tcp_socket);
+ m_write_sp = m_read_sp;
+ }
+ else
+ {
+ m_read_sp.reset(new File(fd, false));
+ m_write_sp.reset(new File(fd, false));
+ }
+ m_uri.assign(addr);
+ return eConnectionStatusSuccess;
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid file descriptor: \"%s\"", s);
+ m_read_sp.reset();
+ m_write_sp.reset();
+ return eConnectionStatusError;
+ }
+ else if ((addr = GetURLAddress(s, FILE_SCHEME)))
+ {
+ // file:///PATH
+ const char *path = addr;
+ int fd = -1;
+ do
+ {
+ fd = ::open(path, O_RDWR);
+ } while (fd == -1 && errno == EINTR);
+
+ if (fd == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ if (::isatty(fd))
+ {
+ // Set up serial terminal emulation
+ struct termios options;
+ ::tcgetattr(fd, &options);
+
+ // Set port speed to maximum
+ ::cfsetospeed(&options, B115200);
+ ::cfsetispeed(&options, B115200);
+
+ // Raw input, disable echo and signals
+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
+
+ // Make sure only one character is needed to return from a read
+ options.c_cc[VMIN] = 1;
+ options.c_cc[VTIME] = 0;
+
+ ::tcsetattr(fd, TCSANOW, &options);
+ }
+
+ int flags = ::fcntl(fd, F_GETFL, 0);
+ if (flags >= 0)
+ {
+ if ((flags & O_NONBLOCK) == 0)
+ {
+ flags |= O_NONBLOCK;
+ ::fcntl(fd, F_SETFL, flags);
+ }
+ }
+ m_read_sp.reset(new File(fd, true));
+ m_write_sp.reset(new File(fd, false));
+ return eConnectionStatusSuccess;
+ }
+#endif
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", s);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("invalid connect arguments");
+ return eConnectionStatusError;
+}
+
+bool
+ConnectionFileDescriptor::InterruptRead()
+{
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write("i", 1, bytes_written);
+ return result.Success();
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Disconnect(Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Disconnect ()", static_cast<void *>(this));
+
+ ConnectionStatus status = eConnectionStatusSuccess;
+
+ if (!IsConnected())
+ {
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", static_cast<void *>(this));
+ return eConnectionStatusSuccess;
+ }
+
+ if (m_read_sp && m_read_sp->IsValid() && m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
+ static_cast<Socket &>(*m_read_sp).PreDisconnect();
+
+ // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
+ // because somebody is doing a blocking read on our file descriptor. If that's the case,
+ // then send the "q" char to the command file channel so the read will wake up and the connection
+ // will then know to shut down.
+
+ m_shutting_down = true;
+
+ Mutex::Locker locker;
+ bool got_lock = locker.TryLock(m_mutex);
+
+ if (!got_lock)
+ {
+ if (m_pipe.CanWrite())
+ {
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write("q", 1, bytes_written);
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, sent 'q' to %d, error = '%s'.",
+ static_cast<void *>(this), m_pipe.GetWriteFileDescriptor(), result.AsCString());
+ }
+ else if (log)
+ {
+ log->Printf("%p ConnectionFileDescriptor::Disconnect(): Couldn't get the lock, but no command pipe is available.",
+ static_cast<void *>(this));
+ }
+ locker.Lock(m_mutex);
+ }
+
+ Error error = m_read_sp->Close();
+ Error error2 = m_write_sp->Close();
+ if (error.Fail() || error2.Fail())
+ status = eConnectionStatusError;
+ if (error_ptr)
+ *error_ptr = error.Fail() ? error : error2;
+
+ // Close any pipes we were using for async interrupts
+ m_pipe.Close();
+
+ m_uri.clear();
+ m_shutting_down = false;
+ return status;
+}
+
+size_t
+ConnectionFileDescriptor::Read(void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+
+ Mutex::Locker locker;
+ bool got_lock = locker.TryLock(m_mutex);
+ if (!got_lock)
+ {
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Read () failed to get the connection lock.", static_cast<void *>(this));
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to get the connection lock for read.");
+
+ status = eConnectionStatusTimedOut;
+ return 0;
+ }
+
+ if (m_shutting_down)
+ {
+ status = eConnectionStatusError;
+ return 0;
+ }
+
+ status = BytesAvailable(timeout_usec, error_ptr);
+ if (status != eConnectionStatusSuccess)
+ return 0;
+
+ Error error;
+ size_t bytes_read = dst_len;
+ error = m_read_sp->Read(dst, bytes_read);
+
+ if (log)
+ {
+ log->Printf("%p ConnectionFileDescriptor::Read() fd = %" PRIu64 ", dst = %p, dst_len = %" PRIu64 ") => %" PRIu64 ", error = %s",
+ static_cast<void *>(this), static_cast<uint64_t>(m_read_sp->GetWaitableHandle()), static_cast<void *>(dst),
+ static_cast<uint64_t>(dst_len), static_cast<uint64_t>(bytes_read), error.AsCString());
+ }
+
+ if (bytes_read == 0)
+ {
+ error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
+ status = eConnectionStatusEndOfFile;
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ uint32_t error_value = error.GetError();
+ switch (error_value)
+ {
+ case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
+ if (m_read_sp->GetFdType() == IOObject::eFDTypeSocket)
+ status = eConnectionStatusTimedOut;
+ else
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case EFAULT: // Buf points outside the allocated address space.
+ case EINTR: // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
+ case EINVAL: // The pointer associated with fildes was negative.
+ case EIO: // An I/O error occurred while reading from the file system.
+ // The process group is orphaned.
+ // The file is a regular file, nbyte is greater than 0,
+ // the starting position is before the end-of-file, and
+ // the starting position is greater than or equal to the
+ // offset maximum established for the open file
+ // descriptor associated with fildes.
+ case EISDIR: // An attempt is made to read a directory.
+ case ENOBUFS: // An attempt to allocate a memory buffer fails.
+ case ENOMEM: // Insufficient memory is available.
+ status = eConnectionStatusError;
+ break; // Break to close....
+
+ case ENOENT: // no such file or directory
+ case EBADF: // fildes is not a valid file or socket descriptor open for reading.
+ case ENXIO: // An action is requested of a device that does not exist..
+ // A requested action cannot be performed by the device.
+ case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
+ status = eConnectionStatusTimedOut;
+ return 0;
+
+ default:
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Read (), unexpected error: %s", static_cast<void *>(this),
+ strerror(error_value));
+ status = eConnectionStatusError;
+ break; // Break to close....
+ }
+
+ return 0;
+ }
+ return bytes_read;
+}
+
+size_t
+ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this),
+ static_cast<const void *>(src), static_cast<uint64_t>(src_len));
+
+ if (!IsConnected())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+
+ Error error;
+
+ size_t bytes_sent = src_len;
+ error = m_write_sp->Write(src, bytes_sent);
+
+ if (log)
+ {
+ log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
+ static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src),
+ static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EAGAIN:
+ case EINTR:
+ status = eConnectionStatusSuccess;
+ return 0;
+
+ case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
+ case ENOTCONN: // A read is attempted on an unconnected socket.
+ status = eConnectionStatusLostConnection;
+ break; // Break to close....
+
+ default:
+ status = eConnectionStatusError;
+ break; // Break to close....
+ }
+
+ return 0;
+ }
+
+ status = eConnectionStatusSuccess;
+ return bytes_sent;
+}
+
+std::string
+ConnectionFileDescriptor::GetURI()
+{
+ return m_uri;
+}
+
+// This ConnectionFileDescriptor::BytesAvailable() uses select().
+//
+// PROS:
+// - select is consistent across most unix platforms
+// - The Apple specific version allows for unlimited fds in the fd_sets by
+// setting the _DARWIN_UNLIMITED_SELECT define prior to including the
+// required header files.
+// CONS:
+// - on non-Apple platforms, only supports file descriptors up to FD_SETSIZE.
+// This implementation will assert if it runs into that hard limit to let
+// users know that another ConnectionFileDescriptor::BytesAvailable() should
+// be used or a new version of ConnectionFileDescriptor::BytesAvailable()
+// should be written for the system that is running into the limitations.
+
+#if defined(__APPLE__)
+#define FD_SET_DATA(fds) fds.data()
+#else
+#define FD_SET_DATA(fds) &fds
+#endif
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable(uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", static_cast<void *>(this), timeout_usec);
+
+ struct timeval *tv_ptr;
+ struct timeval tv;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Inifinite wait...
+ tv_ptr = nullptr;
+ }
+ else
+ {
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds(timeout_usec);
+ tv.tv_sec = time_value.seconds();
+ tv.tv_usec = time_value.microseconds();
+ tv_ptr = &tv;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
+ const int pipe_fd = m_pipe.GetReadFileDescriptor();
+
+ if (handle != IOObject::kInvalidHandleValue)
+ {
+#if defined(_MSC_VER)
+ // select() won't accept pipes on Windows. The entire Windows codepath needs to be
+ // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
+ // this will allow ::select() to not return an error.
+ const bool have_pipe_fd = false;
+#else
+ const bool have_pipe_fd = pipe_fd >= 0;
+#if !defined(__APPLE__)
+ assert(handle < FD_SETSIZE);
+ if (have_pipe_fd)
+ assert(pipe_fd < FD_SETSIZE);
+#endif
+#endif
+ while (handle == m_read_sp->GetWaitableHandle())
+ {
+ const int nfds = std::max<int>(handle, pipe_fd) + 1;
+#if defined(__APPLE__)
+ llvm::SmallVector<fd_set, 1> read_fds;
+ read_fds.resize((nfds / FD_SETSIZE) + 1);
+ for (size_t i = 0; i < read_fds.size(); ++i)
+ FD_ZERO(&read_fds[i]);
+// FD_SET doesn't bounds check, it just happily walks off the end
+// but we have taken care of making the extra storage with our
+// SmallVector of fd_set objects
+#else
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+#endif
+ FD_SET(handle, FD_SET_DATA(read_fds));
+ if (have_pipe_fd)
+ FD_SET(pipe_fd, FD_SET_DATA(read_fds));
+
+ Error error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf(
+ "%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr));
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
+ static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr));
+ }
+
+ const int num_set_fds = ::select(nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) "
+ "=> %d, error = %s",
+ static_cast<void *>(this), nfds, handle, pipe_fd, static_cast<void *>(tv_ptr), num_set_fds,
+ error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => "
+ "%d, error = %s",
+ static_cast<void *>(this), nfds, handle, static_cast<void *>(tv_ptr), num_set_fds, error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
+ return eConnectionStatusSuccess;
+ if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
+ {
+ // There is an interrupt or exit command in the command pipe
+ // Read the data from that pipe:
+ char buffer[1];
+
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read(pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+
+ switch (buffer[0])
+ {
+ case 'q':
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() "
+ "got data: %c from the command channel.",
+ static_cast<void *>(this), buffer[0]);
+ return eConnectionStatusEndOfFile;
+ case 'i':
+ // Interrupt the current read
+ return eConnectionStatusInterrupted;
+ }
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *error_ptr)
+{
+ Socket *socket = nullptr;
+ Error error = Socket::UnixDomainAccept(socket_name, m_child_processes_inherit, socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ if (error.Fail())
+ {
+ return eConnectionStatusError;
+ }
+ m_uri.assign(socket_name);
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *error_ptr)
+{
+ Socket *socket = nullptr;
+ Error error = Socket::UnixDomainConnect(socket_name, m_child_processes_inherit, socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ if (error.Fail())
+ {
+ return eConnectionStatusError;
+ }
+ m_uri.assign(socket_name);
+ return eConnectionStatusSuccess;
+}
+
+lldb::ConnectionStatus
+ConnectionFileDescriptor::UnixAbstractSocketConnect(const char *socket_name, Error *error_ptr)
+{
+ Socket *socket = nullptr;
+ Error error = Socket::UnixAbstractConnect(socket_name, m_child_processes_inherit, socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ if (error.Fail())
+ {
+ return eConnectionStatusError;
+ }
+ m_uri.assign(socket_name);
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr)
+{
+ m_port_predicate.SetValue(0, eBroadcastNever);
+
+ Socket *socket = nullptr;
+ m_waiting_for_accept = true;
+ Error error = Socket::TcpListen(s, m_child_processes_inherit, socket, &m_port_predicate);
+ if (error_ptr)
+ *error_ptr = error;
+ if (error.Fail())
+ return eConnectionStatusError;
+
+ std::unique_ptr<Socket> listening_socket_up;
+
+ listening_socket_up.reset(socket);
+ socket = nullptr;
+ error = listening_socket_up->Accept(s, m_child_processes_inherit, socket);
+ listening_socket_up.reset();
+ if (error_ptr)
+ *error_ptr = error;
+ if (error.Fail())
+ return eConnectionStatusError;
+
+ InitializeSocket(socket);
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr)
+{
+ Socket *socket = nullptr;
+ Error error = Socket::TcpConnect(s, m_child_processes_inherit, socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ if (error.Fail())
+ {
+ return eConnectionStatusError;
+ }
+ m_uri.assign(s);
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr)
+{
+ Socket *send_socket = nullptr;
+ Socket *recv_socket = nullptr;
+ Error error = Socket::UdpConnect(s, m_child_processes_inherit, send_socket, recv_socket);
+ if (error_ptr)
+ *error_ptr = error;
+ m_write_sp.reset(send_socket);
+ m_read_sp.reset(recv_socket);
+ if (error.Fail())
+ {
+ return eConnectionStatusError;
+ }
+ m_uri.assign(s);
+ return eConnectionStatusSuccess;
+}
+
+uint16_t
+ConnectionFileDescriptor::GetListeningPort(uint32_t timeout_sec)
+{
+ uint16_t bound_port = 0;
+ if (timeout_sec == UINT32_MAX)
+ m_port_predicate.WaitForValueNotEqualTo(0, bound_port);
+ else
+ {
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds(timeout_sec);
+ m_port_predicate.WaitForValueNotEqualTo(0, bound_port, &timeout);
+ }
+ return bound_port;
+}
+
+bool
+ConnectionFileDescriptor::GetChildProcessesInherit() const
+{
+ return m_child_processes_inherit;
+}
+
+void
+ConnectionFileDescriptor::SetChildProcessesInherit(bool child_processes_inherit)
+{
+ m_child_processes_inherit = child_processes_inherit;
+}
+
+void
+ConnectionFileDescriptor::InitializeSocket(Socket* socket)
+{
+ assert(socket->GetSocketProtocol() == Socket::ProtocolTcp);
+ TCPSocket* tcp_socket = static_cast<TCPSocket*>(socket);
+
+ m_write_sp.reset(socket);
+ m_read_sp = m_write_sp;
+ StreamString strm;
+ strm.Printf("connect://%s:%u",tcp_socket->GetRemoteIPAddress().c_str(), tcp_socket->GetRemotePortNumber());
+ m_uri.swap(strm.GetString());
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp
new file mode 100644
index 0000000..b4427e3
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/DomainSocket.cpp
@@ -0,0 +1,133 @@
+//===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/DomainSocket.h"
+
+#include "lldb/Host/FileSystem.h"
+
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+using namespace lldb;
+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))
+#endif
+#endif // #ifdef __ANDROID__
+
+namespace {
+
+const int kDomain = AF_UNIX;
+const int kType = SOCK_STREAM;
+
+bool SetSockAddr(llvm::StringRef name,
+ const size_t name_offset,
+ sockaddr_un* saddr_un,
+ socklen_t& saddr_un_len)
+{
+ if (name.size() + name_offset > sizeof(saddr_un->sun_path))
+ return false;
+
+ memset(saddr_un, 0, sizeof(*saddr_un));
+ saddr_un->sun_family = kDomain;
+
+ memcpy(saddr_un->sun_path + name_offset, name.data(), name.size());
+
+ // For domain sockets we can use SUN_LEN in order to calculate size of
+ // sockaddr_un, but for abstract sockets we have to calculate size manually
+ // because of leading null symbol.
+ if (name_offset == 0)
+ saddr_un_len = SUN_LEN(saddr_un);
+ else
+ saddr_un_len = offsetof(struct sockaddr_un, sun_path) + name_offset + name.size();
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ saddr_un->sun_len = saddr_un_len;
+#endif
+
+ return true;
+}
+
+}
+
+DomainSocket::DomainSocket(NativeSocket socket)
+ : Socket(socket, ProtocolUnixDomain, true)
+{
+}
+
+DomainSocket::DomainSocket(bool child_processes_inherit, Error &error)
+ : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error))
+{
+}
+
+DomainSocket::DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error)
+ : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), protocol, true)
+{
+}
+
+Error
+DomainSocket::Connect(llvm::StringRef name)
+{
+ sockaddr_un saddr_un;
+ socklen_t saddr_un_len;
+ if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
+ return Error("Failed to set socket address");
+
+ Error error;
+ if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) < 0)
+ SetLastError (error);
+
+ return error;
+}
+
+Error
+DomainSocket::Listen(llvm::StringRef name, int backlog)
+{
+ sockaddr_un saddr_un;
+ socklen_t saddr_un_len;
+ if (!SetSockAddr(name, GetNameOffset(), &saddr_un, saddr_un_len))
+ return Error("Failed to set socket address");
+
+ DeleteSocketFile(name);
+
+ Error error;
+ if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, saddr_un_len) == 0)
+ if (::listen(GetNativeSocket(), backlog) == 0)
+ return error;
+
+ SetLastError(error);
+ return error;
+}
+
+Error
+DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
+{
+ Error error;
+ auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error);
+ if (error.Success())
+ socket = new DomainSocket(conn_fd);
+
+ return error;
+}
+
+size_t
+DomainSocket::GetNameOffset() const
+{
+ return 0;
+}
+
+void
+DomainSocket::DeleteSocketFile(llvm::StringRef name)
+{
+ FileSystem::Unlink(FileSpec{name, true});
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp b/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp
new file mode 100644
index 0000000..1f2e7db
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/FileSystem.cpp
@@ -0,0 +1,299 @@
+//===-- FileSystem.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/FileSystem.h"
+
+// C includes
+#include <dirent.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef __linux__
+#include <sys/statfs.h>
+#include <sys/mount.h>
+#include <linux/magic.h>
+#endif
+#if defined(__NetBSD__)
+#include <sys/statvfs.h>
+#endif
+
+// lldb Includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+FileSystem::DEV_NULL = "/dev/null";
+
+FileSpec::PathSyntax
+FileSystem::GetNativePathSyntax()
+{
+ return FileSpec::ePathSyntaxPosix;
+}
+
+Error
+FileSystem::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions)
+{
+ if (file_spec)
+ {
+ Error error;
+ if (::mkdir(file_spec.GetCString(), file_permissions) == -1)
+ {
+ error.SetErrorToErrno();
+ errno = 0;
+ 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();
+ return error;
+ }
+ }
+ case EEXIST:
+ {
+ if (file_spec.IsDirectory())
+ return Error{}; // It is a directory and it already exists
+ }
+ }
+ }
+ return error;
+ }
+ return Error{"empty path"};
+}
+
+Error
+FileSystem::DeleteDirectory(const FileSpec &file_spec, bool recurse)
+{
+ Error error;
+ if (file_spec)
+ {
+ if (recurse)
+ {
+ // Save all sub directories in a list so we don't recursively call this function
+ // and possibly run out of file descriptors if the directory is too deep.
+ std::vector<FileSpec> sub_directories;
+
+ FileSpec::ForEachItemInDirectory (file_spec.GetCString(), [&error, &sub_directories](FileSpec::FileType file_type, const FileSpec &spec) -> FileSpec::EnumerateDirectoryResult {
+ if (file_type == FileSpec::eFileTypeDirectory)
+ {
+ // Save all directorires and process them after iterating through this directory
+ sub_directories.push_back(spec);
+ }
+ else
+ {
+ // Update sub_spec to point to the current file and delete it
+ error = FileSystem::Unlink(spec);
+ }
+ // If anything went wrong, stop iterating, else process the next file
+ if (error.Fail())
+ return FileSpec::eEnumerateDirectoryResultQuit;
+ else
+ return FileSpec::eEnumerateDirectoryResultNext;
+ });
+
+ if (error.Success())
+ {
+ // Now delete all sub directories with separate calls that aren't
+ // recursively calling into this function _while_ this function is
+ // iterating through the current directory.
+ for (const auto &sub_directory : sub_directories)
+ {
+ error = DeleteDirectory(sub_directory, recurse);
+ if (error.Fail())
+ break;
+ }
+ }
+ }
+
+ if (error.Success())
+ {
+ if (::rmdir(file_spec.GetCString()) != 0)
+ error.SetErrorToErrno();
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty path");
+ }
+ return error;
+}
+
+Error
+FileSystem::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions)
+{
+ Error error;
+ struct stat file_stats;
+ if (::stat(file_spec.GetCString(), &file_stats) == 0)
+ {
+ // The bits in "st_mode" currently match the definitions
+ // for the file mode bits in unix.
+ file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ else
+ {
+ error.SetErrorToErrno();
+ }
+ return error;
+}
+
+Error
+FileSystem::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions)
+{
+ Error error;
+ if (::chmod(file_spec.GetCString(), file_permissions) != 0)
+ error.SetErrorToErrno();
+ return error;
+}
+
+lldb::user_id_t
+FileSystem::GetFileSize(const FileSpec &file_spec)
+{
+ return file_spec.GetByteSize();
+}
+
+bool
+FileSystem::GetFileExists(const FileSpec &file_spec)
+{
+ return file_spec.Exists();
+}
+
+Error
+FileSystem::Hardlink(const FileSpec &src, const FileSpec &dst)
+{
+ Error error;
+ if (::link(dst.GetCString(), src.GetCString()) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+int
+FileSystem::GetHardlinkCount(const FileSpec &file_spec)
+{
+ struct stat file_stat;
+ if (::stat(file_spec.GetCString(), &file_stat) == 0)
+ return file_stat.st_nlink;
+
+ return -1;
+}
+
+Error
+FileSystem::Symlink(const FileSpec &src, const FileSpec &dst)
+{
+ Error error;
+ if (::symlink(dst.GetCString(), src.GetCString()) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Unlink(const FileSpec &file_spec)
+{
+ Error error;
+ if (::unlink(file_spec.GetCString()) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Readlink(const FileSpec &src, FileSpec &dst)
+{
+ Error error;
+ char buf[PATH_MAX];
+ ssize_t count = ::readlink(src.GetCString(), buf, sizeof(buf) - 1);
+ if (count < 0)
+ error.SetErrorToErrno();
+ else
+ {
+ buf[count] = '\0'; // Success
+ dst.SetFile(buf, false);
+ }
+ return error;
+}
+
+Error
+FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst)
+{
+ char resolved_path[PATH_MAX];
+ if (!src.GetPath (resolved_path, sizeof (resolved_path)))
+ {
+ return Error("Couldn't get the canonical path for %s", src.GetCString());
+ }
+
+ char real_path[PATH_MAX + 1];
+ if (realpath(resolved_path, real_path) == nullptr)
+ {
+ Error err;
+ err.SetErrorToErrno();
+ return err;
+ }
+
+ dst = FileSpec(real_path, false);
+
+ return Error();
+}
+
+#if defined(__NetBSD__)
+static bool IsLocal(const struct statvfs& info)
+{
+ return (info.f_flag & MNT_LOCAL) != 0;
+}
+#else
+static bool IsLocal(const struct statfs& info)
+{
+#ifdef __linux__
+ #define CIFS_MAGIC_NUMBER 0xFF534D42
+ switch ((uint32_t)info.f_type)
+ {
+ case NFS_SUPER_MAGIC:
+ case SMB_SUPER_MAGIC:
+ case CIFS_MAGIC_NUMBER:
+ return false;
+ default:
+ return true;
+ }
+#else
+ return (info.f_flags & MNT_LOCAL) != 0;
+#endif
+}
+#endif
+
+#if defined(__NetBSD__)
+bool
+FileSystem::IsLocal(const FileSpec &spec)
+{
+ struct statvfs statfs_info;
+ std::string path (spec.GetPath());
+ if (statvfs(path.c_str(), &statfs_info) == 0)
+ return ::IsLocal(statfs_info);
+ return false;
+}
+#else
+bool
+FileSystem::IsLocal(const FileSpec &spec)
+{
+ struct statfs statfs_info;
+ std::string path (spec.GetPath());
+ if (statfs(path.c_str(), &statfs_info) == 0)
+ return ::IsLocal(statfs_info);
+ return false;
+}
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp
new file mode 100644
index 0000000..cfdbf56
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostInfoPosix.cpp
@@ -0,0 +1,244 @@
+//===-- HostInfoPosix.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if !defined(LLDB_DISABLE_PYTHON)
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
+#endif
+
+#include "lldb/Core/Log.h"
+#include "lldb/Host/posix/HostInfoPosix.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <grp.h>
+#include <limits.h>
+#include <mutex>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+using namespace lldb_private;
+
+size_t
+HostInfoPosix::GetPageSize()
+{
+ return ::getpagesize();
+}
+
+bool
+HostInfoPosix::GetHostname(std::string &s)
+{
+ char hostname[PATH_MAX];
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (::gethostname(hostname, sizeof(hostname) - 1) == 0)
+ {
+ struct hostent *h = ::gethostbyname(hostname);
+ if (h)
+ s.assign(h->h_name);
+ else
+ s.assign(hostname);
+ return true;
+ }
+ return false;
+}
+
+#ifdef __ANDROID_NDK__
+#include <android/api-level.h>
+#endif
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+#define USE_GETPWUID
+#endif
+
+#ifdef USE_GETPWUID
+static std::mutex s_getpwuid_lock;
+#endif
+
+const char *
+HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
+{
+#ifdef USE_GETPWUID
+ // getpwuid_r is missing from android-9
+ // make getpwuid thread safe with a mutex
+ std::lock_guard<std::mutex> lock(s_getpwuid_lock);
+ struct passwd *user_info_ptr = ::getpwuid(uid);
+ if (user_info_ptr)
+ {
+ user_name.assign(user_info_ptr->pw_name);
+ return user_name.c_str();
+ }
+#else
+ struct passwd user_info;
+ struct passwd *user_info_ptr = &user_info;
+ char user_buffer[PATH_MAX];
+ size_t user_buffer_size = sizeof(user_buffer);
+ if (::getpwuid_r(uid, &user_info, user_buffer, user_buffer_size, &user_info_ptr) == 0)
+ {
+ if (user_info_ptr)
+ {
+ user_name.assign(user_info_ptr->pw_name);
+ return user_name.c_str();
+ }
+ }
+#endif
+ user_name.clear();
+ return nullptr;
+}
+
+const char *
+HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name)
+{
+#ifndef __ANDROID__
+ char group_buffer[PATH_MAX];
+ size_t group_buffer_size = sizeof(group_buffer);
+ struct group group_info;
+ struct group *group_info_ptr = &group_info;
+ // Try the threadsafe version first
+ if (::getgrgid_r(gid, &group_info, group_buffer, group_buffer_size, &group_info_ptr) == 0)
+ {
+ if (group_info_ptr)
+ {
+ group_name.assign(group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ else
+ {
+ // The threadsafe version isn't currently working for me on darwin, but the non-threadsafe version
+ // is, so I am calling it below.
+ group_info_ptr = ::getgrgid(gid);
+ if (group_info_ptr)
+ {
+ group_name.assign(group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ group_name.clear();
+#else
+ assert(false && "getgrgid_r() not supported on Android");
+#endif
+ return NULL;
+}
+
+uint32_t
+HostInfoPosix::GetUserID()
+{
+ return getuid();
+}
+
+uint32_t
+HostInfoPosix::GetGroupID()
+{
+ return getgid();
+}
+
+uint32_t
+HostInfoPosix::GetEffectiveUserID()
+{
+ return geteuid();
+}
+
+uint32_t
+HostInfoPosix::GetEffectiveGroupID()
+{
+ return getegid();
+}
+
+FileSpec
+HostInfoPosix::GetDefaultShell()
+{
+ return FileSpec("/bin/sh", false);
+}
+
+bool
+HostInfoPosix::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ char raw_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+ // Most Posix systems (e.g. Linux/*BSD) will attempt to replace a */lib with */bin as the base
+ // directory for helper exe programs. This will fail if the /lib and /bin directories are
+ // rooted in entirely different trees.
+ if (log)
+ log->Printf("HostInfoPosix::ComputeSupportExeDirectory() attempting to derive the bin path (ePathTypeSupportExecutableDir) from "
+ "this path: %s",
+ raw_path);
+ char *lib_pos = ::strstr(raw_path, "/lib");
+ if (lib_pos != nullptr)
+ {
+ // Now write in bin in place of lib.
+ ::snprintf(lib_pos, PATH_MAX - (lib_pos - raw_path), "/bin");
+
+ if (log)
+ log->Printf("Host::%s() derived the bin path as: %s", __FUNCTION__, raw_path);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Host::%s() failed to find /lib/liblldb within the shared lib path, bailing on bin path construction",
+ __FUNCTION__);
+ }
+ file_spec.GetDirectory().SetCString(raw_path);
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoPosix::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file("/opt/local/include/lldb", false);
+ file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
+ return true;
+}
+
+bool
+HostInfoPosix::ComputePythonDirectory(FileSpec &file_spec)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ char raw_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+#if defined(LLDB_PYTHON_RELATIVE_LIBDIR)
+ // Build the path by backing out of the lib dir, then building
+ // with whatever the real python interpreter uses. (e.g. lib
+ // for most, lib64 on RHEL x86_64).
+ char python_path[PATH_MAX];
+ ::snprintf(python_path, sizeof(python_path), "%s/../%s", raw_path, LLDB_PYTHON_RELATIVE_LIBDIR);
+
+ char final_path[PATH_MAX];
+ realpath(python_path, final_path);
+ file_spec.GetDirectory().SetCString(final_path);
+
+ return true;
+#else
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+
+ // We may get our string truncated. Should we protect this with an assert?
+ ::strncat(raw_path, python_version_dir.c_str(), sizeof(raw_path) - strlen(raw_path) - 1);
+
+ file_spec.GetDirectory().SetCString(raw_path);
+ return true;
+#endif
+#else
+ return false;
+#endif
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp
new file mode 100644
index 0000000..5761a79
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostProcessPosix.cpp
@@ -0,0 +1,113 @@
+//===-- HostProcessPosix.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/posix/HostProcessPosix.h"
+#include "lldb/Host/FileSystem.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <limits.h>
+
+using namespace lldb_private;
+
+namespace
+{
+ const int kInvalidPosixProcess = 0;
+}
+
+HostProcessPosix::HostProcessPosix()
+ : HostNativeProcessBase(kInvalidPosixProcess)
+{
+}
+
+HostProcessPosix::HostProcessPosix(lldb::process_t process)
+ : HostNativeProcessBase(process)
+{
+}
+
+HostProcessPosix::~HostProcessPosix()
+{
+}
+
+Error HostProcessPosix::Signal(int signo) const
+{
+ if (m_process == kInvalidPosixProcess)
+ {
+ Error error;
+ error.SetErrorString("HostProcessPosix refers to an invalid process");
+ return error;
+ }
+
+ return HostProcessPosix::Signal(m_process, signo);
+}
+
+Error HostProcessPosix::Signal(lldb::process_t process, int signo)
+{
+ Error error;
+
+ if (-1 == ::kill(process, signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error HostProcessPosix::Terminate()
+{
+ return Signal(SIGKILL);
+}
+
+Error HostProcessPosix::GetMainModule(FileSpec &file_spec) const
+{
+ Error error;
+
+ // Use special code here because proc/[pid]/exe is a symbolic link.
+ char link_path[PATH_MAX];
+ if (snprintf(link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_process) != 1)
+ {
+ error.SetErrorString("Unable to build /proc/<pid>/exe string");
+ return error;
+ }
+
+ error = FileSystem::Readlink(FileSpec{link_path, false}, file_spec);
+ if (!error.Success())
+ return error;
+
+ // If the binary has been deleted, the link name has " (deleted)" appended.
+ // Remove if there.
+ if (file_spec.GetFilename().GetStringRef().endswith(" (deleted)"))
+ {
+ const char *filename = file_spec.GetFilename().GetCString();
+ static const size_t deleted_len = strlen(" (deleted)");
+ const size_t len = file_spec.GetFilename().GetLength();
+ file_spec.GetFilename().SetCStringWithLength(filename, len - deleted_len);
+ }
+ return error;
+}
+
+lldb::pid_t HostProcessPosix::GetProcessId() const
+{
+ return m_process;
+}
+
+bool HostProcessPosix::IsRunning() const
+{
+ if (m_process == kInvalidPosixProcess)
+ return false;
+
+ // Send this process the null signal. If it succeeds the process is running.
+ Error error = Signal(0);
+ return error.Success();
+}
+
+HostThread
+HostProcessPosix::StartMonitoring(HostProcess::MonitorCallback callback, void *callback_baton, bool monitor_signals)
+{
+ return Host::StartMonitoringChildProcess(callback, callback_baton, m_process, monitor_signals);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp
new file mode 100644
index 0000000..9c48924
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/HostThreadPosix.cpp
@@ -0,0 +1,74 @@
+//===-- HostThreadPosix.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/posix/HostThreadPosix.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostThreadPosix::HostThreadPosix()
+{
+}
+
+HostThreadPosix::HostThreadPosix(lldb::thread_t thread)
+ : HostNativeThreadBase(thread)
+{
+}
+
+HostThreadPosix::~HostThreadPosix()
+{
+}
+
+Error
+HostThreadPosix::Join(lldb::thread_result_t *result)
+{
+ Error error;
+ if (IsJoinable())
+ {
+ int err = ::pthread_join(m_thread, result);
+ error.SetError(err, lldb::eErrorTypePOSIX);
+ }
+ else
+ {
+ if (result)
+ *result = NULL;
+ error.SetError(EINVAL, eErrorTypePOSIX);
+ }
+
+ Reset();
+ return error;
+}
+
+Error
+HostThreadPosix::Cancel()
+{
+ Error error;
+#ifndef __ANDROID__
+ int err = ::pthread_cancel(m_thread);
+ error.SetError(err, eErrorTypePOSIX);
+#else
+ error.SetErrorString("HostThreadPosix::Cancel() not supported on Android");
+#endif
+
+ return error;
+}
+
+Error
+HostThreadPosix::Detach()
+{
+ Error error;
+ int err = ::pthread_detach(m_thread);
+ error.SetError(err, eErrorTypePOSIX);
+ Reset();
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp
new file mode 100644
index 0000000..e52b648
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/LockFilePosix.cpp
@@ -0,0 +1,77 @@
+//===-- LockFilePosix.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/LockFilePosix.h"
+
+#include <fcntl.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+
+Error fileLock (int fd, int cmd, int lock_type, const uint64_t start, const uint64_t len)
+{
+ struct flock fl;
+
+ fl.l_type = lock_type;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = start;
+ fl.l_len = len;
+ fl.l_pid = ::getpid ();
+
+ Error error;
+ if (::fcntl (fd, cmd, &fl) == -1)
+ error.SetErrorToErrno ();
+
+ return error;
+}
+
+} // namespace
+
+LockFilePosix::LockFilePosix (int fd)
+ : LockFileBase (fd)
+{
+}
+
+LockFilePosix::~LockFilePosix ()
+{
+ Unlock ();
+}
+
+Error
+LockFilePosix::DoWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLKW, F_WRLCK, start, len);
+}
+
+Error
+LockFilePosix::DoTryWriteLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLK, F_WRLCK, start, len);
+}
+
+Error
+LockFilePosix::DoReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLKW, F_RDLCK, start, len);
+}
+
+Error
+LockFilePosix::DoTryReadLock (const uint64_t start, const uint64_t len)
+{
+ return fileLock (m_fd, F_SETLK, F_RDLCK, start, len);
+}
+
+Error
+LockFilePosix::DoUnlock ()
+{
+ return fileLock (m_fd, F_SETLK, F_UNLCK, m_start, m_len);
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
new file mode 100644
index 0000000..897f2d1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/MainLoopPosix.cpp
@@ -0,0 +1,193 @@
+//===-- MainLoopPosix.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/MainLoopPosix.h"
+
+#include <vector>
+
+#include "lldb/Core/Error.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static sig_atomic_t g_signal_flags[NSIG];
+
+static void
+SignalHandler(int signo, siginfo_t *info, void *)
+{
+ assert(signo < NSIG);
+ g_signal_flags[signo] = 1;
+}
+
+
+MainLoopPosix::~MainLoopPosix()
+{
+ assert(m_read_fds.size() == 0);
+ assert(m_signals.size() == 0);
+}
+
+MainLoopPosix::ReadHandleUP
+MainLoopPosix::RegisterReadObject(const IOObjectSP &object_sp, const Callback &callback, Error &error)
+{
+ if (!object_sp || !object_sp->IsValid())
+ {
+ error.SetErrorString("IO object is not valid.");
+ return nullptr;
+ }
+
+ const bool inserted = m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
+ if (! inserted)
+ {
+ error.SetErrorStringWithFormat("File descriptor %d already monitored.",
+ object_sp->GetWaitableHandle());
+ return nullptr;
+ }
+
+ return CreateReadHandle(object_sp);
+}
+
+// We shall block the signal, then install the signal handler. The signal will be unblocked in
+// the Run() function to check for signal delivery.
+MainLoopPosix::SignalHandleUP
+MainLoopPosix::RegisterSignal(int signo, const Callback &callback, Error &error)
+{
+ if (m_signals.find(signo) != m_signals.end())
+ {
+ error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
+ return nullptr;
+ }
+
+ SignalInfo info;
+ info.callback = callback;
+ struct sigaction new_action;
+ new_action.sa_sigaction = &SignalHandler;
+ new_action.sa_flags = SA_SIGINFO;
+ sigemptyset(&new_action.sa_mask);
+ sigaddset(&new_action.sa_mask, signo);
+
+ sigset_t old_set;
+ if (int ret = pthread_sigmask(SIG_BLOCK, &new_action.sa_mask, &old_set))
+ {
+ error.SetErrorStringWithFormat("pthread_sigmask failed with error %d\n", ret);
+ return nullptr;
+ }
+
+ info.was_blocked = sigismember(&old_set, signo);
+ if (sigaction(signo, &new_action, &info.old_action) == -1)
+ {
+ error.SetErrorToErrno();
+ if (!info.was_blocked)
+ pthread_sigmask(SIG_UNBLOCK, &new_action.sa_mask, nullptr);
+ return nullptr;
+ }
+
+ m_signals.insert({signo, info});
+ g_signal_flags[signo] = 0;
+
+ return SignalHandleUP(new SignalHandle(*this, signo));
+}
+
+void
+MainLoopPosix::UnregisterReadObject(IOObject::WaitableHandle handle)
+{
+ bool erased = m_read_fds.erase(handle);
+ UNUSED_IF_ASSERT_DISABLED(erased);
+ assert(erased);
+}
+
+void
+MainLoopPosix::UnregisterSignal(int signo)
+{
+ // We undo the actions of RegisterSignal on a best-effort basis.
+ auto it = m_signals.find(signo);
+ assert(it != m_signals.end());
+
+ sigaction(signo, &it->second.old_action, nullptr);
+
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, signo);
+ pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK, &set, nullptr);
+
+ m_signals.erase(it);
+}
+
+Error
+MainLoopPosix::Run()
+{
+ std::vector<int> signals;
+ sigset_t sigmask;
+ std::vector<int> read_fds;
+ fd_set read_fd_set;
+ m_terminate_request = false;
+
+ // run until termination or until we run out of things to listen to
+ while (! m_terminate_request && (!m_read_fds.empty() || !m_signals.empty()))
+ {
+ // To avoid problems with callbacks changing the things we're supposed to listen to, we
+ // will store the *real* list of events separately.
+ signals.clear();
+ read_fds.clear();
+ FD_ZERO(&read_fd_set);
+ int nfds = 0;
+
+ if (int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask))
+ return Error("pthread_sigmask failed with error %d\n", ret);
+
+ for (const auto &fd: m_read_fds)
+ {
+ read_fds.push_back(fd.first);
+ FD_SET(fd.first, &read_fd_set);
+ nfds = std::max(nfds, fd.first+1);
+ }
+
+ for (const auto &sig: m_signals)
+ {
+ signals.push_back(sig.first);
+ sigdelset(&sigmask, sig.first);
+ }
+
+ if (pselect(nfds, &read_fd_set, nullptr, nullptr, nullptr, &sigmask) == -1 && errno != EINTR)
+ return Error(errno, eErrorTypePOSIX);
+
+ for (int sig: signals)
+ {
+ if (g_signal_flags[sig] == 0)
+ continue; // No signal
+ g_signal_flags[sig] = 0;
+
+ auto it = m_signals.find(sig);
+ if (it == m_signals.end())
+ continue; // Signal must have gotten unregistered in the meantime
+
+ it->second.callback(*this); // Do the work
+
+ if (m_terminate_request)
+ return Error();
+ }
+
+ for (int fd: read_fds)
+ {
+ if (!FD_ISSET(fd, &read_fd_set))
+ continue; // Not ready
+
+ auto it = m_read_fds.find(fd);
+ if (it == m_read_fds.end())
+ continue; // File descriptor must have gotten unregistered in the meantime
+
+ it->second(*this); // Do the work
+
+ if (m_terminate_request)
+ return Error();
+ }
+ }
+ return Error();
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp
new file mode 100644
index 0000000..353faae
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/PipePosix.cpp
@@ -0,0 +1,437 @@
+//===-- PipePosix.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/posix/PipePosix.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+
+#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8))
+#ifndef _GLIBCXX_USE_NANOSLEEP
+#define _GLIBCXX_USE_NANOSLEEP
+#endif
+#endif
+
+#include <functional>
+#include <thread>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+int PipePosix::kInvalidDescriptor = -1;
+
+enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+// pipe2 is supported by a limited set of platforms
+// TODO: Add more platforms that support pipe2.
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
+#define PIPE2_SUPPORTED 1
+#else
+#define PIPE2_SUPPORTED 0
+#endif
+
+namespace
+{
+
+constexpr auto OPEN_WRITER_SLEEP_TIMEOUT_MSECS = 100;
+
+#if defined(FD_CLOEXEC) && !PIPE2_SUPPORTED
+bool SetCloexecFlag(int fd)
+{
+ int flags = ::fcntl(fd, F_GETFD);
+ if (flags == -1)
+ return false;
+ return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0);
+}
+#endif
+
+std::chrono::time_point<std::chrono::steady_clock>
+Now()
+{
+ return std::chrono::steady_clock::now();
+}
+
+Error
+SelectIO(int handle, bool is_read, const std::function<Error(bool&)> &io_handler, const std::chrono::microseconds &timeout)
+{
+ Error error;
+ fd_set fds;
+ bool done = false;
+
+ using namespace std::chrono;
+
+ const auto finish_time = Now() + timeout;
+
+ while (!done)
+ {
+ struct timeval tv = {0, 0};
+ if (timeout != microseconds::zero())
+ {
+ const auto remaining_dur = duration_cast<microseconds>(finish_time - Now());
+ if (remaining_dur.count() <= 0)
+ {
+ error.SetErrorString("timeout exceeded");
+ break;
+ }
+ const auto dur_secs = duration_cast<seconds>(remaining_dur);
+ const auto dur_usecs = remaining_dur % seconds(1);
+
+ tv.tv_sec = dur_secs.count();
+ tv.tv_usec = dur_usecs.count();
+ }
+ else
+ tv.tv_sec = 1;
+
+ FD_ZERO(&fds);
+ FD_SET(handle, &fds);
+
+ const auto retval = ::select(handle + 1,
+ (is_read) ? &fds : nullptr,
+ (is_read) ? nullptr : &fds,
+ nullptr, &tv);
+ if (retval == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ error.SetErrorToErrno();
+ break;
+ }
+ if (retval == 0)
+ {
+ error.SetErrorString("timeout exceeded");
+ break;
+ }
+ if (!FD_ISSET(handle, &fds))
+ {
+ error.SetErrorString("invalid state");
+ break;
+ }
+
+ error = io_handler(done);
+ if (error.Fail())
+ {
+ if (error.GetError() == EINTR)
+ continue;
+ break;
+ }
+ }
+ return error;
+}
+
+}
+
+PipePosix::PipePosix()
+ : m_fds{
+ PipePosix::kInvalidDescriptor,
+ PipePosix::kInvalidDescriptor
+ } {}
+
+PipePosix::PipePosix(int read_fd, int write_fd)
+ : m_fds{read_fd, write_fd} {}
+
+PipePosix::PipePosix(PipePosix &&pipe_posix)
+ : PipeBase{std::move(pipe_posix)},
+ m_fds{
+ pipe_posix.ReleaseReadFileDescriptor(),
+ pipe_posix.ReleaseWriteFileDescriptor()
+ } {}
+
+PipePosix &PipePosix::operator=(PipePosix &&pipe_posix)
+{
+ PipeBase::operator=(std::move(pipe_posix));
+ m_fds[READ] = pipe_posix.ReleaseReadFileDescriptor();
+ m_fds[WRITE] = pipe_posix.ReleaseWriteFileDescriptor();
+ return *this;
+}
+
+PipePosix::~PipePosix()
+{
+ Close();
+}
+
+Error
+PipePosix::CreateNew(bool child_processes_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ Error error;
+#if PIPE2_SUPPORTED
+ if (::pipe2(m_fds, (child_processes_inherit) ? 0 : O_CLOEXEC) == 0)
+ return error;
+#else
+ if (::pipe(m_fds) == 0)
+ {
+#ifdef FD_CLOEXEC
+ if (!child_processes_inherit)
+ {
+ if (!SetCloexecFlag(m_fds[0]) || !SetCloexecFlag(m_fds[1]))
+ {
+ error.SetErrorToErrno();
+ Close();
+ return error;
+ }
+ }
+#endif
+ return error;
+ }
+#endif
+
+ error.SetErrorToErrno();
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return error;
+}
+
+Error
+PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ Error error;
+ if (::mkfifo(name.data(), 0660) != 0)
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name)
+{
+ llvm::SmallString<PATH_MAX> named_pipe_path;
+ llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
+ FileSpec tmpdir_file_spec;
+ tmpdir_file_spec.Clear();
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ {
+ tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
+ }
+ else
+ {
+ tmpdir_file_spec.AppendPathComponent("/tmp");
+ tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
+ }
+
+ // It's possible that another process creates the target path after we've
+ // verified it's available but before we create it, in which case we
+ // should try again.
+ Error error;
+ do {
+ llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path);
+ error = CreateNew(named_pipe_path, child_process_inherit);
+ } while (error.GetError() == EEXIST);
+
+ if (error.Success())
+ name = named_pipe_path;
+ return error;
+}
+
+Error
+PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ int flags = O_RDONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ Error error;
+ int fd = ::open(name.data(), flags);
+ if (fd != -1)
+ m_fds[READ] = fd;
+ else
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+PipePosix::OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout)
+{
+ if (CanRead() || CanWrite())
+ return Error("Pipe is already opened");
+
+ int flags = O_WRONLY | O_NONBLOCK;
+ if (!child_process_inherit)
+ flags |= O_CLOEXEC;
+
+ using namespace std::chrono;
+ const auto finish_time = Now() + timeout;
+
+ while (!CanWrite())
+ {
+ if (timeout != microseconds::zero())
+ {
+ const auto dur = duration_cast<microseconds>(finish_time - Now()).count();
+ if (dur <= 0)
+ return Error("timeout exceeded - reader hasn't opened so far");
+ }
+
+ errno = 0;
+ int fd = ::open(name.data(), flags);
+ if (fd == -1)
+ {
+ const auto errno_copy = errno;
+ // We may get ENXIO if a reader side of the pipe hasn't opened yet.
+ if (errno_copy != ENXIO)
+ return Error(errno_copy, eErrorTypePOSIX);
+
+ std::this_thread::sleep_for(milliseconds(OPEN_WRITER_SLEEP_TIMEOUT_MSECS));
+ }
+ else
+ {
+ m_fds[WRITE] = fd;
+ }
+ }
+
+ return Error();
+}
+
+int
+PipePosix::GetReadFileDescriptor() const
+{
+ return m_fds[READ];
+}
+
+int
+PipePosix::GetWriteFileDescriptor() const
+{
+ return m_fds[WRITE];
+}
+
+int
+PipePosix::ReleaseReadFileDescriptor()
+{
+ const int fd = m_fds[READ];
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ return fd;
+}
+
+int
+PipePosix::ReleaseWriteFileDescriptor()
+{
+ const int fd = m_fds[WRITE];
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ return fd;
+}
+
+void
+PipePosix::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+Error
+PipePosix::Delete(llvm::StringRef name)
+{
+ return FileSystem::Unlink(FileSpec{name.data(), true});
+}
+
+bool
+PipePosix::CanRead() const
+{
+ return m_fds[READ] != PipePosix::kInvalidDescriptor;
+}
+
+bool
+PipePosix::CanWrite() const
+{
+ return m_fds[WRITE] != PipePosix::kInvalidDescriptor;
+}
+
+void
+PipePosix::CloseReadFileDescriptor()
+{
+ if (CanRead())
+ {
+ close(m_fds[READ]);
+ m_fds[READ] = PipePosix::kInvalidDescriptor;
+ }
+}
+
+void
+PipePosix::CloseWriteFileDescriptor()
+{
+ if (CanWrite())
+ {
+ close(m_fds[WRITE]);
+ m_fds[WRITE] = PipePosix::kInvalidDescriptor;
+ }
+}
+
+Error
+PipePosix::ReadWithTimeout(void *buf, size_t size, const std::chrono::microseconds &timeout, size_t &bytes_read)
+{
+ bytes_read = 0;
+ if (!CanRead())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ auto handle = GetReadFileDescriptor();
+ return SelectIO(handle,
+ true,
+ [=, &bytes_read](bool &done)
+ {
+ Error error;
+ auto result = ::read(handle,
+ reinterpret_cast<char*>(buf) + bytes_read,
+ size - bytes_read);
+ if (result != -1)
+ {
+ bytes_read += result;
+ if (bytes_read == size || result == 0)
+ done = true;
+ }
+ else
+ error.SetErrorToErrno();
+
+ return error;
+ },
+ timeout);
+}
+
+Error
+PipePosix::Write(const void *buf, size_t size, size_t &bytes_written)
+{
+ bytes_written = 0;
+ if (!CanWrite())
+ return Error(EINVAL, eErrorTypePOSIX);
+
+ auto handle = GetWriteFileDescriptor();
+ return SelectIO(handle,
+ false,
+ [=, &bytes_written](bool &done)
+ {
+ Error error;
+ auto result = ::write(handle,
+ reinterpret_cast<const char*>(buf) + bytes_written,
+ size - bytes_written);
+ if (result != -1)
+ {
+ bytes_written += result;
+ if (bytes_written == size)
+ done = true;
+ }
+ else
+ error.SetErrorToErrno();
+
+ return error;
+ },
+ std::chrono::microseconds::zero());
+}
diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp
new file mode 100644
index 0000000..dd5c512
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp
@@ -0,0 +1,33 @@
+//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/posix/ProcessLauncherPosix.h"
+
+#include "lldb/Target/ProcessLaunchInfo.h"
+
+#include <limits.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+HostProcess
+ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error)
+{
+ lldb::pid_t pid;
+ char exe_path[PATH_MAX];
+
+ launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
+
+ // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make MacOSX re-use this
+ // ProcessLauncher when it wants a posix_spawn launch.
+ error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+ return HostProcess(pid);
+}
OpenPOWER on IntegriCloud