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/Host/FileSystem.h"
11#include "lldb/Host/HostInfo.h"
12#include "lldb/Utility/DataBufferHeap.h"
13#include "lldb/Utility/DataExtractor.h"
14#include "lldb/Utility/Endian.h"
15#include "lldb/Utility/StreamString.h"
16#include "gtest/gtest.h"
17#include <complex>
18#include <limits>
19
20using namespace lldb;
21using namespace lldb_private;
22
23// This is needed for the tests because they rely on the Target global
24// properties.
25class DumpDataExtractorTest : public ::testing::Test {
26public:
27 void SetUp() override {
28 FileSystem::Initialize();
29 HostInfo::Initialize();
30 }
31 void TearDown() override {
32 HostInfo::Terminate();
33 FileSystem::Terminate();
34 }
35};
36
37static void TestDumpWithAddress(uint64_t base_addr, size_t item_count,
38 llvm::StringRef expected) {
39 std::vector<uint8_t> data{0x11, 0x22};
40 StreamString result;
41 DataBufferHeap dumpbuffer(&data[0], data.size());
42 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
43 endian::InlHostByteOrder(), /*addr_size=*/4);
44
45 DumpDataExtractor(DE: extractor, s: &result, offset: 0, item_format: lldb::Format::eFormatHex,
46 /*item_byte_size=*/1, item_count,
47 /*num_per_line=*/1, base_addr, item_bit_size: 0, item_bit_offset: 0);
48 ASSERT_EQ(expected, result.GetString());
49}
50
51TEST_F(DumpDataExtractorTest, BaseAddress) {
52 TestDumpWithAddress(base_addr: 0x12341234, item_count: 1, expected: "0x12341234: 0x11");
53 TestDumpWithAddress(LLDB_INVALID_ADDRESS, item_count: 1, expected: "0x11");
54 TestDumpWithAddress(base_addr: 0x12341234, item_count: 2, expected: "0x12341234: 0x11\n0x12341235: 0x22");
55 TestDumpWithAddress(LLDB_INVALID_ADDRESS, item_count: 2, expected: "0x11\n0x22");
56}
57
58static void TestDumpWithOffset(offset_t start_offset,
59 llvm::StringRef expected) {
60 std::vector<uint8_t> data{0x11, 0x22, 0x33};
61 StreamString result;
62 DataBufferHeap dumpbuffer(&data[0], data.size());
63 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
64 endian::InlHostByteOrder(), /*addr_size=*/4);
65
66 DumpDataExtractor(DE: extractor, s: &result, offset: start_offset, item_format: lldb::Format::eFormatHex,
67 /*item_byte_size=*/1, /*item_count=*/data.size(),
68 /*num_per_line=*/data.size(), /*base_addr=*/0, item_bit_size: 0, item_bit_offset: 0);
69 ASSERT_EQ(expected, result.GetString());
70}
71
72TEST_F(DumpDataExtractorTest, StartOffset) {
73 TestDumpWithOffset(start_offset: 0, expected: "0x00000000: 0x11 0x22 0x33");
74 // The offset applies to the DataExtractor, not the address used when
75 // formatting.
76 TestDumpWithOffset(start_offset: 1, expected: "0x00000000: 0x22 0x33");
77 // If the offset is outside the DataExtractor's range we do nothing.
78 TestDumpWithOffset(start_offset: 3, expected: "");
79}
80
81TEST_F(DumpDataExtractorTest, NullStream) {
82 // We don't do any work if there is no output stream.
83 uint8_t c = 0x11;
84 StreamString result;
85 DataBufferHeap dumpbuffer(&c, 0);
86 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
87 endian::InlHostByteOrder(), /*addr_size=*/4);
88
89 DumpDataExtractor(DE: extractor, s: nullptr, offset: 0, item_format: lldb::Format::eFormatHex,
90 /*item_byte_size=*/1, /*item_count=*/1,
91 /*num_per_line=*/1, /*base_addr=*/0, item_bit_size: 0, item_bit_offset: 0);
92 ASSERT_EQ("", result.GetString());
93}
94
95static void TestDumpImpl(const void *data, size_t data_size,
96 size_t item_byte_size, size_t item_count,
97 size_t num_per_line, uint64_t base_addr,
98 lldb::Format format, llvm::StringRef expected) {
99 StreamString result;
100 DataBufferHeap dumpbuffer(data, data_size);
101 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
102 endian::InlHostByteOrder(),
103 /*addr_size=*/4);
104 DumpDataExtractor(DE: extractor, s: &result, offset: 0, item_format: format, item_byte_size, item_count,
105 num_per_line, base_addr, item_bit_size: 0, item_bit_offset: 0);
106 ASSERT_EQ(expected, result.GetString());
107}
108
109template <typename T>
110static void TestDump(T data, lldb::Format format, llvm::StringRef expected) {
111 TestDumpImpl(&data, sizeof(T), sizeof(T), 1, 1, LLDB_INVALID_ADDRESS, format,
112 expected);
113}
114
115static void TestDump(llvm::StringRef str, lldb::Format format,
116 llvm::StringRef expected) {
117 TestDumpImpl(data: str.bytes_begin(),
118 // +1 to include the NULL char as the last byte
119 data_size: str.size() + 1, item_byte_size: str.size() + 1, item_count: 1, num_per_line: 1, LLDB_INVALID_ADDRESS,
120 format, expected);
121}
122
123template <typename T>
124static void TestDump(const std::vector<T> data, lldb::Format format,
125 llvm::StringRef expected) {
126 size_t sz_bytes = data.size() * sizeof(T);
127 TestDumpImpl(&data[0], sz_bytes, sz_bytes, data.size(), 1,
128 LLDB_INVALID_ADDRESS, format, expected);
129}
130
131TEST_F(DumpDataExtractorTest, Formats) {
132 TestDump<uint8_t>(data: 1, format: lldb::eFormatDefault, expected: "0x01");
133 TestDump<uint8_t>(data: 1, format: lldb::eFormatBoolean, expected: "true");
134 TestDump<uint8_t>(data: 0xAA, format: lldb::eFormatBinary, expected: "0b10101010");
135 TestDump<uint8_t>(data: 1, format: lldb::eFormatBytes, expected: "01");
136 TestDump<uint8_t>(data: 1, format: lldb::eFormatBytesWithASCII, expected: "01 .");
137 TestDump(data: '?', format: lldb::eFormatChar, expected: "'?'");
138 TestDump(data: '\x1A', format: lldb::eFormatCharPrintable, expected: ".");
139 TestDump(data: '#', format: lldb::eFormatCharPrintable, expected: "#");
140 TestDump(data: std::complex<float>(1.2f, 3.4f), format: lldb::eFormatComplex, expected: "1.2 + 3.4i");
141 TestDump(data: std::complex<double>(4.5, 6.7), format: lldb::eFormatComplex, expected: "4.5 + 6.7i");
142
143 // long double is not tested here because for some platforms we treat it as 10
144 // bytes when the compiler allocates 16 bytes of space for it. (see
145 // DataExtractor::GetLongDouble) Meaning that when we extract the second one,
146 // it gets the wrong value (it's 6 bytes off). You could manually construct a
147 // set of bytes to match the 10 byte format but then if the test runs on a
148 // machine where we don't use 10 it'll break.
149
150 // Test printable characters.
151 TestDump(str: llvm::StringRef("aardvark"), format: lldb::Format::eFormatCString,
152 expected: "\"aardvark\"");
153 // Test unprintable characters.
154 TestDump(str: llvm::StringRef("\xcf\xfa\xed\xfe\f"), format: lldb::Format::eFormatCString,
155 expected: "\"\\xcf\\xfa\\xed\\xfe\\f\"");
156 // Test a mix of printable and unprintable characters.
157 TestDump(str: llvm::StringRef("\xcf\xfa\ffoo"), format: lldb::Format::eFormatCString,
158 expected: "\"\\xcf\\xfa\\ffoo\"");
159
160 TestDump<uint16_t>(data: 99, format: lldb::Format::eFormatDecimal, expected: "99");
161 // Just prints as a signed integer.
162 TestDump(data: -1, format: lldb::Format::eFormatEnum, expected: "-1");
163 TestDump(data: 0xcafef00d, format: lldb::Format::eFormatHex, expected: "0xcafef00d");
164 TestDump(data: 0xcafef00d, format: lldb::Format::eFormatHexUppercase, expected: "0xCAFEF00D");
165 TestDump(data: 0.456, format: lldb::Format::eFormatFloat, expected: "0.45600000000000002");
166 TestDump(data: 9, format: lldb::Format::eFormatOctal, expected: "011");
167 // Chars packed into an integer.
168 TestDump<uint32_t>(data: 0x4C4C4442, format: lldb::Format::eFormatOSType, expected: "'LLDB'");
169 // Unicode8 doesn't have a specific formatter.
170 TestDump<uint8_t>(data: 0x34, format: lldb::Format::eFormatUnicode8, expected: "0x34");
171 TestDump<uint16_t>(data: 0x1122, format: lldb::Format::eFormatUnicode16, expected: "U+1122");
172 TestDump<uint32_t>(data: 0x12345678, format: lldb::Format::eFormatUnicode32,
173 expected: "U+0x12345678");
174 TestDump<unsigned int>(data: 654321, format: lldb::Format::eFormatUnsigned, expected: "654321");
175 // This pointer is printed based on the size of uint64_t, so the test is the
176 // same for 32/64 bit host.
177 TestDump<uint64_t>(data: 0x4444555566667777, format: lldb::Format::eFormatPointer,
178 expected: "0x4444555566667777");
179
180 TestDump(data: std::vector<char>{'A', '\x01', 'C'},
181 format: lldb::Format::eFormatVectorOfChar, expected: "{A\\x01C}");
182 TestDump(data: std::vector<int8_t>{0, -1, std::numeric_limits<int8_t>::max()},
183 format: lldb::Format::eFormatVectorOfSInt8, expected: "{0 -1 127}");
184 TestDump(data: std::vector<uint8_t>{12, 0xFF, 34},
185 format: lldb::Format::eFormatVectorOfUInt8, expected: "{0x0c 0xff 0x22}");
186 TestDump(data: std::vector<int16_t>{-1, 1234, std::numeric_limits<int16_t>::max()},
187 format: lldb::Format::eFormatVectorOfSInt16, expected: "{-1 1234 32767}");
188 TestDump(data: std::vector<uint16_t>{0xffff, 0xabcd, 0x1234},
189 format: lldb::Format::eFormatVectorOfUInt16, expected: "{0xffff 0xabcd 0x1234}");
190 TestDump(data: std::vector<int32_t>{0, -1, std::numeric_limits<int32_t>::max()},
191 format: lldb::Format::eFormatVectorOfSInt32, expected: "{0 -1 2147483647}");
192 TestDump(data: std::vector<uint32_t>{0, 0xffffffff, 0x1234abcd},
193 format: lldb::Format::eFormatVectorOfUInt32,
194 expected: "{0x00000000 0xffffffff 0x1234abcd}");
195 TestDump(data: std::vector<int64_t>{0, -1, std::numeric_limits<int64_t>::max()},
196 format: lldb::Format::eFormatVectorOfSInt64, expected: "{0 -1 9223372036854775807}");
197 TestDump(data: std::vector<uint64_t>{0, 0xaaaabbbbccccdddd},
198 format: lldb::Format::eFormatVectorOfUInt64,
199 expected: "{0x0000000000000000 0xaaaabbbbccccdddd}");
200
201 // See half2float for format details.
202 // Test zeroes.
203 TestDump(data: std::vector<uint16_t>{0x0000, 0x8000},
204 format: lldb::Format::eFormatVectorOfFloat16, expected: "{0 -0}");
205 // Some subnormal numbers.
206 TestDump(data: std::vector<uint16_t>{0x0001, 0x8001},
207 format: lldb::Format::eFormatVectorOfFloat16, expected: "{5.9605E-8 -5.9605E-8}");
208 // A full mantisse and empty expontent.
209 TestDump(data: std::vector<uint16_t>{0x83ff, 0x03ff},
210 format: lldb::Format::eFormatVectorOfFloat16, expected: "{-6.0976E-5 6.0976E-5}");
211 // Some normal numbers.
212 TestDump(data: std::vector<uint16_t>{0b0100001001001000},
213 format: lldb::Format::eFormatVectorOfFloat16, expected: "{3.1406}");
214 // Largest and smallest normal number.
215 TestDump(data: std::vector<uint16_t>{0x0400, 0x7bff},
216 format: lldb::Format::eFormatVectorOfFloat16, expected: "{6.1035E-5 65504}");
217 TestDump(data: std::vector<uint16_t>{0xabcd, 0x1234},
218 format: lldb::Format::eFormatVectorOfFloat16, expected: "{-0.060944 7.5722E-4}");
219
220 // quiet/signaling NaNs.
221 TestDump(data: std::vector<uint16_t>{0xffff, 0xffc0, 0x7fff, 0x7fc0},
222 format: lldb::Format::eFormatVectorOfFloat16, expected: "{NaN NaN NaN NaN}");
223 // +/-Inf.
224 TestDump(data: std::vector<uint16_t>{0xfc00, 0x7c00},
225 format: lldb::Format::eFormatVectorOfFloat16, expected: "{-Inf +Inf}");
226
227 TestDump(data: std::vector<float>{std::numeric_limits<float>::min(),
228 std::numeric_limits<float>::max()},
229 format: lldb::Format::eFormatVectorOfFloat32,
230 expected: "{1.17549435E-38 3.40282347E+38}");
231 TestDump(data: std::vector<float>{std::numeric_limits<float>::quiet_NaN(),
232 std::numeric_limits<float>::signaling_NaN(),
233 -std::numeric_limits<float>::quiet_NaN(),
234 -std::numeric_limits<float>::signaling_NaN()},
235 format: lldb::Format::eFormatVectorOfFloat32, expected: "{NaN NaN NaN NaN}");
236 TestDump(data: std::vector<double>{std::numeric_limits<double>::min(),
237 std::numeric_limits<double>::max()},
238 format: lldb::Format::eFormatVectorOfFloat64,
239 expected: "{2.2250738585072014E-308 1.7976931348623157E+308}");
240 TestDump(
241 data: std::vector<double>{
242 std::numeric_limits<double>::quiet_NaN(),
243 std::numeric_limits<double>::signaling_NaN(),
244 -std::numeric_limits<double>::quiet_NaN(),
245 -std::numeric_limits<double>::signaling_NaN(),
246 },
247 format: lldb::Format::eFormatVectorOfFloat64, expected: "{NaN NaN NaN NaN}");
248
249 // Not sure we can rely on having uint128_t everywhere so emulate with
250 // uint64_t.
251 TestDump(
252 data: std::vector<uint64_t>{0x1, 0x1111222233334444, 0xaaaabbbbccccdddd, 0x0},
253 format: lldb::Format::eFormatVectorOfUInt128,
254 expected: "{0x11112222333344440000000000000001 "
255 "0x0000000000000000aaaabbbbccccdddd}");
256
257 TestDump(data: std::vector<int>{2, 4}, format: lldb::Format::eFormatComplexInteger,
258 expected: "2 + 4i");
259
260 // Without an execution context this just prints the pointer on its own.
261 TestDump<uint32_t>(data: 0x11223344, format: lldb::Format::eFormatAddressInfo,
262 expected: "0x11223344");
263
264 // Input not written in hex form because that requires C++17.
265 TestDump<float>(data: 10, format: lldb::Format::eFormatHexFloat, expected: "0x1.4p3");
266 TestDump<double>(data: 10, format: lldb::Format::eFormatHexFloat, expected: "0x1.4p3");
267 // long double not supported, see ItemByteSizeErrors.
268
269 // Can't disassemble without an execution context.
270 TestDump<uint32_t>(data: 0xcafef00d, format: lldb::Format::eFormatInstruction,
271 expected: "invalid target");
272
273 // Has no special handling, intended for use elsewhere.
274 TestDump<int>(data: 99, format: lldb::Format::eFormatVoid, expected: "0x00000063");
275}
276
277TEST_F(DumpDataExtractorTest, FormatCharArray) {
278 // Unlike the other formats, charArray isn't 1 array of N chars.
279 // It must be passed as N chars of 1 byte each.
280 // (eFormatVectorOfChar does this swap for you)
281 std::vector<char> data{'A', '\x01', '#'};
282 StreamString result;
283 DataBufferHeap dumpbuffer(&data[0], data.size());
284 DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
285 endian::InlHostByteOrder(), /*addr_size=*/4);
286
287 DumpDataExtractor(DE: extractor, s: &result, offset: 0, item_format: lldb::Format::eFormatCharArray,
288 /*item_byte_size=*/1,
289 /*item_count=*/data.size(),
290 /*num_per_line=*/data.size(), base_addr: 0, item_bit_size: 0, item_bit_offset: 0);
291 ASSERT_EQ("0x00000000: A\\x01#", result.GetString());
292
293 result.Clear();
294 DumpDataExtractor(DE: extractor, s: &result, offset: 0, item_format: lldb::Format::eFormatCharArray, item_byte_size: 1,
295 item_count: data.size(), num_per_line: 1, base_addr: 0, item_bit_size: 0, item_bit_offset: 0);
296 // ASSERT macro thinks the split strings are multiple arguments so make a var.
297 const char *expected = "0x00000000: A\n"
298 "0x00000001: \\x01\n"
299 "0x00000002: #";
300 ASSERT_EQ(expected, result.GetString());
301}
302
303template <typename T>
304void TestDumpMultiLine(std::vector<T> data, lldb::Format format,
305 size_t num_per_line, llvm::StringRef expected) {
306 size_t sz_bytes = data.size() * sizeof(T);
307 TestDumpImpl(&data[0], sz_bytes, data.size(), sz_bytes, num_per_line,
308 0x80000000, format, expected);
309}
310
311template <typename T>
312void TestDumpMultiLine(const T *data, size_t num_items, lldb::Format format,
313 size_t num_per_line, llvm::StringRef expected) {
314 TestDumpImpl(data, sizeof(T) * num_items, sizeof(T), num_items, num_per_line,
315 0x80000000, format, expected);
316}
317
318TEST_F(DumpDataExtractorTest, MultiLine) {
319 // A vector counts as 1 item regardless of size.
320 TestDumpMultiLine(data: std::vector<uint8_t>{0x11},
321 format: lldb::Format::eFormatVectorOfUInt8, num_per_line: 1,
322 expected: "0x80000000: {0x11}");
323 TestDumpMultiLine(data: std::vector<uint8_t>{0x11, 0x22},
324 format: lldb::Format::eFormatVectorOfUInt8, num_per_line: 1,
325 expected: "0x80000000: {0x11 0x22}");
326
327 // If you have multiple vectors then that's multiple items.
328 // Here we say that these 2 bytes are actually 2 1 byte vectors.
329 const std::vector<uint8_t> vector_data{0x11, 0x22};
330 TestDumpMultiLine(data: vector_data.data(), num_items: 2, format: lldb::Format::eFormatVectorOfUInt8,
331 num_per_line: 1, expected: "0x80000000: {0x11}\n0x80000001: {0x22}");
332
333 // Single value formats can span multiple lines.
334 const std::vector<uint8_t> bytes{0x11, 0x22, 0x33};
335 const char *expected_bytes_3_line = "0x80000000: 0x11\n"
336 "0x80000001: 0x22\n"
337 "0x80000002: 0x33";
338 TestDumpMultiLine(data: bytes.data(), num_items: bytes.size(), format: lldb::Format::eFormatHex, num_per_line: 1,
339 expected: expected_bytes_3_line);
340
341 // Lines may not have the full number of items.
342 TestDumpMultiLine(data: bytes.data(), num_items: bytes.size(), format: lldb::Format::eFormatHex, num_per_line: 4,
343 expected: "0x80000000: 0x11 0x22 0x33");
344 const char *expected_bytes_2_line = "0x80000000: 0x11 0x22\n"
345 "0x80000002: 0x33";
346 TestDumpMultiLine(data: bytes.data(), num_items: bytes.size(), format: lldb::Format::eFormatHex, num_per_line: 2,
347 expected: expected_bytes_2_line);
348
349 // The line address accounts for item sizes other than 1 byte.
350 const std::vector<uint16_t> shorts{0x1111, 0x2222, 0x3333};
351 const char *expected_shorts_2_line = "0x80000000: 0x1111 0x2222\n"
352 "0x80000004: 0x3333";
353 TestDumpMultiLine(data: shorts.data(), num_items: shorts.size(), format: lldb::Format::eFormatHex, num_per_line: 2,
354 expected: expected_shorts_2_line);
355
356 // The ascii column is positioned using the maximum line length.
357 const std::vector<char> chars{'L', 'L', 'D', 'B'};
358 const char *expected_chars_2_lines = "0x80000000: 4c 4c 44 LLD\n"
359 "0x80000003: 42 B";
360 TestDumpMultiLine(data: chars.data(), num_items: chars.size(),
361 format: lldb::Format::eFormatBytesWithASCII, num_per_line: 3,
362 expected: expected_chars_2_lines);
363}
364
365void TestDumpWithItemByteSize(size_t item_byte_size, lldb::Format format,
366 llvm::StringRef expected) {
367 // We won't be reading this data so anything will do.
368 uint8_t dummy = 0;
369 TestDumpImpl(data: &dummy, data_size: 1, item_byte_size, item_count: 1, num_per_line: 1, LLDB_INVALID_ADDRESS, format,
370 expected);
371}
372
373TEST_F(DumpDataExtractorTest, ItemByteSizeErrors) {
374 TestDumpWithItemByteSize(
375 item_byte_size: 16, format: lldb::Format::eFormatBoolean,
376 expected: "error: unsupported byte size (16) for boolean format");
377 TestDumpWithItemByteSize(item_byte_size: 21, format: lldb::Format::eFormatChar,
378 expected: "error: unsupported byte size (21) for char format");
379 TestDumpWithItemByteSize(
380 item_byte_size: 18, format: lldb::Format::eFormatComplexInteger,
381 expected: "error: unsupported byte size (18) for complex integer format");
382
383 // The code uses sizeof(long double) for these checks. This changes by host
384 // but we know it won't be >16.
385 TestDumpWithItemByteSize(
386 item_byte_size: 34, format: lldb::Format::eFormatComplex,
387 expected: "error: unsupported byte size (34) for complex float format");
388 TestDumpWithItemByteSize(
389 item_byte_size: 18, format: lldb::Format::eFormatFloat,
390 expected: "error: unsupported byte size (18) for float format");
391
392 // We want sizes to exactly match one of float/double.
393 TestDumpWithItemByteSize(
394 item_byte_size: 14, format: lldb::Format::eFormatComplex,
395 expected: "error: unsupported byte size (14) for complex float format");
396 TestDumpWithItemByteSize(item_byte_size: 3, format: lldb::Format::eFormatFloat,
397 expected: "error: unsupported byte size (3) for float format");
398
399 // We only allow float and double size.
400 TestDumpWithItemByteSize(
401 item_byte_size: 1, format: lldb::Format::eFormatHexFloat,
402 expected: "error: unsupported byte size (1) for hex float format");
403 TestDumpWithItemByteSize(
404 item_byte_size: 17, format: lldb::Format::eFormatHexFloat,
405 expected: "error: unsupported byte size (17) for hex float format");
406}
407

source code of lldb/unittests/Core/DumpDataExtractorTest.cpp