Jason Molenda eaeb8ddd4a [LLDB] add arch-specific watchpoint behavior defaults to lldb
lldb was originally designed to get the watchpoint exception behavior
from the gdb remote serial protocol stub -- exceptions are either
received before the instruction executes, or after the instruction
has executed.  This behavior was reported via two lldb extensions
to gdb RSP, so generic remote stubs like gdbserver or a JTAG stub,
would not tell lldb which behavior was correct, and it would default
to "exceptions are received after the instruction has executed".
Two architectures hard coded their correct "exceptions before
instruction" behavior, to work around this issue.

Most architectures have a fixed behavior of watchpoint exceptions,
and we can center that information in lldb.  We can allow a remote
stub to override the default behavior via our packet extensions
if it's needed on a specific target.

This patch also separates the fetching of the number of watchpoints
from whether exceptions are before/after the insn.  Currently if
lldb couldn't fetch the number of watchpoints (not really needed), it
also wouldn't get when exceptions are received, and watchpoint
handling would fail.  lldb doesn't actually use the number of
watchpoints for anything beyond printing it to the user.

Differential Revision: https://reviews.llvm.org/D143215
rdar://101426626
2023-02-14 11:35:39 -08:00

122 lines
4.4 KiB
C++

//===-- ProcessWindows.h ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_
#define liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_
#include "lldb/Target/Process.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-forward.h"
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
#include "ProcessDebugger.h"
namespace lldb_private {
class HostProcess;
class ProcessWindows : public Process, public ProcessDebugger {
public:
// Static functions.
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec *,
bool can_connect);
static void Initialize();
static void Terminate();
static llvm::StringRef GetPluginNameStatic() { return "windows"; }
static llvm::StringRef GetPluginDescriptionStatic();
~ProcessWindows();
size_t GetSTDOUT(char *buf, size_t buf_size, Status &error) override;
size_t GetSTDERR(char *buf, size_t buf_size, Status &error) override;
size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) override;
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
Status EnableBreakpointSite(BreakpointSite *bp_site) override;
Status DisableBreakpointSite(BreakpointSite *bp_site) override;
Status DoDetach(bool keep_stopped) override;
Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
Status DoAttachToProcessWithID(
lldb::pid_t pid,
const lldb_private::ProcessAttachInfo &attach_info) override;
Status DoResume() override;
Status DoDestroy() override;
Status DoHalt(bool &caused_stop) override;
void DidLaunch() override;
void DidAttach(lldb_private::ArchSpec &arch_spec) override;
void RefreshStateAfterStop() override;
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
bool DestroyRequiresHalt() override { return false; }
bool DoUpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override;
bool IsAlive() override;
ArchSpec GetSystemArchitecture() override;
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error) override;
size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
Status &error) override;
lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
Status &error) override;
Status DoDeallocateMemory(lldb::addr_t ptr) override;
lldb::addr_t GetImageInfoAddress() override;
DynamicLoaderWindowsDYLD *GetDynamicLoader() override;
// IDebugDelegate overrides.
void OnExitProcess(uint32_t exit_code) override;
void OnDebuggerConnected(lldb::addr_t image_base) override;
ExceptionResult OnDebugException(bool first_chance,
const ExceptionRecord &record) override;
void OnCreateThread(const HostThread &thread) override;
void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override;
void OnLoadDll(const ModuleSpec &module_spec,
lldb::addr_t module_addr) override;
void OnUnloadDll(lldb::addr_t module_addr) override;
void OnDebugString(const std::string &string) override;
void OnDebuggerError(const Status &error, uint32_t type) override;
std::optional<uint32_t> GetWatchpointSlotCount() override;
Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
protected:
ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
Status DoGetMemoryRegionInfo(lldb::addr_t vm_addr,
MemoryRegionInfo &info) override;
private:
struct WatchpointInfo {
uint32_t slot_id;
lldb::addr_t address;
uint32_t size;
bool read;
bool write;
};
std::map<lldb::break_id_t, WatchpointInfo> m_watchpoints;
std::vector<lldb::break_id_t> m_watchpoint_ids;
};
} // namespace lldb_private
#endif // liblldb_Plugins_Process_Windows_Common_ProcessWindows_H_