aboutsummaryrefslogtreecommitdiff
path: root/source/Host
diff options
context:
space:
mode:
Diffstat (limited to 'source/Host')
-rw-r--r--source/Host/common/Condition.cpp5
-rw-r--r--source/Host/common/DynamicLibrary.cpp33
-rw-r--r--source/Host/common/Editline.cpp418
-rw-r--r--source/Host/common/File.cpp39
-rw-r--r--source/Host/common/FileCache.cpp127
-rw-r--r--source/Host/common/FileSpec.cpp381
-rw-r--r--source/Host/common/Host.cpp1282
-rw-r--r--source/Host/common/HostInfoBase.cpp318
-rw-r--r--source/Host/common/IOObject.cpp14
-rw-r--r--source/Host/common/Mutex.cpp4
-rw-r--r--source/Host/common/NativeBreakpoint.cpp116
-rw-r--r--source/Host/common/NativeBreakpoint.h66
-rw-r--r--source/Host/common/NativeBreakpointList.cpp199
-rw-r--r--source/Host/common/NativeBreakpointList.h53
-rw-r--r--source/Host/common/NativeProcessProtocol.cpp412
-rw-r--r--source/Host/common/NativeProcessProtocol.h333
-rw-r--r--source/Host/common/NativeThreadProtocol.cpp97
-rw-r--r--source/Host/common/NativeThreadProtocol.h85
-rw-r--r--source/Host/common/OptionParser.cpp21
-rw-r--r--source/Host/common/Pipe.cpp171
-rw-r--r--source/Host/common/Socket.cpp662
-rw-r--r--source/Host/common/SocketAddress.cpp3
-rw-r--r--source/Host/common/SoftwareBreakpoint.cpp296
-rw-r--r--source/Host/common/SoftwareBreakpoint.h51
-rw-r--r--source/Host/common/Terminal.cpp5
-rw-r--r--source/Host/freebsd/Host.cpp102
-rw-r--r--source/Host/freebsd/HostInfoFreeBSD.cpp85
-rw-r--r--source/Host/posix/FileSystem.cpp201
-rw-r--r--source/Host/posix/HostInfoPosix.cpp193
-rw-r--r--source/Host/posix/HostProcessPosix.cpp103
30 files changed, 4242 insertions, 1633 deletions
diff --git a/source/Host/common/Condition.cpp b/source/Host/common/Condition.cpp
index 7bc6b6554648..1c1afb4add7e 100644
--- a/source/Host/common/Condition.cpp
+++ b/source/Host/common/Condition.cpp
@@ -57,11 +57,6 @@ Condition::Signal ()
return ::pthread_cond_signal (&m_condition);
}
-/* convert struct timeval to ms(milliseconds) */
-static unsigned long int tv2ms(struct timeval a) {
- return ((a.tv_sec * 1000) + (a.tv_usec / 1000));
-}
-
//----------------------------------------------------------------------
// The Wait() function atomically blocks the current thread
// waiting on the owned condition variable, and unblocks the mutex
diff --git a/source/Host/common/DynamicLibrary.cpp b/source/Host/common/DynamicLibrary.cpp
deleted file mode 100644
index 315a675895ff..000000000000
--- a/source/Host/common/DynamicLibrary.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-//===-- DynamicLibrary.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/DynamicLibrary.h"
-
-using namespace lldb_private;
-
-DynamicLibrary::DynamicLibrary (const FileSpec& spec, uint32_t options) : m_filespec(spec)
-{
- Error err;
- m_handle = Host::DynamicLibraryOpen (spec,options,err);
- if (err.Fail())
- m_handle = NULL;
-}
-
-bool
-DynamicLibrary::IsValid ()
-{
- return m_handle != NULL;
-}
-
-DynamicLibrary::~DynamicLibrary ()
-{
- if (m_handle)
- Host::DynamicLibraryClose (m_handle);
-}
diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp
index 679aadd54c4f..7af9f39a7863 100644
--- a/source/Host/common/Editline.cpp
+++ b/source/Host/common/Editline.cpp
@@ -20,30 +20,158 @@
using namespace lldb;
using namespace lldb_private;
+namespace lldb_private {
+ typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
+
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. This class allows
+ // multiple editline instances to
+ //
+
+ 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_init();
+ ::history (m_history, &m_event, H_SETSIZE, size);
+ if (unique_entries)
+ ::history (m_history, &m_event, H_SETUNIQUE, 1);
+ }
+
+ const char *
+ GetHistoryFilePath()
+ {
+ if (m_path.empty() && m_history && !m_prefix.empty())
+ {
+ char history_path[PATH_MAX];
+ ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_prefix.c_str());
+ m_path = std::move(FileSpec(history_path, true).GetPath());
+ }
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+ }
+
+ public:
+
+ ~EditlineHistory()
+ {
+ Save ();
+
+ if (m_history)
+ {
+ ::history_end (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;
+ }
+
+ ::History *
+ GetHistoryPtr ()
+ {
+ return m_history;
+ }
+
+ void
+ Enter (const char *line_cstr)
+ {
+ if (m_history)
+ ::history (m_history, &m_event, H_ENTER, line_cstr);
+ }
+
+ bool
+ Load ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ ::history (m_history, &m_event, H_LOAD, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ Save ()
+ {
+ if (m_history)
+ {
+ const char *path = GetHistoryFilePath();
+ if (path)
+ {
+ ::history (m_history, &m_event, H_SAVE, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ ::History *m_history; // The history object
+ ::HistEvent 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
+ };
+}
+
+
static const char k_prompt_escape_char = '\1';
Editline::Editline (const char *prog, // prog can't be NULL
const char *prompt, // can be NULL for no prompt
+ bool configure_for_multiline,
FILE *fin,
FILE *fout,
FILE *ferr) :
m_editline (NULL),
- m_history (NULL),
- m_history_event (),
- m_program (),
+ m_history_sp (),
m_prompt (),
m_lines_prompt (),
- m_getc_buffer (),
- m_getc_mutex (Mutex::eMutexTypeNormal),
- m_getc_cond (),
-// m_gets_mutex (Mutex::eMutexTypeNormal),
+ m_getting_char (false),
m_completion_callback (NULL),
m_completion_callback_baton (NULL),
m_line_complete_callback (NULL),
m_line_complete_callback_baton (NULL),
m_lines_command (Command::None),
+ m_line_offset (0),
m_lines_curr_line (0),
m_lines_max_line (0),
+ m_file (fileno(fin), false),
m_prompt_with_line_numbers (false),
m_getting_line (false),
m_got_eof (false),
@@ -51,14 +179,16 @@ Editline::Editline (const char *prog, // prog can't be NULL
{
if (prog && prog[0])
{
- m_program = prog;
m_editline = ::el_init(prog, fin, fout, ferr);
- m_history = ::history_init();
+
+ // Get a shared history instance
+ m_history_sp = EditlineHistory::GetHistory(prog);
}
else
{
m_editline = ::el_init("lldb-tmp", fin, fout, ferr);
}
+
if (prompt && prompt[0])
SetPrompt (prompt);
@@ -76,28 +206,44 @@ Editline::Editline (const char *prog, // prog can't be NULL
::el_set (m_editline, EL_PROMPT, GetPromptCallback);
#endif
::el_set (m_editline, EL_EDITOR, "emacs");
- if (m_history)
+ if (m_history_sp && m_history_sp->IsValid())
{
- ::el_set (m_editline, EL_HIST, history, m_history);
+ ::el_set (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
}
::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete);
+ // Keep old "lldb_complete" mapping for older clients that used this in their .editrc. editline also
+ // has a bad bug where if you have a bind command that tries to bind to a function name that doesn't
+ // exist, it will corrupt the heap and probably crash your process later.
+ ::el_set (m_editline, EL_ADDFN, "lldb_complete", "Editline completion function", Editline::CallbackComplete);
::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine);
::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine);
::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 does.
::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key.
- ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte
+ ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be auto complete
+
+ if (configure_for_multiline)
+ {
+ // Use escape sequences for control characters due to bugs in editline
+ // where "-k up" and "-k down" don't always work.
+ ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
+ // Bindings for next/prev history
+ ::el_set (m_editline, EL_BIND, "^P", "ed-prev-history", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^N", "ed-next-history", NULL); // Map down arrow
+ }
+ else
+ {
+ // Use escape sequences for control characters due to bugs in editline
+ // where "-k up" and "-k down" don't always work.
+ ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
+ ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
+ }
// Source $PWD/.editrc then $HOME/.editrc
::el_source (m_editline, NULL);
- if (m_history)
- {
- ::history (m_history, &m_history_event, H_SETSIZE, 800);
- ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
- }
-
// Always read through our callback function so we don't read
// stuff we aren't supposed to. This also stops the extra echoing
// that can happen when you have more input than editline can handle
@@ -109,14 +255,12 @@ Editline::Editline (const char *prog, // prog can't be NULL
Editline::~Editline()
{
- SaveHistory();
-
- if (m_history)
- {
- ::history_end (m_history);
- m_history = NULL;
- }
-
+ // 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();
+
// 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.
@@ -132,36 +276,19 @@ Editline::SetGetCharCallback (GetCharCallbackType callback)
::el_set (m_editline, EL_GETCFN, callback);
}
-FileSpec
-Editline::GetHistoryFile()
-{
- char history_path[PATH_MAX];
- ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str());
- return FileSpec(history_path, true);
-}
-
bool
Editline::LoadHistory ()
{
- if (m_history)
- {
- FileSpec history_file(GetHistoryFile());
- if (history_file.Exists())
- ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str());
- return true;
- }
+ if (m_history_sp)
+ return m_history_sp->Load();
return false;
}
bool
Editline::SaveHistory ()
{
- if (m_history)
- {
- std::string history_path = GetHistoryFile().GetPath();
- ::history (m_history, &m_history_event, H_SAVE, history_path.c_str());
- return true;
- }
+ if (m_history_sp)
+ return m_history_sp->Save();
return false;
}
@@ -180,13 +307,8 @@ Editline::PrivateGetLine(std::string &line)
if (m_editline != NULL)
{
int line_len = 0;
- const char *line_cstr = NULL;
// Call el_gets to prompt the user and read the user's input.
-// {
-// // Make sure we know when we are in el_gets() by using a mutex
-// Mutex::Locker locker (m_gets_mutex);
- line_cstr = ::el_gets (m_editline, &line_len);
-// }
+ const char *line_cstr = ::el_gets (m_editline, &line_len);
static int save_errno = (line_len < 0) ? errno : 0;
@@ -198,20 +320,18 @@ Editline::PrivateGetLine(std::string &line)
{
// Decrement the length so we don't have newline characters in "line" for when
// we assign the cstr into the std::string
- while (line_len > 0 &&
- (line_cstr[line_len - 1] == '\n' ||
- line_cstr[line_len - 1] == '\r'))
- --line_len;
+ llvm::StringRef line_ref (line_cstr);
+ line_ref = line_ref.rtrim("\n\r");
- if (line_len > 0)
+ if (!line_ref.empty() && !m_interrupted)
{
// We didn't strip the newlines, we just adjusted the length, and
// we want to add the history item with the newlines
- if (m_history)
- ::history (m_history, &m_history_event, H_ENTER, line_cstr);
+ if (m_history_sp)
+ m_history_sp->Enter(line_cstr);
// Copy the part of the c string that we want (removing the newline chars)
- line.assign(line_cstr, line_len);
+ line = std::move(line_ref.str());
}
}
}
@@ -224,15 +344,14 @@ Editline::PrivateGetLine(std::string &line)
Error
-Editline::GetLine(std::string &line)
+Editline::GetLine(std::string &line, bool &interrupted)
{
Error error;
+ interrupted = false;
line.clear();
// Set arrow key bindings for up and down arrows for single line
// mode where up and down arrows do prev/next history
- ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow
m_interrupted = false;
if (!m_got_eof)
@@ -252,6 +371,8 @@ Editline::GetLine(std::string &line)
m_getting_line = false;
}
+ interrupted = m_interrupted;
+
if (m_got_eof && line.empty())
{
// Only set the error if we didn't get an error back from PrivateGetLine()
@@ -278,9 +399,10 @@ Editline::Push (const char *bytes, size_t len)
Error
-Editline::GetLines(const std::string &end_line, StringList &lines)
+Editline::GetLines(const std::string &end_line, StringList &lines, bool &interrupted)
{
Error error;
+ interrupted = false;
if (m_getting_line)
{
error.SetErrorString("already getting a line");
@@ -294,10 +416,6 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
// Set arrow key bindings for up and down arrows for multiple line
// mode where up and down arrows do edit prev/next line
- ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow
- ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow
- ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL);
- ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL);
m_interrupted = false;
LineStatus line_status = LineStatus::Success;
@@ -321,6 +439,11 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
{
line_status = LineStatus::Error;
}
+ else if (m_interrupted)
+ {
+ interrupted = true;
+ line_status = LineStatus::Done;
+ }
else
{
switch (m_lines_command)
@@ -385,7 +508,7 @@ Editline::GetLines(const std::string &end_line, StringList &lines)
// If we have a callback, call it one more time to let the
// user know the lines are complete
- if (m_line_complete_callback)
+ if (m_line_complete_callback && !interrupted)
m_line_complete_callback (this,
lines,
UINT32_MAX,
@@ -599,70 +722,78 @@ Editline::GetPromptCallback (::EditLine *e)
return "";
}
-size_t
-Editline::SetInputBuffer (const char *c, size_t len)
-{
- if (c && len > 0)
- {
- Mutex::Locker locker(m_getc_mutex);
- SetGetCharCallback(GetCharInputBufferCallback);
- m_getc_buffer.append(c, len);
- m_getc_cond.Broadcast();
- }
- return len;
-}
-
-int
-Editline::GetChar (char *c)
-{
- Mutex::Locker locker(m_getc_mutex);
- if (m_getc_buffer.empty())
- m_getc_cond.Wait(m_getc_mutex);
- if (m_getc_buffer.empty())
- return 0;
- *c = m_getc_buffer[0];
- m_getc_buffer.erase(0,1);
- return 1;
-}
-
-int
-Editline::GetCharInputBufferCallback (EditLine *e, char *c)
-{
- Editline *editline = GetClientData (e);
- if (editline)
- return editline->GetChar(c);
- return 0;
-}
-
int
Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
{
Editline *editline = GetClientData (e);
if (editline && editline->m_got_eof == false)
{
- char ch = ::fgetc(editline->GetInputFile());
- if (ch == '\x04')
- {
- // Only turn a CTRL+D into a EOF if we receive the
- // CTRL+D an empty line, otherwise it will forward
- // delete the character at the cursor
- const LineInfo *line_info = ::el_line(e);
- if (line_info != NULL &&
- line_info->buffer == line_info->cursor &&
- line_info->cursor == line_info->lastchar)
- {
- ch = EOF;
- }
- }
-
- if (ch == EOF)
+ FILE *f = editline->GetInputFile();
+ if (f == NULL)
{
editline->m_got_eof = true;
+ return 0;
}
- else
+
+
+ while (1)
{
- *c = ch;
- return 1;
+ lldb::ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = 0;
+ // When we start to call el_gets() the editline library needs to
+ // output the prompt
+ editline->m_getting_char.SetValue(true, eBroadcastAlways);
+ const size_t n = editline->m_file.Read(&ch, 1, UINT32_MAX, status, NULL);
+ editline->m_getting_char.SetValue(false, eBroadcastAlways);
+ if (n)
+ {
+ if (ch == '\x04')
+ {
+ // Only turn a CTRL+D into a EOF if we receive the
+ // CTRL+D an empty line, otherwise it will forward
+ // delete the character at the cursor
+ const LineInfo *line_info = ::el_line(e);
+ if (line_info != NULL &&
+ line_info->buffer == line_info->cursor &&
+ line_info->cursor == line_info->lastchar)
+ {
+ editline->m_got_eof = true;
+ break;
+ }
+ }
+
+ if (status == eConnectionStatusEndOfFile)
+ {
+ editline->m_got_eof = true;
+ break;
+ }
+ else
+ {
+ *c = ch;
+ return 1;
+ }
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusInterrupted:
+ editline->m_interrupted = true;
+ *c = '\n';
+ return 1;
+
+ case eConnectionStatusSuccess: // Success
+ break;
+
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ case eConnectionStatusEndOfFile: // End-of-file encountered
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ editline->m_got_eof = true;
+ break;
+ }
+ }
}
}
return 0;
@@ -671,12 +802,23 @@ Editline::GetCharFromInputFileCallback (EditLine *e, char *c)
void
Editline::Hide ()
{
- FILE *out_file = GetOutputFile();
- if (out_file)
+ if (m_getting_line)
{
- const LineInfo *line_info = ::el_line(m_editline);
- if (line_info)
- ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
+ // If we are getting a line, we might have started to call el_gets() and
+ // it might be printing the prompt. Here we make sure we are actually getting
+ // a character. This way we know the entire prompt has been printed.
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds(1);
+ if (m_getting_char.WaitForValueEqualTo(true, &timeout))
+ {
+ FILE *out_file = GetOutputFile();
+ if (out_file)
+ {
+ const LineInfo *line_info = ::el_line(m_editline);
+ if (line_info)
+ ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer));
+ }
+ }
}
}
@@ -684,13 +826,25 @@ Editline::Hide ()
void
Editline::Refresh()
{
- ::el_set (m_editline, EL_REFRESH);
+ if (m_getting_line)
+ {
+ // If we are getting a line, we might have started to call el_gets() and
+ // it might be printing the prompt. Here we make sure we are actually getting
+ // a character. This way we know the entire prompt has been printed.
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds(1);
+ if (m_getting_char.WaitForValueEqualTo(true, &timeout))
+ {
+ ::el_set (m_editline, EL_REFRESH);
+ }
+ }
}
-void
+bool
Editline::Interrupt ()
{
m_interrupted = true;
if (m_getting_line || m_lines_curr_line > 0)
- el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets()
+ return m_file.InterruptRead();
+ return false; // Interrupt not handled as we weren't getting a line or lines
}
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
index bb0ee39fbc7b..50513af2dc14 100644
--- a/source/Host/common/File.cpp
+++ b/source/Host/common/File.cpp
@@ -24,6 +24,7 @@
#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"
@@ -77,11 +78,11 @@ 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_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
@@ -91,11 +92,11 @@ File::File(const char *path, uint32_t options, uint32_t 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_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
@@ -107,11 +108,11 @@ File::File (const FileSpec& filespec,
}
File::File (const File &rhs) :
+ IOObject(eFDTypeFile, false),
m_descriptor (kInvalidDescriptor),
m_stream (kInvalidStream),
m_options (0),
m_own_stream (false),
- m_own_descriptor (false),
m_is_interactive (eLazyBoolCalculate),
m_is_real_terminal (eLazyBoolCalculate)
{
@@ -148,13 +149,20 @@ File::GetDescriptor() const
return kInvalidDescriptor;
}
+IOObject::WaitableHandle
+File::GetWaitableHandle()
+{
+ return m_descriptor;
+}
+
+
void
File::SetDescriptor (int fd, bool transfer_ownership)
{
if (IsValid())
Close();
m_descriptor = fd;
- m_own_descriptor = transfer_ownership;
+ m_should_close_fd = transfer_ownership;
}
@@ -168,7 +176,7 @@ File::GetStream ()
const char *mode = GetStreamOpenModeFromOptions (m_options);
if (mode)
{
- if (!m_own_descriptor)
+ 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
@@ -177,7 +185,7 @@ File::GetStream ()
#else
m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
#endif
- m_own_descriptor = true;
+ m_should_close_fd = true;
}
do
@@ -191,7 +199,7 @@ File::GetStream ()
if (m_stream)
{
m_own_stream = true;
- m_own_descriptor = false;
+ m_should_close_fd = false;
}
}
}
@@ -228,7 +236,7 @@ File::Duplicate (const File &rhs)
else
{
m_options = rhs.m_options;
- m_own_descriptor = true;
+ m_should_close_fd = true;
}
}
else
@@ -307,7 +315,7 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
error.SetErrorToErrno();
else
{
- m_own_descriptor = true;
+ m_should_close_fd = true;
m_options = options;
}
@@ -371,7 +379,7 @@ File::Close ()
error.SetErrorToErrno();
}
- if (DescriptorIsValid() && m_own_descriptor)
+ if (DescriptorIsValid() && m_should_close_fd)
{
if (::close (m_descriptor) != 0)
error.SetErrorToErrno();
@@ -380,7 +388,7 @@ File::Close ()
m_stream = kInvalidStream;
m_options = 0;
m_own_stream = false;
- m_own_descriptor = false;
+ m_should_close_fd = false;
m_is_interactive = eLazyBoolCalculate;
m_is_real_terminal = eLazyBoolCalculate;
return error;
@@ -669,6 +677,7 @@ File::Write (const void *buf, size_t &num_bytes)
num_bytes = 0;
error.SetErrorString("invalid file handle");
}
+
return error;
}
@@ -887,7 +896,13 @@ File::CalculateInteractiveAndTerminal ()
{
m_is_interactive = eLazyBoolNo;
m_is_real_terminal = eLazyBoolNo;
-#ifndef _MSC_VER
+#ifdef _WIN32
+ if (_isatty(fd))
+ {
+ m_is_interactive = eLazyBoolYes;
+ m_is_real_terminal = eLazyBoolYes;
+ }
+#else
if (isatty(fd))
{
m_is_interactive = eLazyBoolYes;
diff --git a/source/Host/common/FileCache.cpp b/source/Host/common/FileCache.cpp
new file mode 100644
index 000000000000..96b2a2ec02af
--- /dev/null
+++ b/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/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp
index 48f1ac78d927..8c4014c074f5 100644
--- a/source/Host/common/FileSpec.cpp
+++ b/source/Host/common/FileSpec.cpp
@@ -27,21 +27,22 @@
#include <pwd.h>
#endif
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/File.h"
-#include "lldb/Host/FileSpec.h"
-#include "lldb/Host/Host.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;
@@ -54,104 +55,68 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
return false;
}
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
-static const char*
-GetCachedGlobTildeSlash()
-{
- static std::string g_tilde;
- if (g_tilde.empty())
- {
- struct passwd *user_entry;
- user_entry = getpwuid(geteuid());
- if (user_entry != NULL)
- g_tilde = user_entry->pw_dir;
-
- if (g_tilde.empty())
- return NULL;
- }
- return g_tilde.c_str();
-}
-
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
// Resolves the username part of a path of the form ~user/other/directories, and
// writes the result into dst_path.
-// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved.
-// Otherwise returns the number of characters copied into dst_path. If the return
-// is >= dst_len, then the resolved path is too long...
-size_t
-FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len)
+void
+FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path)
{
- if (src_path == NULL || src_path[0] == '\0')
- return 0;
-
-#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
-
- char user_home[PATH_MAX];
- const char *user_name;
-
-
- // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
- if (src_path[0] != '~')
- {
- size_t len = strlen (src_path);
- if (len >= dst_len)
- {
- ::bcopy (src_path, dst_path, dst_len - 1);
- dst_path[dst_len] = '\0';
- }
- else
- ::bcopy (src_path, dst_path, len + 1);
-
- return len;
- }
-
- const char *first_slash = ::strchr (src_path, '/');
- char remainder[PATH_MAX];
+#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ if (path.empty() || path[0] != '~')
+ return;
- if (first_slash == NULL)
+ llvm::StringRef path_str(path.data());
+ size_t slash_pos = path_str.find_first_of("/", 1);
+ if (slash_pos == 1)
{
- // The whole name is the username (minus the ~):
- user_name = src_path + 1;
- remainder[0] = '\0';
- }
- else
- {
- size_t user_name_len = first_slash - src_path - 1;
- ::memcpy (user_home, src_path + 1, user_name_len);
- user_home[user_name_len] = '\0';
- user_name = user_home;
+ // A path of the form ~/ resolves to the current user's home dir
+ llvm::SmallString<64> home_dir;
+ if (!llvm::sys::path::home_directory(home_dir))
+ return;
- ::strcpy (remainder, first_slash);
+ // 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;
}
- if (user_name == NULL)
- return 0;
- // User name of "" means the current user...
-
- struct passwd *user_entry;
- const char *home_dir = NULL;
-
- if (user_name[0] == '\0')
+ 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)
{
- home_dir = GetCachedGlobTildeSlash();
+ // 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
{
- user_entry = ::getpwnam (user_name);
- if (user_entry != NULL)
- home_dir = user_entry->pw_dir;
+ // Unable to resolve username (user doesn't exist?)
+ path.clear();
}
-
- if (home_dir == NULL)
- return 0;
- else
- return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder);
-#else
- // Resolving home directories is not supported, just copy the path...
- return ::snprintf (dst_path, dst_len, "%s", src_path);
-#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+#endif
}
size_t
@@ -187,49 +152,24 @@ FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches)
#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
}
-
-
-size_t
-FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
+void
+FileSpec::Resolve (llvm::SmallVectorImpl<char> &path)
{
- if (src_path == NULL || src_path[0] == '\0')
- return 0;
+ if (path.empty())
+ return;
- // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
- char unglobbed_path[PATH_MAX];
#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- if (src_path[0] == '~')
- {
- size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path));
-
- // If we couldn't find the user referred to, or the resultant path was too long,
- // then just copy over the src_path.
- if (return_count == 0 || return_count >= sizeof(unglobbed_path))
- ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
- }
- else
+ if (path[0] == '~')
+ ResolveUsername(path);
#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
- {
- ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
- }
- // Now resolve the path if needed
- char resolved_path[PATH_MAX];
- if (::realpath (unglobbed_path, resolved_path))
- {
- // Success, copy the resolved path
- return ::snprintf(dst_path, dst_len, "%s", resolved_path);
- }
- else
- {
- // Failed, just copy the unglobbed path
- return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
- }
+ llvm::sys::fs::make_absolute(path);
}
-FileSpec::FileSpec() :
- m_directory(),
- m_filename()
+FileSpec::FileSpec()
+ : m_directory()
+ , m_filename()
+ , m_syntax(FileSystem::GetNativePathSyntax())
{
}
@@ -237,13 +177,13 @@ FileSpec::FileSpec() :
// Default constructor that can take an optional full path to a
// file on disk.
//------------------------------------------------------------------
-FileSpec::FileSpec(const char *pathname, bool resolve_path) :
+FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) :
m_directory(),
m_filename(),
m_is_resolved(false)
{
if (pathname && pathname[0])
- SetFile(pathname, resolve_path);
+ SetFile(pathname, resolve_path, syntax);
}
//------------------------------------------------------------------
@@ -252,7 +192,8 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path) :
FileSpec::FileSpec(const FileSpec& rhs) :
m_directory (rhs.m_directory),
m_filename (rhs.m_filename),
- m_is_resolved (rhs.m_is_resolved)
+ m_is_resolved (rhs.m_is_resolved),
+ m_syntax (rhs.m_syntax)
{
}
@@ -268,7 +209,7 @@ FileSpec::FileSpec(const FileSpec* rhs) :
}
//------------------------------------------------------------------
-// Virtual destrcuctor in case anyone inherits from this class.
+// Virtual destructor in case anyone inherits from this class.
//------------------------------------------------------------------
FileSpec::~FileSpec()
{
@@ -285,83 +226,65 @@ FileSpec::operator= (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;
}
return *this;
}
+void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
+{
+ if (syntax == ePathSyntaxPosix ||
+ (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
+ return;
+
+ std::replace(path.begin(), path.end(), '\\', '/');
+}
+
+void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax)
+{
+ if (syntax == ePathSyntaxPosix ||
+ (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix))
+ return;
+
+ std::replace(path.begin(), path.end(), '/', '\\');
+}
+
//------------------------------------------------------------------
// 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)
+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;
- char resolved_path[PATH_MAX];
- bool path_fit = true;
-
+ llvm::SmallString<64> normalized(pathname);
+ Normalize(normalized, syntax);
+
if (resolve)
{
- path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1);
- m_is_resolved = path_fit;
+ FileSpec::Resolve (normalized);
+ m_is_resolved = true;
}
- else
- {
- // Copy the path because "basename" and "dirname" want to muck with the
- // path buffer
- if (::strlen (pathname) > sizeof(resolved_path) - 1)
- path_fit = false;
- else
- ::strcpy (resolved_path, pathname);
- }
-
- if (path_fit)
+ llvm::StringRef resolve_path_ref(normalized.c_str());
+ llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref);
+ if (!filename_ref.empty())
{
- char *filename = ::basename (resolved_path);
- if (filename)
- {
- m_filename.SetCString (filename);
- // Truncate the basename off the end of the resolved path
-
- // Only attempt to get the dirname if it looks like we have a path
- if (strchr(resolved_path, '/')
-#ifdef _WIN32
- || strchr(resolved_path, '\\')
-#endif
- )
- {
- char *directory = ::dirname (resolved_path);
-
- // Make sure we didn't get our directory resolved to "." without having
- // specified
- if (directory)
- m_directory.SetCString(directory);
- else
- {
- char *last_resolved_path_slash = strrchr(resolved_path, '/');
-#ifdef _WIN32
- char* last_resolved_path_slash_windows = strrchr(resolved_path, '\\');
- if (last_resolved_path_slash_windows > last_resolved_path_slash)
- last_resolved_path_slash = last_resolved_path_slash_windows;
-#endif
- if (last_resolved_path_slash)
- {
- *last_resolved_path_slash = '\0';
- m_directory.SetCString(resolved_path);
- }
- }
- }
- }
- else
- m_directory.SetCString(resolved_path);
+ 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());
}
//----------------------------------------------------------------------
@@ -562,6 +485,15 @@ FileSpec::Exists () const
}
bool
+FileSpec::Readable () const
+{
+ const uint32_t permissions = GetPermissions();
+ if (permissions & eFilePermissionsEveryoneR)
+ return true;
+ return false;
+}
+
+bool
FileSpec::ResolveExecutableLocation ()
{
if (!m_directory)
@@ -572,8 +504,7 @@ FileSpec::ResolveExecutableLocation ()
const std::string file_str (file_cstr);
std::string path = llvm::sys::FindProgramByName (file_str);
llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
- //llvm::StringRef dir_ref = path.getDirname();
- if (! dir_ref.empty())
+ if (!dir_ref.empty())
{
// FindProgramByName returns "." if it can't find the file.
if (strcmp (".", dir_ref.data()) == 0)
@@ -607,7 +538,7 @@ FileSpec::ResolvePath ()
return true; // We have already resolved this path
char path_buf[PATH_MAX];
- if (!GetPath (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);
@@ -623,6 +554,12 @@ FileSpec::GetByteSize() const
return 0;
}
+FileSpec::PathSyntax
+FileSpec::GetPathSyntax() const
+{
+ return m_syntax;
+}
+
FileSpec::FileType
FileSpec::GetFileType () const
{
@@ -652,7 +589,7 @@ FileSpec::GetPermissions () const
{
uint32_t file_permissions = 0;
if (*this)
- Host::GetFilePermissions(GetPath().c_str(), file_permissions);
+ FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions);
return file_permissions;
}
@@ -708,45 +645,30 @@ FileSpec::GetFilename() const
// values.
//------------------------------------------------------------------
size_t
-FileSpec::GetPath(char *path, size_t path_max_len) const
+FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const
{
- if (path_max_len)
- {
- const char *dirname = m_directory.GetCString();
- const char *filename = m_filename.GetCString();
- if (dirname)
- {
- if (filename)
- return ::snprintf (path, path_max_len, "%s/%s", dirname, filename);
- else
- return ::snprintf (path, path_max_len, "%s", dirname);
- }
- else if (filename)
- {
- return ::snprintf (path, path_max_len, "%s", filename);
- }
- }
- if (path)
- path[0] = '\0';
- return 0;
+ if (!path)
+ return 0;
+
+ std::string result = GetPath(denormalize);
+
+ size_t result_length = std::min(path_max_len-1, result.length());
+ ::strncpy(path, result.c_str(), result_length + 1);
+ return result_length;
}
std::string
-FileSpec::GetPath (void) const
+FileSpec::GetPath (bool denormalize) const
{
- static ConstString g_slash_only ("/");
- std::string path;
- const char *dirname = m_directory.GetCString();
- const char *filename = m_filename.GetCString();
- if (dirname)
- {
- path.append (dirname);
- if (filename && m_directory != g_slash_only)
- path.append ("/");
- }
- if (filename)
- path.append (filename);
- return path;
+ llvm::SmallString<64> result;
+ if (m_directory)
+ result.append(m_directory.GetCString());
+ if (m_filename)
+ llvm::sys::path::append(result, m_filename.GetCString());
+ if (denormalize && !result.empty())
+ DeNormalize(result, m_syntax);
+
+ return std::string(result.begin(), result.end());
}
ConstString
@@ -780,7 +702,7 @@ FileSpec::GetFileNameStrippingExtension () const
// 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 mappped will start "file_offset" bytes into the
+// 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
@@ -936,12 +858,11 @@ FileSpec::EnumerateDirectory
if (dir_path && dir_path[0])
{
#if _WIN32
- char szDir[MAX_PATH];
- strcpy_s(szDir, MAX_PATH, dir_path);
- strcat_s(szDir, MAX_PATH, "\\*");
+ std::string szDir(dir_path);
+ szDir += "\\*";
WIN32_FIND_DATA ffd;
- HANDLE hFind = FindFirstFile(szDir, &ffd);
+ HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index d43221c0e136..00c2fa37b383 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -12,11 +12,12 @@
// C includes
#include <errno.h>
#include <limits.h>
+#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include "lldb/Host/windows/windows.h"
#include <winsock2.h>
-#include <WS2tcpip.h>
+#include <ws2tcpip.h>
#else
#include <unistd.h>
#include <dlfcn.h>
@@ -35,10 +36,9 @@
#include <mach/mach_port.h>
#include <mach/mach_init.h>
#include <mach-o/dyld.h>
-#include <AvailabilityMacros.h>
#endif
-#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__)
#include <spawn.h>
#include <sys/wait.h>
#include <sys/syscall.h>
@@ -48,7 +48,11 @@
#include <pthread_np.h>
#endif
+// C++ includes
+#include <limits>
+
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Debugger.h"
@@ -60,13 +64,19 @@
#include "lldb/Host/Config.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/FileAction.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/CleanUp.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#if defined (__APPLE__)
@@ -85,6 +95,12 @@ extern "C"
using namespace lldb;
using namespace lldb_private;
+// Define maximum thread name length
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__NetBSD__)
+uint32_t const Host::MAX_THREAD_NAME_LENGTH = 16;
+#else
+uint32_t const Host::MAX_THREAD_NAME_LENGTH = std::numeric_limits<uint32_t>::max ();
+#endif
#if !defined (__APPLE__) && !defined (_WIN32)
struct MonitorInfo
@@ -116,7 +132,18 @@ Host::StartMonitoringChildProcess
info_ptr->monitor_signals = monitor_signals;
char thread_name[256];
- ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+
+ if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ {
+ // On some platforms, the thread name is limited to 16 characters. We need to
+ // abbreviate there or the pid info would get truncated.
+ ::snprintf (thread_name, sizeof(thread_name), "wait4(%" PRIu64 ")", pid);
+ }
+ else
+ {
+ ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+ }
+
thread = ThreadCreate (thread_name,
MonitorChildProcessThreadFunction,
info_ptr,
@@ -168,7 +195,7 @@ MonitorChildProcessThreadFunction (void *arg)
const bool monitor_signals = info->monitor_signals;
assert (info->pid <= UINT32_MAX);
- const ::pid_t pid = monitor_signals ? -1 * info->pid : info->pid;
+ const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid;
delete info;
@@ -302,181 +329,6 @@ Host::SystemLog (SystemLogType type, const char *format, ...)
va_end (args);
}
-const ArchSpec &
-Host::GetArchitecture (SystemDefaultArchitecture arch_kind)
-{
- static bool g_supports_32 = false;
- static bool g_supports_64 = false;
- static ArchSpec g_host_arch_32;
- static ArchSpec g_host_arch_64;
-
-#if defined (__APPLE__)
-
- // Apple is different in that it can support both 32 and 64 bit executables
- // in the same operating system running concurrently. Here we detect the
- // correct host architectures for both 32 and 64 bit including if 64 bit
- // executables are supported on the system.
-
- if (g_supports_32 == false && g_supports_64 == false)
- {
- // All apple systems support 32 bit execution.
- g_supports_32 = true;
- uint32_t cputype, cpusubtype;
- uint32_t is_64_bit_capable = false;
- size_t len = sizeof(cputype);
- ArchSpec host_arch;
- // These will tell us about the kernel architecture, which even on a 64
- // bit machine can be 32 bit...
- if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
- {
- len = sizeof (cpusubtype);
- if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
- cpusubtype = CPU_TYPE_ANY;
-
- len = sizeof (is_64_bit_capable);
- if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
- {
- if (is_64_bit_capable)
- g_supports_64 = true;
- }
-
- if (is_64_bit_capable)
- {
-#if defined (__i386__) || defined (__x86_64__)
- if (cpusubtype == CPU_SUBTYPE_486)
- cpusubtype = CPU_SUBTYPE_I386_ALL;
-#endif
- if (cputype & CPU_ARCH_ABI64)
- {
- // We have a 64 bit kernel on a 64 bit system
- g_host_arch_32.SetArchitecture (eArchTypeMachO, ~(CPU_ARCH_MASK) & cputype, cpusubtype);
- g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- }
- else
- {
- // We have a 32 bit kernel on a 64 bit system
- g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- cputype |= CPU_ARCH_ABI64;
- g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- }
- }
- else
- {
- g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
- g_host_arch_64.Clear();
- }
- }
- }
-
-#else // #if defined (__APPLE__)
-
- if (g_supports_32 == false && g_supports_64 == false)
- {
- llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
-
- g_host_arch_32.Clear();
- g_host_arch_64.Clear();
-
- // If the OS is Linux, "unknown" in the vendor slot isn't what we want
- // for the default triple. It's probably an artifact of config.guess.
- if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor)
- triple.setVendorName ("");
-
- const char* distribution_id = GetDistributionId ().AsCString();
-
- switch (triple.getArch())
- {
- default:
- g_host_arch_32.SetTriple(triple);
- g_host_arch_32.SetDistributionId (distribution_id);
- g_supports_32 = true;
- break;
-
- case llvm::Triple::x86_64:
- g_host_arch_64.SetTriple(triple);
- g_host_arch_64.SetDistributionId (distribution_id);
- g_supports_64 = true;
- g_host_arch_32.SetTriple(triple.get32BitArchVariant());
- g_host_arch_32.SetDistributionId (distribution_id);
- g_supports_32 = true;
- break;
-
- case llvm::Triple::sparcv9:
- case llvm::Triple::ppc64:
- g_host_arch_64.SetTriple(triple);
- g_host_arch_64.SetDistributionId (distribution_id);
- g_supports_64 = true;
- break;
- }
-
- g_supports_32 = g_host_arch_32.IsValid();
- g_supports_64 = g_host_arch_64.IsValid();
- }
-
-#endif // #else for #if defined (__APPLE__)
-
- if (arch_kind == eSystemDefaultArchitecture32)
- return g_host_arch_32;
- else if (arch_kind == eSystemDefaultArchitecture64)
- return g_host_arch_64;
-
- if (g_supports_64)
- return g_host_arch_64;
-
- return g_host_arch_32;
-}
-
-const ConstString &
-Host::GetVendorString()
-{
- static ConstString g_vendor;
- if (!g_vendor)
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
- g_vendor.SetCStringWithLength(str_ref.data(), str_ref.size());
- }
- return g_vendor;
-}
-
-const ConstString &
-Host::GetOSString()
-{
- static ConstString g_os_string;
- if (!g_os_string)
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
- g_os_string.SetCStringWithLength(str_ref.data(), str_ref.size());
- }
- return g_os_string;
-}
-
-const ConstString &
-Host::GetTargetTriple()
-{
- static ConstString g_host_triple;
- if (!(g_host_triple))
- {
- const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
- g_host_triple.SetCString(host_arch.GetTriple().getTriple().c_str());
- }
- return g_host_triple;
-}
-
-// See linux/Host.cpp for Linux-based implementations of this.
-// Add your platform-specific implementation to the appropriate host file.
-#if !defined(__linux__)
-
-const ConstString &
- Host::GetDistributionId ()
-{
- static ConstString s_distribution_id;
- return s_distribution_id;
-}
-
-#endif // #if !defined(__linux__)
-
lldb::pid_t
Host::GetCurrentProcessID()
{
@@ -806,51 +658,6 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid,
#endif
-FileSpec
-Host::GetProgramFileSpec ()
-{
- static FileSpec g_program_filespec;
- if (!g_program_filespec)
- {
-#if defined (__APPLE__)
- char program_fullpath[PATH_MAX];
- // If DST is NULL, then return the number of bytes needed.
- uint32_t len = sizeof(program_fullpath);
- int err = _NSGetExecutablePath (program_fullpath, &len);
- if (err == 0)
- g_program_filespec.SetFile (program_fullpath, false);
- else if (err == -1)
- {
- char *large_program_fullpath = (char *)::malloc (len + 1);
-
- err = _NSGetExecutablePath (large_program_fullpath, &len);
- if (err == 0)
- g_program_filespec.SetFile (large_program_fullpath, false);
-
- ::free (large_program_fullpath);
- }
-#elif defined (__linux__)
- char exe_path[PATH_MAX];
- ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
- if (len > 0) {
- exe_path[len] = 0;
- g_program_filespec.SetFile(exe_path, false);
- }
-#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
- 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;
- }
-#endif
- }
- return g_program_filespec;
-}
-
#if !defined (__APPLE__) // see Host.mm
bool
@@ -869,130 +676,6 @@ Host::ResolveExecutableInBundle (FileSpec &file)
#ifndef _WIN32
-// Opaque info that tracks a dynamic library that was loaded
-struct DynamicLibraryInfo
-{
- DynamicLibraryInfo (const FileSpec &fs, int o, void *h) :
- file_spec (fs),
- open_options (o),
- handle (h)
- {
- }
-
- const FileSpec file_spec;
- uint32_t open_options;
- void * handle;
-};
-
-void *
-Host::DynamicLibraryOpen (const FileSpec &file_spec, uint32_t options, Error &error)
-{
- char path[PATH_MAX];
- if (file_spec.GetPath(path, sizeof(path)))
- {
- int mode = 0;
-
- if (options & eDynamicLibraryOpenOptionLazy)
- mode |= RTLD_LAZY;
- else
- mode |= RTLD_NOW;
-
-
- if (options & eDynamicLibraryOpenOptionLocal)
- mode |= RTLD_LOCAL;
- else
- mode |= RTLD_GLOBAL;
-
-#ifdef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
- if (options & eDynamicLibraryOpenOptionLimitGetSymbol)
- mode |= RTLD_FIRST;
-#endif
-
- void * opaque = ::dlopen (path, mode);
-
- if (opaque)
- {
- error.Clear();
- return new DynamicLibraryInfo (file_spec, options, opaque);
- }
- else
- {
- error.SetErrorString(::dlerror());
- }
- }
- else
- {
- error.SetErrorString("failed to extract path");
- }
- return NULL;
-}
-
-Error
-Host::DynamicLibraryClose (void *opaque)
-{
- Error error;
- if (opaque == NULL)
- {
- error.SetErrorString ("invalid dynamic library handle");
- }
- else
- {
- DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
- if (::dlclose (dylib_info->handle) != 0)
- {
- error.SetErrorString(::dlerror());
- }
-
- dylib_info->open_options = 0;
- dylib_info->handle = 0;
- delete dylib_info;
- }
- return error;
-}
-
-void *
-Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &error)
-{
- if (opaque == NULL)
- {
- error.SetErrorString ("invalid dynamic library handle");
- }
- else
- {
- DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
-
- void *symbol_addr = ::dlsym (dylib_info->handle, symbol_name);
- if (symbol_addr)
- {
-#ifndef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
- // This host doesn't support limiting searches to this shared library
- // so we need to verify that the match came from this shared library
- // if it was requested in the Host::DynamicLibraryOpen() function.
- if (dylib_info->open_options & eDynamicLibraryOpenOptionLimitGetSymbol)
- {
- FileSpec match_dylib_spec (Host::GetModuleFileSpecForHostAddress (symbol_addr));
- if (match_dylib_spec != dylib_info->file_spec)
- {
- char dylib_path[PATH_MAX];
- if (dylib_info->file_spec.GetPath (dylib_path, sizeof(dylib_path)))
- error.SetErrorStringWithFormat ("symbol not found in \"%s\"", dylib_path);
- else
- error.SetErrorString ("symbol not found");
- return NULL;
- }
- }
-#endif
- error.Clear();
- return symbol_addr;
- }
- else
- {
- error.SetErrorString(::dlerror());
- }
- }
- return NULL;
-}
-
FileSpec
Host::GetModuleFileSpecForHostAddress (const void *host_addr)
{
@@ -1008,427 +691,6 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr)
#endif
-bool
-Host::GetLLDBPath (PathType path_type, 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".
- Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST);
-
- switch (path_type)
- {
- case ePathTypeLLDBShlibDir:
- {
- static ConstString g_lldb_so_dir;
- if (!g_lldb_so_dir)
- {
- FileSpec lldb_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)Host::GetLLDBPath));
- g_lldb_so_dir = lldb_file_spec.GetDirectory();
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_lldb_so_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_so_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
- case ePathTypeSupportExecutableDir:
- {
- static ConstString g_lldb_support_exe_dir;
- if (!g_lldb_support_exe_dir)
- {
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
-#if defined (__APPLE__)
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
-#if defined (__arm__)
- // Shallow bundle
- *framework_pos = '\0';
-#else
- // Normal bundle
- ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path));
-#endif
- }
-#endif
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_support_exe_dir.SetCString(resolved_path);
- }
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_support_exe_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
- case ePathTypeHeaderDir:
- {
- static ConstString g_lldb_headers_dir;
- if (!g_lldb_headers_dir)
- {
-#if defined (__APPLE__)
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Headers", PATH_MAX - (framework_pos - raw_path));
- }
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_headers_dir.SetCString(resolved_path);
- }
-#else
- // TODO: Anyone know how we can determine this for linux? Other systems??
- g_lldb_headers_dir.SetCString ("/opt/local/include/lldb");
-#endif
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_lldb_headers_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_headers_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-
-#ifdef LLDB_DISABLE_PYTHON
- case ePathTypePythonDir:
- return false;
-#else
- case ePathTypePythonDir:
- {
- static ConstString g_lldb_python_dir;
- if (!g_lldb_python_dir)
- {
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
-#if defined (__APPLE__)
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path));
- }
- else
- {
-#endif
- llvm::SmallString<256> python_version_dir;
- llvm::raw_svector_ostream os(python_version_dir);
- os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
- os.flush();
-
- // 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);
-
-#if defined (__APPLE__)
- }
-#endif
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_python_dir.SetCString(resolved_path);
- }
-
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypePythonDir) => '%s'", g_lldb_python_dir.GetCString());
-
- }
- file_spec.GetDirectory() = g_lldb_python_dir;
- return (bool)file_spec.GetDirectory();
- }
- break;
-#endif
-
- case ePathTypeLLDBSystemPlugins: // System plug-ins directory
- {
-#if defined (__APPLE__) || defined(__linux__)
- static ConstString g_lldb_system_plugin_dir;
- static bool g_lldb_system_plugin_dir_located = false;
- if (!g_lldb_system_plugin_dir_located)
- {
- g_lldb_system_plugin_dir_located = true;
-#if defined (__APPLE__)
- FileSpec lldb_file_spec;
- if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
- {
- char raw_path[PATH_MAX];
- char resolved_path[PATH_MAX];
- lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
-
- char *framework_pos = ::strstr (raw_path, "LLDB.framework");
- if (framework_pos)
- {
- framework_pos += strlen("LLDB.framework");
- ::strncpy (framework_pos, "/Resources/PlugIns", PATH_MAX - (framework_pos - raw_path));
- FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
- g_lldb_system_plugin_dir.SetCString(resolved_path);
- }
- return false;
- }
-#elif defined (__linux__)
- FileSpec lldb_file_spec("/usr/lib/lldb", true);
- if (lldb_file_spec.Exists())
- {
- g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
- }
-#endif // __APPLE__ || __linux__
-
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_lldb_system_plugin_dir.GetCString());
-
- }
-
- if (g_lldb_system_plugin_dir)
- {
- file_spec.GetDirectory() = g_lldb_system_plugin_dir;
- return true;
- }
-#else
- // TODO: where would system LLDB plug-ins be located on other systems?
- return false;
-#endif
- }
- break;
-
- case ePathTypeLLDBUserPlugins: // User plug-ins directory
- {
-#if defined (__APPLE__)
- static ConstString g_lldb_user_plugin_dir;
- if (!g_lldb_user_plugin_dir)
- {
- char user_plugin_path[PATH_MAX];
- if (FileSpec::Resolve ("~/Library/Application Support/LLDB/PlugIns",
- user_plugin_path,
- sizeof(user_plugin_path)))
- {
- g_lldb_user_plugin_dir.SetCString(user_plugin_path);
- }
- }
- file_spec.GetDirectory() = g_lldb_user_plugin_dir;
- return (bool)file_spec.GetDirectory();
-#elif defined (__linux__)
- static ConstString g_lldb_user_plugin_dir;
- if (!g_lldb_user_plugin_dir)
- {
- // XDG Base Directory Specification
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
- // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
- FileSpec lldb_file_spec;
- const char *xdg_data_home = getenv("XDG_DATA_HOME");
- if (xdg_data_home && xdg_data_home[0])
- {
- std::string user_plugin_dir (xdg_data_home);
- user_plugin_dir += "/lldb";
- lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
- }
- else
- {
- const char *home_dir = getenv("HOME");
- if (home_dir && home_dir[0])
- {
- std::string user_plugin_dir (home_dir);
- user_plugin_dir += "/.local/share/lldb";
- lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
- }
- }
-
- if (lldb_file_spec.Exists())
- g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_lldb_user_plugin_dir.GetCString());
- }
- file_spec.GetDirectory() = g_lldb_user_plugin_dir;
- return (bool)file_spec.GetDirectory();
-#endif
- // TODO: where would user LLDB plug-ins be located on other systems?
- return false;
- }
-
- case ePathTypeLLDBTempSystemDir:
- {
- static ConstString g_lldb_tmp_dir;
- if (!g_lldb_tmp_dir)
- {
- const char *tmpdir_cstr = getenv("TMPDIR");
- if (tmpdir_cstr == NULL)
- {
- tmpdir_cstr = getenv("TMP");
- if (tmpdir_cstr == NULL)
- tmpdir_cstr = getenv("TEMP");
- }
- if (tmpdir_cstr)
- {
- g_lldb_tmp_dir.SetCString(tmpdir_cstr);
- if (log)
- log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString());
- }
- }
- file_spec.GetDirectory() = g_lldb_tmp_dir;
- return (bool)file_spec.GetDirectory();
- }
- }
-
- return false;
-}
-
-
-bool
-Host::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;
-}
-
-#ifndef _WIN32
-
-const char *
-Host::GetUserName (uint32_t uid, std::string &user_name)
-{
- 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();
- }
- }
- user_name.clear();
- return NULL;
-}
-
-const char *
-Host::GetGroupName (uint32_t gid, std::string &group_name)
-{
- 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();
- return NULL;
-}
-
-uint32_t
-Host::GetUserID ()
-{
- return getuid();
-}
-
-uint32_t
-Host::GetGroupID ()
-{
- return getgid();
-}
-
-uint32_t
-Host::GetEffectiveUserID ()
-{
- return geteuid();
-}
-
-uint32_t
-Host::GetEffectiveGroupID ()
-{
- return getegid();
-}
-
-#endif
-
-#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm
-bool
-Host::GetOSBuildString (std::string &s)
-{
- s.clear();
- return false;
-}
-
-bool
-Host::GetOSKernelDescription (std::string &s)
-{
- s.clear();
- return false;
-}
-#endif
-
-#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__)
-uint32_t
-Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
-{
- process_infos.Clear();
- return process_infos.GetSize();
-}
-
-bool
-Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
-{
- process_info.Clear();
- return false;
-}
-#endif
-
#if !defined(__linux__)
bool
Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
@@ -1447,7 +709,7 @@ Host::GetDummyTarget (lldb_private::Debugger &debugger)
{
ArchSpec arch(Target::GetDefaultArchitecture());
if (!arch.IsValid())
- arch = Host::GetArchitecture ();
+ arch = HostInfo::GetArchitecture();
Error err = debugger.GetTargetList().CreateTarget(debugger,
NULL,
arch.GetTriple().getTriple().c_str(),
@@ -1545,9 +807,9 @@ Host::RunShellCommand (const char *command,
// 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 (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
+ if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
{
- tmpdir_file_spec.GetFilename().SetCString("lldb-shell-output.XXXXXX");
+ tmpdir_file_spec.AppendPathComponent("lldb-shell-output.XXXXXX");
strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer));
}
else
@@ -1601,7 +863,7 @@ Host::RunShellCommand (const char *command,
{
error.SetErrorString("timed out waiting for shell command to complete");
- // Kill the process since it didn't complete withint the timeout specified
+ // 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();
@@ -1651,7 +913,7 @@ Host::RunShellCommand (const char *command,
// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC
// systems
-#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__)
+#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__)
// this method needs to be visible to macosx/Host.cpp and
// common/Host.cpp.
@@ -1682,7 +944,7 @@ Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info)
g_use_close_on_exec_flag = eLazyBoolNo;
uint32_t major, minor, update;
- if (Host::GetOSVersion(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))
@@ -1757,8 +1019,8 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
cpu_type_t cpu = arch_spec.GetMachOCPUType();
cpu_type_t sub = arch_spec.GetMachOCPUSubType();
if (cpu != 0 &&
- cpu != UINT32_MAX &&
- cpu != LLDB_INVALID_CPUTYPE &&
+ 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;
@@ -1840,13 +1102,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
for (size_t i=0; i<num_file_actions; ++i)
{
- const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
+ const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i);
if (launch_file_action)
{
- if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions,
- launch_file_action,
- log,
- error))
+ if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error))
return error;
}
}
@@ -1862,12 +1121,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
if (error.Fail() || log)
{
error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )",
- pid,
- exe_path,
- &file_actions,
- &attr,
- argv,
- envp);
+ 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)
@@ -1889,11 +1146,9 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
if (error.Fail() || log)
{
error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )",
- pid,
- exe_path,
- &attr,
- argv,
- envp);
+ 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)
@@ -1920,12 +1175,79 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i
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 // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__)
-// The functions below implement process launching via posix_spawn() for Linux
-// and FreeBSD.
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__)
+// The functions below implement process launching via posix_spawn() for Linux,
+// FreeBSD and NetBSD.
Error
Host::LaunchProcess (ProcessLaunchInfo &launch_info)
@@ -2005,58 +1327,10 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info)
return error;
}
-#endif // defined(__linux__) or defined(__FreeBSD__)
+#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#ifndef _WIN32
-size_t
-Host::GetPageSize()
-{
- return ::getpagesize();
-}
-
-uint32_t
-Host::GetNumberCPUS ()
-{
- static uint32_t g_num_cores = UINT32_MAX;
- if (g_num_cores == UINT32_MAX)
- {
-#if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__)
-
- g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN);
-
-#else
-
- // Assume POSIX support if a host specific case has not been supplied above
- g_num_cores = 0;
- int num_cores = 0;
- size_t num_cores_len = sizeof(num_cores);
-#ifdef HW_AVAILCPU
- int mib[] = { CTL_HW, HW_AVAILCPU };
-#else
- int mib[] = { CTL_HW, HW_NCPU };
-#endif
-
- /* get the number of CPUs from the system */
- if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
- {
- g_num_cores = num_cores;
- }
- else
- {
- mib[1] = HW_NCPU;
- num_cores_len = sizeof(num_cores);
- if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
- {
- if (num_cores > 0)
- g_num_cores = num_cores;
- }
- }
-#endif
- }
- return g_num_cores;
-}
-
void
Host::Kill(lldb::pid_t pid, int signo)
{
@@ -2090,319 +1364,13 @@ Host::LaunchApplication (const FileSpec &app_file_spec)
#endif
+#if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__NetBSD__)
-#ifdef LLDB_DISABLE_POSIX
-
-Error
-Host::MakeDirectory (const char* path, uint32_t mode)
-{
- Error error;
- error.SetErrorStringWithFormat("%s in not implemented on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::SetFilePermissions (const char* path, uint32_t file_permissions)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Symlink (const char *src, const char *dst)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Readlink (const char *path, char *buf, size_t buf_len)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-Error
-Host::Unlink (const char *path)
-{
- Error error;
- error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__);
- return error;
-}
-
-#else
-
-Error
-Host::MakeDirectory (const char* path, uint32_t file_permissions)
-{
- Error error;
- if (path && path[0])
- {
- if (::mkdir(path, file_permissions) != 0)
- {
- error.SetErrorToErrno();
- switch (error.GetError())
- {
- case ENOENT:
- {
- // Parent directory doesn't exist, so lets make it if we can
- FileSpec spec(path, false);
- if (spec.GetDirectory() && spec.GetFilename())
- {
- // Make the parent directory and try again
- Error error2 = Host::MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
- if (error2.Success())
- {
- // Try and make the directory again now that the parent directory was made successfully
- if (::mkdir(path, file_permissions) == 0)
- error.Clear();
- else
- error.SetErrorToErrno();
- }
- }
- }
- break;
- case EEXIST:
- {
- FileSpec path_spec(path, false);
- if (path_spec.IsDirectory())
- error.Clear(); // It is a directory and it already exists
- }
- break;
- }
- }
- }
- else
- {
- error.SetErrorString("empty path");
- }
- return error;
-}
-
-Error
-Host::GetFilePermissions (const char* path, uint32_t &file_permissions)
-{
- Error error;
- struct stat file_stats;
- if (::stat (path, &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
-Host::SetFilePermissions (const char* path, uint32_t file_permissions)
-{
- Error error;
- if (::chmod(path, file_permissions) != 0)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Symlink (const char *src, const char *dst)
-{
- Error error;
- if (::symlink(dst, src) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Unlink (const char *path)
-{
- Error error;
- if (::unlink(path) == -1)
- error.SetErrorToErrno();
- return error;
-}
-
-Error
-Host::Readlink (const char *path, char *buf, size_t buf_len)
-{
- Error error;
- ssize_t count = ::readlink(path, buf, buf_len);
- if (count < 0)
- error.SetErrorToErrno();
- else if (count < (buf_len-1))
- buf[count] = '\0'; // Success
- else
- error.SetErrorString("'buf' buffer is too small to contain link contents");
- return error;
-}
-
-
-#endif
-
-typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap;
-FDToFileMap& GetFDToFileMap()
-{
- static FDToFileMap g_fd2filemap;
- return g_fd2filemap;
-}
-
-lldb::user_id_t
-Host::OpenFile (const FileSpec& file_spec,
- uint32_t flags,
- uint32_t mode,
- Error &error)
+const lldb_private::UnixSignalsSP&
+Host::GetUnixSignals ()
{
- 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();
- GetFDToFileMap()[fd] = file_sp;
- return fd;
+ static UnixSignalsSP s_unix_signals_sp (new UnixSignals ());
+ return s_unix_signals_sp;
}
-bool
-Host::CloseFile (lldb::user_id_t fd, Error &error)
-{
- if (fd == UINT64_MAX)
- {
- error.SetErrorString ("invalid file descriptor");
- return false;
- }
- FDToFileMap& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.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();
- file_map.erase(pos);
- return error.Success();
-}
-
-uint64_t
-Host::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& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.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 (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
-Host::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& file_map = GetFDToFileMap();
- FDToFileMap::iterator pos = file_map.find(fd);
- if (pos == file_map.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 (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;
-}
-
-lldb::user_id_t
-Host::GetFileSize (const FileSpec& file_spec)
-{
- return file_spec.GetByteSize();
-}
-
-bool
-Host::GetFileExists (const FileSpec& file_spec)
-{
- return file_spec.Exists();
-}
-
-bool
-Host::CalculateMD5 (const FileSpec& file_spec,
- uint64_t &low,
- uint64_t &high)
-{
-#if defined (__APPLE__)
- StreamString md5_cmd_line;
- md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
- std::string hash_string;
- Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
- if (err.Fail())
- return false;
- // a correctly formed MD5 is 16-bytes, that is 32 hex digits
- // if the output is any other length it is probably wrong
- if (hash_string.size() != 32)
- return false;
- std::string part1(hash_string,0,16);
- std::string part2(hash_string,16);
- const char* part1_cstr = part1.c_str();
- const char* part2_cstr = part2.c_str();
- high = ::strtoull(part1_cstr, NULL, 16);
- low = ::strtoull(part2_cstr, NULL, 16);
- return true;
-#else
- // your own MD5 implementation here
- return false;
#endif
-}
diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp
new file mode 100644
index 000000000000..4eb43bfaf6ff
--- /dev/null
+++ b/source/Host/common/HostInfoBase.cpp
@@ -0,0 +1,318 @@
+//===-- 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/Support/Host.h"
+
+#include <thread>
+
+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.GetDirectory().GetCString(), true);
+}
+
+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_system_plugin_dir;
+ FileSpec m_lldb_user_plugin_dir;
+ FileSpec m_lldb_tmp_dir;
+};
+
+HostInfoBaseFields *g_fields = nullptr;
+}
+
+#define COMPUTE_LLDB_PATH(compute_function, member_var) \
+ { \
+ static bool is_initialized = false; \
+ static bool success = false; \
+ if (!is_initialized) \
+ { \
+ is_initialized = true; \
+ success = HostInfo::compute_function(member_var); \
+ } \
+ if (success) \
+ result = &member_var; \
+ }
+
+void
+HostInfoBase::Initialize()
+{
+ g_fields = new HostInfoBaseFields();
+}
+
+uint32_t
+HostInfoBase::GetNumberCPUS()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ g_fields->m_number_cpus = std::thread::hardware_concurrency();
+ is_initialized = true;
+ }
+
+ return g_fields->m_number_cpus;
+}
+
+llvm::StringRef
+HostInfoBase::GetVendorString()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
+ g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end());
+ is_initialized = true;
+ }
+ return g_fields->m_vendor_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetOSString()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
+ g_fields->m_os_string.assign(str_ref.begin(), str_ref.end());
+ is_initialized = true;
+ }
+ return g_fields->m_os_string;
+}
+
+llvm::StringRef
+HostInfoBase::GetTargetTriple()
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ const ArchSpec &host_arch = HostInfo::GetArchitecture();
+ g_fields->m_host_triple = host_arch.GetTriple().getTriple();
+ is_initialized = true;
+ }
+ return g_fields->m_host_triple;
+}
+
+const ArchSpec &
+HostInfoBase::GetArchitecture(ArchitectureKind arch_kind)
+{
+ static bool is_initialized = false;
+ if (!is_initialized)
+ {
+ HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64);
+ is_initialized = true;
+ }
+
+ // 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
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ FileSpec *result = nullptr;
+ switch (type)
+ {
+ case lldb::ePathTypeLLDBShlibDir:
+ COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeSupportExecutableDir:
+ COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
+ g_fields->m_lldb_support_exe_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeHeaderDir:
+ COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypePythonDir:
+ COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBSystemPlugins:
+ COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
+ g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBUserPlugins:
+ COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
+ g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
+ break;
+ case lldb::ePathTypeLLDBTempSystemDir:
+ COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir)
+ if (log)
+ log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str());
+ 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))));
+
+ // 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::ComputeTempFileDirectory(FileSpec &file_spec)
+{
+ const char *tmpdir_cstr = getenv("TMPDIR");
+ if (tmpdir_cstr == NULL)
+ {
+ tmpdir_cstr = getenv("TMP");
+ if (tmpdir_cstr == NULL)
+ tmpdir_cstr = getenv("TEMP");
+ }
+ if (!tmpdir_cstr)
+ return false;
+
+ StreamString pid_tmpdir;
+ pid_tmpdir.Printf("%s/lldb", tmpdir_cstr);
+ if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success())
+ return false;
+
+ pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID());
+ if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), 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().SetCStringWithLength(pid_tmpdir.GetString().c_str(), pid_tmpdir.GetString().size());
+ 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::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::getDefaultTargetTriple());
+
+ arch_32.Clear();
+ arch_64.Clear();
+
+ switch (triple.getArch())
+ {
+ default:
+ arch_32.SetTriple(triple);
+ break;
+
+ case llvm::Triple::x86_64:
+ arch_64.SetTriple(triple);
+ arch_32.SetTriple(triple.get32BitArchVariant());
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::mips64:
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::ppc64:
+ arch_64.SetTriple(triple);
+ break;
+ }
+}
diff --git a/source/Host/common/IOObject.cpp b/source/Host/common/IOObject.cpp
new file mode 100644
index 000000000000..6f7de442be1d
--- /dev/null
+++ b/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/source/Host/common/Mutex.cpp b/source/Host/common/Mutex.cpp
index 4e0135535628..c26467fa0d79 100644
--- a/source/Host/common/Mutex.cpp
+++ b/source/Host/common/Mutex.cpp
@@ -242,9 +242,9 @@ Mutex::Mutex (Mutex::Type type) :
//----------------------------------------------------------------------
Mutex::~Mutex()
{
+#if ENABLE_MUTEX_ERROR_CHECKING
int err = ::pthread_mutex_destroy (&m_mutex);
assert(err == 0);
-#if ENABLE_MUTEX_ERROR_CHECKING
if (err == 0)
error_check_mutex (&m_mutex, eMutexActionDestroyed);
else
@@ -253,6 +253,8 @@ Mutex::~Mutex()
assert(err == 0);
}
memset (&m_mutex, '\xba', sizeof(m_mutex));
+#else
+ ::pthread_mutex_destroy (&m_mutex);
#endif
}
diff --git a/source/Host/common/NativeBreakpoint.cpp b/source/Host/common/NativeBreakpoint.cpp
new file mode 100644
index 000000000000..284d7d11d6ce
--- /dev/null
+++ b/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 "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/source/Host/common/NativeBreakpoint.h b/source/Host/common/NativeBreakpoint.h
new file mode 100644
index 000000000000..367003b94e35
--- /dev/null
+++ b/source/Host/common/NativeBreakpoint.h
@@ -0,0 +1,66 @@
+//===-- NativeBreakpoint.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeBreakpoint_h_
+#define liblldb_NativeBreakpoint_h_
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private
+{
+ class NativeBreakpointList;
+
+ class NativeBreakpoint
+ {
+ friend class NativeBreakpointList;
+
+ public:
+ // The assumption is that derived breakpoints are enabled when created.
+ NativeBreakpoint (lldb::addr_t addr);
+
+ virtual
+ ~NativeBreakpoint ();
+
+ Error
+ Enable ();
+
+ Error
+ Disable ();
+
+ lldb::addr_t
+ GetAddress () const { return m_addr; }
+
+ bool
+ IsEnabled () const { return m_enabled; }
+
+ virtual bool
+ IsSoftwareBreakpoint () const = 0;
+
+ protected:
+ const lldb::addr_t m_addr;
+ int32_t m_ref_count;
+
+ virtual Error
+ DoEnable () = 0;
+
+ virtual Error
+ DoDisable () = 0;
+
+ private:
+ bool m_enabled;
+
+ // -----------------------------------------------------------
+ // interface for NativeBreakpointList
+ // -----------------------------------------------------------
+ void AddRef ();
+ int32_t DecRef ();
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpoint_h_
diff --git a/source/Host/common/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp
new file mode 100644
index 000000000000..ecd0624bde09
--- /dev/null
+++ b/source/Host/common/NativeBreakpointList.cpp
@@ -0,0 +1,199 @@
+//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpointList.h"
+
+#include "lldb/Core/Log.h"
+
+#include "NativeBreakpoint.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 ();
+}
+
diff --git a/source/Host/common/NativeBreakpointList.h b/source/Host/common/NativeBreakpointList.h
new file mode 100644
index 000000000000..51617330d075
--- /dev/null
+++ b/source/Host/common/NativeBreakpointList.h
@@ -0,0 +1,53 @@
+//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeBreakpointList_h_
+#define liblldb_NativeBreakpointList_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+// #include "lldb/Host/NativeBreakpoint.h"
+
+#include <functional>
+#include <map>
+
+namespace lldb_private
+{
+ class NativeBreakpointList
+ {
+ public:
+ typedef std::function<Error (lldb::addr_t addr, size_t size_hint, bool hardware, NativeBreakpointSP &breakpoint_sp)> CreateBreakpointFunc;
+
+ NativeBreakpointList ();
+
+ Error
+ AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func);
+
+ Error
+ DecRef (lldb::addr_t addr);
+
+ Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ Error
+ GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+
+ private:
+ typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
+
+ Mutex m_mutex;
+ BreakpointMap m_breakpoints;
+ };
+}
+
+#endif // ifndef liblldb_NativeBreakpointList_h_
diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp
new file mode 100644
index 000000000000..b7a77266c58c
--- /dev/null
+++ b/source/Host/common/NativeProcessProtocol.cpp
@@ -0,0 +1,412 @@
+//===-- 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 "NativeProcessProtocol.h"
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "NativeThreadProtocol.h"
+#include "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_terminal_fd (-1),
+ m_stop_id (0)
+{
+}
+
+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::GetThreadByID (lldb::tid_t tid)
+{
+ Mutex::Locker locker (m_threads_mutex);
+ for (auto thread_sp : m_threads)
+ {
+ if (thread_sp->GetID() == tid)
+ return thread_sp;
+ }
+ return NativeThreadProtocolSP ();
+}
+
+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;
+}
+
+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));
+
+ // FIXME save the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // 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 Error ();
+}
+
+Error
+NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
+{
+ // FIXME remove the watchpoint on the set of process watchpoint vars
+ // so we can add them to a thread each time a new thread is registered.
+
+ // 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;
+ }
+ }
+ return overall_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);
+ 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.
+}
diff --git a/source/Host/common/NativeProcessProtocol.h b/source/Host/common/NativeProcessProtocol.h
new file mode 100644
index 000000000000..035a264e172e
--- /dev/null
+++ b/source/Host/common/NativeProcessProtocol.h
@@ -0,0 +1,333 @@
+//===-- NativeProcessProtocol.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessProtocol_h_
+#define liblldb_NativeProcessProtocol_h_
+
+#include <vector>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeBreakpointList.h"
+
+namespace lldb_private
+{
+ class MemoryRegionInfo;
+ class ResumeActionList;
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol
+ //------------------------------------------------------------------
+ class NativeProcessProtocol :
+ public std::enable_shared_from_this<NativeProcessProtocol>
+ {
+ friend class SoftwareBreakpoint;
+
+ public:
+ static NativeProcessProtocol *
+ CreateInstance (lldb::pid_t pid);
+
+ // lldb_private::Host calls should be used to launch a process for debugging, and
+ // then the process should be attached to. When attaching to a process
+ // lldb_private::Host calls should be used to locate the process to attach to,
+ // and then this function should be called.
+ NativeProcessProtocol (lldb::pid_t pid);
+
+ public:
+ virtual ~NativeProcessProtocol ()
+ {
+ }
+
+ virtual Error
+ Resume (const ResumeActionList &resume_actions) = 0;
+
+ virtual Error
+ Halt () = 0;
+
+ virtual Error
+ Detach () = 0;
+
+ //------------------------------------------------------------------
+ /// Sends a process a UNIX signal \a signal.
+ ///
+ /// Implementer note: the WillSignal ()/DidSignal () calls
+ /// from the Process class are not replicated here since no
+ /// concrete classes implemented any behavior for those and
+ /// put all the work in DoSignal (...).
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ Signal (int signo) = 0;
+
+ virtual Error
+ Kill () = 0;
+
+ //----------------------------------------------------------------------
+ // Memory and memory region functions
+ //----------------------------------------------------------------------
+
+ virtual Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info);
+
+ virtual Error
+ ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
+
+ virtual Error
+ WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
+
+ virtual Error
+ AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
+
+ virtual Error
+ DeallocateMemory (lldb::addr_t addr) = 0;
+
+ virtual lldb::addr_t
+ GetSharedLibraryInfoAddress () = 0;
+
+ virtual bool
+ IsAlive () const;
+
+ virtual size_t
+ UpdateThreads () = 0;
+
+ virtual bool
+ GetArchitecture (ArchSpec &arch) const = 0;
+
+ //----------------------------------------------------------------------
+ // Breakpoint functions
+ //----------------------------------------------------------------------
+ virtual Error
+ SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) = 0;
+
+ virtual Error
+ RemoveBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ EnableBreakpoint (lldb::addr_t addr);
+
+ virtual Error
+ DisableBreakpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Watchpoint functions
+ //----------------------------------------------------------------------
+ virtual uint32_t
+ GetMaxWatchpoints () const;
+
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware);
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr);
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ lldb::pid_t
+ GetID() const
+ {
+ return m_pid;
+ }
+
+ lldb::StateType
+ GetState () const;
+
+ bool
+ IsRunning () const
+ {
+ return m_state == lldb::eStateRunning || IsStepping();
+ }
+
+ bool
+ IsStepping () const
+ {
+ return m_state == lldb::eStateStepping;
+ }
+
+ bool
+ CanResume () const
+ {
+ return m_state == lldb::eStateStopped;
+ }
+
+ bool
+ GetByteOrder (lldb::ByteOrder &byte_order) const;
+
+ //----------------------------------------------------------------------
+ // Exit Status
+ //----------------------------------------------------------------------
+ virtual bool
+ GetExitStatus (lldb_private::ExitType *exit_type, int *status, std::string &exit_description);
+
+ virtual bool
+ SetExitStatus (lldb_private::ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange);
+
+ //----------------------------------------------------------------------
+ // Access to threads
+ //----------------------------------------------------------------------
+ NativeThreadProtocolSP
+ GetThreadAtIndex (uint32_t idx);
+
+ NativeThreadProtocolSP
+ GetThreadByID (lldb::tid_t tid);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid)
+ {
+ m_current_thread_id = tid;
+ }
+
+ lldb::tid_t
+ GetCurrentThreadID ()
+ {
+ return m_current_thread_id;
+ }
+
+ NativeThreadProtocolSP
+ GetCurrentThread ()
+ {
+ return GetThreadByID (m_current_thread_id);
+ }
+
+ //----------------------------------------------------------------------
+ // Access to inferior stdio
+ //----------------------------------------------------------------------
+ virtual
+ int GetTerminalFileDescriptor ()
+ {
+ return m_terminal_fd;
+ }
+
+ //----------------------------------------------------------------------
+ // Stop id interface
+ //----------------------------------------------------------------------
+
+ uint32_t
+ GetStopID () const;
+
+ // ---------------------------------------------------------------------
+ // Callbacks for low-level process state changes
+ // ---------------------------------------------------------------------
+ class NativeDelegate
+ {
+ public:
+ virtual
+ ~NativeDelegate () {}
+
+ virtual void
+ InitializeDelegate (NativeProcessProtocol *process) = 0;
+
+ virtual void
+ ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0;
+
+ virtual void
+ DidExec (NativeProcessProtocol *process) = 0;
+ };
+
+ //------------------------------------------------------------------
+ /// Register a native delegate.
+ ///
+ /// Clients can register nofication callbacks by passing in a
+ /// NativeDelegate impl and passing it into this function.
+ ///
+ /// Note: it is required that the lifetime of the
+ /// native_delegate outlive the NativeProcessProtocol.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl to be called when certain events
+ /// happen within the NativeProcessProtocol or related threads.
+ ///
+ /// @return
+ /// true if the delegate was registered successfully;
+ /// false if the delegate was already registered.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate.
+ //------------------------------------------------------------------
+ bool
+ RegisterNativeDelegate (NativeDelegate &native_delegate);
+
+ //------------------------------------------------------------------
+ /// Unregister a native delegate previously registered.
+ ///
+ /// @param[in] native_delegate
+ /// A NativeDelegate impl previously registered with this process.
+ ///
+ /// @return Returns \b true if the NativeDelegate was
+ /// successfully removed from the process, \b false otherwise.
+ ///
+ /// @see NativeProcessProtocol::NativeDelegate
+ //------------------------------------------------------------------
+ bool
+ UnregisterNativeDelegate (NativeDelegate &native_delegate);
+
+ protected:
+ lldb::pid_t m_pid;
+
+ std::vector<NativeThreadProtocolSP> m_threads;
+ lldb::tid_t m_current_thread_id;
+ mutable Mutex m_threads_mutex;
+
+ lldb::StateType m_state;
+ mutable Mutex m_state_mutex;
+
+ lldb_private::ExitType m_exit_type;
+ int m_exit_status;
+ std::string m_exit_description;
+ Mutex m_delegates_mutex;
+ std::vector<NativeDelegate*> m_delegates;
+ NativeBreakpointList m_breakpoint_list;
+ int m_terminal_fd;
+ uint32_t m_stop_id;
+
+ // -----------------------------------------------------------
+ // Internal interface for state handling
+ // -----------------------------------------------------------
+ void
+ SetState (lldb::StateType state, bool notify_delegates = true);
+
+ // Derived classes need not impelment this. It can be used as a
+ // hook to clear internal caches that should be invalidated when
+ // stop ids change.
+ //
+ // Note this function is called with the state mutex obtained
+ // by the caller.
+ virtual void
+ DoStopIDBumped (uint32_t newBumpId);
+
+ // -----------------------------------------------------------
+ // Internal interface for software breakpoints
+ // -----------------------------------------------------------
+ Error
+ SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint);
+
+ virtual Error
+ GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0;
+
+ // -----------------------------------------------------------
+ /// Notify the delegate that an exec occurred.
+ ///
+ /// Provide a mechanism for a delegate to clear out any exec-
+ /// sensitive data.
+ // -----------------------------------------------------------
+ void
+ NotifyDidExec ();
+
+ private:
+
+ void
+ SynchronouslyNotifyProcessStateChanged (lldb::StateType state);
+ };
+}
+
+#endif // #ifndef liblldb_NativeProcessProtocol_h_
diff --git a/source/Host/common/NativeThreadProtocol.cpp b/source/Host/common/NativeThreadProtocol.cpp
new file mode 100644
index 000000000000..6cef5b1fa2d2
--- /dev/null
+++ b/source/Host/common/NativeThreadProtocol.cpp
@@ -0,0 +1,97 @@
+//===-- 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 "NativeThreadProtocol.h"
+
+#include "NativeProcessProtocol.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "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 ();
+}
+
+uint32_t
+NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+ // Default: no translation. Do the real translation where there
+ // is access to the host signal numbers.
+ switch (stop_info.reason)
+ {
+ case eStopReasonSignal:
+ return stop_info.details.signal.signo;
+ break;
+
+ case eStopReasonException:
+ // FIXME verify the way to specify pass-thru here.
+ return static_cast<uint32_t> (stop_info.details.exception.type);
+ break;
+
+ default:
+ assert (0 && "unexpected stop_info.reason found");
+ return 0;
+ }
+}
diff --git a/source/Host/common/NativeThreadProtocol.h b/source/Host/common/NativeThreadProtocol.h
new file mode 100644
index 000000000000..9b404be500b9
--- /dev/null
+++ b/source/Host/common/NativeThreadProtocol.h
@@ -0,0 +1,85 @@
+//===-- NativeThreadProtocol.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadProtocol_h_
+#define liblldb_NativeThreadProtocol_h_
+
+#include <memory>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+
+namespace lldb_private
+{
+ //------------------------------------------------------------------
+ // NativeThreadProtocol
+ //------------------------------------------------------------------
+ class NativeThreadProtocol:
+ public std::enable_shared_from_this<NativeThreadProtocol>
+ {
+ public:
+ NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid);
+
+ virtual ~NativeThreadProtocol()
+ {
+ }
+
+ virtual const char *
+ GetName() = 0;
+
+ virtual lldb::StateType
+ GetState () = 0;
+
+ virtual NativeRegisterContextSP
+ GetRegisterContext () = 0;
+
+ virtual Error
+ ReadRegister (uint32_t reg, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegister (uint32_t reg, const RegisterValue &reg_value);
+
+ virtual Error
+ SaveAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual Error
+ RestoreAllRegisters (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ GetStopReason (ThreadStopInfo &stop_info) = 0;
+
+ virtual uint32_t
+ TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const;
+
+ lldb::tid_t
+ GetID() const
+ {
+ return m_tid;
+ }
+
+ NativeProcessProtocolSP
+ GetProcess ();
+
+ // ---------------------------------------------------------------------
+ // Thread-specific watchpoints
+ // ---------------------------------------------------------------------
+ virtual Error
+ SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
+
+ virtual Error
+ RemoveWatchpoint (lldb::addr_t addr) = 0;
+
+ protected:
+ NativeProcessProtocolWP m_process_wp;
+ lldb::tid_t m_tid;
+ };
+}
+
+#endif // #ifndef liblldb_NativeThreadProtocol_h_
diff --git a/source/Host/common/OptionParser.cpp b/source/Host/common/OptionParser.cpp
index cf133597cb84..a91e764bfe3b 100644
--- a/source/Host/common/OptionParser.cpp
+++ b/source/Host/common/OptionParser.cpp
@@ -8,11 +8,10 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/OptionParser.h"
-
-#if (!defined( _MSC_VER ) && defined( _WIN32 ))
-#define _BSD_SOURCE // Required so that getopt.h defines optreset
-#endif
#include "lldb/Host/HostGetOpt.h"
+#include "lldb/lldb-private-types.h"
+
+#include <vector>
using namespace lldb_private;
@@ -40,7 +39,19 @@ OptionParser::Parse (int argc,
const Option *longopts,
int *longindex)
{
- return getopt_long_only(argc, argv, optstring, (const option*)longopts, 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*
diff --git a/source/Host/common/Pipe.cpp b/source/Host/common/Pipe.cpp
new file mode 100644
index 000000000000..4db0e32c93b7
--- /dev/null
+++ b/source/Host/common/Pipe.cpp
@@ -0,0 +1,171 @@
+//===-- Pipe.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/Pipe.h"
+
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace lldb_private;
+
+int Pipe::kInvalidDescriptor = -1;
+
+enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+Pipe::Pipe()
+{
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+}
+
+Pipe::~Pipe()
+{
+ Close();
+}
+
+bool
+Pipe::Open()
+{
+ if (IsValid())
+ return true;
+
+#ifdef _WIN32
+ if (::_pipe(m_fds, 256, O_BINARY) == 0)
+ return true;
+#else
+ if (::pipe(m_fds) == 0)
+ return true;
+#endif
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return false;
+}
+
+int
+Pipe::GetReadFileDescriptor() const
+{
+ return m_fds[READ];
+}
+
+int
+Pipe::GetWriteFileDescriptor() const
+{
+ return m_fds[WRITE];
+}
+
+int
+Pipe::ReleaseReadFileDescriptor()
+{
+ const int fd = m_fds[READ];
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ return fd;
+}
+
+int
+Pipe::ReleaseWriteFileDescriptor()
+{
+ const int fd = m_fds[WRITE];
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return fd;
+}
+
+void
+Pipe::Close()
+{
+ CloseReadFileDescriptor();
+ CloseWriteFileDescriptor();
+}
+
+bool
+Pipe::ReadDescriptorIsValid() const
+{
+ return m_fds[READ] != Pipe::kInvalidDescriptor;
+}
+
+bool
+Pipe::WriteDescriptorIsValid() const
+{
+ return m_fds[WRITE] != Pipe::kInvalidDescriptor;
+}
+
+bool
+Pipe::IsValid() const
+{
+ return ReadDescriptorIsValid() && WriteDescriptorIsValid();
+}
+
+bool
+Pipe::CloseReadFileDescriptor()
+{
+ if (ReadDescriptorIsValid())
+ {
+ int err;
+#ifdef _WIN32
+ err = _close(m_fds[READ]);
+#else
+ err = close(m_fds[READ]);
+#endif
+ m_fds[READ] = Pipe::kInvalidDescriptor;
+ return err == 0;
+ }
+ return true;
+}
+
+bool
+Pipe::CloseWriteFileDescriptor()
+{
+ if (WriteDescriptorIsValid())
+ {
+ int err;
+#ifdef _WIN32
+ err = _close(m_fds[WRITE]);
+#else
+ err = close(m_fds[WRITE]);
+#endif
+ m_fds[WRITE] = Pipe::kInvalidDescriptor;
+ return err == 0;
+ }
+ return true;
+}
+
+
+size_t
+Pipe::Read (void *buf, size_t num_bytes)
+{
+ if (ReadDescriptorIsValid())
+ {
+ const int fd = GetReadFileDescriptor();
+#ifdef _WIN32
+ return _read (fd, (char *)buf, num_bytes);
+#else
+ return read (fd, buf, num_bytes);
+#endif
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call read
+}
+
+size_t
+Pipe::Write (const void *buf, size_t num_bytes)
+{
+ if (WriteDescriptorIsValid())
+ {
+ const int fd = GetWriteFileDescriptor();
+#ifdef _WIN32
+ return _write (fd, (char *)buf, num_bytes);
+#else
+ return write (fd, buf, num_bytes);
+#endif
+ }
+ return 0; // Return 0 since errno won't be set if we didn't call write
+}
+
diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp
new file mode 100644
index 000000000000..31e3228497ec
--- /dev/null
+++ b/source/Host/common/Socket.cpp
@@ -0,0 +1,662 @@
+//===-- 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/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/SocketAddress.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+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)
+
+Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close)
+ : IOObject(eFDTypeSocket, should_close)
+ , m_protocol(protocol)
+ , m_socket(socket)
+{
+
+}
+
+Socket::~Socket()
+{
+ Close();
+}
+
+Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket)
+{
+ // Store the result in a unique_ptr in case we error out, the memory will get correctly freed.
+ std::unique_ptr<Socket> final_socket;
+ NativeSocket sock = kInvalidSocketValue;
+ Error error;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ if (log)
+ log->Printf ("Socket::TcpConnect (host/port = %s)", host_and_port.data());
+
+ 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;
+
+ // Create the socket
+ sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sock == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // Since they both refer to the same socket descriptor, arbitrarily choose the send socket to
+ // be the owner.
+ final_socket.reset(new Socket(sock, ProtocolTcp, true));
+
+ // Enable local address reuse
+ final_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+
+ int inet_pton_result = ::inet_pton (AF_INET, 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 (AF_INET, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ if (inet_pton_result == -1)
+ error.SetErrorToErrno();
+ else
+ error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
+
+ return error;
+ }
+ }
+
+ if (-1 == ::connect (sock, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ final_socket->SetOption(IPPROTO_TCP, TCP_NODELAY, 1);
+ error.Clear();
+ socket = final_socket.release();
+ return error;
+}
+
+Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate)
+{
+ std::unique_ptr<Socket> listen_socket;
+ NativeSocket listen_sock = kInvalidSocketValue;
+ Error error;
+
+ const sa_family_t family = AF_INET;
+ const int socktype = SOCK_STREAM;
+ const int protocol = IPPROTO_TCP;
+ listen_sock = ::socket (family, socktype, protocol);
+ if (listen_sock == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ listen_socket.reset(new Socket(listen_sock, ProtocolTcp, true));
+
+ // enable local address reuse
+ listen_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("ConnectionFileDescriptor::SocketListen (%s)", host_and_port.data());
+
+ 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;
+
+ SocketAddress anyaddr;
+ if (anyaddr.SetToAnyAddress (family, port))
+ {
+ int err = ::bind (listen_sock, anyaddr, anyaddr.GetLength());
+ if (err == -1)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ err = ::listen (listen_sock, 1);
+ if (err == -1)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ // 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->GetPortNumber();
+
+ // 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::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket)
+{
+ Error error;
+ std::string host_str;
+ std::string port_str;
+ int32_t port;
+ if (!DecodeHostAndPort(host_and_port, host_str, port_str, port, &error))
+ return error;
+
+ const sa_family_t family = AF_INET;
+ const int socktype = SOCK_STREAM;
+ 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<Socket> 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 = ::accept (this->GetNativeSocket(), (struct sockaddr *)&accept_addr, &accept_addr_len);
+
+ if (sock == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError()
+ error.SetErrorToErrno();
+ 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;
+ // Since both sockets have the same descriptor, arbitrarily choose the send
+ // socket to be the owner.
+ accepted_socket.reset(new Socket(sock, ProtocolTcp, 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->SetOption (IPPROTO_TCP, TCP_NODELAY, 1);
+ error.Clear();
+ socket = accepted_socket.release();
+ return error;
+
+}
+
+Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket)
+{
+ std::unique_ptr<Socket> final_send_socket;
+ std::unique_ptr<Socket> final_recv_socket;
+ NativeSocket final_send_fd = kInvalidSocketValue;
+ NativeSocket final_recv_fd = kInvalidSocketValue;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("Socket::UdpConnect (host/port = %s)", 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;
+
+ // 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_fd = ::socket (AF_INET, SOCK_DGRAM, 0);
+ if (final_recv_fd == kInvalidSocketValue)
+ {
+ // Socket creation failed...
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ final_recv_socket.reset(new Socket(final_recv_fd, ProtocolUdp, true));
+
+ // Socket was created, now lets bind to the requested port
+ SocketAddress addr;
+ addr.SetToAnyAddress (AF_INET, 0);
+
+ if (::bind (final_recv_fd, addr, addr.GetLength()) == -1)
+ {
+ // Bind failed...
+ // TODO: On Windows use WSAGetLastError()
+ error.SetErrorToErrno();
+ }
+ }
+
+ 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 = NULL;
+
+ ::memset (&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ 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 != NULL;
+ service_info_ptr = service_info_ptr->ai_next)
+ {
+ final_send_fd = ::socket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol);
+
+ if (final_send_fd != kInvalidSocketValue)
+ {
+ final_send_socket.reset(new Socket(final_send_fd, ProtocolUdp, true));
+ final_send_socket->m_udp_send_sockaddr = service_info_ptr;
+ break;
+ }
+ else
+ continue;
+ }
+
+ :: freeaddrinfo (service_info_list);
+
+ if (final_send_fd == kInvalidSocketValue)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ send_socket = final_send_socket.release();
+ recv_socket = final_recv_socket.release();
+ error.Clear();
+ return error;
+}
+
+Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket)
+{
+ Error error;
+#ifndef LLDB_DISABLE_POSIX
+ std::unique_ptr<Socket> final_socket;
+
+ // Open the socket that was passed in as an option
+ struct sockaddr_un saddr_un;
+ int fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ final_socket.reset(new Socket(fd, ProtocolUnixDomain, true));
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::connect (fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ socket = final_socket.release();
+#else
+ error.SetErrorString("Unix domain sockets are not supported on this platform.");
+#endif
+ return error;
+}
+
+Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket)
+{
+ Error error;
+#ifndef LLDB_DISABLE_POSIX
+ struct sockaddr_un saddr_un;
+ std::unique_ptr<Socket> listen_socket;
+ std::unique_ptr<Socket> final_socket;
+ NativeSocket listen_fd = kInvalidSocketValue;
+ NativeSocket socket_fd = kInvalidSocketValue;
+
+ listen_fd = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (listen_fd == kInvalidSocketValue)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ listen_socket.reset(new Socket(listen_fd, ProtocolUnixDomain, true));
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ FileSystem::Unlink(name.data());
+ bool success = false;
+ if (::bind (listen_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
+ {
+ if (::listen (listen_fd, 5) == 0)
+ {
+ socket_fd = ::accept (listen_fd, NULL, 0);
+ if (socket_fd > 0)
+ {
+ final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true));
+ success = true;
+ }
+ }
+ }
+
+ if (!success)
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+ // We are done with the listen port
+ listen_socket.reset();
+
+ socket = final_socket.release();
+#else
+ error.SetErrorString("Unix domain sockets are not supported on this platform.");
+#endif
+ 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))
+ {
+ port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ }
+ }
+
+ // 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();
+ port = Args::StringToSInt32(host_and_port.data(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ port_str = host_and_port;
+ 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);
+ // TODO: Use WSAGetLastError on windows.
+ } while (bytes_received < 0 && errno == EINTR);
+
+ if (bytes_received < 0)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_received;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | 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
+ {
+ if (m_protocol == ProtocolUdp)
+ {
+ bytes_sent = ::sendto (m_socket,
+ static_cast<const char*>(buf),
+ num_bytes,
+ 0,
+ m_udp_send_sockaddr,
+ m_udp_send_sockaddr.GetLength());
+ }
+ else
+ bytes_sent = ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0);
+ // TODO: Use WSAGetLastError on windows.
+ } while (bytes_sent < 0 && errno == EINTR);
+
+ if (bytes_sent < 0)
+ {
+ // TODO: On Windows, use WSAGEtLastError.
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_sent;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ 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)
+ {
+ // TODO: On Windows, use WSAGetLastError().
+ error.SetErrorToErrno();
+ }
+
+ 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));
+}
+
+uint16_t Socket::GetPortNumber(const NativeSocket& socket)
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ if (socket >= 0)
+ {
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (socket, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+ }
+ return 0;
+}
+
+// Return the port number that is being used by the socket.
+uint16_t Socket::GetPortNumber() const
+{
+ return GetPortNumber(m_socket);
+}
diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp
index 75f3cd13f586..a952a83185fb 100644
--- a/source/Host/common/SocketAddress.cpp
+++ b/source/Host/common/SocketAddress.cpp
@@ -11,7 +11,7 @@
#include <stddef.h>
// C Includes
-#if !defined(_MSC_VER)
+#if !defined(_WIN32)
#include <arpa/inet.h>
#endif
#include <assert.h>
@@ -90,6 +90,7 @@ GetFamilyLength (sa_family_t family)
case AF_INET6: return sizeof(struct sockaddr_in6);
}
assert(0 && "Unsupported address family");
+ return 0;
}
socklen_t
diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp
new file mode 100644
index 000000000000..fe2f504ebc71
--- /dev/null
+++ b/source/Host/common/SoftwareBreakpoint.cpp
@@ -0,0 +1,296 @@
+//===-- 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 "SoftwareBreakpoint.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+
+#include "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.
+ lldb::addr_t bytes_read = 0;
+
+ Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (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 != static_cast<lldb::addr_t> (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, 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, bytes_read);
+ }
+
+ // Write a software breakpoint in place of the original opcode.
+ lldb::addr_t bytes_written = 0;
+ error = process.WriteMemory (addr, bp_opcode_bytes, static_cast<lldb::addr_t> (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 != static_cast<lldb::addr_t> (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, bytes_written);
+ if (log)
+ log->PutCString (error.AsCString ());
+ return error;
+ }
+
+ uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+ lldb::addr_t verify_bytes_read = 0;
+ error = process.ReadMemory(addr, verify_bp_opcode_bytes, static_cast<lldb::addr_t> (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 != static_cast<lldb::addr_t> (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, 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, 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 breakoint 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
+ lldb::addr_t bytes_read = 0;
+ error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
+ if (error.Success () && (bytes_read < static_cast<lldb::addr_t> (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, bytes_read);
+ }
+ if (error.Success ())
+ {
+ bool verify = false;
+ // Make sure we have the a 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.
+ lldb::addr_t bytes_written = 0;
+ error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
+ if (error.Success () && (bytes_written < static_cast<lldb::addr_t> (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, 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
+
+ lldb::addr_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 < static_cast<lldb::addr_t> (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, 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)
+ 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/source/Host/common/SoftwareBreakpoint.h b/source/Host/common/SoftwareBreakpoint.h
new file mode 100644
index 000000000000..1fed19eca612
--- /dev/null
+++ b/source/Host/common/SoftwareBreakpoint.h
@@ -0,0 +1,51 @@
+//===-- SoftwareBreakpoint.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SoftwareBreakpoint_h_
+#define liblldb_SoftwareBreakpoint_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "NativeBreakpoint.h"
+
+namespace lldb_private
+{
+ class SoftwareBreakpoint : public NativeBreakpoint
+ {
+ public:
+ static Error
+ CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn);
+
+ SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size);
+
+ protected:
+ Error
+ DoEnable () override;
+
+ Error
+ DoDisable () override;
+
+ bool
+ IsSoftwareBreakpoint () const override;
+
+ private:
+ /// Max number of bytes that a software trap opcode sequence can occupy.
+ static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
+ NativeProcessProtocol &m_process;
+ uint8_t m_saved_opcodes [MAX_TRAP_OPCODE_SIZE];
+ uint8_t m_trap_opcodes [MAX_TRAP_OPCODE_SIZE];
+ const size_t m_opcode_size;
+
+ static Error
+ EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes);
+
+ };
+}
+
+#endif // #ifndef liblldb_SoftwareBreakpoint_h_
diff --git a/source/Host/common/Terminal.cpp b/source/Host/common/Terminal.cpp
index f63c468bb92c..ca46eb0f744b 100644
--- a/source/Host/common/Terminal.cpp
+++ b/source/Host/common/Terminal.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Host/Terminal.h"
+#include "llvm/ADT/STLExtras.h"
#include <fcntl.h>
#include <signal.h>
@@ -250,7 +251,7 @@ TerminalState::TTYStateIsValid() const
bool
TerminalState::ProcessGroupIsValid() const
{
- return m_process_group != -1;
+ return static_cast<int32_t>(m_process_group) != -1;
}
//------------------------------------------------------------------
@@ -274,7 +275,7 @@ TerminalStateSwitcher::~TerminalStateSwitcher ()
uint32_t
TerminalStateSwitcher::GetNumberOfStates() const
{
- return sizeof(m_ttystates)/sizeof(TerminalState);
+ return llvm::array_lengthof(m_ttystates);
}
//------------------------------------------------------------------
diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp
index c4a6ca37e9c4..dc092e86d78b 100644
--- a/source/Host/freebsd/Host.cpp
+++ b/source/Host/freebsd/Host.cpp
@@ -13,7 +13,6 @@
#include <execinfo.h>
#include <sys/types.h>
#include <sys/user.h>
-#include <sys/utsname.h>
#include <sys/sysctl.h>
#include <sys/proc.h>
@@ -27,6 +26,7 @@
#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"
@@ -39,8 +39,9 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Utility/CleanUp.h"
-#include "llvm/Support/Host.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
+#include "llvm/Support/Host.h"
extern "C" {
extern char **environ;
@@ -86,7 +87,40 @@ Host::ThreadCreated (const char *thread_name)
std::string
Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
{
+ struct kinfo_proc *kp = nullptr, *nkp;
+ size_t len = 0;
+ int error;
+ int name[4] = {
+ CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, (int)pid
+ };
+
+ while (1) {
+ error = sysctl(name, 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 std::string();
+ }
+ kp = nkp;
+ continue;
+ }
+ if (error != 0)
+ len = 0;
+ break;
+ }
+
std::string thread_name;
+ for (size_t i = 0; i < len / sizeof(*kp); i++) {
+ if (kp[i].ki_tid == (int)tid) {
+ thread_name = kp[i].ki_tdname;
+ break;
+ }
+ }
+ free(kp);
return thread_name;
}
@@ -134,56 +168,6 @@ Host::GetEnvironment (StringList &env)
return env.GetSize();
}
-bool
-Host::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
-Host::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
-Host::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;
-}
-
static bool
GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info)
@@ -240,7 +224,7 @@ GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
{
if (process_info.ProcessIDIsValid())
{
- process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
return true;
}
process_info.GetArchitecture().Clear();
@@ -306,9 +290,9 @@ Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstance
const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
bool all_users = match_info.GetMatchAllUsers();
- const lldb::pid_t our_pid = getpid();
+ const ::pid_t our_pid = getpid();
const uid_t our_uid = getuid();
- for (int i = 0; i < actual_pid_count; i++)
+ for (size_t i = 0; i < actual_pid_count; i++)
{
const struct kinfo_proc &kinfo = kinfos[i];
const bool kinfo_user_matches = (all_users ||
@@ -418,3 +402,11 @@ Host::GetAuxvData(lldb_private::Process *process)
done:
return buf_sp;
}
+
+const UnixSignalsSP&
+Host::GetUnixSignals ()
+{
+ static const lldb_private::UnixSignalsSP s_unix_signals_sp (new FreeBSDSignals ());
+ return s_unix_signals_sp;
+}
+
diff --git a/source/Host/freebsd/HostInfoFreeBSD.cpp b/source/Host/freebsd/HostInfoFreeBSD.cpp
new file mode 100644
index 000000000000..78458259f0a2
--- /dev/null
+++ b/source/Host/freebsd/HostInfoFreeBSD.cpp
@@ -0,0 +1,85 @@
+//===-- 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;
+
+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/source/Host/posix/FileSystem.cpp b/source/Host/posix/FileSystem.cpp
new file mode 100644
index 000000000000..571316811142
--- /dev/null
+++ b/source/Host/posix/FileSystem.cpp
@@ -0,0 +1,201 @@
+//===-- 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 <sys/stat.h>
+#include <sys/types.h>
+
+// lldb Includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FileSpec::PathSyntax
+FileSystem::GetNativePathSyntax()
+{
+ return FileSpec::ePathSyntaxPosix;
+}
+
+Error
+FileSystem::MakeDirectory(const char *path, uint32_t file_permissions)
+{
+ Error error;
+ if (path && path[0])
+ {
+ if (::mkdir(path, file_permissions) != 0)
+ {
+ error.SetErrorToErrno();
+ switch (error.GetError())
+ {
+ case ENOENT:
+ {
+ // Parent directory doesn't exist, so lets make it if we can
+ FileSpec spec(path, false);
+ if (spec.GetDirectory() && spec.GetFilename())
+ {
+ // Make the parent directory and try again
+ Error error2 = MakeDirectory(spec.GetDirectory().GetCString(), file_permissions);
+ if (error2.Success())
+ {
+ // Try and make the directory again now that the parent directory was made successfully
+ if (::mkdir(path, file_permissions) == 0)
+ error.Clear();
+ else
+ error.SetErrorToErrno();
+ }
+ }
+ }
+ break;
+
+ case EEXIST:
+ {
+ FileSpec path_spec(path, false);
+ if (path_spec.IsDirectory())
+ error.Clear(); // It is a directory and it already exists
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty path");
+ }
+ return error;
+}
+
+Error
+FileSystem::DeleteDirectory(const char *path, bool recurse)
+{
+ Error error;
+ if (path && path[0])
+ {
+ if (recurse)
+ {
+ StreamString command;
+ command.Printf("rm -rf \"%s\"", path);
+ int status = ::system(command.GetString().c_str());
+ if (status != 0)
+ error.SetError(status, eErrorTypeGeneric);
+ }
+ else
+ {
+ if (::rmdir(path) != 0)
+ error.SetErrorToErrno();
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty path");
+ }
+ return error;
+}
+
+Error
+FileSystem::GetFilePermissions(const char *path, uint32_t &file_permissions)
+{
+ Error error;
+ struct stat file_stats;
+ if (::stat(path, &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 char *path, uint32_t file_permissions)
+{
+ Error error;
+ if (::chmod(path, 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::Symlink(const char *src, const char *dst)
+{
+ Error error;
+ if (::symlink(dst, src) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Unlink(const char *path)
+{
+ Error error;
+ if (::unlink(path) == -1)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Error
+FileSystem::Readlink(const char *path, char *buf, size_t buf_len)
+{
+ Error error;
+ ssize_t count = ::readlink(path, buf, buf_len);
+ if (count < 0)
+ error.SetErrorToErrno();
+ else if (static_cast<size_t>(count) < (buf_len - 1))
+ buf[count] = '\0'; // Success
+ else
+ error.SetErrorString("'buf' buffer is too small to contain link contents");
+ return error;
+}
+
+bool
+FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high)
+{
+#if defined(__APPLE__)
+ StreamString md5_cmd_line;
+ md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str());
+ std::string hash_string;
+ Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60);
+ if (err.Fail())
+ return false;
+ // a correctly formed MD5 is 16-bytes, that is 32 hex digits
+ // if the output is any other length it is probably wrong
+ if (hash_string.size() != 32)
+ return false;
+ std::string part1(hash_string, 0, 16);
+ std::string part2(hash_string, 16);
+ const char *part1_cstr = part1.c_str();
+ const char *part2_cstr = part2.c_str();
+ high = ::strtoull(part1_cstr, NULL, 16);
+ low = ::strtoull(part2_cstr, NULL, 16);
+ return true;
+#else
+ // your own MD5 implementation here
+ return false;
+#endif
+}
diff --git a/source/Host/posix/HostInfoPosix.cpp b/source/Host/posix/HostInfoPosix.cpp
new file mode 100644
index 000000000000..77fdc2b61a31
--- /dev/null
+++ b/source/Host/posix/HostInfoPosix.cpp
@@ -0,0 +1,193 @@
+//===-- HostInfoPosix.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-python.h"
+
+#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 <netdb.h>
+#include <pwd.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;
+}
+
+const char *
+HostInfoPosix::LookupUserName(uint32_t uid, std::string &user_name)
+{
+ 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();
+ }
+ }
+ user_name.clear();
+ return NULL;
+}
+
+const char *
+HostInfoPosix::LookupGroupName(uint32_t gid, std::string &group_name)
+{
+ 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();
+ 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();
+}
+
+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)
+ {
+ // First terminate the raw path at the start of lib.
+ *lib_pos = '\0';
+
+ // Now write in bin in place of lib.
+ ::strncpy(lib_pos, "/bin", PATH_MAX - (lib_pos - raw_path));
+
+ 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)
+{
+ 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));
+
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+ os.flush();
+
+ // 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;
+}
diff --git a/source/Host/posix/HostProcessPosix.cpp b/source/Host/posix/HostProcessPosix.cpp
new file mode 100644
index 000000000000..4618de4711de
--- /dev/null
+++ b/source/Host/posix/HostProcessPosix.cpp
@@ -0,0 +1,103 @@
+//===-- HostProcessWindows.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/HostProcessPosix.h"
+#include "lldb/Host/FileSystem.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+#include <limits.h>
+
+using namespace lldb_private;
+
+const lldb::pid_t HostProcessPosix::kInvalidProcessId = 0;
+
+HostProcessPosix::HostProcessPosix()
+: m_pid(kInvalidProcessId)
+{
+}
+
+HostProcessPosix::~HostProcessPosix()
+{
+}
+
+Error HostProcessPosix::Create(lldb::pid_t pid)
+{
+ Error error;
+ if (pid == kInvalidProcessId)
+ error.SetErrorString("Attempt to create an invalid process");
+
+ m_pid = pid;
+ return error;
+}
+
+Error HostProcessPosix::Signal(int signo) const
+{
+ if (m_pid <= 0)
+ {
+ Error error;
+ error.SetErrorString("HostProcessPosix refers to an invalid process");
+ return error;
+ }
+
+ return HostProcessPosix::Signal(m_pid, signo);
+}
+
+Error HostProcessPosix::Signal(lldb::pid_t pid, int signo)
+{
+ Error error;
+
+ if (-1 == ::kill(pid, signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+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];
+ char exe_path[PATH_MAX] = "";
+ if (snprintf (link_path, PATH_MAX, "/proc/%" PRIu64 "/exe", m_pid) <= 0)
+ {
+ error.SetErrorString("Unable to build /proc/<pid>/exe string");
+ return error;
+ }
+
+ error = FileSystem::Readlink(link_path, exe_path, llvm::array_lengthof(exe_path));
+ if (!error.Success())
+ return error;
+
+ const ssize_t len = strlen(exe_path);
+ // If the binary has been deleted, the link name has " (deleted)" appended.
+ // Remove if there.
+ static const ssize_t deleted_len = strlen(" (deleted)");
+ if (len > deleted_len &&
+ !strcmp(exe_path + len - deleted_len, " (deleted)"))
+ {
+ exe_path[len - deleted_len] = 0;
+ }
+
+ file_spec.SetFile(exe_path, false);
+ return error;
+}
+
+lldb::pid_t HostProcessPosix::GetProcessId() const
+{
+ return m_pid;
+}
+
+bool HostProcessPosix::IsRunning() const
+{
+ // Send this process the null signal. If it succeeds the process is running.
+ Error error = Signal(0);
+ return error.Success();
+}