brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.9 KiB · 79dd46b Raw
663 lines · cpp
1//===-- NativeProcessWindows.cpp ------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Host/windows/windows.h"10#include <psapi.h>11 12#include "NativeProcessWindows.h"13#include "NativeThreadWindows.h"14#include "lldb/Host/FileSystem.h"15#include "lldb/Host/HostNativeProcessBase.h"16#include "lldb/Host/HostProcess.h"17#include "lldb/Host/ProcessLaunchInfo.h"18#include "lldb/Host/windows/AutoHandle.h"19#include "lldb/Host/windows/HostThreadWindows.h"20#include "lldb/Host/windows/ProcessLauncherWindows.h"21#include "lldb/Target/MemoryRegionInfo.h"22#include "lldb/Target/Process.h"23#include "lldb/Utility/State.h"24#include "llvm/Support/ConvertUTF.h"25#include "llvm/Support/Errc.h"26#include "llvm/Support/Error.h"27#include "llvm/Support/Format.h"28#include "llvm/Support/Threading.h"29#include "llvm/Support/raw_ostream.h"30 31#include "DebuggerThread.h"32#include "ExceptionRecord.h"33#include "ProcessWindowsLog.h"34 35#include <tlhelp32.h>36 37#pragma warning(disable : 4005)38#include "winternl.h"39#include <ntstatus.h>40 41using namespace lldb;42using namespace lldb_private;43using namespace llvm;44 45namespace lldb_private {46 47NativeProcessWindows::NativeProcessWindows(ProcessLaunchInfo &launch_info,48                                           NativeDelegate &delegate,49                                           llvm::Error &E)50    : NativeProcessProtocol(LLDB_INVALID_PROCESS_ID,51                            launch_info.GetPTY().ReleasePrimaryFileDescriptor(),52                            delegate),53      ProcessDebugger(), m_arch(launch_info.GetArchitecture()) {54  ErrorAsOutParameter EOut(&E);55  DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));56  E = LaunchProcess(launch_info, delegate_sp).ToError();57  if (E)58    return;59 60  SetID(GetDebuggedProcessId());61}62 63NativeProcessWindows::NativeProcessWindows(lldb::pid_t pid, int terminal_fd,64                                           NativeDelegate &delegate,65                                           llvm::Error &E)66    : NativeProcessProtocol(pid, terminal_fd, delegate), ProcessDebugger() {67  ErrorAsOutParameter EOut(&E);68  DebugDelegateSP delegate_sp(new NativeDebugDelegate(*this));69  ProcessAttachInfo attach_info;70  attach_info.SetProcessID(pid);71  E = AttachProcess(pid, attach_info, delegate_sp).ToError();72  if (E)73    return;74 75  SetID(GetDebuggedProcessId());76 77  ProcessInstanceInfo info;78  if (!Host::GetProcessInfo(pid, info)) {79    E = createStringError(inconvertibleErrorCode(),80                          "Cannot get process information");81    return;82  }83  m_arch = info.GetArchitecture();84}85 86Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {87  Log *log = GetLog(WindowsLog::Process);88  Status error;89  llvm::sys::ScopedLock lock(m_mutex);90 91  StateType state = GetState();92  if (state == eStateStopped || state == eStateCrashed) {93    LLDB_LOG(log, "process {0} is in state {1}.  Resuming...",94             GetDebuggedProcessId(), state);95    LLDB_LOG(log, "resuming {0} threads.", m_threads.size());96 97    bool failed = false;98    for (uint32_t i = 0; i < m_threads.size(); ++i) {99      auto thread = static_cast<NativeThreadWindows *>(m_threads[i].get());100      const ResumeAction *const action =101          resume_actions.GetActionForThread(thread->GetID(), true);102      if (action == nullptr)103        continue;104 105      switch (action->state) {106      case eStateRunning:107      case eStateStepping: {108        Status result = thread->DoResume(action->state);109        if (result.Fail()) {110          failed = true;111          LLDB_LOG(log,112                   "Trying to resume thread at index {0}, but failed with "113                   "error {1}.",114                   i, result);115        }116        break;117      }118      case eStateSuspended:119      case eStateStopped:120        break;121 122      default:123        return Status::FromErrorStringWithFormat(124            "NativeProcessWindows::%s (): unexpected state %s specified "125            "for pid %" PRIu64 ", tid %" PRIu64,126            __FUNCTION__, StateAsCString(action->state), GetID(),127            thread->GetID());128      }129    }130 131    if (failed) {132      error = Status::FromErrorString("NativeProcessWindows::DoResume failed");133    } else {134      SetState(eStateRunning);135    }136 137    // Resume the debug loop.138    ExceptionRecordSP active_exception =139        m_session_data->m_debugger->GetActiveException().lock();140    if (active_exception) {141      // Resume the process and continue processing debug events.  Mask the142      // exception so that from the process's view, there is no indication that143      // anything happened.144      m_session_data->m_debugger->ContinueAsyncException(145          ExceptionResult::MaskException);146    }147  } else {148    LLDB_LOG(log, "error: process {0} is in state {1}.  Returning...",149             GetDebuggedProcessId(), GetState());150  }151 152  return error;153}154 155NativeThreadWindows *156NativeProcessWindows::GetThreadByID(lldb::tid_t thread_id) {157  return static_cast<NativeThreadWindows *>(158      NativeProcessProtocol::GetThreadByID(thread_id));159}160 161Status NativeProcessWindows::Halt() {162  bool caused_stop = false;163  StateType state = GetState();164  if (state != eStateStopped)165    return HaltProcess(caused_stop);166  return Status();167}168 169Status NativeProcessWindows::Detach() {170  Status error;171  Log *log = GetLog(WindowsLog::Process);172  StateType state = GetState();173  if (state != eStateExited && state != eStateDetached) {174    error = DetachProcess();175    if (error.Success())176      SetState(eStateDetached);177    else178      LLDB_LOG(log, "Detaching process error: {0}", error);179  } else {180    error = Status::FromErrorStringWithFormatv(181        "error: process {0} in state = {1}, but "182        "cannot detach it in this state.",183        GetID(), state);184    LLDB_LOG(log, "error: {0}", error);185  }186  return error;187}188 189Status NativeProcessWindows::Signal(int signo) {190  Status error;191  error = Status::FromErrorString(192      "Windows does not support sending signals to processes");193  return error;194}195 196Status NativeProcessWindows::Interrupt() { return Halt(); }197 198Status NativeProcessWindows::Kill() {199  StateType state = GetState();200  return DestroyProcess(state);201}202 203Status NativeProcessWindows::IgnoreSignals(llvm::ArrayRef<int> signals) {204  return Status();205}206 207Status NativeProcessWindows::GetMemoryRegionInfo(lldb::addr_t load_addr,208                                                 MemoryRegionInfo &range_info) {209  return ProcessDebugger::GetMemoryRegionInfo(load_addr, range_info);210}211 212Status NativeProcessWindows::ReadMemory(lldb::addr_t addr, void *buf,213                                        size_t size, size_t &bytes_read) {214  return ProcessDebugger::ReadMemory(addr, buf, size, bytes_read);215}216 217Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf,218                                         size_t size, size_t &bytes_written) {219  return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written);220}221 222llvm::Expected<lldb::addr_t>223NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) {224  lldb::addr_t addr;225  Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr);226  if (ST.Success())227    return addr;228  return ST.ToError();229}230 231llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) {232  return ProcessDebugger::DeallocateMemory(addr).ToError();233}234 235lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; }236 237bool NativeProcessWindows::IsAlive() const {238  StateType state = GetState();239  switch (state) {240  case eStateCrashed:241  case eStateDetached:242  case eStateExited:243  case eStateInvalid:244  case eStateUnloaded:245    return false;246  default:247    return true;248  }249}250 251void NativeProcessWindows::SetStopReasonForThread(NativeThreadWindows &thread,252                                                  lldb::StopReason reason,253                                                  std::string description) {254  SetCurrentThreadID(thread.GetID());255 256  ThreadStopInfo stop_info;257  stop_info.reason = reason;258  // No signal support on Windows but required to provide a 'valid' signum.259  stop_info.signo = SIGTRAP;260 261  if (reason == StopReason::eStopReasonException) {262    stop_info.details.exception.type = 0;263    stop_info.details.exception.data_count = 0;264  }265 266  thread.SetStopReason(stop_info, description);267}268 269void NativeProcessWindows::StopThread(lldb::tid_t thread_id,270                                      lldb::StopReason reason,271                                      std::string description) {272  NativeThreadWindows *thread = GetThreadByID(thread_id);273  if (!thread)274    return;275 276  for (uint32_t i = 0; i < m_threads.size(); ++i) {277    auto t = static_cast<NativeThreadWindows *>(m_threads[i].get());278    Status error = t->DoStop();279    if (error.Fail())280      exit(1);281  }282  SetStopReasonForThread(*thread, reason, description);283}284 285size_t NativeProcessWindows::UpdateThreads() { return m_threads.size(); }286 287llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>288NativeProcessWindows::GetAuxvData() const {289  // Not available on this target.290  return llvm::errc::not_supported;291}292 293llvm::Expected<llvm::ArrayRef<uint8_t>>294NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {295  static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e,296                                             0xd4};     // brk #0xf000297  static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe298 299  switch (GetArchitecture().GetMachine()) {300  case llvm::Triple::aarch64:301    return llvm::ArrayRef(g_aarch64_opcode);302 303  case llvm::Triple::arm:304  case llvm::Triple::thumb:305    return llvm::ArrayRef(g_thumb_opcode);306 307  default:308    return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);309  }310}311 312size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {313  // Windows always reports an incremented PC after a breakpoint is hit,314  // even on ARM.315  return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size();316}317 318bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {319  auto it = m_software_breakpoints.find(addr);320  if (it == m_software_breakpoints.end())321    return false;322  return true;323}324 325Status NativeProcessWindows::SetBreakpoint(lldb::addr_t addr, uint32_t size,326                                           bool hardware) {327  if (hardware)328    return SetHardwareBreakpoint(addr, size);329  return SetSoftwareBreakpoint(addr, size);330}331 332Status NativeProcessWindows::RemoveBreakpoint(lldb::addr_t addr,333                                              bool hardware) {334  if (hardware)335    return RemoveHardwareBreakpoint(addr);336  return RemoveSoftwareBreakpoint(addr);337}338 339Status NativeProcessWindows::CacheLoadedModules() {340  Status error;341  if (!m_loaded_modules.empty())342    return Status();343 344  // Retrieve loaded modules by a Target/Module free implemenation.345  AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetID()));346  if (snapshot.IsValid()) {347    MODULEENTRY32W me;348    me.dwSize = sizeof(MODULEENTRY32W);349    if (Module32FirstW(snapshot.get(), &me)) {350      do {351        std::string path;352        if (!llvm::convertWideToUTF8(me.szExePath, path))353          continue;354 355        FileSpec file_spec(path);356        FileSystem::Instance().Resolve(file_spec);357        m_loaded_modules[file_spec] = (addr_t)me.modBaseAddr;358      } while (Module32Next(snapshot.get(), &me));359    }360 361    if (!m_loaded_modules.empty())362      return Status();363  }364 365  error = Status(::GetLastError(), lldb::ErrorType::eErrorTypeWin32);366  return error;367}368 369Status NativeProcessWindows::GetLoadedModuleFileSpec(const char *module_path,370                                                     FileSpec &file_spec) {371  Status error = CacheLoadedModules();372  if (error.Fail())373    return error;374 375  FileSpec module_file_spec(module_path);376  FileSystem::Instance().Resolve(module_file_spec);377  for (auto &it : m_loaded_modules) {378    if (it.first == module_file_spec) {379      file_spec = it.first;380      return Status();381    }382  }383  return Status::FromErrorStringWithFormat(384      "Module (%s) not found in process %" PRIu64 "!",385      module_file_spec.GetPath().c_str(), GetID());386}387 388Status389NativeProcessWindows::GetFileLoadAddress(const llvm::StringRef &file_name,390                                         lldb::addr_t &load_addr) {391  Status error = CacheLoadedModules();392  if (error.Fail())393    return error;394 395  load_addr = LLDB_INVALID_ADDRESS;396  FileSpec file_spec(file_name);397  FileSystem::Instance().Resolve(file_spec);398  for (auto &it : m_loaded_modules) {399    if (it.first == file_spec) {400      load_addr = it.second;401      return Status();402    }403  }404  return Status::FromErrorStringWithFormat(405      "Can't get loaded address of file (%s) in process %" PRIu64 "!",406      file_spec.GetPath().c_str(), GetID());407}408 409void NativeProcessWindows::OnExitProcess(uint32_t exit_code) {410  Log *log = GetLog(WindowsLog::Process);411  LLDB_LOG(log, "Process {0} exited with code {1}", GetID(), exit_code);412 413  ProcessDebugger::OnExitProcess(exit_code);414 415  // No signal involved.  It is just an exit event.416  WaitStatus wait_status(WaitStatus::Exit, exit_code);417  SetExitStatus(wait_status, true);418 419  // Notify the native delegate.420  SetState(eStateExited, true);421}422 423void NativeProcessWindows::OnDebuggerConnected(lldb::addr_t image_base) {424  Log *log = GetLog(WindowsLog::Process);425  LLDB_LOG(log, "Debugger connected to process {0}. Image base = {1:x}",426           GetDebuggedProcessId(), image_base);427 428  // This is the earliest chance we can resolve the process ID and429  // architecture if we don't know them yet.430  if (GetID() == LLDB_INVALID_PROCESS_ID)431    SetID(GetDebuggedProcessId());432 433  if (GetArchitecture().GetMachine() == llvm::Triple::UnknownArch) {434    ProcessInstanceInfo process_info;435    if (!Host::GetProcessInfo(GetDebuggedProcessId(), process_info)) {436      LLDB_LOG(log, "Cannot get process information during debugger connecting "437                    "to process");438      return;439    }440    SetArchitecture(process_info.GetArchitecture());441  }442 443  // The very first one shall always be the main thread.444  assert(m_threads.empty());445  m_threads.push_back(std::make_unique<NativeThreadWindows>(446      *this, m_session_data->m_debugger->GetMainThread()));447}448 449ExceptionResult450NativeProcessWindows::OnDebugException(bool first_chance,451                                       const ExceptionRecord &record) {452  Log *log = GetLog(WindowsLog::Exception);453  llvm::sys::ScopedLock lock(m_mutex);454 455  // Let the debugger establish the internal status.456  ProcessDebugger::OnDebugException(first_chance, record);457 458  static bool initial_stop = false;459  if (!first_chance) {460    SetState(eStateStopped, false);461  }462 463  ExceptionResult result = ExceptionResult::SendToApplication;464  switch (record.GetExceptionCode()) {465  case DWORD(STATUS_SINGLE_STEP):466  case STATUS_WX86_SINGLE_STEP: {467#ifndef __aarch64__468    uint32_t wp_id = LLDB_INVALID_INDEX32;469    if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID())) {470      NativeRegisterContextWindows &reg_ctx = thread->GetRegisterContext();471      Status error =472          reg_ctx.GetWatchpointHitIndex(wp_id, record.GetExceptionAddress());473      if (error.Fail())474        LLDB_LOG(log,475                 "received error while checking for watchpoint hits, pid = "476                 "{0}, error = {1}",477                 thread->GetID(), error);478      if (wp_id != LLDB_INVALID_INDEX32) {479        addr_t wp_addr = reg_ctx.GetWatchpointAddress(wp_id);480        addr_t wp_hit_addr = reg_ctx.GetWatchpointHitAddress(wp_id);481        std::string desc =482            formatv("{0} {1} {2}", wp_addr, wp_id, wp_hit_addr).str();483        StopThread(record.GetThreadID(), StopReason::eStopReasonWatchpoint,484                   desc);485      }486    }487    if (wp_id == LLDB_INVALID_INDEX32)488#endif489      StopThread(record.GetThreadID(), StopReason::eStopReasonTrace);490 491    SetState(eStateStopped, true);492 493    // Continue the debugger.494    return ExceptionResult::MaskException;495  }496  case DWORD(STATUS_BREAKPOINT):497  case STATUS_WX86_BREAKPOINT:498 499    if (NativeThreadWindows *stop_thread =500            GetThreadByID(record.GetThreadID())) {501      auto &reg_ctx = stop_thread->GetRegisterContext();502      const auto exception_addr = record.GetExceptionAddress();503      const auto thread_id = record.GetThreadID();504 505      if (FindSoftwareBreakpoint(exception_addr)) {506        LLDB_LOG(log, "Hit non-loader breakpoint at address {0:x}.",507                 exception_addr);508        // The current PC is AFTER the BP opcode, on all architectures.509        reg_ctx.SetPC(reg_ctx.GetPC() - GetSoftwareBreakpointPCOffset());510        StopThread(thread_id, StopReason::eStopReasonBreakpoint);511        SetState(eStateStopped, true);512        return ExceptionResult::MaskException;513      } else {514        // This block of code will only be entered in case of a hardware515        // watchpoint or breakpoint hit on AArch64. However, we only handle516        // hardware watchpoints below as breakpoints are not yet supported.517        const std::vector<ULONG_PTR> &args = record.GetExceptionArguments();518        // Check that the ExceptionInformation array of EXCEPTION_RECORD519        // contains at least two elements: the first is a read-write flag520        // indicating the type of data access operation (read or write) while521        // the second contains the virtual address of the accessed data.522        if (args.size() >= 2) {523          uint32_t hw_id = LLDB_INVALID_INDEX32;524          Status error = reg_ctx.GetWatchpointHitIndex(hw_id, args[1]);525          if (error.Fail())526            LLDB_LOG(log,527                     "received error while checking for watchpoint hits, pid = "528                     "{0}, error = {1}",529                     thread_id, error);530 531          if (hw_id != LLDB_INVALID_INDEX32) {532            std::string desc =533                formatv("{0} {1} {2}", reg_ctx.GetWatchpointAddress(hw_id),534                        hw_id, exception_addr)535                    .str();536            StopThread(thread_id, StopReason::eStopReasonWatchpoint, desc);537            SetState(eStateStopped, true);538            return ExceptionResult::MaskException;539          }540        }541      }542    }543 544    if (!initial_stop) {545      initial_stop = true;546      LLDB_LOG(log,547               "Hit loader breakpoint at address {0:x}, setting initial stop "548               "event.",549               record.GetExceptionAddress());550 551      // We are required to report the reason for the first stop after552      // launching or being attached.553      if (NativeThreadWindows *thread = GetThreadByID(record.GetThreadID()))554        SetStopReasonForThread(*thread, StopReason::eStopReasonBreakpoint);555 556      // Do not notify the native delegate (e.g. llgs) since at this moment557      // the program hasn't returned from Manager::Launch() and the delegate558      // might not have an valid native process to operate on.559      SetState(eStateStopped, false);560 561      // Hit the initial stop. Continue the application.562      return ExceptionResult::BreakInDebugger;563    }564 565    [[fallthrough]];566  default:567    LLDB_LOG(log,568             "Debugger thread reported exception {0:x} at address {1:x} "569             "(first_chance={2})",570             record.GetExceptionCode(), record.GetExceptionAddress(),571             first_chance);572 573    {574      std::string desc;575      llvm::raw_string_ostream desc_stream(desc);576      desc_stream << "Exception "577                  << llvm::format_hex(record.GetExceptionCode(), 8)578                  << " encountered at address "579                  << llvm::format_hex(record.GetExceptionAddress(), 8);580      StopThread(record.GetThreadID(), StopReason::eStopReasonException,581                 desc.c_str());582 583      SetState(eStateStopped, true);584    }585 586    // For non-breakpoints, give the application a chance to handle the587    // exception first.588    if (first_chance)589      result = ExceptionResult::SendToApplication;590    else591      result = ExceptionResult::BreakInDebugger;592  }593 594  return result;595}596 597void NativeProcessWindows::OnCreateThread(const HostThread &new_thread) {598  llvm::sys::ScopedLock lock(m_mutex);599 600  auto thread = std::make_unique<NativeThreadWindows>(*this, new_thread);601  thread->GetRegisterContext().ClearAllHardwareWatchpoints();602  for (const auto &pair : GetWatchpointMap()) {603    const NativeWatchpoint &wp = pair.second;604    thread->SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags,605                          wp.m_hardware);606  }607 608  m_threads.push_back(std::move(thread));609}610 611void NativeProcessWindows::OnExitThread(lldb::tid_t thread_id,612                                        uint32_t exit_code) {613  llvm::sys::ScopedLock lock(m_mutex);614  NativeThreadWindows *thread = GetThreadByID(thread_id);615  if (!thread)616    return;617 618  for (auto t = m_threads.begin(); t != m_threads.end();) {619    if ((*t)->GetID() == thread_id) {620      t = m_threads.erase(t);621    } else {622      ++t;623    }624  }625}626 627void NativeProcessWindows::OnLoadDll(const ModuleSpec &module_spec,628                                     lldb::addr_t module_addr) {629  // Simply invalidate the cached loaded modules.630  if (!m_loaded_modules.empty())631    m_loaded_modules.clear();632}633 634void NativeProcessWindows::OnUnloadDll(lldb::addr_t module_addr) {635  if (!m_loaded_modules.empty())636    m_loaded_modules.clear();637}638 639llvm::Expected<std::unique_ptr<NativeProcessProtocol>>640NativeProcessWindows::Manager::Launch(641    ProcessLaunchInfo &launch_info,642    NativeProcessProtocol::NativeDelegate &native_delegate) {643  Error E = Error::success();644  auto process_up = std::unique_ptr<NativeProcessWindows>(645      new NativeProcessWindows(launch_info, native_delegate, E));646  if (E)647    return std::move(E);648  return std::move(process_up);649}650 651llvm::Expected<std::unique_ptr<NativeProcessProtocol>>652NativeProcessWindows::Manager::Attach(653    lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {654  Error E = Error::success();655  // Set pty primary fd invalid since it is not available.656  auto process_up = std::unique_ptr<NativeProcessWindows>(657      new NativeProcessWindows(pid, -1, native_delegate, E));658  if (E)659    return std::move(E);660  return std::move(process_up);661}662} // namespace lldb_private663