584 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/VirtualDataExtractor.h"10#include "lldb/Utility/DataBufferHeap.h"11#include "gtest/gtest.h"12 13using namespace lldb_private;14using namespace lldb;15 16using Table = VirtualDataExtractor::LookupTable;17using Entry = Table::Entry;18 19TEST(VirtualDataExtractorTest, BasicConstruction) {20 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};21 22 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(23 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});24 25 EXPECT_EQ(extractor->GetByteSize(), 8U);26}27 28TEST(VirtualDataExtractorTest, GetDataAtVirtualOffset) {29 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};30 31 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(32 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});33 34 offset_t virtual_offset = 0x1000;35 const void *data = extractor->GetData(&virtual_offset, 4);36 37 ASSERT_NE(data, nullptr);38 EXPECT_EQ(virtual_offset, 0x1004U);39 EXPECT_EQ(memcmp(data, buffer, 4), 0);40}41 42TEST(VirtualDataExtractorTest, GetDataAtVirtualOffsetInvalid) {43 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};44 45 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(46 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});47 48 // Try to read from an invalid virtual address.49 offset_t virtual_offset = 0x2000;50 const void *data = extractor->GetData(&virtual_offset, 4);51 52 EXPECT_EQ(data, nullptr);53}54 55TEST(VirtualDataExtractorTest, GetU8AtVirtualOffset) {56 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};57 58 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(59 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});60 61 offset_t virtual_offset = 0x1000;62 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x12U);63 EXPECT_EQ(virtual_offset, 0x1001U);64 65 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x34U);66 EXPECT_EQ(virtual_offset, 0x1002U);67}68 69TEST(VirtualDataExtractorTest, GetU16AtVirtualOffset) {70 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};71 72 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(73 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});74 75 offset_t virtual_offset = 0x1000;76 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0x3412U);77 EXPECT_EQ(virtual_offset, 0x1002U);78 79 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0x7856U);80 EXPECT_EQ(virtual_offset, 0x1004U);81}82 83TEST(VirtualDataExtractorTest, GetU32AtVirtualOffset) {84 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};85 86 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(87 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});88 89 offset_t virtual_offset = 0x1000;90 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0x78563412U);91 EXPECT_EQ(virtual_offset, 0x1004U);92 93 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0xF0DEBC9AU);94 EXPECT_EQ(virtual_offset, 0x1008U);95}96 97TEST(VirtualDataExtractorTest, GetU64AtVirtualOffset) {98 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};99 100 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(101 buffer, sizeof(buffer), eByteOrderLittle, 8, Table{Entry(0x1000, 8, 0)});102 103 offset_t virtual_offset = 0x1000;104 EXPECT_EQ(extractor->GetU64(&virtual_offset), 0xF0DEBC9A78563412ULL);105 EXPECT_EQ(virtual_offset, 0x1008U);106}107 108TEST(VirtualDataExtractorTest, GetAddressAtVirtualOffset) {109 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};110 111 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(112 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});113 114 offset_t virtual_offset = 0x1000;115 EXPECT_EQ(extractor->GetAddress(&virtual_offset), 0x78563412U);116 EXPECT_EQ(virtual_offset, 0x1004U);117}118 119TEST(VirtualDataExtractorTest, BigEndian) {120 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};121 122 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(123 buffer, sizeof(buffer), eByteOrderBig, 4, Table{Entry(0x1000, 4, 0)});124 125 offset_t virtual_offset = 0x1000;126 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0x1234U);127 EXPECT_EQ(virtual_offset, 0x1002U);128 129 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0x5678U);130 EXPECT_EQ(virtual_offset, 0x1004U);131}132 133TEST(VirtualDataExtractorTest, MultipleEntries) {134 // Create a buffer with distinct patterns for each section.135 uint8_t buffer[] = {136 0x01, 0x02, 0x03, 0x04, // Physical offset 0-3.137 0x11, 0x12, 0x13, 0x14, // Physical offset 4-7.138 0x21, 0x22, 0x23, 0x24 // Physical offset 8-11.139 };140 141 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(142 buffer, sizeof(buffer), eByteOrderLittle, 4,143 Table{Entry(0x1000, 4, 0), // Virt 0x1000-0x1004144 Entry(0x2000, 4, 4), // Virt 0x2000-0x2004145 Entry(0x3000, 4, 8)}); // Virt 0x3000-0x3004146 147 // Test reading from first virtual range.148 offset_t virtual_offset = 0x1000;149 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x01U);150 151 // Test reading from second virtual range.152 virtual_offset = 0x2000;153 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x11U);154 155 // Test reading from third virtual range.156 virtual_offset = 0x3000;157 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x21U);158}159 160TEST(VirtualDataExtractorTest, NonContiguousVirtualAddresses) {161 uint8_t buffer[] = {0xAA, 0xBB, 0xCC, 0xDD};162 163 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(164 buffer, sizeof(buffer), eByteOrderLittle, 4,165 Table{Entry(0x1000, 2, 0), // Virt 0x1000-0x1002166 Entry(0x5000, 2, 2)}); // Virt 0x5000-0x5002167 168 // Test reading from first virtual range.169 offset_t virtual_offset = 0x1000;170 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0xBBAAU);171 172 // Test reading from second virtual range (non-contiguous).173 virtual_offset = 0x5000;174 EXPECT_EQ(extractor->GetU16(&virtual_offset), 0xDDCCU);175 176 // Test that gap between ranges is invalid.177 virtual_offset = 0x3000;178 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0U);179}180 181TEST(VirtualDataExtractorTest, SharedDataBuffer) {182 // Test with shared_ptr to DataBuffer.183 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};184 auto data_sp = std::make_shared<DataBufferHeap>(buffer, sizeof(buffer));185 186 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(187 data_sp, eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});188 189 offset_t virtual_offset = 0x1000;190 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0x04030201U);191}192 193TEST(VirtualDataExtractorTest, NullPointerHandling) {194 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};195 196 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(197 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});198 199 // Test that passing nullptr returns default values.200 EXPECT_EQ(extractor->GetU8(nullptr), 0U);201 EXPECT_EQ(extractor->GetU16(nullptr), 0U);202 EXPECT_EQ(extractor->GetU32(nullptr), 0U);203 EXPECT_EQ(extractor->GetU64(nullptr), 0U);204 EXPECT_EQ(extractor->GetAddress(nullptr), 0U);205 EXPECT_EQ(extractor->GetData(nullptr, 4), nullptr);206}207 208TEST(VirtualDataExtractorTest, OffsetMapping) {209 // Test that virtual to physical offset mapping works correctly.210 uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDD};211 212 // Map virtual address 0x1000 to physical offset 4 (skipping first 4 bytes).213 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(214 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 4)});215 216 offset_t virtual_offset = 0x1000;217 // Should read from physical offset 4, not 0.218 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0xDDCCBBAAU);219}220 221TEST(VirtualDataExtractorTest, GetU8Unchecked) {222 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};223 224 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(225 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});226 227 offset_t virtual_offset = 0x1000;228 EXPECT_EQ(extractor->GetU8_unchecked(&virtual_offset), 0x12U);229 EXPECT_EQ(virtual_offset, 0x1001U);230 231 EXPECT_EQ(extractor->GetU8_unchecked(&virtual_offset), 0x34U);232 EXPECT_EQ(virtual_offset, 0x1002U);233}234 235TEST(VirtualDataExtractorTest, GetU16Unchecked) {236 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};237 238 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(239 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});240 241 offset_t virtual_offset = 0x1000;242 EXPECT_EQ(extractor->GetU16_unchecked(&virtual_offset), 0x3412U);243 EXPECT_EQ(virtual_offset, 0x1002U);244 245 EXPECT_EQ(extractor->GetU16_unchecked(&virtual_offset), 0x7856U);246 EXPECT_EQ(virtual_offset, 0x1004U);247}248 249TEST(VirtualDataExtractorTest, GetU32Unchecked) {250 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};251 252 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(253 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});254 255 offset_t virtual_offset = 0x1000;256 EXPECT_EQ(extractor->GetU32_unchecked(&virtual_offset), 0x78563412U);257 EXPECT_EQ(virtual_offset, 0x1004U);258 259 EXPECT_EQ(extractor->GetU32_unchecked(&virtual_offset), 0xF0DEBC9AU);260 EXPECT_EQ(virtual_offset, 0x1008U);261}262 263TEST(VirtualDataExtractorTest, GetU64Unchecked) {264 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};265 266 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(267 buffer, sizeof(buffer), eByteOrderLittle, 8, Table{Entry(0x1000, 8, 0)});268 269 offset_t virtual_offset = 0x1000;270 EXPECT_EQ(extractor->GetU64_unchecked(&virtual_offset),271 0xF0DEBC9A78563412ULL);272 EXPECT_EQ(virtual_offset, 0x1008U);273}274 275TEST(VirtualDataExtractorTest, GetMaxU64Unchecked) {276 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};277 278 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(279 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});280 281 // Test various byte sizes.282 offset_t virtual_offset = 0x1000;283 EXPECT_EQ(extractor->GetMaxU64_unchecked(&virtual_offset, 1), 0x12U);284 EXPECT_EQ(virtual_offset, 0x1001U);285 286 virtual_offset = 0x1000;287 EXPECT_EQ(extractor->GetMaxU64_unchecked(&virtual_offset, 2), 0x3412U);288 EXPECT_EQ(virtual_offset, 0x1002U);289 290 virtual_offset = 0x1000;291 EXPECT_EQ(extractor->GetMaxU64_unchecked(&virtual_offset, 4), 0x78563412U);292 EXPECT_EQ(virtual_offset, 0x1004U);293 294 virtual_offset = 0x1000;295 EXPECT_EQ(extractor->GetMaxU64_unchecked(&virtual_offset, 8),296 0xF0DEBC9A78563412ULL);297 EXPECT_EQ(virtual_offset, 0x1008U);298}299 300TEST(VirtualDataExtractorTest, GetAddressUnchecked) {301 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};302 303 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(304 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});305 306 offset_t virtual_offset = 0x1000;307 EXPECT_EQ(extractor->GetAddress_unchecked(&virtual_offset), 0x78563412U);308 EXPECT_EQ(virtual_offset, 0x1004U);309}310 311TEST(VirtualDataExtractorTest, UncheckedWithBigEndian) {312 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78};313 314 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(315 buffer, sizeof(buffer), eByteOrderBig, 4, Table{Entry(0x1000, 4, 0)});316 317 offset_t virtual_offset = 0x1000;318 EXPECT_EQ(extractor->GetU16_unchecked(&virtual_offset), 0x1234U);319 EXPECT_EQ(virtual_offset, 0x1002U);320 321 EXPECT_EQ(extractor->GetU16_unchecked(&virtual_offset), 0x5678U);322 EXPECT_EQ(virtual_offset, 0x1004U);323}324 325TEST(VirtualDataExtractorTest, GetCStr) {326 // Create buffer with null-terminated strings.327 uint8_t buffer[] = {'H', 'e', 'l', 'l', 'o', '\0', 'W', 'o',328 'r', 'l', 'd', '\0', 'F', 'o', 'o', '\0'};329 330 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(331 buffer, sizeof(buffer), eByteOrderLittle, 4,332 Table{Entry(0x1000, 6, 0), Entry(0x2000, 12, 6)});333 334 // Test reading first string.335 offset_t virtual_offset = 0x1000;336 const char *str1 = extractor->GetCStr(&virtual_offset);337 ASSERT_NE(str1, nullptr);338 EXPECT_STREQ(str1, "Hello");339 EXPECT_EQ(virtual_offset, 0x1006U); // After "Hello\0"340 341 // Test reading second string.342 virtual_offset = 0x2000;343 const char *str2 = extractor->GetCStr(&virtual_offset);344 ASSERT_NE(str2, nullptr);345 EXPECT_STREQ(str2, "World");346 EXPECT_EQ(virtual_offset, 0x2006U); // After "World\0"347}348 349TEST(VirtualDataExtractorTest, GetFloat) {350 // Create buffer with float value (IEEE 754 single precision).351 // 3.14159f in little endian: 0xDB 0x0F 0x49 0x40352 uint8_t buffer[] = {0xDB, 0x0F, 0x49, 0x40};353 354 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(355 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});356 357 offset_t virtual_offset = 0x1000;358 float value = extractor->GetFloat(&virtual_offset);359 EXPECT_NEAR(value, 3.14159f, 0.00001f);360 EXPECT_EQ(virtual_offset, 0x1004U);361}362 363TEST(VirtualDataExtractorTest, GetDouble) {364 // Create buffer with double value (IEEE 754 double precision).365 // 3.14159265358979 in little endian366 uint8_t buffer[] = {0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40};367 368 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(369 buffer, sizeof(buffer), eByteOrderLittle, 8, Table{Entry(0x1000, 8, 0)});370 371 offset_t virtual_offset = 0x1000;372 double value = extractor->GetDouble(&virtual_offset);373 EXPECT_NEAR(value, 3.14159265358979, 0.00000000000001);374 EXPECT_EQ(virtual_offset, 0x1008U);375}376 377TEST(VirtualDataExtractorTest, GetULEB128) {378 // ULEB128 encoding: 0x624 (1572 decimal) = 0xA4 0x0C379 uint8_t buffer[] = {0xA4, 0x0C, 0xFF, 0x00, 0x7F, 0x80, 0x01};380 381 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(382 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 7, 0)});383 384 // Test reading first ULEB128 value (1572).385 offset_t virtual_offset = 0x1000;386 EXPECT_EQ(extractor->GetULEB128(&virtual_offset), 1572U);387 EXPECT_EQ(virtual_offset, 0x1002U);388 389 // Test reading second ULEB128 value (127).390 virtual_offset = 0x1004;391 EXPECT_EQ(extractor->GetULEB128(&virtual_offset), 127U);392 EXPECT_EQ(virtual_offset, 0x1005U);393 394 // Test reading third ULEB128 value (128).395 EXPECT_EQ(extractor->GetULEB128(&virtual_offset), 128U);396 EXPECT_EQ(virtual_offset, 0x1007U);397}398 399TEST(VirtualDataExtractorTest, GetSLEB128) {400 // SLEB128 encoding: -123 = 0x85 0x7F, 123 = 0xFB 0x00401 uint8_t buffer[] = {0x85, 0x7F, 0xFB, 0x00};402 403 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(404 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});405 406 // Test reading negative SLEB128 value (-123).407 offset_t virtual_offset = 0x1000;408 EXPECT_EQ(extractor->GetSLEB128(&virtual_offset), -123);409 EXPECT_EQ(virtual_offset, 0x1002U);410 411 // Test reading positive SLEB128 value (123).412 EXPECT_EQ(extractor->GetSLEB128(&virtual_offset), 123);413 EXPECT_EQ(virtual_offset, 0x1004U);414}415 416TEST(VirtualDataExtractorTest, GetU8Array) {417 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};418 419 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(420 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});421 422 // Test reading array of 4 bytes.423 offset_t virtual_offset = 0x1000;424 uint8_t dst[4] = {0};425 void *result = extractor->GetU8(&virtual_offset, dst, 4);426 ASSERT_NE(result, nullptr);427 EXPECT_EQ(dst[0], 0x01U);428 EXPECT_EQ(dst[1], 0x02U);429 EXPECT_EQ(dst[2], 0x03U);430 EXPECT_EQ(dst[3], 0x04U);431 EXPECT_EQ(virtual_offset, 0x1004U);432}433 434TEST(VirtualDataExtractorTest, GetU16Array) {435 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};436 437 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(438 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});439 440 // Test reading array of 3 uint16_t values.441 offset_t virtual_offset = 0x1000;442 uint16_t dst[3] = {0};443 void *result = extractor->GetU16(&virtual_offset, dst, 3);444 ASSERT_NE(result, nullptr);445 EXPECT_EQ(dst[0], 0x3412U);446 EXPECT_EQ(dst[1], 0x7856U);447 EXPECT_EQ(dst[2], 0xBC9AU);448 EXPECT_EQ(virtual_offset, 0x1006U);449}450 451TEST(VirtualDataExtractorTest, GetU32Array) {452 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};453 454 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(455 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});456 457 // Test reading array of 2 uint32_t values.458 offset_t virtual_offset = 0x1000;459 uint32_t dst[2] = {0};460 void *result = extractor->GetU32(&virtual_offset, dst, 2);461 ASSERT_NE(result, nullptr);462 EXPECT_EQ(dst[0], 0x78563412U);463 EXPECT_EQ(dst[1], 0xF0DEBC9AU);464 EXPECT_EQ(virtual_offset, 0x1008U);465}466 467TEST(VirtualDataExtractorTest, GetU64Array) {468 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,469 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};470 471 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(472 buffer, sizeof(buffer), eByteOrderLittle, 8, Table{Entry(0x1000, 16, 0)});473 474 // Test reading array of 2 uint64_t values.475 offset_t virtual_offset = 0x1000;476 uint64_t dst[2] = {0};477 void *result = extractor->GetU64(&virtual_offset, dst, 2);478 ASSERT_NE(result, nullptr);479 EXPECT_EQ(dst[0], 0x0807060504030201ULL);480 EXPECT_EQ(dst[1], 0x1817161514131211ULL);481 EXPECT_EQ(virtual_offset, 0x1010U);482}483 484TEST(VirtualDataExtractorTest, GetMaxU64WithVariableSizes) {485 uint8_t buffer[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};486 487 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(488 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 8, 0)});489 490 // Test reading 3-byte value.491 offset_t virtual_offset = 0x1000;492 EXPECT_EQ(extractor->GetMaxU64(&virtual_offset, 3), 0x563412U);493 EXPECT_EQ(virtual_offset, 0x1003U);494 495 // Test reading 5-byte value.496 virtual_offset = 0x1000;497 EXPECT_EQ(extractor->GetMaxU64(&virtual_offset, 5), 0x9A78563412ULL);498 EXPECT_EQ(virtual_offset, 0x1005U);499}500 501TEST(VirtualDataExtractorTest, GetMaxS64) {502 // Test with negative number (sign extension).503 uint8_t buffer[] = {0xFF, 0xFF, 0xFF, 0xFF};504 505 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(506 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});507 508 // Test reading 1-byte signed value (-1).509 offset_t virtual_offset = 0x1000;510 EXPECT_EQ(extractor->GetMaxS64(&virtual_offset, 1), -1);511 EXPECT_EQ(virtual_offset, 0x1001U);512 513 // Test reading 2-byte signed value (-1).514 virtual_offset = 0x1000;515 EXPECT_EQ(extractor->GetMaxS64(&virtual_offset, 2), -1);516 EXPECT_EQ(virtual_offset, 0x1002U);517}518 519TEST(VirtualDataExtractorTest, CannotReadAcrossEntryBoundaries) {520 // Create buffer with two separate regions.521 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x11, 0x12, 0x13, 0x14};522 523 // First entry: virtual 0x1000-0x1004 maps to physical 0-4.524 // Second entry: virtual 0x2000-0x2004 maps to physical 4-8.525 // Note: there's a gap in virtual addresses (0x1004-0x2000).526 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(527 buffer, sizeof(buffer), eByteOrderLittle, 4,528 Table{Entry(0x1000, 4, 0), Entry(0x2000, 4, 4)});529 530 // Verify we can read within the first entry.531 offset_t virtual_offset = 0x1000;532 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0x04030201U);533 EXPECT_EQ(virtual_offset, 0x1004U);534 535 // Verify we can read within the second entry.536 virtual_offset = 0x2000;537 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0x14131211U);538 EXPECT_EQ(virtual_offset, 0x2004U);539 540 // Verify we CANNOT read in the gap between entries.541 // This address is not in any lookup table entry.542 virtual_offset = 0x1500;543 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0U);544 EXPECT_EQ(virtual_offset, 0x1500U);545 546 // Verify we CANNOT read data pointer from the gap.547 virtual_offset = 0x1800;548 const void *data = extractor->GetData(&virtual_offset, 1);549 EXPECT_EQ(data, nullptr);550 EXPECT_EQ(virtual_offset, 0x1800U); // Offset unchanged.551 552 // Verify we can read individual bytes within each entry.553 virtual_offset = 0x1003;554 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x04U);555 EXPECT_EQ(virtual_offset, 0x1004U);556 557 // Verify we CANNOT read past the end of an entry.558 virtual_offset = 0x1004;559 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0U);560 EXPECT_EQ(virtual_offset, 0x1004U);561}562 563TEST(VirtualDataExtractorTest, ReadExactlyAtEntryEnd) {564 uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04};565 566 lldb::DataExtractorSP extractor = std::make_shared<VirtualDataExtractor>(567 buffer, sizeof(buffer), eByteOrderLittle, 4, Table{Entry(0x1000, 4, 0)});568 569 // Reading exactly to the end of an entry should work.570 offset_t virtual_offset = 0x1000;571 EXPECT_EQ(extractor->GetU32(&virtual_offset), 0x04030201U);572 EXPECT_EQ(virtual_offset, 0x1004U);573 574 // But reading one byte past the end should fail.575 virtual_offset = 0x1004;576 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0U);577 EXPECT_EQ(virtual_offset, 0x1004U);578 579 // Reading from just before the end should work for smaller sizes.580 virtual_offset = 0x1003;581 EXPECT_EQ(extractor->GetU8(&virtual_offset), 0x04U);582 EXPECT_EQ(virtual_offset, 0x1004U);583}584