1//===-- RegisterContextThreadMemory.cpp -------------------------*- C++ -*-===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Target/OperatingSystem.h"
10#include "lldb/Target/Process.h"
11#include "lldb/Target/Thread.h"
12#include "lldb/Utility/Status.h"
13#include "lldb/lldb-private.h"
14
15#include "RegisterContextThreadMemory.h"
16
17using namespace lldb;
18using namespace lldb_private;
19
20RegisterContextThreadMemory::RegisterContextThreadMemory(
21    Thread &thread, lldb::addr_t register_data_addr)
22    : RegisterContext(thread, 0), m_thread_wp(thread.shared_from_this()),
23      m_reg_ctx_sp(), m_register_data_addr(register_data_addr), m_stop_id(0) {}
24
25RegisterContextThreadMemory::~RegisterContextThreadMemory() {}
26
27void RegisterContextThreadMemory::UpdateRegisterContext() {
28  ThreadSP thread_sp(m_thread_wp.lock());
29  if (thread_sp) {
30    ProcessSP process_sp(thread_sp->GetProcess());
31
32    if (process_sp) {
33      const uint32_t stop_id = process_sp->GetModID().GetStopID();
34      if (m_stop_id != stop_id) {
35        m_stop_id = stop_id;
36        m_reg_ctx_sp.reset();
37      }
38      if (!m_reg_ctx_sp) {
39        ThreadSP backing_thread_sp(thread_sp->GetBackingThread());
40        if (backing_thread_sp) {
41          m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
42        } else {
43          OperatingSystem *os = process_sp->GetOperatingSystem();
44          if (os->IsOperatingSystemPluginThread(thread_sp))
45            m_reg_ctx_sp = os->CreateRegisterContextForThread(
46                thread_sp.get(), m_register_data_addr);
47        }
48      }
49    } else {
50      m_reg_ctx_sp.reset();
51    }
52  } else {
53    m_reg_ctx_sp.reset();
54  }
55}
56
57// Subclasses must override these functions
58void RegisterContextThreadMemory::InvalidateAllRegisters() {
59  UpdateRegisterContext();
60  if (m_reg_ctx_sp)
61    m_reg_ctx_sp->InvalidateAllRegisters();
62}
63
64size_t RegisterContextThreadMemory::GetRegisterCount() {
65  UpdateRegisterContext();
66  if (m_reg_ctx_sp)
67    return m_reg_ctx_sp->GetRegisterCount();
68  return 0;
69}
70
71const RegisterInfo *
72RegisterContextThreadMemory::GetRegisterInfoAtIndex(size_t reg) {
73  UpdateRegisterContext();
74  if (m_reg_ctx_sp)
75    return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
76  return nullptr;
77}
78
79size_t RegisterContextThreadMemory::GetRegisterSetCount() {
80  UpdateRegisterContext();
81  if (m_reg_ctx_sp)
82    return m_reg_ctx_sp->GetRegisterSetCount();
83  return 0;
84}
85
86const RegisterSet *RegisterContextThreadMemory::GetRegisterSet(size_t reg_set) {
87  UpdateRegisterContext();
88  if (m_reg_ctx_sp)
89    return m_reg_ctx_sp->GetRegisterSet(reg_set);
90  return nullptr;
91}
92
93bool RegisterContextThreadMemory::ReadRegister(const RegisterInfo *reg_info,
94                                               RegisterValue &reg_value) {
95  UpdateRegisterContext();
96  if (m_reg_ctx_sp)
97    return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
98  return false;
99}
100
101bool RegisterContextThreadMemory::WriteRegister(
102    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
103  UpdateRegisterContext();
104  if (m_reg_ctx_sp)
105    return m_reg_ctx_sp->WriteRegister(reg_info, reg_value);
106  return false;
107}
108
109bool RegisterContextThreadMemory::ReadAllRegisterValues(
110    lldb::DataBufferSP &data_sp) {
111  UpdateRegisterContext();
112  if (m_reg_ctx_sp)
113    return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
114  return false;
115}
116
117bool RegisterContextThreadMemory::WriteAllRegisterValues(
118    const lldb::DataBufferSP &data_sp) {
119  UpdateRegisterContext();
120  if (m_reg_ctx_sp)
121    return m_reg_ctx_sp->WriteAllRegisterValues(data_sp);
122  return false;
123}
124
125bool RegisterContextThreadMemory::CopyFromRegisterContext(
126    lldb::RegisterContextSP reg_ctx_sp) {
127  UpdateRegisterContext();
128  if (m_reg_ctx_sp)
129    return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
130  return false;
131}
132
133uint32_t RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber(
134    lldb::RegisterKind kind, uint32_t num) {
135  UpdateRegisterContext();
136  if (m_reg_ctx_sp)
137    return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
138  return false;
139}
140
141uint32_t RegisterContextThreadMemory::NumSupportedHardwareBreakpoints() {
142  UpdateRegisterContext();
143  if (m_reg_ctx_sp)
144    return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
145  return false;
146}
147
148uint32_t RegisterContextThreadMemory::SetHardwareBreakpoint(lldb::addr_t addr,
149                                                            size_t size) {
150  UpdateRegisterContext();
151  if (m_reg_ctx_sp)
152    return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
153  return 0;
154}
155
156bool RegisterContextThreadMemory::ClearHardwareBreakpoint(uint32_t hw_idx) {
157  UpdateRegisterContext();
158  if (m_reg_ctx_sp)
159    return m_reg_ctx_sp->ClearHardwareBreakpoint(hw_idx);
160  return false;
161}
162
163uint32_t RegisterContextThreadMemory::NumSupportedHardwareWatchpoints() {
164  UpdateRegisterContext();
165  if (m_reg_ctx_sp)
166    return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
167  return 0;
168}
169
170uint32_t RegisterContextThreadMemory::SetHardwareWatchpoint(lldb::addr_t addr,
171                                                            size_t size,
172                                                            bool read,
173                                                            bool write) {
174  UpdateRegisterContext();
175  if (m_reg_ctx_sp)
176    return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
177  return 0;
178}
179
180bool RegisterContextThreadMemory::ClearHardwareWatchpoint(uint32_t hw_index) {
181  UpdateRegisterContext();
182  if (m_reg_ctx_sp)
183    return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
184  return false;
185}
186
187bool RegisterContextThreadMemory::HardwareSingleStep(bool enable) {
188  UpdateRegisterContext();
189  if (m_reg_ctx_sp)
190    return m_reg_ctx_sp->HardwareSingleStep(enable);
191  return false;
192}
193
194Status RegisterContextThreadMemory::ReadRegisterValueFromMemory(
195    const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr,
196    uint32_t src_len, RegisterValue &reg_value) {
197  UpdateRegisterContext();
198  if (m_reg_ctx_sp)
199    return m_reg_ctx_sp->ReadRegisterValueFromMemory(reg_info, src_addr,
200                                                     src_len, reg_value);
201  Status error;
202  error.SetErrorString("invalid register context");
203  return error;
204}
205
206Status RegisterContextThreadMemory::WriteRegisterValueToMemory(
207    const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr,
208    uint32_t dst_len, const RegisterValue &reg_value) {
209  UpdateRegisterContext();
210  if (m_reg_ctx_sp)
211    return m_reg_ctx_sp->WriteRegisterValueToMemory(reg_info, dst_addr, dst_len,
212                                                    reg_value);
213  Status error;
214  error.SetErrorString("invalid register context");
215  return error;
216}
217