1 //===-- DataDumpExtractorTest.cpp -----------------------------------------===// 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/Core/DumpDataExtractor.h" 10 #include "lldb/Utility/DataBufferHeap.h" 11 #include "lldb/Utility/DataExtractor.h" 12 #include "lldb/Utility/Endian.h" 13 #include "lldb/Utility/StreamString.h" 14 #include "gtest/gtest.h" 15 #include <complex> 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 static void testDumpWithAddress(uint64_t base_addr, size_t item_count, 21 llvm::StringRef expected) { 22 std::vector<uint8_t> data{0x11, 0x22}; 23 StreamString result; 24 DataBufferHeap dumpbuffer(&data[0], data.size()); 25 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), 26 endian::InlHostByteOrder(), /*addr_size=*/4); 27 28 DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatHex, 29 /*item_byte_size=*/1, item_count, 30 /*num_per_line=*/1, base_addr, 0, 0); 31 ASSERT_EQ(expected, result.GetString()); 32 } 33 34 TEST(DumpDataExtractorTest, BaseAddress) { 35 testDumpWithAddress(0x12341234, 1, "0x12341234: 0x11"); 36 testDumpWithAddress(LLDB_INVALID_ADDRESS, 1, "0x11"); 37 testDumpWithAddress(0x12341234, 2, "0x12341234: 0x11\n0x12341235: 0x22"); 38 testDumpWithAddress(LLDB_INVALID_ADDRESS, 2, "0x11\n0x22"); 39 } 40 41 static void testDumpWithOffset(offset_t start_offset, 42 llvm::StringRef expected) { 43 std::vector<uint8_t> data{0x11, 0x22, 0x33}; 44 StreamString result; 45 DataBufferHeap dumpbuffer(&data[0], data.size()); 46 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), 47 endian::InlHostByteOrder(), /*addr_size=*/4); 48 49 DumpDataExtractor(extractor, &result, start_offset, lldb::Format::eFormatHex, 50 /*item_byte_size=*/1, /*item_count=*/data.size(), 51 /*num_per_line=*/data.size(), /*base_addr=*/0, 0, 0); 52 ASSERT_EQ(expected, result.GetString()); 53 } 54 55 TEST(DumpDataExtractorTest, StartOffset) { 56 testDumpWithOffset(0, "0x00000000: 0x11 0x22 0x33"); 57 // The offset applies to the DataExtractor, not the address used when 58 // formatting. 59 testDumpWithOffset(1, "0x00000000: 0x22 0x33"); 60 // If the offset is outside the DataExtractor's range we do nothing. 61 testDumpWithOffset(3, ""); 62 } 63 64 TEST(DumpDataExtractorTest, NullStream) { 65 // We don't do any work if there is no output stream. 66 uint8_t c = 0x11; 67 StreamString result; 68 DataBufferHeap dumpbuffer(&c, 0); 69 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), 70 endian::InlHostByteOrder(), /*addr_size=*/4); 71 72 DumpDataExtractor(extractor, nullptr, 0, lldb::Format::eFormatHex, 73 /*item_byte_size=*/1, /*item_count=*/1, 74 /*num_per_line=*/1, /*base_addr=*/0, 0, 0); 75 ASSERT_EQ("", result.GetString()); 76 } 77 78 static void TestDumpImpl(const void *data, size_t data_size, 79 size_t item_byte_size, size_t item_count, 80 size_t num_per_line, uint64_t base_addr, 81 lldb::Format format, llvm::StringRef expected) { 82 StreamString result; 83 DataBufferHeap dumpbuffer(data, data_size); 84 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), 85 endian::InlHostByteOrder(), 86 /*addr_size=*/4); 87 DumpDataExtractor(extractor, &result, 0, format, item_byte_size, item_count, 88 num_per_line, base_addr, 0, 0); 89 ASSERT_EQ(expected, result.GetString()); 90 } 91 92 template <typename T> 93 static void TestDump(T data, lldb::Format format, llvm::StringRef expected) { 94 TestDumpImpl(&data, sizeof(T), sizeof(T), 1, 1, LLDB_INVALID_ADDRESS, format, 95 expected); 96 } 97 98 static void TestDump(llvm::StringRef str, lldb::Format format, 99 llvm::StringRef expected) { 100 TestDumpImpl(str.bytes_begin(), 101 // +1 to include the NULL char as the last byte 102 str.size() + 1, str.size() + 1, 1, 1, LLDB_INVALID_ADDRESS, 103 format, expected); 104 } 105 106 template <typename T> 107 static void TestDump(const std::vector<T> data, lldb::Format format, 108 llvm::StringRef expected) { 109 size_t sz_bytes = data.size() * sizeof(T); 110 TestDumpImpl(&data[0], sz_bytes, sz_bytes, data.size(), 1, 111 LLDB_INVALID_ADDRESS, format, expected); 112 } 113 114 TEST(DumpDataExtractorTest, Formats) { 115 TestDump<uint8_t>(1, lldb::eFormatDefault, "0x01"); 116 TestDump<uint8_t>(1, lldb::eFormatBoolean, "true"); 117 TestDump<uint8_t>(0xAA, lldb::eFormatBinary, "0b10101010"); 118 TestDump<uint8_t>(1, lldb::eFormatBytes, "01"); 119 TestDump<uint8_t>(1, lldb::eFormatBytesWithASCII, "01 ."); 120 TestDump('?', lldb::eFormatChar, "'?'"); 121 TestDump('\x1A', lldb::eFormatCharPrintable, "."); 122 TestDump('#', lldb::eFormatCharPrintable, "#"); 123 TestDump(std::complex<float>(1.2, 3.4), lldb::eFormatComplex, "1.2 + 3.4i"); 124 TestDump(std::complex<double>(4.5, 6.7), lldb::eFormatComplex, "4.5 + 6.7i"); 125 126 // long double is not tested here because for some platforms we treat it as 10 127 // bytes when the compiler allocates 16 bytes of space for it. (see 128 // DataExtractor::GetLongDouble) Meaning that when we extract the second one, 129 // it gets the wrong value (it's 6 bytes off). You could manually construct a 130 // set of bytes to match the 10 byte format but then if the test runs on a 131 // machine where we don't use 10 it'll break. 132 133 TestDump(llvm::StringRef("aardvark"), lldb::Format::eFormatCString, 134 "\"aardvark\""); 135 TestDump<uint16_t>(99, lldb::Format::eFormatDecimal, "99"); 136 // Just prints as a signed integer. 137 TestDump(-1, lldb::Format::eFormatEnum, "-1"); 138 TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d"); 139 TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D"); 140 TestDump(0.456, lldb::Format::eFormatFloat, "0.456"); 141 TestDump(9, lldb::Format::eFormatOctal, "011"); 142 // Chars packed into an integer. 143 TestDump<uint32_t>(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'"); 144 // Unicode8 doesn't have a specific formatter. 145 TestDump<uint8_t>(0x34, lldb::Format::eFormatUnicode8, "0x34"); 146 TestDump<uint16_t>(0x1122, lldb::Format::eFormatUnicode16, "U+1122"); 147 TestDump<uint32_t>(0x12345678, lldb::Format::eFormatUnicode32, 148 "U+0x12345678"); 149 TestDump<unsigned int>(654321, lldb::Format::eFormatUnsigned, "654321"); 150 // This pointer is printed based on the size of uint64_t, so the test is the 151 // same for 32/64 bit host. 152 TestDump<uint64_t>(0x4444555566667777, lldb::Format::eFormatPointer, 153 "0x4444555566667777"); 154 155 TestDump(std::vector<char>{'A', '\x01', 'C'}, 156 lldb::Format::eFormatVectorOfChar, "{A\\x01C}"); 157 TestDump(std::vector<int8_t>{0, -1, std::numeric_limits<int8_t>::max()}, 158 lldb::Format::eFormatVectorOfSInt8, "{0 -1 127}"); 159 TestDump(std::vector<uint8_t>{12, 0xFF, 34}, 160 lldb::Format::eFormatVectorOfUInt8, "{0x0c 0xff 0x22}"); 161 TestDump(std::vector<int16_t>{-1, 1234, std::numeric_limits<int16_t>::max()}, 162 lldb::Format::eFormatVectorOfSInt16, "{-1 1234 32767}"); 163 TestDump(std::vector<uint16_t>{0xffff, 0xabcd, 0x1234}, 164 lldb::Format::eFormatVectorOfUInt16, "{0xffff 0xabcd 0x1234}"); 165 TestDump(std::vector<int32_t>{0, -1, std::numeric_limits<int32_t>::max()}, 166 lldb::Format::eFormatVectorOfSInt32, "{0 -1 2147483647}"); 167 TestDump(std::vector<uint32_t>{0, 0xffffffff, 0x1234abcd}, 168 lldb::Format::eFormatVectorOfUInt32, 169 "{0x00000000 0xffffffff 0x1234abcd}"); 170 TestDump(std::vector<int64_t>{0, -1, std::numeric_limits<int64_t>::max()}, 171 lldb::Format::eFormatVectorOfSInt64, "{0 -1 9223372036854775807}"); 172 TestDump(std::vector<uint64_t>{0, 0xaaaabbbbccccdddd}, 173 lldb::Format::eFormatVectorOfUInt64, 174 "{0x0000000000000000 0xaaaabbbbccccdddd}"); 175 176 // See half2float for format details. 177 TestDump(std::vector<uint16_t>{0xabcd, 0x1234}, 178 lldb::Format::eFormatVectorOfFloat16, "{-0.0609436 0.000757217}"); 179 TestDump(std::vector<float>{std::numeric_limits<float>::min(), 180 std::numeric_limits<float>::max()}, 181 lldb::Format::eFormatVectorOfFloat32, "{1.17549e-38 3.40282e+38}"); 182 TestDump(std::vector<double>{std::numeric_limits<double>::min(), 183 std::numeric_limits<double>::max()}, 184 lldb::Format::eFormatVectorOfFloat64, 185 "{2.2250738585072e-308 1.79769313486232e+308}"); 186 187 // Not sure we can rely on having uint128_t everywhere so emulate with 188 // uint64_t. 189 TestDump( 190 std::vector<uint64_t>{0x1, 0x1111222233334444, 0xaaaabbbbccccdddd, 0x0}, 191 lldb::Format::eFormatVectorOfUInt128, 192 "{0x11112222333344440000000000000001 " 193 "0x0000000000000000aaaabbbbccccdddd}"); 194 195 TestDump(std::vector<int>{2, 4}, lldb::Format::eFormatComplexInteger, 196 "2 + 4i"); 197 198 // Without an execution context this just prints the pointer on its own. 199 TestDump<uint32_t>(0x11223344, lldb::Format::eFormatAddressInfo, 200 "0x11223344"); 201 202 // Input not written in hex form because that requires C++17. 203 TestDump<float>(10, lldb::Format::eFormatHexFloat, "0x1.4p3"); 204 TestDump<double>(10, lldb::Format::eFormatHexFloat, "0x1.4p3"); 205 // Long double we don't support and format an error saying so. 206 // However sizeof(long double) is 8/12/16 depending on the host so not tested 207 // here. 208 209 // Can't disassemble without an execution context. 210 TestDump<uint32_t>(0xcafef00d, lldb::Format::eFormatInstruction, 211 "invalid target"); 212 213 // Has no special handling, intended for use elsewhere. 214 TestDump<int>(99, lldb::Format::eFormatVoid, "0x00000063"); 215 } 216 217 TEST(DumpDataExtractorTest, FormatCharArray) { 218 // Unlike the other formats, charArray isn't 1 array of N chars. 219 // It must be passed as N chars of 1 byte each. 220 // (eFormatVectorOfChar does this swap for you) 221 std::vector<char> data{'A', '\x01', '#'}; 222 StreamString result; 223 DataBufferHeap dumpbuffer(&data[0], data.size()); 224 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), 225 endian::InlHostByteOrder(), /*addr_size=*/4); 226 227 DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, 228 /*item_byte_size=*/1, 229 /*item_count=*/data.size(), 230 /*num_per_line=*/data.size(), 0, 0, 0); 231 ASSERT_EQ("0x00000000: A\\x01#", result.GetString()); 232 233 result.Clear(); 234 DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, 1, 235 data.size(), 1, 0, 0, 0); 236 // ASSERT macro thinks the split strings are multiple arguments so make a var. 237 const char *expected = "0x00000000: A\n" 238 "0x00000001: \\x01\n" 239 "0x00000002: #"; 240 ASSERT_EQ(expected, result.GetString()); 241 } 242 243 template <typename T> 244 void testDumpMultiLine(std::vector<T> data, lldb::Format format, 245 size_t num_per_line, llvm::StringRef expected) { 246 size_t sz_bytes = data.size() * sizeof(T); 247 TestDumpImpl(&data[0], sz_bytes, data.size(), sz_bytes, num_per_line, 248 0x80000000, format, expected); 249 } 250 251 template <typename T> 252 void testDumpMultiLine(const T *data, size_t num_items, lldb::Format format, 253 size_t num_per_line, llvm::StringRef expected) { 254 TestDumpImpl(data, sizeof(T) * num_items, sizeof(T), num_items, num_per_line, 255 0x80000000, format, expected); 256 } 257 258 TEST(DumpDataExtractorTest, MultiLine) { 259 // A vector counts as 1 item regardless of size. 260 testDumpMultiLine(std::vector<uint8_t>{0x11}, 261 lldb::Format::eFormatVectorOfUInt8, 1, 262 "0x80000000: {0x11}"); 263 testDumpMultiLine(std::vector<uint8_t>{0x11, 0x22}, 264 lldb::Format::eFormatVectorOfUInt8, 1, 265 "0x80000000: {0x11 0x22}"); 266 267 // If you have multiple vectors then that's multiple items. 268 // Here we say that these 2 bytes are actually 2 1 byte vectors. 269 const std::vector<uint8_t> vector_data{0x11, 0x22}; 270 testDumpMultiLine(vector_data.data(), 2, lldb::Format::eFormatVectorOfUInt8, 271 1, "0x80000000: {0x11}\n0x80000001: {0x22}"); 272 273 // Single value formats can span multiple lines. 274 const std::vector<uint8_t> bytes{0x11, 0x22, 0x33}; 275 const char *expected_bytes_3_line = "0x80000000: 0x11\n" 276 "0x80000001: 0x22\n" 277 "0x80000002: 0x33"; 278 testDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 1, 279 expected_bytes_3_line); 280 281 // Lines may not have the full number of items. 282 testDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 4, 283 "0x80000000: 0x11 0x22 0x33"); 284 const char *expected_bytes_2_line = "0x80000000: 0x11 0x22\n" 285 "0x80000002: 0x33"; 286 testDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 2, 287 expected_bytes_2_line); 288 289 // The line address accounts for item sizes other than 1 byte. 290 const std::vector<uint16_t> shorts{0x1111, 0x2222, 0x3333}; 291 const char *expected_shorts_2_line = "0x80000000: 0x1111 0x2222\n" 292 "0x80000004: 0x3333"; 293 testDumpMultiLine(shorts.data(), shorts.size(), lldb::Format::eFormatHex, 2, 294 expected_shorts_2_line); 295 296 // The ascii column is positioned using the maximum line length. 297 const std::vector<char> chars{'L', 'L', 'D', 'B'}; 298 const char *expected_chars_2_lines = "0x80000000: 4c 4c 44 LLD\n" 299 "0x80000003: 42 B"; 300 testDumpMultiLine(chars.data(), chars.size(), 301 lldb::Format::eFormatBytesWithASCII, 3, 302 expected_chars_2_lines); 303 } 304