diff options
Diffstat (limited to 'source/Host/windows')
-rw-r--r-- | source/Host/windows/ConnectionGenericFileWindows.cpp | 323 | ||||
-rw-r--r-- | source/Host/windows/EditLineWin.cpp | 350 | ||||
-rw-r--r-- | source/Host/windows/FileSystem.cpp | 107 | ||||
-rw-r--r-- | source/Host/windows/Host.cpp | 275 | ||||
-rw-r--r-- | source/Host/windows/HostInfoWindows.cpp | 120 | ||||
-rw-r--r-- | source/Host/windows/HostProcessWindows.cpp | 120 | ||||
-rw-r--r-- | source/Host/windows/HostThreadWindows.cpp | 75 | ||||
-rw-r--r-- | source/Host/windows/LockFileWindows.cpp | 79 | ||||
-rw-r--r-- | source/Host/windows/PipeWindows.cpp | 339 | ||||
-rw-r--r-- | source/Host/windows/ProcessLauncherWindows.cpp | 159 | ||||
-rw-r--r-- | source/Host/windows/ProcessRunLock.cpp | 82 | ||||
-rw-r--r-- | source/Host/windows/Windows.cpp | 231 |
12 files changed, 0 insertions, 2260 deletions
diff --git a/source/Host/windows/ConnectionGenericFileWindows.cpp b/source/Host/windows/ConnectionGenericFileWindows.cpp deleted file mode 100644 index e59e190dcb2d..000000000000 --- a/source/Host/windows/ConnectionGenericFileWindows.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//===-- ConnectionGenericFileWindows.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/windows/ConnectionGenericFileWindows.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/Timeout.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/ConvertUTF.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { -// This is a simple helper class to package up the information needed to return -// from a Read/Write operation function. Since there is a lot of code to be -// run before exit regardless of whether the operation succeeded or failed, -// combined with many possible return paths, this is the cleanest way to -// represent it. -class ReturnInfo { -public: - void Set(size_t bytes, ConnectionStatus status, DWORD error_code) { - m_error.SetError(error_code, eErrorTypeWin32); - m_bytes = bytes; - m_status = status; - } - - void Set(size_t bytes, ConnectionStatus status, llvm::StringRef error_msg) { - m_error.SetErrorString(error_msg.data()); - m_bytes = bytes; - m_status = status; - } - - size_t GetBytes() const { return m_bytes; } - ConnectionStatus GetStatus() const { return m_status; } - const Status &GetError() const { return m_error; } - -private: - Status m_error; - size_t m_bytes; - ConnectionStatus m_status; -}; -} - -ConnectionGenericFile::ConnectionGenericFile() - : m_file(INVALID_HANDLE_VALUE), m_owns_file(false) { - ::ZeroMemory(&m_overlapped, sizeof(m_overlapped)); - ::ZeroMemory(&m_file_position, sizeof(m_file_position)); - InitializeEventHandles(); -} - -ConnectionGenericFile::ConnectionGenericFile(lldb::file_t file, bool owns_file) - : m_file(file), m_owns_file(owns_file) { - ::ZeroMemory(&m_overlapped, sizeof(m_overlapped)); - ::ZeroMemory(&m_file_position, sizeof(m_file_position)); - InitializeEventHandles(); -} - -ConnectionGenericFile::~ConnectionGenericFile() { - if (m_owns_file && IsConnected()) - ::CloseHandle(m_file); - - ::CloseHandle(m_event_handles[kBytesAvailableEvent]); - ::CloseHandle(m_event_handles[kInterruptEvent]); -} - -void ConnectionGenericFile::InitializeEventHandles() { - m_event_handles[kInterruptEvent] = CreateEvent(NULL, FALSE, FALSE, NULL); - - // Note, we should use a manual reset event for the hEvent argument of the - // OVERLAPPED. This is because both WaitForMultipleObjects and - // GetOverlappedResult (if you set the bWait argument to TRUE) will wait for - // the event to be signalled. If we use an auto-reset event, - // WaitForMultipleObjects will reset the event, return successfully, and then - // GetOverlappedResult will block since the event is no longer signalled. - m_event_handles[kBytesAvailableEvent] = - ::CreateEvent(NULL, TRUE, FALSE, NULL); -} - -bool ConnectionGenericFile::IsConnected() const { - return m_file && (m_file != INVALID_HANDLE_VALUE); -} - -lldb::ConnectionStatus ConnectionGenericFile::Connect(llvm::StringRef path, - Status *error_ptr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionGenericFile::Connect (url = '%s')", - static_cast<void *>(this), path.str().c_str()); - - if (!path.consume_front("file://")) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("unsupported connection URL: '%s'", - path.str().c_str()); - return eConnectionStatusError; - } - - if (IsConnected()) { - ConnectionStatus status = Disconnect(error_ptr); - if (status != eConnectionStatusSuccess) - return status; - } - - // Open the file for overlapped access. If it does not exist, create it. We - // open it overlapped so that we can issue asynchronous reads and then use - // WaitForMultipleObjects to allow the read to be interrupted by an event - // object. - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(path, wpath)) { - if (error_ptr) - error_ptr->SetError(1, eErrorTypeGeneric); - return eConnectionStatusError; - } - m_file = ::CreateFileW(wpath.c_str(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, OPEN_ALWAYS, - FILE_FLAG_OVERLAPPED, NULL); - if (m_file == INVALID_HANDLE_VALUE) { - if (error_ptr) - error_ptr->SetError(::GetLastError(), eErrorTypeWin32); - return eConnectionStatusError; - } - - m_owns_file = true; - m_uri.assign(path); - return eConnectionStatusSuccess; -} - -lldb::ConnectionStatus ConnectionGenericFile::Disconnect(Status *error_ptr) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) - log->Printf("%p ConnectionGenericFile::Disconnect ()", - static_cast<void *>(this)); - - if (!IsConnected()) - return eConnectionStatusSuccess; - - // Reset the handle so that after we unblock any pending reads, subsequent - // calls to Read() will see a disconnected state. - HANDLE old_file = m_file; - m_file = INVALID_HANDLE_VALUE; - - // Set the disconnect event so that any blocking reads unblock, then cancel - // any pending IO operations. - ::CancelIoEx(old_file, &m_overlapped); - - // Close the file handle if we owned it, but don't close the event handles. - // We could always reconnect with the same Connection instance. - if (m_owns_file) - ::CloseHandle(old_file); - - ::ZeroMemory(&m_file_position, sizeof(m_file_position)); - m_owns_file = false; - m_uri.clear(); - return eConnectionStatusSuccess; -} - -size_t ConnectionGenericFile::Read(void *dst, size_t dst_len, - const Timeout<std::micro> &timeout, - lldb::ConnectionStatus &status, - Status *error_ptr) { - ReturnInfo return_info; - BOOL result = 0; - DWORD bytes_read = 0; - - if (error_ptr) - error_ptr->Clear(); - - if (!IsConnected()) { - return_info.Set(0, eConnectionStatusNoConnection, ERROR_INVALID_HANDLE); - goto finish; - } - - m_overlapped.hEvent = m_event_handles[kBytesAvailableEvent]; - - result = ::ReadFile(m_file, dst, dst_len, NULL, &m_overlapped); - if (result || ::GetLastError() == ERROR_IO_PENDING) { - if (!result) { - // The expected return path. The operation is pending. Wait for the - // operation to complete or be interrupted. - DWORD milliseconds = - timeout - ? std::chrono::duration_cast<std::chrono::milliseconds>(*timeout) - .count() - : INFINITE; - DWORD wait_result = - ::WaitForMultipleObjects(llvm::array_lengthof(m_event_handles), - m_event_handles, FALSE, milliseconds); - // All of the events are manual reset events, so make sure we reset them - // to non-signalled. - switch (wait_result) { - case WAIT_OBJECT_0 + kBytesAvailableEvent: - break; - case WAIT_OBJECT_0 + kInterruptEvent: - return_info.Set(0, eConnectionStatusInterrupted, 0); - goto finish; - case WAIT_TIMEOUT: - return_info.Set(0, eConnectionStatusTimedOut, 0); - goto finish; - case WAIT_FAILED: - return_info.Set(0, eConnectionStatusError, ::GetLastError()); - goto finish; - } - } - // The data is ready. Figure out how much was read and return; - if (!::GetOverlappedResult(m_file, &m_overlapped, &bytes_read, FALSE)) { - DWORD result_error = ::GetLastError(); - // ERROR_OPERATION_ABORTED occurs when someone calls Disconnect() during - // a blocking read. This triggers a call to CancelIoEx, which causes the - // operation to complete and the result to be ERROR_OPERATION_ABORTED. - if (result_error == ERROR_HANDLE_EOF || - result_error == ERROR_OPERATION_ABORTED || - result_error == ERROR_BROKEN_PIPE) - return_info.Set(bytes_read, eConnectionStatusEndOfFile, 0); - else - return_info.Set(bytes_read, eConnectionStatusError, result_error); - } else if (bytes_read == 0) - return_info.Set(bytes_read, eConnectionStatusEndOfFile, 0); - else - return_info.Set(bytes_read, eConnectionStatusSuccess, 0); - - goto finish; - } else if (::GetLastError() == ERROR_BROKEN_PIPE) { - // The write end of a pipe was closed. This is equivalent to EOF. - return_info.Set(0, eConnectionStatusEndOfFile, 0); - } else { - // An unknown error occurred. Fail out. - return_info.Set(0, eConnectionStatusError, ::GetLastError()); - } - goto finish; - -finish: - status = return_info.GetStatus(); - if (error_ptr) - *error_ptr = return_info.GetError(); - - // kBytesAvailableEvent is a manual reset event. Make sure it gets reset - // here so that any subsequent operations don't immediately see bytes - // available. - ResetEvent(m_event_handles[kBytesAvailableEvent]); - - IncrementFilePointer(return_info.GetBytes()); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) { - log->Printf("%p ConnectionGenericFile::Read() handle = %p, dst = %p, " - "dst_len = %zu) => %zu, error = %s", - this, m_file, dst, dst_len, return_info.GetBytes(), - return_info.GetError().AsCString()); - } - - return return_info.GetBytes(); -} - -size_t ConnectionGenericFile::Write(const void *src, size_t src_len, - lldb::ConnectionStatus &status, - Status *error_ptr) { - ReturnInfo return_info; - DWORD bytes_written = 0; - BOOL result = 0; - - if (error_ptr) - error_ptr->Clear(); - - if (!IsConnected()) { - return_info.Set(0, eConnectionStatusNoConnection, ERROR_INVALID_HANDLE); - goto finish; - } - - m_overlapped.hEvent = NULL; - - // Writes are not interruptible like reads are, so just block until it's - // done. - result = ::WriteFile(m_file, src, src_len, NULL, &m_overlapped); - if (!result && ::GetLastError() != ERROR_IO_PENDING) { - return_info.Set(0, eConnectionStatusError, ::GetLastError()); - goto finish; - } - - if (!::GetOverlappedResult(m_file, &m_overlapped, &bytes_written, TRUE)) { - return_info.Set(bytes_written, eConnectionStatusError, ::GetLastError()); - goto finish; - } - - return_info.Set(bytes_written, eConnectionStatusSuccess, 0); - goto finish; - -finish: - status = return_info.GetStatus(); - if (error_ptr) - *error_ptr = return_info.GetError(); - - IncrementFilePointer(return_info.GetBytes()); - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION)); - if (log) { - log->Printf("%p ConnectionGenericFile::Write() handle = %p, src = %p, " - "src_len = %zu) => %zu, error = %s", - this, m_file, src, src_len, return_info.GetBytes(), - return_info.GetError().AsCString()); - } - return return_info.GetBytes(); -} - -std::string ConnectionGenericFile::GetURI() { return m_uri; } - -bool ConnectionGenericFile::InterruptRead() { - return ::SetEvent(m_event_handles[kInterruptEvent]); -} - -void ConnectionGenericFile::IncrementFilePointer(DWORD amount) { - LARGE_INTEGER old_pos; - old_pos.HighPart = m_overlapped.OffsetHigh; - old_pos.LowPart = m_overlapped.Offset; - old_pos.QuadPart += amount; - m_overlapped.Offset = old_pos.LowPart; - m_overlapped.OffsetHigh = old_pos.HighPart; -} diff --git a/source/Host/windows/EditLineWin.cpp b/source/Host/windows/EditLineWin.cpp deleted file mode 100644 index 3bccc4e1a2c9..000000000000 --- a/source/Host/windows/EditLineWin.cpp +++ /dev/null @@ -1,350 +0,0 @@ -//===-- EditLineWin.cpp -----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// this file is only relevant for Visual C++ -#if defined(_WIN32) - -#include "lldb/Host/windows/windows.h" - -#include "lldb/Host/windows/editlinewin.h" -#include "llvm/Support/ErrorHandling.h" -#include <assert.h> -#include <vector> - -// edit line EL_ADDFN function pointer type -typedef unsigned char (*el_addfn_func)(EditLine *e, int ch); -typedef const char *(*el_prompt_func)(EditLine *); - -// edit line wrapper binding container -struct el_binding { - // - const char *name; - const char *help; - // function pointer to callback routine - el_addfn_func func; - // ascii key this function is bound to - const char *key; -}; - -// stored key bindings -static std::vector<el_binding *> _bindings; - -// TODO: this should in fact be related to the exact edit line context we create -static void *clientData = NULL; - -// store the current prompt string -// default to what we expect to receive anyway -static const char *_prompt = "(lldb) "; - -#if !defined(_WIP_INPUT_METHOD) - -static char *el_get_s(char *buffer, int chars) { return gets_s(buffer, chars); } -#else - -static void con_output(char _in) { - HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written = 0; - // get the cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(hout, &info); - // output this char - WriteConsoleOutputCharacterA(hout, &_in, 1, info.dwCursorPosition, &written); - // advance cursor position - info.dwCursorPosition.X++; - SetConsoleCursorPosition(hout, info.dwCursorPosition); -} - -static void con_backspace(void) { - HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(hout, &info); - // nudge cursor backwards - info.dwCursorPosition.X--; - SetConsoleCursorPosition(hout, info.dwCursorPosition); - // blank out the last character - WriteConsoleOutputCharacterA(hout, " ", 1, info.dwCursorPosition, &written); -} - -static void con_return(void) { - HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo(hout, &info); - // move onto the new line - info.dwCursorPosition.X = 0; - info.dwCursorPosition.Y++; - SetConsoleCursorPosition(hout, info.dwCursorPosition); -} - -static bool runBind(char _key) { - for (int i = 0; i < _bindings.size(); i++) { - el_binding *bind = _bindings[i]; - if (bind->key[0] == _key) { - bind->func((EditLine *)-1, _key); - return true; - } - } - return false; -} - -// replacement get_s which is EL_BIND aware -static char *el_get_s(char *buffer, int chars) { - // - char *head = buffer; - // - for (;; Sleep(10)) { - // - INPUT_RECORD _record; - // - DWORD _read = 0; - if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE), &_record, 1, - &_read) == FALSE) - break; - // if we didn't read a key - if (_read == 0) - continue; - // only interested in key events - if (_record.EventType != KEY_EVENT) - continue; - // is the key down - if (!_record.Event.KeyEvent.bKeyDown) - continue; - // read the ascii key character - char _key = _record.Event.KeyEvent.uChar.AsciiChar; - // non ascii conformant key press - if (_key == 0) { - // check the scan code - // if VK_UP scroll back through history - // if VK_DOWN scroll forward through history - continue; - } - // try to execute any bind this key may have - if (runBind(_key)) - continue; - // if we read a return key - if (_key == '\n' || _key == '\r') { - con_return(); - break; - } - // key is backspace - if (_key == 0x8) { - // avoid deleting past beginning - if (head > buffer) { - con_backspace(); - head--; - } - continue; - } - - // add this key to the input buffer - if ((head - buffer) < (chars - 1)) { - con_output(_key); - *(head++) = _key; - } - } - // insert end of line character - *head = '\0'; - - return buffer; -} -#endif - -// edit line initialize -EditLine *el_init(const char *, FILE *, FILE *, FILE *) { - // - SetConsoleTitleA("lldb"); - // return dummy handle - return (EditLine *)-1; -} - -const char *el_gets(EditLine *el, int *length) { - // print the prompt if we have one - if (_prompt != NULL) - printf("%s", _prompt); - // create a buffer for the user input - char *buffer = new char[MAX_PATH]; - // try to get user input string - if (el_get_s(buffer, MAX_PATH)) { - // get the string length in 'length' - while (buffer[*length] != '\0') - (*length)++; - // return the input buffer - // remember that this memory has the be free'd somewhere - return buffer; - } else { - // on error - delete[] buffer; - return NULL; - } -} - -int el_set(EditLine *el, int code, ...) { - va_list vl; - va_start(vl, code); - // - switch (code) { - // edit line set prompt message - case (EL_PROMPT): { - // EL_PROMPT, char *(*f)( EditLine *) - // define a prompt printing function as 'f', which is to return a - // string that - // contains the prompt. - - // get the function pointer from the arg list - void *func_vp = (void *)va_arg(vl, el_prompt_func); - // cast to suitable prototype - el_prompt_func func_fp = (el_prompt_func)func_vp; - // call to get the prompt as a string - _prompt = func_fp(el); - } break; - - case (EL_PROMPT_ESC): { - // EL_PROMPT, char *(*f)( EditLine *) - // define a prompt printing function as 'f', which is to return a - // string that - // contains the prompt. - - // get the function pointer from the arg list - void *func_vp = (void *)va_arg(vl, el_prompt_func); - va_arg(vl, int); - // call to get the prompt as a string - el_prompt_func func_fp = (el_prompt_func)func_vp; - _prompt = func_fp(el); - } break; - - case (EL_EDITOR): { - // EL_EDITOR, const char *mode - // set editing mode to "emacs" or "vi" - } break; - case (EL_HIST): { - // EL_HIST, History *(*fun)(History *, int op, ... ), const char *ptr - // defines which history function to use, which is usually history(). - // Ptr should be the - // value returned by history_init(). - } break; - case (EL_ADDFN): { - // EL_ADDFN, const char *name, const char *help, unsigned char - // (*func)(EditLine *e, int ch) - // add a user defined function, func), referred to as 'name' which is - // invoked when a key which is bound to 'name' is - // entered. 'help' is a description of 'name'. at invocation time, 'ch' - // is the key which caused the invocation. the - // return value of 'func()' should be one of: - // CC_NORM add a normal character - // CC_NEWLINE end of line was entered - // CC_EOF EOF was entered - // CC_ARGHACK expecting further command input as arguments, do - // nothing visually. - // CC_REFRESH refresh display. - // CC_REFRESH_BEEP refresh display and beep. - // CC_CURSOR cursor moved so update and perform CC_REFRESH - // CC_REDISPLAY redisplay entire input line. this is useful - // if a key binding outputs extra information. - // CC_ERROR an error occurred. beep and flush tty. - // CC_FATAL fatal error, reset tty to known state. - - el_binding *binding = new el_binding; - binding->name = va_arg(vl, const char *); - binding->help = va_arg(vl, const char *); - binding->func = va_arg(vl, el_addfn_func); - binding->key = 0; - // add this to the bindings list - _bindings.push_back(binding); - } break; - case (EL_BIND): { - // EL_BIND, const char *, ..., NULL - // perform the BIND built-in command. Refer to editrc(5) for more - // information. - - const char *name = va_arg(vl, const char *); - - for (auto bind : _bindings) { - if (strcmp(bind->name, name) == 0) { - bind->key = va_arg(vl, const char *); - break; - } - } - - } break; - case (EL_CLIENTDATA): { - clientData = va_arg(vl, void *); - } break; - } - return 0; -} - -void el_end(EditLine *el) { - // assert( !"Not implemented!" ); -} - -void el_reset(EditLine *) { llvm_unreachable("Not implemented!"); } - -int el_getc(EditLine *, char *) { - llvm_unreachable("Not implemented!"); -} - -void el_push(EditLine *, const char *) {} - -void el_beep(EditLine *) { Beep(1000, 500); } - -int el_parse(EditLine *, int, const char **) { - llvm_unreachable("Not implemented!"); -} - -int el_get(EditLine *el, int code, ...) { - va_list vl; - va_start(vl, code); - - switch (code) { - case (EL_CLIENTDATA): { - void **dout = va_arg(vl, void **); - *dout = clientData; - } break; - default: - llvm_unreachable("Not implemented!"); - } - return 0; -} - -int el_source(EditLine *el, const char *file) { - // init edit line by reading the contents of 'file' nothing to do here on - // windows... - return 0; -} - -void el_resize(EditLine *) { llvm_unreachable("Not implemented!"); } - -const LineInfo *el_line(EditLine *el) { return 0; } - -int el_insertstr(EditLine *, const char *) { - // assert( !"Not implemented!" ); - return 0; -} - -void el_deletestr(EditLine *, int) { llvm_unreachable("Not implemented!"); } - -History *history_init(void) { - // return dummy handle - return (History *)-1; -} - -void history_end(History *) { - // assert( !"Not implemented!" ); -} - -int history(History *, HistEvent *, int op, ...) { - // perform operation 'op' on the history list with optional arguments as - // needed by the operation. - return 0; -} - -#endif diff --git a/source/Host/windows/FileSystem.cpp b/source/Host/windows/FileSystem.cpp deleted file mode 100644 index 3217cdc8480a..000000000000 --- a/source/Host/windows/FileSystem.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===-- FileSystem.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/windows/windows.h" - -#include <shellapi.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/windows/AutoHandle.h" -#include "lldb/Host/windows/PosixApi.h" - -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" - -using namespace lldb_private; - -const char *FileSystem::DEV_NULL = "nul"; - -const char *FileSystem::PATH_CONVERSION_ERROR = - "Error converting path between UTF-8 and native encoding"; - -Status FileSystem::Symlink(const FileSpec &src, const FileSpec &dst) { - Status error; - std::wstring wsrc, wdst; - if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc) || - !llvm::ConvertUTF8toWide(dst.GetCString(), wdst)) - error.SetErrorString(PATH_CONVERSION_ERROR); - if (error.Fail()) - return error; - DWORD attrib = ::GetFileAttributesW(wdst.c_str()); - if (attrib == INVALID_FILE_ATTRIBUTES) { - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - return error; - } - bool is_directory = !!(attrib & FILE_ATTRIBUTE_DIRECTORY); - DWORD flag = is_directory ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; - BOOL result = ::CreateSymbolicLinkW(wsrc.c_str(), wdst.c_str(), flag); - if (!result) - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - return error; -} - -Status FileSystem::Readlink(const FileSpec &src, FileSpec &dst) { - Status error; - std::wstring wsrc; - if (!llvm::ConvertUTF8toWide(src.GetCString(), wsrc)) { - error.SetErrorString(PATH_CONVERSION_ERROR); - return error; - } - - HANDLE h = ::CreateFileW(wsrc.c_str(), GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); - if (h == INVALID_HANDLE_VALUE) { - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - return error; - } - - std::vector<wchar_t> buf(PATH_MAX + 1); - // Subtract 1 from the path length since this function does not add a null - // terminator. - DWORD result = ::GetFinalPathNameByHandleW( - h, buf.data(), buf.size() - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); - std::string path; - if (result == 0) - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - else if (!llvm::convertWideToUTF8(buf.data(), path)) - error.SetErrorString(PATH_CONVERSION_ERROR); - else - dst.SetFile(path, FileSpec::Style::native); - - ::CloseHandle(h); - return error; -} - -Status FileSystem::ResolveSymbolicLink(const FileSpec &src, FileSpec &dst) { - return Status("ResolveSymbolicLink() isn't implemented on Windows"); -} - -FILE *FileSystem::Fopen(const char *path, const char *mode) { - std::wstring wpath, wmode; - if (!llvm::ConvertUTF8toWide(path, wpath)) - return nullptr; - if (!llvm::ConvertUTF8toWide(mode, wmode)) - return nullptr; - FILE *file; - if (_wfopen_s(&file, wpath.c_str(), wmode.c_str()) != 0) - return nullptr; - return file; -} - -int FileSystem::Open(const char *path, int flags, int mode) { - std::wstring wpath; - if (!llvm::ConvertUTF8toWide(path, wpath)) - return -1; - int result; - ::_wsopen_s(&result, wpath.c_str(), flags, _SH_DENYNO, mode); - return result; -} diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp deleted file mode 100644 index 3ac16a42286a..000000000000 --- a/source/Host/windows/Host.cpp +++ /dev/null @@ -1,275 +0,0 @@ -//===-- source/Host/windows/Host.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/windows/AutoHandle.h" -#include "lldb/Host/windows/windows.h" -#include <stdio.h> - -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Target/Process.h" -#include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/StructuredData.h" - -#include "llvm/Support/ConvertUTF.h" - -// Windows includes -#include <tlhelp32.h> - -using namespace lldb; -using namespace lldb_private; - -namespace { -bool GetTripleForProcess(const FileSpec &executable, llvm::Triple &triple) { - // Open the PE File as a binary file, and parse just enough information to - // determine the machine type. - File imageBinary; - FileSystem::Instance().Open(imageBinary, executable, File::eOpenOptionRead, - lldb::eFilePermissionsUserRead); - imageBinary.SeekFromStart(0x3c); - int32_t peOffset = 0; - uint32_t peHead = 0; - uint16_t machineType = 0; - size_t readSize = sizeof(peOffset); - imageBinary.Read(&peOffset, readSize); - imageBinary.SeekFromStart(peOffset); - imageBinary.Read(&peHead, readSize); - if (peHead != 0x00004550) // "PE\0\0", little-endian - return false; // Status: Can't find PE header - readSize = 2; - imageBinary.Read(&machineType, readSize); - triple.setVendor(llvm::Triple::PC); - triple.setOS(llvm::Triple::Win32); - triple.setArch(llvm::Triple::UnknownArch); - if (machineType == 0x8664) - triple.setArch(llvm::Triple::x86_64); - else if (machineType == 0x14c) - triple.setArch(llvm::Triple::x86); - - return true; -} - -bool GetExecutableForProcess(const AutoHandle &handle, std::string &path) { - // Get the process image path. MAX_PATH isn't long enough, paths can - // actually be up to 32KB. - std::vector<wchar_t> buffer(PATH_MAX); - DWORD dwSize = buffer.size(); - if (!::QueryFullProcessImageNameW(handle.get(), 0, &buffer[0], &dwSize)) - return false; - return llvm::convertWideToUTF8(buffer.data(), path); -} - -void GetProcessExecutableAndTriple(const AutoHandle &handle, - ProcessInstanceInfo &process) { - // We may not have permissions to read the path from the process. So start - // off by setting the executable file to whatever Toolhelp32 gives us, and - // then try to enhance this with more detailed information, but fail - // gracefully. - std::string executable; - llvm::Triple triple; - triple.setVendor(llvm::Triple::PC); - triple.setOS(llvm::Triple::Win32); - triple.setArch(llvm::Triple::UnknownArch); - if (GetExecutableForProcess(handle, executable)) { - FileSpec executableFile(executable.c_str()); - process.SetExecutableFile(executableFile, true); - GetTripleForProcess(executableFile, triple); - } - process.SetArchitecture(ArchSpec(triple)); - - // TODO(zturner): Add the ability to get the process user name. -} -} - -lldb::thread_t Host::GetCurrentThread() { - return lldb::thread_t(::GetCurrentThread()); -} - -void Host::Kill(lldb::pid_t pid, int signo) { - TerminateProcess((HANDLE)pid, 1); -} - -const char *Host::GetSignalAsCString(int signo) { return NULL; } - -FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { - FileSpec module_filespec; - - HMODULE hmodule = NULL; - if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR)host_addr, &hmodule)) - return module_filespec; - - std::vector<wchar_t> buffer(PATH_MAX); - DWORD chars_copied = 0; - do { - chars_copied = ::GetModuleFileNameW(hmodule, &buffer[0], buffer.size()); - if (chars_copied == buffer.size() && - ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) - buffer.resize(buffer.size() * 2); - } while (chars_copied >= buffer.size()); - std::string path; - if (!llvm::convertWideToUTF8(buffer.data(), path)) - return module_filespec; - module_filespec.SetFile(path, FileSpec::Style::native); - return module_filespec; -} - -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); - - AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); - if (!snapshot.IsValid()) - return 0; - - PROCESSENTRY32W pe = {}; - pe.dwSize = sizeof(PROCESSENTRY32W); - if (Process32FirstW(snapshot.get(), &pe)) { - do { - AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, - pe.th32ProcessID), - nullptr); - - ProcessInstanceInfo process; - std::string exeFile; - llvm::convertWideToUTF8(pe.szExeFile, exeFile); - process.SetExecutableFile(FileSpec(exeFile), true); - process.SetProcessID(pe.th32ProcessID); - process.SetParentProcessID(pe.th32ParentProcessID); - GetProcessExecutableAndTriple(handle, process); - - if (match_info.MatchAllProcesses() || match_info.Matches(process)) - process_infos.Append(process); - } while (Process32NextW(snapshot.get(), &pe)); - } - return process_infos.GetSize(); -} - -bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { - process_info.Clear(); - - AutoHandle handle( - ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid), - nullptr); - if (!handle.IsValid()) - return false; - - process_info.SetProcessID(pid); - GetProcessExecutableAndTriple(handle, process_info); - - // Need to read the PEB to get parent process and command line arguments. - return true; -} - -HostThread Host::StartMonitoringChildProcess( - const Host::MonitorChildProcessCallback &callback, lldb::pid_t pid, - bool monitor_signals) { - return HostThread(); -} - -Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { - Status error; - if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { - FileSpec expand_tool_spec = HostInfo::GetSupportExeDir(); - if (!expand_tool_spec) { - error.SetErrorString("could not find support executable directory for " - "the lldb-argdumper tool"); - return error; - } - expand_tool_spec.AppendPathComponent("lldb-argdumper.exe"); - if (!FileSystem::Instance().Exists(expand_tool_spec)) { - error.SetErrorString("could not find the lldb-argdumper tool"); - return error; - } - - std::string quoted_cmd_string; - launch_info.GetArguments().GetQuotedCommandString(quoted_cmd_string); - std::replace(quoted_cmd_string.begin(), quoted_cmd_string.end(), '\\', '/'); - StreamString expand_command; - - expand_command.Printf("\"%s\" %s", expand_tool_spec.GetPath().c_str(), - quoted_cmd_string.c_str()); - - int status; - std::string output; - std::string command = expand_command.GetString(); - RunShellCommand(command.c_str(), launch_info.GetWorkingDirectory(), &status, - nullptr, &output, std::chrono::seconds(10)); - - if (status != 0) { - error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", - status); - return error; - } - - auto data_sp = StructuredData::ParseJSON(output); - if (!data_sp) { - error.SetErrorString("invalid JSON"); - return error; - } - - auto dict_sp = data_sp->GetAsDictionary(); - if (!data_sp) { - error.SetErrorString("invalid JSON"); - return error; - } - - auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments"); - if (!args_sp) { - error.SetErrorString("invalid JSON"); - return error; - } - - auto args_array_sp = args_sp->GetAsArray(); - if (!args_array_sp) { - error.SetErrorString("invalid JSON"); - return error; - } - - launch_info.GetArguments().Clear(); - - for (size_t i = 0; i < args_array_sp->GetSize(); i++) { - auto item_sp = args_array_sp->GetItemAtIndex(i); - if (!item_sp) - continue; - auto str_sp = item_sp->GetAsString(); - if (!str_sp) - continue; - - launch_info.GetArguments().AppendArgument(str_sp->GetValue()); - } - } - - return error; -} - -Environment Host::GetEnvironment() { - Environment env; - // The environment block on Windows is a contiguous buffer of NULL terminated - // strings, where the end of the environment block is indicated by two - // consecutive NULLs. - LPWCH environment_block = ::GetEnvironmentStringsW(); - while (*environment_block != L'\0') { - std::string current_var; - auto current_var_size = wcslen(environment_block) + 1; - if (!llvm::convertWideToUTF8(environment_block, current_var)) { - environment_block += current_var_size; - continue; - } - if (current_var[0] != '=') - env.insert(current_var); - - environment_block += current_var_size; - } - return env; -} diff --git a/source/Host/windows/HostInfoWindows.cpp b/source/Host/windows/HostInfoWindows.cpp deleted file mode 100644 index 81392d9a85b3..000000000000 --- a/source/Host/windows/HostInfoWindows.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===-- HostInfoWindows.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/windows/windows.h" - -#include <objbase.h> - -#include <mutex> - -#include "lldb/Host/windows/HostInfoWindows.h" -#include "lldb/Host/windows/PosixApi.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lldb_private; - -FileSpec HostInfoWindows::m_program_filespec; - -void HostInfoWindows::Initialize() { - ::CoInitializeEx(nullptr, COINIT_MULTITHREADED); - HostInfoBase::Initialize(); -} - -void HostInfoWindows::Terminate() { - HostInfoBase::Terminate(); - ::CoUninitialize(); -} - -size_t HostInfoWindows::GetPageSize() { - SYSTEM_INFO systemInfo; - GetNativeSystemInfo(&systemInfo); - return systemInfo.dwPageSize; -} - -llvm::VersionTuple HostInfoWindows::GetOSVersion() { - OSVERSIONINFOEX info; - - ZeroMemory(&info, sizeof(OSVERSIONINFOEX)); - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); -#pragma warning(push) -#pragma warning(disable : 4996) - // Starting with Microsoft SDK for Windows 8.1, this function is deprecated - // in favor of the new Windows Version Helper APIs. Since we don't specify a - // minimum SDK version, it's easier to simply disable the warning rather than - // try to support both APIs. - if (GetVersionEx((LPOSVERSIONINFO)&info) == 0) - return llvm::VersionTuple(); -#pragma warning(pop) - - return llvm::VersionTuple(info.dwMajorVersion, info.dwMinorVersion, - info.wServicePackMajor); -} - -bool HostInfoWindows::GetOSBuildString(std::string &s) { - s.clear(); - llvm::VersionTuple version = GetOSVersion(); - if (version.empty()) - return false; - - llvm::raw_string_ostream stream(s); - stream << "Windows NT " << version.getAsString(); - return true; -} - -bool HostInfoWindows::GetOSKernelDescription(std::string &s) { - return GetOSBuildString(s); -} - -bool HostInfoWindows::GetHostname(std::string &s) { - wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1; - if (!::GetComputerNameW(buffer, &dwSize)) - return false; - - return llvm::convertWideToUTF8(buffer, s); -} - -FileSpec HostInfoWindows::GetProgramFileSpec() { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - std::vector<wchar_t> buffer(PATH_MAX); - ::GetModuleFileNameW(NULL, buffer.data(), buffer.size()); - std::string path; - llvm::convertWideToUTF8(buffer.data(), path); - m_program_filespec.SetFile(path, FileSpec::Style::native); - }); - return m_program_filespec; -} - -FileSpec HostInfoWindows::GetDefaultShell() { - // Try to retrieve ComSpec from the environment. On the rare occasion - // that it fails, try a well-known path for ComSpec instead. - - std::string shell; - if (GetEnvironmentVar("ComSpec", shell)) - return FileSpec(shell); - - return FileSpec("C:\\Windows\\system32\\cmd.exe"); -} - -bool HostInfoWindows::GetEnvironmentVar(const std::string &var_name, - std::string &var) { - std::wstring wvar_name; - if (!llvm::ConvertUTF8toWide(var_name, wvar_name)) - return false; - - if (const wchar_t *wvar = _wgetenv(wvar_name.c_str())) - return llvm::convertWideToUTF8(wvar, var); - return false; -} diff --git a/source/Host/windows/HostProcessWindows.cpp b/source/Host/windows/HostProcessWindows.cpp deleted file mode 100644 index 701167ff6fea..000000000000 --- a/source/Host/windows/HostProcessWindows.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===-- HostProcessWindows.cpp ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/windows/HostProcessWindows.h" -#include "lldb/Host/HostThread.h" -#include "lldb/Host/ThreadLauncher.h" -#include "lldb/Host/windows/windows.h" -#include "lldb/Utility/FileSpec.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/ConvertUTF.h" - -#include <psapi.h> - -using namespace lldb_private; - -namespace { -struct MonitorInfo { - Host::MonitorChildProcessCallback callback; - HANDLE process_handle; -}; -} - -HostProcessWindows::HostProcessWindows() - : HostNativeProcessBase(), m_owns_handle(true) {} - -HostProcessWindows::HostProcessWindows(lldb::process_t process) - : HostNativeProcessBase(process), m_owns_handle(true) {} - -HostProcessWindows::~HostProcessWindows() { Close(); } - -void HostProcessWindows::SetOwnsHandle(bool owns) { m_owns_handle = owns; } - -Status HostProcessWindows::Terminate() { - Status error; - if (m_process == nullptr) - error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32); - - if (!::TerminateProcess(m_process, 0)) - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - - return error; -} - -Status HostProcessWindows::GetMainModule(FileSpec &file_spec) const { - Status error; - if (m_process == nullptr) - error.SetError(ERROR_INVALID_HANDLE, lldb::eErrorTypeWin32); - - std::vector<wchar_t> wpath(PATH_MAX); - if (::GetProcessImageFileNameW(m_process, wpath.data(), wpath.size())) { - std::string path; - if (llvm::convertWideToUTF8(wpath.data(), path)) - file_spec.SetFile(path, FileSpec::Style::native); - else - error.SetErrorString("Error converting path to UTF-8"); - } else - error.SetError(::GetLastError(), lldb::eErrorTypeWin32); - - return error; -} - -lldb::pid_t HostProcessWindows::GetProcessId() const { - return (m_process == LLDB_INVALID_PROCESS) ? -1 : ::GetProcessId(m_process); -} - -bool HostProcessWindows::IsRunning() const { - if (m_process == nullptr) - return false; - - DWORD code = 0; - if (!::GetExitCodeProcess(m_process, &code)) - return false; - - return (code == STILL_ACTIVE); -} - -HostThread HostProcessWindows::StartMonitoring( - const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { - HostThread monitor_thread; - MonitorInfo *info = new MonitorInfo; - info->callback = callback; - - // Since the life of this HostProcessWindows instance and the life of the - // process may be different, duplicate the handle so that the monitor thread - // can have ownership over its own copy of the handle. - HostThread result; - if (::DuplicateHandle(GetCurrentProcess(), m_process, GetCurrentProcess(), - &info->process_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) - result = ThreadLauncher::LaunchThread("ChildProcessMonitor", - HostProcessWindows::MonitorThread, - info, nullptr); - return result; -} - -lldb::thread_result_t HostProcessWindows::MonitorThread(void *thread_arg) { - DWORD exit_code; - - MonitorInfo *info = static_cast<MonitorInfo *>(thread_arg); - if (info) { - ::WaitForSingleObject(info->process_handle, INFINITE); - ::GetExitCodeProcess(info->process_handle, &exit_code); - info->callback(::GetProcessId(info->process_handle), true, 0, exit_code); - ::CloseHandle(info->process_handle); - delete (info); - } - return 0; -} - -void HostProcessWindows::Close() { - if (m_owns_handle && m_process != LLDB_INVALID_PROCESS) - ::CloseHandle(m_process); - m_process = nullptr; -} diff --git a/source/Host/windows/HostThreadWindows.cpp b/source/Host/windows/HostThreadWindows.cpp deleted file mode 100644 index b516230e7fa4..000000000000 --- a/source/Host/windows/HostThreadWindows.cpp +++ /dev/null @@ -1,75 +0,0 @@ -//===-- HostThreadWindows.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/Utility/Status.h" - -#include "lldb/Host/windows/HostThreadWindows.h" -#include "lldb/Host/windows/windows.h" - -#include "llvm/ADT/STLExtras.h" - -using namespace lldb; -using namespace lldb_private; - -namespace { -void __stdcall ExitThreadProxy(ULONG_PTR dwExitCode) { - ::ExitThread(dwExitCode); -} -} - -HostThreadWindows::HostThreadWindows() - : HostNativeThreadBase(), m_owns_handle(true) {} - -HostThreadWindows::HostThreadWindows(lldb::thread_t thread) - : HostNativeThreadBase(thread), m_owns_handle(true) {} - -HostThreadWindows::~HostThreadWindows() { Reset(); } - -void HostThreadWindows::SetOwnsHandle(bool owns) { m_owns_handle = owns; } - -Status HostThreadWindows::Join(lldb::thread_result_t *result) { - Status error; - if (IsJoinable()) { - DWORD wait_result = ::WaitForSingleObject(m_thread, INFINITE); - if (WAIT_OBJECT_0 == wait_result && result) { - DWORD exit_code = 0; - if (!::GetExitCodeThread(m_thread, &exit_code)) - *result = 0; - *result = exit_code; - } else if (WAIT_OBJECT_0 != wait_result) - error.SetError(::GetLastError(), eErrorTypeWin32); - } else - error.SetError(ERROR_INVALID_HANDLE, eErrorTypeWin32); - - Reset(); - return error; -} - -Status HostThreadWindows::Cancel() { - Status error; - - DWORD result = ::QueueUserAPC(::ExitThreadProxy, m_thread, 0); - error.SetError(result, eErrorTypeWin32); - return error; -} - -lldb::tid_t HostThreadWindows::GetThreadId() const { - return ::GetThreadId(m_thread); -} - -void HostThreadWindows::Reset() { - if (m_owns_handle && m_thread != LLDB_INVALID_HOST_THREAD) - ::CloseHandle(m_thread); - - HostNativeThreadBase::Reset(); -} - -bool HostThreadWindows::EqualsThread(lldb::thread_t thread) const { - return GetThreadId() == ::GetThreadId(thread); -} diff --git a/source/Host/windows/LockFileWindows.cpp b/source/Host/windows/LockFileWindows.cpp deleted file mode 100644 index 2178fd1f5f6c..000000000000 --- a/source/Host/windows/LockFileWindows.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===-- LockFileWindows.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/windows/LockFileWindows.h" - -#include <io.h> - -using namespace lldb; -using namespace lldb_private; - -namespace { - -Status fileLock(HANDLE file_handle, DWORD flags, const uint64_t start, - const uint64_t len) { - if (start != 0) - return Status("Non-zero start lock regions are not supported"); - - OVERLAPPED overlapped = {}; - - if (!::LockFileEx(file_handle, flags, 0, len, 0, &overlapped) && - ::GetLastError() != ERROR_IO_PENDING) - return Status(::GetLastError(), eErrorTypeWin32); - - DWORD bytes; - if (!::GetOverlappedResult(file_handle, &overlapped, &bytes, TRUE)) - return Status(::GetLastError(), eErrorTypeWin32); - - return Status(); -} - -} // namespace - -LockFileWindows::LockFileWindows(int fd) - : LockFileBase(fd), m_file(reinterpret_cast<HANDLE>(_get_osfhandle(fd))) {} - -LockFileWindows::~LockFileWindows() { Unlock(); } - -bool LockFileWindows::IsValidFile() const { - return LockFileBase::IsValidFile() && m_file != INVALID_HANDLE_VALUE; -} - -Status LockFileWindows::DoWriteLock(const uint64_t start, const uint64_t len) { - return fileLock(m_file, LOCKFILE_EXCLUSIVE_LOCK, start, len); -} - -Status LockFileWindows::DoTryWriteLock(const uint64_t start, - const uint64_t len) { - return fileLock(m_file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, - start, len); -} - -Status LockFileWindows::DoReadLock(const uint64_t start, const uint64_t len) { - return fileLock(m_file, 0, start, len); -} - -Status LockFileWindows::DoTryReadLock(const uint64_t start, - const uint64_t len) { - return fileLock(m_file, LOCKFILE_FAIL_IMMEDIATELY, start, len); -} - -Status LockFileWindows::DoUnlock() { - OVERLAPPED overlapped = {}; - - if (!::UnlockFileEx(m_file, 0, m_len, 0, &overlapped) && - ::GetLastError() != ERROR_IO_PENDING) - return Status(::GetLastError(), eErrorTypeWin32); - - DWORD bytes; - if (!::GetOverlappedResult(m_file, &overlapped, &bytes, TRUE)) - return Status(::GetLastError(), eErrorTypeWin32); - - return Status(); -} diff --git a/source/Host/windows/PipeWindows.cpp b/source/Host/windows/PipeWindows.cpp deleted file mode 100644 index 57221a72899c..000000000000 --- a/source/Host/windows/PipeWindows.cpp +++ /dev/null @@ -1,339 +0,0 @@ -//===-- PipeWindows.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/windows/PipeWindows.h" - -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" - -#include <fcntl.h> -#include <io.h> -#include <rpc.h> - -#include <atomic> -#include <string> - -using namespace lldb; -using namespace lldb_private; - -namespace { -std::atomic<uint32_t> g_pipe_serial(0); -constexpr llvm::StringLiteral g_pipe_name_prefix = "\\\\.\\Pipe\\"; -} // namespace - -PipeWindows::PipeWindows() - : m_read(INVALID_HANDLE_VALUE), m_write(INVALID_HANDLE_VALUE), - m_read_fd(PipeWindows::kInvalidDescriptor), - m_write_fd(PipeWindows::kInvalidDescriptor) { - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); -} - -PipeWindows::PipeWindows(pipe_t read, pipe_t write) - : m_read((HANDLE)read), m_write((HANDLE)write), - m_read_fd(PipeWindows::kInvalidDescriptor), - m_write_fd(PipeWindows::kInvalidDescriptor) { - assert(read != LLDB_INVALID_PIPE || write != LLDB_INVALID_PIPE); - - // Don't risk in passing file descriptors and getting handles from them by - // _get_osfhandle since the retrieved handles are highly likely unrecognized - // in the current process and usually crashes the program. Pass handles - // instead since the handle can be inherited. - - if (read != LLDB_INVALID_PIPE) { - m_read_fd = _open_osfhandle((intptr_t)read, _O_RDONLY); - // Make sure the fd and native handle are consistent. - if (m_read_fd < 0) - m_read = INVALID_HANDLE_VALUE; - } - - if (write != LLDB_INVALID_PIPE) { - m_write_fd = _open_osfhandle((intptr_t)write, _O_WRONLY); - if (m_write_fd < 0) - m_write = INVALID_HANDLE_VALUE; - } - - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); -} - -PipeWindows::~PipeWindows() { Close(); } - -Status PipeWindows::CreateNew(bool child_process_inherit) { - // Create an anonymous pipe with the specified inheritance. - SECURITY_ATTRIBUTES sa{sizeof(SECURITY_ATTRIBUTES), 0, - child_process_inherit ? TRUE : FALSE}; - BOOL result = ::CreatePipe(&m_read, &m_write, &sa, 1024); - if (result == FALSE) - return Status(::GetLastError(), eErrorTypeWin32); - - m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY); - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - m_read_overlapped.hEvent = ::CreateEventA(nullptr, TRUE, FALSE, nullptr); - - m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY); - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); - - return Status(); -} - -Status PipeWindows::CreateNewNamed(bool child_process_inherit) { - // Even for anonymous pipes, we open a named pipe. This is because you - // cannot get overlapped i/o on Windows without using a named pipe. So we - // synthesize a unique name. - uint32_t serial = g_pipe_serial.fetch_add(1); - std::string pipe_name; - llvm::raw_string_ostream pipe_name_stream(pipe_name); - pipe_name_stream << "lldb.pipe." << ::GetCurrentProcessId() << "." << serial; - pipe_name_stream.flush(); - - return CreateNew(pipe_name.c_str(), child_process_inherit); -} - -Status PipeWindows::CreateNew(llvm::StringRef name, - bool child_process_inherit) { - if (name.empty()) - return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32); - - if (CanRead() || CanWrite()) - return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32); - - std::string pipe_path = g_pipe_name_prefix; - pipe_path.append(name); - - // Always open for overlapped i/o. We implement blocking manually in Read - // and Write. - DWORD read_mode = FILE_FLAG_OVERLAPPED; - m_read = ::CreateNamedPipeA( - pipe_path.c_str(), PIPE_ACCESS_INBOUND | read_mode, - PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL); - if (INVALID_HANDLE_VALUE == m_read) - return Status(::GetLastError(), eErrorTypeWin32); - m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY); - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - - // Open the write end of the pipe. Note that closing either the read or - // write end of the pipe could directly close the pipe itself. - Status result = OpenNamedPipe(name, child_process_inherit, false); - if (!result.Success()) { - CloseReadFileDescriptor(); - return result; - } - - return result; -} - -Status PipeWindows::CreateWithUniqueName(llvm::StringRef prefix, - bool child_process_inherit, - llvm::SmallVectorImpl<char> &name) { - llvm::SmallString<128> pipe_name; - Status error; - ::UUID unique_id; - RPC_CSTR unique_string; - RPC_STATUS status = ::UuidCreate(&unique_id); - if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) - status = ::UuidToStringA(&unique_id, &unique_string); - if (status == RPC_S_OK) { - pipe_name = prefix; - pipe_name += "-"; - pipe_name += reinterpret_cast<char *>(unique_string); - ::RpcStringFreeA(&unique_string); - error = CreateNew(pipe_name, child_process_inherit); - } else { - error.SetError(status, eErrorTypeWin32); - } - if (error.Success()) - name = pipe_name; - return error; -} - -Status PipeWindows::OpenAsReader(llvm::StringRef name, - bool child_process_inherit) { - if (CanRead()) - return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32); - - return OpenNamedPipe(name, child_process_inherit, true); -} - -Status -PipeWindows::OpenAsWriterWithTimeout(llvm::StringRef name, - bool child_process_inherit, - const std::chrono::microseconds &timeout) { - if (CanWrite()) - return Status(ERROR_ALREADY_EXISTS, eErrorTypeWin32); - - return OpenNamedPipe(name, child_process_inherit, false); -} - -Status PipeWindows::OpenNamedPipe(llvm::StringRef name, - bool child_process_inherit, bool is_read) { - if (name.empty()) - return Status(ERROR_INVALID_PARAMETER, eErrorTypeWin32); - - assert(is_read ? !CanRead() : !CanWrite()); - - SECURITY_ATTRIBUTES attributes = {}; - attributes.bInheritHandle = child_process_inherit; - - std::string pipe_path = g_pipe_name_prefix; - pipe_path.append(name); - - if (is_read) { - m_read = ::CreateFileA(pipe_path.c_str(), GENERIC_READ, 0, &attributes, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (INVALID_HANDLE_VALUE == m_read) - return Status(::GetLastError(), eErrorTypeWin32); - - m_read_fd = _open_osfhandle((intptr_t)m_read, _O_RDONLY); - - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - m_read_overlapped.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - } else { - m_write = ::CreateFileA(pipe_path.c_str(), GENERIC_WRITE, 0, &attributes, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (INVALID_HANDLE_VALUE == m_write) - return Status(::GetLastError(), eErrorTypeWin32); - - m_write_fd = _open_osfhandle((intptr_t)m_write, _O_WRONLY); - - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); - } - - return Status(); -} - -int PipeWindows::GetReadFileDescriptor() const { return m_read_fd; } - -int PipeWindows::GetWriteFileDescriptor() const { return m_write_fd; } - -int PipeWindows::ReleaseReadFileDescriptor() { - if (!CanRead()) - return PipeWindows::kInvalidDescriptor; - int result = m_read_fd; - m_read_fd = PipeWindows::kInvalidDescriptor; - if (m_read_overlapped.hEvent) - ::CloseHandle(m_read_overlapped.hEvent); - m_read = INVALID_HANDLE_VALUE; - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); - return result; -} - -int PipeWindows::ReleaseWriteFileDescriptor() { - if (!CanWrite()) - return PipeWindows::kInvalidDescriptor; - int result = m_write_fd; - m_write_fd = PipeWindows::kInvalidDescriptor; - m_write = INVALID_HANDLE_VALUE; - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); - return result; -} - -void PipeWindows::CloseReadFileDescriptor() { - if (!CanRead()) - return; - - if (m_read_overlapped.hEvent) - ::CloseHandle(m_read_overlapped.hEvent); - - _close(m_read_fd); - m_read = INVALID_HANDLE_VALUE; - m_read_fd = PipeWindows::kInvalidDescriptor; - ZeroMemory(&m_read_overlapped, sizeof(m_read_overlapped)); -} - -void PipeWindows::CloseWriteFileDescriptor() { - if (!CanWrite()) - return; - - _close(m_write_fd); - m_write = INVALID_HANDLE_VALUE; - m_write_fd = PipeWindows::kInvalidDescriptor; - ZeroMemory(&m_write_overlapped, sizeof(m_write_overlapped)); -} - -void PipeWindows::Close() { - CloseReadFileDescriptor(); - CloseWriteFileDescriptor(); -} - -Status PipeWindows::Delete(llvm::StringRef name) { return Status(); } - -bool PipeWindows::CanRead() const { return (m_read != INVALID_HANDLE_VALUE); } - -bool PipeWindows::CanWrite() const { return (m_write != INVALID_HANDLE_VALUE); } - -HANDLE -PipeWindows::GetReadNativeHandle() { return m_read; } - -HANDLE -PipeWindows::GetWriteNativeHandle() { return m_write; } - -Status PipeWindows::ReadWithTimeout(void *buf, size_t size, - const std::chrono::microseconds &duration, - size_t &bytes_read) { - if (!CanRead()) - return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32); - - bytes_read = 0; - DWORD sys_bytes_read = size; - BOOL result = ::ReadFile(m_read, buf, sys_bytes_read, &sys_bytes_read, - &m_read_overlapped); - if (!result && GetLastError() != ERROR_IO_PENDING) - return Status(::GetLastError(), eErrorTypeWin32); - - DWORD timeout = (duration == std::chrono::microseconds::zero()) - ? INFINITE - : duration.count() * 1000; - DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout); - if (wait_result != WAIT_OBJECT_0) { - // The operation probably failed. However, if it timed out, we need to - // cancel the I/O. Between the time we returned from WaitForSingleObject - // and the time we call CancelIoEx, the operation may complete. If that - // hapens, CancelIoEx will fail and return ERROR_NOT_FOUND. If that - // happens, the original operation should be considered to have been - // successful. - bool failed = true; - DWORD failure_error = ::GetLastError(); - if (wait_result == WAIT_TIMEOUT) { - BOOL cancel_result = CancelIoEx(m_read, &m_read_overlapped); - if (!cancel_result && GetLastError() == ERROR_NOT_FOUND) - failed = false; - } - if (failed) - return Status(failure_error, eErrorTypeWin32); - } - - // Now we call GetOverlappedResult setting bWait to false, since we've - // already waited as long as we're willing to. - if (!GetOverlappedResult(m_read, &m_read_overlapped, &sys_bytes_read, FALSE)) - return Status(::GetLastError(), eErrorTypeWin32); - - bytes_read = sys_bytes_read; - return Status(); -} - -Status PipeWindows::Write(const void *buf, size_t num_bytes, - size_t &bytes_written) { - if (!CanWrite()) - return Status(ERROR_INVALID_HANDLE, eErrorTypeWin32); - - DWORD sys_bytes_written = 0; - BOOL write_result = ::WriteFile(m_write, buf, num_bytes, &sys_bytes_written, - &m_write_overlapped); - if (!write_result && GetLastError() != ERROR_IO_PENDING) - return Status(::GetLastError(), eErrorTypeWin32); - - BOOL result = GetOverlappedResult(m_write, &m_write_overlapped, - &sys_bytes_written, TRUE); - if (!result) - return Status(::GetLastError(), eErrorTypeWin32); - return Status(); -} diff --git a/source/Host/windows/ProcessLauncherWindows.cpp b/source/Host/windows/ProcessLauncherWindows.cpp deleted file mode 100644 index a186c7177fdf..000000000000 --- a/source/Host/windows/ProcessLauncherWindows.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//===-- ProcessLauncherWindows.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/windows/ProcessLauncherWindows.h" -#include "lldb/Host/HostProcess.h" -#include "lldb/Target/ProcessLaunchInfo.h" - -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/ConvertUTF.h" - -#include <string> -#include <vector> - -using namespace lldb; -using namespace lldb_private; - -namespace { -void CreateEnvironmentBuffer(const Environment &env, - std::vector<char> &buffer) { - if (env.size() == 0) - return; - - // Environment buffer is a null terminated list of null terminated strings - for (const auto &KV : env) { - std::wstring warg; - if (llvm::ConvertUTF8toWide(Environment::compose(KV), warg)) { - buffer.insert(buffer.end(), (char *)warg.c_str(), - (char *)(warg.c_str() + warg.size() + 1)); - } - } - // One null wchar_t (to end the block) is two null bytes - buffer.push_back(0); - buffer.push_back(0); -} -} - -HostProcess -ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, - Status &error) { - error.Clear(); - - std::string executable; - std::string commandLine; - std::vector<char> environment; - STARTUPINFO startupinfo = {}; - PROCESS_INFORMATION pi = {}; - - HANDLE stdin_handle = GetStdioHandle(launch_info, STDIN_FILENO); - HANDLE stdout_handle = GetStdioHandle(launch_info, STDOUT_FILENO); - HANDLE stderr_handle = GetStdioHandle(launch_info, STDERR_FILENO); - - startupinfo.cb = sizeof(startupinfo); - startupinfo.dwFlags |= STARTF_USESTDHANDLES; - startupinfo.hStdError = - stderr_handle ? stderr_handle : ::GetStdHandle(STD_ERROR_HANDLE); - startupinfo.hStdInput = - stdin_handle ? stdin_handle : ::GetStdHandle(STD_INPUT_HANDLE); - startupinfo.hStdOutput = - stdout_handle ? stdout_handle : ::GetStdHandle(STD_OUTPUT_HANDLE); - - const char *hide_console_var = - getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); - if (hide_console_var && - llvm::StringRef(hide_console_var).equals_lower("true")) { - startupinfo.dwFlags |= STARTF_USESHOWWINDOW; - startupinfo.wShowWindow = SW_HIDE; - } - - DWORD flags = CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; - if (launch_info.GetFlags().Test(eLaunchFlagDebug)) - flags |= DEBUG_ONLY_THIS_PROCESS; - - if (launch_info.GetFlags().Test(eLaunchFlagDisableSTDIO)) - flags &= ~CREATE_NEW_CONSOLE; - - LPVOID env_block = nullptr; - ::CreateEnvironmentBuffer(launch_info.GetEnvironment(), environment); - if (!environment.empty()) - env_block = environment.data(); - - executable = launch_info.GetExecutableFile().GetPath(); - launch_info.GetArguments().GetQuotedCommandString(commandLine); - - std::wstring wexecutable, wcommandLine, wworkingDirectory; - llvm::ConvertUTF8toWide(executable, wexecutable); - llvm::ConvertUTF8toWide(commandLine, wcommandLine); - llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), - wworkingDirectory); - - wcommandLine.resize(PATH_MAX); // Needs to be over-allocated because - // CreateProcessW can modify it - BOOL result = ::CreateProcessW( - wexecutable.c_str(), &wcommandLine[0], NULL, NULL, TRUE, flags, env_block, - wworkingDirectory.size() == 0 ? NULL : wworkingDirectory.c_str(), - &startupinfo, &pi); - - if (!result) { - // Call GetLastError before we make any other system calls. - error.SetError(::GetLastError(), eErrorTypeWin32); - } - - if (result) { - // Do not call CloseHandle on pi.hProcess, since we want to pass that back - // through the HostProcess. - ::CloseHandle(pi.hThread); - } - - if (stdin_handle) - ::CloseHandle(stdin_handle); - if (stdout_handle) - ::CloseHandle(stdout_handle); - if (stderr_handle) - ::CloseHandle(stderr_handle); - - if (!result) - return HostProcess(); - - return HostProcess(pi.hProcess); -} - -HANDLE -ProcessLauncherWindows::GetStdioHandle(const ProcessLaunchInfo &launch_info, - int fd) { - const FileAction *action = launch_info.GetFileActionForFD(fd); - if (action == nullptr) - return NULL; - SECURITY_ATTRIBUTES secattr = {}; - secattr.nLength = sizeof(SECURITY_ATTRIBUTES); - secattr.bInheritHandle = TRUE; - - llvm::StringRef path = action->GetPath(); - DWORD access = 0; - DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - DWORD create = 0; - DWORD flags = 0; - if (fd == STDIN_FILENO) { - access = GENERIC_READ; - create = OPEN_EXISTING; - flags = FILE_ATTRIBUTE_READONLY; - } - if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { - access = GENERIC_WRITE; - create = CREATE_ALWAYS; - if (fd == STDERR_FILENO) - flags = FILE_FLAG_WRITE_THROUGH; - } - - std::wstring wpath; - llvm::ConvertUTF8toWide(path, wpath); - HANDLE result = ::CreateFileW(wpath.c_str(), access, share, &secattr, create, - flags, NULL); - return (result == INVALID_HANDLE_VALUE) ? NULL : result; -} diff --git a/source/Host/windows/ProcessRunLock.cpp b/source/Host/windows/ProcessRunLock.cpp deleted file mode 100644 index 64276917fc81..000000000000 --- a/source/Host/windows/ProcessRunLock.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- ProcessRunLock.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/ProcessRunLock.h" -#include "lldb/Host/windows/windows.h" - -static PSRWLOCK GetLock(lldb::rwlock_t lock) { - return static_cast<PSRWLOCK>(lock); -} - -static bool ReadLock(lldb::rwlock_t rwlock) { - ::AcquireSRWLockShared(GetLock(rwlock)); - return true; -} - -static bool ReadUnlock(lldb::rwlock_t rwlock) { - ::ReleaseSRWLockShared(GetLock(rwlock)); - return true; -} - -static bool WriteLock(lldb::rwlock_t rwlock) { - ::AcquireSRWLockExclusive(GetLock(rwlock)); - return true; -} - -static bool WriteTryLock(lldb::rwlock_t rwlock) { - return !!::TryAcquireSRWLockExclusive(GetLock(rwlock)); -} - -static bool WriteUnlock(lldb::rwlock_t rwlock) { - ::ReleaseSRWLockExclusive(GetLock(rwlock)); - return true; -} - -using namespace lldb_private; - -ProcessRunLock::ProcessRunLock() : m_running(false) { - m_rwlock = new SRWLOCK; - InitializeSRWLock(GetLock(m_rwlock)); -} - -ProcessRunLock::~ProcessRunLock() { delete static_cast<SRWLOCK *>(m_rwlock); } - -bool ProcessRunLock::ReadTryLock() { - ::ReadLock(m_rwlock); - if (m_running == false) - return true; - ::ReadUnlock(m_rwlock); - return false; -} - -bool ProcessRunLock::ReadUnlock() { return ::ReadUnlock(m_rwlock); } - -bool ProcessRunLock::SetRunning() { - WriteLock(m_rwlock); - m_running = true; - WriteUnlock(m_rwlock); - return true; -} - -bool ProcessRunLock::TrySetRunning() { - if (WriteTryLock(m_rwlock)) { - bool was_running = m_running; - m_running = true; - WriteUnlock(m_rwlock); - return !was_running; - } - return false; -} - -bool ProcessRunLock::SetStopped() { - WriteLock(m_rwlock); - m_running = false; - WriteUnlock(m_rwlock); - return true; -} diff --git a/source/Host/windows/Windows.cpp b/source/Host/windows/Windows.cpp deleted file mode 100644 index 9d0e70e6d126..000000000000 --- a/source/Host/windows/Windows.cpp +++ /dev/null @@ -1,231 +0,0 @@ -//===-- Windows.cpp ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// This file provides Windows support functions - -#include "lldb/Host/PosixApi.h" -#include "lldb/Host/windows/windows.h" - -#include "llvm/Support/ConvertUTF.h" - -#include <assert.h> -#include <cerrno> -#include <ctype.h> -#include <io.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -namespace { -bool utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize) { - const llvm::UTF8 *sourceStart = reinterpret_cast<const llvm::UTF8 *>(utf8); - size_t sourceLen = strlen(utf8) + 1 /* convert null too */; - llvm::UTF16 *target = reinterpret_cast<llvm::UTF16 *>(buf); - llvm::ConversionFlags flags = llvm::strictConversion; - return llvm::ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, - target + bufSize, flags) == llvm::conversionOK; -} - -bool wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize) { - const llvm::UTF16 *sourceStart = reinterpret_cast<const llvm::UTF16 *>(wide); - size_t sourceLen = wcslen(wide) + 1 /* convert null too */; - llvm::UTF8 *target = reinterpret_cast<llvm::UTF8 *>(buf); - llvm::ConversionFlags flags = llvm::strictConversion; - return llvm::ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, - target + bufSize, flags) == llvm::conversionOK; -} -} - -int vasprintf(char **ret, const char *fmt, va_list ap) { - char *buf; - int len; - size_t buflen; - va_list ap2; - -#if defined(_MSC_VER) || defined(__MINGW64) - ap2 = ap; - len = _vscprintf(fmt, ap2); -#else - va_copy(ap2, ap); - len = vsnprintf(NULL, 0, fmt, ap2); -#endif - - if (len >= 0 && - (buf = (char *)malloc((buflen = (size_t)(len + 1)))) != NULL) { - len = vsnprintf(buf, buflen, fmt, ap); - *ret = buf; - } else { - *ret = NULL; - len = -1; - } - - va_end(ap2); - return len; -} - -char *strcasestr(const char *s, const char *find) { - char c, sc; - size_t len; - - if ((c = *find++) != 0) { - c = tolower((unsigned char)c); - len = strlen(find); - do { - do { - if ((sc = *s++) == 0) - return 0; - } while ((char)tolower((unsigned char)sc) != c); - } while (strncasecmp(s, find, len) != 0); - s--; - } - return ((char *)s); -} - -char *realpath(const char *name, char *resolved) { - char *retname = NULL; - - /* SUSv3 says we must set `errno = EINVAL', and return NULL, - * if `name' is passed as a NULL pointer. - */ - if (name == NULL) { - errno = EINVAL; - return NULL; - } - - /* Otherwise, `name' must refer to a readable filesystem object, - * if we are going to resolve its absolute path name. - */ - wchar_t wideNameBuffer[PATH_MAX]; - wchar_t *wideName = wideNameBuffer; - if (!utf8ToWide(name, wideName, PATH_MAX)) { - errno = EINVAL; - return NULL; - } - - if (_waccess(wideName, 4) != 0) - return NULL; - - /* If `name' didn't point to an existing entity, - * then we don't get to here; we simply fall past this block, - * returning NULL, with `errno' appropriately set by `access'. - * - * When we _do_ get to here, then we can use `_fullpath' to - * resolve the full path for `name' into `resolved', but first, - * check that we have a suitable buffer, in which to return it. - */ - - if ((retname = resolved) == NULL) { - /* Caller didn't give us a buffer, so we'll exercise the - * option granted by SUSv3, and allocate one. - * - * `_fullpath' would do this for us, but it uses `malloc', and - * Microsoft's implementation doesn't set `errno' on failure. - * If we don't do this explicitly ourselves, then we will not - * know if `_fullpath' fails on `malloc' failure, or for some - * other reason, and we want to set `errno = ENOMEM' for the - * `malloc' failure case. - */ - - retname = (char *)malloc(PATH_MAX); - if (retname == NULL) { - errno = ENOMEM; - return NULL; - } - } - - /* Otherwise, when we do have a valid buffer, - * `_fullpath' should only fail if the path name is too long. - */ - - wchar_t wideFullPathBuffer[PATH_MAX]; - wchar_t *wideFullPath; - if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == - NULL) { - errno = ENAMETOOLONG; - return NULL; - } - - // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS - // FIXME: Check for failure - size_t initialLength = wcslen(wideFullPath); - GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX); - GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1); - - // Convert back to UTF-8 - if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX)) { - errno = EINVAL; - return NULL; - } - - // Force drive to be upper case - if (retname[1] == ':') - retname[0] = toupper(retname[0]); - - return retname; -} - -#ifdef _MSC_VER - -char *basename(char *path) { - char *l1 = strrchr(path, '\\'); - char *l2 = strrchr(path, '/'); - if (l2 > l1) - l1 = l2; - if (!l1) - return path; // no base name - return &l1[1]; -} - -char *dirname(char *path) { - char *l1 = strrchr(path, '\\'); - char *l2 = strrchr(path, '/'); - if (l2 > l1) - l1 = l2; - if (!l1) - return NULL; // no dir name - *l1 = 0; - return path; -} - -int strcasecmp(const char *s1, const char *s2) { return stricmp(s1, s2); } - -int strncasecmp(const char *s1, const char *s2, size_t n) { - return strnicmp(s1, s2, n); -} - -int usleep(uint32_t useconds) { - Sleep(useconds / 1000); - return 0; -} - -#if _MSC_VER < 1900 -namespace lldb_private { -int vsnprintf(char *buffer, size_t count, const char *format, va_list argptr) { - int old_errno = errno; - int r = ::vsnprintf(buffer, count, format, argptr); - int new_errno = errno; - buffer[count - 1] = '\0'; - if (r == -1 || r == count) { - FILE *nul = fopen("nul", "w"); - int bytes_written = ::vfprintf(nul, format, argptr); - fclose(nul); - if (bytes_written < count) - errno = new_errno; - else { - errno = old_errno; - r = bytes_written; - } - } - return r; -} -} // namespace lldb_private -#endif - -#endif // _MSC_VER |