diff options
Diffstat (limited to 'source/Host/common')
37 files changed, 7648 insertions, 9745 deletions
diff --git a/source/Host/common/Condition.cpp b/source/Host/common/Condition.cpp deleted file mode 100644 index 1c1afb4add7e..000000000000 --- a/source/Host/common/Condition.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===-- Condition.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <errno.h> - -#include "lldb/Host/Condition.h" -#include "lldb/Host/TimeValue.h" - - -using namespace lldb_private; - -#ifndef _WIN32 - -//---------------------------------------------------------------------- -// Default constructor -// -// The default constructor will initialize a new pthread condition -// and maintain the condition in the object state. -//---------------------------------------------------------------------- -Condition::Condition () : - m_condition() -{ - ::pthread_cond_init (&m_condition, NULL); -} - -//---------------------------------------------------------------------- -// Destructor -// -// Destroys the pthread condition that the object owns. -//---------------------------------------------------------------------- -Condition::~Condition () -{ - ::pthread_cond_destroy (&m_condition); -} - -//---------------------------------------------------------------------- -// Unblock all threads waiting for a condition variable -//---------------------------------------------------------------------- -int -Condition::Broadcast () -{ - return ::pthread_cond_broadcast (&m_condition); -} - -//---------------------------------------------------------------------- -// Unblocks one thread waiting for the condition variable -//---------------------------------------------------------------------- -int -Condition::Signal () -{ - return ::pthread_cond_signal (&m_condition); -} - -//---------------------------------------------------------------------- -// The Wait() function atomically blocks the current thread -// waiting on the owned condition variable, and unblocks the mutex -// specified by "mutex". The waiting thread unblocks only after -// another thread calls Signal(), or Broadcast() with the same -// condition variable, or if "abstime" is valid (non-NULL) this -// function will return when the system time reaches the time -// specified in "abstime". If "abstime" is NULL this function will -// wait for an infinite amount of time for the condition variable -// to be signaled or broadcasted. -// -// The current thread re-acquires the lock on "mutex". -//---------------------------------------------------------------------- -int -Condition::Wait (Mutex &mutex, const TimeValue *abstime, bool *timed_out) -{ - int err = 0; - do - { - if (abstime && abstime->IsValid()) - { - struct timespec abstime_ts = abstime->GetAsTimeSpec(); - err = ::pthread_cond_timedwait (&m_condition, mutex.GetMutex(), &abstime_ts); - } - else - err = ::pthread_cond_wait (&m_condition, mutex.GetMutex()); - } while (err == EINTR); - - if (timed_out != NULL) - { - if (err == ETIMEDOUT) - *timed_out = true; - else - *timed_out = false; - } - - return err; -} - -#endif - -//---------------------------------------------------------------------- -// Get accessor to the pthread condition object -//---------------------------------------------------------------------- -lldb::condition_t * -Condition::GetCondition() -{ - return &m_condition; -} diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp index d7209feb46db..a600c61c8e6b 100644 --- a/source/Host/common/Editline.cpp +++ b/source/Host/common/Editline.cpp @@ -11,15 +11,16 @@ #include <iostream> #include <limits.h> -#include "lldb/Host/Editline.h" -#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Core/Error.h" -#include "lldb/Core/StringList.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/StringList.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/Editline.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/SelectHelper.h" using namespace lldb_private; using namespace lldb_private::line_editor; @@ -33,14 +34,17 @@ using namespace lldb_private::line_editor; // the function declaraction has been hoisted here. #if defined(__APPLE__) extern "C" { - int setupterm(char *term, int fildes, int *errret); +int setupterm(char *term, int fildes, int *errret); } #define USE_SETUPTERM_WORKAROUND #endif -// Editline uses careful cursor management to achieve the illusion of editing a multi-line block of text -// with a single line editor. Preserving this illusion requires fairly careful management of cursor -// state. Read and understand the relationship between DisplayInput(), MoveCursor(), SetCurrentLine(), +// Editline uses careful cursor management to achieve the illusion of editing a +// multi-line block of text +// with a single line editor. Preserving this illusion requires fairly careful +// management of cursor +// state. Read and understand the relationship between DisplayInput(), +// MoveCursor(), SetCurrentLine(), // and SaveEditedLine() before making changes. #define ESCAPE "\x1b" @@ -62,7 +66,8 @@ extern "C" { #define EditLineConstString(str) str #define EditLineStringFormatSpec "%s" -// use #defines so wide version functions and structs will resolve to old versions +// use #defines so wide version functions and structs will resolve to old +// versions // for case of libedit not built with wide char support #define history_w history #define history_winit history_init @@ -75,1431 +80,1290 @@ extern "C" { #define el_wgetc el_getc #define el_wpush el_push #define el_wparse el_parse -#define el_wset el_set -#define el_wget el_get +#define el_wset el_set +#define el_wget el_get #define el_wline el_line #define el_winsertstr el_insertstr -#define el_wdeletestr el_deletestr +#define el_wdeletestr el_deletestr #endif // #if LLDB_EDITLINE_USE_WCHAR -bool -IsOnlySpaces (const EditLineStringType & content) -{ - for (wchar_t ch : content) - { - if (ch != EditLineCharType(' ')) - return false; - } - return true; +bool IsOnlySpaces(const EditLineStringType &content) { + for (wchar_t ch : content) { + if (ch != EditLineCharType(' ')) + return false; + } + return true; } -EditLineStringType -CombineLines (const std::vector<EditLineStringType> & lines) -{ - EditLineStringStreamType combined_stream; - for (EditLineStringType line : lines) - { - combined_stream << line.c_str() << "\n"; - } - return combined_stream.str(); +EditLineStringType CombineLines(const std::vector<EditLineStringType> &lines) { + EditLineStringStreamType combined_stream; + for (EditLineStringType line : lines) { + combined_stream << line.c_str() << "\n"; + } + return combined_stream.str(); } -std::vector<EditLineStringType> -SplitLines (const EditLineStringType & input) -{ - std::vector<EditLineStringType> result; - size_t start = 0; - while (start < input.length()) - { - size_t end = input.find ('\n', start); - if (end == std::string::npos) - { - result.insert (result.end(), input.substr (start)); - break; - } - result.insert (result.end(), input.substr (start, end - start)); - start = end + 1; +std::vector<EditLineStringType> SplitLines(const EditLineStringType &input) { + std::vector<EditLineStringType> result; + size_t start = 0; + while (start < input.length()) { + size_t end = input.find('\n', start); + if (end == std::string::npos) { + result.insert(result.end(), input.substr(start)); + break; } - return result; + result.insert(result.end(), input.substr(start, end - start)); + start = end + 1; + } + return result; } -EditLineStringType -FixIndentation (const EditLineStringType & line, int indent_correction) -{ - if (indent_correction == 0) - return line; - if (indent_correction < 0) - return line.substr (-indent_correction); - return EditLineStringType (indent_correction, EditLineCharType(' ')) + line; +EditLineStringType FixIndentation(const EditLineStringType &line, + int indent_correction) { + if (indent_correction == 0) + return line; + if (indent_correction < 0) + return line.substr(-indent_correction); + return EditLineStringType(indent_correction, EditLineCharType(' ')) + line; } -int -GetIndentation (const EditLineStringType & line) -{ - int space_count = 0; - for (EditLineCharType ch : line) - { - if (ch != EditLineCharType(' ')) - break; - ++space_count; - } - return space_count; +int GetIndentation(const EditLineStringType &line) { + int space_count = 0; + for (EditLineCharType ch : line) { + if (ch != EditLineCharType(' ')) + break; + ++space_count; + } + return space_count; } -bool -IsInputPending (FILE * file) -{ - // FIXME: This will be broken on Windows if we ever re-enable Editline. You can't use select - // on something that isn't a socket. This will have to be re-written to not use a FILE*, but - // instead use some kind of yet-to-be-created abstraction that select-like functionality on - // non-socket objects. - const int fd = fileno (file); - fd_set fds; - FD_ZERO (&fds); - FD_SET (fd, &fds); - timeval timeout = { 0, 0 }; - return select (fd + 1, &fds, NULL, NULL, &timeout); +bool IsInputPending(FILE *file) { + // FIXME: This will be broken on Windows if we ever re-enable Editline. You + // can't use select + // on something that isn't a socket. This will have to be re-written to not + // use a FILE*, but + // instead use some kind of yet-to-be-created abstraction that select-like + // functionality on + // non-socket objects. + const int fd = fileno(file); + SelectHelper select_helper; + select_helper.SetTimeout(std::chrono::microseconds(0)); + select_helper.FDSetRead(fd); + return select_helper.Select().Success(); } -namespace lldb_private -{ - namespace line_editor - { - typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP; - - // EditlineHistory objects are sometimes shared between multiple - // Editline instances with the same program name. - - class EditlineHistory - { - private: - // Use static GetHistory() function to get a EditlineHistorySP to one of these objects - EditlineHistory (const std::string &prefix, uint32_t size, bool unique_entries) : - m_history (NULL), - m_event (), - m_prefix (prefix), - m_path () - { - m_history = history_winit(); - history_w (m_history, &m_event, H_SETSIZE, size); - if (unique_entries) - history_w (m_history, &m_event, H_SETUNIQUE, 1); - } - - const char * - GetHistoryFilePath() - { - if (m_path.empty() && m_history && !m_prefix.empty()) - { - FileSpec parent_path{"~/.lldb", true}; - char history_path[PATH_MAX]; - if (FileSystem::MakeDirectory(parent_path, lldb::eFilePermissionsDirectoryDefault).Success()) - { - snprintf (history_path, sizeof (history_path), "~/.lldb/%s-history", m_prefix.c_str()); - } - else - { - snprintf (history_path, sizeof (history_path), "~/%s-widehistory", m_prefix.c_str()); - } - m_path = FileSpec (history_path, true).GetPath(); - } - if (m_path.empty()) - return NULL; - return m_path.c_str(); - } - - public: - - ~EditlineHistory() - { - Save(); - - if (m_history) - { - history_wend (m_history); - m_history = NULL; - } - } - - static EditlineHistorySP - GetHistory (const std::string &prefix) - { - typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap; - static std::recursive_mutex g_mutex; - static WeakHistoryMap g_weak_map; - std::lock_guard<std::recursive_mutex> guard(g_mutex); - WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix); - EditlineHistorySP history_sp; - if (pos != g_weak_map.end()) - { - history_sp = pos->second.lock(); - if (history_sp) - return history_sp; - g_weak_map.erase (pos); - } - history_sp.reset (new EditlineHistory (prefix, 800, true)); - g_weak_map[prefix] = history_sp; - return history_sp; - } - - bool IsValid() const - { - return m_history != NULL; - } - - HistoryW * - GetHistoryPtr () - { - return m_history; - } - - void - Enter (const EditLineCharType *line_cstr) - { - if (m_history) - history_w (m_history, &m_event, H_ENTER, line_cstr); - } - - bool - Load () - { - if (m_history) - { - const char *path = GetHistoryFilePath(); - if (path) - { - history_w (m_history, &m_event, H_LOAD, path); - return true; - } - } - return false; - } - - bool - Save () - { - if (m_history) - { - const char *path = GetHistoryFilePath(); - if (path) - { - history_w (m_history, &m_event, H_SAVE, path); - return true; - } - } - return false; - } - - protected: - HistoryW * m_history; // The history object - HistEventW m_event; // The history event needed to contain all history events - std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history - std::string m_path; // Path to the history file - }; +namespace lldb_private { +namespace line_editor { +typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP; + +// EditlineHistory objects are sometimes shared between multiple +// Editline instances with the same program name. + +class EditlineHistory { +private: + // Use static GetHistory() function to get a EditlineHistorySP to one of these + // objects + EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries) + : m_history(NULL), m_event(), m_prefix(prefix), m_path() { + m_history = history_winit(); + history_w(m_history, &m_event, H_SETSIZE, size); + if (unique_entries) + history_w(m_history, &m_event, H_SETUNIQUE, 1); + } + + const char *GetHistoryFilePath() { + if (m_path.empty() && m_history && !m_prefix.empty()) { + FileSpec parent_path{"~/.lldb", true}; + char history_path[PATH_MAX]; + if (FileSystem::MakeDirectory(parent_path, + lldb::eFilePermissionsDirectoryDefault) + .Success()) { + snprintf(history_path, sizeof(history_path), "~/.lldb/%s-history", + m_prefix.c_str()); + } else { + snprintf(history_path, sizeof(history_path), "~/%s-widehistory", + m_prefix.c_str()); + } + m_path = FileSpec(history_path, true).GetPath(); + } + if (m_path.empty()) + return NULL; + return m_path.c_str(); + } + +public: + ~EditlineHistory() { + Save(); + + if (m_history) { + history_wend(m_history); + m_history = NULL; + } + } + + static EditlineHistorySP GetHistory(const std::string &prefix) { + typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap; + static std::recursive_mutex g_mutex; + static WeakHistoryMap g_weak_map; + std::lock_guard<std::recursive_mutex> guard(g_mutex); + WeakHistoryMap::const_iterator pos = g_weak_map.find(prefix); + EditlineHistorySP history_sp; + if (pos != g_weak_map.end()) { + history_sp = pos->second.lock(); + if (history_sp) + return history_sp; + g_weak_map.erase(pos); + } + history_sp.reset(new EditlineHistory(prefix, 800, true)); + g_weak_map[prefix] = history_sp; + return history_sp; + } + + bool IsValid() const { return m_history != NULL; } + + HistoryW *GetHistoryPtr() { return m_history; } + + void Enter(const EditLineCharType *line_cstr) { + if (m_history) + history_w(m_history, &m_event, H_ENTER, line_cstr); + } + + bool Load() { + if (m_history) { + const char *path = GetHistoryFilePath(); + if (path) { + history_w(m_history, &m_event, H_LOAD, path); + return true; + } + } + return false; + } + + bool Save() { + if (m_history) { + const char *path = GetHistoryFilePath(); + if (path) { + history_w(m_history, &m_event, H_SAVE, path); + return true; + } } + return false; + } + +protected: + HistoryW *m_history; // The history object + HistEventW m_event; // The history event needed to contain all history events + std::string m_prefix; // The prefix name (usually the editline program name) + // to use when loading/saving history + std::string m_path; // Path to the history file +}; +} } //------------------------------------------------------------------ // Editline private methods //------------------------------------------------------------------ -void -Editline::SetBaseLineNumber (int line_number) -{ - std::stringstream line_number_stream; - line_number_stream << line_number; - m_base_line_number = line_number; - m_line_number_digits = std::max (3, (int)line_number_stream.str().length() + 1); +void Editline::SetBaseLineNumber(int line_number) { + std::stringstream line_number_stream; + line_number_stream << line_number; + m_base_line_number = line_number; + m_line_number_digits = + std::max(3, (int)line_number_stream.str().length() + 1); } -std::string -Editline::PromptForIndex (int line_index) -{ - bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0; - std::string prompt = m_set_prompt; - if (use_line_numbers && prompt.length() == 0) - { - prompt = ": "; - } - std::string continuation_prompt = prompt; - if (m_set_continuation_prompt.length() > 0) - { - continuation_prompt = m_set_continuation_prompt; - - // Ensure that both prompts are the same length through space padding - while (continuation_prompt.length() < prompt.length()) - { - continuation_prompt += ' '; - } - while (prompt.length() < continuation_prompt.length()) - { - prompt += ' '; - } +std::string Editline::PromptForIndex(int line_index) { + bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0; + std::string prompt = m_set_prompt; + if (use_line_numbers && prompt.length() == 0) { + prompt = ": "; + } + std::string continuation_prompt = prompt; + if (m_set_continuation_prompt.length() > 0) { + continuation_prompt = m_set_continuation_prompt; + + // Ensure that both prompts are the same length through space padding + while (continuation_prompt.length() < prompt.length()) { + continuation_prompt += ' '; } - - if (use_line_numbers) - { - StreamString prompt_stream; - prompt_stream.Printf("%*d%s", m_line_number_digits, m_base_line_number + line_index, - (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str()); - return std::move (prompt_stream.GetString()); + while (prompt.length() < continuation_prompt.length()) { + prompt += ' '; } - return (line_index == 0) ? prompt : continuation_prompt; + } + + if (use_line_numbers) { + StreamString prompt_stream; + prompt_stream.Printf( + "%*d%s", m_line_number_digits, m_base_line_number + line_index, + (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str()); + return std::move(prompt_stream.GetString()); + } + return (line_index == 0) ? prompt : continuation_prompt; } -void -Editline::SetCurrentLine (int line_index) -{ - m_current_line_index = line_index; - m_current_prompt = PromptForIndex (line_index); +void Editline::SetCurrentLine(int line_index) { + m_current_line_index = line_index; + m_current_prompt = PromptForIndex(line_index); } -int -Editline::GetPromptWidth() -{ - return (int)PromptForIndex (0).length(); -} +int Editline::GetPromptWidth() { return (int)PromptForIndex(0).length(); } -bool -Editline::IsEmacs() -{ - const char * editor; - el_get (m_editline, EL_EDITOR, &editor); - return editor[0] == 'e'; +bool Editline::IsEmacs() { + const char *editor; + el_get(m_editline, EL_EDITOR, &editor); + return editor[0] == 'e'; } -bool -Editline::IsOnlySpaces() -{ - const LineInfoW * info = el_wline (m_editline); - for (const EditLineCharType * character = info->buffer; character < info->lastchar; character++) - { - if (*character != ' ') - return false; - } - return true; +bool Editline::IsOnlySpaces() { + const LineInfoW *info = el_wline(m_editline); + for (const EditLineCharType *character = info->buffer; + character < info->lastchar; character++) { + if (*character != ' ') + return false; + } + return true; } -int -Editline::GetLineIndexForLocation (CursorLocation location, int cursor_row) -{ - int line = 0; - if (location == CursorLocation::EditingPrompt || location == CursorLocation::BlockEnd || - location == CursorLocation::EditingCursor) - { - for (unsigned index = 0; index < m_current_line_index; index++) - { - line += CountRowsForLine (m_input_lines[index]); - } - if (location == CursorLocation::EditingCursor) - { - line += cursor_row; - } - else if (location == CursorLocation::BlockEnd) - { - for (unsigned index = m_current_line_index; index < m_input_lines.size(); index++) - { - line += CountRowsForLine (m_input_lines[index]); - } - --line; - } +int Editline::GetLineIndexForLocation(CursorLocation location, int cursor_row) { + int line = 0; + if (location == CursorLocation::EditingPrompt || + location == CursorLocation::BlockEnd || + location == CursorLocation::EditingCursor) { + for (unsigned index = 0; index < m_current_line_index; index++) { + line += CountRowsForLine(m_input_lines[index]); } - return line; -} - -void -Editline::MoveCursor (CursorLocation from, CursorLocation to) -{ - const LineInfoW * info = el_wline (m_editline); - int editline_cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth()); - int editline_cursor_row = editline_cursor_position / m_terminal_width; - - // Determine relative starting and ending lines - int fromLine = GetLineIndexForLocation (from, editline_cursor_row); - int toLine = GetLineIndexForLocation (to, editline_cursor_row); - if (toLine != fromLine) - { - fprintf (m_output_file, (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs (toLine - fromLine)); + if (location == CursorLocation::EditingCursor) { + line += cursor_row; + } else if (location == CursorLocation::BlockEnd) { + for (unsigned index = m_current_line_index; index < m_input_lines.size(); + index++) { + line += CountRowsForLine(m_input_lines[index]); + } + --line; } - - // Determine target column - int toColumn = 1; - if (to == CursorLocation::EditingCursor) - { - toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1; - } - else if (to == CursorLocation::BlockEnd) - { - toColumn = ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % 80) + 1; - } - fprintf (m_output_file, ANSI_SET_COLUMN_N, toColumn); + } + return line; } -void -Editline::DisplayInput (int firstIndex) -{ - fprintf (m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); - int line_count = (int)m_input_lines.size(); - const char *faint = m_color_prompts ? ANSI_FAINT : ""; - const char *unfaint = m_color_prompts ? ANSI_UNFAINT : ""; - - for (int index = firstIndex; index < line_count; index++) - { - fprintf (m_output_file, "%s" "%s" "%s" EditLineStringFormatSpec " ", - faint, - PromptForIndex (index).c_str(), - unfaint, - m_input_lines[index].c_str()); - if (index < line_count - 1) - fprintf (m_output_file, "\n"); - } +void Editline::MoveCursor(CursorLocation from, CursorLocation to) { + const LineInfoW *info = el_wline(m_editline); + int editline_cursor_position = + (int)((info->cursor - info->buffer) + GetPromptWidth()); + int editline_cursor_row = editline_cursor_position / m_terminal_width; + + // Determine relative starting and ending lines + int fromLine = GetLineIndexForLocation(from, editline_cursor_row); + int toLine = GetLineIndexForLocation(to, editline_cursor_row); + if (toLine != fromLine) { + fprintf(m_output_file, + (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, + std::abs(toLine - fromLine)); + } + + // Determine target column + int toColumn = 1; + if (to == CursorLocation::EditingCursor) { + toColumn = + editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1; + } else if (to == CursorLocation::BlockEnd) { + toColumn = + ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % + 80) + + 1; + } + fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); } +void Editline::DisplayInput(int firstIndex) { + fprintf(m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1); + int line_count = (int)m_input_lines.size(); + const char *faint = m_color_prompts ? ANSI_FAINT : ""; + const char *unfaint = m_color_prompts ? ANSI_UNFAINT : ""; + + for (int index = firstIndex; index < line_count; index++) { + fprintf(m_output_file, "%s" + "%s" + "%s" EditLineStringFormatSpec " ", + faint, PromptForIndex(index).c_str(), unfaint, + m_input_lines[index].c_str()); + if (index < line_count - 1) + fprintf(m_output_file, "\n"); + } +} -int -Editline::CountRowsForLine (const EditLineStringType & content) -{ - auto prompt = PromptForIndex (0); // Prompt width is constant during an edit session - int line_length = (int)(content.length() + prompt.length()); - return (line_length / m_terminal_width) + 1; +int Editline::CountRowsForLine(const EditLineStringType &content) { + auto prompt = + PromptForIndex(0); // Prompt width is constant during an edit session + int line_length = (int)(content.length() + prompt.length()); + return (line_length / m_terminal_width) + 1; } -void -Editline::SaveEditedLine() -{ - const LineInfoW * info = el_wline (m_editline); - m_input_lines[m_current_line_index] = EditLineStringType (info->buffer, info->lastchar - info->buffer); +void Editline::SaveEditedLine() { + const LineInfoW *info = el_wline(m_editline); + m_input_lines[m_current_line_index] = + EditLineStringType(info->buffer, info->lastchar - info->buffer); } -StringList -Editline::GetInputAsStringList(int line_count) -{ - StringList lines; - for (EditLineStringType line : m_input_lines) - { - if (line_count == 0) - break; +StringList Editline::GetInputAsStringList(int line_count) { + StringList lines; + for (EditLineStringType line : m_input_lines) { + if (line_count == 0) + break; #if LLDB_EDITLINE_USE_WCHAR - lines.AppendString (m_utf8conv.to_bytes (line)); + lines.AppendString(m_utf8conv.to_bytes(line)); #else - lines.AppendString(line); + lines.AppendString(line); #endif - --line_count; - } - return lines; + --line_count; + } + return lines; } -unsigned char -Editline::RecallHistory (bool earlier) -{ - if (!m_history_sp || !m_history_sp->IsValid()) +unsigned char Editline::RecallHistory(bool earlier) { + if (!m_history_sp || !m_history_sp->IsValid()) + return CC_ERROR; + + HistoryW *pHistory = m_history_sp->GetHistoryPtr(); + HistEventW history_event; + std::vector<EditLineStringType> new_input_lines; + + // Treat moving from the "live" entry differently + if (!m_in_history) { + if (earlier == false) + return CC_ERROR; // Can't go newer than the "live" entry + if (history_w(pHistory, &history_event, H_FIRST) == -1) + return CC_ERROR; + + // Save any edits to the "live" entry in case we return by moving forward in + // history + // (it would be more bash-like to save over any current entry, but libedit + // doesn't + // offer the ability to add entries anywhere except the end.) + SaveEditedLine(); + m_live_history_lines = m_input_lines; + m_in_history = true; + } else { + if (history_w(pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1) { + // Can't move earlier than the earliest entry + if (earlier) return CC_ERROR; - - HistoryW * pHistory = m_history_sp->GetHistoryPtr(); - HistEventW history_event; - std::vector<EditLineStringType> new_input_lines; - - // Treat moving from the "live" entry differently - if (!m_in_history) - { - if (earlier == false) - return CC_ERROR; // Can't go newer than the "live" entry - if (history_w (pHistory, &history_event, H_FIRST) == -1) - return CC_ERROR; - - // Save any edits to the "live" entry in case we return by moving forward in history - // (it would be more bash-like to save over any current entry, but libedit doesn't - // offer the ability to add entries anywhere except the end.) - SaveEditedLine(); - m_live_history_lines = m_input_lines; - m_in_history = true; - } - else - { - if (history_w (pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1) - { - // Can't move earlier than the earliest entry - if (earlier) - return CC_ERROR; - - // ... but moving to newer than the newest yields the "live" entry - new_input_lines = m_live_history_lines; - m_in_history = false; - } + + // ... but moving to newer than the newest yields the "live" entry + new_input_lines = m_live_history_lines; + m_in_history = false; } - - // If we're pulling the lines from history, split them apart - if (m_in_history) - new_input_lines = SplitLines (history_event.str); - - // Erase the current edit session and replace it with a new one - MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart); - m_input_lines = new_input_lines; - DisplayInput(); - - // Prepare to edit the last line when moving to previous entry, or the first line - // when moving to next entry - SetCurrentLine (m_current_line_index = earlier ? (int)m_input_lines.size() - 1 : 0); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); - return CC_NEWLINE; + } + + // If we're pulling the lines from history, split them apart + if (m_in_history) + new_input_lines = SplitLines(history_event.str); + + // Erase the current edit session and replace it with a new one + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); + m_input_lines = new_input_lines; + DisplayInput(); + + // Prepare to edit the last line when moving to previous entry, or the first + // line + // when moving to next entry + SetCurrentLine(m_current_line_index = + earlier ? (int)m_input_lines.size() - 1 : 0); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + return CC_NEWLINE; } -int -Editline::GetCharacter (EditLineCharType * c) -{ - const LineInfoW * info = el_wline (m_editline); - - // Paint a faint version of the desired prompt over the version libedit draws - // (will only be requested if colors are supported) - if (m_needs_prompt_repaint) - { - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - fprintf (m_output_file, "%s" "%s" "%s", ANSI_FAINT, Prompt(), ANSI_UNFAINT); - MoveCursor (CursorLocation::EditingPrompt, CursorLocation::EditingCursor); - m_needs_prompt_repaint = false; +int Editline::GetCharacter(EditLineCharType *c) { + const LineInfoW *info = el_wline(m_editline); + + // Paint a faint version of the desired prompt over the version libedit draws + // (will only be requested if colors are supported) + if (m_needs_prompt_repaint) { + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + fprintf(m_output_file, "%s" + "%s" + "%s", + ANSI_FAINT, Prompt(), ANSI_UNFAINT); + MoveCursor(CursorLocation::EditingPrompt, CursorLocation::EditingCursor); + m_needs_prompt_repaint = false; + } + + if (m_multiline_enabled) { + // Detect when the number of rows used for this input line changes due to an + // edit + int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth()); + int new_line_rows = (lineLength / m_terminal_width) + 1; + if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows) { + // Respond by repainting the current state from this line on + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + SaveEditedLine(); + DisplayInput(m_current_line_index); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); } - - if (m_multiline_enabled) - { - // Detect when the number of rows used for this input line changes due to an edit - int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth()); - int new_line_rows = (lineLength / m_terminal_width) + 1; - if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows) - { - // Respond by repainting the current state from this line on - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - SaveEditedLine(); - DisplayInput (m_current_line_index); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor); - } - m_current_line_rows = new_line_rows; + m_current_line_rows = new_line_rows; + } + + // Read an actual character + while (true) { + lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess; + char ch = 0; + + // This mutex is locked by our caller (GetLine). Unlock it while we read a + // character + // (blocking operation), so we do not hold the mutex indefinitely. This + // gives a chance + // for someone to interrupt us. After Read returns, immediately lock the + // mutex again and + // check if we were interrupted. + m_output_mutex.unlock(); + int read_count = m_input_connection.Read(&ch, 1, llvm::None, status, NULL); + m_output_mutex.lock(); + if (m_editor_status == EditorStatus::Interrupted) { + while (read_count > 0 && status == lldb::eConnectionStatusSuccess) + read_count = m_input_connection.Read(&ch, 1, llvm::None, status, NULL); + lldbassert(status == lldb::eConnectionStatusInterrupted); + return 0; } - - // Read an actual character - while (true) - { - lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess; - char ch = 0; - - // This mutex is locked by our caller (GetLine). Unlock it while we read a character - // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance - // for someone to interrupt us. After Read returns, immediately lock the mutex again and - // check if we were interrupted. - m_output_mutex.unlock(); - int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL); - m_output_mutex.lock(); - if (m_editor_status == EditorStatus::Interrupted) - { - while (read_count > 0 && status == lldb::eConnectionStatusSuccess) - read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL); - lldbassert(status == lldb::eConnectionStatusInterrupted); - return 0; - } - if (read_count) - { + if (read_count) { #if LLDB_EDITLINE_USE_WCHAR - // After the initial interruptible read, this is guaranteed not to block - ungetc (ch, m_input_file); - *c = fgetwc (m_input_file); - if (*c != WEOF) - return 1; + // After the initial interruptible read, this is guaranteed not to block + ungetc(ch, m_input_file); + *c = fgetwc(m_input_file); + if (*c != WEOF) + return 1; #else - *c = ch; - if(ch != (char)EOF) - return 1; + *c = ch; + if (ch != (char)EOF) + return 1; #endif - } - else - { - switch (status) - { - case lldb::eConnectionStatusSuccess: // Success - break; - - case lldb::eConnectionStatusInterrupted: - lldbassert(0 && "Interrupts should have been handled above."); - - case lldb::eConnectionStatusError: // Check GetError() for details - case lldb::eConnectionStatusTimedOut: // Request timed out - case lldb::eConnectionStatusEndOfFile: // End-of-file encountered - case lldb::eConnectionStatusNoConnection: // No connection - case lldb::eConnectionStatusLostConnection: // Lost connection while connected to a valid connection - m_editor_status = EditorStatus::EndOfInput; - return 0; - } - } + } else { + switch (status) { + case lldb::eConnectionStatusSuccess: // Success + break; + + case lldb::eConnectionStatusInterrupted: + lldbassert(0 && "Interrupts should have been handled above."); + + case lldb::eConnectionStatusError: // Check GetError() for details + case lldb::eConnectionStatusTimedOut: // Request timed out + case lldb::eConnectionStatusEndOfFile: // End-of-file encountered + case lldb::eConnectionStatusNoConnection: // No connection + case lldb::eConnectionStatusLostConnection: // Lost connection while + // connected to a valid + // connection + m_editor_status = EditorStatus::EndOfInput; + return 0; + } } + } } -const char * -Editline::Prompt() -{ - if (m_color_prompts) - m_needs_prompt_repaint = true; - return m_current_prompt.c_str(); +const char *Editline::Prompt() { + if (m_color_prompts) + m_needs_prompt_repaint = true; + return m_current_prompt.c_str(); } -unsigned char -Editline::BreakLineCommand (int ch) -{ - // Preserve any content beyond the cursor, truncate and save the current line - const LineInfoW * info = el_wline (m_editline); - auto current_line = EditLineStringType (info->buffer, info->cursor - info->buffer); - auto new_line_fragment = EditLineStringType (info->cursor, info->lastchar - info->cursor); - m_input_lines[m_current_line_index] = current_line; - - // Ignore whitespace-only extra fragments when breaking a line - if (::IsOnlySpaces (new_line_fragment)) - new_line_fragment = EditLineConstString(""); - - // Establish the new cursor position at the start of a line when inserting a line break - m_revert_cursor_index = 0; - - // Don't perform automatic formatting when pasting - if (!IsInputPending (m_input_file)) - { - // Apply smart indentation - if (m_fix_indentation_callback) - { - StringList lines = GetInputAsStringList (m_current_line_index + 1); +unsigned char Editline::BreakLineCommand(int ch) { + // Preserve any content beyond the cursor, truncate and save the current line + const LineInfoW *info = el_wline(m_editline); + auto current_line = + EditLineStringType(info->buffer, info->cursor - info->buffer); + auto new_line_fragment = + EditLineStringType(info->cursor, info->lastchar - info->cursor); + m_input_lines[m_current_line_index] = current_line; + + // Ignore whitespace-only extra fragments when breaking a line + if (::IsOnlySpaces(new_line_fragment)) + new_line_fragment = EditLineConstString(""); + + // Establish the new cursor position at the start of a line when inserting a + // line break + m_revert_cursor_index = 0; + + // Don't perform automatic formatting when pasting + if (!IsInputPending(m_input_file)) { + // Apply smart indentation + if (m_fix_indentation_callback) { + StringList lines = GetInputAsStringList(m_current_line_index + 1); #if LLDB_EDITLINE_USE_WCHAR - lines.AppendString (m_utf8conv.to_bytes (new_line_fragment)); + lines.AppendString(m_utf8conv.to_bytes(new_line_fragment)); #else - lines.AppendString (new_line_fragment); + lines.AppendString(new_line_fragment); #endif - - int indent_correction = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton); - new_line_fragment = FixIndentation(new_line_fragment, indent_correction); - m_revert_cursor_index = GetIndentation(new_line_fragment); - } + + int indent_correction = m_fix_indentation_callback( + this, lines, 0, m_fix_indentation_callback_baton); + new_line_fragment = FixIndentation(new_line_fragment, indent_correction); + m_revert_cursor_index = GetIndentation(new_line_fragment); } - - // Insert the new line and repaint everything from the split line on down - m_input_lines.insert (m_input_lines.begin() + m_current_line_index + 1, new_line_fragment); - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - DisplayInput (m_current_line_index); - - // Reposition the cursor to the right line and prepare to edit the new line - SetCurrentLine (m_current_line_index + 1); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); - return CC_NEWLINE; + } + + // Insert the new line and repaint everything from the split line on down + m_input_lines.insert(m_input_lines.begin() + m_current_line_index + 1, + new_line_fragment); + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + DisplayInput(m_current_line_index); + + // Reposition the cursor to the right line and prepare to edit the new line + SetCurrentLine(m_current_line_index + 1); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + return CC_NEWLINE; } -unsigned char -Editline::EndOrAddLineCommand(int ch) -{ - // Don't perform end of input detection when pasting, always treat this as a line break - if (IsInputPending(m_input_file)) - { +unsigned char Editline::EndOrAddLineCommand(int ch) { + // Don't perform end of input detection when pasting, always treat this as a + // line break + if (IsInputPending(m_input_file)) { + return BreakLineCommand(ch); + } + + // Save any edits to this line + SaveEditedLine(); + + // If this is the end of the last line, consider whether to add a line instead + const LineInfoW *info = el_wline(m_editline); + if (m_current_line_index == m_input_lines.size() - 1 && + info->cursor == info->lastchar) { + if (m_is_input_complete_callback) { + auto lines = GetInputAsStringList(); + if (!m_is_input_complete_callback(this, lines, + m_is_input_complete_callback_baton)) { return BreakLineCommand(ch); - } - - // Save any edits to this line - SaveEditedLine(); + } - // If this is the end of the last line, consider whether to add a line instead - const LineInfoW *info = el_wline(m_editline); - if (m_current_line_index == m_input_lines.size() - 1 && info->cursor == info->lastchar) - { - if (m_is_input_complete_callback) - { - auto lines = GetInputAsStringList(); - if (!m_is_input_complete_callback(this, lines, m_is_input_complete_callback_baton)) - { - return BreakLineCommand(ch); - } - - // The completion test is allowed to change the input lines when complete - m_input_lines.clear(); - for (unsigned index = 0; index < lines.GetSize(); index++) - { + // The completion test is allowed to change the input lines when complete + m_input_lines.clear(); + for (unsigned index = 0; index < lines.GetSize(); index++) { #if LLDB_EDITLINE_USE_WCHAR - m_input_lines.insert(m_input_lines.end(), m_utf8conv.from_bytes(lines[index])); + m_input_lines.insert(m_input_lines.end(), + m_utf8conv.from_bytes(lines[index])); #else - m_input_lines.insert(m_input_lines.end(), lines[index]); + m_input_lines.insert(m_input_lines.end(), lines[index]); #endif - } - } + } } - MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); - fprintf(m_output_file, "\n"); - m_editor_status = EditorStatus::Complete; - return CC_NEWLINE; + } + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); + fprintf(m_output_file, "\n"); + m_editor_status = EditorStatus::Complete; + return CC_NEWLINE; } -unsigned char -Editline::DeleteNextCharCommand(int ch) -{ - LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); - - // Just delete the next character normally if possible - if (info->cursor < info->lastchar) - { - info->cursor++; - el_deletestr (m_editline, 1); - return CC_REFRESH; - } +unsigned char Editline::DeleteNextCharCommand(int ch) { + LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline)); - // Fail when at the end of the last line, except when ^D is pressed on - // the line is empty, in which case it is treated as EOF - if (m_current_line_index == m_input_lines.size() - 1) - { - if (ch == 4 && info->buffer == info->lastchar) - { - fprintf (m_output_file, "^D\n"); - m_editor_status = EditorStatus::EndOfInput; - return CC_EOF; - } - return CC_ERROR; - } - - // Prepare to combine this line with the one below - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - - // Insert the next line of text at the cursor and restore the cursor position - const EditLineCharType * cursor = info->cursor; - el_winsertstr (m_editline, m_input_lines[m_current_line_index + 1].c_str()); - info->cursor = cursor; - SaveEditedLine(); - - // Delete the extra line - m_input_lines.erase (m_input_lines.begin() + m_current_line_index + 1); - - // Clear and repaint from this line on down - DisplayInput (m_current_line_index); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor); + // Just delete the next character normally if possible + if (info->cursor < info->lastchar) { + info->cursor++; + el_deletestr(m_editline, 1); return CC_REFRESH; + } + + // Fail when at the end of the last line, except when ^D is pressed on + // the line is empty, in which case it is treated as EOF + if (m_current_line_index == m_input_lines.size() - 1) { + if (ch == 4 && info->buffer == info->lastchar) { + fprintf(m_output_file, "^D\n"); + m_editor_status = EditorStatus::EndOfInput; + return CC_EOF; + } + return CC_ERROR; + } + + // Prepare to combine this line with the one below + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + + // Insert the next line of text at the cursor and restore the cursor position + const EditLineCharType *cursor = info->cursor; + el_winsertstr(m_editline, m_input_lines[m_current_line_index + 1].c_str()); + info->cursor = cursor; + SaveEditedLine(); + + // Delete the extra line + m_input_lines.erase(m_input_lines.begin() + m_current_line_index + 1); + + // Clear and repaint from this line on down + DisplayInput(m_current_line_index); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); + return CC_REFRESH; } -unsigned char -Editline::DeletePreviousCharCommand (int ch) -{ - LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); - - // Just delete the previous character normally when not at the start of a line - if (info->cursor > info->buffer) - { - el_deletestr (m_editline, 1); - return CC_REFRESH; - } - - // No prior line and no prior character? Let the user know - if (m_current_line_index == 0) - return CC_ERROR; - - // No prior character, but prior line? Combine with the line above - SaveEditedLine(); - SetCurrentLine (m_current_line_index - 1); - auto priorLine = m_input_lines[m_current_line_index]; - m_input_lines.erase (m_input_lines.begin() + m_current_line_index); - m_input_lines[m_current_line_index] = priorLine + m_input_lines[m_current_line_index]; - - // Repaint from the new line down - fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine (priorLine), 1); - DisplayInput (m_current_line_index); - - // Put the cursor back where libedit expects it to be before returning to editing - // by telling libedit about the newly inserted text - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); - el_winsertstr (m_editline, priorLine.c_str()); - return CC_REDISPLAY; +unsigned char Editline::DeletePreviousCharCommand(int ch) { + LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline)); + + // Just delete the previous character normally when not at the start of a line + if (info->cursor > info->buffer) { + el_deletestr(m_editline, 1); + return CC_REFRESH; + } + + // No prior line and no prior character? Let the user know + if (m_current_line_index == 0) + return CC_ERROR; + + // No prior character, but prior line? Combine with the line above + SaveEditedLine(); + SetCurrentLine(m_current_line_index - 1); + auto priorLine = m_input_lines[m_current_line_index]; + m_input_lines.erase(m_input_lines.begin() + m_current_line_index); + m_input_lines[m_current_line_index] = + priorLine + m_input_lines[m_current_line_index]; + + // Repaint from the new line down + fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + CountRowsForLine(priorLine), 1); + DisplayInput(m_current_line_index); + + // Put the cursor back where libedit expects it to be before returning to + // editing + // by telling libedit about the newly inserted text + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + el_winsertstr(m_editline, priorLine.c_str()); + return CC_REDISPLAY; } -unsigned char -Editline::PreviousLineCommand (int ch) -{ - SaveEditedLine(); +unsigned char Editline::PreviousLineCommand(int ch) { + SaveEditedLine(); - if (m_current_line_index == 0) { - return RecallHistory (true); - } - - // Start from a known location - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - - // Treat moving up from a blank last line as a deletion of that line - if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) - { - m_input_lines.erase (m_input_lines.begin() + m_current_line_index); - fprintf (m_output_file, ANSI_CLEAR_BELOW); - } - - SetCurrentLine (m_current_line_index - 1); - fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, - CountRowsForLine (m_input_lines[m_current_line_index]), 1); - return CC_NEWLINE; + if (m_current_line_index == 0) { + return RecallHistory(true); + } + + // Start from a known location + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + + // Treat moving up from a blank last line as a deletion of that line + if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) { + m_input_lines.erase(m_input_lines.begin() + m_current_line_index); + fprintf(m_output_file, ANSI_CLEAR_BELOW); + } + + SetCurrentLine(m_current_line_index - 1); + fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, + CountRowsForLine(m_input_lines[m_current_line_index]), 1); + return CC_NEWLINE; } -unsigned char -Editline::NextLineCommand (int ch) -{ - SaveEditedLine(); +unsigned char Editline::NextLineCommand(int ch) { + SaveEditedLine(); - // Handle attempts to move down from the last line - if (m_current_line_index == m_input_lines.size() - 1) - { - // Don't add an extra line if the existing last line is blank, move through history instead - if (IsOnlySpaces()) - { - return RecallHistory (false); - } - - // Determine indentation for the new line - int indentation = 0; - if (m_fix_indentation_callback) - { - StringList lines = GetInputAsStringList(); - lines.AppendString(""); - indentation = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton); - } - m_input_lines.insert (m_input_lines.end(), EditLineStringType (indentation, EditLineCharType(' '))); + // Handle attempts to move down from the last line + if (m_current_line_index == m_input_lines.size() - 1) { + // Don't add an extra line if the existing last line is blank, move through + // history instead + if (IsOnlySpaces()) { + return RecallHistory(false); } - - // Move down past the current line using newlines to force scrolling if needed - SetCurrentLine (m_current_line_index + 1); - const LineInfoW * info = el_wline (m_editline); - int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth()); - int cursor_row = cursor_position / m_terminal_width; - for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++) - { - fprintf (m_output_file, "\n"); + + // Determine indentation for the new line + int indentation = 0; + if (m_fix_indentation_callback) { + StringList lines = GetInputAsStringList(); + lines.AppendString(""); + indentation = m_fix_indentation_callback( + this, lines, 0, m_fix_indentation_callback_baton); } - return CC_NEWLINE; + m_input_lines.insert( + m_input_lines.end(), + EditLineStringType(indentation, EditLineCharType(' '))); + } + + // Move down past the current line using newlines to force scrolling if needed + SetCurrentLine(m_current_line_index + 1); + const LineInfoW *info = el_wline(m_editline); + int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth()); + int cursor_row = cursor_position / m_terminal_width; + for (int line_count = 0; line_count < m_current_line_rows - cursor_row; + line_count++) { + fprintf(m_output_file, "\n"); + } + return CC_NEWLINE; } -unsigned char -Editline::PreviousHistoryCommand(int ch) -{ - SaveEditedLine(); +unsigned char Editline::PreviousHistoryCommand(int ch) { + SaveEditedLine(); - return RecallHistory(true); + return RecallHistory(true); } -unsigned char -Editline::NextHistoryCommand(int ch) -{ - SaveEditedLine(); +unsigned char Editline::NextHistoryCommand(int ch) { + SaveEditedLine(); - return RecallHistory(false); + return RecallHistory(false); } -unsigned char -Editline::FixIndentationCommand(int ch) -{ - if (!m_fix_indentation_callback) - return CC_NORM; +unsigned char Editline::FixIndentationCommand(int ch) { + if (!m_fix_indentation_callback) + return CC_NORM; - // Insert the character typed before proceeding - EditLineCharType inserted[] = { (EditLineCharType)ch, 0 }; - el_winsertstr (m_editline, inserted); - LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); - int cursor_position = info->cursor - info->buffer; + // Insert the character typed before proceeding + EditLineCharType inserted[] = {(EditLineCharType)ch, 0}; + el_winsertstr(m_editline, inserted); + LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline)); + int cursor_position = info->cursor - info->buffer; - // Save the edits and determine the correct indentation level - SaveEditedLine(); - StringList lines = GetInputAsStringList (m_current_line_index + 1); - int indent_correction = m_fix_indentation_callback (this, lines, cursor_position, m_fix_indentation_callback_baton); - - // If it is already correct no special work is needed - if (indent_correction == 0) - return CC_REFRESH; - - // Change the indentation level of the line - std::string currentLine = lines.GetStringAtIndex (m_current_line_index); - if (indent_correction > 0) - { - currentLine = currentLine.insert (0, indent_correction, ' '); - } - else - { - currentLine = currentLine.erase (0, -indent_correction); - } + // Save the edits and determine the correct indentation level + SaveEditedLine(); + StringList lines = GetInputAsStringList(m_current_line_index + 1); + int indent_correction = m_fix_indentation_callback( + this, lines, cursor_position, m_fix_indentation_callback_baton); + + // If it is already correct no special work is needed + if (indent_correction == 0) + return CC_REFRESH; + + // Change the indentation level of the line + std::string currentLine = lines.GetStringAtIndex(m_current_line_index); + if (indent_correction > 0) { + currentLine = currentLine.insert(0, indent_correction, ' '); + } else { + currentLine = currentLine.erase(0, -indent_correction); + } #if LLDB_EDITLINE_USE_WCHAR - m_input_lines[m_current_line_index] = m_utf8conv.from_bytes (currentLine); + m_input_lines[m_current_line_index] = m_utf8conv.from_bytes(currentLine); #else - m_input_lines[m_current_line_index] = currentLine; + m_input_lines[m_current_line_index] = currentLine; #endif - // Update the display to reflect the change - MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt); - DisplayInput (m_current_line_index); - - // Reposition the cursor back on the original line and prepare to restart editing - // with a new cursor position - SetCurrentLine (m_current_line_index); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); - m_revert_cursor_index = cursor_position + indent_correction; - return CC_NEWLINE; + // Update the display to reflect the change + MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt); + DisplayInput(m_current_line_index); + + // Reposition the cursor back on the original line and prepare to restart + // editing + // with a new cursor position + SetCurrentLine(m_current_line_index); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + m_revert_cursor_index = cursor_position + indent_correction; + return CC_NEWLINE; } -unsigned char -Editline::RevertLineCommand (int ch) -{ - el_winsertstr (m_editline, m_input_lines[m_current_line_index].c_str()); - if (m_revert_cursor_index >= 0) - { - LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); - info->cursor = info->buffer + m_revert_cursor_index; - if (info->cursor > info->lastchar) - { - info->cursor = info->lastchar; - } - m_revert_cursor_index = -1; +unsigned char Editline::RevertLineCommand(int ch) { + el_winsertstr(m_editline, m_input_lines[m_current_line_index].c_str()); + if (m_revert_cursor_index >= 0) { + LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline)); + info->cursor = info->buffer + m_revert_cursor_index; + if (info->cursor > info->lastchar) { + info->cursor = info->lastchar; } - return CC_REFRESH; + m_revert_cursor_index = -1; + } + return CC_REFRESH; } -unsigned char -Editline::BufferStartCommand (int ch) -{ - SaveEditedLine(); - MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart); - SetCurrentLine (0); - m_revert_cursor_index = 0; - return CC_NEWLINE; +unsigned char Editline::BufferStartCommand(int ch) { + SaveEditedLine(); + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); + SetCurrentLine(0); + m_revert_cursor_index = 0; + return CC_NEWLINE; } -unsigned char -Editline::BufferEndCommand (int ch) -{ - SaveEditedLine(); - MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockEnd); - SetCurrentLine ((int)m_input_lines.size() - 1); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); - return CC_NEWLINE; +unsigned char Editline::BufferEndCommand(int ch) { + SaveEditedLine(); + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd); + SetCurrentLine((int)m_input_lines.size() - 1); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + return CC_NEWLINE; } -unsigned char -Editline::TabCommand (int ch) -{ - if (m_completion_callback == nullptr) - return CC_ERROR; - - const LineInfo *line_info = el_line (m_editline); - StringList completions; - int page_size = 40; - - const int num_completions = m_completion_callback (line_info->buffer, - line_info->cursor, - line_info->lastchar, - 0, // Don't skip any matches (start at match zero) - -1, // Get all the matches - completions, - m_completion_callback_baton); - - if (num_completions == 0) - return CC_ERROR; - // if (num_completions == -1) - // { - // el_insertstr (m_editline, m_completion_key); - // return CC_REDISPLAY; - // } - // else - if (num_completions == -2) - { - // Replace the entire line with the first string... - el_deletestr (m_editline, line_info->cursor - line_info->buffer); - el_insertstr (m_editline, completions.GetStringAtIndex (0)); - return CC_REDISPLAY; - } - - // If we get a longer match display that first. - const char *completion_str = completions.GetStringAtIndex (0); - if (completion_str != nullptr && *completion_str != '\0') - { - el_insertstr (m_editline, completion_str); - return CC_REDISPLAY; - } - - if (num_completions > 1) - { - int num_elements = num_completions + 1; - fprintf (m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:"); - if (num_completions < page_size) - { - for (int i = 1; i < num_elements; i++) - { - completion_str = completions.GetStringAtIndex (i); - fprintf (m_output_file, "\n\t%s", completion_str); - } - fprintf (m_output_file, "\n"); +unsigned char Editline::TabCommand(int ch) { + if (m_completion_callback == nullptr) + return CC_ERROR; + + const LineInfo *line_info = el_line(m_editline); + StringList completions; + int page_size = 40; + + const int num_completions = m_completion_callback( + line_info->buffer, line_info->cursor, line_info->lastchar, + 0, // Don't skip any matches (start at match zero) + -1, // Get all the matches + completions, m_completion_callback_baton); + + if (num_completions == 0) + return CC_ERROR; + // if (num_completions == -1) + // { + // el_insertstr (m_editline, m_completion_key); + // return CC_REDISPLAY; + // } + // else + if (num_completions == -2) { + // Replace the entire line with the first string... + el_deletestr(m_editline, line_info->cursor - line_info->buffer); + el_insertstr(m_editline, completions.GetStringAtIndex(0)); + return CC_REDISPLAY; + } + + // If we get a longer match display that first. + const char *completion_str = completions.GetStringAtIndex(0); + if (completion_str != nullptr && *completion_str != '\0') { + el_insertstr(m_editline, completion_str); + return CC_REDISPLAY; + } + + if (num_completions > 1) { + int num_elements = num_completions + 1; + fprintf(m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:"); + if (num_completions < page_size) { + for (int i = 1; i < num_elements; i++) { + completion_str = completions.GetStringAtIndex(i); + fprintf(m_output_file, "\n\t%s", completion_str); + } + fprintf(m_output_file, "\n"); + } else { + int cur_pos = 1; + char reply; + int got_char; + while (cur_pos < num_elements) { + int endpoint = cur_pos + page_size; + if (endpoint > num_elements) + endpoint = num_elements; + for (; cur_pos < endpoint; cur_pos++) { + completion_str = completions.GetStringAtIndex(cur_pos); + fprintf(m_output_file, "\n\t%s", completion_str); } - else - { - int cur_pos = 1; - char reply; - int got_char; - while (cur_pos < num_elements) - { - int endpoint = cur_pos + page_size; - if (endpoint > num_elements) - endpoint = num_elements; - for (; cur_pos < endpoint; cur_pos++) - { - completion_str = completions.GetStringAtIndex (cur_pos); - fprintf (m_output_file, "\n\t%s", completion_str); - } - - if (cur_pos >= num_elements) - { - fprintf (m_output_file, "\n"); - break; - } - - fprintf (m_output_file, "\nMore (Y/n/a): "); - reply = 'n'; - got_char = el_getc(m_editline, &reply); - if (got_char == -1 || reply == 'n') - break; - if (reply == 'a') - page_size = num_elements - cur_pos; - } + + if (cur_pos >= num_elements) { + fprintf(m_output_file, "\n"); + break; } - DisplayInput(); - MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); + + fprintf(m_output_file, "\nMore (Y/n/a): "); + reply = 'n'; + got_char = el_getc(m_editline, &reply); + if (got_char == -1 || reply == 'n') + break; + if (reply == 'a') + page_size = num_elements - cur_pos; + } } - return CC_REDISPLAY; + DisplayInput(); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); + } + return CC_REDISPLAY; } -void -Editline::ConfigureEditor (bool multiline) -{ - if (m_editline && m_multiline_enabled == multiline) - return; - m_multiline_enabled = multiline; - - if (m_editline) - { - // Disable edit mode to stop the terminal from flushing all input - // during the call to el_end() since we expect to have multiple editline - // instances in this program. - el_set (m_editline, EL_EDITMODE, 0); - el_end (m_editline); - } - - m_editline = el_init (m_editor_name.c_str(), m_input_file, m_output_file, m_error_file); - TerminalSizeChanged(); - - if (m_history_sp && m_history_sp->IsValid()) - { - m_history_sp->Load(); - el_wset (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); - } - el_set (m_editline, EL_CLIENTDATA, this); - el_set (m_editline, EL_SIGNAL, 0); - el_set (m_editline, EL_EDITOR, "emacs"); - el_set (m_editline, EL_PROMPT, (EditlinePromptCallbackType)([] (EditLine *editline) { - return Editline::InstanceFor (editline)->Prompt(); - })); - - el_wset (m_editline, EL_GETCFN, - (EditlineGetCharCallbackType)([] (EditLine * editline, EditLineCharType * c) { - return Editline::InstanceFor (editline)->GetCharacter (c); - })); - - // Commands used for multiline support, registered whether or not they're used - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), EditLineConstString("Insert a line break"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BreakLineCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"), - EditLineConstString("End editing or continue when incomplete"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"), - EditLineConstString("Delete next character"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"), - EditLineConstString("Delete previous character"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"), - EditLineConstString("Move to previous line"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->PreviousLineCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), EditLineConstString("Move to next line"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextLineCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"), - EditLineConstString("Move to previous history"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), EditLineConstString("Move to next history"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextHistoryCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"), - EditLineConstString("Move to start of buffer"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferStartCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"), EditLineConstString("Move to end of buffer"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferEndCommand(ch); })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"), - EditLineConstString("Fix line indentation"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor (editline)->FixIndentationCommand (ch); - })); - - // Register the complete callback under two names for compatibility with older clients using - // custom .editrc files (largely becuase libedit has a bad bug where if you have a bind command - // that tries to bind to a function name that doesn't exist, it can corrupt the heap and - // crash your process later.) - EditlineCommandCallbackType complete_callback = [] (EditLine * editline, int ch) { - return Editline::InstanceFor (editline)->TabCommand (ch); - }; - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"), EditLineConstString("Invoke completion"), - complete_callback); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"), EditLineConstString("Invoke completion"), - complete_callback); - - // General bindings we don't mind being overridden - if (!multiline) { - el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string - } - el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode - el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to auto complete - - // Allow user-specific customization prior to registering bindings we absolutely require - el_source (m_editline, NULL); - - // Register an internal binding that external developers shouldn't use - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"), - EditLineConstString("Revert line to saved state"), - (EditlineCommandCallbackType)( - [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->RevertLineCommand(ch); })); - - // Register keys that perform auto-indent correction - if (m_fix_indentation_callback && m_fix_indentation_callback_chars) - { - char bind_key[2] = { 0, 0 }; - const char * indent_chars = m_fix_indentation_callback_chars; - while (*indent_chars) - { - bind_key[0] = *indent_chars; - el_set (m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL); - ++indent_chars; - } +void Editline::ConfigureEditor(bool multiline) { + if (m_editline && m_multiline_enabled == multiline) + return; + m_multiline_enabled = multiline; + + if (m_editline) { + // Disable edit mode to stop the terminal from flushing all input + // during the call to el_end() since we expect to have multiple editline + // instances in this program. + el_set(m_editline, EL_EDITMODE, 0); + el_end(m_editline); + } + + m_editline = + el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file); + TerminalSizeChanged(); + + if (m_history_sp && m_history_sp->IsValid()) { + m_history_sp->Load(); + el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); + } + el_set(m_editline, EL_CLIENTDATA, this); + el_set(m_editline, EL_SIGNAL, 0); + el_set(m_editline, EL_EDITOR, "emacs"); + el_set(m_editline, EL_PROMPT, + (EditlinePromptCallbackType)([](EditLine *editline) { + return Editline::InstanceFor(editline)->Prompt(); + })); + + el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([]( + EditLine *editline, EditLineCharType *c) { + return Editline::InstanceFor(editline)->GetCharacter(c); + })); + + // Commands used for multiline support, registered whether or not they're used + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), + EditLineConstString("Insert a line break"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BreakLineCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"), + EditLineConstString("End editing or continue when incomplete"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"), + EditLineConstString("Delete next character"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); + })); + el_wset( + m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"), + EditLineConstString("Delete previous character"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"), + EditLineConstString("Move to previous line"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousLineCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), + EditLineConstString("Move to next line"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->NextLineCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"), + EditLineConstString("Move to previous history"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), + EditLineConstString("Move to next history"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->NextHistoryCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"), + EditLineConstString("Move to start of buffer"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BufferStartCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"), + EditLineConstString("Move to end of buffer"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BufferEndCommand(ch); + })); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"), + EditLineConstString("Fix line indentation"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->FixIndentationCommand(ch); + })); + + // Register the complete callback under two names for compatibility with older + // clients using + // custom .editrc files (largely because libedit has a bad bug where if you + // have a bind command + // that tries to bind to a function name that doesn't exist, it can corrupt + // the heap and + // crash your process later.) + EditlineCommandCallbackType complete_callback = [](EditLine *editline, + int ch) { + return Editline::InstanceFor(editline)->TabCommand(ch); + }; + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"), + EditLineConstString("Invoke completion"), complete_callback); + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"), + EditLineConstString("Invoke completion"), complete_callback); + + // General bindings we don't mind being overridden + if (!multiline) { + el_set(m_editline, EL_BIND, "^r", "em-inc-search-prev", + NULL); // Cycle through backwards search, entering string + } + el_set(m_editline, EL_BIND, "^w", "ed-delete-prev-word", + NULL); // Delete previous word, behave like bash in emacs mode + el_set(m_editline, EL_BIND, "\t", "lldb-complete", + NULL); // Bind TAB to auto complete + + // Allow user-specific customization prior to registering bindings we + // absolutely require + el_source(m_editline, NULL); + + // Register an internal binding that external developers shouldn't use + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"), + EditLineConstString("Revert line to saved state"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->RevertLineCommand(ch); + })); + + // Register keys that perform auto-indent correction + if (m_fix_indentation_callback && m_fix_indentation_callback_chars) { + char bind_key[2] = {0, 0}; + const char *indent_chars = m_fix_indentation_callback_chars; + while (*indent_chars) { + bind_key[0] = *indent_chars; + el_set(m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL); + ++indent_chars; } - - // Multi-line editor bindings - if (multiline) - { - el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL); - el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL); - el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL); - el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL); - el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL); - el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL); - el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL); - el_set (m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL); - el_set (m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL); - el_set (m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL); - - // Editor-specific bindings - if (IsEmacs()) - { - el_set (m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL); - el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL); - el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL); - el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL); - el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history", NULL); - el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history", NULL); - el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history", NULL); - el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL); - } - else - { - el_set (m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL); - - el_set (m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", NULL); - el_set (m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL); - el_set (m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL); - el_set (m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", NULL); - el_set (m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", NULL); - - // Escape is absorbed exiting edit mode, so re-register important sequences - // without the prefix - el_set (m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL); - el_set (m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL); - el_set (m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL); - } + } + + // Multi-line editor bindings + if (multiline) { + el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL); + el_set(m_editline, EL_BIND, "^p", "lldb-previous-line", NULL); + el_set(m_editline, EL_BIND, "^n", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL); + el_set(m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL); + + // Editor-specific bindings + if (IsEmacs()) { + el_set(m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL); + el_set(m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history", + NULL); + el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history", + NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history", + NULL); + el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL); + } else { + el_set(m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL); + + el_set(m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", + NULL); + el_set(m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL); + el_set(m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", + NULL); + el_set(m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", + NULL); + + // Escape is absorbed exiting edit mode, so re-register important + // sequences + // without the prefix + el_set(m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL); + el_set(m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL); + el_set(m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL); } + } } //------------------------------------------------------------------ // Editline public methods //------------------------------------------------------------------ -Editline * -Editline::InstanceFor (EditLine * editline) -{ - Editline * editor; - el_get (editline, EL_CLIENTDATA, &editor); - return editor; +Editline *Editline::InstanceFor(EditLine *editline) { + Editline *editor; + el_get(editline, EL_CLIENTDATA, &editor); + return editor; } -Editline::Editline (const char * editline_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts) : - m_editor_status (EditorStatus::Complete), - m_color_prompts(color_prompts), - m_input_file (input_file), - m_output_file (output_file), - m_error_file (error_file), - m_input_connection (fileno(input_file), false) -{ - // Get a shared history instance - m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; - m_history_sp = EditlineHistory::GetHistory (m_editor_name); +Editline::Editline(const char *editline_name, FILE *input_file, + FILE *output_file, FILE *error_file, bool color_prompts) + : m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts), + m_input_file(input_file), m_output_file(output_file), + m_error_file(error_file), m_input_connection(fileno(input_file), false) { + // Get a shared history instance + m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; + m_history_sp = EditlineHistory::GetHistory(m_editor_name); #ifdef USE_SETUPTERM_WORKAROUND - if (m_output_file) - { - const int term_fd = fileno(m_output_file); - if (term_fd != -1) - { - static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr; - static std::set<int> *g_init_terminal_fds_ptr = nullptr; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, [&]() { - g_init_terminal_fds_mutex_ptr = new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues - g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid C++ destructor chain issues - }); - - // We must make sure to initialize the terminal a given file descriptor - // only once. If we do this multiple times, we start leaking memory. - std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr); - if (g_init_terminal_fds_ptr->find(term_fd) == g_init_terminal_fds_ptr->end()) - { - g_init_terminal_fds_ptr->insert(term_fd); - setupterm((char *)0, term_fd, (int *)0); - } - } + if (m_output_file) { + const int term_fd = fileno(m_output_file); + if (term_fd != -1) { + static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr; + static std::set<int> *g_init_terminal_fds_ptr = nullptr; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [&]() { + g_init_terminal_fds_mutex_ptr = + new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues + g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid + // C++ destructor chain + // issues + }); + + // We must make sure to initialize the terminal a given file descriptor + // only once. If we do this multiple times, we start leaking memory. + std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr); + if (g_init_terminal_fds_ptr->find(term_fd) == + g_init_terminal_fds_ptr->end()) { + g_init_terminal_fds_ptr->insert(term_fd); + setupterm((char *)0, term_fd, (int *)0); + } } + } #endif } -Editline::~Editline() -{ - if (m_editline) - { - // Disable edit mode to stop the terminal from flushing all input - // during the call to el_end() since we expect to have multiple editline - // instances in this program. - el_set (m_editline, EL_EDITMODE, 0); - el_end (m_editline); - m_editline = nullptr; - } - - // EditlineHistory objects are sometimes shared between multiple - // Editline instances with the same program name. So just release - // our shared pointer and if we are the last owner, it will save the - // history to the history save file automatically. - m_history_sp.reset(); +Editline::~Editline() { + if (m_editline) { + // Disable edit mode to stop the terminal from flushing all input + // during the call to el_end() since we expect to have multiple editline + // instances in this program. + el_set(m_editline, EL_EDITMODE, 0); + el_end(m_editline); + m_editline = nullptr; + } + + // EditlineHistory objects are sometimes shared between multiple + // Editline instances with the same program name. So just release + // our shared pointer and if we are the last owner, it will save the + // history to the history save file automatically. + m_history_sp.reset(); } -void -Editline::SetPrompt (const char * prompt) -{ - m_set_prompt = prompt == nullptr ? "" : prompt; +void Editline::SetPrompt(const char *prompt) { + m_set_prompt = prompt == nullptr ? "" : prompt; } -void -Editline::SetContinuationPrompt (const char * continuation_prompt) -{ - m_set_continuation_prompt = continuation_prompt == nullptr ? "" : continuation_prompt; +void Editline::SetContinuationPrompt(const char *continuation_prompt) { + m_set_continuation_prompt = + continuation_prompt == nullptr ? "" : continuation_prompt; } -void -Editline::TerminalSizeChanged() -{ - if (m_editline != nullptr) - { - el_resize (m_editline); - int columns; - // Despite the man page claiming non-zero indicates success, it's actually zero - if (el_get (m_editline, EL_GETTC, "co", &columns) == 0) - { - m_terminal_width = columns; - if (m_current_line_rows != -1) - { - const LineInfoW * info = el_wline (m_editline); - int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth()); - m_current_line_rows = (lineLength / columns) + 1; - } - } - else - { - m_terminal_width = INT_MAX; - m_current_line_rows = 1; - } +void Editline::TerminalSizeChanged() { + if (m_editline != nullptr) { + el_resize(m_editline); + int columns; + // Despite the man page claiming non-zero indicates success, it's actually + // zero + if (el_get(m_editline, EL_GETTC, "co", &columns) == 0) { + m_terminal_width = columns; + if (m_current_line_rows != -1) { + const LineInfoW *info = el_wline(m_editline); + int lineLength = + (int)((info->lastchar - info->buffer) + GetPromptWidth()); + m_current_line_rows = (lineLength / columns) + 1; + } + } else { + m_terminal_width = INT_MAX; + m_current_line_rows = 1; } + } } -const char * -Editline::GetPrompt() -{ - return m_set_prompt.c_str(); -} +const char *Editline::GetPrompt() { return m_set_prompt.c_str(); } -uint32_t -Editline::GetCurrentLine() -{ - return m_current_line_index; -} +uint32_t Editline::GetCurrentLine() { return m_current_line_index; } -bool -Editline::Interrupt() -{ - bool result = true; - std::lock_guard<std::mutex> guard(m_output_mutex); - if (m_editor_status == EditorStatus::Editing) { - fprintf(m_output_file, "^C\n"); - result = m_input_connection.InterruptRead(); - } - m_editor_status = EditorStatus::Interrupted; - return result; +bool Editline::Interrupt() { + bool result = true; + std::lock_guard<std::mutex> guard(m_output_mutex); + if (m_editor_status == EditorStatus::Editing) { + fprintf(m_output_file, "^C\n"); + result = m_input_connection.InterruptRead(); + } + m_editor_status = EditorStatus::Interrupted; + return result; } -bool -Editline::Cancel() -{ - bool result = true; - std::lock_guard<std::mutex> guard(m_output_mutex); - if (m_editor_status == EditorStatus::Editing) { - MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); - result = m_input_connection.InterruptRead(); - } - m_editor_status = EditorStatus::Interrupted; - return result; +bool Editline::Cancel() { + bool result = true; + std::lock_guard<std::mutex> guard(m_output_mutex); + if (m_editor_status == EditorStatus::Editing) { + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); + fprintf(m_output_file, ANSI_CLEAR_BELOW); + result = m_input_connection.InterruptRead(); + } + m_editor_status = EditorStatus::Interrupted; + return result; } -void -Editline::SetAutoCompleteCallback (CompleteCallbackType callback, void * baton) -{ - m_completion_callback = callback; - m_completion_callback_baton = baton; +void Editline::SetAutoCompleteCallback(CompleteCallbackType callback, + void *baton) { + m_completion_callback = callback; + m_completion_callback_baton = baton; } -void -Editline::SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton) -{ - m_is_input_complete_callback = callback; - m_is_input_complete_callback_baton = baton; +void Editline::SetIsInputCompleteCallback(IsInputCompleteCallbackType callback, + void *baton) { + m_is_input_complete_callback = callback; + m_is_input_complete_callback_baton = baton; } -bool -Editline::SetFixIndentationCallback (FixIndentationCallbackType callback, - void * baton, - const char * indent_chars) -{ - m_fix_indentation_callback = callback; - m_fix_indentation_callback_baton = baton; - m_fix_indentation_callback_chars = indent_chars; - return false; +bool Editline::SetFixIndentationCallback(FixIndentationCallbackType callback, + void *baton, + const char *indent_chars) { + m_fix_indentation_callback = callback; + m_fix_indentation_callback_baton = baton; + m_fix_indentation_callback_chars = indent_chars; + return false; } -bool -Editline::GetLine (std::string &line, bool &interrupted) -{ - ConfigureEditor (false); - m_input_lines = std::vector<EditLineStringType>(); - m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); +bool Editline::GetLine(std::string &line, bool &interrupted) { + ConfigureEditor(false); + m_input_lines = std::vector<EditLineStringType>(); + m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); - std::lock_guard<std::mutex> guard(m_output_mutex); + std::lock_guard<std::mutex> guard(m_output_mutex); - lldbassert(m_editor_status != EditorStatus::Editing); - if (m_editor_status == EditorStatus::Interrupted) - { - m_editor_status = EditorStatus::Complete; - interrupted = true; - return true; - } - - SetCurrentLine (0); - m_in_history = false; - m_editor_status = EditorStatus::Editing; - m_revert_cursor_index = -1; - - int count; - auto input = el_wgets (m_editline, &count); - - interrupted = m_editor_status == EditorStatus::Interrupted; - if (!interrupted) - { - if (input == nullptr) - { - fprintf (m_output_file, "\n"); - m_editor_status = EditorStatus::EndOfInput; - } - else - { - m_history_sp->Enter (input); + lldbassert(m_editor_status != EditorStatus::Editing); + if (m_editor_status == EditorStatus::Interrupted) { + m_editor_status = EditorStatus::Complete; + interrupted = true; + return true; + } + + SetCurrentLine(0); + m_in_history = false; + m_editor_status = EditorStatus::Editing; + m_revert_cursor_index = -1; + + int count; + auto input = el_wgets(m_editline, &count); + + interrupted = m_editor_status == EditorStatus::Interrupted; + if (!interrupted) { + if (input == nullptr) { + fprintf(m_output_file, "\n"); + m_editor_status = EditorStatus::EndOfInput; + } else { + m_history_sp->Enter(input); #if LLDB_EDITLINE_USE_WCHAR - line = m_utf8conv.to_bytes (SplitLines (input)[0]); + line = m_utf8conv.to_bytes(SplitLines(input)[0]); #else - line = SplitLines (input)[0]; + line = SplitLines(input)[0]; #endif - m_editor_status = EditorStatus::Complete; - } + m_editor_status = EditorStatus::Complete; } - return m_editor_status != EditorStatus::EndOfInput; + } + return m_editor_status != EditorStatus::EndOfInput; } -bool -Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) -{ - ConfigureEditor (true); - - // Print the initial input lines, then move the cursor back up to the start of input - SetBaseLineNumber (first_line_number); - m_input_lines = std::vector<EditLineStringType>(); - m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); - - std::lock_guard<std::mutex> guard(m_output_mutex); - // Begin the line editing loop - DisplayInput(); - SetCurrentLine (0); - MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart); - m_editor_status = EditorStatus::Editing; - m_in_history = false; - - m_revert_cursor_index = -1; - while (m_editor_status == EditorStatus::Editing) - { - int count; - m_current_line_rows = -1; - el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content - el_wgets (m_editline, &count); - } - - interrupted = m_editor_status == EditorStatus::Interrupted; - if (!interrupted) - { - // Save the completed entry in history before returning - m_history_sp->Enter (CombineLines (m_input_lines).c_str()); - - lines = GetInputAsStringList(); - } - return m_editor_status != EditorStatus::EndOfInput; +bool Editline::GetLines(int first_line_number, StringList &lines, + bool &interrupted) { + ConfigureEditor(true); + + // Print the initial input lines, then move the cursor back up to the start of + // input + SetBaseLineNumber(first_line_number); + m_input_lines = std::vector<EditLineStringType>(); + m_input_lines.insert(m_input_lines.begin(), EditLineConstString("")); + + std::lock_guard<std::mutex> guard(m_output_mutex); + // Begin the line editing loop + DisplayInput(); + SetCurrentLine(0); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::BlockStart); + m_editor_status = EditorStatus::Editing; + m_in_history = false; + + m_revert_cursor_index = -1; + while (m_editor_status == EditorStatus::Editing) { + int count; + m_current_line_rows = -1; + el_wpush(m_editline, EditLineConstString( + "\x1b[^")); // Revert to the existing line content + el_wgets(m_editline, &count); + } + + interrupted = m_editor_status == EditorStatus::Interrupted; + if (!interrupted) { + // Save the completed entry in history before returning + m_history_sp->Enter(CombineLines(m_input_lines).c_str()); + + lines = GetInputAsStringList(); + } + return m_editor_status != EditorStatus::EndOfInput; } -void -Editline::PrintAsync (Stream *stream, const char *s, size_t len) -{ - std::lock_guard<std::mutex> guard(m_output_mutex); - if (m_editor_status == EditorStatus::Editing) - { - MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); - fprintf(m_output_file, ANSI_CLEAR_BELOW); - } - stream->Write (s, len); - stream->Flush(); - if (m_editor_status == EditorStatus::Editing) - { - DisplayInput(); - MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); - } +void Editline::PrintAsync(Stream *stream, const char *s, size_t len) { + std::lock_guard<std::mutex> guard(m_output_mutex); + if (m_editor_status == EditorStatus::Editing) { + MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); + fprintf(m_output_file, ANSI_CLEAR_BELOW); + } + stream->Write(s, len); + stream->Flush(); + if (m_editor_status == EditorStatus::Editing) { + DisplayInput(); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); + } } diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index 89587a999d93..4eb9ae15f069 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -34,1028 +34,829 @@ using namespace lldb; using namespace lldb_private; -static const char * -GetStreamOpenModeFromOptions (uint32_t options) -{ - if (options & File::eOpenOptionAppend) - { - if (options & File::eOpenOptionRead) - { - if (options & File::eOpenOptionCanCreateNewOnly) - return "a+x"; - else - return "a+"; - } - else if (options & File::eOpenOptionWrite) - { - if (options & File::eOpenOptionCanCreateNewOnly) - return "ax"; - else - return "a"; - } - } - else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite) - { - if (options & File::eOpenOptionCanCreate) - { - if (options & File::eOpenOptionCanCreateNewOnly) - return "w+x"; - else - return "w+"; - } - else - return "r+"; - } - else if (options & File::eOpenOptionRead) - { - return "r"; - } - else if (options & File::eOpenOptionWrite) - { - return "w"; - } - return NULL; +static const char *GetStreamOpenModeFromOptions(uint32_t options) { + if (options & File::eOpenOptionAppend) { + if (options & File::eOpenOptionRead) { + if (options & File::eOpenOptionCanCreateNewOnly) + return "a+x"; + else + return "a+"; + } else if (options & File::eOpenOptionWrite) { + if (options & File::eOpenOptionCanCreateNewOnly) + return "ax"; + else + return "a"; + } + } else if (options & File::eOpenOptionRead && + options & File::eOpenOptionWrite) { + if (options & File::eOpenOptionCanCreate) { + if (options & File::eOpenOptionCanCreateNewOnly) + return "w+x"; + else + return "w+"; + } else + return "r+"; + } else if (options & File::eOpenOptionRead) { + return "r"; + } else if (options & File::eOpenOptionWrite) { + return "w"; + } + return NULL; } int File::kInvalidDescriptor = -1; -FILE * File::kInvalidStream = NULL; - -File::File(const char *path, uint32_t options, uint32_t permissions) : - IOObject(eFDTypeFile, false), - m_descriptor (kInvalidDescriptor), - m_stream (kInvalidStream), - m_options (), - m_own_stream (false), - m_is_interactive (eLazyBoolCalculate), - m_is_real_terminal (eLazyBoolCalculate) -{ - Open (path, options, permissions); -} - -File::File (const FileSpec& filespec, - uint32_t options, - uint32_t permissions) : - IOObject(eFDTypeFile, false), - m_descriptor (kInvalidDescriptor), - m_stream (kInvalidStream), - m_options (0), - m_own_stream (false), - m_is_interactive (eLazyBoolCalculate), - m_is_real_terminal (eLazyBoolCalculate) +FILE *File::kInvalidStream = NULL; -{ - if (filespec) - { - Open (filespec.GetPath().c_str(), options, permissions); - } +File::File(const char *path, uint32_t options, uint32_t permissions) + : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor), + m_stream(kInvalidStream), m_options(), m_own_stream(false), + m_is_interactive(eLazyBoolCalculate), + m_is_real_terminal(eLazyBoolCalculate) { + Open(path, options, permissions); } -File::~File() +File::File(const FileSpec &filespec, uint32_t options, uint32_t permissions) + : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor), + m_stream(kInvalidStream), m_options(0), m_own_stream(false), + m_is_interactive(eLazyBoolCalculate), + m_is_real_terminal(eLazyBoolCalculate) + { - Close (); + if (filespec) { + Open(filespec.GetPath().c_str(), options, permissions); + } } +File::~File() { Close(); } -int -File::GetDescriptor() const -{ - if (DescriptorIsValid()) - return m_descriptor; +int File::GetDescriptor() const { + if (DescriptorIsValid()) + return m_descriptor; - // Don't open the file descriptor if we don't need to, just get it from the - // stream if we have one. - if (StreamIsValid()) - { + // Don't open the file descriptor if we don't need to, just get it from the + // stream if we have one. + if (StreamIsValid()) { #if defined(LLVM_ON_WIN32) - return _fileno(m_stream); + return _fileno(m_stream); #else - return fileno(m_stream); + return fileno(m_stream); #endif - } + } - // Invalid descriptor and invalid stream, return invalid descriptor. - return kInvalidDescriptor; -} - -IOObject::WaitableHandle -File::GetWaitableHandle() -{ - return m_descriptor; + // Invalid descriptor and invalid stream, return invalid descriptor. + return kInvalidDescriptor; } +IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; } -void -File::SetDescriptor (int fd, bool transfer_ownership) -{ - if (IsValid()) - Close(); - m_descriptor = fd; - m_should_close_fd = transfer_ownership; +void File::SetDescriptor(int fd, bool transfer_ownership) { + if (IsValid()) + Close(); + m_descriptor = fd; + m_should_close_fd = transfer_ownership; } - -FILE * -File::GetStream () -{ - if (!StreamIsValid()) - { - if (DescriptorIsValid()) - { - const char *mode = GetStreamOpenModeFromOptions (m_options); - if (mode) - { - if (!m_should_close_fd) - { - // We must duplicate the file descriptor if we don't own it because - // when you call fdopen, the stream will own the fd +FILE *File::GetStream() { + if (!StreamIsValid()) { + if (DescriptorIsValid()) { + const char *mode = GetStreamOpenModeFromOptions(m_options); + if (mode) { + if (!m_should_close_fd) { +// We must duplicate the file descriptor if we don't own it because +// when you call fdopen, the stream will own the fd #ifdef _WIN32 - m_descriptor = ::_dup(GetDescriptor()); + m_descriptor = ::_dup(GetDescriptor()); #else - m_descriptor = dup(GetDescriptor()); + m_descriptor = dup(GetDescriptor()); #endif - m_should_close_fd = true; - } - - do - { - m_stream = ::fdopen (m_descriptor, mode); - } while (m_stream == NULL && errno == EINTR); - - // If we got a stream, then we own the stream and should no - // longer own the descriptor because fclose() will close it for us - - if (m_stream) - { - m_own_stream = true; - m_should_close_fd = false; - } - } + m_should_close_fd = true; + } + + do { + m_stream = ::fdopen(m_descriptor, mode); + } while (m_stream == NULL && errno == EINTR); + + // If we got a stream, then we own the stream and should no + // longer own the descriptor because fclose() will close it for us + + if (m_stream) { + m_own_stream = true; + m_should_close_fd = false; } + } } - return m_stream; + } + return m_stream; } -void -File::SetStream (FILE *fh, bool transfer_ownership) -{ - if (IsValid()) - Close(); - m_stream = fh; - m_own_stream = transfer_ownership; +void File::SetStream(FILE *fh, bool transfer_ownership) { + if (IsValid()) + Close(); + m_stream = fh; + m_own_stream = transfer_ownership; } -Error -File::Open (const char *path, uint32_t options, uint32_t permissions) -{ - Error error; - if (IsValid()) - Close (); - - int oflag = 0; - const bool read = options & eOpenOptionRead; - const bool write = options & eOpenOptionWrite; - if (write) - { - if (read) - oflag |= O_RDWR; - else - oflag |= O_WRONLY; - - if (options & eOpenOptionAppend) - oflag |= O_APPEND; - - if (options & eOpenOptionTruncate) - oflag |= O_TRUNC; - - if (options & eOpenOptionCanCreate) - oflag |= O_CREAT; - - if (options & eOpenOptionCanCreateNewOnly) - oflag |= O_CREAT | O_EXCL; - } - else if (read) - { - oflag |= O_RDONLY; +Error File::Open(const char *path, uint32_t options, uint32_t permissions) { + Error error; + if (IsValid()) + Close(); + + int oflag = 0; + const bool read = options & eOpenOptionRead; + const bool write = options & eOpenOptionWrite; + if (write) { + if (read) + oflag |= O_RDWR; + else + oflag |= O_WRONLY; + + if (options & eOpenOptionAppend) + oflag |= O_APPEND; + + if (options & eOpenOptionTruncate) + oflag |= O_TRUNC; + + if (options & eOpenOptionCanCreate) + oflag |= O_CREAT; + + if (options & eOpenOptionCanCreateNewOnly) + oflag |= O_CREAT | O_EXCL; + } else if (read) { + oflag |= O_RDONLY; #ifndef _WIN32 - if (options & eOpenOptionDontFollowSymlinks) - oflag |= O_NOFOLLOW; + if (options & eOpenOptionDontFollowSymlinks) + oflag |= O_NOFOLLOW; #endif - } - + } + #ifndef _WIN32 - if (options & eOpenOptionNonBlocking) - oflag |= O_NONBLOCK; - if (options & eOpenOptionCloseOnExec) - oflag |= O_CLOEXEC; + if (options & eOpenOptionNonBlocking) + oflag |= O_NONBLOCK; + if (options & eOpenOptionCloseOnExec) + oflag |= O_CLOEXEC; #else - oflag |= O_BINARY; + oflag |= O_BINARY; #endif - mode_t mode = 0; - if (oflag & O_CREAT) - { - if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR; - if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR; - if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR; - if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP; - if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP; - if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP; - if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH; - if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH; - if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH; - } + mode_t mode = 0; + if (oflag & O_CREAT) { + if (permissions & lldb::eFilePermissionsUserRead) + mode |= S_IRUSR; + if (permissions & lldb::eFilePermissionsUserWrite) + mode |= S_IWUSR; + if (permissions & lldb::eFilePermissionsUserExecute) + mode |= S_IXUSR; + if (permissions & lldb::eFilePermissionsGroupRead) + mode |= S_IRGRP; + if (permissions & lldb::eFilePermissionsGroupWrite) + mode |= S_IWGRP; + if (permissions & lldb::eFilePermissionsGroupExecute) + mode |= S_IXGRP; + if (permissions & lldb::eFilePermissionsWorldRead) + mode |= S_IROTH; + if (permissions & lldb::eFilePermissionsWorldWrite) + mode |= S_IWOTH; + if (permissions & lldb::eFilePermissionsWorldExecute) + mode |= S_IXOTH; + } + + do { +#ifdef _MSC_VER + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(path, wpath)) { + m_descriptor = -1; + error.SetErrorString("Error converting path to UTF-16"); + return error; + } + ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode); +#else + m_descriptor = ::open(path, oflag, mode); +#endif + } while (m_descriptor < 0 && errno == EINTR); + + if (!DescriptorIsValid()) + error.SetErrorToErrno(); + else { + m_should_close_fd = true; + m_options = options; + } + + return error; +} + +uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) { + if (file_spec) { + struct stat file_stats; + int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); + if (stat_result == -1) + error.SetErrorToErrno(); + else { + error.Clear(); + return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + } else + error.SetErrorString("empty file spec"); + return 0; +} + +uint32_t File::GetPermissions(Error &error) const { + int fd = GetDescriptor(); + if (fd != kInvalidDescriptor) { + struct stat file_stats; + if (::fstat(fd, &file_stats) == -1) + error.SetErrorToErrno(); + else { + error.Clear(); + return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + } else { + error.SetErrorString("invalid file descriptor"); + } + return 0; +} + +Error File::Close() { + Error error; + if (StreamIsValid() && m_own_stream) { + if (::fclose(m_stream) == EOF) + error.SetErrorToErrno(); + } + + if (DescriptorIsValid() && m_should_close_fd) { + if (::close(m_descriptor) != 0) + error.SetErrorToErrno(); + } + m_descriptor = kInvalidDescriptor; + m_stream = kInvalidStream; + m_options = 0; + m_own_stream = false; + m_should_close_fd = false; + m_is_interactive = eLazyBoolCalculate; + m_is_real_terminal = eLazyBoolCalculate; + return error; +} + +void File::Clear() { + m_stream = nullptr; + m_descriptor = -1; + m_options = 0; + m_own_stream = false; + m_is_interactive = m_supports_colors = m_is_real_terminal = + eLazyBoolCalculate; +} + +Error File::GetFileSpec(FileSpec &file_spec) const { + Error error; +#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED + if (IsValid()) { + char path[PATH_MAX]; + if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) + error.SetErrorToErrno(); + else + file_spec.SetFile(path, false); + } else { + error.SetErrorString("invalid file handle"); + } +#elif defined(__linux__) + char proc[64]; + char path[PATH_MAX]; + if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) + error.SetErrorString("cannot resolve file descriptor"); + else { + ssize_t len; + if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) + error.SetErrorToErrno(); + else { + path[len] = '\0'; + file_spec.SetFile(path, false); + } + } +#else + error.SetErrorString("File::GetFileSpec is not supported on this platform"); +#endif - do - { + if (error.Fail()) + file_spec.Clear(); + return error; +} + +off_t File::SeekFromStart(off_t offset, Error *error_ptr) { + off_t result = 0; + if (DescriptorIsValid()) { + result = ::lseek(m_descriptor, offset, SEEK_SET); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (StreamIsValid()) { + result = ::fseek(m_stream, offset, SEEK_SET); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (error_ptr) { + error_ptr->SetErrorString("invalid file handle"); + } + return result; +} + +off_t File::SeekFromCurrent(off_t offset, Error *error_ptr) { + off_t result = -1; + if (DescriptorIsValid()) { + result = ::lseek(m_descriptor, offset, SEEK_CUR); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (StreamIsValid()) { + result = ::fseek(m_stream, offset, SEEK_CUR); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (error_ptr) { + error_ptr->SetErrorString("invalid file handle"); + } + return result; +} + +off_t File::SeekFromEnd(off_t offset, Error *error_ptr) { + off_t result = -1; + if (DescriptorIsValid()) { + result = ::lseek(m_descriptor, offset, SEEK_END); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (StreamIsValid()) { + result = ::fseek(m_stream, offset, SEEK_END); + + if (error_ptr) { + if (result == -1) + error_ptr->SetErrorToErrno(); + else + error_ptr->Clear(); + } + } else if (error_ptr) { + error_ptr->SetErrorString("invalid file handle"); + } + return result; +} + +Error File::Flush() { + Error error; + if (StreamIsValid()) { + int err = 0; + do { + err = ::fflush(m_stream); + } while (err == EOF && errno == EINTR); + + if (err == EOF) + error.SetErrorToErrno(); + } else if (!DescriptorIsValid()) { + error.SetErrorString("invalid file handle"); + } + return error; +} + +Error File::Sync() { + Error error; + if (DescriptorIsValid()) { #ifdef _WIN32 - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(path, wpath)) - { - m_descriptor = -1; - error.SetErrorString("Error converting path to UTF-16"); - return error; - } - ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode); + int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); + if (err == 0) + error.SetErrorToGenericError(); #else - m_descriptor = ::open(path, oflag, mode); -#endif - } while (m_descriptor < 0 && errno == EINTR); + int err = 0; + do { + err = ::fsync(m_descriptor); + } while (err == -1 && errno == EINTR); - if (!DescriptorIsValid()) - error.SetErrorToErrno(); - else - { - m_should_close_fd = true; - m_options = options; - } - - return error; + if (err == -1) + error.SetErrorToErrno(); +#endif + } else { + error.SetErrorString("invalid file handle"); + } + return error; } -uint32_t -File::GetPermissions(const FileSpec &file_spec, Error &error) -{ - if (file_spec) - { - struct stat file_stats; - int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); - if (stat_result == -1) - error.SetErrorToErrno(); - else - { - error.Clear(); - return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - } - } - else - error.SetErrorString ("empty file spec"); - return 0; -} +#if defined(__APPLE__) +// Darwin kernels only can read/write <= INT_MAX bytes +#define MAX_READ_SIZE INT_MAX +#define MAX_WRITE_SIZE INT_MAX +#endif -uint32_t -File::GetPermissions(Error &error) const -{ - int fd = GetDescriptor(); - if (fd != kInvalidDescriptor) - { - struct stat file_stats; - if (::fstat (fd, &file_stats) == -1) - error.SetErrorToErrno(); - else - { - error.Clear(); - return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - } - } - else - { - error.SetErrorString ("invalid file descriptor"); - } - return 0; -} +Error File::Read(void *buf, size_t &num_bytes) { + Error error; +#if defined(MAX_READ_SIZE) + if (num_bytes > MAX_READ_SIZE) { + uint8_t *p = (uint8_t *)buf; + size_t bytes_left = num_bytes; + // Init the num_bytes read to zero + num_bytes = 0; -Error -File::Close () -{ - Error error; - if (StreamIsValid() && m_own_stream) - { - if (::fclose (m_stream) == EOF) - error.SetErrorToErrno(); - } - - if (DescriptorIsValid() && m_should_close_fd) - { - if (::close (m_descriptor) != 0) - error.SetErrorToErrno(); - } - m_descriptor = kInvalidDescriptor; - m_stream = kInvalidStream; - m_options = 0; - m_own_stream = false; - m_should_close_fd = false; - m_is_interactive = eLazyBoolCalculate; - m_is_real_terminal = eLazyBoolCalculate; - return error; -} + while (bytes_left > 0) { + size_t curr_num_bytes; + if (bytes_left > MAX_READ_SIZE) + curr_num_bytes = MAX_READ_SIZE; + else + curr_num_bytes = bytes_left; -void -File::Clear () -{ - m_stream = nullptr; - m_descriptor = -1; - m_options = 0; - m_own_stream = false; - m_is_interactive = m_supports_colors = m_is_real_terminal = eLazyBoolCalculate; -} + error = Read(p + num_bytes, curr_num_bytes); -Error -File::GetFileSpec (FileSpec &file_spec) const -{ - Error error; -#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED - if (IsValid ()) - { - char path[PATH_MAX]; - if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) - error.SetErrorToErrno(); - else - file_spec.SetFile (path, false); - } - else - { - error.SetErrorString("invalid file handle"); - } -#elif defined(__linux__) - char proc[64]; - char path[PATH_MAX]; - if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) - error.SetErrorString ("cannot resolve file descriptor"); - else - { - ssize_t len; - if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) - error.SetErrorToErrno(); - else - { - path[len] = '\0'; - file_spec.SetFile (path, false); - } + // Update how many bytes were read + num_bytes += curr_num_bytes; + if (bytes_left < curr_num_bytes) + bytes_left = 0; + else + bytes_left -= curr_num_bytes; + + if (error.Fail()) + break; } -#else - error.SetErrorString ("File::GetFileSpec is not supported on this platform"); + return error; + } #endif - if (error.Fail()) - file_spec.Clear(); - return error; + ssize_t bytes_read = -1; + if (DescriptorIsValid()) { + do { + bytes_read = ::read(m_descriptor, buf, num_bytes); + } while (bytes_read < 0 && errno == EINTR); + + if (bytes_read == -1) { + error.SetErrorToErrno(); + num_bytes = 0; + } else + num_bytes = bytes_read; + } else if (StreamIsValid()) { + bytes_read = ::fread(buf, 1, num_bytes, m_stream); + + if (bytes_read == 0) { + if (::feof(m_stream)) + error.SetErrorString("feof"); + else if (::ferror(m_stream)) + error.SetErrorString("ferror"); + num_bytes = 0; + } else + num_bytes = bytes_read; + } else { + num_bytes = 0; + error.SetErrorString("invalid file handle"); + } + return error; } -off_t -File::SeekFromStart (off_t offset, Error *error_ptr) -{ - off_t result = 0; - if (DescriptorIsValid()) - { - result = ::lseek (m_descriptor, offset, SEEK_SET); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (StreamIsValid ()) - { - result = ::fseek(m_stream, offset, SEEK_SET); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (error_ptr) - { - error_ptr->SetErrorString("invalid file handle"); - } - return result; -} +Error File::Write(const void *buf, size_t &num_bytes) { + Error error; -off_t -File::SeekFromCurrent (off_t offset, Error *error_ptr) -{ - off_t result = -1; - if (DescriptorIsValid()) - { - result = ::lseek (m_descriptor, offset, SEEK_CUR); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (StreamIsValid ()) - { - result = ::fseek(m_stream, offset, SEEK_CUR); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (error_ptr) - { - error_ptr->SetErrorString("invalid file handle"); - } - return result; -} +#if defined(MAX_WRITE_SIZE) + if (num_bytes > MAX_WRITE_SIZE) { + const uint8_t *p = (const uint8_t *)buf; + size_t bytes_left = num_bytes; + // Init the num_bytes written to zero + num_bytes = 0; -off_t -File::SeekFromEnd (off_t offset, Error *error_ptr) -{ - off_t result = -1; - if (DescriptorIsValid()) - { - result = ::lseek (m_descriptor, offset, SEEK_END); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (StreamIsValid ()) - { - result = ::fseek(m_stream, offset, SEEK_END); - - if (error_ptr) - { - if (result == -1) - error_ptr->SetErrorToErrno(); - else - error_ptr->Clear(); - } - } - else if (error_ptr) - { - error_ptr->SetErrorString("invalid file handle"); - } - return result; -} + while (bytes_left > 0) { + size_t curr_num_bytes; + if (bytes_left > MAX_WRITE_SIZE) + curr_num_bytes = MAX_WRITE_SIZE; + else + curr_num_bytes = bytes_left; -Error -File::Flush () -{ - Error error; - if (StreamIsValid()) - { - int err = 0; - do - { - err = ::fflush (m_stream); - } while (err == EOF && errno == EINTR); - - if (err == EOF) - error.SetErrorToErrno(); - } - else if (!DescriptorIsValid()) - { - error.SetErrorString("invalid file handle"); - } - return error; -} + error = Write(p + num_bytes, curr_num_bytes); + // Update how many bytes were read + num_bytes += curr_num_bytes; + if (bytes_left < curr_num_bytes) + bytes_left = 0; + else + bytes_left -= curr_num_bytes; -Error -File::Sync () -{ - Error error; - if (DescriptorIsValid()) - { -#ifdef _WIN32 - int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); - if (err == 0) - error.SetErrorToGenericError(); -#else - int err = 0; - do - { - err = ::fsync (m_descriptor); - } while (err == -1 && errno == EINTR); - - if (err == -1) - error.SetErrorToErrno(); -#endif - } - else - { - error.SetErrorString("invalid file handle"); + if (error.Fail()) + break; } return error; -} - -#if defined (__APPLE__) -// Darwin kernels only can read/write <= INT_MAX bytes -#define MAX_READ_SIZE INT_MAX -#define MAX_WRITE_SIZE INT_MAX + } #endif -Error -File::Read (void *buf, size_t &num_bytes) -{ - Error error; - -#if defined (MAX_READ_SIZE) - if (num_bytes > MAX_READ_SIZE) - { - uint8_t *p = (uint8_t *)buf; - size_t bytes_left = num_bytes; - // Init the num_bytes read to zero - num_bytes = 0; - - while (bytes_left > 0) - { - size_t curr_num_bytes; - if (bytes_left > MAX_READ_SIZE) - curr_num_bytes = MAX_READ_SIZE; - else - curr_num_bytes = bytes_left; - - error = Read (p + num_bytes, curr_num_bytes); - - // Update how many bytes were read - num_bytes += curr_num_bytes; - if (bytes_left < curr_num_bytes) - bytes_left = 0; - else - bytes_left -= curr_num_bytes; - - if (error.Fail()) - break; - } - return error; - } -#endif + ssize_t bytes_written = -1; + if (DescriptorIsValid()) { + do { + bytes_written = ::write(m_descriptor, buf, num_bytes); + } while (bytes_written < 0 && errno == EINTR); + + if (bytes_written == -1) { + error.SetErrorToErrno(); + num_bytes = 0; + } else + num_bytes = bytes_written; + } else if (StreamIsValid()) { + bytes_written = ::fwrite(buf, 1, num_bytes, m_stream); + + if (bytes_written == 0) { + if (::feof(m_stream)) + error.SetErrorString("feof"); + else if (::ferror(m_stream)) + error.SetErrorString("ferror"); + num_bytes = 0; + } else + num_bytes = bytes_written; + + } else { + num_bytes = 0; + error.SetErrorString("invalid file handle"); + } - ssize_t bytes_read = -1; - if (DescriptorIsValid()) - { - do - { - bytes_read = ::read (m_descriptor, buf, num_bytes); - } while (bytes_read < 0 && errno == EINTR); - - if (bytes_read == -1) - { - error.SetErrorToErrno(); - num_bytes = 0; - } - else - num_bytes = bytes_read; - } - else if (StreamIsValid()) - { - bytes_read = ::fread (buf, 1, num_bytes, m_stream); - - if (bytes_read == 0) - { - if (::feof(m_stream)) - error.SetErrorString ("feof"); - else if (::ferror (m_stream)) - error.SetErrorString ("ferror"); - num_bytes = 0; - } - else - num_bytes = bytes_read; - } - else - { - num_bytes = 0; - error.SetErrorString("invalid file handle"); - } - return error; + return error; } - -Error -File::Write (const void *buf, size_t &num_bytes) -{ - Error error; - -#if defined (MAX_WRITE_SIZE) - if (num_bytes > MAX_WRITE_SIZE) - { - const uint8_t *p = (const uint8_t *)buf; - size_t bytes_left = num_bytes; - // Init the num_bytes written to zero - num_bytes = 0; - - while (bytes_left > 0) - { - size_t curr_num_bytes; - if (bytes_left > MAX_WRITE_SIZE) - curr_num_bytes = MAX_WRITE_SIZE; - else - curr_num_bytes = bytes_left; - - error = Write (p + num_bytes, curr_num_bytes); - - // Update how many bytes were read - num_bytes += curr_num_bytes; - if (bytes_left < curr_num_bytes) - bytes_left = 0; - else - bytes_left -= curr_num_bytes; - - if (error.Fail()) - break; - } - return error; - } -#endif - ssize_t bytes_written = -1; - if (DescriptorIsValid()) - { - do - { - bytes_written = ::write (m_descriptor, buf, num_bytes); - } while (bytes_written < 0 && errno == EINTR); - - if (bytes_written == -1) - { - error.SetErrorToErrno(); - num_bytes = 0; - } - else - num_bytes = bytes_written; - } - else if (StreamIsValid()) - { - bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); - - if (bytes_written == 0) - { - if (::feof(m_stream)) - error.SetErrorString ("feof"); - else if (::ferror (m_stream)) - error.SetErrorString ("ferror"); - num_bytes = 0; - } - else - num_bytes = bytes_written; - - } - else - { - num_bytes = 0; - error.SetErrorString("invalid file handle"); - } +Error File::Read(void *buf, size_t &num_bytes, off_t &offset) { + Error error; - return error; -} +#if defined(MAX_READ_SIZE) + if (num_bytes > MAX_READ_SIZE) { + uint8_t *p = (uint8_t *)buf; + size_t bytes_left = num_bytes; + // Init the num_bytes read to zero + num_bytes = 0; + while (bytes_left > 0) { + size_t curr_num_bytes; + if (bytes_left > MAX_READ_SIZE) + curr_num_bytes = MAX_READ_SIZE; + else + curr_num_bytes = bytes_left; -Error -File::Read (void *buf, size_t &num_bytes, off_t &offset) -{ - Error error; - -#if defined (MAX_READ_SIZE) - if (num_bytes > MAX_READ_SIZE) - { - uint8_t *p = (uint8_t *)buf; - size_t bytes_left = num_bytes; - // Init the num_bytes read to zero - num_bytes = 0; - - while (bytes_left > 0) - { - size_t curr_num_bytes; - if (bytes_left > MAX_READ_SIZE) - curr_num_bytes = MAX_READ_SIZE; - else - curr_num_bytes = bytes_left; - - error = Read (p + num_bytes, curr_num_bytes, offset); - - // Update how many bytes were read - num_bytes += curr_num_bytes; - if (bytes_left < curr_num_bytes) - bytes_left = 0; - else - bytes_left -= curr_num_bytes; - - if (error.Fail()) - break; - } - return error; + error = Read(p + num_bytes, curr_num_bytes, offset); + + // Update how many bytes were read + num_bytes += curr_num_bytes; + if (bytes_left < curr_num_bytes) + bytes_left = 0; + else + bytes_left -= curr_num_bytes; + + if (error.Fail()) + break; } + return error; + } #endif #ifndef _WIN32 - int fd = GetDescriptor(); - if (fd != kInvalidDescriptor) - { - ssize_t bytes_read = -1; - do - { - bytes_read = ::pread (fd, buf, num_bytes, offset); - } while (bytes_read < 0 && errno == EINTR); - - if (bytes_read < 0) - { - num_bytes = 0; - error.SetErrorToErrno(); - } - else - { - offset += bytes_read; - num_bytes = bytes_read; - } - } - else - { - num_bytes = 0; - error.SetErrorString("invalid file handle"); - } + int fd = GetDescriptor(); + if (fd != kInvalidDescriptor) { + ssize_t bytes_read = -1; + do { + bytes_read = ::pread(fd, buf, num_bytes, offset); + } while (bytes_read < 0 && errno == EINTR); + + if (bytes_read < 0) { + num_bytes = 0; + error.SetErrorToErrno(); + } else { + offset += bytes_read; + num_bytes = bytes_read; + } + } else { + num_bytes = 0; + error.SetErrorString("invalid file handle"); + } #else - long cur = ::lseek(m_descriptor, 0, SEEK_CUR); - SeekFromStart(offset); - error = Read(buf, num_bytes); - if (!error.Fail()) - SeekFromStart(cur); + long cur = ::lseek(m_descriptor, 0, SEEK_CUR); + SeekFromStart(offset); + error = Read(buf, num_bytes); + if (!error.Fail()) + SeekFromStart(cur); #endif - return error; + return error; } -Error -File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) -{ - Error error; - - if (num_bytes > 0) - { - int fd = GetDescriptor(); - if (fd != kInvalidDescriptor) - { - struct stat file_stats; - if (::fstat (fd, &file_stats) == 0) - { - if (file_stats.st_size > offset) - { - const size_t bytes_left = file_stats.st_size - offset; - if (num_bytes > bytes_left) - num_bytes = bytes_left; - - size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); - std::unique_ptr<DataBufferHeap> data_heap_ap; - data_heap_ap.reset(new DataBufferHeap()); - data_heap_ap->SetByteSize(num_bytes_plus_nul_char); - - if (data_heap_ap.get()) - { - error = Read (data_heap_ap->GetBytes(), num_bytes, offset); - if (error.Success()) - { - // Make sure we read exactly what we asked for and if we got - // less, adjust the array - if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize()) - data_heap_ap->SetByteSize(num_bytes_plus_nul_char); - data_buffer_sp.reset(data_heap_ap.release()); - return error; - } - } - } - else - error.SetErrorString("file is empty"); +Error File::Read(size_t &num_bytes, off_t &offset, bool null_terminate, + DataBufferSP &data_buffer_sp) { + Error error; + + if (num_bytes > 0) { + int fd = GetDescriptor(); + if (fd != kInvalidDescriptor) { + struct stat file_stats; + if (::fstat(fd, &file_stats) == 0) { + if (file_stats.st_size > offset) { + const size_t bytes_left = file_stats.st_size - offset; + if (num_bytes > bytes_left) + num_bytes = bytes_left; + + size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); + std::unique_ptr<DataBufferHeap> data_heap_ap; + data_heap_ap.reset(new DataBufferHeap()); + data_heap_ap->SetByteSize(num_bytes_plus_nul_char); + + if (data_heap_ap.get()) { + error = Read(data_heap_ap->GetBytes(), num_bytes, offset); + if (error.Success()) { + // Make sure we read exactly what we asked for and if we got + // less, adjust the array + if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize()) + data_heap_ap->SetByteSize(num_bytes_plus_nul_char); + data_buffer_sp.reset(data_heap_ap.release()); + return error; } - else - error.SetErrorToErrno(); - } - else - error.SetErrorString("invalid file handle"); - } - else - error.SetErrorString("invalid file handle"); + } + } else + error.SetErrorString("file is empty"); + } else + error.SetErrorToErrno(); + } else + error.SetErrorString("invalid file handle"); + } else + error.SetErrorString("invalid file handle"); - num_bytes = 0; - data_buffer_sp.reset(); - return error; + num_bytes = 0; + data_buffer_sp.reset(); + return error; } -Error -File::Write (const void *buf, size_t &num_bytes, off_t &offset) -{ - Error error; - -#if defined (MAX_WRITE_SIZE) - if (num_bytes > MAX_WRITE_SIZE) - { - const uint8_t *p = (const uint8_t *)buf; - size_t bytes_left = num_bytes; - // Init the num_bytes written to zero - num_bytes = 0; - - while (bytes_left > 0) - { - size_t curr_num_bytes; - if (bytes_left > MAX_WRITE_SIZE) - curr_num_bytes = MAX_WRITE_SIZE; - else - curr_num_bytes = bytes_left; - - error = Write (p + num_bytes, curr_num_bytes, offset); - - // Update how many bytes were read - num_bytes += curr_num_bytes; - if (bytes_left < curr_num_bytes) - bytes_left = 0; - else - bytes_left -= curr_num_bytes; - - if (error.Fail()) - break; - } - return error; +Error File::Write(const void *buf, size_t &num_bytes, off_t &offset) { + Error error; + +#if defined(MAX_WRITE_SIZE) + if (num_bytes > MAX_WRITE_SIZE) { + const uint8_t *p = (const uint8_t *)buf; + size_t bytes_left = num_bytes; + // Init the num_bytes written to zero + num_bytes = 0; + + while (bytes_left > 0) { + size_t curr_num_bytes; + if (bytes_left > MAX_WRITE_SIZE) + curr_num_bytes = MAX_WRITE_SIZE; + else + curr_num_bytes = bytes_left; + + error = Write(p + num_bytes, curr_num_bytes, offset); + + // Update how many bytes were read + num_bytes += curr_num_bytes; + if (bytes_left < curr_num_bytes) + bytes_left = 0; + else + bytes_left -= curr_num_bytes; + + if (error.Fail()) + break; } + return error; + } #endif - int fd = GetDescriptor(); - if (fd != kInvalidDescriptor) - { + int fd = GetDescriptor(); + if (fd != kInvalidDescriptor) { #ifndef _WIN32 - ssize_t bytes_written = -1; - do - { - bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); - } while (bytes_written < 0 && errno == EINTR); - - if (bytes_written < 0) - { - num_bytes = 0; - error.SetErrorToErrno(); - } - else - { - offset += bytes_written; - num_bytes = bytes_written; - } + ssize_t bytes_written = -1; + do { + bytes_written = ::pwrite(m_descriptor, buf, num_bytes, offset); + } while (bytes_written < 0 && errno == EINTR); + + if (bytes_written < 0) { + num_bytes = 0; + error.SetErrorToErrno(); + } else { + offset += bytes_written; + num_bytes = bytes_written; + } #else - long cur = ::lseek(m_descriptor, 0, SEEK_CUR); - error = Write(buf, num_bytes); - long after = ::lseek(m_descriptor, 0, SEEK_CUR); + long cur = ::lseek(m_descriptor, 0, SEEK_CUR); + error = Write(buf, num_bytes); + long after = ::lseek(m_descriptor, 0, SEEK_CUR); - if (!error.Fail()) - SeekFromStart(cur); + if (!error.Fail()) + SeekFromStart(cur); - offset = after; + offset = after; #endif - } - else - { - num_bytes = 0; - error.SetErrorString("invalid file handle"); - } - return error; + } else { + num_bytes = 0; + error.SetErrorString("invalid file handle"); + } + return error; } //------------------------------------------------------------------ // Print some formatted output to the stream. //------------------------------------------------------------------ -size_t -File::Printf (const char *format, ...) -{ - va_list args; - va_start (args, format); - size_t result = PrintfVarArg (format, args); - va_end (args); - return result; +size_t File::Printf(const char *format, ...) { + va_list args; + va_start(args, format); + size_t result = PrintfVarArg(format, args); + va_end(args); + return result; } //------------------------------------------------------------------ // Print some formatted output to the stream. //------------------------------------------------------------------ -size_t -File::PrintfVarArg (const char *format, va_list args) -{ - size_t result = 0; - if (DescriptorIsValid()) - { - char *s = NULL; - result = vasprintf(&s, format, args); - if (s != NULL) - { - if (result > 0) - { - size_t s_len = result; - Write (s, s_len); - result = s_len; - } - free (s); - } - } - else if (StreamIsValid()) - { - result = ::vfprintf (m_stream, format, args); - } - return result; -} - -mode_t -File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options) -{ - mode_t mode = 0; - if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) - mode |= O_RDWR; - else if (open_options & eOpenOptionWrite) - mode |= O_WRONLY; - - if (open_options & eOpenOptionAppend) - mode |= O_APPEND; - - if (open_options & eOpenOptionTruncate) - mode |= O_TRUNC; - - if (open_options & eOpenOptionNonBlocking) - mode |= O_NONBLOCK; - - if (open_options & eOpenOptionCanCreateNewOnly) - mode |= O_CREAT | O_EXCL; - else if (open_options & eOpenOptionCanCreate) - mode |= O_CREAT; - - return mode; -} - -void -File::CalculateInteractiveAndTerminal () -{ - const int fd = GetDescriptor(); - if (fd >= 0) - { - m_is_interactive = eLazyBoolNo; - m_is_real_terminal = eLazyBoolNo; +size_t File::PrintfVarArg(const char *format, va_list args) { + size_t result = 0; + if (DescriptorIsValid()) { + char *s = NULL; + result = vasprintf(&s, format, args); + if (s != NULL) { + if (result > 0) { + size_t s_len = result; + Write(s, s_len); + result = s_len; + } + free(s); + } + } else if (StreamIsValid()) { + result = ::vfprintf(m_stream, format, args); + } + return result; +} + +mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) { + mode_t mode = 0; + if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) + mode |= O_RDWR; + else if (open_options & eOpenOptionWrite) + mode |= O_WRONLY; + + if (open_options & eOpenOptionAppend) + mode |= O_APPEND; + + if (open_options & eOpenOptionTruncate) + mode |= O_TRUNC; + + if (open_options & eOpenOptionNonBlocking) + mode |= O_NONBLOCK; + + if (open_options & eOpenOptionCanCreateNewOnly) + mode |= O_CREAT | O_EXCL; + else if (open_options & eOpenOptionCanCreate) + mode |= O_CREAT; + + return mode; +} + +void File::CalculateInteractiveAndTerminal() { + const int fd = GetDescriptor(); + if (fd >= 0) { + m_is_interactive = eLazyBoolNo; + m_is_real_terminal = eLazyBoolNo; #if defined(_WIN32) - if (_isatty(fd)) - { - m_is_interactive = eLazyBoolYes; - m_is_real_terminal = eLazyBoolYes; - } + if (_isatty(fd)) { + m_is_interactive = eLazyBoolYes; + m_is_real_terminal = eLazyBoolYes; + } #else - if (isatty(fd)) - { - m_is_interactive = eLazyBoolYes; - struct winsize window_size; - if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) - { - if (window_size.ws_col > 0) - { - m_is_real_terminal = eLazyBoolYes; - if (llvm::sys::Process::FileDescriptorHasColors(fd)) - m_supports_colors = eLazyBoolYes; - } - } + if (isatty(fd)) { + m_is_interactive = eLazyBoolYes; + struct winsize window_size; + if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) { + if (window_size.ws_col > 0) { + m_is_real_terminal = eLazyBoolYes; + if (llvm::sys::Process::FileDescriptorHasColors(fd)) + m_supports_colors = eLazyBoolYes; } -#endif + } } +#endif + } } -bool -File::GetIsInteractive () -{ - if (m_is_interactive == eLazyBoolCalculate) - CalculateInteractiveAndTerminal (); - return m_is_interactive == eLazyBoolYes; +bool File::GetIsInteractive() { + if (m_is_interactive == eLazyBoolCalculate) + CalculateInteractiveAndTerminal(); + return m_is_interactive == eLazyBoolYes; } -bool -File::GetIsRealTerminal () -{ - if (m_is_real_terminal == eLazyBoolCalculate) - CalculateInteractiveAndTerminal(); - return m_is_real_terminal == eLazyBoolYes; +bool File::GetIsRealTerminal() { + if (m_is_real_terminal == eLazyBoolCalculate) + CalculateInteractiveAndTerminal(); + return m_is_real_terminal == eLazyBoolYes; } -bool -File::GetIsTerminalWithColors () -{ - if (m_supports_colors == eLazyBoolCalculate) - CalculateInteractiveAndTerminal(); - return m_supports_colors == eLazyBoolYes; +bool File::GetIsTerminalWithColors() { + if (m_supports_colors == eLazyBoolCalculate) + CalculateInteractiveAndTerminal(); + return m_supports_colors == eLazyBoolYes; } - diff --git a/source/Host/common/FileCache.cpp b/source/Host/common/FileCache.cpp index 96b2a2ec02af..db71813e4ffb 100644 --- a/source/Host/common/FileCache.cpp +++ b/source/Host/common/FileCache.cpp @@ -16,112 +16,97 @@ using namespace lldb_private; FileCache *FileCache::m_instance = nullptr; -FileCache & -FileCache::GetInstance() -{ - if (m_instance == nullptr) - m_instance = new FileCache(); +FileCache &FileCache::GetInstance() { + if (m_instance == nullptr) + m_instance = new FileCache(); - return *m_instance; + 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; +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(); +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::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; +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 53c0ab40e676..7f46d303a5d8 100644 --- a/source/Host/common/FileSpec.cpp +++ b/source/Host/common/FileSpec.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #ifndef _WIN32 #include <dirent.h> #else @@ -17,9 +16,9 @@ #ifndef _MSC_VER #include <libgen.h> #endif +#include <fstream> #include <set> #include <string.h> -#include <fstream> #include "lldb/Host/Config.h" // Have to include this before we test the define... #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER @@ -30,14 +29,15 @@ #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/Core/StreamString.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" @@ -49,339 +49,281 @@ using namespace lldb_private; namespace { -bool -PathSyntaxIsPosix(FileSpec::PathSyntax syntax) -{ - return (syntax == FileSpec::ePathSyntaxPosix || - (syntax == FileSpec::ePathSyntaxHostNative && - FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); +bool PathSyntaxIsPosix(FileSpec::PathSyntax syntax) { + return (syntax == FileSpec::ePathSyntaxPosix || + (syntax == FileSpec::ePathSyntaxHostNative && + FileSystem::GetNativePathSyntax() == FileSpec::ePathSyntaxPosix)); } -const char * -GetPathSeparators(FileSpec::PathSyntax syntax) -{ - return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; +const char *GetPathSeparators(FileSpec::PathSyntax syntax) { + return PathSyntaxIsPosix(syntax) ? "/" : "\\/"; } -char -GetPrefferedPathSeparator(FileSpec::PathSyntax syntax) -{ - return GetPathSeparators(syntax)[0]; +char GetPreferredPathSeparator(FileSpec::PathSyntax syntax) { + return GetPathSeparators(syntax)[0]; } -bool -IsPathSeparator(char value, FileSpec::PathSyntax syntax) -{ - return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); +bool IsPathSeparator(char value, FileSpec::PathSyntax syntax) { + return value == '/' || (!PathSyntaxIsPosix(syntax) && value == '\\'); } -void -Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) -{ - if (PathSyntaxIsPosix(syntax)) return; - - std::replace(path.begin(), path.end(), '\\', '/'); - // Windows path can have \\ slashes which can be changed by replace - // call above to //. Here we remove the duplicate. - auto iter = std::unique ( path.begin(), path.end(), - []( char &c1, char &c2 ){ - return (c1 == '/' && c2 == '/');}); - path.erase(iter, path.end()); +void Normalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) { + if (PathSyntaxIsPosix(syntax)) + return; + + std::replace(path.begin(), path.end(), '\\', '/'); + // Windows path can have \\ slashes which can be changed by replace + // call above to //. Here we remove the duplicate. + auto iter = std::unique(path.begin(), path.end(), [](char &c1, char &c2) { + return (c1 == '/' && c2 == '/'); + }); + path.erase(iter, path.end()); } -void -Denormalize(llvm::SmallVectorImpl<char> &path, FileSpec::PathSyntax syntax) -{ - if (PathSyntaxIsPosix(syntax)) return; +void Denormalize(llvm::SmallVectorImpl<char> &path, + FileSpec::PathSyntax syntax) { + if (PathSyntaxIsPosix(syntax)) + return; - std::replace(path.begin(), path.end(), '/', '\\'); + std::replace(path.begin(), path.end(), '/', '\\'); } -bool -GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) -{ - char resolved_path[PATH_MAX]; - if (file_spec->GetPath (resolved_path, sizeof(resolved_path))) - return FileSystem::Stat(resolved_path, stats_ptr) == 0; - return false; +bool GetFileStats(const FileSpec *file_spec, struct stat *stats_ptr) { + char resolved_path[PATH_MAX]; + if (file_spec->GetPath(resolved_path, sizeof(resolved_path))) + return FileSystem::Stat(resolved_path, stats_ptr) == 0; + return false; } -size_t -FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) -{ - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return 0; +size_t FilenamePos(llvm::StringRef str, FileSpec::PathSyntax syntax) { + if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) + return 0; - if (str.size() > 0 && IsPathSeparator(str.back(), syntax)) - return str.size() - 1; + if (str.size() > 0 && IsPathSeparator(str.back(), syntax)) + return str.size() - 1; - size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1); + size_t pos = str.find_last_of(GetPathSeparators(syntax), str.size() - 1); - if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos) - pos = str.find_last_of(':', str.size() - 2); + if (!PathSyntaxIsPosix(syntax) && pos == llvm::StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); - if (pos == llvm::StringRef::npos || (pos == 1 && IsPathSeparator(str[0], syntax))) - return 0; + if (pos == llvm::StringRef::npos || + (pos == 1 && IsPathSeparator(str[0], syntax))) + return 0; - return pos + 1; + return pos + 1; } -size_t -RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) -{ - // case "c:/" - if (!PathSyntaxIsPosix(syntax) && (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax))) - return 2; +size_t RootDirStart(llvm::StringRef str, FileSpec::PathSyntax syntax) { + // case "c:/" + if (!PathSyntaxIsPosix(syntax) && + (str.size() > 2 && str[1] == ':' && IsPathSeparator(str[2], syntax))) + return 2; - // case "//" - if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) - return llvm::StringRef::npos; + // case "//" + if (str.size() == 2 && IsPathSeparator(str[0], syntax) && str[0] == str[1]) + return llvm::StringRef::npos; - // case "//net" - if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] && !IsPathSeparator(str[2], syntax)) - return str.find_first_of(GetPathSeparators(syntax), 2); + // case "//net" + if (str.size() > 3 && IsPathSeparator(str[0], syntax) && str[0] == str[1] && + !IsPathSeparator(str[2], syntax)) + return str.find_first_of(GetPathSeparators(syntax), 2); - // case "/" - if (str.size() > 0 && IsPathSeparator(str[0], syntax)) - return 0; + // case "/" + if (str.size() > 0 && IsPathSeparator(str[0], syntax)) + return 0; - return llvm::StringRef::npos; + return llvm::StringRef::npos; } -size_t -ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) -{ - size_t end_pos = FilenamePos(path, syntax); +size_t ParentPathEnd(llvm::StringRef path, FileSpec::PathSyntax syntax) { + size_t end_pos = FilenamePos(path, syntax); - bool filename_was_sep = path.size() > 0 && IsPathSeparator(path[end_pos], syntax); + bool filename_was_sep = + path.size() > 0 && IsPathSeparator(path[end_pos], syntax); - // Skip separators except for root dir. - size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax); + // Skip separators except for root dir. + size_t root_dir_pos = RootDirStart(path.substr(0, end_pos), syntax); - while (end_pos > 0 && (end_pos - 1) != root_dir_pos && IsPathSeparator(path[end_pos - 1], syntax)) - --end_pos; + while (end_pos > 0 && (end_pos - 1) != root_dir_pos && + IsPathSeparator(path[end_pos - 1], syntax)) + --end_pos; - if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) - return llvm::StringRef::npos; + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return llvm::StringRef::npos; - return end_pos; + return end_pos; } } // end anonymous namespace // Resolves the username part of a path of the form ~user/other/directories, and -// writes the result into dst_path. This will also resolve "~" to the current user. -// If you want to complete "~" to the list of users, pass it to ResolvePartialUsername. -void -FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) -{ +// writes the result into dst_path. This will also resolve "~" to the current +// user. +// If you want to complete "~" to the list of users, pass it to +// ResolvePartialUsername. +void FileSpec::ResolveUsername(llvm::SmallVectorImpl<char> &path) { #if LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path.empty() || path[0] != '~') - return; - - llvm::StringRef path_str(path.data(), path.size()); - size_t slash_pos = path_str.find('/', 1); - if (slash_pos == 1 || path.size() == 1) - { - // A path of ~/ resolves to the current user's home dir - llvm::SmallString<64> home_dir; - // llvm::sys::path::home_directory() only checks if "HOME" is set in the - // environment and does nothing else to locate the user home directory - if (!llvm::sys::path::home_directory(home_dir)) - { - struct passwd *pw = getpwuid(getuid()); - if (pw && pw->pw_dir && pw->pw_dir[0]) - { - // Update our environemnt so llvm::sys::path::home_directory() works next time - setenv("HOME", pw->pw_dir, 0); - home_dir.assign(llvm::StringRef(pw->pw_dir)); - } - else - { - return; - } - } - - // Overwrite the ~ with the first character of the homedir, and insert - // the rest. This way we only trigger one move, whereas an insert - // followed by a delete (or vice versa) would trigger two. - path[0] = home_dir[0]; - path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + if (path.empty() || path[0] != '~') + return; + + llvm::StringRef path_str(path.data(), path.size()); + size_t slash_pos = path_str.find('/', 1); + if (slash_pos == 1 || path.size() == 1) { + // A path of ~/ resolves to the current user's home dir + llvm::SmallString<64> home_dir; + // llvm::sys::path::home_directory() only checks if "HOME" is set in the + // environment and does nothing else to locate the user home directory + if (!llvm::sys::path::home_directory(home_dir)) { + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir && pw->pw_dir[0]) { + // Update our environemnt so llvm::sys::path::home_directory() works + // next time + setenv("HOME", pw->pw_dir, 0); + home_dir.assign(llvm::StringRef(pw->pw_dir)); + } else { return; + } } - - auto username_begin = path.begin()+1; - auto username_end = (slash_pos == llvm::StringRef::npos) - ? path.end() - : (path.begin() + slash_pos); - size_t replacement_length = std::distance(path.begin(), username_end); - - llvm::SmallString<20> username(username_begin, username_end); - struct passwd *user_entry = ::getpwnam(username.c_str()); - if (user_entry != nullptr) - { - // Copy over the first n characters of the path, where n is the smaller of the length - // of the home directory and the slash pos. - llvm::StringRef homedir(user_entry->pw_dir); - size_t initial_copy_length = std::min(homedir.size(), replacement_length); - auto src_begin = homedir.begin(); - auto src_end = src_begin + initial_copy_length; - std::copy(src_begin, src_end, path.begin()); - if (replacement_length > homedir.size()) - { - // We copied the entire home directory, but the ~username portion of the path was - // longer, so there's characters that need to be removed. - path.erase(path.begin() + initial_copy_length, username_end); - } - else if (replacement_length < homedir.size()) - { - // We copied all the way up to the slash in the destination, but there's still more - // characters that need to be inserted. - path.insert(username_end, src_end, homedir.end()); - } - } - else - { - // Unable to resolve username (user doesn't exist?) - path.clear(); + + // Overwrite the ~ with the first character of the homedir, and insert + // the rest. This way we only trigger one move, whereas an insert + // followed by a delete (or vice versa) would trigger two. + path[0] = home_dir[0]; + path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + return; + } + + auto username_begin = path.begin() + 1; + auto username_end = (slash_pos == llvm::StringRef::npos) + ? path.end() + : (path.begin() + slash_pos); + size_t replacement_length = std::distance(path.begin(), username_end); + + llvm::SmallString<20> username(username_begin, username_end); + struct passwd *user_entry = ::getpwnam(username.c_str()); + if (user_entry != nullptr) { + // Copy over the first n characters of the path, where n is the smaller of + // the length + // of the home directory and the slash pos. + llvm::StringRef homedir(user_entry->pw_dir); + size_t initial_copy_length = std::min(homedir.size(), replacement_length); + auto src_begin = homedir.begin(); + auto src_end = src_begin + initial_copy_length; + std::copy(src_begin, src_end, path.begin()); + if (replacement_length > homedir.size()) { + // We copied the entire home directory, but the ~username portion of the + // path was + // longer, so there's characters that need to be removed. + path.erase(path.begin() + initial_copy_length, username_end); + } else if (replacement_length < homedir.size()) { + // We copied all the way up to the slash in the destination, but there's + // still more + // characters that need to be inserted. + path.insert(username_end, src_end, homedir.end()); } + } else { + // Unable to resolve username (user doesn't exist?) + path.clear(); + } #endif } -size_t -FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) -{ +size_t FileSpec::ResolvePartialUsername(llvm::StringRef partial_name, + StringList &matches) { #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - size_t extant_entries = matches.GetSize(); - - setpwent(); - struct passwd *user_entry; - const char *name_start = partial_name + 1; - std::set<std::string> name_list; - - while ((user_entry = getpwent()) != NULL) - { - if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name) - { - std::string tmp_buf("~"); - tmp_buf.append(user_entry->pw_name); - tmp_buf.push_back('/'); - name_list.insert(tmp_buf); - } - } - std::set<std::string>::iterator pos, end = name_list.end(); - for (pos = name_list.begin(); pos != end; pos++) - { - matches.AppendString((*pos).c_str()); + size_t extant_entries = matches.GetSize(); + + setpwent(); + struct passwd *user_entry; + partial_name = partial_name.drop_front(); + std::set<std::string> name_list; + + while ((user_entry = getpwent()) != NULL) { + if (llvm::StringRef(user_entry->pw_name).startswith(partial_name)) { + std::string tmp_buf("~"); + tmp_buf.append(user_entry->pw_name); + tmp_buf.push_back('/'); + name_list.insert(tmp_buf); } - return matches.GetSize() - extant_entries; + } + + for (auto &name : name_list) { + matches.AppendString(name); + } + return matches.GetSize() - extant_entries; #else - // Resolving home directories is not supported, just copy the path... - return 0; -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER + // Resolving home directories is not supported, just copy the path... + return 0; +#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER } -void -FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) -{ - if (path.empty()) - return; +void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) { + if (path.empty()) + return; #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (path[0] == '~') - ResolveUsername(path); + if (path[0] == '~') + ResolveUsername(path); #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - // Save a copy of the original path that's passed in - llvm::SmallString<128> original_path(path.begin(), path.end()); + // Save a copy of the original path that's passed in + llvm::SmallString<128> original_path(path.begin(), path.end()); - llvm::sys::fs::make_absolute(path); - if (!llvm::sys::fs::exists(path)) - { - path.clear(); - path.append(original_path.begin(), original_path.end()); - } + llvm::sys::fs::make_absolute(path); + if (!llvm::sys::fs::exists(path)) { + path.clear(); + path.append(original_path.begin(), original_path.end()); + } } -FileSpec::FileSpec() : - m_directory(), - m_filename(), - m_syntax(FileSystem::GetNativePathSyntax()) -{ -} +FileSpec::FileSpec() : m_syntax(FileSystem::GetNativePathSyntax()) {} //------------------------------------------------------------------ // Default constructor that can take an optional full path to a // file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : - m_directory(), - m_filename(), - m_is_resolved(false), - m_syntax(syntax) -{ - if (pathname && pathname[0]) - SetFile(pathname, resolve_path, syntax); -} - -FileSpec::FileSpec(const char *pathname, bool resolve_path, ArchSpec arch) : - FileSpec{pathname, resolve_path, arch.GetTriple().isOSWindows() ? ePathSyntaxWindows : ePathSyntaxPosix} -{ -} - -FileSpec::FileSpec(const std::string &path, bool resolve_path, PathSyntax syntax) : - FileSpec{path.c_str(), resolve_path, syntax} -{ +FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, PathSyntax syntax) + : m_syntax(syntax) { + SetFile(path, resolve_path, syntax); } -FileSpec::FileSpec(const std::string &path, bool resolve_path, ArchSpec arch) : - FileSpec{path.c_str(), resolve_path, arch} -{ -} +FileSpec::FileSpec(llvm::StringRef path, bool resolve_path, ArchSpec arch) + : FileSpec{path, resolve_path, arch.GetTriple().isOSWindows() + ? ePathSyntaxWindows + : ePathSyntaxPosix} {} //------------------------------------------------------------------ // Copy constructor //------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec& rhs) : - m_directory (rhs.m_directory), - m_filename (rhs.m_filename), - m_is_resolved (rhs.m_is_resolved), - m_syntax (rhs.m_syntax) -{ -} +FileSpec::FileSpec(const FileSpec &rhs) + : m_directory(rhs.m_directory), m_filename(rhs.m_filename), + m_is_resolved(rhs.m_is_resolved), m_syntax(rhs.m_syntax) {} //------------------------------------------------------------------ // Copy constructor //------------------------------------------------------------------ -FileSpec::FileSpec(const FileSpec* rhs) : - m_directory(), - m_filename() -{ - if (rhs) - *this = *rhs; +FileSpec::FileSpec(const FileSpec *rhs) : m_directory(), m_filename() { + if (rhs) + *this = *rhs; } //------------------------------------------------------------------ // Virtual destructor in case anyone inherits from this class. //------------------------------------------------------------------ -FileSpec::~FileSpec() -{ -} +FileSpec::~FileSpec() {} //------------------------------------------------------------------ // Assignment operator. //------------------------------------------------------------------ -const FileSpec& -FileSpec::operator= (const FileSpec& rhs) -{ - if (this != &rhs) - { - m_directory = rhs.m_directory; - m_filename = rhs.m_filename; - m_is_resolved = rhs.m_is_resolved; - m_syntax = rhs.m_syntax; - } - return *this; +const FileSpec &FileSpec::operator=(const FileSpec &rhs) { + if (this != &rhs) { + m_directory = rhs.m_directory; + m_filename = rhs.m_filename; + m_is_resolved = rhs.m_is_resolved; + m_syntax = rhs.m_syntax; + } + return *this; } //------------------------------------------------------------------ @@ -389,66 +331,57 @@ FileSpec::operator= (const FileSpec& rhs) // be split up into a directory and filename and stored as uniqued // string values for quick comparison and efficient memory usage. //------------------------------------------------------------------ -void -FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) -{ - m_filename.Clear(); - m_directory.Clear(); - m_is_resolved = false; - m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax; - - if (pathname == NULL || pathname[0] == '\0') - return; - - llvm::SmallString<64> resolved(pathname); - - if (resolve) - { - FileSpec::Resolve (resolved); - m_is_resolved = true; - } +void FileSpec::SetFile(llvm::StringRef pathname, bool resolve, + PathSyntax syntax) { + // CLEANUP: Use StringRef for string handling. This function is kind of a + // mess and the unclear semantics of RootDirStart and ParentPathEnd make + // it very difficult to understand this function. There's no reason this + // function should be particularly complicated or difficult to understand. + m_filename.Clear(); + m_directory.Clear(); + m_is_resolved = false; + m_syntax = (syntax == ePathSyntaxHostNative) + ? FileSystem::GetNativePathSyntax() + : syntax; + + if (pathname.empty()) + return; - Normalize(resolved, syntax); + llvm::SmallString<64> resolved(pathname); - llvm::StringRef resolve_path_ref(resolved.c_str()); - size_t dir_end = ParentPathEnd(resolve_path_ref, syntax); - if (dir_end == 0) - { - m_filename.SetString(resolve_path_ref); - return; - } + if (resolve) { + FileSpec::Resolve(resolved); + m_is_resolved = true; + } - m_directory.SetString(resolve_path_ref.substr(0, dir_end)); + Normalize(resolved, m_syntax); - size_t filename_begin = dir_end; - size_t root_dir_start = RootDirStart(resolve_path_ref, syntax); - while (filename_begin != llvm::StringRef::npos && filename_begin < resolve_path_ref.size() && - filename_begin != root_dir_start && IsPathSeparator(resolve_path_ref[filename_begin], syntax)) - ++filename_begin; - m_filename.SetString((filename_begin == llvm::StringRef::npos || filename_begin >= resolve_path_ref.size()) - ? "." - : resolve_path_ref.substr(filename_begin)); -} + llvm::StringRef resolve_path_ref(resolved.c_str()); + size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax); + if (dir_end == 0) { + m_filename.SetString(resolve_path_ref); + return; + } -void -FileSpec::SetFile(const char *pathname, bool resolve, ArchSpec arch) -{ - return SetFile(pathname, resolve, - arch.GetTriple().isOSWindows() - ? ePathSyntaxWindows - : ePathSyntaxPosix); -} + m_directory.SetString(resolve_path_ref.substr(0, dir_end)); -void -FileSpec::SetFile(const std::string &pathname, bool resolve, PathSyntax syntax) -{ - return SetFile(pathname.c_str(), resolve, syntax); + size_t filename_begin = dir_end; + size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax); + while (filename_begin != llvm::StringRef::npos && + filename_begin < resolve_path_ref.size() && + filename_begin != root_dir_start && + IsPathSeparator(resolve_path_ref[filename_begin], m_syntax)) + ++filename_begin; + m_filename.SetString((filename_begin == llvm::StringRef::npos || + filename_begin >= resolve_path_ref.size()) + ? "." + : resolve_path_ref.substr(filename_begin)); } -void -FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch) -{ - return SetFile(pathname.c_str(), resolve, arch); +void FileSpec::SetFile(llvm::StringRef path, bool resolve, ArchSpec arch) { + return SetFile(path, resolve, arch.GetTriple().isOSWindows() + ? ePathSyntaxWindows + : ePathSyntaxPosix); } //---------------------------------------------------------------------- @@ -458,10 +391,7 @@ FileSpec::SetFile(const std::string &pathname, bool resolve, ArchSpec arch) // if (file_spec) // {} //---------------------------------------------------------------------- -FileSpec::operator bool() const -{ - return m_filename || m_directory; -} +FileSpec::operator bool() const { return m_filename || m_directory; } //---------------------------------------------------------------------- // Logical NOT operator. This allows code to check any FileSpec @@ -470,123 +400,96 @@ FileSpec::operator bool() const // if (!file_spec) // {} //---------------------------------------------------------------------- -bool -FileSpec::operator!() const -{ - return !m_directory && !m_filename; -} +bool FileSpec::operator!() const { return !m_directory && !m_filename; } -bool -FileSpec::DirectoryEquals(const FileSpec &rhs) const -{ - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive); +bool FileSpec::DirectoryEquals(const FileSpec &rhs) const { + const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); + return ConstString::Equals(m_directory, rhs.m_directory, case_sensitive); } -bool -FileSpec::FileEquals(const FileSpec &rhs) const -{ - const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); - return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive); +bool FileSpec::FileEquals(const FileSpec &rhs) const { + const bool case_sensitive = IsCaseSensitive() || rhs.IsCaseSensitive(); + return ConstString::Equals(m_filename, rhs.m_filename, case_sensitive); } //------------------------------------------------------------------ // Equal to operator //------------------------------------------------------------------ -bool -FileSpec::operator== (const FileSpec& rhs) const -{ - if (!FileEquals(rhs)) - return false; - if (DirectoryEquals(rhs)) - return true; - - // TODO: determine if we want to keep this code in here. - // The code below was added to handle a case where we were - // trying to set a file and line breakpoint and one path - // was resolved, and the other not and the directory was - // in a mount point that resolved to a more complete path: - // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling - // this out... - if (IsResolved() && rhs.IsResolved()) - { - // Both paths are resolved, no need to look further... - return false; - } - - FileSpec resolved_lhs(*this); - - // If "this" isn't resolved, resolve it - if (!IsResolved()) - { - if (resolved_lhs.ResolvePath()) - { - // This path wasn't resolved but now it is. Check if the resolved - // directory is the same as our unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - m_is_resolved = (m_directory == resolved_lhs.m_directory); - } - else - return false; - } - - FileSpec resolved_rhs(rhs); - if (!rhs.IsResolved()) - { - if (resolved_rhs.ResolvePath()) - { - // rhs's path wasn't resolved but now it is. Check if the resolved - // directory is the same as rhs's unresolved directory, and if so, - // we can mark this object as resolved to avoid more future resolves - rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); - } - else - return false; - } - - // If we reach this point in the code we were able to resolve both paths - // and since we only resolve the paths if the basenames are equal, then - // we can just check if both directories are equal... - return DirectoryEquals(rhs); +bool FileSpec::operator==(const FileSpec &rhs) const { + if (!FileEquals(rhs)) + return false; + if (DirectoryEquals(rhs)) + return true; + + // TODO: determine if we want to keep this code in here. + // The code below was added to handle a case where we were + // trying to set a file and line breakpoint and one path + // was resolved, and the other not and the directory was + // in a mount point that resolved to a more complete path: + // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling + // this out... + if (IsResolved() && rhs.IsResolved()) { + // Both paths are resolved, no need to look further... + return false; + } + + FileSpec resolved_lhs(*this); + + // If "this" isn't resolved, resolve it + if (!IsResolved()) { + if (resolved_lhs.ResolvePath()) { + // This path wasn't resolved but now it is. Check if the resolved + // directory is the same as our unresolved directory, and if so, + // we can mark this object as resolved to avoid more future resolves + m_is_resolved = (m_directory == resolved_lhs.m_directory); + } else + return false; + } + + FileSpec resolved_rhs(rhs); + if (!rhs.IsResolved()) { + if (resolved_rhs.ResolvePath()) { + // rhs's path wasn't resolved but now it is. Check if the resolved + // directory is the same as rhs's unresolved directory, and if so, + // we can mark this object as resolved to avoid more future resolves + rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory); + } else + return false; + } + + // If we reach this point in the code we were able to resolve both paths + // and since we only resolve the paths if the basenames are equal, then + // we can just check if both directories are equal... + return DirectoryEquals(rhs); } //------------------------------------------------------------------ // Not equal to operator //------------------------------------------------------------------ -bool -FileSpec::operator!= (const FileSpec& rhs) const -{ - return !(*this == rhs); -} +bool FileSpec::operator!=(const FileSpec &rhs) const { return !(*this == rhs); } //------------------------------------------------------------------ // Less than operator //------------------------------------------------------------------ -bool -FileSpec::operator< (const FileSpec& rhs) const -{ - return FileSpec::Compare(*this, rhs, true) < 0; +bool FileSpec::operator<(const FileSpec &rhs) const { + return FileSpec::Compare(*this, rhs, true) < 0; } //------------------------------------------------------------------ // Dump a FileSpec object to a stream //------------------------------------------------------------------ -Stream& -lldb_private::operator << (Stream &s, const FileSpec& f) -{ - f.Dump(&s); - return s; +Stream &lldb_private::operator<<(Stream &s, const FileSpec &f) { + f.Dump(&s); + return s; } //------------------------------------------------------------------ // Clear this object by releasing both the directory and filename // string values and making them both the empty string. //------------------------------------------------------------------ -void -FileSpec::Clear() -{ - m_directory.Clear(); - m_filename.Clear(); +void FileSpec::Clear() { + m_directory.Clear(); + m_filename.Clear(); } //------------------------------------------------------------------ @@ -600,166 +503,102 @@ FileSpec::Clear() // Return -1 if the "a" is less than "b", 0 if "a" is equal to "b" // and "1" if "a" is greater than "b". //------------------------------------------------------------------ -int -FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full) -{ - int result = 0; - - // case sensitivity of compare - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - // If full is true, then we must compare both the directory and filename. - - // If full is false, then if either directory is empty, then we match on - // the basename only, and if both directories have valid values, we still - // do a full compare. This allows for matching when we just have a filename - // in one of the FileSpec objects. - - if (full || (a.m_directory && b.m_directory)) - { - result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive); - if (result) - return result; - } - return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive); -} +int FileSpec::Compare(const FileSpec &a, const FileSpec &b, bool full) { + int result = 0; -bool -FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full, bool remove_backups) -{ - // case sensitivity of equality test - const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - - if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) - return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); - else if (remove_backups == false) - return a == b; - else - { - if (!ConstString::Equals(a.m_filename, b.m_filename, case_sensitive)) - return false; - if (ConstString::Equals(a.m_directory, b.m_directory, case_sensitive)) - return true; - ConstString a_without_dots; - ConstString b_without_dots; + // case sensitivity of compare + const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); - RemoveBackupDots (a.m_directory, a_without_dots); - RemoveBackupDots (b.m_directory, b_without_dots); - return ConstString::Equals(a_without_dots, b_without_dots, case_sensitive); - } + // If full is true, then we must compare both the directory and filename. + + // If full is false, then if either directory is empty, then we match on + // the basename only, and if both directories have valid values, we still + // do a full compare. This allows for matching when we just have a filename + // in one of the FileSpec objects. + + if (full || (a.m_directory && b.m_directory)) { + result = ConstString::Compare(a.m_directory, b.m_directory, case_sensitive); + if (result) + return result; + } + return ConstString::Compare(a.m_filename, b.m_filename, case_sensitive); } -void -FileSpec::NormalizePath () -{ - ConstString normalized_directory; - FileSpec::RemoveBackupDots(m_directory, normalized_directory); - m_directory = normalized_directory; +bool FileSpec::Equal(const FileSpec &a, const FileSpec &b, bool full, + bool remove_backups) { + // case sensitivity of equality test + const bool case_sensitive = a.IsCaseSensitive() || b.IsCaseSensitive(); + + if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty())) + return ConstString::Equals(a.m_filename, b.m_filename, case_sensitive); + + if (remove_backups == false) + return a == b; + + if (a == b) + return true; + + return Equal(a.GetNormalizedPath(), b.GetNormalizedPath(), full, false); } -void -FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &result_const_str) -{ - const char *input = input_const_str.GetCString(); - result_const_str.Clear(); - if (!input || input[0] == '\0') - return; +FileSpec FileSpec::GetNormalizedPath() const { + // Fast path. Do nothing if the path is not interesting. + if (!m_directory.GetStringRef().contains(".") && + !m_directory.GetStringRef().contains("//") && + m_filename.GetStringRef() != ".." && m_filename.GetStringRef() != ".") + return *this; - const char win_sep = '\\'; - const char unix_sep = '/'; - char found_sep; - const char *win_backup = "\\.."; - const char *unix_backup = "/.."; - - bool is_win = false; - - // Determine the platform for the path (win or unix): - - if (input[0] == win_sep) - is_win = true; - else if (input[0] == unix_sep) - is_win = false; - else if (input[1] == ':') - is_win = true; - else if (strchr(input, unix_sep) != nullptr) - is_win = false; - else if (strchr(input, win_sep) != nullptr) - is_win = true; - else - { - // No separators at all, no reason to do any work here. - result_const_str = input_const_str; - return; + llvm::SmallString<64> path, result; + const bool normalize = false; + GetPath(path, normalize); + llvm::StringRef rest(path); + + // We will not go below root dir. + size_t root_dir_start = RootDirStart(path, m_syntax); + const bool absolute = root_dir_start != llvm::StringRef::npos; + if (absolute) { + result += rest.take_front(root_dir_start + 1); + rest = rest.drop_front(root_dir_start + 1); + } else { + if (m_syntax == ePathSyntaxWindows && path.size() > 2 && path[1] == ':') { + result += rest.take_front(2); + rest = rest.drop_front(2); } - - llvm::StringRef backup_sep; - if (is_win) - { - found_sep = win_sep; - backup_sep = win_backup; + } + + bool anything_added = false; + llvm::SmallVector<llvm::StringRef, 0> components, processed; + rest.split(components, '/', -1, false); + processed.reserve(components.size()); + for (auto component : components) { + if (component == ".") + continue; // Skip these. + if (component != "..") { + processed.push_back(component); + continue; // Regular file name. } - else - { - found_sep = unix_sep; - backup_sep = unix_backup; + if (!processed.empty()) { + processed.pop_back(); + continue; // Dots. Go one level up if we can. } - - llvm::StringRef input_ref(input); - llvm::StringRef curpos(input); - - bool had_dots = false; - std::string result; - - while (1) - { - // Start of loop - llvm::StringRef before_sep; - std::pair<llvm::StringRef, llvm::StringRef> around_sep = curpos.split(backup_sep); - - before_sep = around_sep.first; - curpos = around_sep.second; - - if (curpos.empty()) - { - if (had_dots) - { - while (before_sep.startswith("//")) - before_sep = before_sep.substr(1); - if (!before_sep.empty()) - { - result.append(before_sep.data(), before_sep.size()); - } - } - break; - } - had_dots = true; - - unsigned num_backups = 1; - while (curpos.startswith(backup_sep)) - { - num_backups++; - curpos = curpos.slice(backup_sep.size(), curpos.size()); - } - - size_t end_pos = before_sep.size(); - while (num_backups-- > 0) - { - end_pos = before_sep.rfind(found_sep, end_pos); - if (end_pos == llvm::StringRef::npos) - { - result_const_str = input_const_str; - return; - } - } - result.append(before_sep.data(), end_pos); - } - - if (had_dots) - result_const_str.SetCString(result.c_str()); - else - result_const_str = input_const_str; - - return; + if (absolute) + continue; // We're at the top level. Cannot go higher than that. Skip. + + result += component; // We're a relative path. We need to keep these. + result += '/'; + anything_added = true; + } + for (auto component : processed) { + result += component; + result += '/'; + anything_added = true; + } + if (anything_added) + result.pop_back(); // Pop last '/'. + else if (result.empty()) + result = "."; + + return FileSpec(result, false, m_syntax); } //------------------------------------------------------------------ @@ -767,279 +606,223 @@ FileSpec::RemoveBackupDots (const ConstString &input_const_str, ConstString &res // a valid directory name, it will be displayed followed by a // directory delimiter, and the filename. //------------------------------------------------------------------ -void -FileSpec::Dump(Stream *s) const -{ - if (s) - { - std::string path{GetPath(true)}; - s->PutCString(path.c_str()); - char path_separator = GetPrefferedPathSeparator(m_syntax); - if (!m_filename && !path.empty() && path.back() != path_separator) - s->PutChar(path_separator); - } +void FileSpec::Dump(Stream *s) const { + if (s) { + std::string path{GetPath(true)}; + s->PutCString(path); + char path_separator = GetPreferredPathSeparator(m_syntax); + if (!m_filename && !path.empty() && path.back() != path_separator) + s->PutChar(path_separator); + } } //------------------------------------------------------------------ // Returns true if the file exists. //------------------------------------------------------------------ -bool -FileSpec::Exists () const -{ - struct stat file_stats; - return GetFileStats (this, &file_stats); -} - -bool -FileSpec::Readable () const -{ - const uint32_t permissions = GetPermissions(); - if (permissions & eFilePermissionsEveryoneR) - return true; - return false; -} - -bool -FileSpec::ResolveExecutableLocation () -{ - if (!m_directory) - { - const char *file_cstr = m_filename.GetCString(); - if (file_cstr) - { - const std::string file_str (file_cstr); - llvm::ErrorOr<std::string> error_or_path = llvm::sys::findProgramByName (file_str); - if (!error_or_path) - return false; - std::string path = error_or_path.get(); - llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - if (!dir_ref.empty()) - { - // FindProgramByName returns "." if it can't find the file. - if (strcmp (".", dir_ref.data()) == 0) - return false; - - m_directory.SetCString (dir_ref.data()); - if (Exists()) - return true; - else - { - // If FindProgramByName found the file, it returns the directory + filename in its return results. - // We need to separate them. - FileSpec tmp_file (dir_ref.data(), false); - if (tmp_file.Exists()) - { - m_directory = tmp_file.m_directory; - return true; - } - } - } +bool FileSpec::Exists() const { + struct stat file_stats; + return GetFileStats(this, &file_stats); +} + +bool FileSpec::Readable() const { + const uint32_t permissions = GetPermissions(); + if (permissions & eFilePermissionsEveryoneR) + return true; + return false; +} + +bool FileSpec::ResolveExecutableLocation() { + // CLEANUP: Use StringRef for string handling. + if (!m_directory) { + const char *file_cstr = m_filename.GetCString(); + if (file_cstr) { + const std::string file_str(file_cstr); + llvm::ErrorOr<std::string> error_or_path = + llvm::sys::findProgramByName(file_str); + if (!error_or_path) + return false; + std::string path = error_or_path.get(); + llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); + if (!dir_ref.empty()) { + // FindProgramByName returns "." if it can't find the file. + if (strcmp(".", dir_ref.data()) == 0) + return false; + + m_directory.SetCString(dir_ref.data()); + if (Exists()) + return true; + else { + // If FindProgramByName found the file, it returns the directory + + // filename in its return results. + // We need to separate them. + FileSpec tmp_file(dir_ref.data(), false); + if (tmp_file.Exists()) { + m_directory = tmp_file.m_directory; + return true; + } } + } } - - return false; + } + + return false; } -bool -FileSpec::ResolvePath () -{ - if (m_is_resolved) - return true; // We have already resolved this path +bool FileSpec::ResolvePath() { + if (m_is_resolved) + return true; // We have already resolved this path - char path_buf[PATH_MAX]; - if (!GetPath (path_buf, PATH_MAX, false)) - return false; - // SetFile(...) will set m_is_resolved correctly if it can resolve the path - SetFile (path_buf, true); - return m_is_resolved; + char path_buf[PATH_MAX]; + if (!GetPath(path_buf, PATH_MAX, false)) + return false; + // SetFile(...) will set m_is_resolved correctly if it can resolve the path + SetFile(path_buf, true); + return m_is_resolved; } -uint64_t -FileSpec::GetByteSize() const -{ - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - return file_stats.st_size; - return 0; +uint64_t FileSpec::GetByteSize() const { + struct stat file_stats; + if (GetFileStats(this, &file_stats)) + return file_stats.st_size; + return 0; } -FileSpec::PathSyntax -FileSpec::GetPathSyntax() const -{ - return m_syntax; -} +FileSpec::PathSyntax FileSpec::GetPathSyntax() const { return m_syntax; } -FileSpec::FileType -FileSpec::GetFileType () const -{ - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - { - mode_t file_type = file_stats.st_mode & S_IFMT; - switch (file_type) - { - case S_IFDIR: return eFileTypeDirectory; - case S_IFREG: return eFileTypeRegular; +FileSpec::FileType FileSpec::GetFileType() const { + struct stat file_stats; + if (GetFileStats(this, &file_stats)) { + mode_t file_type = file_stats.st_mode & S_IFMT; + switch (file_type) { + case S_IFDIR: + return eFileTypeDirectory; + case S_IFREG: + return eFileTypeRegular; #ifndef _WIN32 - case S_IFIFO: return eFileTypePipe; - case S_IFSOCK: return eFileTypeSocket; - case S_IFLNK: return eFileTypeSymbolicLink; + case S_IFIFO: + return eFileTypePipe; + case S_IFSOCK: + return eFileTypeSocket; + case S_IFLNK: + return eFileTypeSymbolicLink; #endif - default: - break; - } - return eFileTypeUnknown; + default: + break; } - return eFileTypeInvalid; + return eFileTypeUnknown; + } + return eFileTypeInvalid; } -bool -FileSpec::IsSymbolicLink () const -{ - char resolved_path[PATH_MAX]; - if (!GetPath (resolved_path, sizeof (resolved_path))) - return false; +bool FileSpec::IsSymbolicLink() const { + char resolved_path[PATH_MAX]; + if (!GetPath(resolved_path, sizeof(resolved_path))) + return false; #ifdef _WIN32 - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) - return false; - auto attrs = ::GetFileAttributesW(wpath.c_str()); - if (attrs == INVALID_FILE_ATTRIBUTES) - return false; + std::wstring wpath; + if (!llvm::ConvertUTF8toWide(resolved_path, wpath)) + return false; + auto attrs = ::GetFileAttributesW(wpath.c_str()); + if (attrs == INVALID_FILE_ATTRIBUTES) + return false; - return (attrs & FILE_ATTRIBUTE_REPARSE_POINT); + return (attrs & FILE_ATTRIBUTE_REPARSE_POINT); #else - struct stat file_stats; - if (::lstat (resolved_path, &file_stats) != 0) - return false; + struct stat file_stats; + if (::lstat(resolved_path, &file_stats) != 0) + return false; - return (file_stats.st_mode & S_IFMT) == S_IFLNK; + return (file_stats.st_mode & S_IFMT) == S_IFLNK; #endif } -uint32_t -FileSpec::GetPermissions () const -{ - uint32_t file_permissions = 0; - if (*this) - FileSystem::GetFilePermissions(*this, file_permissions); - return file_permissions; -} - -TimeValue -FileSpec::GetModificationTime () const -{ - TimeValue mod_time; - struct stat file_stats; - if (GetFileStats (this, &file_stats)) - mod_time.OffsetWithSeconds(file_stats.st_mtime); - return mod_time; +uint32_t FileSpec::GetPermissions() const { + uint32_t file_permissions = 0; + if (*this) + FileSystem::GetFilePermissions(*this, file_permissions); + return file_permissions; } //------------------------------------------------------------------ // Directory string get accessor. //------------------------------------------------------------------ -ConstString & -FileSpec::GetDirectory() -{ - return m_directory; -} +ConstString &FileSpec::GetDirectory() { return m_directory; } //------------------------------------------------------------------ // Directory string const get accessor. //------------------------------------------------------------------ -const ConstString & -FileSpec::GetDirectory() const -{ - return m_directory; -} +const ConstString &FileSpec::GetDirectory() const { return m_directory; } //------------------------------------------------------------------ // Filename string get accessor. //------------------------------------------------------------------ -ConstString & -FileSpec::GetFilename() -{ - return m_filename; -} +ConstString &FileSpec::GetFilename() { return m_filename; } //------------------------------------------------------------------ // Filename string const get accessor. //------------------------------------------------------------------ -const ConstString & -FileSpec::GetFilename() const -{ - return m_filename; -} +const ConstString &FileSpec::GetFilename() const { return m_filename; } //------------------------------------------------------------------ // Extract the directory and path into a fixed buffer. This is // needed as the directory and path are stored in separate string // values. //------------------------------------------------------------------ -size_t -FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const -{ - if (!path) - return 0; - - std::string result = GetPath(denormalize); - ::snprintf(path, path_max_len, "%s", result.c_str()); - return std::min(path_max_len-1, result.length()); -} +size_t FileSpec::GetPath(char *path, size_t path_max_len, + bool denormalize) const { + if (!path) + return 0; -std::string -FileSpec::GetPath(bool denormalize) const -{ - llvm::SmallString<64> result; - GetPath(result, denormalize); - return std::string(result.begin(), result.end()); + std::string result = GetPath(denormalize); + ::snprintf(path, path_max_len, "%s", result.c_str()); + return std::min(path_max_len - 1, result.length()); } -const char * -FileSpec::GetCString(bool denormalize) const -{ - return ConstString{GetPath(denormalize)}.AsCString(NULL); +std::string FileSpec::GetPath(bool denormalize) const { + llvm::SmallString<64> result; + GetPath(result, denormalize); + return std::string(result.begin(), result.end()); } -void -FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, bool denormalize) const -{ - path.append(m_directory.GetStringRef().begin(), m_directory.GetStringRef().end()); - if (m_directory && m_filename && !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - path.insert(path.end(), GetPrefferedPathSeparator(m_syntax)); - path.append(m_filename.GetStringRef().begin(), m_filename.GetStringRef().end()); - Normalize(path, m_syntax); - if (denormalize && !path.empty()) - Denormalize(path, m_syntax); +const char *FileSpec::GetCString(bool denormalize) const { + return ConstString{GetPath(denormalize)}.AsCString(NULL); } -ConstString -FileSpec::GetFileNameExtension () const -{ - if (m_filename) - { - const char *filename = m_filename.GetCString(); - const char* dot_pos = strrchr(filename, '.'); - if (dot_pos && dot_pos[1] != '\0') - return ConstString(dot_pos+1); - } - return ConstString(); +void FileSpec::GetPath(llvm::SmallVectorImpl<char> &path, + bool denormalize) const { + path.append(m_directory.GetStringRef().begin(), + m_directory.GetStringRef().end()); + if (m_directory && m_filename && + !IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + path.insert(path.end(), GetPreferredPathSeparator(m_syntax)); + path.append(m_filename.GetStringRef().begin(), + m_filename.GetStringRef().end()); + Normalize(path, m_syntax); + if (denormalize && !path.empty()) + Denormalize(path, m_syntax); } -ConstString -FileSpec::GetFileNameStrippingExtension () const -{ +ConstString FileSpec::GetFileNameExtension() const { + if (m_filename) { const char *filename = m_filename.GetCString(); - if (filename == NULL) - return ConstString(); - - const char* dot_pos = strrchr(filename, '.'); - if (dot_pos == NULL) - return m_filename; - - return ConstString(filename, dot_pos-filename); + const char *dot_pos = strrchr(filename, '.'); + if (dot_pos && dot_pos[1] != '\0') + return ConstString(dot_pos + 1); + } + return ConstString(); +} + +ConstString FileSpec::GetFileNameStrippingExtension() const { + const char *filename = m_filename.GetCString(); + if (filename == NULL) + return ConstString(); + + const char *dot_pos = strrchr(filename, '.'); + if (dot_pos == NULL) + return m_filename; + + return ConstString(filename, dot_pos - filename); } //------------------------------------------------------------------ @@ -1053,66 +836,56 @@ FileSpec::GetFileNameStrippingExtension () const // truncated. The final number of bytes that get mapped can be // verified using the DataBuffer::GetByteSize() function. //------------------------------------------------------------------ -DataBufferSP -FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const -{ - DataBufferSP data_sp; - std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); - if (mmap_data.get()) - { - const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size); - if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size)) - data_sp.reset(mmap_data.release()); - } - return data_sp; +DataBufferSP FileSpec::MemoryMapFileContents(off_t file_offset, + size_t file_size) const { + DataBufferSP data_sp; + std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap()); + if (mmap_data.get()) { + const size_t mapped_length = + mmap_data->MemoryMapFromFileSpec(this, file_offset, file_size); + if (((file_size == SIZE_MAX) && (mapped_length > 0)) || + (mapped_length >= file_size)) + data_sp.reset(mmap_data.release()); + } + return data_sp; +} + +DataBufferSP FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, + size_t file_size) const { + if (FileSystem::IsLocal(*this)) + return MemoryMapFileContents(file_offset, file_size); + else + return ReadFileContents(file_offset, file_size, NULL); } -DataBufferSP -FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const -{ - if (FileSystem::IsLocal(*this)) - return MemoryMapFileContents(file_offset, file_size); - else - return ReadFileContents(file_offset, file_size, NULL); -} - - //------------------------------------------------------------------ // Return the size in bytes that this object takes in memory. This // returns the size in bytes of this object, not any shared string // values it may refer to. //------------------------------------------------------------------ -size_t -FileSpec::MemorySize() const -{ - return m_filename.MemorySize() + m_directory.MemorySize(); -} - - -size_t -FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const -{ - Error error; - size_t bytes_read = 0; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - off_t file_offset_after_seek = file_offset; - bytes_read = dst_len; - error = file.Read(dst, bytes_read, file_offset_after_seek); - } - } - else - { - error.SetErrorString("invalid file specification"); +size_t FileSpec::MemorySize() const { + return m_filename.MemorySize() + m_directory.MemorySize(); +} + +size_t FileSpec::ReadFileContents(off_t file_offset, void *dst, size_t dst_len, + Error *error_ptr) const { + Error error; + size_t bytes_read = 0; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + off_t file_offset_after_seek = file_offset; + bytes_read = dst_len; + error = file.Read(dst, bytes_read, file_offset_after_seek); } - if (error_ptr) - *error_ptr = error; - return bytes_read; + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return bytes_read; } //------------------------------------------------------------------ @@ -1126,486 +899,441 @@ FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error // truncated. The final number of bytes that get mapped can be // verified using the DataBuffer::GetByteSize() function. //------------------------------------------------------------------ -DataBufferSP -FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const -{ - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - const bool null_terminate = false; - error = file.Read (file_size, file_offset, null_terminate, data_sp); - } +DataBufferSP FileSpec::ReadFileContents(off_t file_offset, size_t file_size, + Error *error_ptr) const { + Error error; + DataBufferSP data_sp; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + const bool null_terminate = false; + error = file.Read(file_size, file_offset, null_terminate, data_sp); + } + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return data_sp; +} + +DataBufferSP FileSpec::ReadFileContentsAsCString(Error *error_ptr) { + Error error; + DataBufferSP data_sp; + char resolved_path[PATH_MAX]; + if (GetPath(resolved_path, sizeof(resolved_path))) { + File file; + error = file.Open(resolved_path, File::eOpenOptionRead); + if (error.Success()) { + off_t offset = 0; + size_t length = SIZE_MAX; + const bool null_terminate = true; + error = file.Read(length, offset, null_terminate, data_sp); } - else - { - error.SetErrorString("invalid file specification"); + } else { + error.SetErrorString("invalid file specification"); + } + if (error_ptr) + *error_ptr = error; + return data_sp; +} + +size_t FileSpec::ReadFileLines(STLStringArray &lines) { + lines.clear(); + char path[PATH_MAX]; + if (GetPath(path, sizeof(path))) { + std::ifstream file_stream(path); + + if (file_stream) { + std::string line; + while (getline(file_stream, line)) + lines.push_back(line); } - if (error_ptr) - *error_ptr = error; - return data_sp; + } + return lines.size(); } -DataBufferSP -FileSpec::ReadFileContentsAsCString(Error *error_ptr) -{ - Error error; - DataBufferSP data_sp; - char resolved_path[PATH_MAX]; - if (GetPath(resolved_path, sizeof(resolved_path))) - { - File file; - error = file.Open(resolved_path, File::eOpenOptionRead); - if (error.Success()) - { - off_t offset = 0; - size_t length = SIZE_MAX; - const bool null_terminate = true; - error = file.Read (length, offset, null_terminate, data_sp); - } +FileSpec::EnumerateDirectoryResult +FileSpec::ForEachItemInDirectory(llvm::StringRef dir_path, + DirectoryCallback const &callback) { + if (dir_path.empty()) + return eEnumerateDirectoryResultNext; + +#ifdef _WIN32 + std::string szDir(dir_path); + szDir += "\\*"; + + std::wstring wszDir; + if (!llvm::ConvertUTF8toWide(szDir, wszDir)) { + return eEnumerateDirectoryResultNext; } - else - { - error.SetErrorString("invalid file specification"); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd); + + if (hFind == INVALID_HANDLE_VALUE) { + return eEnumerateDirectoryResultNext; } - if (error_ptr) - *error_ptr = error; - return data_sp; -} -size_t -FileSpec::ReadFileLines (STLStringArray &lines) -{ - lines.clear(); - char path[PATH_MAX]; - if (GetPath(path, sizeof(path))) - { - std::ifstream file_stream (path); - - if (file_stream) - { - std::string line; - while (getline (file_stream, line)) - lines.push_back (line); + do { + FileSpec::FileType file_type = eFileTypeUnknown; + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + size_t len = wcslen(ffd.cFileName); + + if (len == 1 && ffd.cFileName[0] == L'.') + continue; + + if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') + continue; + + file_type = eFileTypeDirectory; + } else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) { + file_type = eFileTypeOther; + } else { + file_type = eFileTypeRegular; + } + + std::string fileName; + if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) { + continue; + } + + std::string child_path = llvm::join_items("\\", dir_path, fileName); + // Don't resolve the file type or path + FileSpec child_path_spec(child_path.data(), false); + + EnumerateDirectoryResult result = callback(file_type, child_path_spec); + + switch (result) { + case eEnumerateDirectoryResultNext: + // Enumerate next entry in the current directory. We just + // exit this switch and will continue enumerating the + // current directory as we currently are... + break; + + case eEnumerateDirectoryResultEnter: // Recurse into the current entry + // if it is a directory or symlink, + // or next if not + if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == + eEnumerateDirectoryResultQuit) { + // The subdirectory returned Quit, which means to + // stop all directory enumerations at all levels. + return eEnumerateDirectoryResultQuit; } - } - return lines.size(); -} + break; -FileSpec::EnumerateDirectoryResult -FileSpec::ForEachItemInDirectory (const char *dir_path, DirectoryCallback const &callback) -{ - if (dir_path && dir_path[0]) - { -#ifdef _WIN32 - std::string szDir(dir_path); - szDir += "\\*"; + case eEnumerateDirectoryResultExit: // Exit from the current directory + // at the current level. + // Exit from this directory level and tell parent to + // keep enumerating. + return eEnumerateDirectoryResultNext; - std::wstring wszDir; - if (!llvm::ConvertUTF8toWide(szDir, wszDir)) - { - return eEnumerateDirectoryResultNext; + case eEnumerateDirectoryResultQuit: // Stop directory enumerations at + // any level + return eEnumerateDirectoryResultQuit; + } + } while (FindNextFileW(hFind, &ffd) != 0); + + FindClose(hFind); +#else + std::string dir_string(dir_path); + lldb_utility::CleanUp<DIR *, int> dir_path_dir(opendir(dir_string.c_str()), + NULL, closedir); + if (dir_path_dir.is_valid()) { + char dir_path_last_char = dir_path.back(); + + long path_max = fpathconf(dirfd(dir_path_dir.get()), _PC_NAME_MAX); +#if defined(__APPLE_) && defined(__DARWIN_MAXPATHLEN) + if (path_max < __DARWIN_MAXPATHLEN) + path_max = __DARWIN_MAXPATHLEN; +#endif + struct dirent *buf, *dp; + buf = (struct dirent *)malloc(offsetof(struct dirent, d_name) + path_max + + 1); + + while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) { + // Only search directories + if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { + size_t len = strlen(dp->d_name); + + if (len == 1 && dp->d_name[0] == '.') + continue; + + if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') + continue; } - WIN32_FIND_DATAW ffd; - HANDLE hFind = FindFirstFileW(wszDir.c_str(), &ffd); + FileSpec::FileType file_type = eFileTypeUnknown; - if (hFind == INVALID_HANDLE_VALUE) - { - return eEnumerateDirectoryResultNext; + switch (dp->d_type) { + default: + case DT_UNKNOWN: + file_type = eFileTypeUnknown; + break; + case DT_FIFO: + file_type = eFileTypePipe; + break; + case DT_CHR: + file_type = eFileTypeOther; + break; + case DT_DIR: + file_type = eFileTypeDirectory; + break; + case DT_BLK: + file_type = eFileTypeOther; + break; + case DT_REG: + file_type = eFileTypeRegular; + break; + case DT_LNK: + file_type = eFileTypeSymbolicLink; + break; + case DT_SOCK: + file_type = eFileTypeSocket; + break; +#if !defined(__OpenBSD__) + case DT_WHT: + file_type = eFileTypeOther; + break; +#endif } - do - { - FileSpec::FileType file_type = eFileTypeUnknown; - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - size_t len = wcslen(ffd.cFileName); + std::string child_path; + // Don't make paths with "/foo//bar", that just confuses everybody. + if (dir_path_last_char == '/') + child_path = llvm::join_items("", dir_path, dp->d_name); + else + child_path = llvm::join_items('/', dir_path, dp->d_name); - if (len == 1 && ffd.cFileName[0] == L'.') - continue; + // Don't resolve the file type or path + FileSpec child_path_spec(child_path, false); - if (len == 2 && ffd.cFileName[0] == L'.' && ffd.cFileName[1] == L'.') - continue; + EnumerateDirectoryResult result = + callback(file_type, child_path_spec); - file_type = eFileTypeDirectory; - } - else if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) - { - file_type = eFileTypeOther; - } - else - { - file_type = eFileTypeRegular; - } + switch (result) { + case eEnumerateDirectoryResultNext: + // Enumerate next entry in the current directory. We just + // exit this switch and will continue enumerating the + // current directory as we currently are... + break; - std::string fileName; - if (!llvm::convertWideToUTF8(ffd.cFileName, fileName)) - { - continue; + case eEnumerateDirectoryResultEnter: // Recurse into the current entry + // if it is a directory or + // symlink, or next if not + if (FileSpec::ForEachItemInDirectory(child_path, callback) == + eEnumerateDirectoryResultQuit) { + // The subdirectory returned Quit, which means to + // stop all directory enumerations at all levels. + if (buf) + free(buf); + return eEnumerateDirectoryResultQuit; } + break; - std::vector<char> child_path(PATH_MAX); - const int child_path_len = - ::snprintf(child_path.data(), child_path.size(), "%s\\%s", dir_path, fileName.c_str()); - if (child_path_len < (int)(child_path.size() - 1)) - { - // Don't resolve the file type or path - FileSpec child_path_spec(child_path.data(), false); - - EnumerateDirectoryResult result = callback (file_type, child_path_spec); - - switch (result) - { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::ForEachItemInDirectory(child_path.data(), callback) == - eEnumerateDirectoryResultQuit) - { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level - return eEnumerateDirectoryResultQuit; - } - } - } while (FindNextFileW(hFind, &ffd) != 0); + case eEnumerateDirectoryResultExit: // Exit from the current directory + // at the current level. + // Exit from this directory level and tell parent to + // keep enumerating. + if (buf) + free(buf); + return eEnumerateDirectoryResultNext; - FindClose(hFind); -#else - lldb_utility::CleanUp <DIR *, int> dir_path_dir(opendir(dir_path), NULL, closedir); - if (dir_path_dir.is_valid()) - { - char dir_path_last_char = dir_path[strlen(dir_path) - 1]; - - long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX); -#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN) - if (path_max < __DARWIN_MAXPATHLEN) - path_max = __DARWIN_MAXPATHLEN; -#endif - struct dirent *buf, *dp; - buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1); - - while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp) - { - // Only search directories - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) - { - size_t len = strlen(dp->d_name); - - if (len == 1 && dp->d_name[0] == '.') - continue; - - if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') - continue; - } - - FileSpec::FileType file_type = eFileTypeUnknown; - - switch (dp->d_type) - { - default: - case DT_UNKNOWN: file_type = eFileTypeUnknown; break; - case DT_FIFO: file_type = eFileTypePipe; break; - case DT_CHR: file_type = eFileTypeOther; break; - case DT_DIR: file_type = eFileTypeDirectory; break; - case DT_BLK: file_type = eFileTypeOther; break; - case DT_REG: file_type = eFileTypeRegular; break; - case DT_LNK: file_type = eFileTypeSymbolicLink; break; - case DT_SOCK: file_type = eFileTypeSocket; break; -#if !defined(__OpenBSD__) - case DT_WHT: file_type = eFileTypeOther; break; -#endif - } - - char child_path[PATH_MAX]; - - // Don't make paths with "/foo//bar", that just confuses everybody. - int child_path_len; - if (dir_path_last_char == '/') - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s%s", dir_path, dp->d_name); - else - child_path_len = ::snprintf (child_path, sizeof(child_path), "%s/%s", dir_path, dp->d_name); - - if (child_path_len < (int)(sizeof(child_path) - 1)) - { - // Don't resolve the file type or path - FileSpec child_path_spec (child_path, false); - - EnumerateDirectoryResult result = callback (file_type, child_path_spec); - - switch (result) - { - case eEnumerateDirectoryResultNext: - // Enumerate next entry in the current directory. We just - // exit this switch and will continue enumerating the - // current directory as we currently are... - break; - - case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not - if (FileSpec::ForEachItemInDirectory (child_path, callback) == eEnumerateDirectoryResultQuit) - { - // The subdirectory returned Quit, which means to - // stop all directory enumerations at all levels. - if (buf) - free (buf); - return eEnumerateDirectoryResultQuit; - } - break; - - case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level. - // Exit from this directory level and tell parent to - // keep enumerating. - if (buf) - free (buf); - return eEnumerateDirectoryResultNext; - - case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level - if (buf) - free (buf); - return eEnumerateDirectoryResultQuit; - } - } - } + case eEnumerateDirectoryResultQuit: // Stop directory enumerations at + // any level if (buf) - { - free (buf); - } - } -#endif + free(buf); + return eEnumerateDirectoryResultQuit; + } + } + if (buf) { + free(buf); + } } - // By default when exiting a directory, we tell the parent enumeration - // to continue enumerating. - return eEnumerateDirectoryResultNext; +#endif + // By default when exiting a directory, we tell the parent enumeration + // to continue enumerating. + return eEnumerateDirectoryResultNext; } FileSpec::EnumerateDirectoryResult -FileSpec::EnumerateDirectory -( - const char *dir_path, - bool find_directories, - bool find_files, - bool find_other, - EnumerateDirectoryCallbackType callback, - void *callback_baton -) -{ - return ForEachItemInDirectory(dir_path, - [&find_directories, &find_files, &find_other, &callback, &callback_baton] - (FileType file_type, const FileSpec &file_spec) { - switch (file_type) - { - case FileType::eFileTypeDirectory: - if (find_directories) - return callback(callback_baton, file_type, file_spec); - break; - case FileType::eFileTypeRegular: - if (find_files) - return callback(callback_baton, file_type, file_spec); - break; - default: - if (find_other) - return callback(callback_baton, file_type, file_spec); - break; - } - return eEnumerateDirectoryResultNext; - }); -} - -FileSpec -FileSpec::CopyByAppendingPathComponent (const char *new_path) const -{ - FileSpec ret = *this; - ret.AppendPathComponent(new_path); - return ret; +FileSpec::EnumerateDirectory(llvm::StringRef dir_path, bool find_directories, + bool find_files, bool find_other, + EnumerateDirectoryCallbackType callback, + void *callback_baton) { + return ForEachItemInDirectory( + dir_path, + [&find_directories, &find_files, &find_other, &callback, + &callback_baton](FileType file_type, const FileSpec &file_spec) { + switch (file_type) { + case FileType::eFileTypeDirectory: + if (find_directories) + return callback(callback_baton, file_type, file_spec); + break; + case FileType::eFileTypeRegular: + if (find_files) + return callback(callback_baton, file_type, file_spec); + break; + default: + if (find_other) + return callback(callback_baton, file_type, file_spec); + break; + } + return eEnumerateDirectoryResultNext; + }); } FileSpec -FileSpec::CopyByRemovingLastPathComponent () const -{ - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return FileSpec("",resolve); - if (m_directory.IsEmpty()) - return FileSpec("",resolve); - if (m_filename.IsEmpty()) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) - return FileSpec("",resolve); - if (last_slash_ptr == dir_cstr) - return FileSpec("/",resolve); - - size_t last_slash_pos = last_slash_ptr - dir_cstr+1; - ConstString new_path(dir_cstr,last_slash_pos); - return FileSpec(new_path.GetCString(),resolve); +FileSpec::CopyByAppendingPathComponent(llvm::StringRef component) const { + FileSpec ret = *this; + ret.AppendPathComponent(component); + return ret; +} + +FileSpec FileSpec::CopyByRemovingLastPathComponent() const { + // CLEANUP: Use StringRef for string handling. + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) + return FileSpec("", resolve); + if (m_directory.IsEmpty()) + return FileSpec("", resolve); + if (m_filename.IsEmpty()) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + + // check for obvious cases before doing the full thing + if (!last_slash_ptr) + return FileSpec("", resolve); + if (last_slash_ptr == dir_cstr) + return FileSpec("/", resolve); + + size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; + ConstString new_path(dir_cstr, last_slash_pos); + return FileSpec(new_path.GetCString(), resolve); + } else + return FileSpec(m_directory.GetCString(), resolve); +} + +ConstString FileSpec::GetLastPathComponent() const { + // CLEANUP: Use StringRef for string handling. + if (m_filename) + return m_filename; + if (m_directory) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + if (last_slash_ptr == NULL) + return m_directory; + if (last_slash_ptr == dir_cstr) { + if (last_slash_ptr[1] == 0) + return ConstString(last_slash_ptr); + else + return ConstString(last_slash_ptr + 1); } - else - return FileSpec(m_directory.GetCString(),resolve); -} - -ConstString -FileSpec::GetLastPathComponent () const -{ - if (m_filename) - return m_filename; - if (m_directory) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - if (last_slash_ptr == NULL) - return m_directory; - if (last_slash_ptr == dir_cstr) - { - if (last_slash_ptr[1] == 0) - return ConstString(last_slash_ptr); - else - return ConstString(last_slash_ptr+1); - } - if (last_slash_ptr[1] != 0) - return ConstString(last_slash_ptr+1); - const char* penultimate_slash_ptr = last_slash_ptr; - while (*penultimate_slash_ptr) - { - --penultimate_slash_ptr; - if (penultimate_slash_ptr == dir_cstr) - break; - if (*penultimate_slash_ptr == '/') - break; - } - ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); - return result; + if (last_slash_ptr[1] != 0) + return ConstString(last_slash_ptr + 1); + const char *penultimate_slash_ptr = last_slash_ptr; + while (*penultimate_slash_ptr) { + --penultimate_slash_ptr; + if (penultimate_slash_ptr == dir_cstr) + break; + if (*penultimate_slash_ptr == '/') + break; } - return ConstString(); + ConstString result(penultimate_slash_ptr + 1, + last_slash_ptr - penultimate_slash_ptr); + return result; + } + return ConstString(); } -void -FileSpec::PrependPathComponent(const char *new_path) -{ - if (!new_path) return; - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - { - SetFile(new_path, resolve); - return; - } - StreamString stream; - if (m_filename.IsEmpty()) - stream.Printf("%s/%s", new_path, m_directory.GetCString()); - else if (m_directory.IsEmpty()) - stream.Printf("%s/%s", new_path, m_filename.GetCString()); - else - stream.Printf("%s/%s/%s", new_path, m_directory.GetCString(), m_filename.GetCString()); - SetFile(stream.GetData(), resolve); -} +void FileSpec::PrependPathComponent(llvm::StringRef component) { + if (component.empty()) + return; + + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) { + SetFile(component, resolve); + return; + } + + char sep = GetPreferredPathSeparator(m_syntax); + std::string result; + if (m_filename.IsEmpty()) + result = llvm::join_items(sep, component, m_directory.GetStringRef()); + else if (m_directory.IsEmpty()) + result = llvm::join_items(sep, component, m_filename.GetStringRef()); + else + result = llvm::join_items(sep, component, m_directory.GetStringRef(), + m_filename.GetStringRef()); -void -FileSpec::PrependPathComponent(const std::string &new_path) -{ - return PrependPathComponent(new_path.c_str()); + SetFile(result, resolve); } -void -FileSpec::PrependPathComponent(const FileSpec &new_path) -{ - return PrependPathComponent(new_path.GetPath(false)); +void FileSpec::PrependPathComponent(const FileSpec &new_path) { + return PrependPathComponent(new_path.GetPath(false)); } -void -FileSpec::AppendPathComponent(const char *new_path) -{ - if (!new_path) return; - - StreamString stream; - if (!m_directory.IsEmpty()) - { - stream.PutCString(m_directory.GetCString()); - if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) - stream.PutChar(GetPrefferedPathSeparator(m_syntax)); - } +void FileSpec::AppendPathComponent(llvm::StringRef component) { + if (component.empty()) + return; - if (!m_filename.IsEmpty()) - { - stream.PutCString(m_filename.GetCString()); - if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) - stream.PutChar(GetPrefferedPathSeparator(m_syntax)); - } + std::string result; + if (!m_directory.IsEmpty()) { + result += m_directory.GetStringRef(); + if (!IsPathSeparator(m_directory.GetStringRef().back(), m_syntax)) + result += GetPreferredPathSeparator(m_syntax); + } - stream.PutCString(new_path); + if (!m_filename.IsEmpty()) { + result += m_filename.GetStringRef(); + if (!IsPathSeparator(m_filename.GetStringRef().back(), m_syntax)) + result += GetPreferredPathSeparator(m_syntax); + } - const bool resolve = false; - SetFile(stream.GetData(), resolve, m_syntax); -} + component = component.drop_while( + [this](char c) { return IsPathSeparator(c, m_syntax); }); + + result += component; -void -FileSpec::AppendPathComponent(const std::string &new_path) -{ - return AppendPathComponent(new_path.c_str()); + SetFile(result, false, m_syntax); } -void -FileSpec::AppendPathComponent(const FileSpec &new_path) -{ - return AppendPathComponent(new_path.GetPath(false)); +void FileSpec::AppendPathComponent(const FileSpec &new_path) { + return AppendPathComponent(new_path.GetPath(false)); } -void -FileSpec::RemoveLastPathComponent () -{ - const bool resolve = false; - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - { - SetFile("",resolve); - return; +void FileSpec::RemoveLastPathComponent() { + // CLEANUP: Use StringRef for string handling. + + const bool resolve = false; + if (m_filename.IsEmpty() && m_directory.IsEmpty()) { + SetFile("", resolve); + return; + } + if (m_directory.IsEmpty()) { + SetFile("", resolve); + return; + } + if (m_filename.IsEmpty()) { + const char *dir_cstr = m_directory.GetCString(); + const char *last_slash_ptr = ::strrchr(dir_cstr, '/'); + + // check for obvious cases before doing the full thing + if (!last_slash_ptr) { + SetFile("", resolve); + return; } - if (m_directory.IsEmpty()) - { - SetFile("",resolve); - return; + if (last_slash_ptr == dir_cstr) { + SetFile("/", resolve); + return; } - if (m_filename.IsEmpty()) - { - const char* dir_cstr = m_directory.GetCString(); - const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); - - // check for obvious cases before doing the full thing - if (!last_slash_ptr) - { - SetFile("",resolve); - return; - } - if (last_slash_ptr == dir_cstr) - { - SetFile("/",resolve); - return; - } - size_t last_slash_pos = last_slash_ptr - dir_cstr+1; - ConstString new_path(dir_cstr,last_slash_pos); - SetFile(new_path.GetCString(),resolve); - } - else - SetFile(m_directory.GetCString(),resolve); + size_t last_slash_pos = last_slash_ptr - dir_cstr + 1; + ConstString new_path(dir_cstr, last_slash_pos); + SetFile(new_path.GetCString(), resolve); + } else + SetFile(m_directory.GetCString(), resolve); } //------------------------------------------------------------------ /// Returns true if the filespec represents an implementation source @@ -1616,57 +1344,88 @@ FileSpec::RemoveLastPathComponent () /// \b true if the filespec represents an implementation source /// file, \b false otherwise. //------------------------------------------------------------------ -bool -FileSpec::IsSourceImplementationFile () const -{ - ConstString extension (GetFileNameExtension()); - if (extension) - { - static RegularExpression g_source_file_regex ("^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])$"); - return g_source_file_regex.Execute (extension.GetCString()); - } +bool FileSpec::IsSourceImplementationFile() const { + ConstString extension(GetFileNameExtension()); + if (!extension) return false; + + static RegularExpression g_source_file_regex(llvm::StringRef( + "^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[" + "cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][" + "rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])" + "$")); + return g_source_file_regex.Execute(extension.GetStringRef()); } -bool -FileSpec::IsRelative() const -{ - const char *dir = m_directory.GetCString(); - llvm::StringRef directory(dir ? dir : ""); - - if (directory.size() > 0) - { - if (PathSyntaxIsPosix(m_syntax)) - { - // If the path doesn't start with '/' or '~', return true - switch (directory[0]) - { - case '/': - case '~': - return false; - default: - return true; - } - } - else - { - if (directory.size() >= 2 && directory[1] == ':') - return false; - if (directory[0] == '/') - return false; - return true; - } - } - else if (m_filename) - { - // No directory, just a basename, return true +bool FileSpec::IsRelative() const { + const char *dir = m_directory.GetCString(); + llvm::StringRef directory(dir ? dir : ""); + + if (directory.size() > 0) { + if (PathSyntaxIsPosix(m_syntax)) { + // If the path doesn't start with '/' or '~', return true + switch (directory[0]) { + case '/': + case '~': + return false; + default: return true; + } + } else { + if (directory.size() >= 2 && directory[1] == ':') + return false; + if (directory[0] == '/') + return false; + return true; } - return false; + } else if (m_filename) { + // No directory, just a basename, return true + return true; + } + return false; } -bool -FileSpec::IsAbsolute() const -{ - return !FileSpec::IsRelative(); +bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); } + +void llvm::format_provider<FileSpec>::format(const FileSpec &F, + raw_ostream &Stream, + StringRef Style) { + assert( + (Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) && + "Invalid FileSpec style!"); + + StringRef dir = F.GetDirectory().GetStringRef(); + StringRef file = F.GetFilename().GetStringRef(); + + if (dir.empty() && file.empty()) { + Stream << "(empty)"; + return; + } + + if (Style.equals_lower("F")) { + Stream << (file.empty() ? "(empty)" : file); + return; + } + + // Style is either D or empty, either way we need to print the directory. + if (!dir.empty()) { + // Directory is stored in normalized form, which might be different + // than preferred form. In order to handle this, we need to cut off + // the filename, then denormalize, then write the entire denorm'ed + // directory. + llvm::SmallString<64> denormalized_dir = dir; + Denormalize(denormalized_dir, F.GetPathSyntax()); + Stream << denormalized_dir; + Stream << GetPreferredPathSeparator(F.GetPathSyntax()); + } + + if (Style.equals_lower("D")) { + // We only want to print the directory, so now just exit. + if (dir.empty()) + Stream << "(empty)"; + return; + } + + if (!file.empty()) + Stream << file; } diff --git a/source/Host/common/FileSystem.cpp b/source/Host/common/FileSystem.cpp index 5a5dbc79fe11..88f29b46f360 100644 --- a/source/Host/common/FileSystem.cpp +++ b/source/Host/common/FileSystem.cpp @@ -9,6 +9,7 @@ #include "lldb/Host/FileSystem.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" #include <algorithm> @@ -20,84 +21,82 @@ using namespace lldb_private; namespace { -bool -CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, llvm::MD5::MD5Result &md5_result) -{ - llvm::MD5 md5_hash; - std::ifstream file(file_spec.GetPath(), std::ios::binary); - if (!file.is_open()) - return false; - - if (offset > 0) - file.seekg(offset, file.beg); - - std::vector<char> read_buf(4096); - uint64_t total_read_bytes = 0; - while (!file.eof()) - { - const uint64_t to_read = (length > 0) ? - std::min(static_cast<uint64_t>(read_buf.size()), length - total_read_bytes) : - read_buf.size(); - if (to_read == 0) - break; - - file.read(&read_buf[0], to_read); - const auto read_bytes = file.gcount(); - if (read_bytes == 0) - break; - - md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes)); - total_read_bytes += read_bytes; - } - - md5_hash.final(md5_result); - return true; +bool CalcMD5(const FileSpec &file_spec, uint64_t offset, uint64_t length, + llvm::MD5::MD5Result &md5_result) { + llvm::MD5 md5_hash; + std::ifstream file(file_spec.GetPath(), std::ios::binary); + if (!file.is_open()) + return false; + + if (offset > 0) + file.seekg(offset, file.beg); + + std::vector<char> read_buf(4096); + uint64_t total_read_bytes = 0; + while (!file.eof()) { + const uint64_t to_read = + (length > 0) ? std::min(static_cast<uint64_t>(read_buf.size()), + length - total_read_bytes) + : read_buf.size(); + if (to_read == 0) + break; + + file.read(&read_buf[0], to_read); + const auto read_bytes = file.gcount(); + if (read_bytes == 0) + break; + + md5_hash.update(llvm::StringRef(&read_buf[0], read_bytes)); + total_read_bytes += read_bytes; + } + + md5_hash.final(md5_result); + return true; } -} // namespace +} // namespace -bool -FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high) -{ - return CalculateMD5(file_spec, 0, 0, low, high); +bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t &low, + uint64_t &high) { + return CalculateMD5(file_spec, 0, 0, low, high); } -bool -FileSystem::CalculateMD5(const FileSpec &file_spec, - uint64_t offset, - uint64_t length, - uint64_t &low, - uint64_t &high) -{ - llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, offset, length, md5_result)) - return false; - - const auto uint64_res = reinterpret_cast<const uint64_t*>(md5_result); - high = uint64_res[0]; - low = uint64_res[1]; - - return true; +bool FileSystem::CalculateMD5(const FileSpec &file_spec, uint64_t offset, + uint64_t length, uint64_t &low, uint64_t &high) { + llvm::MD5::MD5Result md5_result; + if (!CalcMD5(file_spec, offset, length, md5_result)) + return false; + + const auto uint64_res = reinterpret_cast<const uint64_t *>(md5_result); + high = uint64_res[0]; + low = uint64_res[1]; + + return true; +} + +bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec, + std::string &digest_str) { + return CalculateMD5AsString(file_spec, 0, 0, digest_str); } -bool -FileSystem::CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str) -{ - return CalculateMD5AsString(file_spec, 0, 0, digest_str); +bool FileSystem::CalculateMD5AsString(const FileSpec &file_spec, + uint64_t offset, uint64_t length, + std::string &digest_str) { + llvm::MD5::MD5Result md5_result; + if (!CalcMD5(file_spec, offset, length, md5_result)) + return false; + + llvm::SmallString<32> result_str; + llvm::MD5::stringifyResult(md5_result, result_str); + digest_str = result_str.c_str(); + return true; } -bool -FileSystem::CalculateMD5AsString(const FileSpec &file_spec, - uint64_t offset, - uint64_t length, - std::string& digest_str) -{ - llvm::MD5::MD5Result md5_result; - if (!CalcMD5(file_spec, offset, length, md5_result)) - return false; - - llvm::SmallString<32> result_str; - llvm::MD5::stringifyResult(md5_result, result_str); - digest_str = result_str.c_str(); - return true; +llvm::sys::TimePoint<> +FileSystem::GetModificationTime(const FileSpec &file_spec) { + llvm::sys::fs::file_status status; + std::error_code ec = llvm::sys::fs::status(file_spec.GetPath(), status); + if (ec) + return llvm::sys::TimePoint<>(); + return status.getLastModificationTime(); } diff --git a/source/Host/common/GetOptInc.cpp b/source/Host/common/GetOptInc.cpp index 7689f36c8154..1d9b31743736 100644 --- a/source/Host/common/GetOptInc.cpp +++ b/source/Host/common/GetOptInc.cpp @@ -1,6 +1,16 @@ +//===-- GetOptInc.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + #include "lldb/Host/common/GetOptInc.h" -#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || defined(REPLACE_GETOPT_LONG_ONLY) +#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || \ + defined(REPLACE_GETOPT_LONG_ONLY) // getopt.cpp #include <errno.h> @@ -8,32 +18,32 @@ #include <string.h> #if defined(REPLACE_GETOPT) -int opterr = 1; /* if error message should be printed */ -int optind = 1; /* index into parent argv vector */ -int optopt = '?'; /* character checked for validity */ -int optreset; /* reset getopt */ -char *optarg; /* argument associated with option */ +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ #endif #define PRINT_ERROR ((opterr) && (*options != ':')) -#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ -#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ -#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ /* return values */ -#define BADCH (int)'?' -#define BADARG ((*options == ':') ? (int)':' : (int)'?') -#define INORDER (int)1 +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 -#define EMSG "" +#define EMSG "" -static int getopt_internal(int, char * const *, const char *, - const struct option *, int *, int); -static int parse_long_options(char * const *, const char *, - const struct option *, int *, int); +static int getopt_internal(int, char *const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char *const *, const char *, + const struct option *, int *, int); static int gcd(int, int); -static void permute_args(int, int, int, char * const *); +static void permute_args(int, int, int, char *const *); static const char *place = EMSG; /* option letter processing */ @@ -44,19 +54,17 @@ static int nonopt_end = -1; /* first option after non options (for permute) */ /* * Compute the greatest common divisor of a and b. */ -static int -gcd(int a, int b) -{ - int c; +static int gcd(int a, int b) { + int c; + c = a % b; + while (c != 0) { + a = b; + b = c; c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } + } - return (b); + return (b); } static void pass() {} @@ -67,36 +75,34 @@ static void pass() {} * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ -static void -permute_args(int panonopt_start, int panonopt_end, int opt_end, -char * const *nargv) -{ - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = gcd(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { - cstart = panonopt_end + i; - pos = cstart; - for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **)nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } +static void permute_args(int panonopt_start, int panonopt_end, int opt_end, + char *const *nargv) { + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end + i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **)nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; } + } } /* @@ -104,318 +110,297 @@ char * const *nargv) * Parse long options in argc/argv argument vector. * Returns -1 if short_too is set and the option does not match long_options. */ -static int -parse_long_options(char * const *nargv, const char *options, -const struct option *long_options, int *idx, int short_too) -{ - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = const_cast<char*>(place); - match = -1; - - optind++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; +static int parse_long_options(char *const *nargv, const char *options, + const struct option *long_options, int *idx, + int short_too) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = const_cast<char *>(place); + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); } - else - current_argv_len = strlen(current_argv); - - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - break; - } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == required_argument) { /* - * If this is a known short option, don't allow - * a partial match of a single character. + * optional argument doesn't use next nargv */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) /* partial match */ - match = i; - else { - /* ambiguous abbreviation */ - if (PRINT_ERROR) - warnx(ambig, (int)current_argv_len, - current_argv); - optopt = 0; - return (BADCH); - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (PRINT_ERROR) - warnx(noarg, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - return (BADARG); - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - optarg = has_equal; - else if (long_options[match].has_arg == - required_argument) { - /* - * optional argument doesn't use next nargv - */ - optarg = nargv[optind++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (optarg == NULL)) { - /* - * Missing argument; leading ':' indicates no error - * should be generated. - */ - if (PRINT_ERROR) - warnx(recargstring, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - optopt = long_options[match].val; - else - optopt = 0; - --optind; - return (BADARG); - } + optarg = nargv[optind++]; + } } - else { /* unknown option */ - if (short_too) { - --optind; - return (-1); - } - if (PRINT_ERROR) - warnx(illoptstring, current_argv); + if ((long_options[match].has_arg == required_argument) && + (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else optopt = 0; - return (BADCH); + --optind; + return (BADARG); } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); } - else - return (long_options[match].val); + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. */ -static int -getopt_internal(int nargc, char * const *nargv, const char *options, -const struct option *long_options, int *idx, int flags) -{ - const char *oli; /* option letter list index */ - int optchar, short_too; - static int posixly_correct = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (optind == 0) - optind = optreset = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - if (posixly_correct == -1 || optreset) - posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= FLAG_ALLARGS; - else if (posixly_correct || *options == '+') - flags &= ~FLAG_PERMUTE; - if (*options == '+' || *options == '-') - options++; - - optarg = NULL; - if (optreset) - nonopt_start = nonopt_end = -1; +static int getopt_internal(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx, + int flags) { + const char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1 || optreset) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= FLAG_ALLARGS; + else if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + if (*options == '+' || *options == '-') + options++; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; start: - if (optreset || !*place) { /* update scanning pointer */ - optreset = 0; - if (optind >= nargc) { /* end of argument vector */ - place = EMSG; - if (nonopt_end != -1) { - /* do permutation, if we have to */ - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - else if (nonopt_start != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - optind = nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } - if (*(place = nargv[optind]) != '-' || - (place[1] == '\0' && strchr(options, '-') == NULL)) { - place = EMSG; /* found non-option */ - if (flags & FLAG_ALLARGS) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - optarg = nargv[optind++]; - return (INORDER); - } - if (!(flags & FLAG_PERMUTE)) { - /* - * If no permutation wanted, stop parsing - * at first non-option. - */ - return (-1); - } - /* do permutation */ - if (nonopt_start == -1) - nonopt_start = optind; - else if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - nonopt_start = optind - - (nonopt_end - nonopt_start); - nonopt_end = -1; - } - optind++; - /* process next argument */ - goto start; - } - if (nonopt_start != -1 && nonopt_end == -1) - nonopt_end = optind; - + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, optind, nargv); + optind -= nonopt_end - nonopt_start; + } else if (nonopt_start != -1) { /* - * If we have "-" do nothing, if "--" we are done. + * If we skipped non-options, set optind + * to the first of them. */ - if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { - optind++; - place = EMSG; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (nonopt_end != -1) { - permute_args(nonopt_start, nonopt_end, - optind, nargv); - optind -= nonopt_end - nonopt_start; - } - nonopt_start = nonopt_end = -1; - return (-1); - } + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, nargv); + nonopt_start = optind - (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are getopt_long_only() + * If we have "-" do nothing, if "--" we are done. */ - if (long_options != NULL && place != nargv[optind] && - (*place == '-' || (flags & FLAG_LONGONLY))) { - short_too = 0; - if (*place == '-') - place++; /* --foo long option */ - else if (*place != ':' && strchr(options, *place) != NULL) - short_too = 1; /* could be short option too */ - - optchar = parse_long_options(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - place = EMSG; - return (optchar); - } + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); } + } - if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); - if (!*place) - ++optind; + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = const_cast<char *>(place); + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; if (PRINT_ERROR) - warnx(illoptchar, optchar); + warnx(recargchar, optchar); optopt = optchar; - return (BADCH); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*place) /* no space */ - /* NOTHING */; - else if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } - else /* white space */ - place = nargv[optind]; - optchar = parse_long_options(nargv, options, long_options, - idx, 0); - place = EMSG; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*place) - ++optind; + return (BADARG); + } else + optarg = nargv[optind]; } - else { /* takes (optional) argument */ - optarg = NULL; - if (*place) /* no white space */ - optarg = const_cast<char*>(place); - else if (oli[1] != ':') { /* arg not optional */ - if (++optind >= nargc) { /* no arg */ - place = EMSG; - if (PRINT_ERROR) - warnx(recargchar, optchar); - optopt = optchar; - return (BADARG); - } - else - optarg = nargv[optind]; - } - place = EMSG; - ++optind; - } - /* dump back option letter */ - return (optchar); + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); } /* @@ -425,19 +410,17 @@ start: * [eventually this will replace the BSD getopt] */ #if defined(REPLACE_GETOPT) -int -getopt(int nargc, char * const *nargv, const char *options) -{ - - /* - * We don't pass FLAG_PERMUTE to getopt_internal() since - * the BSD getopt(3) (unlike GNU) has never done this. - * - * Furthermore, since many privileged programs call getopt() - * before dropping privileges it makes sense to keep things - * as simple (and bug-free) as possible. - */ - return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +int getopt(int nargc, char *const *nargv, const char *options) { + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); } #endif @@ -446,12 +429,10 @@ getopt(int nargc, char * const *nargv, const char *options) * Parse argc/argv argument vector. */ #if defined(REPLACE_GETOPT_LONG) -int -getopt_long(int nargc, char * const *nargv, const char *options, -const struct option *long_options, int *idx) -{ - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE)); +int getopt_long(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx) { + return ( + getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE)); } #endif @@ -460,13 +441,11 @@ const struct option *long_options, int *idx) * Parse argc/argv argument vector. */ #if defined(REPLACE_GETOPT_LONG_ONLY) -int -getopt_long_only(int nargc, char * const *nargv, const char *options, -const struct option *long_options, int *idx) -{ +int getopt_long_only(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx) { - return (getopt_internal(nargc, nargv, options, long_options, idx, - FLAG_PERMUTE | FLAG_LONGONLY)); + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE | FLAG_LONGONLY)); } #endif diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index 656caa5e0d19..6d0ad0175fd8 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -13,29 +13,30 @@ #include <stdlib.h> #include <sys/types.h> #ifndef _WIN32 -#include <unistd.h> #include <dlfcn.h> #include <grp.h> #include <netdb.h> #include <pwd.h> #include <sys/stat.h> +#include <unistd.h> #endif -#if defined (__APPLE__) -#include <mach/mach_port.h> -#include <mach/mach_init.h> +#if defined(__APPLE__) #include <mach-o/dyld.h> +#include <mach/mach_init.h> +#include <mach/mach_port.h> #endif -#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__) -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) +#if defined(__linux__) || defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) +#if !defined(__ANDROID__) #include <spawn.h> #endif -#include <sys/wait.h> #include <sys/syscall.h> +#include <sys/wait.h> #endif -#if defined (__FreeBSD__) +#if defined(__FreeBSD__) #include <pthread_np.h> #endif @@ -44,43 +45,42 @@ // Other libraries and framework includes // Project includes -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/MonitoringProcessLauncher.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/ProcessLauncher.h" #include "lldb/Host/ThreadLauncher.h" -#include "lldb/lldb-private-forward.h" -#include "llvm/Support/FileSystem.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/CleanUp.h" +#include "lldb/lldb-private-forward.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" -#elif defined(__ANDROID__) || defined(__ANDROID_NDK__) -#include "lldb/Host/android/ProcessLauncherAndroid.h" +#elif defined(__linux__) +#include "lldb/Host/linux/ProcessLauncherLinux.h" #else #include "lldb/Host/posix/ProcessLauncherPosix.h" #endif -#if defined (__APPLE__) +#if defined(__APPLE__) #ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif -extern "C" -{ - int __pthread_chdir(const char *path); - int __pthread_fchdir (int fildes); +extern "C" { +int __pthread_chdir(const char *path); +int __pthread_fchdir(int fildes); } #endif @@ -88,30 +88,30 @@ extern "C" using namespace lldb; using namespace lldb_private; -#if !defined (__APPLE__) && !defined (_WIN32) -struct MonitorInfo -{ - lldb::pid_t pid; // The process ID to monitor - Host::MonitorChildProcessCallback callback; // The callback function to call when "pid" exits or signals - bool monitor_signals; // If true, call the callback when "pid" gets signaled. +#if !defined(__APPLE__) && !defined(_WIN32) +struct MonitorInfo { + lldb::pid_t pid; // The process ID to monitor + Host::MonitorChildProcessCallback + callback; // The callback function to call when "pid" exits or signals + bool monitor_signals; // If true, call the callback when "pid" gets signaled. }; -static thread_result_t -MonitorChildProcessThreadFunction (void *arg); +static thread_result_t MonitorChildProcessThreadFunction(void *arg); -HostThread -Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, - bool monitor_signals) -{ - MonitorInfo * info_ptr = new MonitorInfo(); - - info_ptr->pid = pid; - info_ptr->callback = callback; - info_ptr->monitor_signals = monitor_signals; - - char thread_name[256]; - ::snprintf(thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid); - return ThreadLauncher::LaunchThread(thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL); +HostThread Host::StartMonitoringChildProcess( + const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, + bool monitor_signals) { + MonitorInfo *info_ptr = new MonitorInfo(); + + info_ptr->pid = pid; + info_ptr->callback = callback; + info_ptr->monitor_signals = monitor_signals; + + char thread_name[256]; + ::snprintf(thread_name, sizeof(thread_name), + "<lldb.host.wait4(pid=%" PRIu64 ")>", pid); + return ThreadLauncher::LaunchThread( + thread_name, MonitorChildProcessThreadFunction, info_ptr, NULL); } #ifndef __linux__ @@ -120,26 +120,24 @@ Host::StartMonitoringChildProcess(const Host::MonitorChildProcessCallback &callb // constructed, and exception safely restore the previous value it // when it goes out of scope. //------------------------------------------------------------------ -class ScopedPThreadCancelDisabler -{ +class ScopedPThreadCancelDisabler { public: - ScopedPThreadCancelDisabler() - { - // Disable the ability for this thread to be cancelled - int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state); - if (err != 0) - m_old_state = -1; - } + ScopedPThreadCancelDisabler() { + // Disable the ability for this thread to be cancelled + int err = ::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m_old_state); + if (err != 0) + m_old_state = -1; + } + + ~ScopedPThreadCancelDisabler() { + // Restore the ability for this thread to be cancelled to what it + // previously was. + if (m_old_state != -1) + ::pthread_setcancelstate(m_old_state, 0); + } - ~ScopedPThreadCancelDisabler() - { - // Restore the ability for this thread to be cancelled to what it - // previously was. - if (m_old_state != -1) - ::pthread_setcancelstate (m_old_state, 0); - } private: - int m_old_state; // Save the old cancelability state. + int m_old_state; // Save the old cancelability state. }; #endif // __linux__ @@ -150,279 +148,275 @@ static __thread volatile sig_atomic_t g_usr1_called; static thread_local volatile sig_atomic_t g_usr1_called; #endif -static void -SigUsr1Handler (int) -{ - g_usr1_called = 1; -} +static void SigUsr1Handler(int) { g_usr1_called = 1; } #endif // __linux__ -static bool -CheckForMonitorCancellation() -{ +static bool CheckForMonitorCancellation() { #ifdef __linux__ - if (g_usr1_called) - { - g_usr1_called = 0; - return true; - } + if (g_usr1_called) { + g_usr1_called = 0; + return true; + } #else - ::pthread_testcancel (); + ::pthread_testcancel(); #endif - return false; + return false; } -static thread_result_t -MonitorChildProcessThreadFunction (void *arg) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - const char *function = __FUNCTION__; - if (log) - log->Printf ("%s (arg = %p) thread starting...", function, arg); +static thread_result_t MonitorChildProcessThreadFunction(void *arg) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + const char *function = __FUNCTION__; + if (log) + log->Printf("%s (arg = %p) thread starting...", function, arg); - MonitorInfo *info = (MonitorInfo *)arg; + MonitorInfo *info = (MonitorInfo *)arg; - const Host::MonitorChildProcessCallback callback = info->callback; - const bool monitor_signals = info->monitor_signals; + const Host::MonitorChildProcessCallback callback = info->callback; + const bool monitor_signals = info->monitor_signals; - assert (info->pid <= UINT32_MAX); - const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid; + assert(info->pid <= UINT32_MAX); + const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid; - delete info; + delete info; - int status = -1; -#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) - #define __WALL 0 + int status = -1; +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#define __WALL 0 #endif - const int options = __WALL; + const int options = __WALL; #ifdef __linux__ - // This signal is only used to interrupt the thread from waitpid - struct sigaction sigUsr1Action; - memset(&sigUsr1Action, 0, sizeof(sigUsr1Action)); - sigUsr1Action.sa_handler = SigUsr1Handler; - ::sigaction(SIGUSR1, &sigUsr1Action, nullptr); -#endif // __linux__ - - while (1) - { - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); - if (log) - log->Printf("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options); + // This signal is only used to interrupt the thread from waitpid + struct sigaction sigUsr1Action; + memset(&sigUsr1Action, 0, sizeof(sigUsr1Action)); + sigUsr1Action.sa_handler = SigUsr1Handler; + ::sigaction(SIGUSR1, &sigUsr1Action, nullptr); +#endif // __linux__ - if (CheckForMonitorCancellation ()) - break; + while (1) { + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS); + if (log) + log->Printf("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...", + function, pid, options); - // Get signals from all children with same process group of pid - const ::pid_t wait_pid = ::waitpid (pid, &status, options); + if (CheckForMonitorCancellation()) + break; - if (CheckForMonitorCancellation ()) - break; + // Get signals from all children with same process group of pid + const ::pid_t wait_pid = ::waitpid(pid, &status, options); - if (wait_pid == -1) - { - if (errno == EINTR) - continue; - else - { - if (log) - log->Printf ("%s (arg = %p) thread exiting because waitpid failed (%s)...", __FUNCTION__, arg, strerror(errno)); - break; - } + if (CheckForMonitorCancellation()) + break; + + if (wait_pid == -1) { + if (errno == EINTR) + continue; + else { + if (log) + log->Printf( + "%s (arg = %p) thread exiting because waitpid failed (%s)...", + __FUNCTION__, arg, strerror(errno)); + break; + } + } else if (wait_pid > 0) { + bool exited = false; + int signal = 0; + int exit_status = 0; + const char *status_cstr = NULL; + if (WIFSTOPPED(status)) { + signal = WSTOPSIG(status); + status_cstr = "STOPPED"; + } else if (WIFEXITED(status)) { + exit_status = WEXITSTATUS(status); + status_cstr = "EXITED"; + exited = true; + } else if (WIFSIGNALED(status)) { + signal = WTERMSIG(status); + status_cstr = "SIGNALED"; + if (wait_pid == abs(pid)) { + exited = true; + exit_status = -1; } - else if (wait_pid > 0) - { - bool exited = false; - int signal = 0; - int exit_status = 0; - const char *status_cstr = NULL; - if (WIFSTOPPED(status)) - { - signal = WSTOPSIG(status); - status_cstr = "STOPPED"; - } - else if (WIFEXITED(status)) - { - exit_status = WEXITSTATUS(status); - status_cstr = "EXITED"; - exited = true; - } - else if (WIFSIGNALED(status)) - { - signal = WTERMSIG(status); - status_cstr = "SIGNALED"; - if (wait_pid == abs(pid)) { - exited = true; - exit_status = -1; - } - } - else - { - status_cstr = "(\?\?\?)"; - } - - // Scope for pthread_cancel_disabler - { + } else { + status_cstr = "(\?\?\?)"; + } + + // Scope for pthread_cancel_disabler + { #ifndef __linux__ - ScopedPThreadCancelDisabler pthread_cancel_disabler; + ScopedPThreadCancelDisabler pthread_cancel_disabler; #endif - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); - if (log) - log->Printf ("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i) => pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", - function, - pid, - options, - wait_pid, - status, - status_cstr, - signal, - exit_status); - - if (exited || (signal != 0 && monitor_signals)) - { - bool callback_return = false; - if (callback) - callback_return = callback(wait_pid, exited, signal, exit_status); - - // If our process exited, then this thread should exit - if (exited && wait_pid == abs(pid)) - { - if (log) - log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg); - break; - } - // If the callback returns true, it means this process should - // exit - if (callback_return) - { - if (log) - log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg); - break; - } - } - } + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS); + if (log) + log->Printf("%s ::waitpid (pid = %" PRIi32 + ", &status, options = %i) => pid = %" PRIi32 + ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", + function, pid, options, wait_pid, status, status_cstr, + signal, exit_status); + + if (exited || (signal != 0 && monitor_signals)) { + bool callback_return = false; + if (callback) + callback_return = callback(wait_pid, exited, signal, exit_status); + + // If our process exited, then this thread should exit + if (exited && wait_pid == abs(pid)) { + if (log) + log->Printf("%s (arg = %p) thread exiting because pid received " + "exit signal...", + __FUNCTION__, arg); + break; + } + // If the callback returns true, it means this process should + // exit + if (callback_return) { + if (log) + log->Printf("%s (arg = %p) thread exiting because callback " + "returned true...", + __FUNCTION__, arg); + break; + } } + } } + } - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); - if (log) - log->Printf ("%s (arg = %p) thread exiting...", __FUNCTION__, arg); + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS); + if (log) + log->Printf("%s (arg = %p) thread exiting...", __FUNCTION__, arg); - return NULL; + return NULL; } #endif // #if !defined (__APPLE__) && !defined (_WIN32) -#if !defined (__APPLE__) +#if !defined(__APPLE__) -void -Host::SystemLog (SystemLogType type, const char *format, va_list args) -{ - vfprintf (stderr, format, args); +void Host::SystemLog(SystemLogType type, const char *format, va_list args) { + vfprintf(stderr, format, args); } #endif -void -Host::SystemLog (SystemLogType type, const char *format, ...) -{ - va_list args; - va_start (args, format); - SystemLog (type, format, args); - va_end (args); +void Host::SystemLog(SystemLogType type, const char *format, ...) { + va_list args; + va_start(args, format); + SystemLog(type, format, args); + va_end(args); } -lldb::pid_t -Host::GetCurrentProcessID() -{ - return ::getpid(); -} +lldb::pid_t Host::GetCurrentProcessID() { return ::getpid(); } #ifndef _WIN32 -lldb::tid_t -Host::GetCurrentThreadID() -{ -#if defined (__APPLE__) - // Calling "mach_thread_self()" bumps the reference count on the thread - // port, so we need to deallocate it. mach_task_self() doesn't bump the ref - // count. - thread_port_t thread_self = mach_thread_self(); - mach_port_deallocate(mach_task_self(), thread_self); - return thread_self; +lldb::tid_t Host::GetCurrentThreadID() { +#if defined(__APPLE__) + // Calling "mach_thread_self()" bumps the reference count on the thread + // port, so we need to deallocate it. mach_task_self() doesn't bump the ref + // count. + thread_port_t thread_self = mach_thread_self(); + mach_port_deallocate(mach_task_self(), thread_self); + return thread_self; #elif defined(__FreeBSD__) - return lldb::tid_t(pthread_getthreadid_np()); -#elif defined(__ANDROID_NDK__) - return lldb::tid_t(gettid()); + return lldb::tid_t(pthread_getthreadid_np()); +#elif defined(__ANDROID__) + return lldb::tid_t(gettid()); #elif defined(__linux__) - return lldb::tid_t(syscall(SYS_gettid)); + return lldb::tid_t(syscall(SYS_gettid)); #else - return lldb::tid_t(pthread_self()); + return lldb::tid_t(pthread_self()); #endif } -lldb::thread_t -Host::GetCurrentThread () -{ - return lldb::thread_t(pthread_self()); +lldb::thread_t Host::GetCurrentThread() { + return lldb::thread_t(pthread_self()); } -const char * -Host::GetSignalAsCString (int signo) -{ - switch (signo) - { - case SIGHUP: return "SIGHUP"; // 1 hangup - case SIGINT: return "SIGINT"; // 2 interrupt - case SIGQUIT: return "SIGQUIT"; // 3 quit - case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught) - case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught) - case SIGABRT: return "SIGABRT"; // 6 abort() -#if defined(SIGPOLL) +const char *Host::GetSignalAsCString(int signo) { + switch (signo) { + case SIGHUP: + return "SIGHUP"; // 1 hangup + case SIGINT: + return "SIGINT"; // 2 interrupt + case SIGQUIT: + return "SIGQUIT"; // 3 quit + case SIGILL: + return "SIGILL"; // 4 illegal instruction (not reset when caught) + case SIGTRAP: + return "SIGTRAP"; // 5 trace trap (not reset when caught) + case SIGABRT: + return "SIGABRT"; // 6 abort() +#if defined(SIGPOLL) #if !defined(SIGIO) || (SIGPOLL != SIGIO) -// Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to -// fail with 'multiple define cases with same value' - case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) -#endif -#endif -#if defined(SIGEMT) - case SIGEMT: return "SIGEMT"; // 7 EMT instruction -#endif - case SIGFPE: return "SIGFPE"; // 8 floating point exception - case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored) - case SIGBUS: return "SIGBUS"; // 10 bus error - case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation - case SIGSYS: return "SIGSYS"; // 12 bad argument to system call - case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it - case SIGALRM: return "SIGALRM"; // 14 alarm clock - case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill - case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel - case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty - case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty - case SIGCONT: return "SIGCONT"; // 19 continue a stopped process - case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit - case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read - case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) -#if defined(SIGIO) - case SIGIO: return "SIGIO"; // 23 input/output possible signal -#endif - case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit - case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit - case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm - case SIGPROF: return "SIGPROF"; // 27 profiling time alarm -#if defined(SIGWINCH) - case SIGWINCH: return "SIGWINCH"; // 28 window size changes -#endif -#if defined(SIGINFO) - case SIGINFO: return "SIGINFO"; // 29 information request -#endif - case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1 - case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2 - default: - break; - } - return NULL; + // Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to + // fail with 'multiple define cases with same value' + case SIGPOLL: + return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) +#endif +#endif +#if defined(SIGEMT) + case SIGEMT: + return "SIGEMT"; // 7 EMT instruction +#endif + case SIGFPE: + return "SIGFPE"; // 8 floating point exception + case SIGKILL: + return "SIGKILL"; // 9 kill (cannot be caught or ignored) + case SIGBUS: + return "SIGBUS"; // 10 bus error + case SIGSEGV: + return "SIGSEGV"; // 11 segmentation violation + case SIGSYS: + return "SIGSYS"; // 12 bad argument to system call + case SIGPIPE: + return "SIGPIPE"; // 13 write on a pipe with no one to read it + case SIGALRM: + return "SIGALRM"; // 14 alarm clock + case SIGTERM: + return "SIGTERM"; // 15 software termination signal from kill + case SIGURG: + return "SIGURG"; // 16 urgent condition on IO channel + case SIGSTOP: + return "SIGSTOP"; // 17 sendable stop signal not from tty + case SIGTSTP: + return "SIGTSTP"; // 18 stop signal from tty + case SIGCONT: + return "SIGCONT"; // 19 continue a stopped process + case SIGCHLD: + return "SIGCHLD"; // 20 to parent on child stop or exit + case SIGTTIN: + return "SIGTTIN"; // 21 to readers pgrp upon background tty read + case SIGTTOU: + return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) +#if defined(SIGIO) + case SIGIO: + return "SIGIO"; // 23 input/output possible signal +#endif + case SIGXCPU: + return "SIGXCPU"; // 24 exceeded CPU time limit + case SIGXFSZ: + return "SIGXFSZ"; // 25 exceeded file size limit + case SIGVTALRM: + return "SIGVTALRM"; // 26 virtual time alarm + case SIGPROF: + return "SIGPROF"; // 27 profiling time alarm +#if defined(SIGWINCH) + case SIGWINCH: + return "SIGWINCH"; // 28 window size changes +#endif +#if defined(SIGINFO) + case SIGINFO: + return "SIGINFO"; // 29 information request +#endif + case SIGUSR1: + return "SIGUSR1"; // 30 user defined signal 1 + case SIGUSR2: + return "SIGUSR2"; // 31 user defined signal 2 + default: + break; + } + return NULL; } #endif @@ -430,84 +424,63 @@ Host::GetSignalAsCString (int signo) #ifndef _WIN32 lldb::thread_key_t -Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) -{ - pthread_key_t key; - ::pthread_key_create (&key, callback); - return key; +Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) { + pthread_key_t key; + ::pthread_key_create(&key, callback); + return key; } -void* -Host::ThreadLocalStorageGet(lldb::thread_key_t key) -{ - return ::pthread_getspecific (key); +void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) { + return ::pthread_getspecific(key); } -void -Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) -{ - ::pthread_setspecific (key, value); +void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) { + ::pthread_setspecific(key, value); } #endif -#if !defined (__APPLE__) // see Host.mm +#if !defined(__APPLE__) // see Host.mm -bool -Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle) -{ - bundle.Clear(); - return false; +bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) { + bundle.Clear(); + return false; } -bool -Host::ResolveExecutableInBundle (FileSpec &file) -{ - return false; -} +bool Host::ResolveExecutableInBundle(FileSpec &file) { return false; } #endif #ifndef _WIN32 -FileSpec -Host::GetModuleFileSpecForHostAddress (const void *host_addr) -{ - FileSpec module_filespec; -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) - Dl_info info; - if (::dladdr (host_addr, &info)) - { - if (info.dli_fname) - module_filespec.SetFile(info.dli_fname, true); - } +FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { + FileSpec module_filespec; +#if !defined(__ANDROID__) + Dl_info info; + if (::dladdr(host_addr, &info)) { + if (info.dli_fname) + module_filespec.SetFile(info.dli_fname, true); + } #endif - return module_filespec; + return module_filespec; } #endif #if !defined(__linux__) -bool -Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach) -{ - return false; +bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { + return false; } #endif -struct ShellInfo -{ - ShellInfo () : - process_reaped (false), - pid (LLDB_INVALID_PROCESS_ID), - signo(-1), - status(-1) - { - } +struct ShellInfo { + ShellInfo() + : process_reaped(false), pid(LLDB_INVALID_PROCESS_ID), signo(-1), + status(-1) {} - lldb_private::Predicate<bool> process_reaped; - lldb::pid_t pid; - int signo; - int status; + lldb_private::Predicate<bool> process_reaped; + lldb::pid_t pid; + int signo; + int status; }; static bool @@ -516,548 +489,520 @@ MonitorShellCommand(std::shared_ptr<ShellInfo> shell_info, lldb::pid_t pid, int signo, // Zero for no signal int status) // Exit value of process if signal is zero { - shell_info->pid = pid; - shell_info->signo = signo; - shell_info->status = status; - // Let the thread running Host::RunShellCommand() know that the process - // exited and that ShellInfo has been filled in by broadcasting to it - shell_info->process_reaped.SetValue(true, eBroadcastAlways); - return true; + shell_info->pid = pid; + shell_info->signo = signo; + shell_info->status = status; + // Let the thread running Host::RunShellCommand() know that the process + // exited and that ShellInfo has been filled in by broadcasting to it + shell_info->process_reaped.SetValue(true, eBroadcastAlways); + return true; } -Error -Host::RunShellCommand(const char *command, - const FileSpec &working_dir, - int *status_ptr, - int *signo_ptr, - std::string *command_output_ptr, - uint32_t timeout_sec, - bool run_in_default_shell) -{ - return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, command_output_ptr, timeout_sec, run_in_default_shell); +Error Host::RunShellCommand(const char *command, const FileSpec &working_dir, + int *status_ptr, int *signo_ptr, + std::string *command_output_ptr, + uint32_t timeout_sec, bool run_in_default_shell) { + return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, + command_output_ptr, timeout_sec, run_in_default_shell); } -Error -Host::RunShellCommand(const Args &args, - const FileSpec &working_dir, - int *status_ptr, - int *signo_ptr, - std::string *command_output_ptr, - uint32_t timeout_sec, - bool run_in_default_shell) -{ - Error error; - ProcessLaunchInfo launch_info; - launch_info.SetArchitecture(HostInfo::GetArchitecture()); - if (run_in_default_shell) - { - // Run the command in a shell - launch_info.SetShell(HostInfo::GetDefaultShell()); - launch_info.GetArguments().AppendArguments(args); - const bool localhost = true; - const bool will_debug = false; - const bool first_arg_is_full_shell_command = false; - launch_info.ConvertArgumentsForLaunchingInShell (error, - localhost, - will_debug, - first_arg_is_full_shell_command, - 0); - } - else - { - // No shell, just run it - const bool first_arg_is_executable = true; - launch_info.SetArguments(args, first_arg_is_executable); - } - - if (working_dir) - launch_info.SetWorkingDirectory(working_dir); - llvm::SmallString<PATH_MAX> output_file_path; - - if (command_output_ptr) - { - // Create a temporary file to get the stdout/stderr and redirect the - // output of the command into this file. We will later read this file - // if all goes well and fill the data into "command_output_ptr" - FileSpec tmpdir_file_spec; - if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) - { - tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%"); - llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), output_file_path); - } - else - { - llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", output_file_path); - } - } - - FileSpec output_file_spec{output_file_path.c_str(), false}; - - launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); - if (output_file_spec) - { - launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false, true); - launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO); - } - else - { - launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); - launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); +Error Host::RunShellCommand(const Args &args, const FileSpec &working_dir, + int *status_ptr, int *signo_ptr, + std::string *command_output_ptr, + uint32_t timeout_sec, bool run_in_default_shell) { + Error error; + ProcessLaunchInfo launch_info; + launch_info.SetArchitecture(HostInfo::GetArchitecture()); + if (run_in_default_shell) { + // Run the command in a shell + launch_info.SetShell(HostInfo::GetDefaultShell()); + launch_info.GetArguments().AppendArguments(args); + const bool localhost = true; + const bool will_debug = false; + const bool first_arg_is_full_shell_command = false; + launch_info.ConvertArgumentsForLaunchingInShell( + error, localhost, will_debug, first_arg_is_full_shell_command, 0); + } else { + // No shell, just run it + const bool first_arg_is_executable = true; + launch_info.SetArguments(args, first_arg_is_executable); + } + + if (working_dir) + launch_info.SetWorkingDirectory(working_dir); + llvm::SmallString<PATH_MAX> output_file_path; + + if (command_output_ptr) { + // Create a temporary file to get the stdout/stderr and redirect the + // output of the command into this file. We will later read this file + // if all goes well and fill the data into "command_output_ptr" + FileSpec tmpdir_file_spec; + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { + tmpdir_file_spec.AppendPathComponent("lldb-shell-output.%%%%%%"); + llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(), + output_file_path); + } else { + llvm::sys::fs::createTemporaryFile("lldb-shell-output.%%%%%%", "", + output_file_path); } - - std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo()); - const bool monitor_signals = false; - launch_info.SetMonitorProcessCallback(std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3, - std::placeholders::_4), - monitor_signals); - - error = LaunchProcess (launch_info); - const lldb::pid_t pid = launch_info.GetProcessID(); - - if (error.Success() && pid == LLDB_INVALID_PROCESS_ID) - error.SetErrorString("failed to get process ID"); - - if (error.Success()) - { - TimeValue *timeout_ptr = nullptr; - TimeValue timeout_time(TimeValue::Now()); - if (timeout_sec > 0) { - timeout_time.OffsetWithSeconds(timeout_sec); - timeout_ptr = &timeout_time; - } - bool timed_out = false; - shell_info_sp->process_reaped.WaitForValueEqualTo(true, timeout_ptr, &timed_out); - if (timed_out) - { - error.SetErrorString("timed out waiting for shell command to complete"); - - // Kill the process since it didn't complete within the timeout specified - Kill (pid, SIGKILL); - // Wait for the monitor callback to get the message - timeout_time = TimeValue::Now(); - timeout_time.OffsetWithSeconds(1); - timed_out = false; - shell_info_sp->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out); - } - else - { - if (status_ptr) - *status_ptr = shell_info_sp->status; - - if (signo_ptr) - *signo_ptr = shell_info_sp->signo; - - if (command_output_ptr) - { - command_output_ptr->clear(); - uint64_t file_size = output_file_spec.GetByteSize(); - if (file_size > 0) - { - if (file_size > command_output_ptr->max_size()) - { - error.SetErrorStringWithFormat("shell command output is too large to fit into a std::string"); - } - else - { - std::vector<char> command_output(file_size); - output_file_spec.ReadFileContents(0, command_output.data(), file_size, &error); - if (error.Success()) - command_output_ptr->assign(command_output.data(), file_size); - } - } - } + } + + FileSpec output_file_spec{output_file_path.c_str(), false}; + + launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false); + if (output_file_spec) { + launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false, + true); + launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO); + } else { + launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true); + launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true); + } + + std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo()); + const bool monitor_signals = false; + launch_info.SetMonitorProcessCallback( + std::bind(MonitorShellCommand, shell_info_sp, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3, + std::placeholders::_4), + monitor_signals); + + error = LaunchProcess(launch_info); + const lldb::pid_t pid = launch_info.GetProcessID(); + + if (error.Success() && pid == LLDB_INVALID_PROCESS_ID) + error.SetErrorString("failed to get process ID"); + + if (error.Success()) { + bool timed_out = false; + shell_info_sp->process_reaped.WaitForValueEqualTo( + true, std::chrono::seconds(timeout_sec), &timed_out); + if (timed_out) { + error.SetErrorString("timed out waiting for shell command to complete"); + + // Kill the process since it didn't complete within the timeout specified + Kill(pid, SIGKILL); + // Wait for the monitor callback to get the message + timed_out = false; + shell_info_sp->process_reaped.WaitForValueEqualTo( + true, std::chrono::seconds(1), &timed_out); + } else { + if (status_ptr) + *status_ptr = shell_info_sp->status; + + if (signo_ptr) + *signo_ptr = shell_info_sp->signo; + + if (command_output_ptr) { + command_output_ptr->clear(); + uint64_t file_size = output_file_spec.GetByteSize(); + if (file_size > 0) { + if (file_size > command_output_ptr->max_size()) { + error.SetErrorStringWithFormat( + "shell command output is too large to fit into a std::string"); + } else { + std::vector<char> command_output(file_size); + output_file_spec.ReadFileContents(0, command_output.data(), + file_size, &error); + if (error.Success()) + command_output_ptr->assign(command_output.data(), file_size); + } } + } } + } - if (FileSystem::GetFileExists(output_file_spec)) - FileSystem::Unlink(output_file_spec); - return error; + if (FileSystem::GetFileExists(output_file_spec)) + FileSystem::Unlink(output_file_spec); + return error; } // LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC // systems -#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) -#if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) +#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \ + defined(__GLIBC__) || defined(__NetBSD__) +#if !defined(__ANDROID__) // this method needs to be visible to macosx/Host.cpp and // common/Host.cpp. -short -Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) -{ - short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; - -#if defined (__APPLE__) - if (launch_info.GetFlags().Test (eLaunchFlagExec)) - flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag - - if (launch_info.GetFlags().Test (eLaunchFlagDebug)) - flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag - - if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)) - flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag - - if (launch_info.GetLaunchInSeparateProcessGroup()) - flags |= POSIX_SPAWN_SETPGROUP; - +short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { + short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; + +#if defined(__APPLE__) + if (launch_info.GetFlags().Test(eLaunchFlagExec)) + flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) + flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) + flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag + + if (launch_info.GetLaunchInSeparateProcessGroup()) + flags |= POSIX_SPAWN_SETPGROUP; + #ifdef POSIX_SPAWN_CLOEXEC_DEFAULT -#if defined (__APPLE__) && (defined (__x86_64__) || defined (__i386__)) - static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; - if (g_use_close_on_exec_flag == eLazyBoolCalculate) - { - g_use_close_on_exec_flag = eLazyBoolNo; - - uint32_t major, minor, update; - if (HostInfo::GetOSVersion(major, minor, update)) - { - // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier - if (major > 10 || (major == 10 && minor > 7)) - { - // Only enable for 10.8 and later OS versions - g_use_close_on_exec_flag = eLazyBoolYes; - } - } +#if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__)) + static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; + if (g_use_close_on_exec_flag == eLazyBoolCalculate) { + g_use_close_on_exec_flag = eLazyBoolNo; + + uint32_t major, minor, update; + if (HostInfo::GetOSVersion(major, minor, update)) { + // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or + // earlier + if (major > 10 || (major == 10 && minor > 7)) { + // Only enable for 10.8 and later OS versions + g_use_close_on_exec_flag = eLazyBoolYes; + } } + } #else - static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; + static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; #endif - // Close all files exception those with file actions if this is supported. - if (g_use_close_on_exec_flag == eLazyBoolYes) - flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; + // Close all files exception those with file actions if this is supported. + if (g_use_close_on_exec_flag == eLazyBoolYes) + flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; #endif #endif // #if defined (__APPLE__) - return flags; + return flags; } -Error -Host::LaunchProcessPosixSpawn(const char *exe_path, const ProcessLaunchInfo &launch_info, lldb::pid_t &pid) -{ - Error error; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); +Error Host::LaunchProcessPosixSpawn(const char *exe_path, + const ProcessLaunchInfo &launch_info, + lldb::pid_t &pid) { + Error error; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | + LIBLLDB_LOG_PROCESS)); - posix_spawnattr_t attr; - error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); + posix_spawnattr_t attr; + error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_init ( &attr )"); - if (error.Fail()) - return error; + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_init ( &attr )"); + if (error.Fail()) + return error; - // Make a quick class that will cleanup the posix spawn attributes in case - // we return in the middle of this function. - lldb_utility::CleanUp <posix_spawnattr_t *, int> posix_spawnattr_cleanup(&attr, posix_spawnattr_destroy); - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset (&no_signals); - sigfillset (&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); -#if defined (__linux__) || defined (__FreeBSD__) - ::posix_spawnattr_setsigdefault(&attr, &no_signals); + // Make a quick class that will cleanup the posix spawn attributes in case + // we return in the middle of this function. + lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup( + &attr, posix_spawnattr_destroy); + + sigset_t no_signals; + sigset_t all_signals; + sigemptyset(&no_signals); + sigfillset(&all_signals); + ::posix_spawnattr_setsigmask(&attr, &no_signals); +#if defined(__linux__) || defined(__FreeBSD__) + ::posix_spawnattr_setsigdefault(&attr, &no_signals); #else - ::posix_spawnattr_setsigdefault(&attr, &all_signals); + ::posix_spawnattr_setsigdefault(&attr, &all_signals); #endif - short flags = GetPosixspawnFlags(launch_info); + short flags = GetPosixspawnFlags(launch_info); - error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); - if (error.Fail()) - return error; + error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", + flags); + if (error.Fail()) + return error; - // posix_spawnattr_setbinpref_np appears to be an Apple extension per: - // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ -#if defined (__APPLE__) && !defined (__arm__) - - // Don't set the binpref if a shell was provided. After all, that's only going to affect what version of the shell - // is launched, not what fork of the binary is launched. We insert "arch --arch <ARCH> as part of the shell invocation - // to do that job on OSX. - - if (launch_info.GetShell() == nullptr) +// posix_spawnattr_setbinpref_np appears to be an Apple extension per: +// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ +#if defined(__APPLE__) && !defined(__arm__) + + // Don't set the binpref if a shell was provided. After all, that's only + // going to affect what version of the shell + // is launched, not what fork of the binary is launched. We insert "arch + // --arch <ARCH> as part of the shell invocation + // to do that job on OSX. + + if (launch_info.GetShell() == nullptr) { + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + const ArchSpec &arch_spec = launch_info.GetArchitecture(); + cpu_type_t cpu = arch_spec.GetMachOCPUType(); + cpu_type_t sub = arch_spec.GetMachOCPUSubType(); + if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) && + cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) && + !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try + // to set the CPU type or we will fail { - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... - const ArchSpec &arch_spec = launch_info.GetArchitecture(); - cpu_type_t cpu = arch_spec.GetMachOCPUType(); - cpu_type_t sub = arch_spec.GetMachOCPUSubType(); - if (cpu != 0 && - cpu != static_cast<cpu_type_t>(UINT32_MAX) && - cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) && - !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail - { - size_t ocount = 0; - error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount); - - if (error.Fail() || ocount != 1) - return error; - } + size_t ocount = 0; + error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount), + eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, " + "cpu_type = 0x%8.8x, count => %llu )", + cpu, (uint64_t)ocount); + + if (error.Fail() || ocount != 1) + return error; } - -#endif - - const char *tmp_argv[2]; - char * const *argv = const_cast<char * const*>(launch_info.GetArguments().GetConstArgumentVector()); - char * const *envp = const_cast<char * const*>(launch_info.GetEnvironmentEntries().GetConstArgumentVector()); - if (argv == NULL) - { - // posix_spawn gets very unhappy if it doesn't have at least the program - // name in argv[0]. One of the side affects I have noticed is the environment - // variables don't make it into the child process if "argv == NULL"!!! - tmp_argv[0] = exe_path; - tmp_argv[1] = NULL; - argv = const_cast<char * const*>(tmp_argv); + } + +#endif + + const char *tmp_argv[2]; + char *const *argv = const_cast<char *const *>( + launch_info.GetArguments().GetConstArgumentVector()); + char *const *envp = const_cast<char *const *>( + launch_info.GetEnvironmentEntries().GetConstArgumentVector()); + if (argv == NULL) { + // posix_spawn gets very unhappy if it doesn't have at least the program + // name in argv[0]. One of the side affects I have noticed is the + // environment + // variables don't make it into the child process if "argv == NULL"!!! + tmp_argv[0] = exe_path; + tmp_argv[1] = NULL; + argv = const_cast<char *const *>(tmp_argv); + } + +#if !defined(__APPLE__) + // manage the working directory + char current_dir[PATH_MAX]; + current_dir[0] = '\0'; +#endif + + FileSpec working_dir{launch_info.GetWorkingDirectory()}; + if (working_dir) { +#if defined(__APPLE__) + // Set the working directory on this thread only + if (__pthread_chdir(working_dir.GetCString()) < 0) { + if (errno == ENOENT) { + error.SetErrorStringWithFormat("No such file or directory: %s", + working_dir.GetCString()); + } else if (errno == ENOTDIR) { + error.SetErrorStringWithFormat("Path doesn't name a directory: %s", + working_dir.GetCString()); + } else { + error.SetErrorStringWithFormat("An unknown error occurred when " + "changing directory for process " + "execution."); + } + return error; } - -#if !defined (__APPLE__) - // manage the working directory - char current_dir[PATH_MAX]; - current_dir[0] = '\0'; -#endif - - FileSpec working_dir{launch_info.GetWorkingDirectory()}; - if (working_dir) - { -#if defined (__APPLE__) - // Set the working directory on this thread only - if (__pthread_chdir(working_dir.GetCString()) < 0) { - if (errno == ENOENT) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - } else if (errno == ENOTDIR) { - error.SetErrorStringWithFormat("Path doesn't name a directory: %s", - working_dir.GetCString()); - } else { - error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution."); - } - return error; - } #else - if (::getcwd(current_dir, sizeof(current_dir)) == NULL) - { - error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to save the current directory"); - return error; - } - - if (::chdir(working_dir.GetCString()) == -1) - { - error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to change working directory to %s", - working_dir.GetCString()); - return error; - } -#endif + if (::getcwd(current_dir, sizeof(current_dir)) == NULL) { + error.SetError(errno, eErrorTypePOSIX); + error.LogIfError(log, "unable to save the current directory"); + return error; } - ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; - const size_t num_file_actions = launch_info.GetNumFileActions (); - if (num_file_actions > 0) - { - posix_spawn_file_actions_t file_actions; - error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); - if (error.Fail() || log) - error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )"); - if (error.Fail()) - return error; - - // Make a quick class that will cleanup the posix spawn attributes in case - // we return in the middle of this function. - lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy); - - for (size_t i=0; i<num_file_actions; ++i) - { - const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); - if (launch_file_action) - { - if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error)) - return error; - } - } + if (::chdir(working_dir.GetCString()) == -1) { + error.SetError(errno, eErrorTypePOSIX); + error.LogIfError(log, "unable to change working directory to %s", + working_dir.GetCString()); + return error; + } +#endif + } - error.SetError(::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), eErrorTypePOSIX); + ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; + const size_t num_file_actions = launch_info.GetNumFileActions(); + if (num_file_actions > 0) { + posix_spawn_file_actions_t file_actions; + error.SetError(::posix_spawn_file_actions_init(&file_actions), + eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )"); + if (error.Fail()) + return error; - if (error.Fail() || log) - { - error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", result_pid, - exe_path, static_cast<void *>(&file_actions), static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), - reinterpret_cast<const void *>(envp)); - if (log) - { - for (int ii=0; argv[ii]; ++ii) - log->Printf("argv[%i] = '%s'", ii, argv[ii]); - } - } + // Make a quick class that will cleanup the posix spawn attributes in case + // we return in the middle of this function. + lldb_utility::CleanUp<posix_spawn_file_actions_t *, int> + posix_spawn_file_actions_cleanup(&file_actions, + posix_spawn_file_actions_destroy); + + for (size_t i = 0; i < num_file_actions; ++i) { + const FileAction *launch_file_action = + launch_info.GetFileActionAtIndex(i); + if (launch_file_action) { + if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, + error)) + return error; + } + } + error.SetError( + ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), + eErrorTypePOSIX); + + if (error.Fail() || log) { + error.PutToLog( + log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, " + "attr = %p, argv = %p, envp = %p )", + result_pid, exe_path, static_cast<void *>(&file_actions), + static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), + reinterpret_cast<const void *>(envp)); + if (log) { + for (int ii = 0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } } - else - { - error.SetError(::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), eErrorTypePOSIX); - if (error.Fail() || log) - { - error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", - result_pid, exe_path, static_cast<void *>(&attr), reinterpret_cast<const void *>(argv), - reinterpret_cast<const void *>(envp)); - if (log) - { - for (int ii=0; argv[ii]; ++ii) - log->Printf("argv[%i] = '%s'", ii, argv[ii]); - } - } + } else { + error.SetError( + ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), + eErrorTypePOSIX); + + if (error.Fail() || log) { + error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', " + "file_actions = NULL, attr = %p, argv = %p, envp = " + "%p )", + result_pid, exe_path, static_cast<void *>(&attr), + reinterpret_cast<const void *>(argv), + reinterpret_cast<const void *>(envp)); + if (log) { + for (int ii = 0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } } - pid = result_pid; + } + pid = result_pid; - if (working_dir) - { -#if defined (__APPLE__) - // No more thread specific current working directory - __pthread_fchdir (-1); + if (working_dir) { +#if defined(__APPLE__) + // No more thread specific current working directory + __pthread_fchdir(-1); #else - if (::chdir(current_dir) == -1 && error.Success()) - { - error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to change current directory back to %s", - current_dir); - } -#endif + if (::chdir(current_dir) == -1 && error.Success()) { + error.SetError(errno, eErrorTypePOSIX); + error.LogIfError(log, "unable to change current directory back to %s", + current_dir); } +#endif + } - return error; + 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; +bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, + Log *log, Error &error) { + if (info == NULL) + return false; - 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; + 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().str().c_str(), oflag, mode), + eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "posix_spawn_file_actions_addopen (action=%p, " + "fd=%i, path='%s', oflag=%i, mode=%i)", + static_cast<void *>(file_actions), info->GetFD(), + info->GetPath().str().c_str(), oflag, mode); } - return error.Success(); + break; + } + return error.Success(); } -#endif // !defined(__ANDROID__) && !defined(__ANDROID_NDK__) -#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) +#endif // !defined(__ANDROID__) +#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || + // defined (__GLIBC__) || defined(__NetBSD__) -#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) || defined(_WIN32) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || \ + defined(__NetBSD__) || defined(_WIN32) // The functions below implement process launching via posix_spawn() for Linux, // FreeBSD and NetBSD. -Error -Host::LaunchProcess (ProcessLaunchInfo &launch_info) -{ - std::unique_ptr<ProcessLauncher> delegate_launcher; +Error Host::LaunchProcess(ProcessLaunchInfo &launch_info) { + std::unique_ptr<ProcessLauncher> delegate_launcher; #if defined(_WIN32) - delegate_launcher.reset(new ProcessLauncherWindows()); -#elif defined(__ANDROID__) || defined(__ANDROID_NDK__) - delegate_launcher.reset(new ProcessLauncherAndroid()); + delegate_launcher.reset(new ProcessLauncherWindows()); +#elif defined(__linux__) + delegate_launcher.reset(new ProcessLauncherLinux()); #else - delegate_launcher.reset(new ProcessLauncherPosix()); + delegate_launcher.reset(new ProcessLauncherPosix()); #endif - MonitoringProcessLauncher launcher(std::move(delegate_launcher)); + MonitoringProcessLauncher launcher(std::move(delegate_launcher)); - Error error; - HostProcess process = launcher.LaunchProcess(launch_info, error); + Error error; + HostProcess process = launcher.LaunchProcess(launch_info, error); - // TODO(zturner): It would be better if the entire HostProcess were returned instead of writing - // it into this structure. - launch_info.SetProcessID(process.GetProcessId()); + // TODO(zturner): It would be better if the entire HostProcess were returned + // instead of writing + // it into this structure. + launch_info.SetProcessID(process.GetProcessId()); - return error; + return error; } #endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) #ifndef _WIN32 -void -Host::Kill(lldb::pid_t pid, int signo) -{ - ::kill(pid, signo); -} +void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); } #endif -#if !defined (__APPLE__) -bool -Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no) -{ - return false; -} - -void -Host::SetCrashDescriptionWithFormat (const char *format, ...) -{ -} - -void -Host::SetCrashDescription (const char *description) -{ +#if !defined(__APPLE__) +bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, + uint32_t line_no) { + return false; } #endif -const UnixSignalsSP & -Host::GetUnixSignals() -{ - static const auto s_unix_signals_sp = UnixSignals::Create(HostInfo::GetArchitecture()); - return s_unix_signals_sp; +const UnixSignalsSP &Host::GetUnixSignals() { + static const auto s_unix_signals_sp = + UnixSignals::Create(HostInfo::GetArchitecture()); + return s_unix_signals_sp; } diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp index 2bff4d9a670f..01ac87047c5d 100644 --- a/source/Host/common/HostInfoBase.cpp +++ b/source/Host/common/HostInfoBase.cpp @@ -17,411 +17,379 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Host/HostInfoBase.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" -#include <thread> #include <mutex> // std::once +#include <thread> using namespace lldb; using namespace lldb_private; -namespace -{ - //---------------------------------------------------------------------- - // The HostInfoBaseFields is a work around for windows not supporting - // static variables correctly in a thread safe way. Really each of the - // variables in HostInfoBaseFields should live in the functions in which - // they are used and each one should be static, but the work around is - // in place to avoid this restriction. Ick. - //---------------------------------------------------------------------- - - struct HostInfoBaseFields - { - ~HostInfoBaseFields() - { - if (m_lldb_process_tmp_dir.Exists()) - { - // Remove the LLDB temporary directory if we have one. Set "recurse" to - // true to all files that were created for the LLDB process can be cleaned up. - FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true); - } - } - - uint32_t m_number_cpus; - std::string m_vendor_string; - std::string m_os_string; - std::string m_host_triple; - - ArchSpec m_host_arch_32; - ArchSpec m_host_arch_64; - - FileSpec m_lldb_so_dir; - FileSpec m_lldb_support_exe_dir; - FileSpec m_lldb_headers_dir; - FileSpec m_lldb_python_dir; - FileSpec m_lldb_clang_resource_dir; - FileSpec m_lldb_system_plugin_dir; - FileSpec m_lldb_user_plugin_dir; - FileSpec m_lldb_process_tmp_dir; - FileSpec m_lldb_global_tmp_dir; - }; - - HostInfoBaseFields *g_fields = nullptr; +namespace { +//---------------------------------------------------------------------- +// The HostInfoBaseFields is a work around for windows not supporting +// static variables correctly in a thread safe way. Really each of the +// variables in HostInfoBaseFields should live in the functions in which +// they are used and each one should be static, but the work around is +// in place to avoid this restriction. Ick. +//---------------------------------------------------------------------- + +struct HostInfoBaseFields { + ~HostInfoBaseFields() { + if (m_lldb_process_tmp_dir.Exists()) { + // Remove the LLDB temporary directory if we have one. Set "recurse" to + // true to all files that were created for the LLDB process can be cleaned + // up. + FileSystem::DeleteDirectory(m_lldb_process_tmp_dir, true); + } + } + + uint32_t m_number_cpus; + std::string m_vendor_string; + std::string m_os_string; + std::string m_host_triple; + + ArchSpec m_host_arch_32; + ArchSpec m_host_arch_64; + + FileSpec m_lldb_so_dir; + FileSpec m_lldb_support_exe_dir; + FileSpec m_lldb_headers_dir; + FileSpec m_lldb_python_dir; + FileSpec m_lldb_clang_resource_dir; + FileSpec m_lldb_system_plugin_dir; + FileSpec m_lldb_user_plugin_dir; + FileSpec m_lldb_process_tmp_dir; + FileSpec m_lldb_global_tmp_dir; +}; + +HostInfoBaseFields *g_fields = nullptr; } -void -HostInfoBase::Initialize() -{ - g_fields = new HostInfoBaseFields(); +void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } + +void HostInfoBase::Terminate() { + delete g_fields; + g_fields = nullptr; } -void -HostInfoBase::Terminate() -{ - delete g_fields; - g_fields = nullptr; +uint32_t HostInfoBase::GetNumberCPUS() { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_number_cpus = std::thread::hardware_concurrency(); + }); + return g_fields->m_number_cpus; } -uint32_t -HostInfoBase::GetNumberCPUS() -{ - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_number_cpus = std::thread::hardware_concurrency(); - }); - return g_fields->m_number_cpus; +uint32_t HostInfoBase::GetMaxThreadNameLength() { return 0; } + +llvm::StringRef HostInfoBase::GetVendorString() { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_vendor_string = + HostInfo::GetArchitecture().GetTriple().getVendorName().str(); + }); + return g_fields->m_vendor_string; } -uint32_t -HostInfoBase::GetMaxThreadNameLength() -{ - return 0; +llvm::StringRef HostInfoBase::GetOSString() { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_os_string = + std::move(HostInfo::GetArchitecture().GetTriple().getOSName()); + }); + return g_fields->m_os_string; } -llvm::StringRef -HostInfoBase::GetVendorString() -{ - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_vendor_string = HostInfo::GetArchitecture().GetTriple().getVendorName().str(); - }); - return g_fields->m_vendor_string; +llvm::StringRef HostInfoBase::GetTargetTriple() { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_host_triple = + HostInfo::GetArchitecture().GetTriple().getTriple(); + }); + return g_fields->m_host_triple; } -llvm::StringRef -HostInfoBase::GetOSString() -{ - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName()); - }); - return g_fields->m_os_string; +const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, + g_fields->m_host_arch_64); + }); + + // If an explicit 32 or 64-bit architecture was requested, return that. + if (arch_kind == eArchKind32) + return g_fields->m_host_arch_32; + if (arch_kind == eArchKind64) + return g_fields->m_host_arch_64; + + // Otherwise prefer the 64-bit architecture if it is valid. + return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 + : g_fields->m_host_arch_32; } -llvm::StringRef -HostInfoBase::GetTargetTriple() -{ +bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { + file_spec.Clear(); + +#if defined(LLDB_DISABLE_PYTHON) + if (type == lldb::ePathTypePythonDir) + return false; +#endif + + FileSpec *result = nullptr; + switch (type) { + case lldb::ePathTypeLLDBShlibDir: { static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple(); + static bool success = false; + std::call_once(g_once_flag, []() { + success = + HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", + g_fields->m_lldb_so_dir.GetPath().c_str()); }); - return g_fields->m_host_triple; -} - -const ArchSpec & -HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) -{ + if (success) + result = &g_fields->m_lldb_so_dir; + } break; + case lldb::ePathTypeSupportExecutableDir: { static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeSupportExeDirectory( + g_fields->m_lldb_support_exe_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf( + "HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", + g_fields->m_lldb_support_exe_dir.GetPath().c_str()); }); + if (success) + result = &g_fields->m_lldb_support_exe_dir; + } break; + case lldb::ePathTypeHeaderDir: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", + g_fields->m_lldb_headers_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_headers_dir; + } break; + case lldb::ePathTypePythonDir: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", + g_fields->m_lldb_python_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_python_dir; + } break; + case lldb::ePathTypeClangDir: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = + HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf( + "HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", + g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_clang_resource_dir; + } break; + case lldb::ePathTypeLLDBSystemPlugins: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeSystemPluginsDirectory( + g_fields->m_lldb_system_plugin_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf( + "HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", + g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_system_plugin_dir; + } break; + case lldb::ePathTypeLLDBUserPlugins: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeUserPluginsDirectory( + g_fields->m_lldb_user_plugin_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf( + "HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", + g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_user_plugin_dir; + } break; + case lldb::ePathTypeLLDBTempSystemDir: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeProcessTempFileDirectory( + g_fields->m_lldb_process_tmp_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf( + "HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", + g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_process_tmp_dir; + } break; + case lldb::ePathTypeGlobalLLDBTempSystemDir: { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeGlobalTempFileDirectory( + g_fields->m_lldb_global_tmp_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(" + "ePathTypeGlobalLLDBTempSystemDir) => '%s'", + g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_global_tmp_dir; + } break; + } - // If 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; + if (!result) + return false; + file_spec = *result; + return true; } -bool -HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) -{ - file_spec.Clear(); +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". -#if defined(LLDB_DISABLE_PYTHON) - if (type == lldb::ePathTypePythonDir) - return false; -#endif + FileSpec lldb_file_spec( + Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>( + reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); - FileSpec *result = nullptr; - switch (type) - { - case lldb::ePathTypeLLDBShlibDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_so_dir; - } - break; - case lldb::ePathTypeSupportExecutableDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", - g_fields->m_lldb_support_exe_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_support_exe_dir; - } - break; - case lldb::ePathTypeHeaderDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_headers_dir; - } - break; - case lldb::ePathTypePythonDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_python_dir; - } - break; - case lldb::ePathTypeClangDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_clang_resource_dir; - } - break; - case lldb::ePathTypeLLDBSystemPlugins: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", - g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_system_plugin_dir; - } - break; - case lldb::ePathTypeLLDBUserPlugins: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", - g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_user_plugin_dir; - } - break; - case lldb::ePathTypeLLDBTempSystemDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_process_tmp_dir; - } - break; - case lldb::ePathTypeGlobalLLDBTempSystemDir: - { - static std::once_flag g_once_flag; - static bool success = false; - std::call_once(g_once_flag, []() { - success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir); - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); - }); - if (success) - result = &g_fields->m_lldb_global_tmp_dir; - } - break; - } + // This is necessary because when running the testsuite the shlib might be a + // symbolic link inside the Python resource dir. + FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); - if (!result) - return false; - file_spec = *result; - return true; -} + // Remove the filename so that this FileSpec only represents the directory. + file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); -bool -HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) -{ - // To get paths related to LLDB we get the path to the executable that - // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", - // on linux this is assumed to be the "lldb" main executable. If LLDB on - // linux is actually in a shared library (liblldb.so) then this function will - // need to be modified to "do the right thing". - - FileSpec lldb_file_spec( - Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); - - // This is necessary because when running the testsuite the shlib might be a symbolic link inside the Python resource dir. - FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); - - // Remove the filename so that this FileSpec only represents the directory. - file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); - - return (bool)file_spec.GetDirectory(); + return (bool)file_spec.GetDirectory(); } -bool -HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) -{ - return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); +bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) { + return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); } -bool -HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) -{ - FileSpec temp_file_spec; - if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) - return false; +bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) { + FileSpec temp_file_spec; + if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec)) + return false; - std::string pid_str{std::to_string(Host::GetCurrentProcessID())}; - temp_file_spec.AppendPathComponent(pid_str); - if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) - return false; + std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())}; + temp_file_spec.AppendPathComponent(pid_str); + if (!FileSystem::MakeDirectory(temp_file_spec, + eFilePermissionsDirectoryDefault) + .Success()) + return false; - file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); - return true; + file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); + return true; } -bool -HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) -{ - llvm::SmallVector<char, 16> tmpdir; - llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); - file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); - return true; +bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) { + llvm::SmallVector<char, 16> tmpdir; + llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir); + file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true); + return true; } -bool -HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) -{ - file_spec.Clear(); +bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { + file_spec.Clear(); - FileSpec temp_file_spec; - if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) - return false; + FileSpec temp_file_spec; + if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) + return false; - temp_file_spec.AppendPathComponent("lldb"); - if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) - return false; + temp_file_spec.AppendPathComponent("lldb"); + if (!FileSystem::MakeDirectory(temp_file_spec, + eFilePermissionsDirectoryDefault) + .Success()) + return false; - file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); - return true; + file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); + return true; } -bool -HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) -{ - // TODO(zturner): Figure out how to compute the header directory for all platforms. - return false; +bool HostInfoBase::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::ComputeSystemPluginsDirectory(FileSpec &file_spec) { + // TODO(zturner): Figure out how to compute the system plugins directory for + // all platforms. + return false; } -bool -HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) -{ - return false; -} +bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; } -bool -HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) -{ - // TODO(zturner): Figure out how to compute the user plugins directory for all platforms. - return false; +bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) { + // TODO(zturner): Figure out how to compute the user plugins directory for all + // platforms. + return false; } -void -HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) -{ - llvm::Triple triple(llvm::sys::getProcessTriple()); - - arch_32.Clear(); - arch_64.Clear(); - - switch (triple.getArch()) - { - default: - arch_32.SetTriple(triple); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::ppc64: - case llvm::Triple::x86_64: - arch_64.SetTriple(triple); - arch_32.SetTriple(triple.get32BitArchVariant()); - break; - - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::sparcv9: - case llvm::Triple::systemz: - arch_64.SetTriple(triple); - break; - } +void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64) { + llvm::Triple triple(llvm::sys::getProcessTriple()); + + arch_32.Clear(); + arch_64.Clear(); + + switch (triple.getArch()) { + default: + arch_32.SetTriple(triple); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::ppc64: + case llvm::Triple::x86_64: + arch_64.SetTriple(triple); + arch_32.SetTriple(triple.get32BitArchVariant()); + break; + + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::sparcv9: + case llvm::Triple::systemz: + arch_64.SetTriple(triple); + break; + } } diff --git a/source/Host/common/HostNativeThreadBase.cpp b/source/Host/common/HostNativeThreadBase.cpp index 9fea54d1e3fa..fd39e0d1e2fe 100644 --- a/source/Host/common/HostNativeThreadBase.cpp +++ b/source/Host/common/HostNativeThreadBase.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/HostNativeThreadBase.h" #include "lldb/Core/Log.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Host/HostNativeThreadBase.h" #include "lldb/Host/ThisThread.h" #include "lldb/Host/ThreadLauncher.h" #include "llvm/ADT/StringExtras.h" @@ -18,65 +18,49 @@ using namespace lldb; using namespace lldb_private; HostNativeThreadBase::HostNativeThreadBase() - : m_thread(LLDB_INVALID_HOST_THREAD) - , m_result(0) -{ -} + : m_thread(LLDB_INVALID_HOST_THREAD), m_result(0) {} HostNativeThreadBase::HostNativeThreadBase(thread_t thread) - : m_thread(thread) - , m_result(0) -{ -} + : m_thread(thread), m_result(0) {} -lldb::thread_t -HostNativeThreadBase::GetSystemHandle() const -{ - return m_thread; +lldb::thread_t HostNativeThreadBase::GetSystemHandle() const { + return m_thread; } -lldb::thread_result_t -HostNativeThreadBase::GetResult() const -{ - return m_result; +lldb::thread_result_t HostNativeThreadBase::GetResult() const { + return m_result; } -bool -HostNativeThreadBase::IsJoinable() const -{ - return m_thread != LLDB_INVALID_HOST_THREAD; +bool HostNativeThreadBase::IsJoinable() const { + return m_thread != LLDB_INVALID_HOST_THREAD; } -void -HostNativeThreadBase::Reset() -{ - m_thread = LLDB_INVALID_HOST_THREAD; - m_result = 0; +void HostNativeThreadBase::Reset() { + m_thread = LLDB_INVALID_HOST_THREAD; + m_result = 0; } -lldb::thread_t -HostNativeThreadBase::Release() -{ - lldb::thread_t result = m_thread; - m_thread = LLDB_INVALID_HOST_THREAD; - m_result = 0; +lldb::thread_t HostNativeThreadBase::Release() { + lldb::thread_t result = m_thread; + m_thread = LLDB_INVALID_HOST_THREAD; + m_result = 0; - return result; + return result; } lldb::thread_result_t -HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg) -{ - ThreadLauncher::HostThreadCreateInfo *info = (ThreadLauncher::HostThreadCreateInfo *)arg; - ThisThread::SetName(info->thread_name.c_str(), HostInfo::GetMaxThreadNameLength()); +HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg) { + ThreadLauncher::HostThreadCreateInfo *info = + (ThreadLauncher::HostThreadCreateInfo *)arg; + ThisThread::SetName(info->thread_name, HostInfo::GetMaxThreadNameLength()); - thread_func_t thread_fptr = info->thread_fptr; - thread_arg_t thread_arg = info->thread_arg; + thread_func_t thread_fptr = info->thread_fptr; + thread_arg_t thread_arg = info->thread_arg; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("thread created"); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("thread created"); - delete info; - return thread_fptr(thread_arg); + delete info; + return thread_fptr(thread_arg); } diff --git a/source/Host/common/HostProcess.cpp b/source/Host/common/HostProcess.cpp index 0262e1c03c20..2d99d8e1fc99 100644 --- a/source/Host/common/HostProcess.cpp +++ b/source/Host/common/HostProcess.cpp @@ -7,59 +7,42 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Host/HostNativeProcess.h" #include "lldb/Host/HostProcess.h" +#include "lldb/Host/HostNativeProcess.h" #include "lldb/Host/HostThread.h" using namespace lldb; using namespace lldb_private; -HostProcess::HostProcess() - : m_native_process(new HostNativeProcess) -{ -} +HostProcess::HostProcess() : m_native_process(new HostNativeProcess) {} HostProcess::HostProcess(lldb::process_t process) - : m_native_process(new HostNativeProcess(process)) -{ -} + : m_native_process(new HostNativeProcess(process)) {} -HostProcess::~HostProcess() -{ -} +HostProcess::~HostProcess() {} -Error HostProcess::Terminate() -{ - return m_native_process->Terminate(); -} +Error HostProcess::Terminate() { return m_native_process->Terminate(); } -Error HostProcess::GetMainModule(FileSpec &file_spec) const -{ - return m_native_process->GetMainModule(file_spec); +Error HostProcess::GetMainModule(FileSpec &file_spec) const { + return m_native_process->GetMainModule(file_spec); } -lldb::pid_t HostProcess::GetProcessId() const -{ - return m_native_process->GetProcessId(); +lldb::pid_t HostProcess::GetProcessId() const { + return m_native_process->GetProcessId(); } -bool HostProcess::IsRunning() const -{ - return m_native_process->IsRunning(); -} +bool HostProcess::IsRunning() const { return m_native_process->IsRunning(); } HostThread -HostProcess::StartMonitoring(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) -{ - return m_native_process->StartMonitoring(callback, monitor_signals); +HostProcess::StartMonitoring(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals) { + return m_native_process->StartMonitoring(callback, monitor_signals); } -HostNativeProcessBase &HostProcess::GetNativeProcess() -{ - return *m_native_process; +HostNativeProcessBase &HostProcess::GetNativeProcess() { + return *m_native_process; } -const HostNativeProcessBase &HostProcess::GetNativeProcess() const -{ - return *m_native_process; +const HostNativeProcessBase &HostProcess::GetNativeProcess() const { + return *m_native_process; } diff --git a/source/Host/common/HostThread.cpp b/source/Host/common/HostThread.cpp index 7757477126c4..738b7ef72f16 100644 --- a/source/Host/common/HostThread.cpp +++ b/source/Host/common/HostThread.cpp @@ -7,72 +7,41 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Host/HostNativeThread.h" #include "lldb/Host/HostThread.h" +#include "lldb/Host/HostNativeThread.h" using namespace lldb; using namespace lldb_private; -HostThread::HostThread() - : m_native_thread(new HostNativeThread) -{ -} +HostThread::HostThread() : m_native_thread(new HostNativeThread) {} HostThread::HostThread(lldb::thread_t thread) - : m_native_thread(new HostNativeThread(thread)) -{ -} + : m_native_thread(new HostNativeThread(thread)) {} -Error -HostThread::Join(lldb::thread_result_t *result) -{ - return m_native_thread->Join(result); +Error HostThread::Join(lldb::thread_result_t *result) { + return m_native_thread->Join(result); } -Error -HostThread::Cancel() -{ - return m_native_thread->Cancel(); -} +Error HostThread::Cancel() { return m_native_thread->Cancel(); } -void -HostThread::Reset() -{ - return m_native_thread->Reset(); -} +void HostThread::Reset() { return m_native_thread->Reset(); } -lldb::thread_t -HostThread::Release() -{ - return m_native_thread->Release(); -} +lldb::thread_t HostThread::Release() { return m_native_thread->Release(); } -bool -HostThread::IsJoinable() const -{ - return m_native_thread->IsJoinable(); -} +bool HostThread::IsJoinable() const { return m_native_thread->IsJoinable(); } -HostNativeThread & -HostThread::GetNativeThread() -{ - return static_cast<HostNativeThread &>(*m_native_thread); +HostNativeThread &HostThread::GetNativeThread() { + return static_cast<HostNativeThread &>(*m_native_thread); } -const HostNativeThread & -HostThread::GetNativeThread() const -{ - return static_cast<const HostNativeThread &>(*m_native_thread); +const HostNativeThread &HostThread::GetNativeThread() const { + return static_cast<const HostNativeThread &>(*m_native_thread); } -lldb::thread_result_t -HostThread::GetResult() const -{ - return m_native_thread->GetResult(); +lldb::thread_result_t HostThread::GetResult() const { + return m_native_thread->GetResult(); } -bool -HostThread::EqualsThread(lldb::thread_t thread) const -{ - return m_native_thread->GetSystemHandle() == thread; +bool HostThread::EqualsThread(lldb::thread_t thread) const { + return m_native_thread->GetSystemHandle() == thread; } diff --git a/source/Host/common/LockFileBase.cpp b/source/Host/common/LockFileBase.cpp index f74694561184..b30acc5d5044 100644 --- a/source/Host/common/LockFileBase.cpp +++ b/source/Host/common/LockFileBase.cpp @@ -12,113 +12,71 @@ using namespace lldb; using namespace lldb_private; -namespace -{ +namespace { -Error -AlreadyLocked () -{ - return Error ("Already locked"); -} - -Error -NotLocked () -{ - return Error ("Not locked"); -} +Error AlreadyLocked() { return Error("Already locked"); } +Error NotLocked() { return Error("Not locked"); } } -LockFileBase::LockFileBase (int fd) : - m_fd (fd), - m_locked (false), - m_start (0), - m_len (0) -{ - -} +LockFileBase::LockFileBase(int fd) + : m_fd(fd), m_locked(false), m_start(0), m_len(0) {} -bool -LockFileBase::IsLocked () const -{ - return m_locked; -} +bool LockFileBase::IsLocked() const { return m_locked; } -Error -LockFileBase::WriteLock (const uint64_t start, const uint64_t len) -{ - return DoLock ([&] (const uint64_t start, const uint64_t len) - { - return DoWriteLock (start, len); - }, start, len); +Error LockFileBase::WriteLock(const uint64_t start, const uint64_t len) { + return DoLock([&](const uint64_t start, + const uint64_t len) { return DoWriteLock(start, len); }, + start, len); } -Error -LockFileBase::TryWriteLock (const uint64_t start, const uint64_t len) -{ - return DoLock ([&] (const uint64_t start, const uint64_t len) - { - return DoTryWriteLock (start, len); - }, start, len); +Error LockFileBase::TryWriteLock(const uint64_t start, const uint64_t len) { + return DoLock([&](const uint64_t start, + const uint64_t len) { return DoTryWriteLock(start, len); }, + start, len); } -Error -LockFileBase::ReadLock (const uint64_t start, const uint64_t len) -{ - return DoLock ([&] (const uint64_t start, const uint64_t len) - { - return DoReadLock (start, len); - }, start, len); +Error LockFileBase::ReadLock(const uint64_t start, const uint64_t len) { + return DoLock([&](const uint64_t start, + const uint64_t len) { return DoReadLock(start, len); }, + start, len); } -Error -LockFileBase::TryReadLock (const uint64_t start, const uint64_t len) -{ - return DoLock ([&] (const uint64_t start, const uint64_t len) - { - return DoTryReadLock (start, len); - }, start, len); - +Error LockFileBase::TryReadLock(const uint64_t start, const uint64_t len) { + return DoLock([&](const uint64_t start, + const uint64_t len) { return DoTryReadLock(start, len); }, + start, len); } -Error -LockFileBase::Unlock () -{ - if (!IsLocked ()) - return NotLocked (); - - const auto error = DoUnlock (); - if (error.Success ()) - { - m_locked = false; - m_start = 0; - m_len = 0; - } - return error; +Error LockFileBase::Unlock() { + if (!IsLocked()) + return NotLocked(); + + const auto error = DoUnlock(); + if (error.Success()) { + m_locked = false; + m_start = 0; + m_len = 0; + } + return error; } -bool -LockFileBase::IsValidFile () const -{ - return m_fd != -1; -} +bool LockFileBase::IsValidFile() const { return m_fd != -1; } -Error -LockFileBase::DoLock (const Locker &locker, const uint64_t start, const uint64_t len) -{ - if (!IsValidFile ()) - return Error("File is invalid"); +Error LockFileBase::DoLock(const Locker &locker, const uint64_t start, + const uint64_t len) { + if (!IsValidFile()) + return Error("File is invalid"); - if (IsLocked ()) - return AlreadyLocked (); + if (IsLocked()) + return AlreadyLocked(); - const auto error = locker (start, len); - if (error.Success ()) - { - m_locked = true; - m_start = start; - m_len = len; - } + const auto error = locker(start, len); + if (error.Success()) { + m_locked = true; + m_start = start; + m_len = len; + } - return error; + return error; } diff --git a/source/Host/common/MonitoringProcessLauncher.cpp b/source/Host/common/MonitoringProcessLauncher.cpp index 2845155987e3..ae98cc83379d 100644 --- a/source/Host/common/MonitoringProcessLauncher.cpp +++ b/source/Host/common/MonitoringProcessLauncher.cpp @@ -1,4 +1,4 @@ -//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// +//===-- MonitoringProcessLauncher.cpp ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/MonitoringProcessLauncher.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostProcess.h" -#include "lldb/Host/MonitoringProcessLauncher.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" @@ -20,81 +20,73 @@ using namespace lldb; using namespace lldb_private; -MonitoringProcessLauncher::MonitoringProcessLauncher(std::unique_ptr<ProcessLauncher> delegate_launcher) - : m_delegate_launcher(std::move(delegate_launcher)) -{ -} +MonitoringProcessLauncher::MonitoringProcessLauncher( + std::unique_ptr<ProcessLauncher> delegate_launcher) + : m_delegate_launcher(std::move(delegate_launcher)) {} HostProcess -MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) -{ - ProcessLaunchInfo resolved_info(launch_info); +MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, + Error &error) { + ProcessLaunchInfo resolved_info(launch_info); - error.Clear(); - char exe_path[PATH_MAX]; + error.Clear(); + char exe_path[PATH_MAX]; - PlatformSP host_platform_sp(Platform::GetHostPlatform()); + PlatformSP host_platform_sp(Platform::GetHostPlatform()); - const ArchSpec &arch_spec = resolved_info.GetArchitecture(); + const ArchSpec &arch_spec = resolved_info.GetArchitecture(); - FileSpec exe_spec(resolved_info.GetExecutableFile()); + FileSpec exe_spec(resolved_info.GetExecutableFile()); - FileSpec::FileType file_type = exe_spec.GetFileType(); - if (file_type != FileSpec::eFileTypeRegular) - { - ModuleSpec module_spec(exe_spec, arch_spec); - lldb::ModuleSP exe_module_sp; - error = host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL); + FileSpec::FileType file_type = exe_spec.GetFileType(); + if (file_type != FileSpec::eFileTypeRegular) { + ModuleSpec module_spec(exe_spec, arch_spec); + lldb::ModuleSP exe_module_sp; + error = + host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL); - if (error.Fail()) - return HostProcess(); + if (error.Fail()) + return HostProcess(); - if (exe_module_sp) - exe_spec = exe_module_sp->GetFileSpec(); - } + if (exe_module_sp) + exe_spec = exe_module_sp->GetFileSpec(); + } - if (exe_spec.Exists()) - { - exe_spec.GetPath(exe_path, sizeof(exe_path)); - } - else - { - resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); - error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path); - return HostProcess(); - } - - resolved_info.SetExecutableFile(exe_spec, false); - assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY)); + if (exe_spec.Exists()) { + exe_spec.GetPath(exe_path, sizeof(exe_path)); + } else { + resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); + error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path); + return HostProcess(); + } - HostProcess process = m_delegate_launcher->LaunchProcess(resolved_info, error); + resolved_info.SetExecutableFile(exe_spec, false); + assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY)); - if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + HostProcess process = + m_delegate_launcher->LaunchProcess(resolved_info, error); - Host::MonitorChildProcessCallback callback = launch_info.GetMonitorProcessCallback(); + if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - bool monitor_signals = false; - if (callback) - { - // If the ProcessLaunchInfo specified a callback, use that. - monitor_signals = launch_info.GetMonitorSignals(); - } - else - { - callback = Process::SetProcessExitStatus; - } + Host::MonitorChildProcessCallback callback = + launch_info.GetMonitorProcessCallback(); - process.StartMonitoring(callback, monitor_signals); - if (log) - log->PutCString("started monitoring child process."); + bool monitor_signals = false; + if (callback) { + // If the ProcessLaunchInfo specified a callback, use that. + monitor_signals = launch_info.GetMonitorSignals(); + } else { + callback = Process::SetProcessExitStatus; } - else - { - // Invalid process ID, something didn't go well - if (error.Success()) - error.SetErrorString("process launch failed for unknown reasons"); - } - return process; + + process.StartMonitoring(callback, monitor_signals); + if (log) + log->PutCString("started monitoring child process."); + } else { + // Invalid process ID, something didn't go well + if (error.Success()) + error.SetErrorString("process launch failed for unknown reasons"); + } + return process; } diff --git a/source/Host/common/Mutex.cpp b/source/Host/common/Mutex.cpp deleted file mode 100644 index 98f5321ad67f..000000000000 --- a/source/Host/common/Mutex.cpp +++ /dev/null @@ -1,398 +0,0 @@ -//===-- Mutex.cpp -----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/Mutex.h" -#include "lldb/Host/Host.h" - -#ifndef _WIN32 -#include <pthread.h> -#endif -#include <string.h> -#include <stdio.h> - -#if 0 -// This logging is way too verbose to enable even for a log channel. -// This logging can be enabled by changing the "#if 0", but should be -// reverted prior to checking in. -#include <cstdio> -#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else -#define DEBUG_LOG(fmt, ...) -#endif - -// Enable extra mutex error checking -#if 0 // LLDB_CONFIGURATION_DEBUG -#define ENABLE_MUTEX_ERROR_CHECKING 1 -#include <inttypes.h> -#endif - -#if ENABLE_MUTEX_ERROR_CHECKING -#include <set> - -enum MutexAction -{ - eMutexActionInitialized, - eMutexActionDestroyed, - eMutexActionAssertInitialized -}; - -static bool -error_check_mutex (pthread_mutex_t *m, MutexAction action) -{ - typedef std::set<pthread_mutex_t *> mutex_set; - static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER; - static mutex_set g_initialized_mutex_set; - static mutex_set g_destroyed_mutex_set; - - bool success = true; - int err; - // Manually call lock so we don't to any of this error checking - err = ::pthread_mutex_lock (&g_mutex_set_mutex); - assert(err == 0); - switch (action) - { - case eMutexActionInitialized: - // Make sure this isn't already in our initialized mutex set... - assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end()); - // Remove this from the destroyed set in case it was ever in there - g_destroyed_mutex_set.erase(m); - // Add the mutex to the initialized set - g_initialized_mutex_set.insert(m); - break; - - case eMutexActionDestroyed: - // Make sure this isn't already in our destroyed mutex set... - assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end()); - // Remove this from the initialized so we can put it into the destroyed set - g_initialized_mutex_set.erase(m); - // Add the mutex to the destroyed set - g_destroyed_mutex_set.insert(m); - break; - case eMutexActionAssertInitialized: - // This function will return true if "m" is in the initialized mutex set - success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end(); - assert (success); - break; - } - // Manually call unlock so we don't to any of this error checking - err = ::pthread_mutex_unlock (&g_mutex_set_mutex); - assert(err == 0); - return success; -} - -#endif - -using namespace lldb_private; - -//---------------------------------------------------------------------- -// Default constructor. -// -// This will create a scoped mutex locking object that doesn't have -// a mutex to lock. One will need to be provided using the Reset() -// method. -//---------------------------------------------------------------------- -Mutex::Locker::Locker () : - m_mutex_ptr(NULL) -{ -} - -//---------------------------------------------------------------------- -// Constructor with a Mutex object. -// -// This will create a scoped mutex locking object that extracts the -// mutex owned by "m" and locks it. -//---------------------------------------------------------------------- -Mutex::Locker::Locker (Mutex& m) : - m_mutex_ptr(NULL) -{ - Lock (m); -} - -//---------------------------------------------------------------------- -// Constructor with a Mutex object pointer. -// -// This will create a scoped mutex locking object that extracts the -// mutex owned by "m" and locks it. -//---------------------------------------------------------------------- -Mutex::Locker::Locker (Mutex* m) : - m_mutex_ptr(NULL) -{ - if (m) - Lock (m); -} - -//---------------------------------------------------------------------- -// Destructor -// -// Unlocks any owned mutex object (if it is valid). -//---------------------------------------------------------------------- -Mutex::Locker::~Locker () -{ - Unlock(); -} - -//---------------------------------------------------------------------- -// Unlock the current mutex in this object (if this owns a valid -// mutex) and lock the new "mutex" object if it is non-NULL. -//---------------------------------------------------------------------- -void -Mutex::Locker::Lock (Mutex &mutex) -{ - // We already have this mutex locked or both are NULL... - if (m_mutex_ptr == &mutex) - return; - - Unlock (); - - m_mutex_ptr = &mutex; - m_mutex_ptr->Lock(); -} - -void -Mutex::Locker::Unlock () -{ - if (m_mutex_ptr) - { - m_mutex_ptr->Unlock (); - m_mutex_ptr = NULL; - } -} - -bool -Mutex::Locker::TryLock (Mutex &mutex, const char *failure_message) -{ - // We already have this mutex locked! - if (m_mutex_ptr == &mutex) - return true; - - Unlock (); - - if (mutex.TryLock(failure_message) == 0) - m_mutex_ptr = &mutex; - - return m_mutex_ptr != NULL; -} - -#ifndef _WIN32 - -//---------------------------------------------------------------------- -// Default constructor. -// -// Creates a pthread mutex with no attributes. -//---------------------------------------------------------------------- -Mutex::Mutex () : - m_mutex() -{ - int err; - err = ::pthread_mutex_init (&m_mutex, NULL); -#if ENABLE_MUTEX_ERROR_CHECKING - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionInitialized); -#endif - assert(err == 0); -} - -//---------------------------------------------------------------------- -// Default constructor. -// -// Creates a pthread mutex with "type" as the mutex type. -//---------------------------------------------------------------------- -Mutex::Mutex (Mutex::Type type) : - m_mutex() -{ - int err; - ::pthread_mutexattr_t attr; - err = ::pthread_mutexattr_init (&attr); - assert(err == 0); - switch (type) - { - case eMutexTypeNormal: -#if ENABLE_MUTEX_ERROR_CHECKING - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); -#else - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL); -#endif - break; - - case eMutexTypeRecursive: - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); - break; - } - assert(err == 0); - err = ::pthread_mutex_init (&m_mutex, &attr); -#if ENABLE_MUTEX_ERROR_CHECKING - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionInitialized); -#endif - assert(err == 0); - err = ::pthread_mutexattr_destroy (&attr); - assert(err == 0); -} - -//---------------------------------------------------------------------- -// Destructor. -// -// Destroys the mutex owned by this object. -//---------------------------------------------------------------------- -Mutex::~Mutex() -{ -#if ENABLE_MUTEX_ERROR_CHECKING - int err = ::pthread_mutex_destroy (&m_mutex); - assert(err == 0); - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionDestroyed); - else - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err)); - assert(err == 0); - } - memset (&m_mutex, '\xba', sizeof(m_mutex)); -#else - ::pthread_mutex_destroy (&m_mutex); -#endif -} - -//---------------------------------------------------------------------- -// Locks the mutex owned by this object, if the mutex is already -// locked, the calling thread will block until the mutex becomes -// available. -// -// RETURNS -// The error code from the pthread_mutex_lock() function call. -//---------------------------------------------------------------------- -int -Mutex::Lock() -{ - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex); - -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_lock (&m_mutex); - - -#if ENABLE_MUTEX_ERROR_CHECKING - if (err) - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); - assert(err == 0); - } -#endif - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -//---------------------------------------------------------------------- -// Attempts to lock the mutex owned by this object without blocking. -// If the mutex is already locked, TryLock() will not block waiting -// for the mutex, but will return an error condition. -// -// RETURNS -// The error code from the pthread_mutex_trylock() function call. -//---------------------------------------------------------------------- -int -Mutex::TryLock(const char *failure_message) -{ -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_trylock (&m_mutex); - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -//---------------------------------------------------------------------- -// If the current thread holds the lock on the owned mutex, then -// Unlock() will unlock the mutex. Calling Unlock() on this object -// that the calling thread does not hold will result in undefined -// behavior. -// -// RETURNS -// The error code from the pthread_mutex_unlock() function call. -//---------------------------------------------------------------------- -int -Mutex::Unlock() -{ -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_unlock (&m_mutex); - -#if ENABLE_MUTEX_ERROR_CHECKING - if (err) - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); - assert(err == 0); - } -#endif - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -#endif - -//---------------------------------------------------------------------- -// Mutex get accessor. -//---------------------------------------------------------------------- -lldb::mutex_t * -Mutex::GetMutex() -{ - return &m_mutex; -} - -#ifdef LLDB_CONFIGURATION_DEBUG -int -TrackingMutex::Unlock () -{ - if (!m_failure_message.empty()) - Host::SetCrashDescriptionWithFormat ("Unlocking lock (on thread %p) that thread: %p failed to get: %s", - pthread_self(), - m_thread_that_tried, - m_failure_message.c_str()); - assert (m_failure_message.empty()); - return Mutex::Unlock(); -} - -int -LoggingMutex::Lock () -{ - printf("locking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID()); - int x = Mutex::Lock(); - m_locked = true; - printf("%d\n",x); - return x; -} - -int -LoggingMutex::Unlock () -{ - printf("unlocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID()); - int x = Mutex::Unlock(); - m_locked = false; - printf("%d\n",x); - return x; -} - -int -LoggingMutex::TryLock (const char *failure_message) -{ - printf("trylocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID()); - int x = Mutex::TryLock(failure_message); - if (x == 0) - m_locked = true; - printf("%d\n",x); - return x; -} - -#endif - - diff --git a/source/Host/common/NativeBreakpoint.cpp b/source/Host/common/NativeBreakpoint.cpp index 622b4eab1726..d61a2f531ac3 100644 --- a/source/Host/common/NativeBreakpoint.cpp +++ b/source/Host/common/NativeBreakpoint.cpp @@ -9,108 +9,101 @@ #include "lldb/Host/common/NativeBreakpoint.h" -#include "lldb/lldb-defines.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" +#include "lldb/lldb-defines.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(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 () -{ -} +NativeBreakpoint::~NativeBreakpoint() {} -void -NativeBreakpoint::AddRef () -{ - ++m_ref_count; +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); + 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; +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); + 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; + 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 (); - } +Error NativeBreakpoint::Enable() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - // Log and enable. + if (m_enabled) { + // We're already enabled. Just log and exit. 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; -} + 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()); + } -Error -NativeBreakpoint::Disable () -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + return error; +} - 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 (); - } +Error NativeBreakpoint::Disable() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - // Log and disable. + if (!m_enabled) { + // We're already disabled. Just log and exit. 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; + 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/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp index 67873a06dd27..df5bce8079e0 100644 --- a/source/Host/common/NativeBreakpointList.cpp +++ b/source/Host/common/NativeBreakpointList.cpp @@ -17,204 +17,213 @@ using namespace lldb; using namespace lldb_private; -NativeBreakpointList::NativeBreakpointList() : m_mutex() -{ -} +NativeBreakpointList::NativeBreakpointList() : m_mutex() {} + +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 = %zu, hardware = %s", + __FUNCTION__, addr, size_hint, hardware ? "true" : "false"); + + std::lock_guard<std::recursive_mutex> guard(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); -Error -NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + 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 = %zu, 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 addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false"); + log->Printf( + "NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 + ", size_hint = %zu, hardware = %s -- FAILED: %s", + __FUNCTION__, addr, size_hint, hardware ? "true" : "false", + error.AsCString()); + return error; + } - std::lock_guard<std::recursive_mutex> guard(m_mutex); + // Remember the breakpoint. + assert(breakpoint_sp && "NativeBreakpoint create function succeeded but " + "returned NULL breakpoint"); + m_breakpoints.insert(BreakpointMap::value_type(addr, breakpoint_sp)); - // 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); + return error; +} - iter->second->AddRef (); - return Error (); - } +Error NativeBreakpointList::DecRef(lldb::addr_t addr) { + Error 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; - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, + addr); - // Remember the breakpoint. - assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint"); - m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp)); + std::lock_guard<std::recursive_mutex> guard(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; -} + } -Error -NativeBreakpointList::DecRef (lldb::addr_t addr) -{ - Error error; + // Decrement ref count. + const int32_t new_ref_count = iter->second->DecRef(); + assert(new_ref_count >= 0 && "NativeBreakpoint ref count went negative"); - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (new_ref_count > 0) { + // Still references to this breakpoint. Leave it alone. if (log) - log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - - std::lock_guard<std::recursive_mutex> guard(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"); + log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 + " -- new breakpoint ref count %" PRIu32, + __FUNCTION__, addr, new_ref_count); + return error; + } - 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); - // Breakpoint has no more references. Disable it if it's not - // already disabled. + // If it's enabled, we need to disable it. + if (iter->second->IsEnabled()) { 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); + 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. } - - // Take the breakpoint out of the list. + } else { if (log) - log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr); - - m_breakpoints.erase (iter); - return error; + 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); - - std::lock_guard<std::recursive_mutex> guard(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"); - } +Error NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, + addr); - // Enable it. - return iter->second->Enable (); -} + std::lock_guard<std::recursive_mutex> guard(m_mutex); -Error -NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr) -{ - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + // 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, __FUNCTION__, addr); - - std::lock_guard<std::recursive_mutex> guard(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"); - } + log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", + __FUNCTION__, addr); + return Error("breakpoint not found"); + } - // Disable it. - return iter->second->Disable (); + // Enable it. + return iter->second->Enable(); } -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); +Error NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, + addr); - std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> guard(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"); - } + // 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. - breakpoint_sp = iter->second; - return Error (); + // Disable it. + return iter->second->Disable(); } -Error -NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const -{ - for (const auto &map : m_breakpoints) - { - lldb::addr_t bp_addr = map.first; - // Breapoint not in range, ignore - if (bp_addr < addr || addr + size <= bp_addr) - continue; - const auto &bp_sp = map.second; - // Not software breakpoint, ignore - if (!bp_sp->IsSoftwareBreakpoint()) - continue; - auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp); - auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr; - auto saved_opcodes = software_bp_sp->m_saved_opcodes; - auto opcode_size = software_bp_sp->m_opcode_size; - ::memcpy(opcode_addr, saved_opcodes, opcode_size); - } - return Error(); +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); + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + // Ensure we have said breakpoint. + auto iter = m_breakpoints.find(addr); + if (iter == m_breakpoints.end()) { + // Not found! + breakpoint_sp.reset(); + return Error("breakpoint not found"); + } + + // Disable it. + breakpoint_sp = iter->second; + return Error(); +} + +Error NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, + size_t size) const { + for (const auto &map : m_breakpoints) { + lldb::addr_t bp_addr = map.first; + // Breapoint not in range, ignore + if (bp_addr < addr || addr + size <= bp_addr) + continue; + const auto &bp_sp = map.second; + // Not software breakpoint, ignore + if (!bp_sp->IsSoftwareBreakpoint()) + continue; + auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp); + auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr; + auto saved_opcodes = software_bp_sp->m_saved_opcodes; + auto opcode_size = software_bp_sp->m_opcode_size; + ::memcpy(opcode_addr, saved_opcodes, opcode_size); + } + return Error(); } diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp index dfac0cb5645c..d77b8b2e9746 100644 --- a/source/Host/common/NativeProcessProtocol.cpp +++ b/source/Host/common/NativeProcessProtocol.cpp @@ -9,15 +9,18 @@ #include "lldb/Host/common/NativeProcessProtocol.h" -#include "lldb/lldb-enumerations.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Log.h" +#include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/common/NativeRegisterContext.h" - #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/Host/common/SoftwareBreakpoint.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/lldb-enumerations.h" using namespace lldb; using namespace lldb_private; @@ -27,435 +30,403 @@ using namespace lldb_private; // ----------------------------------------------------------------------------- NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid) - : m_pid(pid), - m_threads(), - m_current_thread_id(LLDB_INVALID_THREAD_ID), - m_threads_mutex(), - m_state(lldb::eStateInvalid), - m_state_mutex(), - m_exit_type(eExitTypeInvalid), - m_exit_status(0), - m_exit_description(), - m_delegates_mutex(), - m_delegates(), - m_breakpoint_list(), - m_watchpoint_list(), - m_terminal_fd(-1), - m_stop_id(0) -{ -} - -lldb_private::Error -NativeProcessProtocol::Interrupt () -{ - Error error; -#if !defined (SIGSTOP) - error.SetErrorString ("local host does not support signaling"); - return error; + : m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID), + m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(), + m_exit_type(eExitTypeInvalid), m_exit_status(0), m_exit_description(), + m_delegates_mutex(), m_delegates(), m_breakpoint_list(), + m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {} + +lldb_private::Error NativeProcessProtocol::Interrupt() { + Error error; +#if !defined(SIGSTOP) + error.SetErrorString("local host does not support signaling"); + return error; #else - return Signal (SIGSTOP); + return Signal(SIGSTOP); #endif } lldb_private::Error -NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) -{ - // Default: not implemented. - return Error ("not implemented"); +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; - } +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; + *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, +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; - } + // 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_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(); + 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); + if (bNotifyStateChange) + SynchronouslyNotifyProcessStateChanged(lldb::eStateExited); - return true; + return true; } -NativeThreadProtocolSP -NativeProcessProtocol::GetThreadAtIndex (uint32_t idx) -{ - std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); - if (idx < m_threads.size ()) - return m_threads[idx]; - return NativeThreadProtocolSP (); +NativeThreadProtocolSP NativeProcessProtocol::GetThreadAtIndex(uint32_t idx) { + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + if (idx < m_threads.size()) + return m_threads[idx]; + return NativeThreadProtocolSP(); } NativeThreadProtocolSP -NativeProcessProtocol::GetThreadByIDUnlocked (lldb::tid_t tid) -{ - for (auto thread_sp : m_threads) - { - if (thread_sp->GetID() == tid) - return thread_sp; - } - return NativeThreadProtocolSP (); +NativeProcessProtocol::GetThreadByIDUnlocked(lldb::tid_t tid) { + for (auto thread_sp : m_threads) { + if (thread_sp->GetID() == tid) + return thread_sp; + } + return NativeThreadProtocolSP(); } -NativeThreadProtocolSP -NativeProcessProtocol::GetThreadByID (lldb::tid_t tid) -{ - std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); - return GetThreadByIDUnlocked (tid); +NativeThreadProtocolSP NativeProcessProtocol::GetThreadByID(lldb::tid_t tid) { + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + return GetThreadByIDUnlocked(tid); } -bool -NativeProcessProtocol::IsAlive () const -{ - return m_state != eStateDetached - && m_state != eStateExited - && m_state != eStateInvalid - && m_state != eStateUnloaded; +bool NativeProcessProtocol::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; +bool NativeProcessProtocol::GetByteOrder(lldb::ByteOrder &byte_order) const { + ArchSpec process_arch; + if (!GetArchitecture(process_arch)) + return false; + byte_order = process_arch.GetByteOrder(); + return true; } -const NativeWatchpointList::WatchpointMap& -NativeProcessProtocol::GetWatchpointMap () const -{ - return m_watchpoint_list.GetWatchpointMap(); +const NativeWatchpointList::WatchpointMap & +NativeProcessProtocol::GetWatchpointMap() const { + return m_watchpoint_list.GetWatchpointMap(); } -uint32_t -NativeProcessProtocol::GetMaxWatchpoints () const -{ - // This default implementation will return the number of - // *hardware* breakpoints available. MacOSX and other OS - // implementations that support software breakpoints will want to - // override this correctly for their implementation. - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - - // get any thread - NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0)); - if (!thread_sp) - { - if (log) - log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__); - return 0; - } +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; + } - NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ()); - if (!reg_ctx_sp) - { + return reg_ctx_sp->NumSupportedHardwareWatchpoints(); +} + +Error NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, + bool hardware) { + // This default implementation assumes setting the watchpoint for + // the process will require setting the watchpoint for each of the + // threads. Furthermore, it will track watchpoints set for the + // process and will add them to each thread that is attached to + // via the (FIXME implement) OnThreadAttached () method. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Update the thread list + UpdateThreads(); + + // Keep track of the threads we successfully set the watchpoint + // for. If one of the thread watchpoint setting operations fails, + // back off and remove the watchpoint for all the threads that + // were successfully set so we get back to a consistent state. + std::vector<NativeThreadProtocolSP> watchpoint_established_threads; + + // Tell each thread to set a watchpoint. In the event that + // hardware watchpoints are requested but the SetWatchpoint fails, + // try to set a software watchpoint as a fallback. It's + // conceivable that if there are more threads than hardware + // watchpoints available, some of the threads will fail to set + // hardware watchpoints while software ones may be available. + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + for (auto thread_sp : m_threads) { + assert(thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + Error thread_error = + thread_sp->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 ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__); - return 0; + log->Warning( + "hardware watchpoint requested but software watchpoint set"); + } } - return reg_ctx_sp->NumSupportedHardwareWatchpoints (); -} - -Error -NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) -{ - // This default implementation assumes setting the watchpoint for - // the process will require setting the watchpoint for each of the - // threads. Furthermore, it will track watchpoints set for the - // process and will add them to each thread that is attached to - // via the (FIXME implement) OnThreadAttached () method. - - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - - // Update the thread list - UpdateThreads (); - - // Keep track of the threads we successfully set the watchpoint - // for. If one of the thread watchpoint setting operations fails, - // back off and remove the watchpoint for all the threads that - // were successfully set so we get back to a consistent state. - std::vector<NativeThreadProtocolSP> watchpoint_established_threads; - - // Tell each thread to set a watchpoint. In the event that - // hardware watchpoints are requested but the SetWatchpoint fails, - // try to set a software watchpoint as a fallback. It's - // conceivable that if there are more threads than hardware - // watchpoints available, some of the threads will fail to set - // hardware watchpoints while software ones may be available. - std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); - for (auto thread_sp : m_threads) - { - assert (thread_sp && "thread list should not have a NULL thread!"); - if (!thread_sp) - continue; - - Error thread_error = thread_sp->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()); } + } - 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 thread_error; } - return m_watchpoint_list.Add (addr, size, watch_flags, hardware); + } + return m_watchpoint_list.Add(addr, size, watch_flags, hardware); } -Error -NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) -{ - // Update the thread list - UpdateThreads (); - - Error overall_error; - - std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); - for (auto thread_sp : m_threads) - { - assert (thread_sp && "thread list should not have a NULL thread!"); - if (!thread_sp) - continue; - - const Error thread_error = thread_sp->RemoveWatchpoint (addr); - if (thread_error.Fail ()) - { - // Keep track of the first thread error if any threads - // fail. We want to try to remove the watchpoint from - // every thread, though, even if one or more have errors. - if (!overall_error.Fail ()) - overall_error = thread_error; - } - } - const Error error = m_watchpoint_list.Remove(addr); - return overall_error.Fail() ? overall_error : error; -} +Error NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) { + // Update the thread list + UpdateThreads(); -bool -NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate) -{ - std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); - if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ()) - return false; + Error overall_error; - m_delegates.push_back (&native_delegate); - native_delegate.InitializeDelegate (this); - return true; + std::lock_guard<std::recursive_mutex> guard(m_threads_mutex); + for (auto thread_sp : m_threads) { + assert(thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + const Error thread_error = thread_sp->RemoveWatchpoint(addr); + if (thread_error.Fail()) { + // Keep track of the first thread error if any threads + // fail. We want to try to remove the watchpoint from + // every thread, though, even if one or more have errors. + if (!overall_error.Fail()) + overall_error = thread_error; + } + } + const Error error = m_watchpoint_list.Remove(addr); + return overall_error.Fail() ? overall_error : error; } -bool -NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate) -{ - std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); - - const auto initial_size = m_delegates.size (); - m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ()); +bool NativeProcessProtocol::RegisterNativeDelegate( + NativeDelegate &native_delegate) { + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); + if (std::find(m_delegates.begin(), m_delegates.end(), &native_delegate) != + m_delegates.end()) + return false; - // 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; + m_delegates.push_back(&native_delegate); + native_delegate.InitializeDelegate(this); + return true; } -void -NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state) -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +bool NativeProcessProtocol::UnregisterNativeDelegate( + NativeDelegate &native_delegate) { + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); - std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); - for (auto native_delegate: m_delegates) - native_delegate->ProcessStateChanged (this, state); + const auto initial_size = m_delegates.size(); + m_delegates.erase( + remove(m_delegates.begin(), m_delegates.end(), &native_delegate), + m_delegates.end()); - 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 ()); - } - } + // 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::NotifyDidExec () -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__); - - { - std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); - for (auto native_delegate: m_delegates) - native_delegate->DidExec (this); +void NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged( + lldb::StateType state) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + std::lock_guard<std::recursive_mutex> guard(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__); -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); + { + std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex); + for (auto native_delegate : m_delegates) + native_delegate->DidExec(this); + } +} - 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::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::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::EnableBreakpoint(lldb::addr_t addr) { + return m_breakpoint_list.EnableBreakpoint(addr); } -Error -NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr) -{ - return m_breakpoint_list.DisableBreakpoint (addr); +Error NativeProcessProtocol::DisableBreakpoint(lldb::addr_t addr) { + return m_breakpoint_list.DisableBreakpoint(addr); } -lldb::StateType -NativeProcessProtocol::GetState () const -{ - std::lock_guard<std::recursive_mutex> guard(m_state_mutex); - return m_state; +lldb::StateType NativeProcessProtocol::GetState() const { + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); + return m_state; } -void -NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) -{ - std::lock_guard<std::recursive_mutex> guard(m_state_mutex); +void NativeProcessProtocol::SetState(lldb::StateType state, + bool notify_delegates) { + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); - if (state == m_state) - return; + if (state == m_state) + return; - m_state = state; + m_state = state; - if (StateIsStoppedState (state, false)) - { - ++m_stop_id; + 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); - } + // 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); +} - // Optionally notify delegates of the state change. - if (notify_delegates) - SynchronouslyNotifyProcessStateChanged (state); +uint32_t NativeProcessProtocol::GetStopID() const { + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); + return m_stop_id; } -uint32_t NativeProcessProtocol::GetStopID () const -{ - std::lock_guard<std::recursive_mutex> guard(m_state_mutex); - return m_stop_id; +void NativeProcessProtocol::DoStopIDBumped(uint32_t /* newBumpId */) { + // Default implementation does nothing. } -void -NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */) -{ - // Default implementation does nothing. +Error NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid, + ArchSpec &arch) { + // Grab process info for the running process. + ProcessInstanceInfo process_info; + if (!Host::GetProcessInfo(pid, process_info)) + return Error("failed to get process info"); + + // Resolve the executable module. + ModuleSpecList module_specs; + if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(), 0, + 0, module_specs)) + return Error("failed to get module specifications"); + lldbassert(module_specs.GetSize() == 1); + + arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture(); + if (arch.IsValid()) + return Error(); + else + return Error("failed to retrieve a valid architecture from the exe module"); } #ifndef __linux__ -// These need to be implemented to support lldb-gdb-server on a given platform. Stubs are +// These need to be implemented to support lldb-gdb-server on a given platform. +// Stubs are // provided to make the rest of the code link on non-supported platforms. -Error -NativeProcessProtocol::Launch (ProcessLaunchInfo &launch_info, - NativeDelegate &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp) -{ - llvm_unreachable("Platform has no NativeProcessProtocol support"); +Error NativeProcessProtocol::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + MainLoop &mainloop, + NativeProcessProtocolSP &process_sp) { + llvm_unreachable("Platform has no NativeProcessProtocol support"); } -Error -NativeProcessProtocol::Attach (lldb::pid_t pid, - NativeDelegate &native_delegate, - MainLoop &mainloop, - NativeProcessProtocolSP &process_sp) -{ - llvm_unreachable("Platform has no NativeProcessProtocol support"); +Error NativeProcessProtocol::Attach(lldb::pid_t pid, + NativeDelegate &native_delegate, + MainLoop &mainloop, + NativeProcessProtocolSP &process_sp) { + llvm_unreachable("Platform has no NativeProcessProtocol support"); } #endif diff --git a/source/Host/common/NativeRegisterContext.cpp b/source/Host/common/NativeRegisterContext.cpp index e67c07964a48..73b2629c57c1 100644 --- a/source/Host/common/NativeRegisterContext.cpp +++ b/source/Host/common/NativeRegisterContext.cpp @@ -12,24 +12,21 @@ #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Host/PosixApi.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" using namespace lldb; using namespace lldb_private; -NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) : - m_thread (thread), - m_concrete_frame_idx (concrete_frame_idx) -{ -} +NativeRegisterContext::NativeRegisterContext(NativeThreadProtocol &thread, + uint32_t concrete_frame_idx) + : m_thread(thread), m_concrete_frame_idx(concrete_frame_idx) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -NativeRegisterContext::~NativeRegisterContext() -{ -} +NativeRegisterContext::~NativeRegisterContext() {} // FIXME revisit invalidation, process stop ids, etc. Right now we don't // support caching in NativeRegisterContext. We can do this later by @@ -58,459 +55,383 @@ NativeRegisterContext::~NativeRegisterContext() // } // } - const RegisterInfo * -NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx) -{ - if (reg_name && reg_name[0]) - { - const uint32_t num_registers = GetRegisterCount(); - for (uint32_t reg = start_idx; reg < num_registers; ++reg) - { - const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); - - if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) || - (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0)) - { - return reg_info; - } - } - } +NativeRegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, + uint32_t start_idx) { + if (reg_name.empty()) return nullptr; -} -const RegisterInfo * -NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num) -{ - const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); - if (reg_num == LLDB_INVALID_REGNUM) - return nullptr; - return GetRegisterInfoAtIndex (reg_num); + const uint32_t num_registers = GetRegisterCount(); + for (uint32_t reg = start_idx; reg < num_registers; ++reg) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + + if (reg_name.equals_lower(reg_info->name) || + reg_name.equals_lower(reg_info->alt_name)) + return reg_info; + } + return nullptr; } -const char * -NativeRegisterContext::GetRegisterName (uint32_t reg) -{ - const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info) - return reg_info->name; +const RegisterInfo *NativeRegisterContext::GetRegisterInfo(uint32_t kind, + uint32_t num) { + const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); + if (reg_num == LLDB_INVALID_REGNUM) return nullptr; + return GetRegisterInfoAtIndex(reg_num); } -const char* -NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const -{ - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - if (!reg_info) - return nullptr; - - for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index) - { - const RegisterSet *const reg_set = GetRegisterSet (set_index); - if (!reg_set) - continue; - - for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index) - { - const uint32_t reg_num = reg_set->registers[reg_num_index]; - // FIXME double check we're checking the right register kind here. - if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) - { - // The given register is a member of this register set. Return the register set name. - return reg_set->name; - } - } - } +const char *NativeRegisterContext::GetRegisterName(uint32_t reg) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info) + return reg_info->name; + return nullptr; +} - // Didn't find it. +const char *NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex( + uint32_t reg_index) const { + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + if (!reg_info) return nullptr; + + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) { + const RegisterSet *const reg_set = GetRegisterSet(set_index); + if (!reg_set) + continue; + + for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; + ++reg_num_index) { + const uint32_t reg_num = reg_set->registers[reg_num_index]; + // FIXME double check we're checking the right register kind here. + if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) { + // The given register is a member of this register set. Return the + // register set name. + return reg_set->name; + } + } + } + + // Didn't find it. + return nullptr; } -lldb::addr_t -NativeRegisterContext::GetPC (lldb::addr_t fail_value) -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); +lldb::addr_t NativeRegisterContext::GetPC(lldb::addr_t fail_value) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - if (log) - log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value); + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); + if (log) + log->Printf("NativeRegisterContext::%s using reg index %" PRIu32 + " (default %" PRIu64 ")", + __FUNCTION__, reg, fail_value); - const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value); + const uint64_t retval = ReadRegisterAsUnsigned(reg, fail_value); - if (log) - log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval); + if (log) + log->Printf("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, + __FUNCTION__, retval); - return retval; + return retval; } lldb::addr_t -NativeRegisterContext::GetPCfromBreakpointLocation (lldb::addr_t fail_value) -{ - return GetPC (fail_value); +NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) { + return GetPC(fail_value); } -Error -NativeRegisterContext::SetPC (lldb::addr_t pc) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - return WriteRegisterFromUnsigned (reg, pc); +Error NativeRegisterContext::SetPC(lldb::addr_t pc) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); + return WriteRegisterFromUnsigned(reg, pc); } -lldb::addr_t -NativeRegisterContext::GetSP (lldb::addr_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - return ReadRegisterAsUnsigned (reg, fail_value); +lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP); + return ReadRegisterAsUnsigned(reg, fail_value); } -Error -NativeRegisterContext::SetSP (lldb::addr_t sp) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - return WriteRegisterFromUnsigned (reg, sp); +Error NativeRegisterContext::SetSP(lldb::addr_t sp) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP); + return WriteRegisterFromUnsigned(reg, sp); } -lldb::addr_t -NativeRegisterContext::GetFP (lldb::addr_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); - return ReadRegisterAsUnsigned (reg, fail_value); +lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FP); + return ReadRegisterAsUnsigned(reg, fail_value); } -Error -NativeRegisterContext::SetFP (lldb::addr_t fp) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); - return WriteRegisterFromUnsigned (reg, fp); +Error NativeRegisterContext::SetFP(lldb::addr_t fp) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FP); + return WriteRegisterFromUnsigned(reg, fp); } -lldb::addr_t -NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); - return ReadRegisterAsUnsigned (reg, fail_value); +lldb::addr_t NativeRegisterContext::GetReturnAddress(lldb::addr_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return ReadRegisterAsUnsigned(reg, fail_value); } -lldb::addr_t -NativeRegisterContext::GetFlags (lldb::addr_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - return ReadRegisterAsUnsigned (reg, fail_value); +lldb::addr_t NativeRegisterContext::GetFlags(lldb::addr_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FLAGS); + return ReadRegisterAsUnsigned(reg, fail_value); } - lldb::addr_t -NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value) -{ - if (reg != LLDB_INVALID_REGNUM) - return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value); - return fail_value; +NativeRegisterContext::ReadRegisterAsUnsigned(uint32_t reg, + lldb::addr_t fail_value) { + if (reg != LLDB_INVALID_REGNUM) + return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value); + return fail_value; } uint64_t -NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value) -{ - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - - if (reg_info) - { - RegisterValue value; - Error error = ReadRegister (reg_info, value); - if (error.Success ()) - { - if (log) - log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64()); - return value.GetAsUInt64(); - } - else - { - if (log) - log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ()); - } - } - else - { - if (log) - log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__); +NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info, + lldb::addr_t fail_value) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + + if (reg_info) { + RegisterValue value; + Error error = ReadRegister(reg_info, value); + if (error.Success()) { + if (log) + log->Printf("NativeRegisterContext::%s ReadRegister() succeeded, value " + "%" PRIu64, + __FUNCTION__, value.GetAsUInt64()); + return value.GetAsUInt64(); + } else { + if (log) + log->Printf("NativeRegisterContext::%s ReadRegister() failed, error %s", + __FUNCTION__, error.AsCString()); } - return fail_value; + } else { + if (log) + log->Printf("NativeRegisterContext::%s ReadRegister() null reg_info", + __FUNCTION__); + } + return fail_value; } -Error -NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval) -{ - if (reg == LLDB_INVALID_REGNUM) - return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__); - return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval); +Error NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg, + uint64_t uval) { + if (reg == LLDB_INVALID_REGNUM) + return Error("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__); + return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval); } -Error -NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval) -{ - assert (reg_info); - if (!reg_info) - return Error ("reg_info is nullptr"); +Error NativeRegisterContext::WriteRegisterFromUnsigned( + const RegisterInfo *reg_info, uint64_t uval) { + assert(reg_info); + if (!reg_info) + return Error("reg_info is nullptr"); - RegisterValue value; - if (!value.SetUInt(uval, reg_info->byte_size)) - return Error ("RegisterValue::SetUInt () failed"); + RegisterValue value; + if (!value.SetUInt(uval, reg_info->byte_size)) + return Error("RegisterValue::SetUInt () failed"); - return WriteRegister (reg_info, value); + return WriteRegister(reg_info, value); } -lldb::tid_t -NativeRegisterContext::GetThreadID() const -{ - return m_thread.GetID(); +lldb::tid_t NativeRegisterContext::GetThreadID() const { + return m_thread.GetID(); } -uint32_t -NativeRegisterContext::NumSupportedHardwareBreakpoints () -{ - return 0; -} +uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints() { return 0; } -uint32_t -NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) -{ - return LLDB_INVALID_INDEX32; +uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + return LLDB_INVALID_INDEX32; } -bool -NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx) -{ - return false; +bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { + return false; } +uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; } -uint32_t -NativeRegisterContext::NumSupportedHardwareWatchpoints () -{ - return 0; +uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, + size_t size, + uint32_t watch_flags) { + return LLDB_INVALID_INDEX32; } -uint32_t -NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) -{ - return LLDB_INVALID_INDEX32; +bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) { + return false; } -bool -NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) -{ - return false; +Error NativeRegisterContext::ClearAllHardwareWatchpoints() { + return Error("not implemented"); } -Error -NativeRegisterContext::ClearAllHardwareWatchpoints () -{ - return Error ("not implemented"); +Error NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { + is_hit = false; + return Error("not implemented"); } -Error -NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) -{ - is_hit = false; - return Error ("not implemented"); +Error NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) { + wp_index = LLDB_INVALID_INDEX32; + return Error("not implemented"); } -Error -NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) -{ - wp_index = LLDB_INVALID_INDEX32; - return Error ("not implemented"); +Error NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index, + bool &is_vacant) { + is_vacant = false; + return Error("not implemented"); } -Error -NativeRegisterContext::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) -{ - is_vacant = false; - return Error ("not implemented"); +lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) { + return LLDB_INVALID_ADDRESS; } -lldb::addr_t -NativeRegisterContext::GetWatchpointAddress (uint32_t wp_index) -{ - return LLDB_INVALID_ADDRESS; +lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) { + return LLDB_INVALID_ADDRESS; } -lldb::addr_t -NativeRegisterContext::GetWatchpointHitAddress (uint32_t wp_index) -{ - return LLDB_INVALID_ADDRESS; -} +bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; } -bool -NativeRegisterContext::HardwareSingleStep (bool enable) -{ - return false; -} +Error NativeRegisterContext::ReadRegisterValueFromMemory( + const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len, + RegisterValue ®_value) { + Error error; + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return error; + } + + // Moving from addr into a register + // + // Case 1: src_len == dst_len + // + // |AABBCCDD| Address contents + // |AABBCCDD| Register contents + // + // Case 2: src_len > dst_len + // + // Error! (The register should always be big enough to hold the data) + // + // Case 3: src_len < dst_len + // + // |AABB| Address contents + // |AABB0000| Register contents [on little-endian hardware] + // |0000AABB| Register contents [on big-endian hardware] + if (src_len > RegisterValue::kMaxRegisterByteSize) { + error.SetErrorString("register too small to receive memory data"); + return error; + } -Error -NativeRegisterContext::ReadRegisterValueFromMemory ( - const RegisterInfo *reg_info, - lldb::addr_t src_addr, - size_t src_len, - RegisterValue ®_value) -{ - Error error; - if (reg_info == nullptr) - { - error.SetErrorString ("invalid register info argument."); - return error; - } + const size_t dst_len = reg_info->byte_size; + if (src_len > dst_len) { + error.SetErrorStringWithFormat( + "%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 + " bytes)", + static_cast<uint64_t>(src_len), reg_info->name, + static_cast<uint64_t>(dst_len)); + return error; + } - // Moving from addr into a register - // - // Case 1: src_len == dst_len - // - // |AABBCCDD| Address contents - // |AABBCCDD| Register contents - // - // Case 2: src_len > dst_len - // - // Error! (The register should always be big enough to hold the data) - // - // Case 3: src_len < dst_len - // - // |AABB| Address contents - // |AABB0000| Register contents [on little-endian hardware] - // |0000AABB| Register contents [on big-endian hardware] - if (src_len > RegisterValue::kMaxRegisterByteSize) - { - error.SetErrorString ("register too small to receive memory data"); - return error; - } + NativeProcessProtocolSP process_sp(m_thread.GetProcess()); + if (!process_sp) { + error.SetErrorString("invalid process"); + return error; + } - const size_t dst_len = reg_info->byte_size; + uint8_t src[RegisterValue::kMaxRegisterByteSize]; - if (src_len > dst_len) - { - error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", - static_cast<uint64_t>(src_len), reg_info->name, static_cast<uint64_t>(dst_len)); - return error; - } + // Read the memory + size_t bytes_read; + error = process_sp->ReadMemory(src_addr, src, src_len, bytes_read); + if (error.Fail()) + return error; - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (!process_sp) - { - error.SetErrorString("invalid process"); - return error; - } + // Make sure the memory read succeeded... + if (bytes_read != src_len) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", + static_cast<uint64_t>(bytes_read), + static_cast<uint64_t>(src_len)); + return error; + } + + // We now have a memory buffer that contains the part or all of the register + // value. Set the register value using this memory data. + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are assuming + // they are the same. + lldb::ByteOrder byte_order; + if (!process_sp->GetByteOrder(byte_order)) { + error.SetErrorString("NativeProcessProtocol::GetByteOrder () failed"); + return error; + } - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Read the memory - size_t bytes_read; - error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read); - if (error.Fail ()) - return error; - - // Make sure the memory read succeeded... - if (bytes_read != src_len) - { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", - static_cast<uint64_t>(bytes_read), static_cast<uint64_t>(src_len)); - return error; - } + reg_value.SetFromMemoryData(reg_info, src, src_len, byte_order, error); - // We now have a memory buffer that contains the part or all of the register - // value. Set the register value using this memory data. - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are assuming - // they are the same. - lldb::ByteOrder byte_order; - if (!process_sp->GetByteOrder (byte_order)) - { - error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed"); - return error; - } + return error; +} - reg_value.SetFromMemoryData ( - reg_info, - src, - src_len, - byte_order, - error); +Error NativeRegisterContext::WriteRegisterValueToMemory( + const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len, + const RegisterValue ®_value) { - return error; -} + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + Error error; -Error -NativeRegisterContext::WriteRegisterValueToMemory ( - const RegisterInfo *reg_info, - lldb::addr_t dst_addr, - size_t dst_len, - const RegisterValue ®_value) -{ - - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - Error error; - - NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); - if (process_sp) - { - - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are assuming - // they are the same. - lldb::ByteOrder byte_order; - if (!process_sp->GetByteOrder (byte_order)) - return Error ("NativeProcessProtocol::GetByteOrder () failed"); - - const size_t bytes_copied = reg_value.GetAsMemoryData ( - reg_info, - dst, - dst_len, - byte_order, - error); - - if (error.Success()) - { - if (bytes_copied == 0) - { - error.SetErrorString("byte copy failed."); - } - else - { - size_t bytes_written; - error = process_sp->WriteMemory(dst_addr, dst, bytes_copied, bytes_written); - if (error.Fail ()) - return error; - - if (bytes_written != bytes_copied) - { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", - static_cast<uint64_t>(bytes_written), static_cast<uint64_t>(bytes_copied)); - } - } + NativeProcessProtocolSP process_sp(m_thread.GetProcess()); + if (process_sp) { + + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are + // assuming + // they are the same. + lldb::ByteOrder byte_order; + if (!process_sp->GetByteOrder(byte_order)) + return Error("NativeProcessProtocol::GetByteOrder () failed"); + + const size_t bytes_copied = + reg_value.GetAsMemoryData(reg_info, dst, dst_len, byte_order, error); + + if (error.Success()) { + if (bytes_copied == 0) { + error.SetErrorString("byte copy failed."); + } else { + size_t bytes_written; + error = + process_sp->WriteMemory(dst_addr, dst, bytes_copied, bytes_written); + if (error.Fail()) + return error; + + if (bytes_written != bytes_copied) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 + " bytes", + static_cast<uint64_t>(bytes_written), + static_cast<uint64_t>(bytes_copied)); } + } } - else - error.SetErrorString("invalid process"); + } else + error.SetErrorString("invalid process"); - return error; + return error; } uint32_t -NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const -{ - const uint32_t num_regs = GetRegisterCount(); +NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) const { + const uint32_t num_regs = GetRegisterCount(); - assert (kind < kNumRegisterKinds); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) - { - const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx); + assert(kind < kNumRegisterKinds); + for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx); - if (reg_info->kinds[kind] == num) - return reg_idx; - } + if (reg_info->kinds[kind] == num) + return reg_idx; + } - return LLDB_INVALID_REGNUM; + return LLDB_INVALID_REGNUM; } - - diff --git a/source/Host/common/NativeRegisterContextRegisterInfo.cpp b/source/Host/common/NativeRegisterContextRegisterInfo.cpp index 0d7c6eced757..5ff596b57693 100644 --- a/source/Host/common/NativeRegisterContextRegisterInfo.cpp +++ b/source/Host/common/NativeRegisterContextRegisterInfo.cpp @@ -1,4 +1,4 @@ -//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===// +//===-- NativeRegisterContextRegisterInfo.cpp -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,44 +7,37 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-types.h" -#include "lldb/lldb-private-forward.h" #include "lldb/Host/common/NativeRegisterContextRegisterInfo.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" using namespace lldb_private; -NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread, - uint32_t concrete_frame_idx, - RegisterInfoInterface *register_info_interface) : - NativeRegisterContext (thread, concrete_frame_idx), - m_register_info_interface_up (register_info_interface) -{ - assert (register_info_interface && "null register_info_interface"); +NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo( + NativeThreadProtocol &thread, uint32_t concrete_frame_idx, + RegisterInfoInterface *register_info_interface) + : NativeRegisterContext(thread, concrete_frame_idx), + m_register_info_interface_up(register_info_interface) { + assert(register_info_interface && "null register_info_interface"); } -uint32_t -NativeRegisterContextRegisterInfo::GetRegisterCount () const -{ - return m_register_info_interface_up->GetRegisterCount (); +uint32_t NativeRegisterContextRegisterInfo::GetRegisterCount() const { + return m_register_info_interface_up->GetRegisterCount(); } -uint32_t -NativeRegisterContextRegisterInfo::GetUserRegisterCount () const -{ - return m_register_info_interface_up->GetUserRegisterCount (); +uint32_t NativeRegisterContextRegisterInfo::GetUserRegisterCount() const { + return m_register_info_interface_up->GetUserRegisterCount(); } -const RegisterInfo * -NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const -{ - if (reg_index <= GetRegisterCount ()) - return m_register_info_interface_up->GetRegisterInfo () + reg_index; - else - return nullptr; +const RegisterInfo *NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex( + uint32_t reg_index) const { + if (reg_index <= GetRegisterCount()) + return m_register_info_interface_up->GetRegisterInfo() + reg_index; + else + return nullptr; } -const RegisterInfoInterface& -NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const -{ - return *m_register_info_interface_up; +const RegisterInfoInterface & +NativeRegisterContextRegisterInfo::GetRegisterInfoInterface() const { + return *m_register_info_interface_up; } diff --git a/source/Host/common/NativeThreadProtocol.cpp b/source/Host/common/NativeThreadProtocol.cpp index ea406e9ef2c6..2e76cff0d670 100644 --- a/source/Host/common/NativeThreadProtocol.cpp +++ b/source/Host/common/NativeThreadProtocol.cpp @@ -16,60 +16,53 @@ 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) -{ -} +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 ®_value) -{ - NativeRegisterContextSP register_context_sp = GetRegisterContext (); - if (!register_context_sp) - return Error ("no register context"); +Error NativeThreadProtocol::ReadRegister(uint32_t reg, + RegisterValue ®_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); + 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);; + return register_context_sp->ReadRegister(reg_info, reg_value); + ; } -Error -NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue ®_value) -{ - NativeRegisterContextSP register_context_sp = GetRegisterContext (); - if (!register_context_sp) - return Error ("no register context"); +Error NativeThreadProtocol::WriteRegister(uint32_t reg, + const RegisterValue ®_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); + 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); + 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::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); +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 (); +NativeProcessProtocolSP NativeThreadProtocol::GetProcess() { + return m_process_wp.lock(); } diff --git a/source/Host/common/NativeWatchpointList.cpp b/source/Host/common/NativeWatchpointList.cpp index 209d213b8e50..5948adf3c8d1 100644 --- a/source/Host/common/NativeWatchpointList.cpp +++ b/source/Host/common/NativeWatchpointList.cpp @@ -14,22 +14,18 @@ using namespace lldb; using namespace lldb_private; -Error -NativeWatchpointList::Add (addr_t addr, size_t size, uint32_t watch_flags, bool hardware) -{ - m_watchpoints[addr] = {addr, size, watch_flags, hardware}; - return Error (); +Error NativeWatchpointList::Add(addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) { + m_watchpoints[addr] = {addr, size, watch_flags, hardware}; + return Error(); } -Error -NativeWatchpointList::Remove (addr_t addr) -{ - m_watchpoints.erase(addr); - return Error (); +Error NativeWatchpointList::Remove(addr_t addr) { + m_watchpoints.erase(addr); + return Error(); } -const NativeWatchpointList::WatchpointMap& -NativeWatchpointList::GetWatchpointMap () const -{ - return m_watchpoints; +const NativeWatchpointList::WatchpointMap & +NativeWatchpointList::GetWatchpointMap() const { + return m_watchpoints; } diff --git a/source/Host/common/OptionParser.cpp b/source/Host/common/OptionParser.cpp index 16a29a1583d5..d78bf335b408 100644 --- a/source/Host/common/OptionParser.cpp +++ b/source/Host/common/OptionParser.cpp @@ -15,102 +15,68 @@ using namespace lldb_private; -void -OptionParser::Prepare(std::unique_lock<std::mutex> &lock) -{ - static std::mutex g_mutex; - lock = std::unique_lock<std::mutex>(g_mutex); +void OptionParser::Prepare(std::unique_lock<std::mutex> &lock) { + static std::mutex g_mutex; + lock = std::unique_lock<std::mutex>(g_mutex); #ifdef __GLIBC__ - optind = 0; + optind = 0; #else - optreset = 1; - optind = 1; + optreset = 1; + optind = 1; #endif } -void -OptionParser::EnableError(bool error) -{ - opterr = error ? 1 : 0; -} +void OptionParser::EnableError(bool error) { opterr = error ? 1 : 0; } -int -OptionParser::Parse (int argc, - char * const argv [], - const char *optstring, - const Option *longopts, - int *longindex) -{ - std::vector<option> opts; - while (longopts->definition != nullptr) - { - option opt; - opt.flag = longopts->flag; - opt.val = longopts->val; - opt.name = longopts->definition->long_option; - opt.has_arg = longopts->definition->option_has_arg; - opts.push_back(opt); - ++longopts; - } - opts.push_back(option()); - return getopt_long_only(argc, argv, optstring, &opts[0], longindex); +int OptionParser::Parse(int argc, char *const argv[], llvm::StringRef optstring, + const Option *longopts, int *longindex) { + std::vector<option> opts; + while (longopts->definition != nullptr) { + option opt; + opt.flag = longopts->flag; + opt.val = longopts->val; + opt.name = longopts->definition->long_option; + opt.has_arg = longopts->definition->option_has_arg; + opts.push_back(opt); + ++longopts; + } + opts.push_back(option()); + std::string opt_cstr = optstring; + return getopt_long_only(argc, argv, opt_cstr.c_str(), &opts[0], longindex); } -char* -OptionParser::GetOptionArgument() -{ - return optarg; -} +char *OptionParser::GetOptionArgument() { return optarg; } -int -OptionParser::GetOptionIndex() -{ - return optind; -} +int OptionParser::GetOptionIndex() { return optind; } -int -OptionParser::GetOptionErrorCause() -{ - return optopt; -} +int OptionParser::GetOptionErrorCause() { return optopt; } -std::string -OptionParser::GetShortOptionString(struct option *long_options) -{ - std::string s; - int i=0; - bool done = false; - while (!done) - { - if (long_options[i].name == 0 && - long_options[i].has_arg == 0 && - long_options[i].flag == 0 && - long_options[i].val == 0) - { - done = true; - } - else - { - if (long_options[i].flag == NULL && - isalpha(long_options[i].val)) - { - s.append(1, (char)long_options[i].val); - switch (long_options[i].has_arg) - { - default: - case no_argument: - break; - - case optional_argument: - s.append(2, ':'); - break; - case required_argument: - s.append(1, ':'); - break; - } - } - ++i; +std::string OptionParser::GetShortOptionString(struct option *long_options) { + std::string s; + int i = 0; + bool done = false; + while (!done) { + if (long_options[i].name == 0 && long_options[i].has_arg == 0 && + long_options[i].flag == 0 && long_options[i].val == 0) { + done = true; + } else { + if (long_options[i].flag == NULL && isalpha(long_options[i].val)) { + s.append(1, (char)long_options[i].val); + switch (long_options[i].has_arg) { + default: + case no_argument: + break; + + case optional_argument: + s.append(2, ':'); + break; + case required_argument: + s.append(1, ':'); + break; } + } + ++i; } - return s; + } + return s; } diff --git a/source/Host/common/PipeBase.cpp b/source/Host/common/PipeBase.cpp index a9d6e6f46c86..cf7e6c97c3c3 100644 --- a/source/Host/common/PipeBase.cpp +++ b/source/Host/common/PipeBase.cpp @@ -11,17 +11,14 @@ using namespace lldb_private; - PipeBase::~PipeBase() = default; -Error -PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit) -{ - return OpenAsWriterWithTimeout(name, child_process_inherit, std::chrono::microseconds::zero()); +Error PipeBase::OpenAsWriter(llvm::StringRef name, bool child_process_inherit) { + return OpenAsWriterWithTimeout(name, child_process_inherit, + std::chrono::microseconds::zero()); } -Error -PipeBase::Read(void *buf, size_t size, size_t &bytes_read) -{ - return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(), bytes_read); +Error PipeBase::Read(void *buf, size_t size, size_t &bytes_read) { + return ReadWithTimeout(buf, size, std::chrono::microseconds::zero(), + bytes_read); } diff --git a/source/Host/common/ProcessRunLock.cpp b/source/Host/common/ProcessRunLock.cpp index 669a96ddd70c..48dcd62bb939 100644 --- a/source/Host/common/ProcessRunLock.cpp +++ b/source/Host/common/ProcessRunLock.cpp @@ -1,71 +1,71 @@ -#ifndef _WIN32 +//===-- ProcessRunLock.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef _WIN32 #include "lldb/Host/ProcessRunLock.h" namespace lldb_private { - ProcessRunLock::ProcessRunLock() - : m_running(false) - { - int err = ::pthread_rwlock_init(&m_rwlock, NULL); (void) err; - //#if LLDB_CONFIGURATION_DEBUG - // assert(err == 0); - //#endif - } +ProcessRunLock::ProcessRunLock() : m_running(false) { + int err = ::pthread_rwlock_init(&m_rwlock, NULL); + (void)err; + //#if LLDB_CONFIGURATION_DEBUG + // assert(err == 0); + //#endif +} - ProcessRunLock::~ProcessRunLock() - { - int err = ::pthread_rwlock_destroy(&m_rwlock); (void) err; - //#if LLDB_CONFIGURATION_DEBUG - // assert(err == 0); - //#endif - } +ProcessRunLock::~ProcessRunLock() { + int err = ::pthread_rwlock_destroy(&m_rwlock); + (void)err; + //#if LLDB_CONFIGURATION_DEBUG + // assert(err == 0); + //#endif +} - bool ProcessRunLock::ReadTryLock() - { - ::pthread_rwlock_rdlock(&m_rwlock); - if (m_running == false) - { - return true; - } - ::pthread_rwlock_unlock(&m_rwlock); - return false; - } +bool ProcessRunLock::ReadTryLock() { + ::pthread_rwlock_rdlock(&m_rwlock); + if (m_running == false) { + return true; + } + ::pthread_rwlock_unlock(&m_rwlock); + return false; +} - bool ProcessRunLock::ReadUnlock() - { - return ::pthread_rwlock_unlock(&m_rwlock) == 0; - } +bool ProcessRunLock::ReadUnlock() { + return ::pthread_rwlock_unlock(&m_rwlock) == 0; +} - bool ProcessRunLock::SetRunning() - { - ::pthread_rwlock_wrlock(&m_rwlock); - m_running = true; - ::pthread_rwlock_unlock(&m_rwlock); - return true; - } +bool ProcessRunLock::SetRunning() { + ::pthread_rwlock_wrlock(&m_rwlock); + m_running = true; + ::pthread_rwlock_unlock(&m_rwlock); + return true; +} - bool ProcessRunLock::TrySetRunning() - { - bool r; +bool ProcessRunLock::TrySetRunning() { + bool r; - if (::pthread_rwlock_trywrlock(&m_rwlock) == 0) - { - r = !m_running; - m_running = true; - ::pthread_rwlock_unlock(&m_rwlock); - return r; - } - return false; - } + if (::pthread_rwlock_trywrlock(&m_rwlock) == 0) { + r = !m_running; + m_running = true; + ::pthread_rwlock_unlock(&m_rwlock); + return r; + } + return false; +} - bool ProcessRunLock::SetStopped() - { - ::pthread_rwlock_wrlock(&m_rwlock); - m_running = false; - ::pthread_rwlock_unlock(&m_rwlock); - return true; - } +bool ProcessRunLock::SetStopped() { + ::pthread_rwlock_wrlock(&m_rwlock); + m_running = false; + ::pthread_rwlock_unlock(&m_rwlock); + return true; +} } #endif diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp index ea049ae6933e..79777c88fa46 100644 --- a/source/Host/common/Socket.cpp +++ b/source/Host/common/Socket.cpp @@ -15,7 +15,6 @@ #include "lldb/Host/Host.h" #include "lldb/Host/SocketAddress.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/TimeValue.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Host/common/UDPSocket.h" @@ -34,456 +33,423 @@ #include "lldb/Host/linux/AbstractSocket.h" #endif -#ifdef __ANDROID_NDK__ -#include <linux/tcp.h> -#include <bits/error_constants.h> +#ifdef __ANDROID__ +#include <arpa/inet.h> #include <asm-generic/errno-base.h> #include <errno.h> -#include <arpa/inet.h> +#include <linux/tcp.h> #if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC) -#include <unistd.h> -#include <sys/syscall.h> #include <fcntl.h> +#include <sys/syscall.h> +#include <unistd.h> #endif // ANDROID_ARM_BUILD_STATIC || ANDROID_MIPS_BUILD_STATIC -#endif // __ANDROID_NDK__ +#endif // __ANDROID__ 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; +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; +#else // #if defined(_WIN32) +typedef const void *set_socket_option_arg_type; +typedef void *get_socket_option_arg_type; const NativeSocket Socket::kInvalidSocketValue = -1; #endif // #if defined(_WIN32) namespace { -bool IsInterrupted() -{ +bool IsInterrupted() { #if defined(_WIN32) - return ::WSAGetLastError() == WSAEINTR; + return ::WSAGetLastError() == WSAEINTR; #else - return errno == EINTR; + return errno == EINTR; #endif } - } Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) - : IOObject(eFDTypeSocket, should_close) - , m_protocol(protocol) - , m_socket(socket) -{ - -} - -Socket::~Socket() -{ - Close(); -} - -std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, bool child_processes_inherit, Error &error) -{ - error.Clear(); - - std::unique_ptr<Socket> socket_up; - switch (protocol) - { - case ProtocolTcp: - socket_up.reset(new TCPSocket(child_processes_inherit, error)); - break; - case ProtocolUdp: - socket_up.reset(new UDPSocket(child_processes_inherit, error)); - break; - case ProtocolUnixDomain: + : IOObject(eFDTypeSocket, should_close), m_protocol(protocol), + m_socket(socket) {} + +Socket::~Socket() { Close(); } + +std::unique_ptr<Socket> Socket::Create(const SocketProtocol protocol, + bool child_processes_inherit, + Error &error) { + error.Clear(); + + std::unique_ptr<Socket> socket_up; + switch (protocol) { + case ProtocolTcp: + socket_up.reset(new TCPSocket(child_processes_inherit, error)); + break; + case ProtocolUdp: + socket_up.reset(new UDPSocket(child_processes_inherit, error)); + break; + case ProtocolUnixDomain: #ifndef LLDB_DISABLE_POSIX - socket_up.reset(new DomainSocket(child_processes_inherit, error)); + socket_up.reset(new DomainSocket(child_processes_inherit, error)); #else - error.SetErrorString("Unix domain sockets are not supported on this platform."); + error.SetErrorString( + "Unix domain sockets are not supported on this platform."); #endif - break; - case ProtocolUnixAbstract: + break; + case ProtocolUnixAbstract: #ifdef __linux__ - socket_up.reset(new AbstractSocket(child_processes_inherit, error)); + socket_up.reset(new AbstractSocket(child_processes_inherit, error)); #else - error.SetErrorString("Abstract domain sockets are not supported on this platform."); + error.SetErrorString( + "Abstract domain sockets are not supported on this platform."); #endif - break; - } + break; + } - if (error.Fail()) - socket_up.reset(); + if (error.Fail()) + socket_up.reset(); - return socket_up; + return socket_up; } -Error Socket::TcpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&socket) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); - if (log) - log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); - - Error error; - std::unique_ptr<Socket> connect_socket(Create(ProtocolTcp, child_processes_inherit, error)); - if (error.Fail()) - return error; +Error Socket::TcpConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); + if (log) + log->Printf("Socket::%s (host/port = %s)", __FUNCTION__, + host_and_port.data()); + + Error error; + std::unique_ptr<Socket> connect_socket( + Create(ProtocolTcp, child_processes_inherit, error)); + if (error.Fail()) + return error; - error = connect_socket->Connect(host_and_port); - if (error.Success()) - socket = connect_socket.release(); + error = connect_socket->Connect(host_and_port); + if (error.Success()) + socket = connect_socket.release(); - return error; + return error; } -Error -Socket::TcpListen (llvm::StringRef host_and_port, - bool child_processes_inherit, - Socket *&socket, - Predicate<uint16_t>* predicate, - int backlog) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("Socket::%s (%s)", __FUNCTION__, host_and_port.data()); - - Error error; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) - return error; - - std::unique_ptr<TCPSocket> listen_socket(new TCPSocket(child_processes_inherit, error)); - if (error.Fail()) - return error; - - error = listen_socket->Listen(host_and_port, backlog); - if (error.Success()) - { - // We were asked to listen on port zero which means we - // must now read the actual port that was given to us - // as port zero is a special code for "find an open port - // for me". - if (port == 0) - port = listen_socket->GetLocalPortNumber(); - - // Set the port predicate since when doing a listen://<host>:<port> - // it often needs to accept the incoming connection which is a blocking - // system call. Allowing access to the bound port using a predicate allows - // us to wait for the port predicate to be set to a non-zero value from - // another thread in an efficient manor. - if (predicate) - predicate->SetValue (port, eBroadcastAlways); - socket = listen_socket.release(); - } +Error Socket::TcpListen(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket, + Predicate<uint16_t> *predicate, int backlog) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("Socket::%s (%s)", __FUNCTION__, host_and_port.data()); + + Error error; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort(host_and_port, host_str, port_str, port, &error)) + return error; + std::unique_ptr<TCPSocket> listen_socket( + new TCPSocket(child_processes_inherit, error)); + if (error.Fail()) return error; + + error = listen_socket->Listen(host_and_port, backlog); + if (error.Success()) { + // We were asked to listen on port zero which means we + // must now read the actual port that was given to us + // as port zero is a special code for "find an open port + // for me". + if (port == 0) + port = listen_socket->GetLocalPortNumber(); + + // Set the port predicate since when doing a listen://<host>:<port> + // it often needs to accept the incoming connection which is a blocking + // system call. Allowing access to the bound port using a predicate allows + // us to wait for the port predicate to be set to a non-zero value from + // another thread in an efficient manor. + if (predicate) + predicate->SetValue(port, eBroadcastAlways); + socket = listen_socket.release(); + } + + return error; } -Error Socket::UdpConnect(llvm::StringRef host_and_port, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("Socket::%s (host/port = %s)", __FUNCTION__, host_and_port.data()); +Error Socket::UdpConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&send_socket, + Socket *&recv_socket) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("Socket::%s (host/port = %s)", __FUNCTION__, + host_and_port.data()); - return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket, recv_socket); + return UDPSocket::Connect(host_and_port, child_processes_inherit, send_socket, + recv_socket); } -Error Socket::UnixDomainConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - std::unique_ptr<Socket> connect_socket(Create(ProtocolUnixDomain, child_processes_inherit, error)); - if (error.Fail()) - return error; +Error Socket::UnixDomainConnect(llvm::StringRef name, + bool child_processes_inherit, Socket *&socket) { + Error error; + std::unique_ptr<Socket> connect_socket( + Create(ProtocolUnixDomain, child_processes_inherit, error)); + if (error.Fail()) + return error; - error = connect_socket->Connect(name); - if (error.Success()) - socket = connect_socket.release(); + error = connect_socket->Connect(name); + if (error.Success()) + socket = connect_socket.release(); - return error; + return error; } -Error Socket::UnixDomainAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - std::unique_ptr<Socket> listen_socket(Create(ProtocolUnixDomain, child_processes_inherit, error)); - if (error.Fail()) - return error; - - error = listen_socket->Listen(name, 5); - if (error.Fail()) - return error; +Error Socket::UnixDomainAccept(llvm::StringRef name, + bool child_processes_inherit, Socket *&socket) { + Error error; + std::unique_ptr<Socket> listen_socket( + Create(ProtocolUnixDomain, child_processes_inherit, error)); + if (error.Fail()) + return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Listen(name, 5); + if (error.Fail()) return error; + + error = listen_socket->Accept(name, child_processes_inherit, socket); + return error; } -Error -Socket::UnixAbstractConnect(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - std::unique_ptr<Socket> connect_socket(Create(ProtocolUnixAbstract, child_processes_inherit, error)); - if (error.Fail()) - return error; - - error = connect_socket->Connect(name); - if (error.Success()) - socket = connect_socket.release(); +Error Socket::UnixAbstractConnect(llvm::StringRef name, + bool child_processes_inherit, + Socket *&socket) { + Error error; + std::unique_ptr<Socket> connect_socket( + Create(ProtocolUnixAbstract, child_processes_inherit, error)); + if (error.Fail()) return error; -} -Error -Socket::UnixAbstractAccept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - Error error; - std::unique_ptr<Socket> listen_socket(Create(ProtocolUnixAbstract,child_processes_inherit, error)); - if (error.Fail()) - return error; + error = connect_socket->Connect(name); + if (error.Success()) + socket = connect_socket.release(); + return error; +} - error = listen_socket->Listen(name, 5); - if (error.Fail()) - return error; +Error Socket::UnixAbstractAccept(llvm::StringRef name, + bool child_processes_inherit, + Socket *&socket) { + Error error; + std::unique_ptr<Socket> listen_socket( + Create(ProtocolUnixAbstract, child_processes_inherit, error)); + if (error.Fail()) + return error; - error = listen_socket->Accept(name, child_processes_inherit, socket); + error = listen_socket->Listen(name, 5); + if (error.Fail()) 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(), ®ex_match)) - { - if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) && - regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str)) - { - bool ok = false; - port = StringConvert::ToUInt32 (port_str.c_str(), UINT32_MAX, 10, &ok); - if (ok && port <= UINT16_MAX) - { - if (error_ptr) - error_ptr->Clear(); - return true; - } - // port is too large - if (error_ptr) - error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data()); - return false; - } - } + error = listen_socket->Accept(name, child_processes_inherit, socket); + return error; +} - // If this was unsuccessful, then check if it's simply a signed 32-bit integer, representing - // a port with an empty host. - host_str.clear(); - port_str.clear(); - bool ok = false; - port = StringConvert::ToUInt32 (host_and_port.data(), UINT32_MAX, 10, &ok); - if (ok && port < UINT16_MAX) - { - port_str = host_and_port; +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(llvm::StringRef("([^:]+):([0-9]+)")); + RegularExpression::Match regex_match(2); + if (g_regex.Execute(host_and_port, ®ex_match)) { + if (regex_match.GetMatchAtIndex(host_and_port.data(), 1, host_str) && + regex_match.GetMatchAtIndex(host_and_port.data(), 2, port_str)) { + bool ok = false; + port = StringConvert::ToUInt32(port_str.c_str(), UINT32_MAX, 10, &ok); + if (ok && port <= UINT16_MAX) { if (error_ptr) - error_ptr->Clear(); + error_ptr->Clear(); return true; + } + // port is too large + if (error_ptr) + error_ptr->SetErrorStringWithFormat( + "invalid host:port specification: '%s'", host_and_port.data()); + return false; } - + } + + // If this was unsuccessful, then check if it's simply a signed 32-bit + // integer, representing + // a port with an empty host. + host_str.clear(); + port_str.clear(); + bool ok = false; + port = StringConvert::ToUInt32(host_and_port.data(), UINT32_MAX, 10, &ok); + if (ok && port < UINT16_MAX) { + port_str = host_and_port; if (error_ptr) - error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data()); - return false; + error_ptr->Clear(); + return true; + } + + if (error_ptr) + error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", + host_and_port.data()); + return false; } -IOObject::WaitableHandle Socket::GetWaitableHandle() -{ - // TODO: On Windows, use WSAEventSelect - return m_socket; +IOObject::WaitableHandle Socket::GetWaitableHandle() { + // TODO: On Windows, use WSAEventSelect + return m_socket; } -Error Socket::Read (void *buf, size_t &num_bytes) -{ - Error error; - int bytes_received = 0; - do - { - bytes_received = ::recv (m_socket, static_cast<char *>(buf), num_bytes, 0); - } while (bytes_received < 0 && IsInterrupted ()); - - if (bytes_received < 0) - { - SetLastError (error); - num_bytes = 0; - } - else - num_bytes = bytes_received; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); - if (log) - { - log->Printf ("%p Socket::Read() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", - static_cast<void*>(this), - static_cast<uint64_t>(m_socket), - buf, - static_cast<uint64_t>(num_bytes), - static_cast<int64_t>(bytes_received), - error.AsCString()); - } - - return error; +Error Socket::Read(void *buf, size_t &num_bytes) { + Error error; + int bytes_received = 0; + do { + bytes_received = ::recv(m_socket, static_cast<char *>(buf), num_bytes, 0); + } while (bytes_received < 0 && IsInterrupted()); + + if (bytes_received < 0) { + SetLastError(error); + num_bytes = 0; + } else + num_bytes = bytes_received; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); + if (log) { + log->Printf("%p Socket::Read() (socket = %" PRIu64 + ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 + " (error = %s)", + static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, + static_cast<uint64_t>(num_bytes), + static_cast<int64_t>(bytes_received), error.AsCString()); + } + + return error; } -Error Socket::Write (const void *buf, size_t &num_bytes) -{ - Error error; - int bytes_sent = 0; - do - { - bytes_sent = Send(buf, num_bytes); - } while (bytes_sent < 0 && IsInterrupted ()); - - if (bytes_sent < 0) - { - SetLastError (error); - num_bytes = 0; - } - else - num_bytes = bytes_sent; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); - if (log) - { - log->Printf ("%p Socket::Write() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", - static_cast<void*>(this), - static_cast<uint64_t>(m_socket), - buf, - static_cast<uint64_t>(num_bytes), - static_cast<int64_t>(bytes_sent), - error.AsCString()); - } - - return error; +Error Socket::Write(const void *buf, size_t &num_bytes) { + Error error; + int bytes_sent = 0; + do { + bytes_sent = Send(buf, num_bytes); + } while (bytes_sent < 0 && IsInterrupted()); + + if (bytes_sent < 0) { + SetLastError(error); + num_bytes = 0; + } else + num_bytes = bytes_sent; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); + if (log) { + log->Printf("%p Socket::Write() (socket = %" PRIu64 + ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 + " (error = %s)", + static_cast<void *>(this), static_cast<uint64_t>(m_socket), buf, + static_cast<uint64_t>(num_bytes), + static_cast<int64_t>(bytes_sent), error.AsCString()); + } + + return error; } -Error Socket::PreDisconnect() -{ - Error error; - return error; +Error Socket::PreDisconnect() { + Error error; + return error; } -Error Socket::Close() -{ - Error error; - if (!IsValid() || !m_should_close_fd) - 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); + 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); + bool success = !!closesocket(m_socket); #else - bool success = !!::close (m_socket); + bool success = !!::close(m_socket); #endif - // A reference to a FD was passed in, set it to an invalid value - m_socket = kInvalidSocketValue; - if (!success) - { - SetLastError (error); - } + // A reference to a FD was passed in, set it to an invalid value + m_socket = kInvalidSocketValue; + if (!success) { + SetLastError(error); + } - return error; + return error; } - -int Socket::GetOption(int level, int option_name, int &option_value) -{ - get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); - socklen_t option_value_size = sizeof(int); - return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size); +int Socket::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)); +int Socket::SetOption(int level, int option_name, int option_value) { + set_socket_option_arg_type option_value_p = + reinterpret_cast<get_socket_option_arg_type>(&option_value); + return ::setsockopt(m_socket, level, option_name, option_value_p, + sizeof(option_value)); } -size_t Socket::Send(const void *buf, const size_t num_bytes) -{ - return ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0); +size_t Socket::Send(const void *buf, const size_t num_bytes) { + return ::send(m_socket, static_cast<const char *>(buf), num_bytes, 0); } -void Socket::SetLastError(Error &error) -{ +void Socket::SetLastError(Error &error) { #if defined(_WIN32) - error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); + error.SetError(::WSAGetLastError(), lldb::eErrorTypeWin32); #else - error.SetErrorToErrno(); + error.SetErrorToErrno(); #endif } -NativeSocket -Socket::CreateSocket(const int domain, - const int type, - const int protocol, - bool child_processes_inherit, - Error& error) -{ - error.Clear(); - auto socketType = type; +NativeSocket Socket::CreateSocket(const int domain, const int type, + const int protocol, + bool child_processes_inherit, Error &error) { + error.Clear(); + auto socketType = type; #ifdef SOCK_CLOEXEC - if (!child_processes_inherit) - socketType |= SOCK_CLOEXEC; + if (!child_processes_inherit) + socketType |= SOCK_CLOEXEC; #endif - auto sock = ::socket (domain, socketType, protocol); - if (sock == kInvalidSocketValue) - SetLastError(error); + auto sock = ::socket(domain, socketType, protocol); + if (sock == kInvalidSocketValue) + SetLastError(error); - return sock; + return sock; } -NativeSocket -Socket::AcceptSocket(NativeSocket sockfd, - struct sockaddr *addr, - socklen_t *addrlen, - bool child_processes_inherit, - Error& error) -{ - error.Clear(); +NativeSocket Socket::AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, + socklen_t *addrlen, + bool child_processes_inherit, Error &error) { + error.Clear(); #if defined(ANDROID_ARM_BUILD_STATIC) || defined(ANDROID_MIPS_BUILD_STATIC) - // Temporary workaround for statically linking Android lldb-server with the - // latest API. - int fd = syscall(__NR_accept, sockfd, addr, addrlen); - if (fd >= 0 && !child_processes_inherit) - { - int flags = ::fcntl(fd, F_GETFD); - if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1) - return fd; - SetLastError(error); - close(fd); - } - return fd; + // Temporary workaround for statically linking Android lldb-server with the + // latest API. + int fd = syscall(__NR_accept, sockfd, addr, addrlen); + if (fd >= 0 && !child_processes_inherit) { + int flags = ::fcntl(fd, F_GETFD); + if (flags != -1 && ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1) + return fd; + SetLastError(error); + close(fd); + } + return fd; #elif defined(SOCK_CLOEXEC) - int flags = 0; - if (!child_processes_inherit) { - flags |= SOCK_CLOEXEC; - } + int flags = 0; + if (!child_processes_inherit) { + flags |= SOCK_CLOEXEC; + } #if defined(__NetBSD__) - NativeSocket fd = ::paccept (sockfd, addr, addrlen, nullptr, flags); + NativeSocket fd = ::paccept(sockfd, addr, addrlen, nullptr, flags); #else - NativeSocket fd = ::accept4 (sockfd, addr, addrlen, flags); + NativeSocket fd = ::accept4(sockfd, addr, addrlen, flags); #endif #else - NativeSocket fd = ::accept (sockfd, addr, addrlen); + NativeSocket fd = ::accept(sockfd, addr, addrlen); #endif - if (fd == kInvalidSocketValue) - SetLastError(error); - return fd; + if (fd == kInvalidSocketValue) + SetLastError(error); + return fd; } diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp index 1dc43ea6294c..1f5de2e5df18 100644 --- a/source/Host/common/SocketAddress.cpp +++ b/source/Host/common/SocketAddress.cpp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +#if defined(_MSC_VER) +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + #include "lldb/Host/SocketAddress.h" #include <stddef.h> #include <stdio.h> @@ -14,15 +18,15 @@ // C Includes #if !defined(_WIN32) #include <arpa/inet.h> -#else -#include "lldb/Host/windows/win32.h" #endif + #include <assert.h> #include <string.h> // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Host/PosixApi.h" // WindowsXP needs an inet_ntop implementation #ifdef _WIN32 @@ -32,336 +36,254 @@ #endif // TODO: implement shortened form "::" for runs of zeros -const char* inet_ntop(int af, const void * src, - char * dst, socklen_t size) -{ - if (size==0) +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { + if (size == 0) { + return nullptr; + } + + switch (af) { + case AF_INET: { { - return nullptr; + const char *formatted = inet_ntoa(*static_cast<const in_addr *>(src)); + if (formatted && strlen(formatted) < static_cast<size_t>(size)) { + return ::strcpy(dst, formatted); + } } - - switch (af) - { - case AF_INET: - { - { - const char* formatted = inet_ntoa(*static_cast<const in_addr*>(src)); - if (formatted && strlen(formatted) < size) - { - return ::strcpy(dst, formatted); - } - } - return nullptr; - case AF_INET6: - { - char tmp[INET6_ADDRSTRLEN] = {0}; - const uint16_t* src16 = static_cast<const uint16_t*>(src); - int full_size = ::snprintf(tmp, sizeof(tmp), - "%x:%x:%x:%x:%x:%x:%x:%x", - ntohs(src16[0]), ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]), - ntohs(src16[4]), ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7]) - ); - if (full_size < static_cast<int>(size)) - { - return ::strcpy(dst, tmp); - } - return nullptr; - } - } + return nullptr; + case AF_INET6: { + char tmp[INET6_ADDRSTRLEN] = {0}; + const uint16_t *src16 = static_cast<const uint16_t *>(src); + int full_size = ::snprintf( + tmp, sizeof(tmp), "%x:%x:%x:%x:%x:%x:%x:%x", ntohs(src16[0]), + ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]), ntohs(src16[4]), + ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7])); + if (full_size < static_cast<int>(size)) { + return ::strcpy(dst, tmp); } return nullptr; -} + } + } + } + return nullptr; +} #endif - using namespace lldb_private; //---------------------------------------------------------------------- // SocketAddress constructor //---------------------------------------------------------------------- -SocketAddress::SocketAddress () -{ - Clear (); -} - -SocketAddress::SocketAddress (const struct sockaddr &s) -{ - m_socket_addr.sa = s; -} +SocketAddress::SocketAddress() { Clear(); } +SocketAddress::SocketAddress(const struct sockaddr &s) { m_socket_addr.sa = s; } -SocketAddress::SocketAddress (const struct sockaddr_in &s) -{ - m_socket_addr.sa_ipv4 = s; +SocketAddress::SocketAddress(const struct sockaddr_in &s) { + m_socket_addr.sa_ipv4 = s; } - -SocketAddress::SocketAddress (const struct sockaddr_in6 &s) -{ - m_socket_addr.sa_ipv6 = s; +SocketAddress::SocketAddress(const struct sockaddr_in6 &s) { + m_socket_addr.sa_ipv6 = s; } - -SocketAddress::SocketAddress (const struct sockaddr_storage &s) -{ - m_socket_addr.sa_storage = s; +SocketAddress::SocketAddress(const struct sockaddr_storage &s) { + m_socket_addr.sa_storage = s; } //---------------------------------------------------------------------- // SocketAddress copy constructor //---------------------------------------------------------------------- -SocketAddress::SocketAddress (const SocketAddress& rhs) : - m_socket_addr (rhs.m_socket_addr) -{ -} +SocketAddress::SocketAddress(const SocketAddress &rhs) + : m_socket_addr(rhs.m_socket_addr) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -SocketAddress::~SocketAddress() -{ -} - -void -SocketAddress::Clear () -{ - memset (&m_socket_addr, 0, sizeof(m_socket_addr)); -} +SocketAddress::~SocketAddress() {} -bool -SocketAddress::IsValid () const -{ - return GetLength () != 0; +void SocketAddress::Clear() { + memset(&m_socket_addr, 0, sizeof(m_socket_addr)); } -static socklen_t -GetFamilyLength (sa_family_t family) -{ - switch (family) - { - case AF_INET: return sizeof(struct sockaddr_in); - case AF_INET6: return sizeof(struct sockaddr_in6); - } - assert(0 && "Unsupported address family"); - return 0; +bool SocketAddress::IsValid() const { return GetLength() != 0; } + +static socklen_t GetFamilyLength(sa_family_t family) { + switch (family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + } + assert(0 && "Unsupported address family"); + return 0; } -socklen_t -SocketAddress::GetLength () const -{ +socklen_t SocketAddress::GetLength() const { #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - return m_socket_addr.sa.sa_len; + return m_socket_addr.sa.sa_len; #else - return GetFamilyLength (GetFamily()); + return GetFamilyLength(GetFamily()); #endif } -socklen_t -SocketAddress::GetMaxLength () -{ - return sizeof (sockaddr_t); -} +socklen_t SocketAddress::GetMaxLength() { return sizeof(sockaddr_t); } -sa_family_t -SocketAddress::GetFamily () const -{ - return m_socket_addr.sa.sa_family; +sa_family_t SocketAddress::GetFamily() const { + return m_socket_addr.sa.sa_family; } -void -SocketAddress::SetFamily (sa_family_t family) -{ - m_socket_addr.sa.sa_family = family; +void SocketAddress::SetFamily(sa_family_t family) { + m_socket_addr.sa.sa_family = family; #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) - m_socket_addr.sa.sa_len = GetFamilyLength (family); + m_socket_addr.sa.sa_len = GetFamilyLength(family); #endif } -std::string -SocketAddress::GetIPAddress () const -{ - char str[INET6_ADDRSTRLEN] = {0}; - switch (GetFamily()) - { - case AF_INET: - if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, sizeof(str))) - return str; - break; - case AF_INET6: - if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, sizeof(str))) - return str; - break; - } - return ""; +std::string SocketAddress::GetIPAddress() const { + char str[INET6_ADDRSTRLEN] = {0}; + switch (GetFamily()) { + case AF_INET: + if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, + sizeof(str))) + return str; + break; + case AF_INET6: + if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, + sizeof(str))) + return str; + break; + } + return ""; } -uint16_t -SocketAddress::GetPort () const -{ - switch (GetFamily()) - { - case AF_INET: return ntohs(m_socket_addr.sa_ipv4.sin_port); - case AF_INET6: return ntohs(m_socket_addr.sa_ipv6.sin6_port); - } - return 0; +uint16_t SocketAddress::GetPort() const { + switch (GetFamily()) { + case AF_INET: + return ntohs(m_socket_addr.sa_ipv4.sin_port); + case AF_INET6: + return ntohs(m_socket_addr.sa_ipv6.sin6_port); + } + return 0; } -bool -SocketAddress::SetPort (uint16_t port) -{ - switch (GetFamily()) - { - case AF_INET: - m_socket_addr.sa_ipv4.sin_port = htons(port); - return true; - - case AF_INET6: - m_socket_addr.sa_ipv6.sin6_port = htons(port); - return true; - } - return false; +bool SocketAddress::SetPort(uint16_t port) { + switch (GetFamily()) { + case AF_INET: + m_socket_addr.sa_ipv4.sin_port = htons(port); + return true; + + case AF_INET6: + m_socket_addr.sa_ipv6.sin6_port = htons(port); + return true; + } + return false; } //---------------------------------------------------------------------- // SocketAddress assignment operator //---------------------------------------------------------------------- -const SocketAddress& -SocketAddress::operator=(const SocketAddress& rhs) -{ - if (this != &rhs) - m_socket_addr = rhs.m_socket_addr; - return *this; +const SocketAddress &SocketAddress::operator=(const SocketAddress &rhs) { + if (this != &rhs) + m_socket_addr = rhs.m_socket_addr; + return *this; } -const SocketAddress& -SocketAddress::operator=(const struct addrinfo *addr_info) -{ - Clear(); - if (addr_info && - addr_info->ai_addr && - addr_info->ai_addrlen > 0&& - addr_info->ai_addrlen <= sizeof m_socket_addr) - { - ::memcpy (&m_socket_addr, - addr_info->ai_addr, - addr_info->ai_addrlen); - } - return *this; +const SocketAddress &SocketAddress:: +operator=(const struct addrinfo *addr_info) { + Clear(); + if (addr_info && addr_info->ai_addr && addr_info->ai_addrlen > 0 && + addr_info->ai_addrlen <= sizeof m_socket_addr) { + ::memcpy(&m_socket_addr, addr_info->ai_addr, addr_info->ai_addrlen); + } + return *this; } -const SocketAddress& -SocketAddress::operator=(const struct sockaddr &s) -{ - m_socket_addr.sa = s; - return *this; +const SocketAddress &SocketAddress::operator=(const struct sockaddr &s) { + m_socket_addr.sa = s; + return *this; } -const SocketAddress& -SocketAddress::operator=(const struct sockaddr_in &s) -{ - m_socket_addr.sa_ipv4 = s; - return *this; +const SocketAddress &SocketAddress::operator=(const struct sockaddr_in &s) { + m_socket_addr.sa_ipv4 = s; + return *this; } -const SocketAddress& -SocketAddress::operator=(const struct sockaddr_in6 &s) -{ - m_socket_addr.sa_ipv6 = s; - return *this; +const SocketAddress &SocketAddress::operator=(const struct sockaddr_in6 &s) { + m_socket_addr.sa_ipv6 = s; + return *this; } -const SocketAddress& -SocketAddress::operator=(const struct sockaddr_storage &s) -{ - m_socket_addr.sa_storage = s; - return *this; +const SocketAddress &SocketAddress:: +operator=(const struct sockaddr_storage &s) { + m_socket_addr.sa_storage = s; + return *this; } -bool -SocketAddress::getaddrinfo (const char *host, - const char *service, - int ai_family, - int ai_socktype, - int ai_protocol, - int ai_flags) -{ - Clear (); - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = ai_family; - hints.ai_socktype = ai_socktype; - hints.ai_protocol = ai_protocol; - hints.ai_flags = ai_flags; - - bool result = false; - struct addrinfo *service_info_list = NULL; - int err = ::getaddrinfo (host, service, &hints, &service_info_list); - if (err == 0 && service_info_list) - { - *this = service_info_list; - result = IsValid (); - } - - if (service_info_list) - ::freeaddrinfo(service_info_list); - - return result; +bool SocketAddress::getaddrinfo(const char *host, const char *service, + int ai_family, int ai_socktype, int ai_protocol, + int ai_flags) { + Clear(); + + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai_family; + hints.ai_socktype = ai_socktype; + hints.ai_protocol = ai_protocol; + hints.ai_flags = ai_flags; + + bool result = false; + struct addrinfo *service_info_list = NULL; + int err = ::getaddrinfo(host, service, &hints, &service_info_list); + if (err == 0 && service_info_list) { + *this = service_info_list; + result = IsValid(); + } + + if (service_info_list) + ::freeaddrinfo(service_info_list); + + return result; } +bool SocketAddress::SetToLocalhost(sa_family_t family, uint16_t port) { + switch (family) { + case AF_INET: + SetFamily(AF_INET); + if (SetPort(port)) { + m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + return true; + } + break; -bool -SocketAddress::SetToLocalhost (sa_family_t family, uint16_t port) -{ - switch (family) - { - case AF_INET: - SetFamily (AF_INET); - if (SetPort (port)) - { - m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - return true; - } - break; - - case AF_INET6: - SetFamily (AF_INET6); - if (SetPort (port)) - { - m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback; - return true; - } - break; - + case AF_INET6: + SetFamily(AF_INET6); + if (SetPort(port)) { + m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback; + return true; } - Clear(); - return false; + break; + } + Clear(); + return false; } -bool -SocketAddress::SetToAnyAddress (sa_family_t family, uint16_t port) -{ - switch (family) - { - case AF_INET: - SetFamily (AF_INET); - if (SetPort (port)) - { - m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY); - return true; - } - break; - - case AF_INET6: - SetFamily (AF_INET6); - if (SetPort (port)) - { - m_socket_addr.sa_ipv6.sin6_addr = in6addr_any; - return true; - } - break; - +bool SocketAddress::SetToAnyAddress(sa_family_t family, uint16_t port) { + switch (family) { + case AF_INET: + SetFamily(AF_INET); + if (SetPort(port)) { + m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + return true; + } + break; + + case AF_INET6: + SetFamily(AF_INET6); + if (SetPort(port)) { + m_socket_addr.sa_ipv6.sin6_addr = in6addr_any; + return true; } - Clear(); - return false; + break; + } + Clear(); + return false; } diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp index 51cb34ffe6dd..3d57b7dd6b88 100644 --- a/source/Host/common/SoftwareBreakpoint.cpp +++ b/source/Host/common/SoftwareBreakpoint.cpp @@ -21,296 +21,332 @@ 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)); +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 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; - } + 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 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)); + 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 addr = 0x%" PRIx64, __FUNCTION__, addr); + log->Printf("SoftwareBreakpoint::%s cannot support %zu trapcode bytes, " + "max size is %zu", + __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE); + return Error("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() " + "returned too many trap opcode bytes: requires %zu but we " + "only support a max of %zu", + 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(); +} - // Save the original opcodes by reading them so we can restore later. - size_t bytes_read = 0; +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"); - Error error = process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read); - if (error.Fail ()) - { - if (log) - log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); - return error; - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); - // Ensure we read as many bytes as we expected. - if (bytes_read != bp_opcode_size) - { - if (log) - log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); - return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_read); - } + // Save the original opcodes by reading them so we can restore later. + size_t bytes_read = 0; - // Log what we read. + Error error = + process.ReadMemory(addr, saved_opcode_bytes, bp_opcode_size, bytes_read); + if (error.Fail()) { if (log) - { - int i = 0; - for (const uint8_t *read_byte = saved_opcode_bytes; read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte) - { - log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 - " ovewriting byte index %d (was 0x%hhx)", - __FUNCTION__, addr, i++, *read_byte); - } - } - - // Write a software breakpoint in place of the original opcode. - size_t bytes_written = 0; - error = process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written); - if (error.Fail ()) - { - if (log) - log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); - return error; - } - - // Ensure we wrote as many bytes as we expected. - if (bytes_written != bp_opcode_size) - { - error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)bytes_written); - if (log) - log->PutCString (error.AsCString ()); - return error; - } - - uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; - size_t verify_bytes_read = 0; - error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, verify_bytes_read); - if (error.Fail ()) - { - if (log) - log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ()); - return error; - } + log->Printf("SoftwareBreakpoint::%s failed to read memory while " + "attempting to set breakpoint: %s", + __FUNCTION__, error.AsCString()); + return error; + } - // Ensure we read as many verification bytes as we expected. - if (verify_bytes_read != bp_opcode_size) - { - if (log) - log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); - return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, (uint64_t)verify_bytes_read); + // Ensure we read as many bytes as we expected. + if (bytes_read != bp_opcode_size) { + if (log) + log->Printf("SoftwareBreakpoint::%s failed to read memory while " + "attempting to set breakpoint: attempted to read %zu bytes " + "but only read %zu", + __FUNCTION__, bp_opcode_size, bytes_read); + return Error("SoftwareBreakpoint::%s failed to read memory while " + "attempting to set breakpoint: attempted to read %zu bytes " + "but only read %zu", + __FUNCTION__, bp_opcode_size, bytes_read); + } + + // Log what we read. + if (log) { + int i = 0; + for (const uint8_t *read_byte = saved_opcode_bytes; + read_byte < saved_opcode_bytes + bp_opcode_size; ++read_byte) { + log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 + " ovewriting byte index %d (was 0x%hhx)", + __FUNCTION__, addr, i++, *read_byte); } + } - 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); - } + // Write a software breakpoint in place of the original opcode. + size_t bytes_written = 0; + error = + process.WriteMemory(addr, bp_opcode_bytes, bp_opcode_size, bytes_written); + if (error.Fail()) { + if (log) + log->Printf("SoftwareBreakpoint::%s failed to write memory while " + "attempting to set breakpoint: %s", + __FUNCTION__, error.AsCString()); + return error; + } + + // Ensure we wrote as many bytes as we expected. + if (bytes_written != bp_opcode_size) { + error.SetErrorStringWithFormat( + "SoftwareBreakpoint::%s failed write memory while attempting to set " + "breakpoint: attempted to write %zu bytes but only wrote %zu", + __FUNCTION__, bp_opcode_size, bytes_written); + if (log) + log->PutCString(error.AsCString()); + return error; + } + uint8_t verify_bp_opcode_bytes[MAX_TRAP_OPCODE_SIZE]; + size_t verify_bytes_read = 0; + error = process.ReadMemory(addr, verify_bp_opcode_bytes, bp_opcode_size, + verify_bytes_read); + if (error.Fail()) { if (log) - log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); + log->Printf("SoftwareBreakpoint::%s failed to read memory while " + "attempting to verify the breakpoint set: %s", + __FUNCTION__, error.AsCString()); + return error; + } - return Error (); + // Ensure we read as many verification bytes as we expected. + if (verify_bytes_read != bp_opcode_size) { + if (log) + log->Printf("SoftwareBreakpoint::%s failed to read memory while " + "attempting to verify breakpoint: attempted to read %zu " + "bytes but only read %zu", + __FUNCTION__, bp_opcode_size, verify_bytes_read); + return Error("SoftwareBreakpoint::%s failed to read memory while " + "attempting to verify breakpoint: attempted to read %zu bytes " + "but only read %zu", + __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); +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::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"); +Error SoftwareBreakpoint::DoDisable() { + Error error; + assert(m_addr && (m_addr != LLDB_INVALID_ADDRESS) && + "can't remove a software breakpoint for an invalid address"); - Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr); - - assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes"); - - if (m_opcode_size > 0) - { - // Clear a software breakpoint instruction - uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE]; - bool break_op_found = false; - assert (m_opcode_size <= sizeof (curr_break_op)); - - // Read the breakpoint opcode - size_t bytes_read = 0; - error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read); - if (error.Success() && bytes_read < m_opcode_size) - { - error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_read); - } - if (error.Success ()) - { - bool verify = false; - // Make sure the breakpoint opcode exists at this address - if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0) - { - break_op_found = true; - // We found a valid breakpoint opcode at this address, now restore - // the saved opcode. - size_t bytes_written = 0; - error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written); - if (error.Success() && bytes_written < m_opcode_size) - { - error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)bytes_written); - } - if (error.Success ()) - { - verify = true; - } - } - else - { - error.SetErrorString("Original breakpoint trap is no longer in memory."); - // Set verify to true and so we can check if the original opcode has already been restored - verify = true; - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, + m_addr); - if (verify) - { - uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE]; - assert (m_opcode_size <= sizeof (verify_opcode)); - // Verify that our original opcode made it back to the inferior - - size_t verify_bytes_read = 0; - error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read); - if (error.Success() && verify_bytes_read < m_opcode_size) - { - error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, (uint64_t)verify_bytes_read); - } - if (error.Success ()) - { - // compare the memory we just read with the original opcode - if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0) - { - // SUCCESS - if (log) - { - int i = 0; - for (const uint8_t *verify_byte = verify_opcode; verify_byte < verify_opcode + m_opcode_size; ++verify_byte) - { - log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 - " replaced byte index %d with 0x%hhx", - __FUNCTION__, m_addr, i++, *verify_byte); - } - log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr); - } - return error; - } - else - { - if (break_op_found) - error.SetErrorString("Failed to restore original opcode."); - } - } - else - error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored."); - } + assert((m_opcode_size > 0) && + "cannot restore opcodes when there are no opcodes"); + + if (m_opcode_size > 0) { + // Clear a software breakpoint instruction + uint8_t curr_break_op[MAX_TRAP_OPCODE_SIZE]; + bool break_op_found = false; + assert(m_opcode_size <= sizeof(curr_break_op)); + + // Read the breakpoint opcode + size_t bytes_read = 0; + error = + m_process.ReadMemory(m_addr, curr_break_op, m_opcode_size, bytes_read); + if (error.Success() && bytes_read < m_opcode_size) { + error.SetErrorStringWithFormat( + "SoftwareBreakpointr::%s addr=0x%" PRIx64 + ": tried to read %zu bytes but only read %zu", + __FUNCTION__, m_addr, m_opcode_size, bytes_read); + } + if (error.Success()) { + bool verify = false; + // Make sure the breakpoint opcode exists at this address + if (::memcmp(curr_break_op, m_trap_opcodes, m_opcode_size) == 0) { + break_op_found = true; + // We found a valid breakpoint opcode at this address, now restore + // the saved opcode. + size_t bytes_written = 0; + error = m_process.WriteMemory(m_addr, m_saved_opcodes, m_opcode_size, + bytes_written); + if (error.Success() && bytes_written < m_opcode_size) { + error.SetErrorStringWithFormat( + "SoftwareBreakpoint::%s addr=0x%" PRIx64 + ": tried to write %zu bytes but only wrote %zu", + __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 + + size_t verify_bytes_read = 0; + error = m_process.ReadMemory(m_addr, verify_opcode, m_opcode_size, + verify_bytes_read); + if (error.Success() && verify_bytes_read < m_opcode_size) { + error.SetErrorStringWithFormat( + "SoftwareBreakpoint::%s addr=0x%" PRIx64 + ": tried to read %zu verification bytes but only read %zu", + __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) { + int i = 0; + for (const uint8_t *verify_byte = verify_opcode; + verify_byte < verify_opcode + m_opcode_size; ++verify_byte) { + log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 + " replaced byte index %d with 0x%hhx", + __FUNCTION__, m_addr, i++, *verify_byte); + } + log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64 + " -- SUCCESS", + __FUNCTION__, m_addr); + } + return error; + } else { + if (break_op_found) + error.SetErrorString("Failed to restore original opcode."); + } + } else + error.SetErrorString("Failed to read memory to verify that " + "breakpoint trap was restored."); + } } + } - if (log && error.Fail ()) - log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s", - __FUNCTION__, - m_addr, - error.AsCString()); - return error; -} - -bool -SoftwareBreakpoint::IsSoftwareBreakpoint () const -{ - return true; + 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/StringConvert.cpp b/source/Host/common/StringConvert.cpp index c4ff67515d4e..b4171437b7e2 100644 --- a/source/Host/common/StringConvert.cpp +++ b/source/Host/common/StringConvert.cpp @@ -15,103 +15,86 @@ // Project includes #include "lldb/Host/StringConvert.h" -namespace lldb_private -{ - namespace StringConvert - { +namespace lldb_private { +namespace StringConvert { - int32_t - ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) - { - if (s && s[0]) - { - char *end = nullptr; - const long sval = ::strtol (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); - return (int32_t)sval; // All characters were used, return the result - } - } - if (success_ptr) - *success_ptr = false; - return fail_value; - } +int32_t ToSInt32(const char *s, int32_t fail_value, int base, + bool *success_ptr) { + if (s && s[0]) { + char *end = nullptr; + const long sval = ::strtol(s, &end, base); + if (*end == '\0') { + if (success_ptr) + *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); + return (int32_t)sval; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} - uint32_t - ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) - { - if (s && s[0]) - { - char *end = nullptr; - const unsigned long uval = ::strtoul (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = (uval <= UINT32_MAX); - return (uint32_t)uval; // All characters were used, return the result - } - } - if (success_ptr) - *success_ptr = false; - return fail_value; - } +uint32_t ToUInt32(const char *s, uint32_t fail_value, int base, + bool *success_ptr) { + if (s && s[0]) { + char *end = nullptr; + const unsigned long uval = ::strtoul(s, &end, base); + if (*end == '\0') { + if (success_ptr) + *success_ptr = (uval <= UINT32_MAX); + return (uint32_t)uval; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} - int64_t - ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) - { - if (s && s[0]) - { - char *end = nullptr; - int64_t uval = ::strtoll (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = true; - return uval; // All characters were used, return the result - } - } - if (success_ptr) - *success_ptr = false; - return fail_value; - } +int64_t ToSInt64(const char *s, int64_t fail_value, int base, + bool *success_ptr) { + if (s && s[0]) { + char *end = nullptr; + int64_t uval = ::strtoll(s, &end, base); + if (*end == '\0') { + if (success_ptr) + *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} - uint64_t - ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) - { - if (s && s[0]) - { - char *end = nullptr; - uint64_t uval = ::strtoull (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = true; - return uval; // All characters were used, return the result - } - } - if (success_ptr) *success_ptr = false; - return fail_value; - } +uint64_t ToUInt64(const char *s, uint64_t fail_value, int base, + bool *success_ptr) { + if (s && s[0]) { + char *end = nullptr; + uint64_t uval = ::strtoull(s, &end, base); + if (*end == '\0') { + if (success_ptr) + *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} - double - ToDouble (const char *s, double fail_value, bool *success_ptr) - { - if (s && s[0]) - { - char *end = nullptr; - double val = strtod (s, &end); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = true; - return val; // All characters were used, return the result - } - } - if (success_ptr) - *success_ptr = false; - return fail_value; - } +double ToDouble(const char *s, double fail_value, bool *success_ptr) { + if (s && s[0]) { + char *end = nullptr; + double val = strtod(s, &end); + if (*end == '\0') { + if (success_ptr) + *success_ptr = true; + return val; // All characters were used, return the result } + } + if (success_ptr) + *success_ptr = false; + return fail_value; +} +} } diff --git a/source/Host/common/Symbols.cpp b/source/Host/common/Symbols.cpp index 60e1dc6bf995..461b15a07f84 100644 --- a/source/Host/common/Symbols.cpp +++ b/source/Host/common/Symbols.cpp @@ -34,294 +34,259 @@ using namespace llvm::MachO; #if defined(__APPLE__) // Forward declaration of method defined in source/Host/macosx/Symbols.cpp -int -LocateMacOSXFilesUsingDebugSymbols -( - const ModuleSpec &module_spec, - ModuleSpec &return_module_spec -); +int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, + ModuleSpec &return_module_spec); #else -int -LocateMacOSXFilesUsingDebugSymbols -( - const ModuleSpec &module_spec, - ModuleSpec &return_module_spec -) { - // Cannot find MacOSX files using debug symbols on non MacOSX. - return 0; +int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, + ModuleSpec &return_module_spec) { + // Cannot find MacOSX files using debug symbols on non MacOSX. + return 0; } #endif -static bool -FileAtPathContainsArchAndUUID (const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid) -{ - ModuleSpecList module_specs; - if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) - { - ModuleSpec spec; - for (size_t i = 0; i < module_specs.GetSize(); ++i) - { - assert(module_specs.GetModuleSpecAtIndex(i, spec)); - if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && - (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch)))) - { - return true; - } - } +static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, + const ArchSpec *arch, + const lldb_private::UUID *uuid) { + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) { + ModuleSpec spec; + for (size_t i = 0; i < module_specs.GetSize(); ++i) { + assert(module_specs.GetModuleSpecAtIndex(i, spec)); + if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == NULL || (spec.GetArchitecturePtr() && + spec.GetArchitecture().IsCompatibleMatch(*arch)))) { + return true; + } } - return false; + } + return false; } -static bool -LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); - if (exec_fspec) - { - char path[PATH_MAX]; - if (exec_fspec->GetPath(path, sizeof(path))) - { - // Make sure the module isn't already just a dSYM file... - if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) - { - if (log) - { - if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) - { - log->Printf ("Searching for dSYM bundle next to executable %s, UUID %s", path, module_spec.GetUUIDPtr()->GetAsString().c_str()); - } - else - { - log->Printf ("Searching for dSYM bundle next to executable %s", path); - } - } - size_t obj_file_path_length = strlen(path); - ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1); - ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1); - - dsym_fspec.SetFile(path, false); - - ModuleSpecList module_specs; - ModuleSpec matched_module_spec; - if (dsym_fspec.Exists() && - FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) - { - if (log) - { - log->Printf ("dSYM with matching UUID & arch found at %s", path); - } - return true; +static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, + FileSpec &dsym_fspec) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + if (exec_fspec) { + char path[PATH_MAX]; + if (exec_fspec->GetPath(path, sizeof(path))) { + // Make sure the module isn't already just a dSYM file... + if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { + if (log) { + if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) { + log->Printf( + "Searching for dSYM bundle next to executable %s, UUID %s", + path, module_spec.GetUUIDPtr()->GetAsString().c_str()); + } else { + log->Printf("Searching for dSYM bundle next to executable %s", + path); + } + } + size_t obj_file_path_length = strlen(path); + ::strncat(path, ".dSYM/Contents/Resources/DWARF/", + sizeof(path) - strlen(path) - 1); + ::strncat(path, exec_fspec->GetFilename().AsCString(), + sizeof(path) - strlen(path) - 1); + + dsym_fspec.SetFile(path, false); + + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + if (dsym_fspec.Exists() && + FileAtPathContainsArchAndUUID(dsym_fspec, + module_spec.GetArchitecturePtr(), + module_spec.GetUUIDPtr())) { + if (log) { + log->Printf("dSYM with matching UUID & arch found at %s", path); + } + return true; + } else { + path[obj_file_path_length] = '\0'; + + char *last_dot = strrchr(path, '.'); + while (last_dot != NULL && last_dot[0]) { + char *next_slash = strchr(last_dot, '/'); + if (next_slash != NULL) { + *next_slash = '\0'; + ::strncat(path, ".dSYM/Contents/Resources/DWARF/", + sizeof(path) - strlen(path) - 1); + ::strncat(path, exec_fspec->GetFilename().AsCString(), + sizeof(path) - strlen(path) - 1); + dsym_fspec.SetFile(path, false); + if (dsym_fspec.Exists() && + FileAtPathContainsArchAndUUID( + dsym_fspec, module_spec.GetArchitecturePtr(), + module_spec.GetUUIDPtr())) { + if (log) { + log->Printf("dSYM with matching UUID & arch found at %s", + path); } + return true; + } else { + *last_dot = '\0'; + char *prev_slash = strrchr(path, '/'); + if (prev_slash != NULL) + *prev_slash = '\0'; else - { - path[obj_file_path_length] = '\0'; - - char *last_dot = strrchr(path, '.'); - while (last_dot != NULL && last_dot[0]) - { - char *next_slash = strchr(last_dot, '/'); - if (next_slash != NULL) - { - *next_slash = '\0'; - ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1); - ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1); - dsym_fspec.SetFile(path, false); - if (dsym_fspec.Exists() && - FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) - { - if (log) - { - log->Printf ("dSYM with matching UUID & arch found at %s", path); - } - return true; - } - else - { - *last_dot = '\0'; - char *prev_slash = strrchr(path, '/'); - if (prev_slash != NULL) - *prev_slash = '\0'; - else - break; - } - } - else - { - break; - } - } - } + break; + } + } else { + break; } + } } + } } - dsym_fspec.Clear(); - return false; + } + dsym_fspec.Clear(); + return false; } -FileSpec -LocateExecutableSymbolFileDsym (const ModuleSpec &module_spec) -{ - const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); - const ArchSpec *arch = module_spec.GetArchitecturePtr(); - const UUID *uuid = module_spec.GetUUIDPtr(); - - Timer scoped_timer (__PRETTY_FUNCTION__, - "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", - exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", - arch ? arch->GetArchitectureName() : "<NULL>", - (const void*)uuid); - - FileSpec symbol_fspec; - ModuleSpec dsym_module_spec; - // First try and find the dSYM in the same directory as the executable or in - // an appropriate parent directory - if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false) - { - // We failed to easily find the dSYM above, so use DebugSymbols - LocateMacOSXFilesUsingDebugSymbols (module_spec, dsym_module_spec); - } - else - { - dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; - } - return dsym_module_spec.GetSymbolFileSpec(); +FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) { + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + const UUID *uuid = module_spec.GetUUIDPtr(); + + Timer scoped_timer( + LLVM_PRETTY_FUNCTION, + "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", + arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); + + FileSpec symbol_fspec; + ModuleSpec dsym_module_spec; + // First try and find the dSYM in the same directory as the executable or in + // an appropriate parent directory + if (LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec) == false) { + // We failed to easily find the dSYM above, so use DebugSymbols + LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec); + } else { + dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; + } + return dsym_module_spec.GetSymbolFileSpec(); } -ModuleSpec -Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec) -{ - ModuleSpec result; - const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); - const ArchSpec *arch = module_spec.GetArchitecturePtr(); - const UUID *uuid = module_spec.GetUUIDPtr(); - Timer scoped_timer (__PRETTY_FUNCTION__, - "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", - exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", - arch ? arch->GetArchitectureName() : "<NULL>", - (const void*)uuid); - - ModuleSpecList module_specs; - ModuleSpec matched_module_spec; - if (exec_fspec && - ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && - module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) - { - result.GetFileSpec() = exec_fspec; - } - else - { - LocateMacOSXFilesUsingDebugSymbols (module_spec, result); - } - return result; +ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { + ModuleSpec result; + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + const UUID *uuid = module_spec.GetUUIDPtr(); + Timer scoped_timer( + LLVM_PRETTY_FUNCTION, + "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", + arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); + + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + if (exec_fspec && + ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && + module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { + result.GetFileSpec() = exec_fspec; + } else { + LocateMacOSXFilesUsingDebugSymbols(module_spec, result); + } + return result; } -FileSpec -Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec) -{ - FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); - if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists()) - return symbol_file_spec; +FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { + FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); + if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists()) + return symbol_file_spec; - const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); - if (symbol_filename && symbol_filename[0]) - { - FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths()); + const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); + if (symbol_filename && symbol_filename[0]) { + FileSpecList debug_file_search_paths( + Target::GetDefaultDebugFileSearchPaths()); - // Add module directory. - const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory(); - debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true)); + // Add module directory. + const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory(); + debug_file_search_paths.AppendIfUnique( + FileSpec(file_dir.AsCString("."), true)); - // Add current working directory. - debug_file_search_paths.AppendIfUnique (FileSpec(".", true)); + // Add current working directory. + debug_file_search_paths.AppendIfUnique(FileSpec(".", true)); #ifndef LLVM_ON_WIN32 - // Add /usr/lib/debug directory. - debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true)); + // Add /usr/lib/debug directory. + debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true)); #endif // LLVM_ON_WIN32 - std::string uuid_str; - const UUID &module_uuid = module_spec.GetUUID(); - if (module_uuid.IsValid()) - { - // Some debug files are stored in the .build-id directory like this: - // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug - uuid_str = module_uuid.GetAsString(""); - uuid_str.insert (2, 1, '/'); - uuid_str = uuid_str + ".debug"; - } + std::string uuid_str; + const UUID &module_uuid = module_spec.GetUUID(); + if (module_uuid.IsValid()) { + // Some debug files are stored in the .build-id directory like this: + // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug + uuid_str = module_uuid.GetAsString(""); + uuid_str.insert(2, 1, '/'); + uuid_str = uuid_str + ".debug"; + } - size_t num_directories = debug_file_search_paths.GetSize(); - for (size_t idx = 0; idx < num_directories; ++idx) - { - FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx); - dirspec.ResolvePath(); - if (!dirspec.Exists() || !dirspec.IsDirectory()) - continue; - - std::vector<std::string> files; - std::string dirname = dirspec.GetPath(); - - files.push_back (dirname + "/" + symbol_filename); - files.push_back (dirname + "/.debug/" + symbol_filename); - files.push_back (dirname + "/.build-id/" + uuid_str); - - // Some debug files may stored in the module directory like this: - // /usr/lib/debug/usr/lib/library.so.debug - if (!file_dir.IsEmpty()) - files.push_back (dirname + file_dir.AsCString() + "/" + symbol_filename); - - const uint32_t num_files = files.size(); - for (size_t idx_file = 0; idx_file < num_files; ++idx_file) - { - const std::string &filename = files[idx_file]; - FileSpec file_spec (filename.c_str(), true); - - if (llvm::sys::fs::equivalent (file_spec.GetPath(), module_spec.GetFileSpec().GetPath())) - continue; - - if (file_spec.Exists()) - { - lldb_private::ModuleSpecList specs; - const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs); - assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture"); - if (num_specs == 1) - { - ModuleSpec mspec; - if (specs.GetModuleSpecAtIndex (0, mspec)) - { - if (mspec.GetUUID() == module_uuid) - return file_spec; - } - } - } + size_t num_directories = debug_file_search_paths.GetSize(); + for (size_t idx = 0; idx < num_directories; ++idx) { + FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); + dirspec.ResolvePath(); + if (!dirspec.Exists() || !dirspec.IsDirectory()) + continue; + + std::vector<std::string> files; + std::string dirname = dirspec.GetPath(); + + files.push_back(dirname + "/" + symbol_filename); + files.push_back(dirname + "/.debug/" + symbol_filename); + files.push_back(dirname + "/.build-id/" + uuid_str); + + // Some debug files may stored in the module directory like this: + // /usr/lib/debug/usr/lib/library.so.debug + if (!file_dir.IsEmpty()) + files.push_back(dirname + file_dir.AsCString() + "/" + symbol_filename); + + const uint32_t num_files = files.size(); + for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { + const std::string &filename = files[idx_file]; + FileSpec file_spec(filename, true); + + if (llvm::sys::fs::equivalent(file_spec.GetPath(), + module_spec.GetFileSpec().GetPath())) + continue; + + if (file_spec.Exists()) { + lldb_private::ModuleSpecList specs; + const size_t num_specs = + ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); + assert(num_specs <= 1 && + "Symbol Vendor supports only a single architecture"); + if (num_specs == 1) { + ModuleSpec mspec; + if (specs.GetModuleSpecAtIndex(0, mspec)) { + if (mspec.GetUUID() == module_uuid) + return file_spec; } + } } + } } + } - return LocateExecutableSymbolFileDsym(module_spec); + return LocateExecutableSymbolFileDsym(module_spec); } -#if !defined (__APPLE__) +#if !defined(__APPLE__) -FileSpec -Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle, - const lldb_private::UUID *uuid, - const ArchSpec *arch) -{ - // FIXME - return FileSpec(); +FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle, + const lldb_private::UUID *uuid, + const ArchSpec *arch) { + // FIXME + return FileSpec(); } -bool -Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup) -{ - // Fill in the module_spec.GetFileSpec() for the object file and/or the - // module_spec.GetSymbolFileSpec() for the debug symbols file. - return false; +bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + bool force_lookup) { + // Fill in the module_spec.GetFileSpec() for the object file and/or the + // module_spec.GetSymbolFileSpec() for the debug symbols file. + return false; } #endif diff --git a/source/Host/common/TCPSocket.cpp b/source/Host/common/TCPSocket.cpp index 07b0cdf908f5..9685ceeeadf1 100644 --- a/source/Host/common/TCPSocket.cpp +++ b/source/Host/common/TCPSocket.cpp @@ -1,4 +1,4 @@ -//===-- TcpSocket.cpp -------------------------------------------*- C++ -*-===// +//===-- TCPSocket.cpp -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +#if defined(_MSC_VER) +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + #include "lldb/Host/common/TCPSocket.h" #include "lldb/Core/Log.h" @@ -24,262 +28,233 @@ using namespace lldb_private; namespace { const int kDomain = AF_INET; -const int kType = SOCK_STREAM; - +const int kType = SOCK_STREAM; } TCPSocket::TCPSocket(NativeSocket socket, bool should_close) - : Socket(socket, ProtocolTcp, should_close) -{ - -} + : Socket(socket, ProtocolTcp, should_close) {} TCPSocket::TCPSocket(bool child_processes_inherit, Error &error) - : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, child_processes_inherit, error), true) -{ -} - + : TCPSocket(CreateSocket(kDomain, kType, IPPROTO_TCP, + child_processes_inherit, error), + true) {} // Return the port number that is being used by the socket. -uint16_t -TCPSocket::GetLocalPortNumber() const -{ - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; +uint16_t TCPSocket::GetLocalPortNumber() const { + if (m_socket != kInvalidSocketValue) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort(); + } + return 0; } -std::string -TCPSocket::GetLocalIPAddress() const -{ - // We bound to port zero, so we need to figure out which port we actually bound to - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetIPAddress (); - } - return ""; +std::string TCPSocket::GetLocalIPAddress() const { + // We bound to port zero, so we need to figure out which port we actually + // bound to + if (m_socket != kInvalidSocketValue) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getsockname(m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress(); + } + return ""; } -uint16_t -TCPSocket::GetRemotePortNumber() const -{ - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - } - return 0; +uint16_t TCPSocket::GetRemotePortNumber() const { + if (m_socket != kInvalidSocketValue) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort(); + } + return 0; } -std::string -TCPSocket::GetRemoteIPAddress () const -{ - // We bound to port zero, so we need to figure out which port we actually bound to - if (m_socket != kInvalidSocketValue) - { - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetIPAddress (); - } - return ""; +std::string TCPSocket::GetRemoteIPAddress() const { + // We bound to port zero, so we need to figure out which port we actually + // bound to + if (m_socket != kInvalidSocketValue) { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength(); + if (::getpeername(m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress(); + } + return ""; } -Error -TCPSocket::Connect(llvm::StringRef name) -{ - if (m_socket == kInvalidSocketValue) - return Error("Invalid socket"); - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION)); - if (log) - log->Printf ("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); - - Error error; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (name, host_str, port_str, port, &error)) - return error; - - struct sockaddr_in sa; - ::memset (&sa, 0, sizeof (sa)); - sa.sin_family = kDomain; - sa.sin_port = htons (port); - - int inet_pton_result = ::inet_pton (kDomain, host_str.c_str(), &sa.sin_addr); - - if (inet_pton_result <= 0) - { - struct hostent *host_entry = gethostbyname (host_str.c_str()); - if (host_entry) - host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); - inet_pton_result = ::inet_pton (kDomain, host_str.c_str(), &sa.sin_addr); - if (inet_pton_result <= 0) - { - if (inet_pton_result == -1) - SetLastError(error); - else - error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str()); - - return error; - } - } +Error TCPSocket::Connect(llvm::StringRef name) { + if (m_socket == kInvalidSocketValue) + return Error("Invalid socket"); - if (-1 == ::connect (GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) - { - SetLastError (error); - return error; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_COMMUNICATION)); + if (log) + log->Printf("TCPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); + + Error error; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + return error; + + struct sockaddr_in sa; + ::memset(&sa, 0, sizeof(sa)); + sa.sin_family = kDomain; + sa.sin_port = htons(port); + + int inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); + + if (inet_pton_result <= 0) { + struct hostent *host_entry = gethostbyname(host_str.c_str()); + if (host_entry) + host_str = ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list); + inet_pton_result = ::inet_pton(kDomain, host_str.c_str(), &sa.sin_addr); + if (inet_pton_result <= 0) { + if (inet_pton_result == -1) + SetLastError(error); + else + error.SetErrorStringWithFormat("invalid host string: '%s'", + host_str.c_str()); + + return error; } + } - // Keep our TCP packets coming without any delays. - SetOptionNoDelay(); - error.Clear(); + if (-1 == + ::connect(GetNativeSocket(), (const struct sockaddr *)&sa, sizeof(sa))) { + SetLastError(error); return error; + } + + // Keep our TCP packets coming without any delays. + SetOptionNoDelay(); + error.Clear(); + return error; } -Error -TCPSocket::Listen(llvm::StringRef name, int backlog) -{ - Error error; +Error TCPSocket::Listen(llvm::StringRef name, int backlog) { + Error error; - // enable local address reuse - SetOptionReuseAddress(); + // enable local address reuse + SetOptionReuseAddress(); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("TCPSocket::%s (%s)", __FUNCTION__, name.data()); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("TCPSocket::%s (%s)", __FUNCTION__, name.data()); - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (name, host_str, port_str, port, &error)) - return error; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + return error; - SocketAddress bind_addr; + SocketAddress bind_addr; - // Only bind to the loopback address if we are expecting a connection from - // localhost to avoid any firewall issues. - const bool bind_addr_success = (host_str == "127.0.0.1") ? - bind_addr.SetToLocalhost (kDomain, port) : - bind_addr.SetToAnyAddress (kDomain, port); + // Only bind to the loopback address if we are expecting a connection from + // localhost to avoid any firewall issues. + const bool bind_addr_success = (host_str == "127.0.0.1") + ? bind_addr.SetToLocalhost(kDomain, port) + : bind_addr.SetToAnyAddress(kDomain, port); - if (!bind_addr_success) - { - error.SetErrorString("Failed to bind port"); - return error; - } + if (!bind_addr_success) { + error.SetErrorString("Failed to bind port"); + return error; + } - int err = ::bind (GetNativeSocket(), bind_addr, bind_addr.GetLength()); - if (err != -1) - err = ::listen (GetNativeSocket(), backlog); + int err = ::bind(GetNativeSocket(), bind_addr, bind_addr.GetLength()); + if (err != -1) + err = ::listen(GetNativeSocket(), backlog); - if (err == -1) - SetLastError (error); + if (err == -1) + SetLastError(error); - return error; + return error; } -Error -TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&conn_socket) -{ - Error error; - std::string host_str; - std::string port_str; - int32_t port; - if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) - return error; - - const sa_family_t family = kDomain; - const int socktype = kType; - const int protocol = IPPROTO_TCP; - SocketAddress listen_addr; - if (host_str.empty()) - listen_addr.SetToLocalhost(family, port); - else if (host_str.compare("*") == 0) - listen_addr.SetToAnyAddress(family, port); - else - { - if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol)) - { - error.SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str()); - return error; - } +Error TCPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, + Socket *&conn_socket) { + Error error; + std::string host_str; + std::string port_str; + int32_t port; + if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + return error; + + const sa_family_t family = kDomain; + const int socktype = kType; + const int protocol = IPPROTO_TCP; + SocketAddress listen_addr; + if (host_str.empty()) + listen_addr.SetToLocalhost(family, port); + else if (host_str.compare("*") == 0) + listen_addr.SetToAnyAddress(family, port); + else { + if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, + socktype, protocol)) { + error.SetErrorStringWithFormat("unable to resolve hostname '%s'", + host_str.c_str()); + return error; } + } - bool accept_connection = false; - std::unique_ptr<TCPSocket> accepted_socket; + bool accept_connection = false; + std::unique_ptr<TCPSocket> accepted_socket; - // Loop until we are happy with our connection - while (!accept_connection) - { - struct sockaddr_in accept_addr; - ::memset (&accept_addr, 0, sizeof accept_addr); -#if !(defined (__linux__) || defined(_WIN32)) - accept_addr.sin_len = sizeof accept_addr; + // 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; + socklen_t accept_addr_len = sizeof accept_addr; - int sock = AcceptSocket (GetNativeSocket(), - (struct sockaddr *)&accept_addr, - &accept_addr_len, - child_processes_inherit, - error); + int sock = AcceptSocket(GetNativeSocket(), (struct sockaddr *)&accept_addr, + &accept_addr_len, child_processes_inherit, error); - if (error.Fail()) - break; + if (error.Fail()) + break; - bool is_same_addr = true; + bool is_same_addr = true; #if !(defined(__linux__) || (defined(_WIN32))) - is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); + is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); #endif - if (is_same_addr) - is_same_addr = (accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr); - - if (is_same_addr || (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) - { - accept_connection = true; - accepted_socket.reset(new TCPSocket(sock, true)); - } - else - { - const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; - ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - accepted_socket.reset(); - } + if (is_same_addr) + is_same_addr = (accept_addr.sin_addr.s_addr == + listen_addr.sockaddr_in().sin_addr.s_addr); + + if (is_same_addr || + (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) { + accept_connection = true; + accepted_socket.reset(new TCPSocket(sock, true)); + } else { + const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; + const uint8_t *listen_ip = + (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; + ::fprintf(stderr, "error: rejecting incoming connection from %u.%u.%u.%u " + "(expecting %u.%u.%u.%u)\n", + accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], + listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + accepted_socket.reset(); } + } - if (!accepted_socket) - return error; - - // Keep our TCP packets coming without any delays. - accepted_socket->SetOptionNoDelay(); - error.Clear(); - conn_socket = accepted_socket.release(); + if (!accepted_socket) return error; + + // Keep our TCP packets coming without any delays. + accepted_socket->SetOptionNoDelay(); + error.Clear(); + conn_socket = accepted_socket.release(); + return error; } -int -TCPSocket::SetOptionNoDelay() -{ - return SetOption (IPPROTO_TCP, TCP_NODELAY, 1); +int TCPSocket::SetOptionNoDelay() { + return SetOption(IPPROTO_TCP, TCP_NODELAY, 1); } -int -TCPSocket::SetOptionReuseAddress() -{ - return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); +int TCPSocket::SetOptionReuseAddress() { + return SetOption(SOL_SOCKET, SO_REUSEADDR, 1); } diff --git a/source/Host/common/Terminal.cpp b/source/Host/common/Terminal.cpp index 9f3abb75e919..022b3fa50a8f 100644 --- a/source/Host/common/Terminal.cpp +++ b/source/Host/common/Terminal.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Terminal.h" + +#include "lldb/Host/PosixApi.h" #include "llvm/ADT/STLExtras.h" #include <fcntl.h> @@ -17,120 +19,91 @@ #include <termios.h> #endif - using namespace lldb_private; -bool -Terminal::IsATerminal () const -{ - - return m_fd >= 0 && ::isatty (m_fd); -} - +bool Terminal::IsATerminal() const { return m_fd >= 0 && ::isatty(m_fd); } -bool -Terminal::SetEcho (bool enabled) -{ - if (FileDescriptorIsValid()) - { +bool Terminal::SetEcho(bool enabled) { + if (FileDescriptorIsValid()) { #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - if (IsATerminal ()) - { - struct termios fd_termios; - if (::tcgetattr(m_fd, &fd_termios) == 0) - { - bool set_corectly = false; - if (enabled) - { - if (fd_termios.c_lflag & ECHO) - set_corectly = true; - else - fd_termios.c_lflag |= ECHO; - } - else - { - if (fd_termios.c_lflag & ECHO) - fd_termios.c_lflag &= ~ECHO; - else - set_corectly = true; - } - - if (set_corectly) - return true; - return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0; - } + if (IsATerminal()) { + struct termios fd_termios; + if (::tcgetattr(m_fd, &fd_termios) == 0) { + bool set_corectly = false; + if (enabled) { + if (fd_termios.c_lflag & ECHO) + set_corectly = true; + else + fd_termios.c_lflag |= ECHO; + } else { + if (fd_termios.c_lflag & ECHO) + fd_termios.c_lflag &= ~ECHO; + else + set_corectly = true; } -#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED + + if (set_corectly) + return true; + return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0; + } } - return false; +#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED + } + return false; } -bool -Terminal::SetCanonical (bool enabled) -{ - if (FileDescriptorIsValid()) - { +bool Terminal::SetCanonical(bool enabled) { + if (FileDescriptorIsValid()) { #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - if (IsATerminal ()) - { - struct termios fd_termios; - if (::tcgetattr(m_fd, &fd_termios) == 0) - { - bool set_corectly = false; - if (enabled) - { - if (fd_termios.c_lflag & ICANON) - set_corectly = true; - else - fd_termios.c_lflag |= ICANON; - } - else - { - if (fd_termios.c_lflag & ICANON) - fd_termios.c_lflag &= ~ICANON; - else - set_corectly = true; - } - - if (set_corectly) - return true; - return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0; - } + if (IsATerminal()) { + struct termios fd_termios; + if (::tcgetattr(m_fd, &fd_termios) == 0) { + bool set_corectly = false; + if (enabled) { + if (fd_termios.c_lflag & ICANON) + set_corectly = true; + else + fd_termios.c_lflag |= ICANON; + } else { + if (fd_termios.c_lflag & ICANON) + fd_termios.c_lflag &= ~ICANON; + else + set_corectly = true; } -#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED + + if (set_corectly) + return true; + return ::tcsetattr(m_fd, TCSANOW, &fd_termios) == 0; + } } - return false; +#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED + } + return false; } //---------------------------------------------------------------------- // Default constructor //---------------------------------------------------------------------- -TerminalState::TerminalState() : - m_tty(), - m_tflags(-1), +TerminalState::TerminalState() + : m_tty(), m_tflags(-1), #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - m_termios_ap(), + m_termios_ap(), #endif - m_process_group(-1) -{ + m_process_group(-1) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -TerminalState::~TerminalState() -{ -} +TerminalState::~TerminalState() {} -void -TerminalState::Clear () -{ - m_tty.Clear(); - m_tflags = -1; +void TerminalState::Clear() { + m_tty.Clear(); + m_tflags = -1; #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - m_termios_ap.reset(); + m_termios_ap.reset(); #endif - m_process_group = -1; + m_process_group = -1; } //---------------------------------------------------------------------- @@ -138,142 +111,114 @@ TerminalState::Clear () // and if "save_process_group" is true, attempt to save the process // group info for the TTY. //---------------------------------------------------------------------- -bool -TerminalState::Save (int fd, bool save_process_group) -{ - m_tty.SetFileDescriptor(fd); - if (m_tty.IsATerminal()) - { +bool TerminalState::Save(int fd, bool save_process_group) { + m_tty.SetFileDescriptor(fd); + if (m_tty.IsATerminal()) { #ifndef LLDB_DISABLE_POSIX - m_tflags = ::fcntl (fd, F_GETFL, 0); + m_tflags = ::fcntl(fd, F_GETFL, 0); #endif #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - if (m_termios_ap.get() == NULL) - m_termios_ap.reset (new struct termios); - int err = ::tcgetattr (fd, m_termios_ap.get()); - if (err != 0) - m_termios_ap.reset(); + if (m_termios_ap.get() == NULL) + m_termios_ap.reset(new struct termios); + int err = ::tcgetattr(fd, m_termios_ap.get()); + if (err != 0) + m_termios_ap.reset(); #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED #ifndef LLDB_DISABLE_POSIX - if (save_process_group) - m_process_group = ::tcgetpgrp (0); - else - m_process_group = -1; -#endif - } + if (save_process_group) + m_process_group = ::tcgetpgrp(0); else - { - m_tty.Clear(); - m_tflags = -1; + m_process_group = -1; +#endif + } else { + m_tty.Clear(); + m_tflags = -1; #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - m_termios_ap.reset(); + m_termios_ap.reset(); #endif - m_process_group = -1; - } - return IsValid(); + m_process_group = -1; + } + return IsValid(); } //---------------------------------------------------------------------- // Restore the state of the TTY using the cached values from a // previous call to Save(). //---------------------------------------------------------------------- -bool -TerminalState::Restore () const -{ +bool TerminalState::Restore() const { #ifndef LLDB_DISABLE_POSIX - if (IsValid()) - { - const int fd = m_tty.GetFileDescriptor(); - if (TFlagsIsValid()) - fcntl (fd, F_SETFL, m_tflags); + if (IsValid()) { + const int fd = m_tty.GetFileDescriptor(); + if (TFlagsIsValid()) + fcntl(fd, F_SETFL, m_tflags); #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - if (TTYStateIsValid()) - tcsetattr (fd, TCSANOW, m_termios_ap.get()); + if (TTYStateIsValid()) + tcsetattr(fd, TCSANOW, m_termios_ap.get()); #endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - if (ProcessGroupIsValid()) - { - // Save the original signal handler. - void (*saved_sigttou_callback) (int) = NULL; - saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN); - // Set the process group - tcsetpgrp (fd, m_process_group); - // Restore the original signal handler. - signal (SIGTTOU, saved_sigttou_callback); - } - return true; + if (ProcessGroupIsValid()) { + // Save the original signal handler. + void (*saved_sigttou_callback)(int) = NULL; + saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN); + // Set the process group + tcsetpgrp(fd, m_process_group); + // Restore the original signal handler. + signal(SIGTTOU, saved_sigttou_callback); } + return true; + } #endif - return false; + return false; } - - - //---------------------------------------------------------------------- // Returns true if this object has valid saved TTY state settings // that can be used to restore a previous state. //---------------------------------------------------------------------- -bool -TerminalState::IsValid() const -{ - return m_tty.FileDescriptorIsValid () && (TFlagsIsValid() || TTYStateIsValid()); +bool TerminalState::IsValid() const { + return m_tty.FileDescriptorIsValid() && + (TFlagsIsValid() || TTYStateIsValid()); } //---------------------------------------------------------------------- // Returns true if m_tflags is valid //---------------------------------------------------------------------- -bool -TerminalState::TFlagsIsValid() const -{ - return m_tflags != -1; -} +bool TerminalState::TFlagsIsValid() const { return m_tflags != -1; } //---------------------------------------------------------------------- // Returns true if m_ttystate is valid //---------------------------------------------------------------------- -bool -TerminalState::TTYStateIsValid() const -{ +bool TerminalState::TTYStateIsValid() const { #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED - return m_termios_ap.get() != 0; + return m_termios_ap.get() != 0; #else - return false; + return false; #endif } //---------------------------------------------------------------------- // Returns true if m_process_group is valid //---------------------------------------------------------------------- -bool -TerminalState::ProcessGroupIsValid() const -{ - return static_cast<int32_t>(m_process_group) != -1; +bool TerminalState::ProcessGroupIsValid() const { + return static_cast<int32_t>(m_process_group) != -1; } //------------------------------------------------------------------ // Constructor //------------------------------------------------------------------ -TerminalStateSwitcher::TerminalStateSwitcher () : - m_currentState(UINT32_MAX) -{ -} +TerminalStateSwitcher::TerminalStateSwitcher() : m_currentState(UINT32_MAX) {} //------------------------------------------------------------------ // Destructor //------------------------------------------------------------------ -TerminalStateSwitcher::~TerminalStateSwitcher () -{ -} +TerminalStateSwitcher::~TerminalStateSwitcher() {} //------------------------------------------------------------------ // Returns the number of states that this switcher contains //------------------------------------------------------------------ -uint32_t -TerminalStateSwitcher::GetNumberOfStates() const -{ - return llvm::array_lengthof(m_ttystates); +uint32_t TerminalStateSwitcher::GetNumberOfStates() const { + return llvm::array_lengthof(m_ttystates); } //------------------------------------------------------------------ @@ -281,28 +226,26 @@ TerminalStateSwitcher::GetNumberOfStates() const // // Returns true if the restore was successful, false otherwise. //------------------------------------------------------------------ -bool -TerminalStateSwitcher::Restore (uint32_t idx) const -{ - const uint32_t num_states = GetNumberOfStates(); - if (idx >= num_states) - return false; - - // See if we already are in this state? - if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid()) - return true; - - // Set the state to match the index passed in and only update the - // current state if there are no errors. - if (m_ttystates[idx].Restore()) - { - m_currentState = idx; - return true; - } - - // We failed to set the state. The tty state was invalid or not - // initialized. +bool TerminalStateSwitcher::Restore(uint32_t idx) const { + const uint32_t num_states = GetNumberOfStates(); + if (idx >= num_states) return false; + + // See if we already are in this state? + if (m_currentState < num_states && (idx == m_currentState) && + m_ttystates[idx].IsValid()) + return true; + + // Set the state to match the index passed in and only update the + // current state if there are no errors. + if (m_ttystates[idx].Restore()) { + m_currentState = idx; + return true; + } + + // We failed to set the state. The tty state was invalid or not + // initialized. + return false; } //------------------------------------------------------------------ @@ -311,13 +254,10 @@ TerminalStateSwitcher::Restore (uint32_t idx) const // // Returns true if the restore was successful, false otherwise. //------------------------------------------------------------------ -bool -TerminalStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group) -{ - const uint32_t num_states = GetNumberOfStates(); - if (idx < num_states) - return m_ttystates[idx].Save(fd, save_process_group); - return false; +bool TerminalStateSwitcher::Save(uint32_t idx, int fd, + bool save_process_group) { + const uint32_t num_states = GetNumberOfStates(); + if (idx < num_states) + return m_ttystates[idx].Save(fd, save_process_group); + return false; } - - diff --git a/source/Host/common/ThisThread.cpp b/source/Host/common/ThisThread.cpp index 763701441c1a..b3f9edee2e16 100644 --- a/source/Host/common/ThisThread.cpp +++ b/source/Host/common/ThisThread.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Host/ThisThread.h" #include "lldb/Core/Error.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Host/ThisThread.h" #include "llvm/ADT/STLExtras.h" @@ -18,35 +18,33 @@ using namespace lldb; using namespace lldb_private; -void -ThisThread::SetName(llvm::StringRef name, int max_length) -{ - std::string truncated_name(name.data()); - - // Thread names are coming in like '<lldb.comm.debugger.edit>' and - // '<lldb.comm.debugger.editline>'. So just chopping the end of the string - // off leads to a lot of similar named threads. Go through the thread name - // and search for the last dot and use that. - - if (max_length > 0 && truncated_name.length() > static_cast<size_t>(max_length)) - { - // First see if we can get lucky by removing any initial or final braces. - std::string::size_type begin = truncated_name.find_first_not_of("(<"); - std::string::size_type end = truncated_name.find_last_not_of(")>."); - if (end - begin > static_cast<size_t>(max_length)) - { - // We're still too long. Since this is a dotted component, use everything after the last - // dot, up to a maximum of |length| characters. - std::string::size_type last_dot = truncated_name.rfind('.'); - if (last_dot != std::string::npos) - begin = last_dot + 1; - - end = std::min(end, begin + max_length); - } - - std::string::size_type count = end - begin + 1; - truncated_name = truncated_name.substr(begin, count); +void ThisThread::SetName(llvm::StringRef name, int max_length) { + std::string truncated_name(name.data()); + + // Thread names are coming in like '<lldb.comm.debugger.edit>' and + // '<lldb.comm.debugger.editline>'. So just chopping the end of the string + // off leads to a lot of similar named threads. Go through the thread name + // and search for the last dot and use that. + + if (max_length > 0 && + truncated_name.length() > static_cast<size_t>(max_length)) { + // First see if we can get lucky by removing any initial or final braces. + std::string::size_type begin = truncated_name.find_first_not_of("(<"); + std::string::size_type end = truncated_name.find_last_not_of(")>."); + if (end - begin > static_cast<size_t>(max_length)) { + // We're still too long. Since this is a dotted component, use everything + // after the last + // dot, up to a maximum of |length| characters. + std::string::size_type last_dot = truncated_name.rfind('.'); + if (last_dot != std::string::npos) + begin = last_dot + 1; + + end = std::min(end, begin + max_length); } - SetName(truncated_name.c_str()); + std::string::size_type count = end - begin + 1; + truncated_name = truncated_name.substr(begin, count); + } + + SetName(truncated_name); } diff --git a/source/Host/common/ThreadLauncher.cpp b/source/Host/common/ThreadLauncher.cpp index c19a23361d81..b91c2fe9baab 100644 --- a/source/Host/common/ThreadLauncher.cpp +++ b/source/Host/common/ThreadLauncher.cpp @@ -1,4 +1,5 @@ -//===-- ThreadLauncher.cpp ---------------------------------------*- C++ -*-===// +//===-- ThreadLauncher.cpp ---------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -8,11 +9,11 @@ //===----------------------------------------------------------------------===// // lldb Includes +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Core/Log.h" #include "lldb/Host/HostNativeThread.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/ThisThread.h" -#include "lldb/Host/ThreadLauncher.h" #if defined(_WIN32) #include "lldb/Host/windows/windows.h" @@ -21,64 +22,65 @@ using namespace lldb; using namespace lldb_private; -HostThread -ThreadLauncher::LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function, lldb::thread_arg_t thread_arg, Error *error_ptr, size_t min_stack_byte_size) -{ - Error error; - if (error_ptr) - error_ptr->Clear(); +HostThread ThreadLauncher::LaunchThread(llvm::StringRef name, + lldb::thread_func_t thread_function, + lldb::thread_arg_t thread_arg, + Error *error_ptr, + size_t min_stack_byte_size) { + Error error; + if (error_ptr) + error_ptr->Clear(); - // Host::ThreadCreateTrampoline will delete this pointer for us. - HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo(name.data(), thread_function, thread_arg); - lldb::thread_t thread; + // Host::ThreadCreateTrampoline will delete this pointer for us. + HostThreadCreateInfo *info_ptr = + new HostThreadCreateInfo(name.data(), thread_function, thread_arg); + lldb::thread_t thread; #ifdef _WIN32 - thread = - (lldb::thread_t)::_beginthreadex(0, (unsigned)min_stack_byte_size, HostNativeThread::ThreadCreateTrampoline, info_ptr, 0, NULL); - if (thread == (lldb::thread_t)(-1L)) - error.SetError(::GetLastError(), eErrorTypeWin32); + thread = (lldb::thread_t)::_beginthreadex( + 0, (unsigned)min_stack_byte_size, + HostNativeThread::ThreadCreateTrampoline, info_ptr, 0, NULL); + if (thread == (lldb::thread_t)(-1L)) + error.SetError(::GetLastError(), eErrorTypeWin32); #else - - // ASAN instrumentation adds a lot of bookkeeping overhead on stack frames. +// ASAN instrumentation adds a lot of bookkeeping overhead on stack frames. #if __has_feature(address_sanitizer) - const size_t eight_megabytes = 8 * 1024 * 1024; - if (min_stack_byte_size < eight_megabytes) - { - min_stack_byte_size += eight_megabytes; - } + const size_t eight_megabytes = 8 * 1024 * 1024; + if (min_stack_byte_size < eight_megabytes) { + min_stack_byte_size += eight_megabytes; + } #endif - pthread_attr_t *thread_attr_ptr = NULL; - pthread_attr_t thread_attr; - bool destroy_attr = false; - if (min_stack_byte_size > 0) - { - if (::pthread_attr_init (&thread_attr) == 0) - { - destroy_attr = true; - size_t default_min_stack_byte_size = 0; - if (::pthread_attr_getstacksize(&thread_attr, &default_min_stack_byte_size) == 0) - { - if (default_min_stack_byte_size < min_stack_byte_size) - { - if (::pthread_attr_setstacksize (&thread_attr, min_stack_byte_size) == 0) - thread_attr_ptr = &thread_attr; - } - } - + pthread_attr_t *thread_attr_ptr = NULL; + pthread_attr_t thread_attr; + bool destroy_attr = false; + if (min_stack_byte_size > 0) { + if (::pthread_attr_init(&thread_attr) == 0) { + destroy_attr = true; + size_t default_min_stack_byte_size = 0; + if (::pthread_attr_getstacksize(&thread_attr, + &default_min_stack_byte_size) == 0) { + if (default_min_stack_byte_size < min_stack_byte_size) { + if (::pthread_attr_setstacksize(&thread_attr, min_stack_byte_size) == + 0) + thread_attr_ptr = &thread_attr; } + } } - int err = ::pthread_create(&thread, thread_attr_ptr, HostNativeThread::ThreadCreateTrampoline, info_ptr); + } + int err = + ::pthread_create(&thread, thread_attr_ptr, + HostNativeThread::ThreadCreateTrampoline, info_ptr); - if (destroy_attr) - ::pthread_attr_destroy(&thread_attr); + if (destroy_attr) + ::pthread_attr_destroy(&thread_attr); - error.SetError(err, eErrorTypePOSIX); + error.SetError(err, eErrorTypePOSIX); #endif - if (error_ptr) - *error_ptr = error; - if (!error.Success()) - thread = LLDB_INVALID_HOST_THREAD; + if (error_ptr) + *error_ptr = error; + if (!error.Success()) + thread = LLDB_INVALID_HOST_THREAD; - return HostThread(thread); + return HostThread(thread); } diff --git a/source/Host/common/TimeValue.cpp b/source/Host/common/TimeValue.cpp deleted file mode 100644 index b471a3dd1f15..000000000000 --- a/source/Host/common/TimeValue.cpp +++ /dev/null @@ -1,222 +0,0 @@ -//===-- TimeValue.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/TimeValue.h" -#include "lldb/Host/Config.h" - -// C Includes -#include <stddef.h> -#include <time.h> -#include <cstring> - -#ifdef _MSC_VER -#include "lldb/Host/windows/windows.h" -#endif - -// C++ Includes -// Other libraries and framework includes -// Project includes -#include "lldb/Core/Stream.h" - - -using namespace lldb_private; - -//---------------------------------------------------------------------- -// TimeValue constructor -//---------------------------------------------------------------------- -TimeValue::TimeValue() : - m_nano_seconds (0) -{ -} - -//---------------------------------------------------------------------- -// TimeValue copy constructor -//---------------------------------------------------------------------- -TimeValue::TimeValue(const TimeValue& rhs) : - m_nano_seconds (rhs.m_nano_seconds) -{ -} - -TimeValue::TimeValue(const struct timespec& ts) : - m_nano_seconds ((uint64_t) ts.tv_sec * NanoSecPerSec + ts.tv_nsec) -{ -} - -TimeValue::TimeValue(uint32_t seconds, uint32_t nanos) : - m_nano_seconds((uint64_t) seconds * NanoSecPerSec + nanos) -{ -} - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -TimeValue::~TimeValue() -{ -} - - -uint64_t -TimeValue::GetAsNanoSecondsSinceJan1_1970() const -{ - return m_nano_seconds; -} - -uint64_t -TimeValue::GetAsMicroSecondsSinceJan1_1970() const -{ - return m_nano_seconds / NanoSecPerMicroSec; -} - -uint64_t -TimeValue::GetAsSecondsSinceJan1_1970() const -{ - return m_nano_seconds / NanoSecPerSec; -} - - - -struct timespec -TimeValue::GetAsTimeSpec () const -{ - struct timespec ts; - ts.tv_sec = m_nano_seconds / NanoSecPerSec; - ts.tv_nsec = m_nano_seconds % NanoSecPerSec; - return ts; -} - -void -TimeValue::Clear () -{ - m_nano_seconds = 0; -} - -bool -TimeValue::IsValid () const -{ - return m_nano_seconds != 0; -} - -void -TimeValue::OffsetWithSeconds (uint64_t sec) -{ - m_nano_seconds += sec * NanoSecPerSec; -} - -void -TimeValue::OffsetWithMicroSeconds (uint64_t usec) -{ - m_nano_seconds += usec * NanoSecPerMicroSec; -} - -void -TimeValue::OffsetWithNanoSeconds (uint64_t nsec) -{ - m_nano_seconds += nsec; -} - -TimeValue -TimeValue::Now() -{ - uint32_t seconds, nanoseconds; -#if _MSC_VER - SYSTEMTIME st; - GetSystemTime(&st); - nanoseconds = st.wMilliseconds * 1000000; - FILETIME ft; - SystemTimeToFileTime(&st, &ft); - - seconds = ((((uint64_t)ft.dwHighDateTime) << 32 | ft.dwLowDateTime) / 10000000) - 11644473600ULL; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - seconds = tv.tv_sec; - nanoseconds = tv.tv_usec * NanoSecPerMicroSec; -#endif - TimeValue now(seconds, nanoseconds); - return now; -} - -//---------------------------------------------------------------------- -// TimeValue assignment operator -//---------------------------------------------------------------------- -const TimeValue& -TimeValue::operator=(const TimeValue& rhs) -{ - m_nano_seconds = rhs.m_nano_seconds; - return *this; -} - -void -TimeValue::Dump (Stream *s, uint32_t width) const -{ - if (s == NULL) - return; - -#ifndef LLDB_DISABLE_POSIX - char time_buf[32]; - time_t time = GetAsSecondsSinceJan1_1970(); - char *time_cstr = ::ctime_r(&time, time_buf); - if (time_cstr) - { - char *newline = ::strpbrk(time_cstr, "\n\r"); - if (newline) - *newline = '\0'; - if (width > 0) - s->Printf("%-*s", width, time_cstr); - else - s->PutCString(time_cstr); - } - else if (width > 0) - s->Printf("%-*s", width, ""); -#endif -} - -bool -lldb_private::operator == (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() == rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -bool -lldb_private::operator != (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() != rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -bool -lldb_private::operator < (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() < rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -bool -lldb_private::operator <= (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() <= rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -bool -lldb_private::operator > (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() > rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -bool -lldb_private::operator >= (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() >= rhs.GetAsNanoSecondsSinceJan1_1970(); -} - -uint64_t -lldb_private::operator - (const TimeValue &lhs, const TimeValue &rhs) -{ - return lhs.GetAsNanoSecondsSinceJan1_1970() - rhs.GetAsNanoSecondsSinceJan1_1970(); -} - - diff --git a/source/Host/common/UDPSocket.cpp b/source/Host/common/UDPSocket.cpp index 9a2028e97a40..972f87eb73d8 100644 --- a/source/Host/common/UDPSocket.cpp +++ b/source/Host/common/UDPSocket.cpp @@ -1,4 +1,4 @@ -//===-- UdpSocket.cpp -------------------------------------------*- C++ -*-===// +//===-- UDPSocket.cpp -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -25,134 +25,113 @@ using namespace lldb_private; namespace { const int kDomain = AF_INET; -const int kType = SOCK_DGRAM; +const int kType = SOCK_DGRAM; static const char *g_not_supported_error = "Not supported"; - } -UDPSocket::UDPSocket(NativeSocket socket) - : Socket(socket, ProtocolUdp, true) -{ -} +UDPSocket::UDPSocket(NativeSocket socket) : Socket(socket, ProtocolUdp, true) {} UDPSocket::UDPSocket(bool child_processes_inherit, Error &error) - : UDPSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) -{ -} + : UDPSocket( + CreateSocket(kDomain, kType, 0, child_processes_inherit, error)) {} -size_t -UDPSocket::Send(const void *buf, const size_t num_bytes) -{ - return ::sendto (m_socket, - static_cast<const char*>(buf), - num_bytes, - 0, - m_send_sockaddr, - m_send_sockaddr.GetLength()); +size_t UDPSocket::Send(const void *buf, const size_t num_bytes) { + return ::sendto(m_socket, static_cast<const char *>(buf), num_bytes, 0, + m_send_sockaddr, m_send_sockaddr.GetLength()); } -Error -UDPSocket::Connect(llvm::StringRef name) -{ - return Error("%s", g_not_supported_error); +Error UDPSocket::Connect(llvm::StringRef name) { + return Error("%s", g_not_supported_error); } -Error -UDPSocket::Listen(llvm::StringRef name, int backlog) -{ - return Error("%s", g_not_supported_error); +Error UDPSocket::Listen(llvm::StringRef name, int backlog) { + return Error("%s", g_not_supported_error); } -Error -UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket) -{ - return Error("%s", g_not_supported_error); +Error UDPSocket::Accept(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket) { + return Error("%s", g_not_supported_error); } -Error -UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, Socket *&send_socket, Socket *&recv_socket) -{ - std::unique_ptr<UDPSocket> final_send_socket; - std::unique_ptr<UDPSocket> final_recv_socket; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf ("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); - - Error error; - std::string host_str; - std::string port_str; - int32_t port = INT32_MIN; - if (!DecodeHostAndPort (name, host_str, port_str, port, &error)) - return error; - - // Setup the receiving end of the UDP connection on this localhost - // on port zero. After we bind to port zero we can read the port. - final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); - if (error.Success()) - { - // Socket was created, now lets bind to the requested port - SocketAddress addr; - addr.SetToAnyAddress (AF_INET, 0); - - if (::bind (final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == -1) - { - // Bind failed... - SetLastError (error); - } - } +Error UDPSocket::Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&send_socket, Socket *&recv_socket) { + std::unique_ptr<UDPSocket> final_send_socket; + std::unique_ptr<UDPSocket> final_recv_socket; - assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); - if (error.Fail()) - return error; - - // At this point we have setup the receive port, now we need to - // setup the UDP send socket - - struct addrinfo hints; - struct addrinfo *service_info_list = nullptr; - - ::memset (&hints, 0, sizeof(hints)); - hints.ai_family = kDomain; - hints.ai_socktype = kType; - int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); - if (err != 0) - { - error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", - host_str.c_str(), - port_str.c_str(), - err, - gai_strerror(err)); - return error; - } + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf("UDPSocket::%s (host/port = %s)", __FUNCTION__, name.data()); - for (struct addrinfo *service_info_ptr = service_info_list; - service_info_ptr != nullptr; - service_info_ptr = service_info_ptr->ai_next) - { - auto send_fd = CreateSocket (service_info_ptr->ai_family, - service_info_ptr->ai_socktype, - service_info_ptr->ai_protocol, - child_processes_inherit, - error); - if (error.Success()) - { - final_send_socket.reset(new UDPSocket(send_fd)); - final_send_socket->m_send_sockaddr = service_info_ptr; - break; - } - else - continue; - } + Error error; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort(name, host_str, port_str, port, &error)) + return error; - :: freeaddrinfo (service_info_list); + // Setup the receiving end of the UDP connection on this localhost + // on port zero. After we bind to port zero we can read the port. + final_recv_socket.reset(new UDPSocket(child_processes_inherit, error)); + if (error.Success()) { + // Socket was created, now lets bind to the requested port + SocketAddress addr; + addr.SetToAnyAddress(AF_INET, 0); + + if (::bind(final_recv_socket->GetNativeSocket(), addr, addr.GetLength()) == + -1) { + // Bind failed... + SetLastError(error); + } + } - if (!final_send_socket) - return error; + assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); + if (error.Fail()) + return error; - send_socket = final_send_socket.release(); - recv_socket = final_recv_socket.release(); - error.Clear(); + // At this point we have setup the receive port, now we need to + // setup the UDP send socket + + struct addrinfo hints; + struct addrinfo *service_info_list = nullptr; + + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = kDomain; + hints.ai_socktype = kType; + int err = ::getaddrinfo(host_str.c_str(), port_str.c_str(), &hints, + &service_info_list); + if (err != 0) { + error.SetErrorStringWithFormat( +#if defined(_MSC_VER) && defined(UNICODE) + "getaddrinfo(%s, %s, &hints, &info) returned error %i (%S)", +#else + "getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", +#endif + host_str.c_str(), port_str.c_str(), err, gai_strerror(err)); + return error; + } + + for (struct addrinfo *service_info_ptr = service_info_list; + service_info_ptr != nullptr; + service_info_ptr = service_info_ptr->ai_next) { + auto send_fd = CreateSocket( + service_info_ptr->ai_family, service_info_ptr->ai_socktype, + service_info_ptr->ai_protocol, child_processes_inherit, error); + if (error.Success()) { + final_send_socket.reset(new UDPSocket(send_fd)); + final_send_socket->m_send_sockaddr = service_info_ptr; + break; + } else + continue; + } + + ::freeaddrinfo(service_info_list); + + if (!final_send_socket) return error; + + send_socket = final_send_socket.release(); + recv_socket = final_recv_socket.release(); + error.Clear(); + return error; } diff --git a/source/Host/common/XML.cpp b/source/Host/common/XML.cpp index dc9cb0bc5a33..c637d938dffa 100644 --- a/source/Host/common/XML.cpp +++ b/source/Host/common/XML.cpp @@ -7,685 +7,525 @@ // //===----------------------------------------------------------------------===// -#include <stdlib.h> /* atof */ +#include <stdlib.h> /* atof */ -#include "lldb/Host/XML.h" #include "lldb/Host/StringConvert.h" +#include "lldb/Host/XML.h" using namespace lldb; using namespace lldb_private; +#pragma mark-- XMLDocument -#pragma mark -- XMLDocument - -XMLDocument::XMLDocument () : - m_document (nullptr) -{ -} +XMLDocument::XMLDocument() : m_document(nullptr) {} -XMLDocument::~XMLDocument () -{ - Clear(); -} +XMLDocument::~XMLDocument() { Clear(); } -void -XMLDocument::Clear() -{ -#if defined( LIBXML2_DEFINED ) - if (m_document) - { - xmlDocPtr doc = m_document; - m_document = nullptr; - xmlFreeDoc(doc); - } +void XMLDocument::Clear() { +#if defined(LIBXML2_DEFINED) + if (m_document) { + xmlDocPtr doc = m_document; + m_document = nullptr; + xmlFreeDoc(doc); + } #endif } -bool -XMLDocument::IsValid() const -{ - return m_document != nullptr; -} +bool XMLDocument::IsValid() const { return m_document != nullptr; } -void -XMLDocument::ErrorCallback (void *ctx, const char *format, ...) -{ - XMLDocument *document = (XMLDocument *)ctx; - va_list args; - va_start (args, format); - document->m_errors.PrintfVarArg(format, args); - document->m_errors.EOL(); - va_end (args); +void XMLDocument::ErrorCallback(void *ctx, const char *format, ...) { + XMLDocument *document = (XMLDocument *)ctx; + va_list args; + va_start(args, format); + document->m_errors.PrintfVarArg(format, args); + document->m_errors.EOL(); + va_end(args); } -bool -XMLDocument::ParseFile (const char *path) -{ -#if defined( LIBXML2_DEFINED ) - Clear(); - xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback ); - m_document = xmlParseFile(path); - xmlSetGenericErrorFunc(nullptr, nullptr); +bool XMLDocument::ParseFile(const char *path) { +#if defined(LIBXML2_DEFINED) + Clear(); + xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback); + m_document = xmlParseFile(path); + xmlSetGenericErrorFunc(nullptr, nullptr); #endif - return IsValid(); + return IsValid(); } -bool -XMLDocument::ParseMemory (const char *xml, size_t xml_length, const char *url) -{ -#if defined( LIBXML2_DEFINED ) - Clear(); - xmlSetGenericErrorFunc( (void *)this, XMLDocument::ErrorCallback ); - m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0); - xmlSetGenericErrorFunc(nullptr, nullptr); +bool XMLDocument::ParseMemory(const char *xml, size_t xml_length, + const char *url) { +#if defined(LIBXML2_DEFINED) + Clear(); + xmlSetGenericErrorFunc((void *)this, XMLDocument::ErrorCallback); + m_document = xmlReadMemory(xml, (int)xml_length, url, nullptr, 0); + xmlSetGenericErrorFunc(nullptr, nullptr); #endif - return IsValid(); - -} - -XMLNode -XMLDocument::GetRootElement(const char *required_name) -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - XMLNode root_node(xmlDocGetRootElement(m_document)); - if (required_name) - { - llvm::StringRef actual_name = root_node.GetName(); - if (actual_name == required_name) - return root_node; - } - else - { - return root_node; - } + return IsValid(); +} + +XMLNode XMLDocument::GetRootElement(const char *required_name) { +#if defined(LIBXML2_DEFINED) + if (IsValid()) { + XMLNode root_node(xmlDocGetRootElement(m_document)); + if (required_name) { + llvm::StringRef actual_name = root_node.GetName(); + if (actual_name == required_name) + return root_node; + } else { + return root_node; } + } #endif - return XMLNode(); + return XMLNode(); } -const std::string & -XMLDocument::GetErrors() const -{ - return m_errors.GetString(); -} +llvm::StringRef XMLDocument::GetErrors() const { return m_errors.GetString(); } -bool -XMLDocument::XMLEnabled () -{ -#if defined( LIBXML2_DEFINED ) - return true; +bool XMLDocument::XMLEnabled() { +#if defined(LIBXML2_DEFINED) + return true; #else - return false; + return false; #endif } -#pragma mark -- XMLNode +#pragma mark-- XMLNode -XMLNode::XMLNode() : - m_node(nullptr) -{ -} +XMLNode::XMLNode() : m_node(nullptr) {} -XMLNode::XMLNode(XMLNodeImpl node) : - m_node(node) -{ -} +XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {} -XMLNode::~XMLNode() -{ - -} +XMLNode::~XMLNode() {} -void -XMLNode::Clear() -{ - m_node = nullptr; -} +void XMLNode::Clear() { m_node = nullptr; } -XMLNode -XMLNode::GetParent() const -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - return XMLNode(m_node->parent); - else - return XMLNode(); -#else +XMLNode XMLNode::GetParent() const { +#if defined(LIBXML2_DEFINED) + if (IsValid()) + return XMLNode(m_node->parent); + else return XMLNode(); +#else + return XMLNode(); #endif - } -XMLNode -XMLNode::GetSibling() const -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - return XMLNode(m_node->next); - else - return XMLNode(); -#else +XMLNode XMLNode::GetSibling() const { +#if defined(LIBXML2_DEFINED) + if (IsValid()) + return XMLNode(m_node->next); + else return XMLNode(); +#else + return XMLNode(); #endif - } -XMLNode -XMLNode::GetChild () const -{ -#if defined( LIBXML2_DEFINED ) +XMLNode XMLNode::GetChild() const { +#if defined(LIBXML2_DEFINED) - if (IsValid()) - return XMLNode(m_node->children); - else - return XMLNode(); -#else + if (IsValid()) + return XMLNode(m_node->children); + else return XMLNode(); +#else + return XMLNode(); #endif - } -llvm::StringRef -XMLNode::GetAttributeValue(const char *name, const char *fail_value) const -{ - const char *attr_value = NULL; -#if defined( LIBXML2_DEFINED ) +llvm::StringRef XMLNode::GetAttributeValue(const char *name, + const char *fail_value) const { + const char *attr_value = NULL; +#if defined(LIBXML2_DEFINED) - if (IsValid()) - attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name); - else - attr_value = fail_value; -#else + if (IsValid()) + attr_value = (const char *)xmlGetProp(m_node, (const xmlChar *)name); + else attr_value = fail_value; +#else + attr_value = fail_value; #endif - if (attr_value) - return llvm::StringRef(attr_value); - else - return llvm::StringRef(); + if (attr_value) + return llvm::StringRef(attr_value); + else + return llvm::StringRef(); } - - - -void -XMLNode::ForEachChildNode (NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - GetChild().ForEachSiblingNode(callback); +void XMLNode::ForEachChildNode(NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) + if (IsValid()) + GetChild().ForEachSiblingNode(callback); #endif } -void -XMLNode::ForEachChildElement (NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - XMLNode child = GetChild(); - if (child) - child.ForEachSiblingElement(callback); +void XMLNode::ForEachChildElement(NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) + XMLNode child = GetChild(); + if (child) + child.ForEachSiblingElement(callback); #endif } -void -XMLNode::ForEachChildElementWithName (const char *name, NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - XMLNode child = GetChild(); - if (child) - child.ForEachSiblingElementWithName(name, callback); +void XMLNode::ForEachChildElementWithName(const char *name, + NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) + XMLNode child = GetChild(); + if (child) + child.ForEachSiblingElementWithName(name, callback); #endif } -void -XMLNode::ForEachAttribute (AttributeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - for (xmlAttrPtr attr = m_node->properties; attr != nullptr; attr=attr->next) - { - // check if name matches - if (attr->name) - { - // check child is a text node - xmlNodePtr child = attr->children; - if (child->type == XML_TEXT_NODE) - { - llvm::StringRef attr_value; - if (child->content) - attr_value = llvm::StringRef((const char *)child->content); - if (callback(llvm::StringRef((const char *)attr->name), attr_value) == false) - return; - } - } +void XMLNode::ForEachAttribute(AttributeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) + + if (IsValid()) { + for (xmlAttrPtr attr = m_node->properties; attr != nullptr; + attr = attr->next) { + // check if name matches + if (attr->name) { + // check child is a text node + xmlNodePtr child = attr->children; + if (child->type == XML_TEXT_NODE) { + llvm::StringRef attr_value; + if (child->content) + attr_value = llvm::StringRef((const char *)child->content); + if (callback(llvm::StringRef((const char *)attr->name), attr_value) == + false) + return; } + } } + } #endif } +void XMLNode::ForEachSiblingNode(NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) -void -XMLNode::ForEachSiblingNode (NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - // iterate through all siblings - for (xmlNodePtr node = m_node; node; node=node->next) - { - if (callback(XMLNode(node)) == false) - return; - } + if (IsValid()) { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node = node->next) { + if (callback(XMLNode(node)) == false) + return; } + } #endif } -void -XMLNode::ForEachSiblingElement (NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - // iterate through all siblings - for (xmlNodePtr node = m_node; node; node=node->next) - { - // we are looking for element nodes only - if (node->type != XML_ELEMENT_NODE) - continue; - - if (callback(XMLNode(node)) == false) - return; - } - } -#endif -} +void XMLNode::ForEachSiblingElement(NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) -void -XMLNode::ForEachSiblingElementWithName (const char *name, NodeCallback const &callback) const -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - // iterate through all siblings - for (xmlNodePtr node = m_node; node; node=node->next) - { - // we are looking for element nodes only - if (node->type != XML_ELEMENT_NODE) - continue; - - // If name is nullptr, we take all nodes of type "t", else - // just the ones whose name matches - if (name) - { - if (strcmp((const char *)node->name, name) != 0) - continue; // Name mismatch, ignore this one - } - else - { - if (node->name) - continue; // nullptr name specified and this element has a name, ignore this one - } - - if (callback(XMLNode(node)) == false) - return; - } - } -#endif -} + if (IsValid()) { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node = node->next) { + // we are looking for element nodes only + if (node->type != XML_ELEMENT_NODE) + continue; -llvm::StringRef -XMLNode::GetName() const -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - if (m_node->name) - return llvm::StringRef((const char *)m_node->name); + if (callback(XMLNode(node)) == false) + return; } + } #endif - return llvm::StringRef(); } -bool -XMLNode::GetElementText (std::string &text) const -{ - text.clear(); -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - bool success = false; - if (m_node->type == XML_ELEMENT_NODE) - { - // check child is a text node - for (xmlNodePtr node = m_node->children; - node != nullptr; - node = node->next) - { - if (node->type == XML_TEXT_NODE) - { - text.append((const char *)node->content); - success = true; - } - } - } - return success; +void XMLNode::ForEachSiblingElementWithName( + const char *name, NodeCallback const &callback) const { +#if defined(LIBXML2_DEFINED) + + if (IsValid()) { + // iterate through all siblings + for (xmlNodePtr node = m_node; node; node = node->next) { + // we are looking for element nodes only + if (node->type != XML_ELEMENT_NODE) + continue; + + // If name is nullptr, we take all nodes of type "t", else + // just the ones whose name matches + if (name) { + if (strcmp((const char *)node->name, name) != 0) + continue; // Name mismatch, ignore this one + } else { + if (node->name) + continue; // nullptr name specified and this element has a name, + // ignore this one + } + + if (callback(XMLNode(node)) == false) + return; } + } #endif - return false; } - -bool -XMLNode::GetElementTextAsUnsigned (uint64_t &value, uint64_t fail_value, int base) const -{ - bool success = false; -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - std::string text; - if (GetElementText(text)) - value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success); - } +llvm::StringRef XMLNode::GetName() const { +#if defined(LIBXML2_DEFINED) + if (IsValid()) { + if (m_node->name) + return llvm::StringRef((const char *)m_node->name); + } #endif - if (!success) - value = fail_value; - return success; + return llvm::StringRef(); } -bool -XMLNode::GetElementTextAsFloat (double &value, double fail_value) const -{ +bool XMLNode::GetElementText(std::string &text) const { + text.clear(); +#if defined(LIBXML2_DEFINED) + if (IsValid()) { bool success = false; -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - std::string text; - if (GetElementText(text)) - { - value = atof(text.c_str()); - success = true; + if (m_node->type == XML_ELEMENT_NODE) { + // check child is a text node + for (xmlNodePtr node = m_node->children; node != nullptr; + node = node->next) { + if (node->type == XML_TEXT_NODE) { + text.append((const char *)node->content); + success = true; } + } } -#endif - if (!success) - value = fail_value; return success; + } +#endif + return false; +} + +bool XMLNode::GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value, + int base) const { + bool success = false; +#if defined(LIBXML2_DEFINED) + if (IsValid()) { + std::string text; + if (GetElementText(text)) + value = StringConvert::ToUInt64(text.c_str(), fail_value, base, &success); + } +#endif + if (!success) + value = fail_value; + return success; +} + +bool XMLNode::GetElementTextAsFloat(double &value, double fail_value) const { + bool success = false; +#if defined(LIBXML2_DEFINED) + if (IsValid()) { + std::string text; + if (GetElementText(text)) { + value = atof(text.c_str()); + success = true; + } + } +#endif + if (!success) + value = fail_value; + return success; } +bool XMLNode::NameIs(const char *name) const { +#if defined(LIBXML2_DEFINED) - -bool -XMLNode::NameIs (const char *name) const -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - // In case we are looking for a nullptr name or an exact pointer match - if (m_node->name == (const xmlChar *)name) - return true; - if (m_node->name) - return strcmp((const char *)m_node->name, name) == 0; - } + if (IsValid()) { + // In case we are looking for a nullptr name or an exact pointer match + if (m_node->name == (const xmlChar *)name) + return true; + if (m_node->name) + return strcmp((const char *)m_node->name, name) == 0; + } #endif - return false; + return false; } -XMLNode -XMLNode::FindFirstChildElementWithName (const char *name) const -{ - XMLNode result_node; +XMLNode XMLNode::FindFirstChildElementWithName(const char *name) const { + XMLNode result_node; -#if defined( LIBXML2_DEFINED ) - ForEachChildElementWithName(name, [&result_node, name](const XMLNode& node) -> bool { +#if defined(LIBXML2_DEFINED) + ForEachChildElementWithName( + name, [&result_node, name](const XMLNode &node) -> bool { result_node = node; // Stop iterating, we found the node we wanted return false; - }); + }); #endif - return result_node; + return result_node; } -bool -XMLNode::IsValid() const -{ - return m_node != nullptr; -} +bool XMLNode::IsValid() const { return m_node != nullptr; } -bool -XMLNode::IsElement () const -{ -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - return m_node->type == XML_ELEMENT_NODE; +bool XMLNode::IsElement() const { +#if defined(LIBXML2_DEFINED) + if (IsValid()) + return m_node->type == XML_ELEMENT_NODE; #endif - return false; -} - - -XMLNode -XMLNode::GetElementForPath (const NamePath &path) -{ -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - if (path.empty()) - return *this; - else - { - XMLNode node = FindFirstChildElementWithName(path[0].c_str()); - const size_t n = path.size(); - for (size_t i=1; node && i<n; ++i) - node = node.FindFirstChildElementWithName(path[i].c_str()); - return node; - } + return false; +} + +XMLNode XMLNode::GetElementForPath(const NamePath &path) { +#if defined(LIBXML2_DEFINED) + + if (IsValid()) { + if (path.empty()) + return *this; + else { + XMLNode node = FindFirstChildElementWithName(path[0].c_str()); + const size_t n = path.size(); + for (size_t i = 1; node && i < n; ++i) + node = node.FindFirstChildElementWithName(path[i].c_str()); + return node; } + } #endif - return XMLNode(); + return XMLNode(); } +#pragma mark-- ApplePropertyList -#pragma mark -- ApplePropertyList - -ApplePropertyList::ApplePropertyList() : - m_xml_doc(), - m_dict_node() -{ - -} +ApplePropertyList::ApplePropertyList() : m_xml_doc(), m_dict_node() {} -ApplePropertyList::ApplePropertyList (const char *path) : - m_xml_doc(), - m_dict_node() -{ - ParseFile(path); +ApplePropertyList::ApplePropertyList(const char *path) + : m_xml_doc(), m_dict_node() { + ParseFile(path); } -ApplePropertyList::~ApplePropertyList() -{ -} +ApplePropertyList::~ApplePropertyList() {} -const std::string & -ApplePropertyList::GetErrors() const -{ - return m_xml_doc.GetErrors(); +llvm::StringRef ApplePropertyList::GetErrors() const { + return m_xml_doc.GetErrors(); } - -bool -ApplePropertyList::ParseFile (const char *path) -{ - if (m_xml_doc.ParseFile(path)) - { - XMLNode plist = m_xml_doc.GetRootElement("plist"); - if (plist) - { - plist.ForEachChildElementWithName("dict", [this](const XMLNode &dict) -> bool { - this->m_dict_node = dict; - return false; // Stop iterating - }); - return (bool)m_dict_node; - } +bool ApplePropertyList::ParseFile(const char *path) { + if (m_xml_doc.ParseFile(path)) { + XMLNode plist = m_xml_doc.GetRootElement("plist"); + if (plist) { + plist.ForEachChildElementWithName("dict", + [this](const XMLNode &dict) -> bool { + this->m_dict_node = dict; + return false; // Stop iterating + }); + return (bool)m_dict_node; } - return false; -} - -bool -ApplePropertyList::IsValid() const -{ - return (bool)m_dict_node; -} - -bool -ApplePropertyList::GetValueAsString (const char *key, std::string &value) const -{ - XMLNode value_node = GetValueNode (key); - if (value_node) - return ApplePropertyList::ExtractStringFromValueNode(value_node, value); - return false; -} - -XMLNode -ApplePropertyList::GetValueNode (const char *key) const -{ - XMLNode value_node; -#if defined( LIBXML2_DEFINED ) - - if (IsValid()) - { - m_dict_node.ForEachChildElementWithName("key", [key, &value_node](const XMLNode &key_node) -> bool { - std::string key_name; - if (key_node.GetElementText(key_name)) - { - if (key_name.compare(key) == 0) - { - value_node = key_node.GetSibling(); - while (value_node && !value_node.IsElement()) - value_node = value_node.GetSibling(); - return false; // Stop iterating - } + } + return false; +} + +bool ApplePropertyList::IsValid() const { return (bool)m_dict_node; } + +bool ApplePropertyList::GetValueAsString(const char *key, + std::string &value) const { + XMLNode value_node = GetValueNode(key); + if (value_node) + return ApplePropertyList::ExtractStringFromValueNode(value_node, value); + return false; +} + +XMLNode ApplePropertyList::GetValueNode(const char *key) const { + XMLNode value_node; +#if defined(LIBXML2_DEFINED) + + if (IsValid()) { + m_dict_node.ForEachChildElementWithName( + "key", [key, &value_node](const XMLNode &key_node) -> bool { + std::string key_name; + if (key_node.GetElementText(key_name)) { + if (key_name.compare(key) == 0) { + value_node = key_node.GetSibling(); + while (value_node && !value_node.IsElement()) + value_node = value_node.GetSibling(); + return false; // Stop iterating } - return true; // Keep iterating + } + return true; // Keep iterating }); - } + } #endif - return value_node; -} - -bool -ApplePropertyList::ExtractStringFromValueNode (const XMLNode &node, std::string &value) -{ - value.clear(); -#if defined( LIBXML2_DEFINED ) - if (node.IsValid()) - { - llvm::StringRef element_name = node.GetName(); - if (element_name == "true" || element_name == "false") - { - // The text value _is_ the element name itself... - value = element_name.str(); - return true; - } - else if (element_name == "dict" || element_name == "array") - return false; // dictionaries and arrays have no text value, so we fail - else - return node.GetElementText(value); - } + return value_node; +} + +bool ApplePropertyList::ExtractStringFromValueNode(const XMLNode &node, + std::string &value) { + value.clear(); +#if defined(LIBXML2_DEFINED) + if (node.IsValid()) { + llvm::StringRef element_name = node.GetName(); + if (element_name == "true" || element_name == "false") { + // The text value _is_ the element name itself... + value = element_name.str(); + return true; + } else if (element_name == "dict" || element_name == "array") + return false; // dictionaries and arrays have no text value, so we fail + else + return node.GetElementText(value); + } #endif - return false; + return false; } -#if defined( LIBXML2_DEFINED ) +#if defined(LIBXML2_DEFINED) namespace { - StructuredData::ObjectSP - CreatePlistValue (XMLNode node) - { - llvm::StringRef element_name = node.GetName(); - if (element_name == "array") - { - std::shared_ptr<StructuredData::Array> array_sp(new StructuredData::Array()); - node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool { - array_sp->AddItem(CreatePlistValue(node)); - return true; // Keep iterating through all child elements of the array - }); - return array_sp; - } - else if (element_name == "dict") - { - XMLNode key_node; - std::shared_ptr<StructuredData::Dictionary> dict_sp(new StructuredData::Dictionary()); - node.ForEachChildElement([&key_node, &dict_sp](const XMLNode &node) -> bool { - if (node.NameIs("key")) - { - // This is a "key" element node - key_node = node; - } - else - { - // This is a value node - if (key_node) - { - std::string key_name; - key_node.GetElementText(key_name); - dict_sp->AddItem(key_name, CreatePlistValue(node)); - key_node.Clear(); - } - } - return true; // Keep iterating through all child elements of the dictionary - }); - return dict_sp; - } - else if (element_name == "real") - { - double value = 0.0; - node.GetElementTextAsFloat(value); - return StructuredData::ObjectSP(new StructuredData::Float(value)); - } - else if (element_name == "integer") - { - uint64_t value = 0; - node.GetElementTextAsUnsigned(value, 0, 0); - return StructuredData::ObjectSP(new StructuredData::Integer(value)); - } - else if ((element_name == "string") || (element_name == "data") || (element_name == "date")) - { - std::string text; - node.GetElementText(text); - return StructuredData::ObjectSP(new StructuredData::String(std::move(text))); - } - else if (element_name == "true") - { - return StructuredData::ObjectSP(new StructuredData::Boolean(true)); - } - else if (element_name == "false") - { - return StructuredData::ObjectSP(new StructuredData::Boolean(false)); - } - return StructuredData::ObjectSP(new StructuredData::Null()); - } +StructuredData::ObjectSP CreatePlistValue(XMLNode node) { + llvm::StringRef element_name = node.GetName(); + if (element_name == "array") { + std::shared_ptr<StructuredData::Array> array_sp( + new StructuredData::Array()); + node.ForEachChildElement([&array_sp](const XMLNode &node) -> bool { + array_sp->AddItem(CreatePlistValue(node)); + return true; // Keep iterating through all child elements of the array + }); + return array_sp; + } else if (element_name == "dict") { + XMLNode key_node; + std::shared_ptr<StructuredData::Dictionary> dict_sp( + new StructuredData::Dictionary()); + node.ForEachChildElement( + [&key_node, &dict_sp](const XMLNode &node) -> bool { + if (node.NameIs("key")) { + // This is a "key" element node + key_node = node; + } else { + // This is a value node + if (key_node) { + std::string key_name; + key_node.GetElementText(key_name); + dict_sp->AddItem(key_name, CreatePlistValue(node)); + key_node.Clear(); + } + } + return true; // Keep iterating through all child elements of the + // dictionary + }); + return dict_sp; + } else if (element_name == "real") { + double value = 0.0; + node.GetElementTextAsFloat(value); + return StructuredData::ObjectSP(new StructuredData::Float(value)); + } else if (element_name == "integer") { + uint64_t value = 0; + node.GetElementTextAsUnsigned(value, 0, 0); + return StructuredData::ObjectSP(new StructuredData::Integer(value)); + } else if ((element_name == "string") || (element_name == "data") || + (element_name == "date")) { + std::string text; + node.GetElementText(text); + return StructuredData::ObjectSP( + new StructuredData::String(std::move(text))); + } else if (element_name == "true") { + return StructuredData::ObjectSP(new StructuredData::Boolean(true)); + } else if (element_name == "false") { + return StructuredData::ObjectSP(new StructuredData::Boolean(false)); + } + return StructuredData::ObjectSP(new StructuredData::Null()); +} } #endif -StructuredData::ObjectSP -ApplePropertyList::GetStructuredData() -{ - StructuredData::ObjectSP root_sp; -#if defined( LIBXML2_DEFINED ) - if (IsValid()) - { - return CreatePlistValue(m_dict_node); - } +StructuredData::ObjectSP ApplePropertyList::GetStructuredData() { + StructuredData::ObjectSP root_sp; +#if defined(LIBXML2_DEFINED) + if (IsValid()) { + return CreatePlistValue(m_dict_node); + } #endif - return root_sp; + return root_sp; } |