LLDB mainline
VirtualDataExtractor.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include <cassert>
11
12using namespace lldb;
13using namespace lldb_private;
14
16 offset_t data_length,
17 ByteOrder byte_order,
18 uint32_t addr_size,
19 LookupTable lookup_table)
20 : DataExtractor(data, data_length, byte_order, addr_size),
21 m_lookup_table(std::move(lookup_table)) {
22 m_lookup_table.Sort();
23}
24
26 ByteOrder byte_order,
27 uint32_t addr_size,
28 LookupTable lookup_table)
29 : DataExtractor(data_sp, byte_order, addr_size),
30 m_lookup_table(std::move(lookup_table)) {
31 m_lookup_table.Sort();
32}
33
35 LookupTable lookup_table)
36 : DataExtractor(data_sp), m_lookup_table(std::move(lookup_table)) {
37 m_lookup_table.Sort();
38}
39
42 // Use RangeDataVector's binary search instead of linear search.
43 return m_lookup_table.FindEntryThatContains(virtual_addr);
44}
45
47 offset_t length) const {
48 const LookupTable::Entry *entry = FindEntry(virtual_addr);
49 if (!entry)
50 return false;
51
52 // Assert that the read does not cross entry boundaries.
53 // RangeData.Contains() checks if a range is fully contained.
54 assert(entry->Contains(LookupTable::Range(virtual_addr, length)) &&
55 "Read crosses lookup table entry boundary");
56
57 // Also validate that the physical offset is within the data buffer.
58 // RangeData.data contains the physical offset.
59 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
60 return ValidOffsetForDataOfSize(physical_offset, length);
61}
62
64 offset_t length) const {
65 // Override to treat offset as virtual address.
66 if (!offset_ptr)
67 return nullptr;
68
69 offset_t virtual_addr = *offset_ptr;
70
71 if (!ValidateVirtualRead(virtual_addr, length))
72 return nullptr;
73
74 const LookupTable::Entry *entry = FindEntry(virtual_addr);
75 assert(entry && "ValidateVirtualRead should have found an entry");
76
77 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
78 // Use base class PeekData directly to avoid recursion.
79 const void *result = DataExtractor::PeekData(physical_offset, length);
80
81 if (result) {
82 // Advance the virtual offset pointer.
83 *offset_ptr += length;
84 }
85
86 return result;
87}
88
90 lldb::ByteOrder byte_order) {
91 // Invoked from the base class ctor.
92 if (!m_data_sp || m_start == nullptr)
93 return DataExtractor::SetData(bytes, length, byte_order);
94
95 // A no-op SetData that is setting the same data buffer again.
96 if (!m_data_sp && m_start == bytes && length == GetVirtualByteSize())
97 return GetVirtualByteSize();
98
99 assert("SetData(1) called on VirtualDataExtractor that already had data" &&
100 false);
101
102 DataExtractor::SetData(bytes, length, byte_order);
104
105 return GetVirtualByteSize();
106}
107
109 lldb::offset_t offset,
110 lldb::offset_t length) {
111 // Invoked from the base class ctor
112 if (!m_data_sp || m_start == nullptr)
113 return DataExtractor::SetData(data, offset, length);
114
115 // A no-op SetData that is setting the same data buffer again
116 if (m_data_sp && data.GetSharedDataBuffer().get() == m_data_sp.get() &&
117 offset == 0 && length == GetVirtualByteSize())
118 return GetVirtualByteSize();
119 assert("SetData(2) called on VirtualDataExtractor that already had data" &&
120 false);
121
122 DataExtractor::SetData(data, offset, length);
124
125 return GetVirtualByteSize();
126}
127
129 lldb::offset_t offset,
130 lldb::offset_t length) {
131 // Invoked from the base class ctor
132 if (!m_data_sp || m_start == nullptr)
133 return DataExtractor::SetData(data_sp, offset, length);
134
135 // A no-op SetData that is setting the same data buffer again
136 if (m_data_sp && data_sp.get() == m_data_sp.get() && offset == 0 &&
137 length == GetVirtualByteSize())
138 return GetVirtualByteSize();
139
140 assert("SetData(3) called on VirtualDataExtractor that already had data" &&
141 false);
142
143 DataExtractor::SetData(data_sp, offset, length);
145
146 return GetVirtualByteSize();
147}
148
150 // calling SetData on a VirtualDataExtractor that already has a
151 // data buffer means the LookupTable needs to be either replaced, or
152 // if we assume the buffer is a subset of the original, we need to
153 // update all the entries to have correct new offsets into the buffer
154 // and remove entries that are outside the new range.
155 // For now, zero out the LookupTable and behave as if this is a simple
156 // DataExtractor.
157 m_lookup_table.Clear();
158 m_lookup_table.Append(
160}
161
163 offset_t lowest = -1ULL;
164 offset_t highest = 0;
165 for (const auto ent : m_lookup_table) {
166 lowest = std::min(lowest, ent.base);
167 highest = std::max(highest, ent.base + ent.size);
168 }
169 return highest - lowest;
170}
171
173 return m_end - m_start;
174}
175
177 const offset_t size = GetVirtualByteSize();
178 if (size > virtual_offset)
179 return size - virtual_offset;
180 return 0;
181}
182
185 const offset_t size = m_end - m_start;
186 if (size > physical_offset)
187 return size - physical_offset;
188 return 0;
189}
190
192 offset_t length) const {
193 // Override to treat offset as virtual address.
194 if (!ValidateVirtualRead(offset, length))
195 return nullptr;
196
197 const LookupTable::Entry *entry = FindEntry(offset);
198 assert(entry && "ValidateVirtualRead should have found an entry");
199
200 offset_t physical_offset = entry->data + (offset - entry->base);
201 // Use the base class PeekData with the physical offset.
202 return DataExtractor::PeekData(physical_offset, length);
203}
204
206 offset_t virtual_addr = *offset_ptr;
207 const LookupTable::Entry *entry = FindEntry(virtual_addr);
208 assert(entry && "Unchecked methods require valid virtual address");
209
210 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
211 uint8_t result = DataExtractor::GetU8_unchecked(&physical_offset);
212 *offset_ptr += 1;
213 return result;
214}
215
217 offset_t virtual_addr = *offset_ptr;
218 const LookupTable::Entry *entry = FindEntry(virtual_addr);
219 assert(entry && "Unchecked methods require valid virtual address");
220
221 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
222 uint16_t result = DataExtractor::GetU16_unchecked(&physical_offset);
223 *offset_ptr += 2;
224 return result;
225}
226
228 offset_t virtual_addr = *offset_ptr;
229 const LookupTable::Entry *entry = FindEntry(virtual_addr);
230 assert(entry && "Unchecked methods require valid virtual address");
231
232 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
233 uint32_t result = DataExtractor::GetU32_unchecked(&physical_offset);
234 *offset_ptr += 4;
235 return result;
236}
237
239 offset_t virtual_addr = *offset_ptr;
240 const LookupTable::Entry *entry = FindEntry(virtual_addr);
241 assert(entry && "Unchecked methods require valid virtual address");
242
243 offset_t physical_offset = entry->data + (virtual_addr - entry->base);
244 uint64_t result = DataExtractor::GetU64_unchecked(&physical_offset);
245 *offset_ptr += 8;
246 return result;
247}
248
251 offset_t virtual_length) {
252 const LookupTable::Entry *entry = FindEntry(virtual_offset);
253 assert(
254 entry &&
255 "VirtualDataExtractor subset extractor requires valid virtual address");
256 if (!entry)
257 return {};
258
259 // Entry::data is the offset into the DataBuffer's actual start/end range
260 // Entry::base is the virtual address at the start of this region of data
261 offset_t offset_into_entry_range = virtual_offset - entry->base;
262 assert(
263 offset_into_entry_range + virtual_length <= entry->size &&
264 "VirtualDataExtractor subset may not span multiple LookupTable entries");
265 if (offset_into_entry_range + virtual_length > entry->size)
266 return {};
267
268 // We could support a Subset VirtualDataExtractor which covered
269 // multiple LookupTable virtual entries, but we'd need to mutate
270 // all of the LookupTable entries that were properly included in
271 // the Subset, a bit tricky. So we won't implement that until it's
272 // needed.
273
274 offset_t physical_start = entry->data + offset_into_entry_range;
275 std::shared_ptr<DataExtractor> new_sp = std::make_shared<DataExtractor>(
277 new_sp->SetData(GetSharedDataBuffer(), physical_start, virtual_length);
278 return new_sp;
279}
280
281// Return a DataExtractorSP that contains a single LookupTable's entry; all
282// bytes are guaranteed to be readable.
285 const LookupTable::Entry *entry = FindEntry(virtual_offset);
286 assert(
287 entry &&
288 "VirtualDataExtractor subset extractor requires valid virtual address");
289 if (!entry)
290 return {};
291
292 // Entry::data is the offset into the DataBuffer's actual start/end range
293 // Entry::base is the virtual address at the start of this region of data
294 offset_t offset_into_entry_range = virtual_offset - entry->base;
295
296 offset_t physical_start = entry->data + offset_into_entry_range;
297 std::shared_ptr<DataExtractor> new_sp = std::make_shared<DataExtractor>(
299 new_sp->SetData(GetSharedDataBuffer(), physical_start,
300 entry->size - offset_into_entry_range);
301 return new_sp;
302}
303
304// Return an ArrayRef to the first contiguous region of the LookupTable
305// only. The LookupTable entries may have gaps of unmapped data, and we
306// can't include those in the ArrayRef or something may touch those pages.
307llvm::ArrayRef<uint8_t> VirtualDataExtractor::GetData() const {
308 const LookupTable::Entry *entry = FindEntry(0);
309 assert(entry &&
310 "VirtualDataExtractor GetData requires valid virtual address");
311 if (!entry)
312 return {};
313 return {m_start + static_cast<size_t>(entry->data), static_cast<size_t>(entry->size)};
314}
virtual uint32_t GetU32_unchecked(lldb::offset_t *offset_ptr) const
bool ValidOffsetForDataOfSize(lldb::offset_t offset, lldb::offset_t length) const
Test the availability of length bytes of data from offset.
const uint8_t * m_start
A pointer to the first byte of data.
lldb::DataBufferSP m_data_sp
The shared pointer to data that can be shared among multiple instances.
virtual const uint8_t * PeekData(lldb::offset_t offset, lldb::offset_t length) const
Peek at a bytes at offset.
const uint8_t * m_end
A pointer to the byte that is past the end of the data.
DataExtractor()
Default constructor.
virtual lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
uint32_t GetAddressByteSize() const
Get the current address size.
virtual uint8_t GetU8_unchecked(lldb::offset_t *offset_ptr) const
virtual uint64_t GetU64_unchecked(lldb::offset_t *offset_ptr) const
lldb::ByteOrder GetByteOrder() const
Get the current byte order value.
virtual uint16_t GetU16_unchecked(lldb::offset_t *offset_ptr) const
lldb::DataBufferSP GetSharedDataBuffer() const
RangeData< lldb::offset_t, lldb::offset_t, lldb::offset_t > Entry
Definition RangeMap.h:462
lldb_private::Range< lldb::offset_t, lldb::offset_t > Range
Definition RangeMap.h:461
lldb::DataExtractorSP GetSubsetExtractorSP(lldb::offset_t offset, lldb::offset_t length) override
Return a new DataExtractor which represents a subset of an existing data extractor's bytes,...
uint32_t GetU32_unchecked(lldb::offset_t *offset_ptr) const override
const LookupTable::Entry * FindEntry(lldb::offset_t virtual_addr) const
Find the lookup entry that contains the given virtual address.
llvm::ArrayRef< uint8_t > GetData() const override
bool ValidateVirtualRead(lldb::offset_t virtual_addr, lldb::offset_t length) const
Validate that a read at a virtual address is within bounds and does not cross entry boundaries.
const uint8_t * PeekData(lldb::offset_t offset, lldb::offset_t length) const override
Peek at a bytes at offset.
uint8_t GetU8_unchecked(lldb::offset_t *offset_ptr) const override
Unchecked overrides.
uint64_t GetU64_unchecked(lldb::offset_t *offset_ptr) const override
RangeDataVector< lldb::offset_t, lldb::offset_t, lldb::offset_t > LookupTable
Type alias for the range map used internally.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order) override
Set data with a buffer that is caller owned.
uint16_t GetU16_unchecked(lldb::offset_t *offset_ptr) const override
lldb::offset_t PhysicalBytesLeft(lldb::offset_t physical_offset) const
lldb::offset_t VirtualBytesLeft(lldb::offset_t virtual_offset) const
A class that represents a running process on the host machine.
uint64_t offset_t
Definition lldb-types.h:85
ByteOrder
Byte ordering definitions.
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
bool Contains(BaseType r) const
Definition RangeMap.h:93