diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-01-06 20:12:03 +0000 | 
| commit | 9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch) | |
| tree | dd2a1ddf0476664c2b823409c36cbccd52662ca7 /source/Host/windows/Host.cpp | |
| parent | 3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff) | |
Notes
Diffstat (limited to 'source/Host/windows/Host.cpp')
| -rw-r--r-- | source/Host/windows/Host.cpp | 326 | 
1 files changed, 326 insertions, 0 deletions
| diff --git a/source/Host/windows/Host.cpp b/source/Host/windows/Host.cpp new file mode 100644 index 000000000000..2c9a139df256 --- /dev/null +++ b/source/Host/windows/Host.cpp @@ -0,0 +1,326 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <stdio.h> +#include "lldb/Host/windows/windows.h" +#include "lldb/Host/windows/AutoHandle.h" + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" + +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StructuredData.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( +            executable.GetPath().c_str(), +            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;       // Error: 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<char> buffer(32768); +        DWORD dwSize = buffer.size(); +        if (!::QueryFullProcessImageNameA(handle.get(), 0, &buffer[0], &dwSize)) +            return false; +        path.assign(&buffer[0]); +        return true; +    } + +    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(), false); +            process.SetExecutableFile(executableFile, true); +            GetTripleForProcess(executableFile, triple); +        } +        process.SetArchitecture(ArchSpec(triple)); + +        // TODO(zturner): Add the ability to get the process user name. +    } +} + +lldb::DataBufferSP +Host::GetAuxvData(lldb_private::Process *process) +{ +    return 0; +} + +lldb::tid_t +Host::GetCurrentThreadID() +{ +    return lldb::tid_t(::GetCurrentThreadId()); +} + +lldb::thread_t +Host::GetCurrentThread () +{ +    return lldb::thread_t(::GetCurrentThread()); +} + +lldb::thread_key_t +Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) +{ +    return TlsAlloc(); +} + +void* +Host::ThreadLocalStorageGet(lldb::thread_key_t key) +{ +    return ::TlsGetValue (key); +} + +void +Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) +{ +   ::TlsSetValue (key, value); +} + +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<char> buffer(MAX_PATH); +    DWORD chars_copied = 0; +    do { +        chars_copied = ::GetModuleFileName(hmodule, &buffer[0], buffer.size()); +        if (chars_copied == buffer.size() && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) +            buffer.resize(buffer.size() * 2); +    } while (chars_copied >= buffer.size()); + +    module_filespec.SetFile(&buffer[0], false); +    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; + +    PROCESSENTRY32 pe = {0}; +    pe.dwSize = sizeof(PROCESSENTRY32); +    if (Process32First(snapshot.get(), &pe)) +    { +        do +        { +            AutoHandle handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID), nullptr); + +            ProcessInstanceInfo process; +            process.SetExecutableFile(FileSpec(pe.szExeFile, false), 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 (Process32Next(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(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals) +{ +    return HostThread(); +} + +Error +Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) +{ +    Error error; +    if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) +    { +        FileSpec expand_tool_spec; +        if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, 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 (!expand_tool_spec.Exists()) +        { +            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; +        RunShellCommand(expand_command.GetData(), launch_info.GetWorkingDirectory(), &status, nullptr, &output, 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().c_str()); +        } +    } +     +    return error; +} + +size_t +Host::GetEnvironment(StringList &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. +    LPCH environment_block = ::GetEnvironmentStrings(); +    env.Clear(); +    while (*environment_block != '\0') +    { +        llvm::StringRef current_var(environment_block); +        if (current_var[0] != '=') +            env.AppendString(current_var); + +        environment_block += current_var.size()+1; +    } +    return env.GetSize(); +} | 
