Skip to content

Commit a225802

Browse files
committed
[lldb] Add VirtualDataExtractor abstraction
1 parent 3f61402 commit a225802

File tree

6 files changed

+455
-2
lines changed

6 files changed

+455
-2
lines changed

lldb/include/lldb/Utility/DataExtractor.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ class DataExtractor {
334334
/// \return
335335
/// A pointer to the bytes in this object's data if the offset
336336
/// and length are valid, or nullptr otherwise.
337-
const void *GetData(lldb::offset_t *offset_ptr, lldb::offset_t length) const {
337+
virtual const void *GetData(lldb::offset_t *offset_ptr,
338+
lldb::offset_t length) const {
338339
const uint8_t *ptr = PeekData(*offset_ptr, length);
339340
if (ptr)
340341
*offset_ptr += length;
@@ -829,7 +830,8 @@ class DataExtractor {
829830
/// A non-nullptr data pointer if \a offset is a valid offset and
830831
/// there are \a length bytes available at that offset, nullptr
831832
/// otherwise.
832-
const uint8_t *PeekData(lldb::offset_t offset, lldb::offset_t length) const {
833+
virtual const uint8_t *PeekData(lldb::offset_t offset,
834+
lldb::offset_t length) const {
833835
if (ValidOffsetForDataOfSize(offset, length))
834836
return m_start + offset;
835837
return nullptr;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
9+
#ifndef LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H
10+
#define LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H
11+
12+
#include "lldb/Utility/DataExtractor.h"
13+
#include "lldb/Utility/RangeMap.h"
14+
#include "lldb/lldb-types.h"
15+
16+
namespace lldb_private {
17+
18+
/// A DataExtractor subclass that allows reading data at virtual addresses
19+
/// using a lookup table that maps virtual address ranges to physical offsets.
20+
///
21+
/// This class maintains a lookup table where each entry contains:
22+
/// - base: starting virtual address for this entry
23+
/// - size: size of this entry in bytes
24+
/// - data: physical offset in the underlying data buffer
25+
///
26+
/// Reads are translated from virtual addresses to physical offsets using
27+
/// this lookup table. Reads cannot cross entry boundaries and this is
28+
/// enforced with assertions.
29+
class VirtualDataExtractor : public DataExtractor {
30+
public:
31+
/// Type alias for the range map used internally.
32+
/// Maps virtual addresses (base) to physical offsets (data).
33+
using LookupTable =
34+
RangeDataVector<lldb::offset_t, lldb::offset_t, lldb::offset_t>;
35+
36+
VirtualDataExtractor() = default;
37+
38+
VirtualDataExtractor(const void *data, lldb::offset_t data_length,
39+
lldb::ByteOrder byte_order, uint32_t addr_size,
40+
LookupTable lookup_table);
41+
42+
VirtualDataExtractor(const lldb::DataBufferSP &data_sp,
43+
lldb::ByteOrder byte_order, uint32_t addr_size,
44+
LookupTable lookup_table);
45+
46+
const void *GetData(lldb::offset_t *offset_ptr,
47+
lldb::offset_t length) const override;
48+
49+
const uint8_t *PeekData(lldb::offset_t offset,
50+
lldb::offset_t length) const override;
51+
52+
const LookupTable &GetLookupTable() const { return m_lookup_table; }
53+
54+
protected:
55+
/// Find the lookup entry that contains the given virtual address.
56+
const LookupTable::Entry *FindEntry(lldb::offset_t virtual_addr) const;
57+
58+
/// Validate that a read at a virtual address is within bounds and
59+
/// does not cross entry boundaries.
60+
bool ValidateVirtualRead(lldb::offset_t virtual_addr,
61+
lldb::offset_t length) const;
62+
63+
private:
64+
LookupTable m_lookup_table;
65+
};
66+
67+
} // namespace lldb_private
68+
69+
#endif // LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H

lldb/source/Utility/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
7878
UserIDResolver.cpp
7979
VASprintf.cpp
8080
VMRange.cpp
81+
VirtualDataExtractor.cpp
8182
XcodeSDK.cpp
8283
ZipFile.cpp
8384

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
9+
#include "lldb/Utility/VirtualDataExtractor.h"
10+
#include <cassert>
11+
12+
using namespace lldb;
13+
using namespace lldb_private;
14+
15+
VirtualDataExtractor::VirtualDataExtractor(const void *data,
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+
25+
VirtualDataExtractor::VirtualDataExtractor(const DataBufferSP &data_sp,
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+
34+
const VirtualDataExtractor::LookupTable::Entry *
35+
VirtualDataExtractor::FindEntry(offset_t virtual_addr) const {
36+
// Use RangeDataVector's binary search instead of linear search.
37+
return m_lookup_table.FindEntryThatContains(virtual_addr);
38+
}
39+
40+
bool VirtualDataExtractor::ValidateVirtualRead(offset_t virtual_addr,
41+
offset_t length) const {
42+
const LookupTable::Entry *entry = FindEntry(virtual_addr);
43+
if (!entry)
44+
return false;
45+
46+
// Assert that the read does not cross entry boundaries.
47+
// RangeData.Contains() checks if a range is fully contained.
48+
assert(entry->Contains(LookupTable::Range(virtual_addr, length)) &&
49+
"Read crosses lookup table entry boundary");
50+
51+
// Also validate that the physical offset is within the data buffer.
52+
// RangeData.data contains the physical offset.
53+
offset_t physical_offset = entry->data + (virtual_addr - entry->base);
54+
return ValidOffsetForDataOfSize(physical_offset, length);
55+
}
56+
57+
const void *VirtualDataExtractor::GetData(offset_t *offset_ptr,
58+
offset_t length) const {
59+
// Override to treat offset as virtual address.
60+
if (!offset_ptr)
61+
return nullptr;
62+
63+
offset_t virtual_addr = *offset_ptr;
64+
65+
if (!ValidateVirtualRead(virtual_addr, length))
66+
return nullptr;
67+
68+
const LookupTable::Entry *entry = FindEntry(virtual_addr);
69+
assert(entry && "ValidateVirtualRead should have found an entry");
70+
71+
offset_t physical_offset = entry->data + (virtual_addr - entry->base);
72+
// Use base class PeekData directly to avoid recursion.
73+
const void *result = DataExtractor::PeekData(physical_offset, length);
74+
75+
if (result) {
76+
// Advance the virtual offset pointer.
77+
*offset_ptr += length;
78+
}
79+
80+
return result;
81+
}
82+
83+
const uint8_t *VirtualDataExtractor::PeekData(offset_t offset,
84+
offset_t length) const {
85+
// Override to treat offset as virtual address.
86+
if (!ValidateVirtualRead(offset, length))
87+
return nullptr;
88+
89+
const LookupTable::Entry *entry = FindEntry(offset);
90+
assert(entry && "ValidateVirtualRead should have found an entry");
91+
92+
offset_t physical_offset = entry->data + (offset - entry->base);
93+
// Use the base class PeekData with the physical offset.
94+
return DataExtractor::PeekData(physical_offset, length);
95+
}

lldb/unittests/Utility/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ add_lldb_unittest(UtilityTests
4848
UserIDResolverTest.cpp
4949
UUIDTest.cpp
5050
VASprintfTest.cpp
51+
VirtualDataExtractorTest.cpp
5152
VMRangeTest.cpp
5253
XcodeSDKTest.cpp
5354

0 commit comments

Comments
 (0)