RegisterContextPOSIXProcessMonitor_arm64.cpp revision 285116
1//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp -----------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===---------------------------------------------------------------------===//
9
10#include "lldb/Core/DataBufferHeap.h"
11#include "lldb/Core/RegisterValue.h"
12#include "lldb/Target/Thread.h"
13
14#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
15#include "ProcessPOSIX.h"
16#include "ProcessMonitor.h"
17#include "RegisterContextPOSIXProcessMonitor_arm64.h"
18
19#define REG_CONTEXT_SIZE (GetGPRSize())
20
21using namespace lldb;
22using namespace lldb_private;
23
24RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
25                                                                                   uint32_t concrete_frame_idx,
26                                                                                   lldb_private::RegisterInfoInterface *register_info)
27    : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info)
28{
29}
30
31ProcessMonitor &
32RegisterContextPOSIXProcessMonitor_arm64::GetMonitor()
33{
34    lldb::ProcessSP base = CalculateProcess();
35    ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
36    return process->GetMonitor();
37}
38
39bool
40RegisterContextPOSIXProcessMonitor_arm64::ReadGPR()
41{
42     ProcessMonitor &monitor = GetMonitor();
43     return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
44}
45
46bool
47RegisterContextPOSIXProcessMonitor_arm64::ReadFPR()
48{
49    ProcessMonitor &monitor = GetMonitor();
50    return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
51}
52
53bool
54RegisterContextPOSIXProcessMonitor_arm64::WriteGPR()
55{
56    ProcessMonitor &monitor = GetMonitor();
57    return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
58}
59
60bool
61RegisterContextPOSIXProcessMonitor_arm64::WriteFPR()
62{
63    ProcessMonitor &monitor = GetMonitor();
64    return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
65}
66
67bool
68RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg,
69                                                       lldb_private::RegisterValue &value)
70{
71    ProcessMonitor &monitor = GetMonitor();
72    return monitor.ReadRegisterValue(m_thread.GetID(),
73                                     GetRegisterOffset(reg),
74                                     GetRegisterName(reg),
75                                     GetRegisterSize(reg),
76                                     value);
77}
78
79bool
80RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg,
81                                                         const lldb_private::RegisterValue &value)
82{
83    unsigned reg_to_write = reg;
84    lldb_private::RegisterValue value_to_write = value;
85
86    // Check if this is a subregister of a full register.
87    const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
88    if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
89    {
90        lldb_private::RegisterValue full_value;
91        uint32_t full_reg = reg_info->invalidate_regs[0];
92        const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
93
94        // Read the full register.
95        if (ReadRegister(full_reg_info, full_value))
96        {
97            lldb_private::Error error;
98            lldb::ByteOrder byte_order = GetByteOrder();
99            uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
100
101            // Get the bytes for the full register.
102            const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
103                                                                   dst,
104                                                                   sizeof(dst),
105                                                                   byte_order,
106                                                                   error);
107            if (error.Success() && dest_size)
108            {
109                uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize];
110
111                // Get the bytes for the source data.
112                const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
113                if (error.Success() && src_size && (src_size < dest_size))
114                {
115                    // Copy the src bytes to the destination.
116                    ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
117                    // Set this full register as the value to write.
118                    value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
119                    value_to_write.SetType(full_reg_info);
120                    reg_to_write = full_reg;
121                }
122            }
123        }
124    }
125
126    ProcessMonitor &monitor = GetMonitor();
127    return monitor.WriteRegisterValue(m_thread.GetID(),
128                                      GetRegisterOffset(reg_to_write),
129                                      GetRegisterName(reg_to_write),
130                                      value_to_write);
131}
132
133bool
134RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
135{
136    if (!reg_info)
137        return false;
138
139    const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
140
141    if (IsFPR(reg))
142    {
143        if (!ReadFPR())
144            return false;
145    }
146    else
147    {
148        uint32_t full_reg = reg;
149        bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
150
151        if (is_subreg)
152        {
153            // Read the full aligned 64-bit register.
154            full_reg = reg_info->invalidate_regs[0];
155        }
156        return ReadRegister(full_reg, value);
157    }
158
159    // Get pointer to m_fpr variable and set the data from it.
160    assert (reg_info->byte_offset < sizeof m_fpr);
161    uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
162    switch (reg_info->byte_size)
163    {
164        case 2:
165            value.SetUInt16(*(uint16_t *)src);
166            return true;
167        case 4:
168            value.SetUInt32(*(uint32_t *)src);
169            return true;
170        case 8:
171            value.SetUInt64(*(uint64_t *)src);
172            return true;
173        default:
174            assert(false && "Unhandled data size.");
175            return false;
176    }
177}
178
179bool
180RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
181{
182    const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
183
184    if (IsGPR(reg))
185        return WriteRegister(reg, value);
186
187    return false;
188}
189
190bool
191RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
192{
193    bool success = false;
194    data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0));
195    if (data_sp && ReadGPR () && ReadFPR ())
196    {
197        uint8_t *dst = data_sp->GetBytes();
198        success = dst != 0;
199
200        if (success)
201        {
202            ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
203            dst += GetGPRSize();
204            ::memcpy (dst, &m_fpr, sizeof m_fpr);
205        }
206    }
207    return success;
208}
209
210bool
211RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
212{
213    bool success = false;
214    if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
215    {
216        uint8_t *src = data_sp->GetBytes();
217        if (src)
218        {
219            ::memcpy (&m_gpr_arm64, src, GetGPRSize());
220            if (WriteGPR()) {
221                src += GetGPRSize();
222                ::memcpy (&m_fpr, src, sizeof m_fpr);
223                success = WriteFPR();
224            }
225        }
226    }
227    return success;
228}
229
230uint32_t
231RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
232                                                                bool read, bool write)
233{
234    const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
235    uint32_t hw_index;
236
237    for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
238    {
239        if (IsWatchpointVacant(hw_index))
240            return SetHardwareWatchpointWithIndex(addr, size,
241                                                  read, write,
242                                                  hw_index);
243    }
244
245    return LLDB_INVALID_INDEX32;
246}
247
248bool
249RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index)
250{
251    return false;
252}
253
254bool
255RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable)
256{
257    return false;
258}
259
260bool
261RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint()
262{
263    // PC points one byte past the int3 responsible for the breakpoint.
264    lldb::addr_t pc;
265
266    if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
267        return false;
268
269    SetPC(pc - 1);
270    return true;
271}
272
273unsigned
274RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset)
275{
276    unsigned reg;
277    for (reg = 0; reg < k_num_registers_arm64; reg++)
278    {
279        if (GetRegisterInfo()[reg].byte_offset == offset)
280            break;
281    }
282    assert(reg < k_num_registers_arm64 && "Invalid register offset.");
283    return reg;
284}
285
286bool
287RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index)
288{
289    return false;
290}
291
292bool
293RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits()
294{
295    return false;
296}
297
298lldb::addr_t
299RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index)
300{
301    return LLDB_INVALID_ADDRESS;
302}
303
304bool
305RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index)
306{
307    return false;
308}
309
310bool
311RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
312                                                                         bool read, bool write,
313                                                                         uint32_t hw_index)
314{
315    return false;
316}
317
318uint32_t
319RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints()
320{
321    return 0;
322}
323