diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Host/common')
25 files changed, 3613 insertions, 1578 deletions
diff --git a/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp b/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp index 7bc6b65..1c1afb4 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Condition.cpp @@ -57,11 +57,6 @@ Condition::Signal () return ::pthread_cond_signal (&m_condition); } -/* convert struct timeval to ms(milliseconds) */ -static unsigned long int tv2ms(struct timeval a) { - return ((a.tv_sec * 1000) + (a.tv_usec / 1000)); -} - //---------------------------------------------------------------------- // The Wait() function atomically blocks the current thread // waiting on the owned condition variable, and unblocks the mutex diff --git a/contrib/llvm/tools/lldb/source/Host/common/DynamicLibrary.cpp b/contrib/llvm/tools/lldb/source/Host/common/DynamicLibrary.cpp deleted file mode 100644 index 315a675..0000000 --- a/contrib/llvm/tools/lldb/source/Host/common/DynamicLibrary.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- DynamicLibrary.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Core/Error.h" -#include "lldb/Host/DynamicLibrary.h" - -using namespace lldb_private; - -DynamicLibrary::DynamicLibrary (const FileSpec& spec, uint32_t options) : m_filespec(spec) -{ - Error err; - m_handle = Host::DynamicLibraryOpen (spec,options,err); - if (err.Fail()) - m_handle = NULL; -} - -bool -DynamicLibrary::IsValid () -{ - return m_handle != NULL; -} - -DynamicLibrary::~DynamicLibrary () -{ - if (m_handle) - Host::DynamicLibraryClose (m_handle); -} diff --git a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp index 679aadd..7af9f39 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp @@ -20,30 +20,158 @@ using namespace lldb; using namespace lldb_private; +namespace lldb_private { + typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP; + + + // EditlineHistory objects are sometimes shared between multiple + // Editline instances with the same program name. This class allows + // multiple editline instances to + // + + class EditlineHistory + { + private: + // Use static GetHistory() function to get a EditlineHistorySP to one of these objects + EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries) : + m_history (NULL), + m_event (), + m_prefix (prefix), + m_path () + { + m_history = ::history_init(); + ::history (m_history, &m_event, H_SETSIZE, size); + if (unique_entries) + ::history (m_history, &m_event, H_SETUNIQUE, 1); + } + + const char * + GetHistoryFilePath() + { + if (m_path.empty() && m_history && !m_prefix.empty()) + { + char history_path[PATH_MAX]; + ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_prefix.c_str()); + m_path = std::move(FileSpec(history_path, true).GetPath()); + } + if (m_path.empty()) + return NULL; + return m_path.c_str(); + } + + public: + + ~EditlineHistory() + { + Save (); + + if (m_history) + { + ::history_end (m_history); + m_history = NULL; + } + } + + static EditlineHistorySP + GetHistory (const std::string &prefix) + { + typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap; + static Mutex g_mutex(Mutex::eMutexTypeRecursive); + static WeakHistoryMap g_weak_map; + Mutex::Locker locker (g_mutex); + WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix); + EditlineHistorySP history_sp; + if (pos != g_weak_map.end()) + { + history_sp = pos->second.lock(); + if (history_sp) + return history_sp; + g_weak_map.erase(pos); + } + history_sp.reset(new EditlineHistory(prefix, 800, true)); + g_weak_map[prefix] = history_sp; + return history_sp; + } + + bool IsValid() const + { + return m_history != NULL; + } + + ::History * + GetHistoryPtr () + { + return m_history; + } + + void + Enter (const char *line_cstr) + { + if (m_history) + ::history (m_history, &m_event, H_ENTER, line_cstr); + } + + bool + Load () + { + if (m_history) + { + const char *path = GetHistoryFilePath(); + if (path) + { + ::history (m_history, &m_event, H_LOAD, path); + return true; + } + } + return false; + } + + bool + Save () + { + if (m_history) + { + const char *path = GetHistoryFilePath(); + if (path) + { + ::history (m_history, &m_event, H_SAVE, path); + return true; + } + } + return false; + } + + protected: + ::History *m_history; // The history object + ::HistEvent m_event;// The history event needed to contain all history events + std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history + std::string m_path; // Path to the history file + }; +} + + static const char k_prompt_escape_char = '\1'; Editline::Editline (const char *prog, // prog can't be NULL const char *prompt, // can be NULL for no prompt + bool configure_for_multiline, FILE *fin, FILE *fout, FILE *ferr) : m_editline (NULL), - m_history (NULL), - m_history_event (), - m_program (), + m_history_sp (), m_prompt (), m_lines_prompt (), - m_getc_buffer (), - m_getc_mutex (Mutex::eMutexTypeNormal), - m_getc_cond (), -// m_gets_mutex (Mutex::eMutexTypeNormal), + m_getting_char (false), m_completion_callback (NULL), m_completion_callback_baton (NULL), m_line_complete_callback (NULL), m_line_complete_callback_baton (NULL), m_lines_command (Command::None), + m_line_offset (0), m_lines_curr_line (0), m_lines_max_line (0), + m_file (fileno(fin), false), m_prompt_with_line_numbers (false), m_getting_line (false), m_got_eof (false), @@ -51,14 +179,16 @@ Editline::Editline (const char *prog, // prog can't be NULL { if (prog && prog[0]) { - m_program = prog; m_editline = ::el_init(prog, fin, fout, ferr); - m_history = ::history_init(); + + // Get a shared history instance + m_history_sp = EditlineHistory::GetHistory(prog); } else { m_editline = ::el_init("lldb-tmp", fin, fout, ferr); } + if (prompt && prompt[0]) SetPrompt (prompt); @@ -76,28 +206,44 @@ Editline::Editline (const char *prog, // prog can't be NULL ::el_set (m_editline, EL_PROMPT, GetPromptCallback); #endif ::el_set (m_editline, EL_EDITOR, "emacs"); - if (m_history) + if (m_history_sp && m_history_sp->IsValid()) { - ::el_set (m_editline, EL_HIST, history, m_history); + ::el_set (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); } ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete); + // Keep old "lldb_complete" mapping for older clients that used this in their .editrc. editline also + // has a bad bug where if you have a bind command that tries to bind to a function name that doesn't + // exist, it will corrupt the heap and probably crash your process later. + ::el_set (m_editline, EL_ADDFN, "lldb_complete", "Editline completion function", Editline::CallbackComplete); ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine); ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine); ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. - ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte + ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be auto complete + + if (configure_for_multiline) + { + // Use escape sequences for control characters due to bugs in editline + // where "-k up" and "-k down" don't always work. + ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow + ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow + // Bindings for next/prev history + ::el_set (m_editline, EL_BIND, "^P", "ed-prev-history", NULL); // Map up arrow + ::el_set (m_editline, EL_BIND, "^N", "ed-next-history", NULL); // Map down arrow + } + else + { + // Use escape sequences for control characters due to bugs in editline + // where "-k up" and "-k down" don't always work. + ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow + ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow + } // Source $PWD/.editrc then $HOME/.editrc ::el_source (m_editline, NULL); - if (m_history) - { - ::history (m_history, &m_history_event, H_SETSIZE, 800); - ::history (m_history, &m_history_event, H_SETUNIQUE, 1); - } - // Always read through our callback function so we don't read // stuff we aren't supposed to. This also stops the extra echoing // that can happen when you have more input than editline can handle @@ -109,14 +255,12 @@ Editline::Editline (const char *prog, // prog can't be NULL Editline::~Editline() { - SaveHistory(); - - if (m_history) - { - ::history_end (m_history); - m_history = NULL; - } - + // EditlineHistory objects are sometimes shared between multiple + // Editline instances with the same program name. So just release + // our shared pointer and if we are the last owner, it will save the + // history to the history save file automatically. + m_history_sp.reset(); + // Disable edit mode to stop the terminal from flushing all input // during the call to el_end() since we expect to have multiple editline // instances in this program. @@ -132,36 +276,19 @@ Editline::SetGetCharCallback (GetCharCallbackType callback) ::el_set (m_editline, EL_GETCFN, callback); } -FileSpec -Editline::GetHistoryFile() -{ - char history_path[PATH_MAX]; - ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str()); - return FileSpec(history_path, true); -} - bool Editline::LoadHistory () { - if (m_history) - { - FileSpec history_file(GetHistoryFile()); - if (history_file.Exists()) - ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str()); - return true; - } + if (m_history_sp) + return m_history_sp->Load(); return false; } bool Editline::SaveHistory () { - if (m_history) - { - std::string history_path = GetHistoryFile().GetPath(); - ::history (m_history, &m_history_event, H_SAVE, history_path.c_str()); - return true; - } + if (m_history_sp) + return m_history_sp->Save(); return false; } @@ -180,13 +307,8 @@ Editline::PrivateGetLine(std::string &line) if (m_editline != NULL) { int line_len = 0; - const char *line_cstr = NULL; // Call el_gets to prompt the user and read the user's input. -// { -// // Make sure we know when we are in el_gets() by using a mutex -// Mutex::Locker locker (m_gets_mutex); - line_cstr = ::el_gets (m_editline, &line_len); -// } + const char *line_cstr = ::el_gets (m_editline, &line_len); static int save_errno = (line_len < 0) ? errno : 0; @@ -198,20 +320,18 @@ Editline::PrivateGetLine(std::string &line) { // Decrement the length so we don't have newline characters in "line" for when // we assign the cstr into the std::string - while (line_len > 0 && - (line_cstr[line_len - 1] == '\n' || - line_cstr[line_len - 1] == '\r')) - --line_len; + llvm::StringRef line_ref (line_cstr); + line_ref = line_ref.rtrim("\n\r"); - if (line_len > 0) + if (!line_ref.empty() && !m_interrupted) { // We didn't strip the newlines, we just adjusted the length, and // we want to add the history item with the newlines - if (m_history) - ::history (m_history, &m_history_event, H_ENTER, line_cstr); + if (m_history_sp) + m_history_sp->Enter(line_cstr); // Copy the part of the c string that we want (removing the newline chars) - line.assign(line_cstr, line_len); + line = std::move(line_ref.str()); } } } @@ -224,15 +344,14 @@ Editline::PrivateGetLine(std::string &line) Error -Editline::GetLine(std::string &line) +Editline::GetLine(std::string &line, bool &interrupted) { Error error; + interrupted = false; line.clear(); // Set arrow key bindings for up and down arrows for single line // mode where up and down arrows do prev/next history - ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow - ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow m_interrupted = false; if (!m_got_eof) @@ -252,6 +371,8 @@ Editline::GetLine(std::string &line) m_getting_line = false; } + interrupted = m_interrupted; + if (m_got_eof && line.empty()) { // Only set the error if we didn't get an error back from PrivateGetLine() @@ -278,9 +399,10 @@ Editline::Push (const char *bytes, size_t len) Error -Editline::GetLines(const std::string &end_line, StringList &lines) +Editline::GetLines(const std::string &end_line, StringList &lines, bool &interrupted) { Error error; + interrupted = false; if (m_getting_line) { error.SetErrorString("already getting a line"); @@ -294,10 +416,6 @@ Editline::GetLines(const std::string &end_line, StringList &lines) // Set arrow key bindings for up and down arrows for multiple line // mode where up and down arrows do edit prev/next line - ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow - ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow - ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL); - ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL); m_interrupted = false; LineStatus line_status = LineStatus::Success; @@ -321,6 +439,11 @@ Editline::GetLines(const std::string &end_line, StringList &lines) { line_status = LineStatus::Error; } + else if (m_interrupted) + { + interrupted = true; + line_status = LineStatus::Done; + } else { switch (m_lines_command) @@ -385,7 +508,7 @@ Editline::GetLines(const std::string &end_line, StringList &lines) // If we have a callback, call it one more time to let the // user know the lines are complete - if (m_line_complete_callback) + if (m_line_complete_callback && !interrupted) m_line_complete_callback (this, lines, UINT32_MAX, @@ -599,70 +722,78 @@ Editline::GetPromptCallback (::EditLine *e) return ""; } -size_t -Editline::SetInputBuffer (const char *c, size_t len) -{ - if (c && len > 0) - { - Mutex::Locker locker(m_getc_mutex); - SetGetCharCallback(GetCharInputBufferCallback); - m_getc_buffer.append(c, len); - m_getc_cond.Broadcast(); - } - return len; -} - -int -Editline::GetChar (char *c) -{ - Mutex::Locker locker(m_getc_mutex); - if (m_getc_buffer.empty()) - m_getc_cond.Wait(m_getc_mutex); - if (m_getc_buffer.empty()) - return 0; - *c = m_getc_buffer[0]; - m_getc_buffer.erase(0,1); - return 1; -} - -int -Editline::GetCharInputBufferCallback (EditLine *e, char *c) -{ - Editline *editline = GetClientData (e); - if (editline) - return editline->GetChar(c); - return 0; -} - int Editline::GetCharFromInputFileCallback (EditLine *e, char *c) { Editline *editline = GetClientData (e); if (editline && editline->m_got_eof == false) { - char ch = ::fgetc(editline->GetInputFile()); - if (ch == '\x04') - { - // Only turn a CTRL+D into a EOF if we receive the - // CTRL+D an empty line, otherwise it will forward - // delete the character at the cursor - const LineInfo *line_info = ::el_line(e); - if (line_info != NULL && - line_info->buffer == line_info->cursor && - line_info->cursor == line_info->lastchar) - { - ch = EOF; - } - } - - if (ch == EOF) + FILE *f = editline->GetInputFile(); + if (f == NULL) { editline->m_got_eof = true; + return 0; } - else + + + while (1) { - *c = ch; - return 1; + lldb::ConnectionStatus status = eConnectionStatusSuccess; + char ch = 0; + // When we start to call el_gets() the editline library needs to + // output the prompt + editline->m_getting_char.SetValue(true, eBroadcastAlways); + const size_t n = editline->m_file.Read(&ch, 1, UINT32_MAX, status, NULL); + editline->m_getting_char.SetValue(false, eBroadcastAlways); + if (n) + { + if (ch == '\x04') + { + // Only turn a CTRL+D into a EOF if we receive the + // CTRL+D an empty line, otherwise it will forward + // delete the character at the cursor + const LineInfo *line_info = ::el_line(e); + if (line_info != NULL && + line_info->buffer == line_info->cursor && + line_info->cursor == line_info->lastchar) + { + editline->m_got_eof = true; + break; + } + } + + if (status == eConnectionStatusEndOfFile) + { + editline->m_got_eof = true; + break; + } + else + { + *c = ch; + return 1; + } + } + else + { + switch (status) + { + case eConnectionStatusInterrupted: + editline->m_interrupted = true; + *c = '\n'; + return 1; + + case eConnectionStatusSuccess: // Success + break; + + case eConnectionStatusError: // Check GetError() for details + case eConnectionStatusTimedOut: // Request timed out + case eConnectionStatusEndOfFile: // End-of-file encountered + case eConnectionStatusNoConnection: // No connection + case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection + editline->m_got_eof = true; + break; + } + } } } return 0; @@ -671,12 +802,23 @@ Editline::GetCharFromInputFileCallback (EditLine *e, char *c) void Editline::Hide () { - FILE *out_file = GetOutputFile(); - if (out_file) + if (m_getting_line) { - const LineInfo *line_info = ::el_line(m_editline); - if (line_info) - ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); + // If we are getting a line, we might have started to call el_gets() and + // it might be printing the prompt. Here we make sure we are actually getting + // a character. This way we know the entire prompt has been printed. + TimeValue timeout = TimeValue::Now(); + timeout.OffsetWithSeconds(1); + if (m_getting_char.WaitForValueEqualTo(true, &timeout)) + { + FILE *out_file = GetOutputFile(); + if (out_file) + { + const LineInfo *line_info = ::el_line(m_editline); + if (line_info) + ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); + } + } } } @@ -684,13 +826,25 @@ Editline::Hide () void Editline::Refresh() { - ::el_set (m_editline, EL_REFRESH); + if (m_getting_line) + { + // If we are getting a line, we might have started to call el_gets() and + // it might be printing the prompt. Here we make sure we are actually getting + // a character. This way we know the entire prompt has been printed. + TimeValue timeout = TimeValue::Now(); + timeout.OffsetWithSeconds(1); + if (m_getting_char.WaitForValueEqualTo(true, &timeout)) + { + ::el_set (m_editline, EL_REFRESH); + } + } } -void +bool Editline::Interrupt () { m_interrupted = true; if (m_getting_line || m_lines_curr_line > 0) - el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets() + return m_file.InterruptRead(); + return false; // Interrupt not handled as we weren't getting a line or lines } diff --git a/contrib/llvm/tools/lldb/source/Host/common/File.cpp b/contrib/llvm/tools/lldb/source/Host/common/File.cpp index bb0ee39..50513af 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/File.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/File.cpp @@ -24,6 +24,7 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" #include "lldb/Host/Config.h" #include "lldb/Host/FileSpec.h" @@ -77,11 +78,11 @@ int File::kInvalidDescriptor = -1; FILE * File::kInvalidStream = NULL; File::File(const char *path, uint32_t options, uint32_t permissions) : + IOObject(eFDTypeFile, false), m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (), m_own_stream (false), - m_own_descriptor (false), m_is_interactive (eLazyBoolCalculate), m_is_real_terminal (eLazyBoolCalculate) { @@ -91,11 +92,11 @@ File::File(const char *path, uint32_t options, uint32_t permissions) : File::File (const FileSpec& filespec, uint32_t options, uint32_t permissions) : + IOObject(eFDTypeFile, false), m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), m_own_stream (false), - m_own_descriptor (false), m_is_interactive (eLazyBoolCalculate), m_is_real_terminal (eLazyBoolCalculate) @@ -107,11 +108,11 @@ File::File (const FileSpec& filespec, } File::File (const File &rhs) : + IOObject(eFDTypeFile, false), m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), m_own_stream (false), - m_own_descriptor (false), m_is_interactive (eLazyBoolCalculate), m_is_real_terminal (eLazyBoolCalculate) { @@ -148,13 +149,20 @@ File::GetDescriptor() const return kInvalidDescriptor; } +IOObject::WaitableHandle +File::GetWaitableHandle() +{ + return m_descriptor; +} + + void File::SetDescriptor (int fd, bool transfer_ownership) { if (IsValid()) Close(); m_descriptor = fd; - m_own_descriptor = transfer_ownership; + m_should_close_fd = transfer_ownership; } @@ -168,7 +176,7 @@ File::GetStream () const char *mode = GetStreamOpenModeFromOptions (m_options); if (mode) { - if (!m_own_descriptor) + if (!m_should_close_fd) { // We must duplicate the file descriptor if we don't own it because // when you call fdopen, the stream will own the fd @@ -177,7 +185,7 @@ File::GetStream () #else m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD); #endif - m_own_descriptor = true; + m_should_close_fd = true; } do @@ -191,7 +199,7 @@ File::GetStream () if (m_stream) { m_own_stream = true; - m_own_descriptor = false; + m_should_close_fd = false; } } } @@ -228,7 +236,7 @@ File::Duplicate (const File &rhs) else { m_options = rhs.m_options; - m_own_descriptor = true; + m_should_close_fd = true; } } else @@ -307,7 +315,7 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) error.SetErrorToErrno(); else { - m_own_descriptor = true; + m_should_close_fd = true; m_options = options; } @@ -371,7 +379,7 @@ File::Close () error.SetErrorToErrno(); } - if (DescriptorIsValid() && m_own_descriptor) + if (DescriptorIsValid() && m_should_close_fd) { if (::close (m_descriptor) != 0) error.SetErrorToErrno(); @@ -380,7 +388,7 @@ File::Close () m_stream = kInvalidStream; m_options = 0; m_own_stream = false; - m_own_descriptor = false; + m_should_close_fd = false; m_is_interactive = eLazyBoolCalculate; m_is_real_terminal = eLazyBoolCalculate; return error; @@ -669,6 +677,7 @@ File::Write (const void *buf, size_t &num_bytes) num_bytes = 0; error.SetErrorString("invalid file handle"); } + return error; } @@ -887,7 +896,13 @@ File::CalculateInteractiveAndTerminal () { m_is_interactive = eLazyBoolNo; m_is_real_terminal = eLazyBoolNo; -#ifndef _MSC_VER +#ifdef _WIN32 + if (_isatty(fd)) + { + m_is_interactive = eLazyBoolYes; + m_is_real_terminal = eLazyBoolYes; + } +#else if (isatty(fd)) { m_is_interactive = eLazyBoolYes; diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp new file mode 100644 index 0000000..96b2a2e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/FileCache.cpp @@ -0,0 +1,127 @@ +//===-- FileCache.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/FileCache.h" + +#include "lldb/Host/File.h" + +using namespace lldb; +using namespace lldb_private; + +FileCache *FileCache::m_instance = nullptr; + +FileCache & +FileCache::GetInstance() +{ + if (m_instance == nullptr) + m_instance = new FileCache(); + + return *m_instance; +} + +lldb::user_id_t +FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags, uint32_t mode, Error &error) +{ + std::string path(file_spec.GetPath()); + if (path.empty()) + { + error.SetErrorString("empty path"); + return UINT64_MAX; + } + FileSP file_sp(new File()); + error = file_sp->Open(path.c_str(), flags, mode); + if (file_sp->IsValid() == false) + return UINT64_MAX; + lldb::user_id_t fd = file_sp->GetDescriptor(); + m_cache[fd] = file_sp; + return fd; +} + +bool +FileCache::CloseFile(lldb::user_id_t fd, Error &error) +{ + if (fd == UINT64_MAX) + { + error.SetErrorString("invalid file descriptor"); + return false; + } + FDToFileMap::iterator pos = m_cache.find(fd); + if (pos == m_cache.end()) + { + error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd); + return false; + } + FileSP file_sp = pos->second; + if (!file_sp) + { + error.SetErrorString("invalid host backing file"); + return false; + } + error = file_sp->Close(); + m_cache.erase(pos); + return error.Success(); +} + +uint64_t +FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, uint64_t src_len, Error &error) +{ + if (fd == UINT64_MAX) + { + error.SetErrorString("invalid file descriptor"); + return UINT64_MAX; + } + FDToFileMap::iterator pos = m_cache.find(fd); + if (pos == m_cache.end()) + { + error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd); + return false; + } + FileSP file_sp = pos->second; + if (!file_sp) + { + error.SetErrorString("invalid host backing file"); + return UINT64_MAX; + } + if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail()) + return UINT64_MAX; + size_t bytes_written = src_len; + error = file_sp->Write(src, bytes_written); + if (error.Fail()) + return UINT64_MAX; + return bytes_written; +} + +uint64_t +FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Error &error) +{ + if (fd == UINT64_MAX) + { + error.SetErrorString("invalid file descriptor"); + return UINT64_MAX; + } + FDToFileMap::iterator pos = m_cache.find(fd); + if (pos == m_cache.end()) + { + error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd); + return false; + } + FileSP file_sp = pos->second; + if (!file_sp) + { + error.SetErrorString("invalid host backing file"); + return UINT64_MAX; + } + if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset || error.Fail()) + return UINT64_MAX; + size_t bytes_read = dst_len; + error = file_sp->Read(dst, bytes_read); + if (error.Fail()) + return UINT64_MAX; + return bytes_read; +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp index 48f1ac7..8c4014c 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/FileSpec.cpp @@ -27,21 +27,22 @@ #include <pwd.h> #endif -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" - -#include "lldb/Core/StreamString.h" -#include "lldb/Host/File.h" -#include "lldb/Host/FileSpec.h" -#include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamString.h" #include "lldb/Core/Stream.h" +#include "lldb/Host/File.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" + using namespace lldb; using namespace lldb_private; @@ -54,104 +55,68 @@ GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr) return false; } -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - -static const char* -GetCachedGlobTildeSlash() -{ - static std::string g_tilde; - if (g_tilde.empty()) - { - struct passwd *user_entry; - user_entry = getpwuid(geteuid()); - if (user_entry != NULL) - g_tilde = user_entry->pw_dir; - - if (g_tilde.empty()) - return NULL; - } - return g_tilde.c_str(); -} - -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - // Resolves the username part of a path of the form ~user/other/directories, and // writes the result into dst_path. -// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved. -// Otherwise returns the number of characters copied into dst_path. If the return -// is >= dst_len, then the resolved path is too long... -size_t -FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len) +void +FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) { - if (src_path == NULL || src_path[0] == '\0') - return 0; - -#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - - char user_home[PATH_MAX]; - const char *user_name; - - - // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...) - if (src_path[0] != '~') - { - size_t len = strlen (src_path); - if (len >= dst_len) - { - ::bcopy (src_path, dst_path, dst_len - 1); - dst_path[dst_len] = '\0'; - } - else - ::bcopy (src_path, dst_path, len + 1); - - return len; - } - - const char *first_slash = ::strchr (src_path, '/'); - char remainder[PATH_MAX]; +#if LLDB_CONFIG_TILDE_RESOLVES_TO_USER + if (path.empty() || path[0] != '~') + return; - if (first_slash == NULL) + llvm::StringRef path_str(path.data()); + size_t slash_pos = path_str.find_first_of("/", 1); + if (slash_pos == 1) { - // The whole name is the username (minus the ~): - user_name = src_path + 1; - remainder[0] = '\0'; - } - else - { - size_t user_name_len = first_slash - src_path - 1; - ::memcpy (user_home, src_path + 1, user_name_len); - user_home[user_name_len] = '\0'; - user_name = user_home; + // A path of the form ~/ resolves to the current user's home dir + llvm::SmallString<64> home_dir; + if (!llvm::sys::path::home_directory(home_dir)) + return; - ::strcpy (remainder, first_slash); + // Overwrite the ~ with the first character of the homedir, and insert + // the rest. This way we only trigger one move, whereas an insert + // followed by a delete (or vice versa) would trigger two. + path[0] = home_dir[0]; + path.insert(path.begin() + 1, home_dir.begin() + 1, home_dir.end()); + return; } - if (user_name == NULL) - return 0; - // User name of "" means the current user... - - struct passwd *user_entry; - const char *home_dir = NULL; - - if (user_name[0] == '\0') + auto username_begin = path.begin()+1; + auto username_end = (slash_pos == llvm::StringRef::npos) + ? path.end() + : (path.begin() + slash_pos); + size_t replacement_length = std::distance(path.begin(), username_end); + + llvm::SmallString<20> username(username_begin, username_end); + struct passwd *user_entry = ::getpwnam(username.c_str()); + if (user_entry != nullptr) { - home_dir = GetCachedGlobTildeSlash(); + // Copy over the first n characters of the path, where n is the smaller of the length + // of the home directory and the slash pos. + llvm::StringRef homedir(user_entry->pw_dir); + size_t initial_copy_length = std::min(homedir.size(), replacement_length); + auto src_begin = homedir.begin(); + auto src_end = src_begin + initial_copy_length; + std::copy(src_begin, src_end, path.begin()); + if (replacement_length > homedir.size()) + { + // We copied the entire home directory, but the ~username portion of the path was + // longer, so there's characters that need to be removed. + path.erase(path.begin() + initial_copy_length, username_end); + } + else if (replacement_length < homedir.size()) + { + // We copied all the way up to the slash in the destination, but there's still more + // characters that need to be inserted. + path.insert(username_end, src_end, homedir.end()); + } } else { - user_entry = ::getpwnam (user_name); - if (user_entry != NULL) - home_dir = user_entry->pw_dir; + // Unable to resolve username (user doesn't exist?) + path.clear(); } - - if (home_dir == NULL) - return 0; - else - return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder); -#else - // Resolving home directories is not supported, just copy the path... - return ::snprintf (dst_path, dst_len, "%s", src_path); -#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER +#endif } size_t @@ -187,49 +152,24 @@ FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER } - - -size_t -FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len) +void +FileSpec::Resolve (llvm::SmallVectorImpl<char> &path) { - if (src_path == NULL || src_path[0] == '\0') - return 0; + if (path.empty()) + return; - // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path... - char unglobbed_path[PATH_MAX]; #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - if (src_path[0] == '~') - { - size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path)); - - // If we couldn't find the user referred to, or the resultant path was too long, - // then just copy over the src_path. - if (return_count == 0 || return_count >= sizeof(unglobbed_path)) - ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path); - } - else + if (path[0] == '~') + ResolveUsername(path); #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER - { - ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path); - } - // Now resolve the path if needed - char resolved_path[PATH_MAX]; - if (::realpath (unglobbed_path, resolved_path)) - { - // Success, copy the resolved path - return ::snprintf(dst_path, dst_len, "%s", resolved_path); - } - else - { - // Failed, just copy the unglobbed path - return ::snprintf(dst_path, dst_len, "%s", unglobbed_path); - } + llvm::sys::fs::make_absolute(path); } -FileSpec::FileSpec() : - m_directory(), - m_filename() +FileSpec::FileSpec() + : m_directory() + , m_filename() + , m_syntax(FileSystem::GetNativePathSyntax()) { } @@ -237,13 +177,13 @@ FileSpec::FileSpec() : // Default constructor that can take an optional full path to a // file on disk. //------------------------------------------------------------------ -FileSpec::FileSpec(const char *pathname, bool resolve_path) : +FileSpec::FileSpec(const char *pathname, bool resolve_path, PathSyntax syntax) : m_directory(), m_filename(), m_is_resolved(false) { if (pathname && pathname[0]) - SetFile(pathname, resolve_path); + SetFile(pathname, resolve_path, syntax); } //------------------------------------------------------------------ @@ -252,7 +192,8 @@ FileSpec::FileSpec(const char *pathname, bool resolve_path) : FileSpec::FileSpec(const FileSpec& rhs) : m_directory (rhs.m_directory), m_filename (rhs.m_filename), - m_is_resolved (rhs.m_is_resolved) + m_is_resolved (rhs.m_is_resolved), + m_syntax (rhs.m_syntax) { } @@ -268,7 +209,7 @@ FileSpec::FileSpec(const FileSpec* rhs) : } //------------------------------------------------------------------ -// Virtual destrcuctor in case anyone inherits from this class. +// Virtual destructor in case anyone inherits from this class. //------------------------------------------------------------------ FileSpec::~FileSpec() { @@ -285,83 +226,65 @@ FileSpec::operator= (const FileSpec& rhs) m_directory = rhs.m_directory; m_filename = rhs.m_filename; m_is_resolved = rhs.m_is_resolved; + m_syntax = rhs.m_syntax; } return *this; } +void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) +{ + if (syntax == ePathSyntaxPosix || + (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(path.begin(), path.end(), '\\', '/'); +} + +void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) +{ + if (syntax == ePathSyntaxPosix || + (syntax == ePathSyntaxHostNative && FileSystem::GetNativePathSyntax() == ePathSyntaxPosix)) + return; + + std::replace(path.begin(), path.end(), '/', '\\'); +} + //------------------------------------------------------------------ // Update the contents of this object with a new path. The path will // be split up into a directory and filename and stored as uniqued // string values for quick comparison and efficient memory usage. //------------------------------------------------------------------ void -FileSpec::SetFile (const char *pathname, bool resolve) +FileSpec::SetFile (const char *pathname, bool resolve, PathSyntax syntax) { m_filename.Clear(); m_directory.Clear(); m_is_resolved = false; + m_syntax = (syntax == ePathSyntaxHostNative) ? FileSystem::GetNativePathSyntax() : syntax; + if (pathname == NULL || pathname[0] == '\0') return; - char resolved_path[PATH_MAX]; - bool path_fit = true; - + llvm::SmallString<64> normalized(pathname); + Normalize(normalized, syntax); + if (resolve) { - path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1); - m_is_resolved = path_fit; + FileSpec::Resolve (normalized); + m_is_resolved = true; } - else - { - // Copy the path because "basename" and "dirname" want to muck with the - // path buffer - if (::strlen (pathname) > sizeof(resolved_path) - 1) - path_fit = false; - else - ::strcpy (resolved_path, pathname); - } - - if (path_fit) + llvm::StringRef resolve_path_ref(normalized.c_str()); + llvm::StringRef filename_ref = llvm::sys::path::filename(resolve_path_ref); + if (!filename_ref.empty()) { - char *filename = ::basename (resolved_path); - if (filename) - { - m_filename.SetCString (filename); - // Truncate the basename off the end of the resolved path - - // Only attempt to get the dirname if it looks like we have a path - if (strchr(resolved_path, '/') -#ifdef _WIN32 - || strchr(resolved_path, '\\') -#endif - ) - { - char *directory = ::dirname (resolved_path); - - // Make sure we didn't get our directory resolved to "." without having - // specified - if (directory) - m_directory.SetCString(directory); - else - { - char *last_resolved_path_slash = strrchr(resolved_path, '/'); -#ifdef _WIN32 - char* last_resolved_path_slash_windows = strrchr(resolved_path, '\\'); - if (last_resolved_path_slash_windows > last_resolved_path_slash) - last_resolved_path_slash = last_resolved_path_slash_windows; -#endif - if (last_resolved_path_slash) - { - *last_resolved_path_slash = '\0'; - m_directory.SetCString(resolved_path); - } - } - } - } - else - m_directory.SetCString(resolved_path); + m_filename.SetString (filename_ref); + llvm::StringRef directory_ref = llvm::sys::path::parent_path(resolve_path_ref); + if (!directory_ref.empty()) + m_directory.SetString(directory_ref); } + else + m_directory.SetCString(normalized.c_str()); } //---------------------------------------------------------------------- @@ -562,6 +485,15 @@ FileSpec::Exists () const } bool +FileSpec::Readable () const +{ + const uint32_t permissions = GetPermissions(); + if (permissions & eFilePermissionsEveryoneR) + return true; + return false; +} + +bool FileSpec::ResolveExecutableLocation () { if (!m_directory) @@ -572,8 +504,7 @@ FileSpec::ResolveExecutableLocation () const std::string file_str (file_cstr); std::string path = llvm::sys::FindProgramByName (file_str); llvm::StringRef dir_ref = llvm::sys::path::parent_path(path); - //llvm::StringRef dir_ref = path.getDirname(); - if (! dir_ref.empty()) + if (!dir_ref.empty()) { // FindProgramByName returns "." if it can't find the file. if (strcmp (".", dir_ref.data()) == 0) @@ -607,7 +538,7 @@ FileSpec::ResolvePath () return true; // We have already resolved this path char path_buf[PATH_MAX]; - if (!GetPath (path_buf, PATH_MAX)) + if (!GetPath (path_buf, PATH_MAX, false)) return false; // SetFile(...) will set m_is_resolved correctly if it can resolve the path SetFile (path_buf, true); @@ -623,6 +554,12 @@ FileSpec::GetByteSize() const return 0; } +FileSpec::PathSyntax +FileSpec::GetPathSyntax() const +{ + return m_syntax; +} + FileSpec::FileType FileSpec::GetFileType () const { @@ -652,7 +589,7 @@ FileSpec::GetPermissions () const { uint32_t file_permissions = 0; if (*this) - Host::GetFilePermissions(GetPath().c_str(), file_permissions); + FileSystem::GetFilePermissions(GetPath().c_str(), file_permissions); return file_permissions; } @@ -708,45 +645,30 @@ FileSpec::GetFilename() const // values. //------------------------------------------------------------------ size_t -FileSpec::GetPath(char *path, size_t path_max_len) const +FileSpec::GetPath(char *path, size_t path_max_len, bool denormalize) const { - if (path_max_len) - { - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) - { - if (filename) - return ::snprintf (path, path_max_len, "%s/%s", dirname, filename); - else - return ::snprintf (path, path_max_len, "%s", dirname); - } - else if (filename) - { - return ::snprintf (path, path_max_len, "%s", filename); - } - } - if (path) - path[0] = '\0'; - return 0; + if (!path) + return 0; + + std::string result = GetPath(denormalize); + + size_t result_length = std::min(path_max_len-1, result.length()); + ::strncpy(path, result.c_str(), result_length + 1); + return result_length; } std::string -FileSpec::GetPath (void) const +FileSpec::GetPath (bool denormalize) const { - static ConstString g_slash_only ("/"); - std::string path; - const char *dirname = m_directory.GetCString(); - const char *filename = m_filename.GetCString(); - if (dirname) - { - path.append (dirname); - if (filename && m_directory != g_slash_only) - path.append ("/"); - } - if (filename) - path.append (filename); - return path; + llvm::SmallString<64> result; + if (m_directory) + result.append(m_directory.GetCString()); + if (m_filename) + llvm::sys::path::append(result, m_filename.GetCString()); + if (denormalize && !result.empty()) + DeNormalize(result, m_syntax); + + return std::string(result.begin(), result.end()); } ConstString @@ -780,7 +702,7 @@ FileSpec::GetFileNameStrippingExtension () const // Returns a shared pointer to a data buffer that contains all or // part of the contents of a file. The data is memory mapped and // will lazily page in data from the file as memory is accessed. -// The data that is mappped will start "file_offset" bytes into the +// The data that is mapped will start "file_offset" bytes into the // file, and "file_size" bytes will be mapped. If "file_size" is // greater than the number of bytes available in the file starting // at "file_offset", the number of bytes will be appropriately @@ -936,12 +858,11 @@ FileSpec::EnumerateDirectory if (dir_path && dir_path[0]) { #if _WIN32 - char szDir[MAX_PATH]; - strcpy_s(szDir, MAX_PATH, dir_path); - strcat_s(szDir, MAX_PATH, "\\*"); + std::string szDir(dir_path); + szDir += "\\*"; WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(szDir, &ffd); + HANDLE hFind = FindFirstFile(szDir.c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp index d43221c..00c2fa3 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp @@ -12,11 +12,12 @@ // C includes #include <errno.h> #include <limits.h> +#include <stdlib.h> #include <sys/types.h> #ifdef _WIN32 #include "lldb/Host/windows/windows.h" #include <winsock2.h> -#include <WS2tcpip.h> +#include <ws2tcpip.h> #else #include <unistd.h> #include <dlfcn.h> @@ -35,10 +36,9 @@ #include <mach/mach_port.h> #include <mach/mach_init.h> #include <mach-o/dyld.h> -#include <AvailabilityMacros.h> #endif -#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) +#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) || defined(__NetBSD__) #include <spawn.h> #include <sys/wait.h> #include <sys/syscall.h> @@ -48,7 +48,11 @@ #include <pthread_np.h> #endif +// C++ includes +#include <limits> + #include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Debugger.h" @@ -60,13 +64,19 @@ #include "lldb/Host/Config.h" #include "lldb/Host/Endian.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/Mutex.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/Target/FileAction.h" #include "lldb/Target/Process.h" +#include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/TargetList.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #if defined (__APPLE__) @@ -85,6 +95,12 @@ extern "C" using namespace lldb; using namespace lldb_private; +// Define maximum thread name length +#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__NetBSD__) +uint32_t const Host::MAX_THREAD_NAME_LENGTH = 16; +#else +uint32_t const Host::MAX_THREAD_NAME_LENGTH = std::numeric_limits<uint32_t>::max (); +#endif #if !defined (__APPLE__) && !defined (_WIN32) struct MonitorInfo @@ -116,7 +132,18 @@ Host::StartMonitoringChildProcess info_ptr->monitor_signals = monitor_signals; char thread_name[256]; - ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid); + + if (Host::MAX_THREAD_NAME_LENGTH <= 16) + { + // On some platforms, the thread name is limited to 16 characters. We need to + // abbreviate there or the pid info would get truncated. + ::snprintf (thread_name, sizeof(thread_name), "wait4(%" PRIu64 ")", pid); + } + else + { + ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid); + } + thread = ThreadCreate (thread_name, MonitorChildProcessThreadFunction, info_ptr, @@ -168,7 +195,7 @@ MonitorChildProcessThreadFunction (void *arg) const bool monitor_signals = info->monitor_signals; assert (info->pid <= UINT32_MAX); - const ::pid_t pid = monitor_signals ? -1 * info->pid : info->pid; + const ::pid_t pid = monitor_signals ? -1 * getpgid(info->pid) : info->pid; delete info; @@ -302,181 +329,6 @@ Host::SystemLog (SystemLogType type, const char *format, ...) va_end (args); } -const ArchSpec & -Host::GetArchitecture (SystemDefaultArchitecture arch_kind) -{ - static bool g_supports_32 = false; - static bool g_supports_64 = false; - static ArchSpec g_host_arch_32; - static ArchSpec g_host_arch_64; - -#if defined (__APPLE__) - - // Apple is different in that it can support both 32 and 64 bit executables - // in the same operating system running concurrently. Here we detect the - // correct host architectures for both 32 and 64 bit including if 64 bit - // executables are supported on the system. - - if (g_supports_32 == false && g_supports_64 == false) - { - // All apple systems support 32 bit execution. - g_supports_32 = true; - uint32_t cputype, cpusubtype; - uint32_t is_64_bit_capable = false; - size_t len = sizeof(cputype); - ArchSpec host_arch; - // These will tell us about the kernel architecture, which even on a 64 - // bit machine can be 32 bit... - if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) - { - len = sizeof (cpusubtype); - if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0) - cpusubtype = CPU_TYPE_ANY; - - len = sizeof (is_64_bit_capable); - if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0) - { - if (is_64_bit_capable) - g_supports_64 = true; - } - - if (is_64_bit_capable) - { -#if defined (__i386__) || defined (__x86_64__) - if (cpusubtype == CPU_SUBTYPE_486) - cpusubtype = CPU_SUBTYPE_I386_ALL; -#endif - if (cputype & CPU_ARCH_ABI64) - { - // We have a 64 bit kernel on a 64 bit system - g_host_arch_32.SetArchitecture (eArchTypeMachO, ~(CPU_ARCH_MASK) & cputype, cpusubtype); - g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype); - } - else - { - // We have a 32 bit kernel on a 64 bit system - g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype); - cputype |= CPU_ARCH_ABI64; - g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype); - } - } - else - { - g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype); - g_host_arch_64.Clear(); - } - } - } - -#else // #if defined (__APPLE__) - - if (g_supports_32 == false && g_supports_64 == false) - { - llvm::Triple triple(llvm::sys::getDefaultTargetTriple()); - - g_host_arch_32.Clear(); - g_host_arch_64.Clear(); - - // If the OS is Linux, "unknown" in the vendor slot isn't what we want - // for the default triple. It's probably an artifact of config.guess. - if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor) - triple.setVendorName (""); - - const char* distribution_id = GetDistributionId ().AsCString(); - - switch (triple.getArch()) - { - default: - g_host_arch_32.SetTriple(triple); - g_host_arch_32.SetDistributionId (distribution_id); - g_supports_32 = true; - break; - - case llvm::Triple::x86_64: - g_host_arch_64.SetTriple(triple); - g_host_arch_64.SetDistributionId (distribution_id); - g_supports_64 = true; - g_host_arch_32.SetTriple(triple.get32BitArchVariant()); - g_host_arch_32.SetDistributionId (distribution_id); - g_supports_32 = true; - break; - - case llvm::Triple::sparcv9: - case llvm::Triple::ppc64: - g_host_arch_64.SetTriple(triple); - g_host_arch_64.SetDistributionId (distribution_id); - g_supports_64 = true; - break; - } - - g_supports_32 = g_host_arch_32.IsValid(); - g_supports_64 = g_host_arch_64.IsValid(); - } - -#endif // #else for #if defined (__APPLE__) - - if (arch_kind == eSystemDefaultArchitecture32) - return g_host_arch_32; - else if (arch_kind == eSystemDefaultArchitecture64) - return g_host_arch_64; - - if (g_supports_64) - return g_host_arch_64; - - return g_host_arch_32; -} - -const ConstString & -Host::GetVendorString() -{ - static ConstString g_vendor; - if (!g_vendor) - { - const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture); - const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName(); - g_vendor.SetCStringWithLength(str_ref.data(), str_ref.size()); - } - return g_vendor; -} - -const ConstString & -Host::GetOSString() -{ - static ConstString g_os_string; - if (!g_os_string) - { - const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture); - const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName(); - g_os_string.SetCStringWithLength(str_ref.data(), str_ref.size()); - } - return g_os_string; -} - -const ConstString & -Host::GetTargetTriple() -{ - static ConstString g_host_triple; - if (!(g_host_triple)) - { - const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture); - g_host_triple.SetCString(host_arch.GetTriple().getTriple().c_str()); - } - return g_host_triple; -} - -// See linux/Host.cpp for Linux-based implementations of this. -// Add your platform-specific implementation to the appropriate host file. -#if !defined(__linux__) - -const ConstString & - Host::GetDistributionId () -{ - static ConstString s_distribution_id; - return s_distribution_id; -} - -#endif // #if !defined(__linux__) - lldb::pid_t Host::GetCurrentProcessID() { @@ -806,51 +658,6 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, #endif -FileSpec -Host::GetProgramFileSpec () -{ - static FileSpec g_program_filespec; - if (!g_program_filespec) - { -#if defined (__APPLE__) - char program_fullpath[PATH_MAX]; - // If DST is NULL, then return the number of bytes needed. - uint32_t len = sizeof(program_fullpath); - int err = _NSGetExecutablePath (program_fullpath, &len); - if (err == 0) - g_program_filespec.SetFile (program_fullpath, false); - else if (err == -1) - { - char *large_program_fullpath = (char *)::malloc (len + 1); - - err = _NSGetExecutablePath (large_program_fullpath, &len); - if (err == 0) - g_program_filespec.SetFile (large_program_fullpath, false); - - ::free (large_program_fullpath); - } -#elif defined (__linux__) - char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - if (len > 0) { - exe_path[len] = 0; - g_program_filespec.SetFile(exe_path, false); - } -#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) - int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; - size_t exe_path_size; - if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0) - { - char *exe_path = new char[exe_path_size]; - if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0) - g_program_filespec.SetFile(exe_path, false); - delete[] exe_path; - } -#endif - } - return g_program_filespec; -} - #if !defined (__APPLE__) // see Host.mm bool @@ -869,130 +676,6 @@ Host::ResolveExecutableInBundle (FileSpec &file) #ifndef _WIN32 -// Opaque info that tracks a dynamic library that was loaded -struct DynamicLibraryInfo -{ - DynamicLibraryInfo (const FileSpec &fs, int o, void *h) : - file_spec (fs), - open_options (o), - handle (h) - { - } - - const FileSpec file_spec; - uint32_t open_options; - void * handle; -}; - -void * -Host::DynamicLibraryOpen (const FileSpec &file_spec, uint32_t options, Error &error) -{ - char path[PATH_MAX]; - if (file_spec.GetPath(path, sizeof(path))) - { - int mode = 0; - - if (options & eDynamicLibraryOpenOptionLazy) - mode |= RTLD_LAZY; - else - mode |= RTLD_NOW; - - - if (options & eDynamicLibraryOpenOptionLocal) - mode |= RTLD_LOCAL; - else - mode |= RTLD_GLOBAL; - -#ifdef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED - if (options & eDynamicLibraryOpenOptionLimitGetSymbol) - mode |= RTLD_FIRST; -#endif - - void * opaque = ::dlopen (path, mode); - - if (opaque) - { - error.Clear(); - return new DynamicLibraryInfo (file_spec, options, opaque); - } - else - { - error.SetErrorString(::dlerror()); - } - } - else - { - error.SetErrorString("failed to extract path"); - } - return NULL; -} - -Error -Host::DynamicLibraryClose (void *opaque) -{ - Error error; - if (opaque == NULL) - { - error.SetErrorString ("invalid dynamic library handle"); - } - else - { - DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque; - if (::dlclose (dylib_info->handle) != 0) - { - error.SetErrorString(::dlerror()); - } - - dylib_info->open_options = 0; - dylib_info->handle = 0; - delete dylib_info; - } - return error; -} - -void * -Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &error) -{ - if (opaque == NULL) - { - error.SetErrorString ("invalid dynamic library handle"); - } - else - { - DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque; - - void *symbol_addr = ::dlsym (dylib_info->handle, symbol_name); - if (symbol_addr) - { -#ifndef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED - // This host doesn't support limiting searches to this shared library - // so we need to verify that the match came from this shared library - // if it was requested in the Host::DynamicLibraryOpen() function. - if (dylib_info->open_options & eDynamicLibraryOpenOptionLimitGetSymbol) - { - FileSpec match_dylib_spec (Host::GetModuleFileSpecForHostAddress (symbol_addr)); - if (match_dylib_spec != dylib_info->file_spec) - { - char dylib_path[PATH_MAX]; - if (dylib_info->file_spec.GetPath (dylib_path, sizeof(dylib_path))) - error.SetErrorStringWithFormat ("symbol not found in \"%s\"", dylib_path); - else - error.SetErrorString ("symbol not found"); - return NULL; - } - } -#endif - error.Clear(); - return symbol_addr; - } - else - { - error.SetErrorString(::dlerror()); - } - } - return NULL; -} - FileSpec Host::GetModuleFileSpecForHostAddress (const void *host_addr) { @@ -1008,427 +691,6 @@ Host::GetModuleFileSpecForHostAddress (const void *host_addr) #endif -bool -Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) -{ - // To get paths related to LLDB we get the path to the executable that - // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", - // on linux this is assumed to be the "lldb" main executable. If LLDB on - // linux is actually in a shared library (liblldb.so) then this function will - // need to be modified to "do the right thing". - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST); - - switch (path_type) - { - case ePathTypeLLDBShlibDir: - { - static ConstString g_lldb_so_dir; - if (!g_lldb_so_dir) - { - FileSpec lldb_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)Host::GetLLDBPath)); - g_lldb_so_dir = lldb_file_spec.GetDirectory(); - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_lldb_so_dir.GetCString()); - } - file_spec.GetDirectory() = g_lldb_so_dir; - return (bool)file_spec.GetDirectory(); - } - break; - - case ePathTypeSupportExecutableDir: - { - static ConstString g_lldb_support_exe_dir; - if (!g_lldb_support_exe_dir) - { - FileSpec lldb_file_spec; - if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec)) - { - char raw_path[PATH_MAX]; - char resolved_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); - -#if defined (__APPLE__) - char *framework_pos = ::strstr (raw_path, "LLDB.framework"); - if (framework_pos) - { - framework_pos += strlen("LLDB.framework"); -#if defined (__arm__) - // Shallow bundle - *framework_pos = '\0'; -#else - // Normal bundle - ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path)); -#endif - } -#endif - FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); - g_lldb_support_exe_dir.SetCString(resolved_path); - } - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString()); - } - file_spec.GetDirectory() = g_lldb_support_exe_dir; - return (bool)file_spec.GetDirectory(); - } - break; - - case ePathTypeHeaderDir: - { - static ConstString g_lldb_headers_dir; - if (!g_lldb_headers_dir) - { -#if defined (__APPLE__) - FileSpec lldb_file_spec; - if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec)) - { - char raw_path[PATH_MAX]; - char resolved_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); - - char *framework_pos = ::strstr (raw_path, "LLDB.framework"); - if (framework_pos) - { - framework_pos += strlen("LLDB.framework"); - ::strncpy (framework_pos, "/Headers", PATH_MAX - (framework_pos - raw_path)); - } - FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); - g_lldb_headers_dir.SetCString(resolved_path); - } -#else - // TODO: Anyone know how we can determine this for linux? Other systems?? - g_lldb_headers_dir.SetCString ("/opt/local/include/lldb"); -#endif - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_lldb_headers_dir.GetCString()); - } - file_spec.GetDirectory() = g_lldb_headers_dir; - return (bool)file_spec.GetDirectory(); - } - break; - -#ifdef LLDB_DISABLE_PYTHON - case ePathTypePythonDir: - return false; -#else - case ePathTypePythonDir: - { - static ConstString g_lldb_python_dir; - if (!g_lldb_python_dir) - { - FileSpec lldb_file_spec; - if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec)) - { - char raw_path[PATH_MAX]; - char resolved_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); - -#if defined (__APPLE__) - char *framework_pos = ::strstr (raw_path, "LLDB.framework"); - if (framework_pos) - { - framework_pos += strlen("LLDB.framework"); - ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path)); - } - else - { -#endif - llvm::SmallString<256> python_version_dir; - llvm::raw_svector_ostream os(python_version_dir); - os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages"; - os.flush(); - - // We may get our string truncated. Should we protect - // this with an assert? - - ::strncat(raw_path, python_version_dir.c_str(), - sizeof(raw_path) - strlen(raw_path) - 1); - -#if defined (__APPLE__) - } -#endif - FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); - g_lldb_python_dir.SetCString(resolved_path); - } - - if (log) - log->Printf("Host::GetLLDBPath(ePathTypePythonDir) => '%s'", g_lldb_python_dir.GetCString()); - - } - file_spec.GetDirectory() = g_lldb_python_dir; - return (bool)file_spec.GetDirectory(); - } - break; -#endif - - case ePathTypeLLDBSystemPlugins: // System plug-ins directory - { -#if defined (__APPLE__) || defined(__linux__) - static ConstString g_lldb_system_plugin_dir; - static bool g_lldb_system_plugin_dir_located = false; - if (!g_lldb_system_plugin_dir_located) - { - g_lldb_system_plugin_dir_located = true; -#if defined (__APPLE__) - FileSpec lldb_file_spec; - if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec)) - { - char raw_path[PATH_MAX]; - char resolved_path[PATH_MAX]; - lldb_file_spec.GetPath(raw_path, sizeof(raw_path)); - - char *framework_pos = ::strstr (raw_path, "LLDB.framework"); - if (framework_pos) - { - framework_pos += strlen("LLDB.framework"); - ::strncpy (framework_pos, "/Resources/PlugIns", PATH_MAX - (framework_pos - raw_path)); - FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); - g_lldb_system_plugin_dir.SetCString(resolved_path); - } - return false; - } -#elif defined (__linux__) - FileSpec lldb_file_spec("/usr/lib/lldb", true); - if (lldb_file_spec.Exists()) - { - g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str()); - } -#endif // __APPLE__ || __linux__ - - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_lldb_system_plugin_dir.GetCString()); - - } - - if (g_lldb_system_plugin_dir) - { - file_spec.GetDirectory() = g_lldb_system_plugin_dir; - return true; - } -#else - // TODO: where would system LLDB plug-ins be located on other systems? - return false; -#endif - } - break; - - case ePathTypeLLDBUserPlugins: // User plug-ins directory - { -#if defined (__APPLE__) - static ConstString g_lldb_user_plugin_dir; - if (!g_lldb_user_plugin_dir) - { - char user_plugin_path[PATH_MAX]; - if (FileSpec::Resolve ("~/Library/Application Support/LLDB/PlugIns", - user_plugin_path, - sizeof(user_plugin_path))) - { - g_lldb_user_plugin_dir.SetCString(user_plugin_path); - } - } - file_spec.GetDirectory() = g_lldb_user_plugin_dir; - return (bool)file_spec.GetDirectory(); -#elif defined (__linux__) - static ConstString g_lldb_user_plugin_dir; - if (!g_lldb_user_plugin_dir) - { - // XDG Base Directory Specification - // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb. - FileSpec lldb_file_spec; - const char *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home && xdg_data_home[0]) - { - std::string user_plugin_dir (xdg_data_home); - user_plugin_dir += "/lldb"; - lldb_file_spec.SetFile (user_plugin_dir.c_str(), true); - } - else - { - const char *home_dir = getenv("HOME"); - if (home_dir && home_dir[0]) - { - std::string user_plugin_dir (home_dir); - user_plugin_dir += "/.local/share/lldb"; - lldb_file_spec.SetFile (user_plugin_dir.c_str(), true); - } - } - - if (lldb_file_spec.Exists()) - g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str()); - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_lldb_user_plugin_dir.GetCString()); - } - file_spec.GetDirectory() = g_lldb_user_plugin_dir; - return (bool)file_spec.GetDirectory(); -#endif - // TODO: where would user LLDB plug-ins be located on other systems? - return false; - } - - case ePathTypeLLDBTempSystemDir: - { - static ConstString g_lldb_tmp_dir; - if (!g_lldb_tmp_dir) - { - const char *tmpdir_cstr = getenv("TMPDIR"); - if (tmpdir_cstr == NULL) - { - tmpdir_cstr = getenv("TMP"); - if (tmpdir_cstr == NULL) - tmpdir_cstr = getenv("TEMP"); - } - if (tmpdir_cstr) - { - g_lldb_tmp_dir.SetCString(tmpdir_cstr); - if (log) - log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString()); - } - } - file_spec.GetDirectory() = g_lldb_tmp_dir; - return (bool)file_spec.GetDirectory(); - } - } - - return false; -} - - -bool -Host::GetHostname (std::string &s) -{ - char hostname[PATH_MAX]; - hostname[sizeof(hostname) - 1] = '\0'; - if (::gethostname (hostname, sizeof(hostname) - 1) == 0) - { - struct hostent* h = ::gethostbyname (hostname); - if (h) - s.assign (h->h_name); - else - s.assign (hostname); - return true; - } - return false; -} - -#ifndef _WIN32 - -const char * -Host::GetUserName (uint32_t uid, std::string &user_name) -{ - struct passwd user_info; - struct passwd *user_info_ptr = &user_info; - char user_buffer[PATH_MAX]; - size_t user_buffer_size = sizeof(user_buffer); - if (::getpwuid_r (uid, - &user_info, - user_buffer, - user_buffer_size, - &user_info_ptr) == 0) - { - if (user_info_ptr) - { - user_name.assign (user_info_ptr->pw_name); - return user_name.c_str(); - } - } - user_name.clear(); - return NULL; -} - -const char * -Host::GetGroupName (uint32_t gid, std::string &group_name) -{ - char group_buffer[PATH_MAX]; - size_t group_buffer_size = sizeof(group_buffer); - struct group group_info; - struct group *group_info_ptr = &group_info; - // Try the threadsafe version first - if (::getgrgid_r (gid, - &group_info, - group_buffer, - group_buffer_size, - &group_info_ptr) == 0) - { - if (group_info_ptr) - { - group_name.assign (group_info_ptr->gr_name); - return group_name.c_str(); - } - } - else - { - // The threadsafe version isn't currently working - // for me on darwin, but the non-threadsafe version - // is, so I am calling it below. - group_info_ptr = ::getgrgid (gid); - if (group_info_ptr) - { - group_name.assign (group_info_ptr->gr_name); - return group_name.c_str(); - } - } - group_name.clear(); - return NULL; -} - -uint32_t -Host::GetUserID () -{ - return getuid(); -} - -uint32_t -Host::GetGroupID () -{ - return getgid(); -} - -uint32_t -Host::GetEffectiveUserID () -{ - return geteuid(); -} - -uint32_t -Host::GetEffectiveGroupID () -{ - return getegid(); -} - -#endif - -#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm -bool -Host::GetOSBuildString (std::string &s) -{ - s.clear(); - return false; -} - -bool -Host::GetOSKernelDescription (std::string &s) -{ - s.clear(); - return false; -} -#endif - -#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__) -uint32_t -Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) -{ - process_infos.Clear(); - return process_infos.GetSize(); -} - -bool -Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) -{ - process_info.Clear(); - return false; -} -#endif - #if !defined(__linux__) bool Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach) @@ -1447,7 +709,7 @@ Host::GetDummyTarget (lldb_private::Debugger &debugger) { ArchSpec arch(Target::GetDefaultArchitecture()); if (!arch.IsValid()) - arch = Host::GetArchitecture (); + arch = HostInfo::GetArchitecture(); Error err = debugger.GetTargetList().CreateTarget(debugger, NULL, arch.GetTriple().getTriple().c_str(), @@ -1545,9 +807,9 @@ Host::RunShellCommand (const char *command, // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" FileSpec tmpdir_file_spec; - if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { - tmpdir_file_spec.GetFilename().SetCString("lldb-shell-output.XXXXXX"); + tmpdir_file_spec.AppendPathComponent("lldb-shell-output.XXXXXX"); strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer)); } else @@ -1601,7 +863,7 @@ Host::RunShellCommand (const char *command, { error.SetErrorString("timed out waiting for shell command to complete"); - // Kill the process since it didn't complete withint the timeout specified + // Kill the process since it didn't complete within the timeout specified Kill (pid, SIGKILL); // Wait for the monitor callback to get the message timeout_time = TimeValue::Now(); @@ -1651,7 +913,7 @@ Host::RunShellCommand (const char *command, // LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC // systems -#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) +#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) || defined(__NetBSD__) // this method needs to be visible to macosx/Host.cpp and // common/Host.cpp. @@ -1682,7 +944,7 @@ Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info) g_use_close_on_exec_flag = eLazyBoolNo; uint32_t major, minor, update; - if (Host::GetOSVersion(major, minor, update)) + if (HostInfo::GetOSVersion(major, minor, update)) { // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier if (major > 10 || (major == 10 && minor > 7)) @@ -1757,8 +1019,8 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i cpu_type_t cpu = arch_spec.GetMachOCPUType(); cpu_type_t sub = arch_spec.GetMachOCPUSubType(); if (cpu != 0 && - cpu != UINT32_MAX && - cpu != LLDB_INVALID_CPUTYPE && + cpu != static_cast<cpu_type_t>(UINT32_MAX) && + cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) && !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail { size_t ocount = 0; @@ -1840,13 +1102,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i for (size_t i=0; i<num_file_actions; ++i) { - const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); + const FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); if (launch_file_action) { - if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions, - launch_file_action, - log, - error)) + if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, error)) return error; } } @@ -1862,12 +1121,10 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i if (error.Fail() || log) { error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", - pid, - exe_path, - &file_actions, - &attr, - argv, - envp); + pid, exe_path, static_cast<void*>(&file_actions), + static_cast<void*>(&attr), + reinterpret_cast<const void*>(argv), + reinterpret_cast<const void*>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) @@ -1889,11 +1146,9 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i if (error.Fail() || log) { error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", - pid, - exe_path, - &attr, - argv, - envp); + pid, exe_path, static_cast<void*>(&attr), + reinterpret_cast<const void*>(argv), + reinterpret_cast<const void*>(envp)); if (log) { for (int ii=0; argv[ii]; ++ii) @@ -1920,12 +1175,79 @@ Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_i return error; } +bool +Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, Log *log, Error &error) +{ + if (info == NULL) + return false; + + posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions); + + switch (info->GetAction()) + { + case FileAction::eFileActionNone: + error.Clear(); + break; + + case FileAction::eFileActionClose: + if (info->GetFD() == -1) + error.SetErrorString("invalid fd for posix_spawn_file_actions_addclose(...)"); + else + { + error.SetError(::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), eErrorTypePOSIX); + if (log && (error.Fail() || log)) + error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)", + static_cast<void *>(file_actions), info->GetFD()); + } + break; + + case FileAction::eFileActionDuplicate: + if (info->GetFD() == -1) + error.SetErrorString("invalid fd for posix_spawn_file_actions_adddup2(...)"); + else if (info->GetActionArgument() == -1) + error.SetErrorString("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); + else + { + error.SetError( + ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()), + eErrorTypePOSIX); + if (log && (error.Fail() || log)) + error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)", + static_cast<void *>(file_actions), info->GetFD(), info->GetActionArgument()); + } + break; + + case FileAction::eFileActionOpen: + if (info->GetFD() == -1) + error.SetErrorString("invalid fd in posix_spawn_file_actions_addopen(...)"); + else + { + int oflag = info->GetActionArgument(); + + mode_t mode = 0; + + if (oflag & O_CREAT) + mode = 0640; + + error.SetError( + ::posix_spawn_file_actions_addopen(file_actions, info->GetFD(), info->GetPath(), oflag, mode), + eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, + "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)", + static_cast<void *>(file_actions), info->GetFD(), info->GetPath(), oflag, mode); + } + break; + } + return error.Success(); +} + #endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems -#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) -// The functions below implement process launching via posix_spawn() for Linux -// and FreeBSD. +#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || defined(__NetBSD__) +// The functions below implement process launching via posix_spawn() for Linux, +// FreeBSD and NetBSD. Error Host::LaunchProcess (ProcessLaunchInfo &launch_info) @@ -2005,58 +1327,10 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) return error; } -#endif // defined(__linux__) or defined(__FreeBSD__) +#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) #ifndef _WIN32 -size_t -Host::GetPageSize() -{ - return ::getpagesize(); -} - -uint32_t -Host::GetNumberCPUS () -{ - static uint32_t g_num_cores = UINT32_MAX; - if (g_num_cores == UINT32_MAX) - { -#if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__) - - g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN); - -#else - - // Assume POSIX support if a host specific case has not been supplied above - g_num_cores = 0; - int num_cores = 0; - size_t num_cores_len = sizeof(num_cores); -#ifdef HW_AVAILCPU - int mib[] = { CTL_HW, HW_AVAILCPU }; -#else - int mib[] = { CTL_HW, HW_NCPU }; -#endif - - /* get the number of CPUs from the system */ - if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0)) - { - g_num_cores = num_cores; - } - else - { - mib[1] = HW_NCPU; - num_cores_len = sizeof(num_cores); - if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0)) - { - if (num_cores > 0) - g_num_cores = num_cores; - } - } -#endif - } - return g_num_cores; -} - void Host::Kill(lldb::pid_t pid, int signo) { @@ -2090,319 +1364,13 @@ Host::LaunchApplication (const FileSpec &app_file_spec) #endif +#if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__NetBSD__) -#ifdef LLDB_DISABLE_POSIX - -Error -Host::MakeDirectory (const char* path, uint32_t mode) -{ - Error error; - error.SetErrorStringWithFormat("%s in not implemented on this host", __PRETTY_FUNCTION__); - return error; -} - -Error -Host::GetFilePermissions (const char* path, uint32_t &file_permissions) -{ - Error error; - error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); - return error; -} - -Error -Host::SetFilePermissions (const char* path, uint32_t file_permissions) -{ - Error error; - error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); - return error; -} - -Error -Host::Symlink (const char *src, const char *dst) -{ - Error error; - error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); - return error; -} - -Error -Host::Readlink (const char *path, char *buf, size_t buf_len) -{ - Error error; - error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); - return error; -} - -Error -Host::Unlink (const char *path) -{ - Error error; - error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); - return error; -} - -#else - -Error -Host::MakeDirectory (const char* path, uint32_t file_permissions) -{ - Error error; - if (path && path[0]) - { - if (::mkdir(path, file_permissions) != 0) - { - error.SetErrorToErrno(); - switch (error.GetError()) - { - case ENOENT: - { - // Parent directory doesn't exist, so lets make it if we can - FileSpec spec(path, false); - if (spec.GetDirectory() && spec.GetFilename()) - { - // Make the parent directory and try again - Error error2 = Host::MakeDirectory(spec.GetDirectory().GetCString(), file_permissions); - if (error2.Success()) - { - // Try and make the directory again now that the parent directory was made successfully - if (::mkdir(path, file_permissions) == 0) - error.Clear(); - else - error.SetErrorToErrno(); - } - } - } - break; - case EEXIST: - { - FileSpec path_spec(path, false); - if (path_spec.IsDirectory()) - error.Clear(); // It is a directory and it already exists - } - break; - } - } - } - else - { - error.SetErrorString("empty path"); - } - return error; -} - -Error -Host::GetFilePermissions (const char* path, uint32_t &file_permissions) -{ - Error error; - struct stat file_stats; - if (::stat (path, &file_stats) == 0) - { - // The bits in "st_mode" currently match the definitions - // for the file mode bits in unix. - file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - } - else - { - error.SetErrorToErrno(); - } - return error; -} - -Error -Host::SetFilePermissions (const char* path, uint32_t file_permissions) -{ - Error error; - if (::chmod(path, file_permissions) != 0) - error.SetErrorToErrno(); - return error; -} - -Error -Host::Symlink (const char *src, const char *dst) -{ - Error error; - if (::symlink(dst, src) == -1) - error.SetErrorToErrno(); - return error; -} - -Error -Host::Unlink (const char *path) -{ - Error error; - if (::unlink(path) == -1) - error.SetErrorToErrno(); - return error; -} - -Error -Host::Readlink (const char *path, char *buf, size_t buf_len) -{ - Error error; - ssize_t count = ::readlink(path, buf, buf_len); - if (count < 0) - error.SetErrorToErrno(); - else if (count < (buf_len-1)) - buf[count] = '\0'; // Success - else - error.SetErrorString("'buf' buffer is too small to contain link contents"); - return error; -} - - -#endif - -typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap; -FDToFileMap& GetFDToFileMap() -{ - static FDToFileMap g_fd2filemap; - return g_fd2filemap; -} - -lldb::user_id_t -Host::OpenFile (const FileSpec& file_spec, - uint32_t flags, - uint32_t mode, - Error &error) +const lldb_private::UnixSignalsSP& +Host::GetUnixSignals () { - std::string path (file_spec.GetPath()); - if (path.empty()) - { - error.SetErrorString("empty path"); - return UINT64_MAX; - } - FileSP file_sp(new File()); - error = file_sp->Open(path.c_str(),flags,mode); - if (file_sp->IsValid() == false) - return UINT64_MAX; - lldb::user_id_t fd = file_sp->GetDescriptor(); - GetFDToFileMap()[fd] = file_sp; - return fd; + static UnixSignalsSP s_unix_signals_sp (new UnixSignals ()); + return s_unix_signals_sp; } -bool -Host::CloseFile (lldb::user_id_t fd, Error &error) -{ - if (fd == UINT64_MAX) - { - error.SetErrorString ("invalid file descriptor"); - return false; - } - FDToFileMap& file_map = GetFDToFileMap(); - FDToFileMap::iterator pos = file_map.find(fd); - if (pos == file_map.end()) - { - error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd); - return false; - } - FileSP file_sp = pos->second; - if (!file_sp) - { - error.SetErrorString ("invalid host backing file"); - return false; - } - error = file_sp->Close(); - file_map.erase(pos); - return error.Success(); -} - -uint64_t -Host::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error) -{ - if (fd == UINT64_MAX) - { - error.SetErrorString ("invalid file descriptor"); - return UINT64_MAX; - } - FDToFileMap& file_map = GetFDToFileMap(); - FDToFileMap::iterator pos = file_map.find(fd); - if (pos == file_map.end()) - { - error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64 , fd); - return false; - } - FileSP file_sp = pos->second; - if (!file_sp) - { - error.SetErrorString ("invalid host backing file"); - return UINT64_MAX; - } - if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail()) - return UINT64_MAX; - size_t bytes_written = src_len; - error = file_sp->Write(src, bytes_written); - if (error.Fail()) - return UINT64_MAX; - return bytes_written; -} - -uint64_t -Host::ReadFile (lldb::user_id_t fd, uint64_t offset, void* dst, uint64_t dst_len, Error &error) -{ - if (fd == UINT64_MAX) - { - error.SetErrorString ("invalid file descriptor"); - return UINT64_MAX; - } - FDToFileMap& file_map = GetFDToFileMap(); - FDToFileMap::iterator pos = file_map.find(fd); - if (pos == file_map.end()) - { - error.SetErrorStringWithFormat ("invalid host file descriptor %" PRIu64, fd); - return false; - } - FileSP file_sp = pos->second; - if (!file_sp) - { - error.SetErrorString ("invalid host backing file"); - return UINT64_MAX; - } - if (file_sp->SeekFromStart(offset, &error) != offset || error.Fail()) - return UINT64_MAX; - size_t bytes_read = dst_len; - error = file_sp->Read(dst ,bytes_read); - if (error.Fail()) - return UINT64_MAX; - return bytes_read; -} - -lldb::user_id_t -Host::GetFileSize (const FileSpec& file_spec) -{ - return file_spec.GetByteSize(); -} - -bool -Host::GetFileExists (const FileSpec& file_spec) -{ - return file_spec.Exists(); -} - -bool -Host::CalculateMD5 (const FileSpec& file_spec, - uint64_t &low, - uint64_t &high) -{ -#if defined (__APPLE__) - StreamString md5_cmd_line; - md5_cmd_line.Printf("md5 -q '%s'", file_spec.GetPath().c_str()); - std::string hash_string; - Error err = Host::RunShellCommand(md5_cmd_line.GetData(), NULL, NULL, NULL, &hash_string, 60); - if (err.Fail()) - return false; - // a correctly formed MD5 is 16-bytes, that is 32 hex digits - // if the output is any other length it is probably wrong - if (hash_string.size() != 32) - return false; - std::string part1(hash_string,0,16); - std::string part2(hash_string,16); - const char* part1_cstr = part1.c_str(); - const char* part2_cstr = part2.c_str(); - high = ::strtoull(part1_cstr, NULL, 16); - low = ::strtoull(part2_cstr, NULL, 16); - return true; -#else - // your own MD5 implementation here - return false; #endif -} diff --git a/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp new file mode 100644 index 0000000..4eb43bf --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/HostInfoBase.cpp @@ -0,0 +1,318 @@ +//===-- HostInfoBase.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/HostInfoBase.h" + +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Host.h" + +#include <thread> + +using namespace lldb; +using namespace lldb_private; + +namespace +{ +void +CleanupProcessSpecificLLDBTempDir() +{ + // Get the process specific LLDB temporary directory and delete it. + FileSpec tmpdir_file_spec; + if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + return; + + // Remove the LLDB temporary directory if we have one. Set "recurse" to + // true to all files that were created for the LLDB process can be cleaned up. + FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true); +} + +struct HostInfoBaseFields +{ + uint32_t m_number_cpus; + std::string m_vendor_string; + std::string m_os_string; + std::string m_host_triple; + + ArchSpec m_host_arch_32; + ArchSpec m_host_arch_64; + + FileSpec m_lldb_so_dir; + FileSpec m_lldb_support_exe_dir; + FileSpec m_lldb_headers_dir; + FileSpec m_lldb_python_dir; + FileSpec m_lldb_system_plugin_dir; + FileSpec m_lldb_user_plugin_dir; + FileSpec m_lldb_tmp_dir; +}; + +HostInfoBaseFields *g_fields = nullptr; +} + +#define COMPUTE_LLDB_PATH(compute_function, member_var) \ + { \ + static bool is_initialized = false; \ + static bool success = false; \ + if (!is_initialized) \ + { \ + is_initialized = true; \ + success = HostInfo::compute_function(member_var); \ + } \ + if (success) \ + result = &member_var; \ + } + +void +HostInfoBase::Initialize() +{ + g_fields = new HostInfoBaseFields(); +} + +uint32_t +HostInfoBase::GetNumberCPUS() +{ + static bool is_initialized = false; + if (!is_initialized) + { + g_fields->m_number_cpus = std::thread::hardware_concurrency(); + is_initialized = true; + } + + return g_fields->m_number_cpus; +} + +llvm::StringRef +HostInfoBase::GetVendorString() +{ + static bool is_initialized = false; + if (!is_initialized) + { + const ArchSpec &host_arch = HostInfo::GetArchitecture(); + const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName(); + g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end()); + is_initialized = true; + } + return g_fields->m_vendor_string; +} + +llvm::StringRef +HostInfoBase::GetOSString() +{ + static bool is_initialized = false; + if (!is_initialized) + { + const ArchSpec &host_arch = HostInfo::GetArchitecture(); + const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName(); + g_fields->m_os_string.assign(str_ref.begin(), str_ref.end()); + is_initialized = true; + } + return g_fields->m_os_string; +} + +llvm::StringRef +HostInfoBase::GetTargetTriple() +{ + static bool is_initialized = false; + if (!is_initialized) + { + const ArchSpec &host_arch = HostInfo::GetArchitecture(); + g_fields->m_host_triple = host_arch.GetTriple().getTriple(); + is_initialized = true; + } + return g_fields->m_host_triple; +} + +const ArchSpec & +HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) +{ + static bool is_initialized = false; + if (!is_initialized) + { + HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); + is_initialized = true; + } + + // If an explicit 32 or 64-bit architecture was requested, return that. + if (arch_kind == eArchKind32) + return g_fields->m_host_arch_32; + if (arch_kind == eArchKind64) + return g_fields->m_host_arch_64; + + // Otherwise prefer the 64-bit architecture if it is valid. + return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64 : g_fields->m_host_arch_32; +} + +bool +HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) +{ + file_spec.Clear(); + +#if defined(LLDB_DISABLE_PYTHON) + if (type == lldb::ePathTypePythonDir) + return false; +#endif + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + FileSpec *result = nullptr; + switch (type) + { + case lldb::ePathTypeLLDBShlibDir: + COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); + break; + case lldb::ePathTypeSupportExecutableDir: + COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", + g_fields->m_lldb_support_exe_dir.GetPath().c_str()); + break; + case lldb::ePathTypeHeaderDir: + COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); + break; + case lldb::ePathTypePythonDir: + COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); + break; + case lldb::ePathTypeLLDBSystemPlugins: + COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", + g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); + break; + case lldb::ePathTypeLLDBUserPlugins: + COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", + g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); + break; + case lldb::ePathTypeLLDBTempSystemDir: + COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir) + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str()); + break; + } + + if (!result) + return false; + file_spec = *result; + return true; +} + +bool +HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) +{ + // To get paths related to LLDB we get the path to the executable that + // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB", + // on linux this is assumed to be the "lldb" main executable. If LLDB on + // linux is actually in a shared library (liblldb.so) then this function will + // need to be modified to "do the right thing". + + FileSpec lldb_file_spec( + Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath)))); + + // Remove the filename so that this FileSpec only represents the directory. + file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); + + return (bool)file_spec.GetDirectory(); +} + +bool +HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) +{ + return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec); +} + +bool +HostInfoBase::ComputeTempFileDirectory(FileSpec &file_spec) +{ + const char *tmpdir_cstr = getenv("TMPDIR"); + if (tmpdir_cstr == NULL) + { + tmpdir_cstr = getenv("TMP"); + if (tmpdir_cstr == NULL) + tmpdir_cstr = getenv("TEMP"); + } + if (!tmpdir_cstr) + return false; + + StreamString pid_tmpdir; + pid_tmpdir.Printf("%s/lldb", tmpdir_cstr); + if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success()) + return false; + + pid_tmpdir.Printf("/%" PRIu64, Host::GetCurrentProcessID()); + if (!FileSystem::MakeDirectory(pid_tmpdir.GetString().c_str(), eFilePermissionsDirectoryDefault).Success()) + return false; + + // Make an atexit handler to clean up the process specify LLDB temp dir + // and all of its contents. + ::atexit(CleanupProcessSpecificLLDBTempDir); + file_spec.GetDirectory().SetCStringWithLength(pid_tmpdir.GetString().c_str(), pid_tmpdir.GetString().size()); + return true; +} + +bool +HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) +{ + // TODO(zturner): Figure out how to compute the header directory for all platforms. + return false; +} + +bool +HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) +{ + // TODO(zturner): Figure out how to compute the system plugins directory for all platforms. + return false; +} + +bool +HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) +{ + // TODO(zturner): Figure out how to compute the user plugins directory for all platforms. + return false; +} + +void +HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64) +{ + llvm::Triple triple(llvm::sys::getDefaultTargetTriple()); + + arch_32.Clear(); + arch_64.Clear(); + + switch (triple.getArch()) + { + default: + arch_32.SetTriple(triple); + break; + + case llvm::Triple::x86_64: + arch_64.SetTriple(triple); + arch_32.SetTriple(triple.get32BitArchVariant()); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::mips64: + case llvm::Triple::sparcv9: + case llvm::Triple::ppc64: + arch_64.SetTriple(triple); + break; + } +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp b/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp new file mode 100644 index 0000000..6f7de44 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/IOObject.cpp @@ -0,0 +1,14 @@ +//===-- IOObject.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/IOObject.h" + +using namespace lldb_private; + +const IOObject::WaitableHandle IOObject::kInvalidHandleValue = -1; diff --git a/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp b/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp index 4e01355..c26467f 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Mutex.cpp @@ -242,9 +242,9 @@ Mutex::Mutex (Mutex::Type type) : //---------------------------------------------------------------------- Mutex::~Mutex() { +#if ENABLE_MUTEX_ERROR_CHECKING int err = ::pthread_mutex_destroy (&m_mutex); assert(err == 0); -#if ENABLE_MUTEX_ERROR_CHECKING if (err == 0) error_check_mutex (&m_mutex, eMutexActionDestroyed); else @@ -253,6 +253,8 @@ Mutex::~Mutex() assert(err == 0); } memset (&m_mutex, '\xba', sizeof(m_mutex)); +#else + ::pthread_mutex_destroy (&m_mutex); #endif } diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp new file mode 100644 index 0000000..284d7d1 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.cpp @@ -0,0 +1,116 @@ +//===-- NativeBreakpoint.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeBreakpoint.h" + +#include "lldb/lldb-defines.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" + +using namespace lldb_private; + +NativeBreakpoint::NativeBreakpoint (lldb::addr_t addr) : + m_addr (addr), + m_ref_count (1), + m_enabled (true) +{ + assert (addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address"); +} + +NativeBreakpoint::~NativeBreakpoint () +{ +} + +void +NativeBreakpoint::AddRef () +{ + ++m_ref_count; + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " bumped up, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count); +} + +int32_t +NativeBreakpoint::DecRef () +{ + --m_ref_count; + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " ref count decremented, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count); + + return m_ref_count; +} + +Error +NativeBreakpoint::Enable () +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + + if (m_enabled) + { + // We're already enabled. Just log and exit. + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already enabled, ignoring.", __FUNCTION__, m_addr); + return Error (); + } + + // Log and enable. + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...", __FUNCTION__, m_addr); + + Error error = DoEnable (); + if (error.Success ()) + { + m_enabled = true; + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.", __FUNCTION__, m_addr); + } + else + { + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ()); + } + + return error; +} + +Error +NativeBreakpoint::Disable () +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + + if (!m_enabled) + { + // We're already disabled. Just log and exit. + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already disabled, ignoring.", __FUNCTION__, m_addr); + return Error (); + } + + // Log and disable. + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...", __FUNCTION__, m_addr); + + Error error = DoDisable (); + if (error.Success ()) + { + m_enabled = false; + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.", __FUNCTION__, m_addr); + } + else + { + if (log) + log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ()); + } + + return error; +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.h b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.h new file mode 100644 index 0000000..367003b --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpoint.h @@ -0,0 +1,66 @@ +//===-- NativeBreakpoint.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeBreakpoint_h_ +#define liblldb_NativeBreakpoint_h_ + +#include "lldb/lldb-types.h" + +namespace lldb_private +{ + class NativeBreakpointList; + + class NativeBreakpoint + { + friend class NativeBreakpointList; + + public: + // The assumption is that derived breakpoints are enabled when created. + NativeBreakpoint (lldb::addr_t addr); + + virtual + ~NativeBreakpoint (); + + Error + Enable (); + + Error + Disable (); + + lldb::addr_t + GetAddress () const { return m_addr; } + + bool + IsEnabled () const { return m_enabled; } + + virtual bool + IsSoftwareBreakpoint () const = 0; + + protected: + const lldb::addr_t m_addr; + int32_t m_ref_count; + + virtual Error + DoEnable () = 0; + + virtual Error + DoDisable () = 0; + + private: + bool m_enabled; + + // ----------------------------------------------------------- + // interface for NativeBreakpointList + // ----------------------------------------------------------- + void AddRef (); + int32_t DecRef (); + }; +} + +#endif // ifndef liblldb_NativeBreakpoint_h_ diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp new file mode 100644 index 0000000..ecd0624 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.cpp @@ -0,0 +1,199 @@ +//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeBreakpointList.h" + +#include "lldb/Core/Log.h" + +#include "NativeBreakpoint.h" + +using namespace lldb; +using namespace lldb_private; + +NativeBreakpointList::NativeBreakpointList () : + m_mutex (Mutex::eMutexTypeRecursive) +{ +} + +Error +NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false"); + + Mutex::Locker locker (m_mutex); + + // Check if the breakpoint is already set. + auto iter = m_breakpoints.find (addr); + if (iter != m_breakpoints.end ()) + { + // Yes - bump up ref count. + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already enabled, upping ref count", __FUNCTION__, addr); + + iter->second->AddRef (); + return Error (); + } + + // Create a new breakpoint using the given create func. + if (log) + log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false"); + + NativeBreakpointSP breakpoint_sp; + Error error = create_func (addr, size_hint, hardware, breakpoint_sp); + if (error.Fail ()) + { + if (log) + log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s -- FAILED: %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false", error.AsCString ()); + return error; + } + + // Remember the breakpoint. + assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint"); + m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp)); + + return error; +} + +Error +NativeBreakpointList::DecRef (lldb::addr_t addr) +{ + Error error; + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + Mutex::Locker locker (m_mutex); + + // Check if the breakpoint is already set. + auto iter = m_breakpoints.find (addr); + if (iter == m_breakpoints.end ()) + { + // Not found! + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr); + error.SetErrorString ("breakpoint not found"); + return error; + } + + // Decrement ref count. + const int32_t new_ref_count = iter->second->DecRef (); + assert (new_ref_count >= 0 && "NativeBreakpoint ref count went negative"); + + if (new_ref_count > 0) + { + // Still references to this breakpoint. Leave it alone. + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- new breakpoint ref count %" PRIu32, __FUNCTION__, addr, new_ref_count); + return error; + } + + // Breakpoint has no more references. Disable it if it's not + // already disabled. + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removing due to no remaining references", __FUNCTION__, addr); + + // If it's enabled, we need to disable it. + if (iter->second->IsEnabled ()) + { + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- currently enabled, now disabling", __FUNCTION__, addr); + error = iter->second->Disable (); + if (error.Fail ()) + { + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removal FAILED: %s", __FUNCTION__, addr, error.AsCString ()); + // Continue since we still want to take it out of the breakpoint list. + } + } + else + { + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already disabled, nothing to do", __FUNCTION__, addr); + } + + // Take the breakpoint out of the list. + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr); + + m_breakpoints.erase (iter); + return error; +} + +Error +NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + Mutex::Locker locker (m_mutex); + + // Ensure we have said breakpoint. + auto iter = m_breakpoints.find (addr); + if (iter == m_breakpoints.end ()) + { + // Not found! + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr); + return Error ("breakpoint not found"); + } + + // Enable it. + return iter->second->Enable (); +} + +Error +NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + Mutex::Locker locker (m_mutex); + + // Ensure we have said breakpoint. + auto iter = m_breakpoints.find (addr); + if (iter == m_breakpoints.end ()) + { + // Not found! + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr); + return Error ("breakpoint not found"); + } + + // Disable it. + return iter->second->Disable (); +} + +Error +NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + Mutex::Locker locker (m_mutex); + + // Ensure we have said breakpoint. + auto iter = m_breakpoints.find (addr); + if (iter == m_breakpoints.end ()) + { + // Not found! + breakpoint_sp.reset (); + return Error ("breakpoint not found"); + } + + // Disable it. + breakpoint_sp = iter->second; + return Error (); +} + diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.h b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.h new file mode 100644 index 0000000..5161733 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeBreakpointList.h @@ -0,0 +1,53 @@ +//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeBreakpointList_h_ +#define liblldb_NativeBreakpointList_h_ + +#include "lldb/lldb-private-forward.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/Mutex.h" +// #include "lldb/Host/NativeBreakpoint.h" + +#include <functional> +#include <map> + +namespace lldb_private +{ + class NativeBreakpointList + { + public: + typedef std::function<Error (lldb::addr_t addr, size_t size_hint, bool hardware, NativeBreakpointSP &breakpoint_sp)> CreateBreakpointFunc; + + NativeBreakpointList (); + + Error + AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func); + + Error + DecRef (lldb::addr_t addr); + + Error + EnableBreakpoint (lldb::addr_t addr); + + Error + DisableBreakpoint (lldb::addr_t addr); + + Error + GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp); + + private: + typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap; + + Mutex m_mutex; + BreakpointMap m_breakpoints; + }; +} + +#endif // ifndef liblldb_NativeBreakpointList_h_ diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp new file mode 100644 index 0000000..b7a7726 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -0,0 +1,412 @@ +//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeProcessProtocol.h" + +#include "lldb/lldb-enumerations.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/State.h" +#include "lldb/Target/NativeRegisterContext.h" + +#include "NativeThreadProtocol.h" +#include "SoftwareBreakpoint.h" + +using namespace lldb; +using namespace lldb_private; + +// ----------------------------------------------------------------------------- +// NativeProcessProtocol Members +// ----------------------------------------------------------------------------- + +NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) : + m_pid (pid), + m_threads (), + m_current_thread_id (LLDB_INVALID_THREAD_ID), + m_threads_mutex (Mutex::eMutexTypeRecursive), + m_state (lldb::eStateInvalid), + m_state_mutex (Mutex::eMutexTypeRecursive), + m_exit_type (eExitTypeInvalid), + m_exit_status (0), + m_exit_description (), + m_delegates_mutex (Mutex::eMutexTypeRecursive), + m_delegates (), + m_breakpoint_list (), + m_terminal_fd (-1), + m_stop_id (0) +{ +} + +lldb_private::Error +NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) +{ + // Default: not implemented. + return Error ("not implemented"); +} + +bool +NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description) +{ + if (m_state == lldb::eStateExited) + { + *exit_type = m_exit_type; + *status = m_exit_status; + exit_description = m_exit_description; + return true; + } + + *status = 0; + return false; +} + +bool +NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange) +{ + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called", + __FUNCTION__, + exit_type, + status, + exit_description ? exit_description : "nullptr", + bNotifyStateChange ? "true" : "false"); + + // Exit status already set + if (m_state == lldb::eStateExited) + { + if (log) + log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status); + return false; + } + + m_state = lldb::eStateExited; + + m_exit_type = exit_type; + m_exit_status = status; + if (exit_description && exit_description[0]) + m_exit_description = exit_description; + else + m_exit_description.clear(); + + if (bNotifyStateChange) + SynchronouslyNotifyProcessStateChanged (lldb::eStateExited); + + return true; +} + +NativeThreadProtocolSP +NativeProcessProtocol::GetThreadAtIndex (uint32_t idx) +{ + Mutex::Locker locker (m_threads_mutex); + if (idx < m_threads.size ()) + return m_threads[idx]; + return NativeThreadProtocolSP (); +} + +NativeThreadProtocolSP +NativeProcessProtocol::GetThreadByID (lldb::tid_t tid) +{ + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + if (thread_sp->GetID() == tid) + return thread_sp; + } + return NativeThreadProtocolSP (); +} + +bool +NativeProcessProtocol::IsAlive () const +{ + return m_state != eStateDetached + && m_state != eStateExited + && m_state != eStateInvalid + && m_state != eStateUnloaded; +} + +bool +NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const +{ + ArchSpec process_arch; + if (!GetArchitecture (process_arch)) + return false; + byte_order = process_arch.GetByteOrder (); + return true; +} + +uint32_t +NativeProcessProtocol::GetMaxWatchpoints () const +{ + // This default implementation will return the number of + // *hardware* breakpoints available. MacOSX and other OS + // implementations that support software breakpoints will want to + // override this correctly for their implementation. + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + // get any thread + NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0)); + if (!thread_sp) + { + if (log) + log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__); + return 0; + } + + NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ()); + if (!reg_ctx_sp) + { + if (log) + log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__); + return 0; + } + + return reg_ctx_sp->NumSupportedHardwareWatchpoints (); +} + +Error +NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) +{ + // This default implementation assumes setting the watchpoint for + // the process will require setting the watchpoint for each of the + // threads. Furthermore, it will track watchpoints set for the + // process and will add them to each thread that is attached to + // via the (FIXME implement) OnThreadAttached () method. + + Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + // FIXME save the watchpoint on the set of process watchpoint vars + // so we can add them to a thread each time a new thread is registered. + + // Update the thread list + UpdateThreads (); + + // Keep track of the threads we successfully set the watchpoint + // for. If one of the thread watchpoint setting operations fails, + // back off and remove the watchpoint for all the threads that + // were successfully set so we get back to a consistent state. + std::vector<NativeThreadProtocolSP> watchpoint_established_threads; + + // Tell each thread to set a watchpoint. In the event that + // hardware watchpoints are requested but the SetWatchpoint fails, + // try to set a software watchpoint as a fallback. It's + // conceivable that if there are more threads than hardware + // watchpoints available, some of the threads will fail to set + // hardware watchpoints while software ones may be available. + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + assert (thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware); + if (thread_error.Fail () && hardware) + { + // Try software watchpoints since we failed on hardware watchpoint setting + // and we may have just run out of hardware watchpoints. + thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false); + if (thread_error.Success ()) + { + if (log) + log->Warning ("hardware watchpoint requested but software watchpoint set"); + } + } + + if (thread_error.Success ()) + { + // Remember that we set this watchpoint successfully in + // case we need to clear it later. + watchpoint_established_threads.push_back (thread_sp); + } + else + { + // Unset the watchpoint for each thread we successfully + // set so that we get back to a consistent state of "not + // set" for the watchpoint. + for (auto unwatch_thread_sp : watchpoint_established_threads) + { + Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr); + if (remove_error.Fail () && log) + { + log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s", + __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ()); + } + } + + return thread_error; + } + } + return Error (); +} + +Error +NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) +{ + // FIXME remove the watchpoint on the set of process watchpoint vars + // so we can add them to a thread each time a new thread is registered. + + // Update the thread list + UpdateThreads (); + + Error overall_error; + + Mutex::Locker locker (m_threads_mutex); + for (auto thread_sp : m_threads) + { + assert (thread_sp && "thread list should not have a NULL thread!"); + if (!thread_sp) + continue; + + const Error thread_error = thread_sp->RemoveWatchpoint (addr); + if (thread_error.Fail ()) + { + // Keep track of the first thread error if any threads + // fail. We want to try to remove the watchpoint from + // every thread, though, even if one or more have errors. + if (!overall_error.Fail ()) + overall_error = thread_error; + } + } + return overall_error; +} + +bool +NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate) +{ + Mutex::Locker locker (m_delegates_mutex); + if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ()) + return false; + + m_delegates.push_back (&native_delegate); + native_delegate.InitializeDelegate (this); + return true; +} + +bool +NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate) +{ + Mutex::Locker locker (m_delegates_mutex); + + const auto initial_size = m_delegates.size (); + m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ()); + + // We removed the delegate if the count of delegates shrank after + // removing all copies of the given native_delegate from the vector. + return m_delegates.size () < initial_size; +} + +void +NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state) +{ + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + + Mutex::Locker locker (m_delegates_mutex); + for (auto native_delegate: m_delegates) + native_delegate->ProcessStateChanged (this, state); + + if (log) + { + if (!m_delegates.empty ()) + { + log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64, + __FUNCTION__, lldb_private::StateAsCString (state), GetID ()); + } + else + { + log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates", + __FUNCTION__, lldb_private::StateAsCString (state), GetID ()); + } + } +} + +void +NativeProcessProtocol::NotifyDidExec () +{ + Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf ("NativeProcessProtocol::%s - preparing to call delegates", __FUNCTION__); + + { + Mutex::Locker locker (m_delegates_mutex); + for (auto native_delegate: m_delegates) + native_delegate->DidExec (this); + } +} + + +Error +NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + return m_breakpoint_list.AddRef (addr, size_hint, false, + [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error + { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); }); +} + +Error +NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.DecRef (addr); +} + +Error +NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.EnableBreakpoint (addr); +} + +Error +NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr) +{ + return m_breakpoint_list.DisableBreakpoint (addr); +} + +lldb::StateType +NativeProcessProtocol::GetState () const +{ + Mutex::Locker locker (m_state_mutex); + return m_state; +} + +void +NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) +{ + Mutex::Locker locker (m_state_mutex); + m_state = state; + + if (StateIsStoppedState (state, false)) + { + ++m_stop_id; + + // Give process a chance to do any stop id bump processing, such as + // clearing cached data that is invalidated each time the process runs. + // Note if/when we support some threads running, we'll end up needing + // to manage this per thread and per process. + DoStopIDBumped (m_stop_id); + } + + // Optionally notify delegates of the state change. + if (notify_delegates) + SynchronouslyNotifyProcessStateChanged (state); +} + +uint32_t NativeProcessProtocol::GetStopID () const +{ + Mutex::Locker locker (m_state_mutex); + return m_stop_id; +} + +void +NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */) +{ + // Default implementation does nothing. +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.h b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.h new file mode 100644 index 0000000..035a264 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.h @@ -0,0 +1,333 @@ +//===-- NativeProcessProtocol.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessProtocol_h_ +#define liblldb_NativeProcessProtocol_h_ + +#include <vector> + +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/Mutex.h" + +#include "NativeBreakpointList.h" + +namespace lldb_private +{ + class MemoryRegionInfo; + class ResumeActionList; + + //------------------------------------------------------------------ + // NativeProcessProtocol + //------------------------------------------------------------------ + class NativeProcessProtocol : + public std::enable_shared_from_this<NativeProcessProtocol> + { + friend class SoftwareBreakpoint; + + public: + static NativeProcessProtocol * + CreateInstance (lldb::pid_t pid); + + // lldb_private::Host calls should be used to launch a process for debugging, and + // then the process should be attached to. When attaching to a process + // lldb_private::Host calls should be used to locate the process to attach to, + // and then this function should be called. + NativeProcessProtocol (lldb::pid_t pid); + + public: + virtual ~NativeProcessProtocol () + { + } + + virtual Error + Resume (const ResumeActionList &resume_actions) = 0; + + virtual Error + Halt () = 0; + + virtual Error + Detach () = 0; + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// Implementer note: the WillSignal ()/DidSignal () calls + /// from the Process class are not replicated here since no + /// concrete classes implemented any behavior for those and + /// put all the work in DoSignal (...). + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Error + Signal (int signo) = 0; + + virtual Error + Kill () = 0; + + //---------------------------------------------------------------------- + // Memory and memory region functions + //---------------------------------------------------------------------- + + virtual Error + GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info); + + virtual Error + ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0; + + virtual Error + WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0; + + virtual Error + AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0; + + virtual Error + DeallocateMemory (lldb::addr_t addr) = 0; + + virtual lldb::addr_t + GetSharedLibraryInfoAddress () = 0; + + virtual bool + IsAlive () const; + + virtual size_t + UpdateThreads () = 0; + + virtual bool + GetArchitecture (ArchSpec &arch) const = 0; + + //---------------------------------------------------------------------- + // Breakpoint functions + //---------------------------------------------------------------------- + virtual Error + SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) = 0; + + virtual Error + RemoveBreakpoint (lldb::addr_t addr); + + virtual Error + EnableBreakpoint (lldb::addr_t addr); + + virtual Error + DisableBreakpoint (lldb::addr_t addr); + + //---------------------------------------------------------------------- + // Watchpoint functions + //---------------------------------------------------------------------- + virtual uint32_t + GetMaxWatchpoints () const; + + virtual Error + SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware); + + virtual Error + RemoveWatchpoint (lldb::addr_t addr); + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + lldb::pid_t + GetID() const + { + return m_pid; + } + + lldb::StateType + GetState () const; + + bool + IsRunning () const + { + return m_state == lldb::eStateRunning || IsStepping(); + } + + bool + IsStepping () const + { + return m_state == lldb::eStateStepping; + } + + bool + CanResume () const + { + return m_state == lldb::eStateStopped; + } + + bool + GetByteOrder (lldb::ByteOrder &byte_order) const; + + //---------------------------------------------------------------------- + // Exit Status + //---------------------------------------------------------------------- + virtual bool + GetExitStatus (lldb_private::ExitType *exit_type, int *status, std::string &exit_description); + + virtual bool + SetExitStatus (lldb_private::ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange); + + //---------------------------------------------------------------------- + // Access to threads + //---------------------------------------------------------------------- + NativeThreadProtocolSP + GetThreadAtIndex (uint32_t idx); + + NativeThreadProtocolSP + GetThreadByID (lldb::tid_t tid); + + void + SetCurrentThreadID (lldb::tid_t tid) + { + m_current_thread_id = tid; + } + + lldb::tid_t + GetCurrentThreadID () + { + return m_current_thread_id; + } + + NativeThreadProtocolSP + GetCurrentThread () + { + return GetThreadByID (m_current_thread_id); + } + + //---------------------------------------------------------------------- + // Access to inferior stdio + //---------------------------------------------------------------------- + virtual + int GetTerminalFileDescriptor () + { + return m_terminal_fd; + } + + //---------------------------------------------------------------------- + // Stop id interface + //---------------------------------------------------------------------- + + uint32_t + GetStopID () const; + + // --------------------------------------------------------------------- + // Callbacks for low-level process state changes + // --------------------------------------------------------------------- + class NativeDelegate + { + public: + virtual + ~NativeDelegate () {} + + virtual void + InitializeDelegate (NativeProcessProtocol *process) = 0; + + virtual void + ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0; + + virtual void + DidExec (NativeProcessProtocol *process) = 0; + }; + + //------------------------------------------------------------------ + /// Register a native delegate. + /// + /// Clients can register nofication callbacks by passing in a + /// NativeDelegate impl and passing it into this function. + /// + /// Note: it is required that the lifetime of the + /// native_delegate outlive the NativeProcessProtocol. + /// + /// @param[in] native_delegate + /// A NativeDelegate impl to be called when certain events + /// happen within the NativeProcessProtocol or related threads. + /// + /// @return + /// true if the delegate was registered successfully; + /// false if the delegate was already registered. + /// + /// @see NativeProcessProtocol::NativeDelegate. + //------------------------------------------------------------------ + bool + RegisterNativeDelegate (NativeDelegate &native_delegate); + + //------------------------------------------------------------------ + /// Unregister a native delegate previously registered. + /// + /// @param[in] native_delegate + /// A NativeDelegate impl previously registered with this process. + /// + /// @return Returns \b true if the NativeDelegate was + /// successfully removed from the process, \b false otherwise. + /// + /// @see NativeProcessProtocol::NativeDelegate + //------------------------------------------------------------------ + bool + UnregisterNativeDelegate (NativeDelegate &native_delegate); + + protected: + lldb::pid_t m_pid; + + std::vector<NativeThreadProtocolSP> m_threads; + lldb::tid_t m_current_thread_id; + mutable Mutex m_threads_mutex; + + lldb::StateType m_state; + mutable Mutex m_state_mutex; + + lldb_private::ExitType m_exit_type; + int m_exit_status; + std::string m_exit_description; + Mutex m_delegates_mutex; + std::vector<NativeDelegate*> m_delegates; + NativeBreakpointList m_breakpoint_list; + int m_terminal_fd; + uint32_t m_stop_id; + + // ----------------------------------------------------------- + // Internal interface for state handling + // ----------------------------------------------------------- + void + SetState (lldb::StateType state, bool notify_delegates = true); + + // Derived classes need not impelment this. It can be used as a + // hook to clear internal caches that should be invalidated when + // stop ids change. + // + // Note this function is called with the state mutex obtained + // by the caller. + virtual void + DoStopIDBumped (uint32_t newBumpId); + + // ----------------------------------------------------------- + // Internal interface for software breakpoints + // ----------------------------------------------------------- + Error + SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint); + + virtual Error + GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0; + + // ----------------------------------------------------------- + /// Notify the delegate that an exec occurred. + /// + /// Provide a mechanism for a delegate to clear out any exec- + /// sensitive data. + // ----------------------------------------------------------- + void + NotifyDidExec (); + + private: + + void + SynchronouslyNotifyProcessStateChanged (lldb::StateType state); + }; +} + +#endif // #ifndef liblldb_NativeProcessProtocol_h_ diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp new file mode 100644 index 0000000..6cef5b1 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.cpp @@ -0,0 +1,97 @@ +//===-- NativeThreadProtocol.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NativeThreadProtocol.h" + +#include "NativeProcessProtocol.h" +#include "lldb/Target/NativeRegisterContext.h" +#include "SoftwareBreakpoint.h" + +using namespace lldb; +using namespace lldb_private; + +NativeThreadProtocol::NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) : + m_process_wp (process->shared_from_this ()), + m_tid (tid) +{ +} + +Error +NativeThreadProtocol::ReadRegister (uint32_t reg, RegisterValue ®_value) +{ + NativeRegisterContextSP register_context_sp = GetRegisterContext (); + if (!register_context_sp) + return Error ("no register context"); + + const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg); + if (!reg_info) + return Error ("no register info for reg num %" PRIu32, reg); + + return register_context_sp->ReadRegister (reg_info, reg_value);; +} + +Error +NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue ®_value) +{ + NativeRegisterContextSP register_context_sp = GetRegisterContext (); + if (!register_context_sp) + return Error ("no register context"); + + const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg); + if (!reg_info) + return Error ("no register info for reg num %" PRIu32, reg); + + return register_context_sp->WriteRegister (reg_info, reg_value); +} + +Error +NativeThreadProtocol::SaveAllRegisters (lldb::DataBufferSP &data_sp) +{ + NativeRegisterContextSP register_context_sp = GetRegisterContext (); + if (!register_context_sp) + return Error ("no register context"); + return register_context_sp->WriteAllRegisterValues (data_sp); +} + +Error +NativeThreadProtocol::RestoreAllRegisters (lldb::DataBufferSP &data_sp) +{ + NativeRegisterContextSP register_context_sp = GetRegisterContext (); + if (!register_context_sp) + return Error ("no register context"); + return register_context_sp->ReadAllRegisterValues (data_sp); +} + +NativeProcessProtocolSP +NativeThreadProtocol::GetProcess () +{ + return m_process_wp.lock (); +} + +uint32_t +NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const +{ + // Default: no translation. Do the real translation where there + // is access to the host signal numbers. + switch (stop_info.reason) + { + case eStopReasonSignal: + return stop_info.details.signal.signo; + break; + + case eStopReasonException: + // FIXME verify the way to specify pass-thru here. + return static_cast<uint32_t> (stop_info.details.exception.type); + break; + + default: + assert (0 && "unexpected stop_info.reason found"); + return 0; + } +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.h b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.h new file mode 100644 index 0000000..9b404be --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeThreadProtocol.h @@ -0,0 +1,85 @@ +//===-- NativeThreadProtocol.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadProtocol_h_ +#define liblldb_NativeThreadProtocol_h_ + +#include <memory> + +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" +#include "lldb/Host/Debug.h" + +namespace lldb_private +{ + //------------------------------------------------------------------ + // NativeThreadProtocol + //------------------------------------------------------------------ + class NativeThreadProtocol: + public std::enable_shared_from_this<NativeThreadProtocol> + { + public: + NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid); + + virtual ~NativeThreadProtocol() + { + } + + virtual const char * + GetName() = 0; + + virtual lldb::StateType + GetState () = 0; + + virtual NativeRegisterContextSP + GetRegisterContext () = 0; + + virtual Error + ReadRegister (uint32_t reg, RegisterValue ®_value); + + virtual Error + WriteRegister (uint32_t reg, const RegisterValue ®_value); + + virtual Error + SaveAllRegisters (lldb::DataBufferSP &data_sp); + + virtual Error + RestoreAllRegisters (lldb::DataBufferSP &data_sp); + + virtual bool + GetStopReason (ThreadStopInfo &stop_info) = 0; + + virtual uint32_t + TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const; + + lldb::tid_t + GetID() const + { + return m_tid; + } + + NativeProcessProtocolSP + GetProcess (); + + // --------------------------------------------------------------------- + // Thread-specific watchpoints + // --------------------------------------------------------------------- + virtual Error + SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0; + + virtual Error + RemoveWatchpoint (lldb::addr_t addr) = 0; + + protected: + NativeProcessProtocolWP m_process_wp; + lldb::tid_t m_tid; + }; +} + +#endif // #ifndef liblldb_NativeThreadProtocol_h_ diff --git a/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp index cf13359..a91e764 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp @@ -8,11 +8,10 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/OptionParser.h" - -#if (!defined( _MSC_VER ) && defined( _WIN32 )) -#define _BSD_SOURCE // Required so that getopt.h defines optreset -#endif #include "lldb/Host/HostGetOpt.h" +#include "lldb/lldb-private-types.h" + +#include <vector> using namespace lldb_private; @@ -40,7 +39,19 @@ OptionParser::Parse (int argc, const Option *longopts, int *longindex) { - return getopt_long_only(argc, argv, optstring, (const option*)longopts, longindex); + std::vector<option> opts; + while (longopts->definition != nullptr) + { + option opt; + opt.flag = longopts->flag; + opt.val = longopts->val; + opt.name = longopts->definition->long_option; + opt.has_arg = longopts->definition->option_has_arg; + opts.push_back(opt); + ++longopts; + } + opts.push_back(option()); + return getopt_long_only(argc, argv, optstring, &opts[0], longindex); } char* diff --git a/contrib/llvm/tools/lldb/source/Host/common/Pipe.cpp b/contrib/llvm/tools/lldb/source/Host/common/Pipe.cpp new file mode 100644 index 0000000..4db0e32 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/Pipe.cpp @@ -0,0 +1,171 @@ +//===-- Pipe.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Pipe.h" + +#if defined(_WIN32) +#include <io.h> +#include <fcntl.h> +#else +#include <unistd.h> +#endif + +using namespace lldb_private; + +int Pipe::kInvalidDescriptor = -1; + +enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE + +Pipe::Pipe() +{ + m_fds[READ] = Pipe::kInvalidDescriptor; + m_fds[WRITE] = Pipe::kInvalidDescriptor; +} + +Pipe::~Pipe() +{ + Close(); +} + +bool +Pipe::Open() +{ + if (IsValid()) + return true; + +#ifdef _WIN32 + if (::_pipe(m_fds, 256, O_BINARY) == 0) + return true; +#else + if (::pipe(m_fds) == 0) + return true; +#endif + m_fds[READ] = Pipe::kInvalidDescriptor; + m_fds[WRITE] = Pipe::kInvalidDescriptor; + return false; +} + +int +Pipe::GetReadFileDescriptor() const +{ + return m_fds[READ]; +} + +int +Pipe::GetWriteFileDescriptor() const +{ + return m_fds[WRITE]; +} + +int +Pipe::ReleaseReadFileDescriptor() +{ + const int fd = m_fds[READ]; + m_fds[READ] = Pipe::kInvalidDescriptor; + return fd; +} + +int +Pipe::ReleaseWriteFileDescriptor() +{ + const int fd = m_fds[WRITE]; + m_fds[WRITE] = Pipe::kInvalidDescriptor; + return fd; +} + +void +Pipe::Close() +{ + CloseReadFileDescriptor(); + CloseWriteFileDescriptor(); +} + +bool +Pipe::ReadDescriptorIsValid() const +{ + return m_fds[READ] != Pipe::kInvalidDescriptor; +} + +bool +Pipe::WriteDescriptorIsValid() const +{ + return m_fds[WRITE] != Pipe::kInvalidDescriptor; +} + +bool +Pipe::IsValid() const +{ + return ReadDescriptorIsValid() && WriteDescriptorIsValid(); +} + +bool +Pipe::CloseReadFileDescriptor() +{ + if (ReadDescriptorIsValid()) + { + int err; +#ifdef _WIN32 + err = _close(m_fds[READ]); +#else + err = close(m_fds[READ]); +#endif + m_fds[READ] = Pipe::kInvalidDescriptor; + return err == 0; + } + return true; +} + +bool +Pipe::CloseWriteFileDescriptor() +{ + if (WriteDescriptorIsValid()) + { + int err; +#ifdef _WIN32 + err = _close(m_fds[WRITE]); +#else + err = close(m_fds[WRITE]); +#endif + m_fds[WRITE] = Pipe::kInvalidDescriptor; + return err == 0; + } + return true; +} + + +size_t +Pipe::Read (void *buf, size_t num_bytes) +{ + if (ReadDescriptorIsValid()) + { + const int fd = GetReadFileDescriptor(); +#ifdef _WIN32 + return _read (fd, (char *)buf, num_bytes); +#else + return read (fd, buf, num_bytes); +#endif + } + return 0; // Return 0 since errno won't be set if we didn't call read +} + +size_t +Pipe::Write (const void *buf, size_t num_bytes) +{ + if (WriteDescriptorIsValid()) + { + const int fd = GetWriteFileDescriptor(); +#ifdef _WIN32 + return _write (fd, (char *)buf, num_bytes); +#else + return write (fd, buf, num_bytes); +#endif + } + return 0; // Return 0 since errno won't be set if we didn't call write +} + diff --git a/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp new file mode 100644 index 0000000..31e3228 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/Socket.cpp @@ -0,0 +1,662 @@ +//===-- Socket.cpp ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Socket.h" + +#include "lldb/Core/Log.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/SocketAddress.h" +#include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" + +#ifndef LLDB_DISABLE_POSIX +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/socket.h> +#include <sys/un.h> +#endif + +using namespace lldb; +using namespace lldb_private; + +#if defined(_WIN32) +typedef const char * set_socket_option_arg_type; +typedef char * get_socket_option_arg_type; +const NativeSocket Socket::kInvalidSocketValue = INVALID_SOCKET; +#else // #if defined(_WIN32) +typedef const void * set_socket_option_arg_type; +typedef void * get_socket_option_arg_type; +const NativeSocket Socket::kInvalidSocketValue = -1; +#endif // #if defined(_WIN32) + +Socket::Socket(NativeSocket socket, SocketProtocol protocol, bool should_close) + : IOObject(eFDTypeSocket, should_close) + , m_protocol(protocol) + , m_socket(socket) +{ + +} + +Socket::~Socket() +{ + Close(); +} + +Error Socket::TcpConnect(llvm::StringRef host_and_port, Socket *&socket) +{ + // Store the result in a unique_ptr in case we error out, the memory will get correctly freed. + std::unique_ptr<Socket> final_socket; + NativeSocket sock = kInvalidSocketValue; + Error error; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST)); + if (log) + log->Printf ("Socket::TcpConnect (host/port = %s)", host_and_port.data()); + + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) + return error; + + // Create the socket + sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == kInvalidSocketValue) + { + // TODO: On Windows, use WSAGetLastError(). + error.SetErrorToErrno(); + return error; + } + + // Since they both refer to the same socket descriptor, arbitrarily choose the send socket to + // be the owner. + final_socket.reset(new Socket(sock, ProtocolTcp, true)); + + // Enable local address reuse + final_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1); + + struct sockaddr_in sa; + ::memset (&sa, 0, sizeof (sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons (port); + + int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); + + if (inet_pton_result <= 0) + { + struct hostent *host_entry = gethostbyname (host_str.c_str()); + if (host_entry) + host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); + inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); + if (inet_pton_result <= 0) + { + // TODO: On Windows, use WSAGetLastError() + if (inet_pton_result == -1) + error.SetErrorToErrno(); + else + error.SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str()); + + return error; + } + } + + if (-1 == ::connect (sock, (const struct sockaddr *)&sa, sizeof(sa))) + { + // TODO: On Windows, use WSAGetLastError() + error.SetErrorToErrno(); + return error; + } + + // Keep our TCP packets coming without any delays. + final_socket->SetOption(IPPROTO_TCP, TCP_NODELAY, 1); + error.Clear(); + socket = final_socket.release(); + return error; +} + +Error Socket::TcpListen(llvm::StringRef host_and_port, Socket *&socket, Predicate<uint16_t>* predicate) +{ + std::unique_ptr<Socket> listen_socket; + NativeSocket listen_sock = kInvalidSocketValue; + Error error; + + const sa_family_t family = AF_INET; + const int socktype = SOCK_STREAM; + const int protocol = IPPROTO_TCP; + listen_sock = ::socket (family, socktype, protocol); + if (listen_sock == kInvalidSocketValue) + { + error.SetErrorToErrno(); + return error; + } + + listen_socket.reset(new Socket(listen_sock, ProtocolTcp, true)); + + // enable local address reuse + listen_socket->SetOption(SOL_SOCKET, SO_REUSEADDR, 1); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf ("ConnectionFileDescriptor::SocketListen (%s)", host_and_port.data()); + + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) + return error; + + SocketAddress anyaddr; + if (anyaddr.SetToAnyAddress (family, port)) + { + int err = ::bind (listen_sock, anyaddr, anyaddr.GetLength()); + if (err == -1) + { + // TODO: On Windows, use WSAGetLastError() + error.SetErrorToErrno(); + return error; + } + + err = ::listen (listen_sock, 1); + if (err == -1) + { + // TODO: On Windows, use WSAGetLastError() + error.SetErrorToErrno(); + return error; + } + + // We were asked to listen on port zero which means we + // must now read the actual port that was given to us + // as port zero is a special code for "find an open port + // for me". + if (port == 0) + port = listen_socket->GetPortNumber(); + + // Set the port predicate since when doing a listen://<host>:<port> + // it often needs to accept the incoming connection which is a blocking + // system call. Allowing access to the bound port using a predicate allows + // us to wait for the port predicate to be set to a non-zero value from + // another thread in an efficient manor. + if (predicate) + predicate->SetValue(port, eBroadcastAlways); + + socket = listen_socket.release(); + } + + return error; +} + +Error Socket::BlockingAccept(llvm::StringRef host_and_port, Socket *&socket) +{ + Error error; + std::string host_str; + std::string port_str; + int32_t port; + if (!DecodeHostAndPort(host_and_port, host_str, port_str, port, &error)) + return error; + + const sa_family_t family = AF_INET; + const int socktype = SOCK_STREAM; + const int protocol = IPPROTO_TCP; + SocketAddress listen_addr; + if (host_str.empty()) + listen_addr.SetToLocalhost(family, port); + else if (host_str.compare("*") == 0) + listen_addr.SetToAnyAddress(family, port); + else + { + if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol)) + { + error.SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str()); + return error; + } + } + + bool accept_connection = false; + std::unique_ptr<Socket> accepted_socket; + + // Loop until we are happy with our connection + while (!accept_connection) + { + struct sockaddr_in accept_addr; + ::memset (&accept_addr, 0, sizeof accept_addr); +#if !(defined (__linux__) || defined(_WIN32)) + accept_addr.sin_len = sizeof accept_addr; +#endif + socklen_t accept_addr_len = sizeof accept_addr; + + int sock = ::accept (this->GetNativeSocket(), (struct sockaddr *)&accept_addr, &accept_addr_len); + + if (sock == kInvalidSocketValue) + { + // TODO: On Windows, use WSAGetLastError() + error.SetErrorToErrno(); + break; + } + + bool is_same_addr = true; +#if !(defined(__linux__) || (defined(_WIN32))) + is_same_addr = (accept_addr_len == listen_addr.sockaddr_in().sin_len); +#endif + if (is_same_addr) + is_same_addr = (accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr); + + if (is_same_addr || (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)) + { + accept_connection = true; + // Since both sockets have the same descriptor, arbitrarily choose the send + // socket to be the owner. + accepted_socket.reset(new Socket(sock, ProtocolTcp, true)); + } + else + { + const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; + const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; + ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n", + accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], + listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + accepted_socket.reset(); + } + } + + if (!accepted_socket) + return error; + + // Keep our TCP packets coming without any delays. + accepted_socket->SetOption (IPPROTO_TCP, TCP_NODELAY, 1); + error.Clear(); + socket = accepted_socket.release(); + return error; + +} + +Error Socket::UdpConnect(llvm::StringRef host_and_port, Socket *&send_socket, Socket *&recv_socket) +{ + std::unique_ptr<Socket> final_send_socket; + std::unique_ptr<Socket> final_recv_socket; + NativeSocket final_send_fd = kInvalidSocketValue; + NativeSocket final_recv_fd = kInvalidSocketValue; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf ("Socket::UdpConnect (host/port = %s)", host_and_port.data()); + + Error error; + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, &error)) + return error; + + // Setup the receiving end of the UDP connection on this localhost + // on port zero. After we bind to port zero we can read the port. + final_recv_fd = ::socket (AF_INET, SOCK_DGRAM, 0); + if (final_recv_fd == kInvalidSocketValue) + { + // Socket creation failed... + // TODO: On Windows, use WSAGetLastError(). + error.SetErrorToErrno(); + } + else + { + final_recv_socket.reset(new Socket(final_recv_fd, ProtocolUdp, true)); + + // Socket was created, now lets bind to the requested port + SocketAddress addr; + addr.SetToAnyAddress (AF_INET, 0); + + if (::bind (final_recv_fd, addr, addr.GetLength()) == -1) + { + // Bind failed... + // TODO: On Windows use WSAGetLastError() + error.SetErrorToErrno(); + } + } + + assert(error.Fail() == !(final_recv_socket && final_recv_socket->IsValid())); + if (error.Fail()) + return error; + + // At this point we have setup the receive port, now we need to + // setup the UDP send socket + + struct addrinfo hints; + struct addrinfo *service_info_list = NULL; + + ::memset (&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list); + if (err != 0) + { + error.SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)", + host_str.c_str(), + port_str.c_str(), + err, + gai_strerror(err)); + return error; + } + + for (struct addrinfo *service_info_ptr = service_info_list; + service_info_ptr != NULL; + service_info_ptr = service_info_ptr->ai_next) + { + final_send_fd = ::socket (service_info_ptr->ai_family, + service_info_ptr->ai_socktype, + service_info_ptr->ai_protocol); + + if (final_send_fd != kInvalidSocketValue) + { + final_send_socket.reset(new Socket(final_send_fd, ProtocolUdp, true)); + final_send_socket->m_udp_send_sockaddr = service_info_ptr; + break; + } + else + continue; + } + + :: freeaddrinfo (service_info_list); + + if (final_send_fd == kInvalidSocketValue) + { + // TODO: On Windows, use WSAGetLastError(). + error.SetErrorToErrno(); + return error; + } + + send_socket = final_send_socket.release(); + recv_socket = final_recv_socket.release(); + error.Clear(); + return error; +} + +Error Socket::UnixDomainConnect(llvm::StringRef name, Socket *&socket) +{ + Error error; +#ifndef LLDB_DISABLE_POSIX + std::unique_ptr<Socket> final_socket; + + // Open the socket that was passed in as an option + struct sockaddr_un saddr_un; + int fd = ::socket (AF_UNIX, SOCK_STREAM, 0); + if (fd == kInvalidSocketValue) + { + error.SetErrorToErrno(); + return error; + } + + final_socket.reset(new Socket(fd, ProtocolUnixDomain, true)); + + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) + saddr_un.sun_len = SUN_LEN (&saddr_un); +#endif + + if (::connect (fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) + { + error.SetErrorToErrno(); + return error; + } + + socket = final_socket.release(); +#else + error.SetErrorString("Unix domain sockets are not supported on this platform."); +#endif + return error; +} + +Error Socket::UnixDomainAccept(llvm::StringRef name, Socket *&socket) +{ + Error error; +#ifndef LLDB_DISABLE_POSIX + struct sockaddr_un saddr_un; + std::unique_ptr<Socket> listen_socket; + std::unique_ptr<Socket> final_socket; + NativeSocket listen_fd = kInvalidSocketValue; + NativeSocket socket_fd = kInvalidSocketValue; + + listen_fd = ::socket (AF_UNIX, SOCK_STREAM, 0); + if (listen_fd == kInvalidSocketValue) + { + error.SetErrorToErrno(); + return error; + } + + listen_socket.reset(new Socket(listen_fd, ProtocolUnixDomain, true)); + + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, name.data(), sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) + saddr_un.sun_len = SUN_LEN (&saddr_un); +#endif + + FileSystem::Unlink(name.data()); + bool success = false; + if (::bind (listen_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) + { + if (::listen (listen_fd, 5) == 0) + { + socket_fd = ::accept (listen_fd, NULL, 0); + if (socket_fd > 0) + { + final_socket.reset(new Socket(socket_fd, ProtocolUnixDomain, true)); + success = true; + } + } + } + + if (!success) + { + error.SetErrorToErrno(); + return error; + } + // We are done with the listen port + listen_socket.reset(); + + socket = final_socket.release(); +#else + error.SetErrorString("Unix domain sockets are not supported on this platform."); +#endif + return error; +} + +bool +Socket::DecodeHostAndPort(llvm::StringRef host_and_port, + std::string &host_str, + std::string &port_str, + int32_t& port, + Error *error_ptr) +{ + static RegularExpression g_regex ("([^:]+):([0-9]+)"); + RegularExpression::Match regex_match(2); + if (g_regex.Execute (host_and_port.data(), ®ex_match)) + { + if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) && + regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str)) + { + port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); + if (port != INT32_MIN) + { + if (error_ptr) + error_ptr->Clear(); + return true; + } + } + } + + // If this was unsuccessful, then check if it's simply a signed 32-bit integer, representing + // a port with an empty host. + host_str.clear(); + port_str.clear(); + port = Args::StringToSInt32(host_and_port.data(), INT32_MIN); + if (port != INT32_MIN) + { + port_str = host_and_port; + return true; + } + + if (error_ptr) + error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data()); + return false; +} + +IOObject::WaitableHandle Socket::GetWaitableHandle() +{ + // TODO: On Windows, use WSAEventSelect + return m_socket; +} + +Error Socket::Read (void *buf, size_t &num_bytes) +{ + Error error; + int bytes_received = 0; + do + { + bytes_received = ::recv (m_socket, static_cast<char *>(buf), num_bytes, 0); + // TODO: Use WSAGetLastError on windows. + } while (bytes_received < 0 && errno == EINTR); + + if (bytes_received < 0) + { + error.SetErrorToErrno(); + num_bytes = 0; + } + else + num_bytes = bytes_received; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_COMMUNICATION)); + if (log) + { + log->Printf ("%p Socket::Read() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", + static_cast<void*>(this), + static_cast<uint64_t>(m_socket), + buf, + static_cast<uint64_t>(num_bytes), + static_cast<int64_t>(bytes_received), + error.AsCString()); + } + + return error; +} + +Error Socket::Write (const void *buf, size_t &num_bytes) +{ + Error error; + int bytes_sent = 0; + do + { + if (m_protocol == ProtocolUdp) + { + bytes_sent = ::sendto (m_socket, + static_cast<const char*>(buf), + num_bytes, + 0, + m_udp_send_sockaddr, + m_udp_send_sockaddr.GetLength()); + } + else + bytes_sent = ::send (m_socket, static_cast<const char *>(buf), num_bytes, 0); + // TODO: Use WSAGetLastError on windows. + } while (bytes_sent < 0 && errno == EINTR); + + if (bytes_sent < 0) + { + // TODO: On Windows, use WSAGEtLastError. + error.SetErrorToErrno(); + num_bytes = 0; + } + else + num_bytes = bytes_sent; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST)); + if (log) + { + log->Printf ("%p Socket::Write() (socket = %" PRIu64 ", src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)", + static_cast<void*>(this), + static_cast<uint64_t>(m_socket), + buf, + static_cast<uint64_t>(num_bytes), + static_cast<int64_t>(bytes_sent), + error.AsCString()); + } + + return error; +} + +Error Socket::PreDisconnect() +{ + Error error; + return error; +} + +Error Socket::Close() +{ + Error error; + if (!IsValid() || !m_should_close_fd) + return error; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); + if (log) + log->Printf ("%p Socket::Close (fd = %i)", static_cast<void*>(this), m_socket); + +#if defined(_WIN32) + bool success = !!closesocket(m_socket); +#else + bool success = !!::close (m_socket); +#endif + // A reference to a FD was passed in, set it to an invalid value + m_socket = kInvalidSocketValue; + if (!success) + { + // TODO: On Windows, use WSAGetLastError(). + error.SetErrorToErrno(); + } + + return error; +} + + +int Socket::GetOption(int level, int option_name, int &option_value) +{ + get_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); + socklen_t option_value_size = sizeof(int); + return ::getsockopt(m_socket, level, option_name, option_value_p, &option_value_size); +} + +int Socket::SetOption(int level, int option_name, int option_value) +{ + set_socket_option_arg_type option_value_p = reinterpret_cast<get_socket_option_arg_type>(&option_value); + return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value)); +} + +uint16_t Socket::GetPortNumber(const NativeSocket& socket) +{ + // We bound to port zero, so we need to figure out which port we actually bound to + if (socket >= 0) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getsockname (socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort (); + } + return 0; +} + +// Return the port number that is being used by the socket. +uint16_t Socket::GetPortNumber() const +{ + return GetPortNumber(m_socket); +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp index 75f3cd1..a952a83 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp @@ -11,7 +11,7 @@ #include <stddef.h> // C Includes -#if !defined(_MSC_VER) +#if !defined(_WIN32) #include <arpa/inet.h> #endif #include <assert.h> @@ -90,6 +90,7 @@ GetFamilyLength (sa_family_t family) case AF_INET6: return sizeof(struct sockaddr_in6); } assert(0 && "Unsupported address family"); + return 0; } socklen_t diff --git a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp new file mode 100644 index 0000000..fe2f504 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.cpp @@ -0,0 +1,296 @@ +//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SoftwareBreakpoint.h" + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Host/Debug.h" +#include "lldb/Host/Mutex.h" + +#include "NativeProcessProtocol.h" + +using namespace lldb_private; + +// ------------------------------------------------------------------- +// static members +// ------------------------------------------------------------------- + +Error +SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp) +{ + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + // Validate the address. + if (addr == LLDB_INVALID_ADDRESS) + return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__); + + // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint + // trap for the breakpoint site. + size_t bp_opcode_size = 0; + const uint8_t *bp_opcode_bytes = NULL; + Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes); + + if (error.Fail ()) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ()); + return error; + } + + // Validate size of trap opcode. + if (bp_opcode_size == 0) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__); + return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr); + } + + if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE); + return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE); + } + + // Validate that we received opcodes. + if (!bp_opcode_bytes) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__); + return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr); + } + + // Enable the breakpoint. + uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; + error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes); + if (error.Fail ()) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ()); + return error; + } + + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); + + // Set the breakpoint and verified it was written properly. Now + // create a breakpoint remover that understands how to undo this + // breakpoint. + breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size)); + return Error (); +} + +Error +SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes) +{ + assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range"); + assert (bp_opcode_bytes && "bp_opcode_bytes is NULL"); + assert (saved_opcode_bytes && "saved_opcode_bytes is NULL"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr); + + // Save the original opcodes by reading them so we can restore later. + lldb::addr_t bytes_read = 0; + + Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_read); + if (error.Fail ()) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); + return error; + } + + // Ensure we read as many bytes as we expected. + if (bytes_read != static_cast<lldb::addr_t> (bp_opcode_size)) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read); + return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read); + } + + // Write a software breakpoint in place of the original opcode. + lldb::addr_t bytes_written = 0; + error = process.WriteMemory (addr, bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_written); + if (error.Fail ()) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ()); + return error; + } + + // Ensure we wrote as many bytes as we expected. + if (bytes_written != static_cast<lldb::addr_t> (bp_opcode_size)) + { + error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_written); + if (log) + log->PutCString (error.AsCString ()); + return error; + } + + uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE]; + lldb::addr_t verify_bytes_read = 0; + error = process.ReadMemory(addr, verify_bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), verify_bytes_read); + if (error.Fail ()) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ()); + return error; + } + + // Ensure we read as many verification bytes as we expected. + if (verify_bytes_read != static_cast<lldb::addr_t> (bp_opcode_size)) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read); + return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read); + } + + if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0) + { + if (log) + log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); + return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr); + } + + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr); + + return Error (); +} + +// ------------------------------------------------------------------- +// instance-level members +// ------------------------------------------------------------------- + +SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) : + NativeBreakpoint (addr), + m_process (process), + m_saved_opcodes (), + m_trap_opcodes (), + m_opcode_size (opcode_size) +{ + assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes"); + assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE && "trap opcode size too large"); + + ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size); + ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size); +} + +Error +SoftwareBreakpoint::DoEnable () +{ + return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes); +} + +Error +SoftwareBreakpoint::DoDisable () +{ + Error error; + assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address"); + + Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr); + + assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes"); + + if (m_opcode_size > 0) + { + // Clear a software breakoint instruction + uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE]; + bool break_op_found = false; + assert (m_opcode_size <= sizeof (curr_break_op)); + + // Read the breakpoint opcode + lldb::addr_t bytes_read = 0; + error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read); + if (error.Success () && (bytes_read < static_cast<lldb::addr_t> (m_opcode_size))) + { + error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_read); + } + if (error.Success ()) + { + bool verify = false; + // Make sure we have the a breakpoint opcode exists at this address + if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0) + { + break_op_found = true; + // We found a valid breakpoint opcode at this address, now restore + // the saved opcode. + lldb::addr_t bytes_written = 0; + error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written); + if (error.Success () && (bytes_written < static_cast<lldb::addr_t> (m_opcode_size))) + { + error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_written); + } + if (error.Success ()) + { + verify = true; + } + } + else + { + error.SetErrorString("Original breakpoint trap is no longer in memory."); + // Set verify to true and so we can check if the original opcode has already been restored + verify = true; + } + + if (verify) + { + uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE]; + assert (m_opcode_size <= sizeof (verify_opcode)); + // Verify that our original opcode made it back to the inferior + + lldb::addr_t verify_bytes_read = 0; + error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read); + if (error.Success () && (verify_bytes_read < static_cast<lldb::addr_t> (m_opcode_size))) + { + error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read); + } + if (error.Success ()) + { + // compare the memory we just read with the original opcode + if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0) + { + // SUCCESS + if (log) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr); + return error; + } + else + { + if (break_op_found) + error.SetErrorString("Failed to restore original opcode."); + } + } + else + error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored."); + } + } + } + + if (log && error.Fail ()) + log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s", + __FUNCTION__, + m_addr, + error.AsCString()); + return error; +} + +bool +SoftwareBreakpoint::IsSoftwareBreakpoint () const +{ + return true; +} + diff --git a/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.h b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.h new file mode 100644 index 0000000..1fed19e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/SoftwareBreakpoint.h @@ -0,0 +1,51 @@ +//===-- SoftwareBreakpoint.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_SoftwareBreakpoint_h_ +#define liblldb_SoftwareBreakpoint_h_ + +#include "lldb/lldb-private-forward.h" +#include "NativeBreakpoint.h" + +namespace lldb_private +{ + class SoftwareBreakpoint : public NativeBreakpoint + { + public: + static Error + CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn); + + SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size); + + protected: + Error + DoEnable () override; + + Error + DoDisable () override; + + bool + IsSoftwareBreakpoint () const override; + + private: + /// Max number of bytes that a software trap opcode sequence can occupy. + static const size_t MAX_TRAP_OPCODE_SIZE = 8; + + NativeProcessProtocol &m_process; + uint8_t m_saved_opcodes [MAX_TRAP_OPCODE_SIZE]; + uint8_t m_trap_opcodes [MAX_TRAP_OPCODE_SIZE]; + const size_t m_opcode_size; + + static Error + EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes); + + }; +} + +#endif // #ifndef liblldb_SoftwareBreakpoint_h_ diff --git a/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp b/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp index f63c468..ca46eb0 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Terminal.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Terminal.h" +#include "llvm/ADT/STLExtras.h" #include <fcntl.h> #include <signal.h> @@ -250,7 +251,7 @@ TerminalState::TTYStateIsValid() const bool TerminalState::ProcessGroupIsValid() const { - return m_process_group != -1; + return static_cast<int32_t>(m_process_group) != -1; } //------------------------------------------------------------------ @@ -274,7 +275,7 @@ TerminalStateSwitcher::~TerminalStateSwitcher () uint32_t TerminalStateSwitcher::GetNumberOfStates() const { - return sizeof(m_ttystates)/sizeof(TerminalState); + return llvm::array_lengthof(m_ttystates); } //------------------------------------------------------------------ |