1//===-- RegisterContextMemory.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 "RegisterContextMemory.h"
10
11#include "DynamicRegisterInfo.h"
12#include "lldb/Target/Process.h"
13#include "lldb/Target/Thread.h"
14#include "lldb/Utility/DataBufferHeap.h"
15#include "lldb/Utility/RegisterValue.h"
16#include "lldb/Utility/Status.h"
17
18using namespace lldb;
19using namespace lldb_private;
20
21// RegisterContextMemory constructor
22RegisterContextMemory::RegisterContextMemory(Thread &thread,
23                                             uint32_t concrete_frame_idx,
24                                             DynamicRegisterInfo &reg_infos,
25                                             addr_t reg_data_addr)
26    : RegisterContext(thread, concrete_frame_idx), m_reg_infos(reg_infos),
27      m_reg_valid(), m_reg_data(), m_reg_data_addr(reg_data_addr) {
28  // Resize our vector of bools to contain one bool for every register. We will
29  // use these boolean values to know when a register value is valid in
30  // m_reg_data.
31  const size_t num_regs = reg_infos.GetNumRegisters();
32  assert(num_regs > 0);
33  m_reg_valid.resize(num_regs);
34
35  // Make a heap based buffer that is big enough to store all registers
36  DataBufferSP reg_data_sp(
37      new DataBufferHeap(reg_infos.GetRegisterDataByteSize(), 0));
38  m_reg_data.SetData(reg_data_sp);
39}
40
41// Destructor
42RegisterContextMemory::~RegisterContextMemory() {}
43
44void RegisterContextMemory::InvalidateAllRegisters() {
45  if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
46    SetAllRegisterValid(false);
47}
48
49void RegisterContextMemory::SetAllRegisterValid(bool b) {
50  std::vector<bool>::iterator pos, end = m_reg_valid.end();
51  for (pos = m_reg_valid.begin(); pos != end; ++pos)
52    *pos = b;
53}
54
55size_t RegisterContextMemory::GetRegisterCount() {
56  return m_reg_infos.GetNumRegisters();
57}
58
59const RegisterInfo *RegisterContextMemory::GetRegisterInfoAtIndex(size_t reg) {
60  return m_reg_infos.GetRegisterInfoAtIndex(reg);
61}
62
63size_t RegisterContextMemory::GetRegisterSetCount() {
64  return m_reg_infos.GetNumRegisterSets();
65}
66
67const RegisterSet *RegisterContextMemory::GetRegisterSet(size_t reg_set) {
68  return m_reg_infos.GetRegisterSet(reg_set);
69}
70
71uint32_t RegisterContextMemory::ConvertRegisterKindToRegisterNumber(
72    lldb::RegisterKind kind, uint32_t num) {
73  return m_reg_infos.ConvertRegisterKindToRegisterNumber(kind, num);
74}
75
76bool RegisterContextMemory::ReadRegister(const RegisterInfo *reg_info,
77                                         RegisterValue &reg_value) {
78  const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
79  if (!m_reg_valid[reg_num]) {
80    if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer()))
81      return false;
82  }
83  const bool partial_data_ok = false;
84  return reg_value
85      .SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset,
86                        partial_data_ok)
87      .Success();
88}
89
90bool RegisterContextMemory::WriteRegister(const RegisterInfo *reg_info,
91                                          const RegisterValue &reg_value) {
92  if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
93    const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
94    addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
95    Status error(WriteRegisterValueToMemory(reg_info, reg_addr,
96                                            reg_info->byte_size, reg_value));
97    m_reg_valid[reg_num] = false;
98    return error.Success();
99  }
100  return false;
101}
102
103bool RegisterContextMemory::ReadAllRegisterValues(DataBufferSP &data_sp) {
104  if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
105    ProcessSP process_sp(CalculateProcess());
106    if (process_sp) {
107      Status error;
108      if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(),
109                                 data_sp->GetByteSize(),
110                                 error) == data_sp->GetByteSize()) {
111        SetAllRegisterValid(true);
112        return true;
113      }
114    }
115  }
116  return false;
117}
118
119bool RegisterContextMemory::WriteAllRegisterValues(
120    const DataBufferSP &data_sp) {
121  if (m_reg_data_addr != LLDB_INVALID_ADDRESS) {
122    ProcessSP process_sp(CalculateProcess());
123    if (process_sp) {
124      Status error;
125      SetAllRegisterValid(false);
126      if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(),
127                                  data_sp->GetByteSize(),
128                                  error) == data_sp->GetByteSize())
129        return true;
130    }
131  }
132  return false;
133}
134
135void RegisterContextMemory::SetAllRegisterData(
136    const lldb::DataBufferSP &data_sp) {
137  m_reg_data.SetData(data_sp);
138  SetAllRegisterValid(true);
139}
140