[Lldb-commits] [lldb] [lldb] Add VirtualDataExtractor abstraction (PR #168802)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Wed Nov 19 17:08:45 PST 2025
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/168802
None
>From a2258029c741f357d0f45c656839492c7411898c Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Wed, 19 Nov 2025 17:07:47 -0800
Subject: [PATCH] [lldb] Add VirtualDataExtractor abstraction
---
lldb/include/lldb/Utility/DataExtractor.h | 6 +-
.../lldb/Utility/VirtualDataExtractor.h | 69 +++++
lldb/source/Utility/CMakeLists.txt | 1 +
lldb/source/Utility/VirtualDataExtractor.cpp | 95 ++++++
lldb/unittests/Utility/CMakeLists.txt | 1 +
.../Utility/VirtualDataExtractorTest.cpp | 285 ++++++++++++++++++
6 files changed, 455 insertions(+), 2 deletions(-)
create mode 100644 lldb/include/lldb/Utility/VirtualDataExtractor.h
create mode 100644 lldb/source/Utility/VirtualDataExtractor.cpp
create mode 100644 lldb/unittests/Utility/VirtualDataExtractorTest.cpp
diff --git a/lldb/include/lldb/Utility/DataExtractor.h b/lldb/include/lldb/Utility/DataExtractor.h
index b4960f5e87c85..fe217795ff3b1 100644
--- a/lldb/include/lldb/Utility/DataExtractor.h
+++ b/lldb/include/lldb/Utility/DataExtractor.h
@@ -334,7 +334,8 @@ class DataExtractor {
/// \return
/// A pointer to the bytes in this object's data if the offset
/// and length are valid, or nullptr otherwise.
- const void *GetData(lldb::offset_t *offset_ptr, lldb::offset_t length) const {
+ virtual const void *GetData(lldb::offset_t *offset_ptr,
+ lldb::offset_t length) const {
const uint8_t *ptr = PeekData(*offset_ptr, length);
if (ptr)
*offset_ptr += length;
@@ -829,7 +830,8 @@ class DataExtractor {
/// A non-nullptr data pointer if \a offset is a valid offset and
/// there are \a length bytes available at that offset, nullptr
/// otherwise.
- const uint8_t *PeekData(lldb::offset_t offset, lldb::offset_t length) const {
+ virtual const uint8_t *PeekData(lldb::offset_t offset,
+ lldb::offset_t length) const {
if (ValidOffsetForDataOfSize(offset, length))
return m_start + offset;
return nullptr;
diff --git a/lldb/include/lldb/Utility/VirtualDataExtractor.h b/lldb/include/lldb/Utility/VirtualDataExtractor.h
new file mode 100644
index 0000000000000..a940e58db7a12
--- /dev/null
+++ b/lldb/include/lldb/Utility/VirtualDataExtractor.h
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H
+#define LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H
+
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/RangeMap.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+/// A DataExtractor subclass that allows reading data at virtual addresses
+/// using a lookup table that maps virtual address ranges to physical offsets.
+///
+/// This class maintains a lookup table where each entry contains:
+/// - base: starting virtual address for this entry
+/// - size: size of this entry in bytes
+/// - data: physical offset in the underlying data buffer
+///
+/// Reads are translated from virtual addresses to physical offsets using
+/// this lookup table. Reads cannot cross entry boundaries and this is
+/// enforced with assertions.
+class VirtualDataExtractor : public DataExtractor {
+public:
+ /// Type alias for the range map used internally.
+ /// Maps virtual addresses (base) to physical offsets (data).
+ using LookupTable =
+ RangeDataVector<lldb::offset_t, lldb::offset_t, lldb::offset_t>;
+
+ VirtualDataExtractor() = default;
+
+ VirtualDataExtractor(const void *data, lldb::offset_t data_length,
+ lldb::ByteOrder byte_order, uint32_t addr_size,
+ LookupTable lookup_table);
+
+ VirtualDataExtractor(const lldb::DataBufferSP &data_sp,
+ lldb::ByteOrder byte_order, uint32_t addr_size,
+ LookupTable lookup_table);
+
+ const void *GetData(lldb::offset_t *offset_ptr,
+ lldb::offset_t length) const override;
+
+ const uint8_t *PeekData(lldb::offset_t offset,
+ lldb::offset_t length) const override;
+
+ const LookupTable &GetLookupTable() const { return m_lookup_table; }
+
+protected:
+ /// Find the lookup entry that contains the given virtual address.
+ const LookupTable::Entry *FindEntry(lldb::offset_t virtual_addr) const;
+
+ /// Validate that a read at a virtual address is within bounds and
+ /// does not cross entry boundaries.
+ bool ValidateVirtualRead(lldb::offset_t virtual_addr,
+ lldb::offset_t length) const;
+
+private:
+ LookupTable m_lookup_table;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_UTILITY_VIRTUALDATAEXTRACTOR_H
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index 1dd4d63f7016f..4696ed4690d37 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -78,6 +78,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
UserIDResolver.cpp
VASprintf.cpp
VMRange.cpp
+ VirtualDataExtractor.cpp
XcodeSDK.cpp
ZipFile.cpp
diff --git a/lldb/source/Utility/VirtualDataExtractor.cpp b/lldb/source/Utility/VirtualDataExtractor.cpp
new file mode 100644
index 0000000000000..f727cf1c8bc8a
--- /dev/null
+++ b/lldb/source/Utility/VirtualDataExtractor.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Utility/VirtualDataExtractor.h"
+#include <cassert>
+
+using namespace lldb;
+using namespace lldb_private;
+
+VirtualDataExtractor::VirtualDataExtractor(const void *data,
+ offset_t data_length,
+ ByteOrder byte_order,
+ uint32_t addr_size,
+ LookupTable lookup_table)
+ : DataExtractor(data, data_length, byte_order, addr_size),
+ m_lookup_table(std::move(lookup_table)) {
+ m_lookup_table.Sort();
+}
+
+VirtualDataExtractor::VirtualDataExtractor(const DataBufferSP &data_sp,
+ ByteOrder byte_order,
+ uint32_t addr_size,
+ LookupTable lookup_table)
+ : DataExtractor(data_sp, byte_order, addr_size),
+ m_lookup_table(std::move(lookup_table)) {
+ m_lookup_table.Sort();
+}
+
+const VirtualDataExtractor::LookupTable::Entry *
+VirtualDataExtractor::FindEntry(offset_t virtual_addr) const {
+ // Use RangeDataVector's binary search instead of linear search.
+ return m_lookup_table.FindEntryThatContains(virtual_addr);
+}
+
+bool VirtualDataExtractor::ValidateVirtualRead(offset_t virtual_addr,
+ offset_t length) const {
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ if (!entry)
+ return false;
+
+ // Assert that the read does not cross entry boundaries.
+ // RangeData.Contains() checks if a range is fully contained.
+ assert(entry->Contains(LookupTable::Range(virtual_addr, length)) &&
+ "Read crosses lookup table entry boundary");
+
+ // Also validate that the physical offset is within the data buffer.
+ // RangeData.data contains the physical offset.
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ return ValidOffsetForDataOfSize(physical_offset, length);
+}
+
+const void *VirtualDataExtractor::GetData(offset_t *offset_ptr,
+ offset_t length) const {
+ // Override to treat offset as virtual address.
+ if (!offset_ptr)
+ return nullptr;
+
+ offset_t virtual_addr = *offset_ptr;
+
+ if (!ValidateVirtualRead(virtual_addr, length))
+ return nullptr;
+
+ const LookupTable::Entry *entry = FindEntry(virtual_addr);
+ assert(entry && "ValidateVirtualRead should have found an entry");
+
+ offset_t physical_offset = entry->data + (virtual_addr - entry->base);
+ // Use base class PeekData directly to avoid recursion.
+ const void *result = DataExtractor::PeekData(physical_offset, length);
+
+ if (result) {
+ // Advance the virtual offset pointer.
+ *offset_ptr += length;
+ }
+
+ return result;
+}
+
+const uint8_t *VirtualDataExtractor::PeekData(offset_t offset,
+ offset_t length) const {
+ // Override to treat offset as virtual address.
+ if (!ValidateVirtualRead(offset, length))
+ return nullptr;
+
+ const LookupTable::Entry *entry = FindEntry(offset);
+ assert(entry && "ValidateVirtualRead should have found an entry");
+
+ offset_t physical_offset = entry->data + (offset - entry->base);
+ // Use the base class PeekData with the physical offset.
+ return DataExtractor::PeekData(physical_offset, length);
+}
diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt
index aed4177f5edee..77b52079cf32b 100644
--- a/lldb/unittests/Utility/CMakeLists.txt
+++ b/lldb/unittests/Utility/CMakeLists.txt
@@ -48,6 +48,7 @@ add_lldb_unittest(UtilityTests
UserIDResolverTest.cpp
UUIDTest.cpp
VASprintfTest.cpp
+ VirtualDataExtractorTest.cpp
VMRangeTest.cpp
XcodeSDKTest.cpp
diff --git a/lldb/unittests/Utility/VirtualDataExtractorTest.cpp b/lldb/unittests/Utility/VirtualDataExtractorTest.cpp
new file mode 100644
index 0000000000000..2a321884bab84
--- /dev/null
+++ b/lldb/unittests/Utility/VirtualDataExtractorTest.cpp
@@ -0,0 +1,285 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "lldb/Utility/VirtualDataExtractor.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+TEST(VirtualDataExtractorTest, BasicConstruction) {
+ // Create a simple data buffer.
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+
+ // Create a lookup table that maps virtual addresses to physical offsets.
+ VirtualDataExtractor::LookupTable lookup_table;
+ // Virtual address 0x1000-0x1008 maps to physical offset 0-8.
+ // Entry(base=virtual_offset, size, data=physical_offset).
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 8, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ EXPECT_EQ(extractor.GetByteSize(), 8U);
+}
+
+TEST(VirtualDataExtractorTest, GetDataAtVirtualOffset) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 8, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ const void *data = extractor.GetData(&virtual_offset, 4);
+
+ ASSERT_NE(data, nullptr);
+ EXPECT_EQ(virtual_offset, 0x1004U);
+ EXPECT_EQ(memcmp(data, buffer, 4), 0);
+}
+
+TEST(VirtualDataExtractorTest, GetDataAtVirtualOffsetInvalid) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ // Try to read from an invalid virtual address.
+ offset_t virtual_offset = 0x2000;
+ const void *data = extractor.GetData(&virtual_offset, 4);
+
+ EXPECT_EQ(data, nullptr);
+}
+
+TEST(VirtualDataExtractorTest, GetU8AtVirtualOffset) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0x12U);
+ EXPECT_EQ(virtual_offset, 0x1001U);
+
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0x34U);
+ EXPECT_EQ(virtual_offset, 0x1002U);
+}
+
+TEST(VirtualDataExtractorTest, GetU16AtVirtualOffset) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0x3412U);
+ EXPECT_EQ(virtual_offset, 0x1002U);
+
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0x7856U);
+ EXPECT_EQ(virtual_offset, 0x1004U);
+}
+
+TEST(VirtualDataExtractorTest, GetU32AtVirtualOffset) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 8, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU32(&virtual_offset), 0x78563412U);
+ EXPECT_EQ(virtual_offset, 0x1004U);
+
+ EXPECT_EQ(extractor.GetU32(&virtual_offset), 0xF0DEBC9AU);
+ EXPECT_EQ(virtual_offset, 0x1008U);
+}
+
+TEST(VirtualDataExtractorTest, GetU64AtVirtualOffset) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 8, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 8,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU64(&virtual_offset), 0xF0DEBC9A78563412ULL);
+ EXPECT_EQ(virtual_offset, 0x1008U);
+}
+
+TEST(VirtualDataExtractorTest, GetAddressAtVirtualOffset) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetAddress(&virtual_offset), 0x78563412U);
+ EXPECT_EQ(virtual_offset, 0x1004U);
+}
+
+TEST(VirtualDataExtractorTest, BigEndian) {
+ uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderBig, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0x1234U);
+ EXPECT_EQ(virtual_offset, 0x1002U);
+
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0x5678U);
+ EXPECT_EQ(virtual_offset, 0x1004U);
+}
+
+TEST(VirtualDataExtractorTest, MultipleEntries) {
+ // Create a buffer with distinct patterns for each section.
+ uint8_t buffer[] = {
+ 0x01, 0x02, 0x03, 0x04, // Physical offset 0-3.
+ 0x11, 0x12, 0x13, 0x14, // Physical offset 4-7.
+ 0x21, 0x22, 0x23, 0x24 // Physical offset 8-11.
+ };
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ // Map different virtual address ranges to different physical offsets.
+ // Entry(base=virtual_offset, size, data=physical_offset).
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ 0x1000, 4, 0)); // Virt 0x1000-0x1004 -> phys 0-4.
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ 0x2000, 4, 4)); // Virt 0x2000-0x2004 -> phys 4-8.
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ 0x3000, 4, 8)); // Virt 0x3000-0x3004 -> phys 8-12.
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ // Test reading from first virtual range.
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0x01U);
+
+ // Test reading from second virtual range.
+ virtual_offset = 0x2000;
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0x11U);
+
+ // Test reading from third virtual range.
+ virtual_offset = 0x3000;
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0x21U);
+}
+
+TEST(VirtualDataExtractorTest, NonContiguousVirtualAddresses) {
+ uint8_t buffer[] = {0xAA, 0xBB, 0xCC, 0xDD};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ // Create non-contiguous virtual address mapping.
+ // Entry(base=virtual_offset, size, data=physical_offset).
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ 0x1000, 2, 0)); // Virt 0x1000-0x1002 -> phys 0-2.
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(
+ 0x5000, 2, 2)); // Virt 0x5000-0x5002 -> phys 2-4.
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ // Test reading from first virtual range.
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0xBBAAU);
+
+ // Test reading from second virtual range (non-contiguous).
+ virtual_offset = 0x5000;
+ EXPECT_EQ(extractor.GetU16(&virtual_offset), 0xDDCCU);
+
+ // Test that gap between ranges is invalid.
+ virtual_offset = 0x3000;
+ EXPECT_EQ(extractor.GetU8(&virtual_offset), 0U);
+}
+
+TEST(VirtualDataExtractorTest, SharedDataBuffer) {
+ // Test with shared_ptr to DataBuffer.
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
+ auto data_sp = std::make_shared<DataBufferHeap>(buffer, sizeof(buffer));
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(data_sp, eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ EXPECT_EQ(extractor.GetU32(&virtual_offset), 0x04030201U);
+}
+
+TEST(VirtualDataExtractorTest, LookupTableAccess) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 2, 0));
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x2000, 2, 2));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ const auto &table = extractor.GetLookupTable();
+ EXPECT_EQ(table.GetSize(), 2U);
+ EXPECT_FALSE(table.IsEmpty());
+}
+
+TEST(VirtualDataExtractorTest, NullPointerHandling) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 0));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ // Test that passing nullptr returns default values.
+ EXPECT_EQ(extractor.GetU8(nullptr), 0U);
+ EXPECT_EQ(extractor.GetU16(nullptr), 0U);
+ EXPECT_EQ(extractor.GetU32(nullptr), 0U);
+ EXPECT_EQ(extractor.GetU64(nullptr), 0U);
+ EXPECT_EQ(extractor.GetAddress(nullptr), 0U);
+ EXPECT_EQ(extractor.GetData(nullptr, 4), nullptr);
+}
+
+TEST(VirtualDataExtractorTest, OffsetMapping) {
+ // Test that virtual to physical offset mapping works correctly.
+ uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD};
+
+ VirtualDataExtractor::LookupTable lookup_table;
+ // Map virtual address 0x1000 to physical offset 4 (skipping first 4 bytes).
+ // Entry(base=virtual_offset, size, data=physical_offset).
+ lookup_table.Append(VirtualDataExtractor::LookupTable::Entry(0x1000, 4, 4));
+
+ VirtualDataExtractor extractor(buffer, sizeof(buffer), eByteOrderLittle, 4,
+ std::move(lookup_table));
+
+ offset_t virtual_offset = 0x1000;
+ // Should read from physical offset 4, not 0.
+ EXPECT_EQ(extractor.GetU32(&virtual_offset), 0xDDCCBBAAU);
+}
More information about the lldb-commits
mailing list