blob: 803fed54d6b0928ef4c6c3fe6defa5d532cc29fd (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
//===-- NativeRegisterContextDBReg_arm.cpp --------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "NativeRegisterContextDBReg_arm.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
using namespace lldb_private;
uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) {
Log *log = GetLog(LLDBLog::Watchpoints);
LLDB_LOG(log, "wp_index: {0}", wp_index);
switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
case 0x01:
return 1;
case 0x03:
return 2;
case 0x07:
return 3;
case 0x0f:
return 4;
default:
return 0;
}
}
std::optional<NativeRegisterContextDBReg::WatchpointDetails>
NativeRegisterContextDBReg_arm::AdjustWatchpoint(
const WatchpointDetails &details) {
auto [size, addr] = details;
if (size == 0 || size > 4)
return {};
// Check 4-byte alignment for hardware watchpoint target address. Below is a
// hack to recalculate address and size in order to make sure we can watch
// non 4-byte aligned addresses as well.
if (addr & 0x03) {
uint8_t watch_mask = (addr & 0x03) + size;
if (watch_mask > 0x04)
return {};
else if (watch_mask <= 0x02)
size = 2;
else
size = 4;
addr = addr & (~0x03);
}
return WatchpointDetails{size, addr};
}
NativeRegisterContextDBReg::BreakpointDetails
NativeRegisterContextDBReg_arm::AdjustBreakpoint(
const BreakpointDetails &details) {
BreakpointDetails bd = details;
// Use size to get a hint of arm vs thumb modes.
// LLDB usually aligns this client side, but other clients may not.
switch (bd.size) {
case 2:
bd.addr &= ~1;
break;
case 4:
bd.addr &= ~3;
break;
default:
// We assume that ValidateBreakpoint would have caught this earlier.
llvm_unreachable("Invalid breakpoint size!");
}
return bd;
}
uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
switch (size) {
case 2:
return (0x3 << 5) | 7;
case 4:
return (0xfu << 5) | 7;
default:
// ValidateBreakpoint would have rejected this earlier.
llvm_unreachable("Invalid breakpoint size.");
}
}
uint32_t
NativeRegisterContextDBReg_arm::MakeWatchControlValue(size_t size,
uint32_t watch_flags) {
// We can only watch up to four bytes that follow a 4 byte aligned address
// per watchpoint register pair, so make sure we can properly encode this.
// We assume that the address was 4 byte aligned by AdjustWatchpoint.
uint32_t byte_mask = (1u << size) - 1u;
// Check if we need multiple watchpoint register
if (byte_mask > 0xfu)
return LLDB_INVALID_INDEX32;
// Setup control value
// Make the byte_mask into a valid Byte Address Select mask
uint32_t control_value = byte_mask << 5;
// Turn on appropriate watchpoint flags read or write
control_value |= (watch_flags << 3);
// Enable this watchpoint and make it stop in privileged or user mode;
control_value |= 7;
return control_value;
}
|