xref: /llvm-project/lldb/unittests/Core/DumpDataExtractorTest.cpp (revision 30a5ddaef3e88912e10a6b1c8173b00819c722d3)
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 not supported, see ItemByteSizeErrors.
206 
207   // Can't disassemble without an execution context.
208   TestDump<uint32_t>(0xcafef00d, lldb::Format::eFormatInstruction,
209                      "invalid target");
210 
211   // Has no special handling, intended for use elsewhere.
212   TestDump<int>(99, lldb::Format::eFormatVoid, "0x00000063");
213 }
214 
215 TEST(DumpDataExtractorTest, FormatCharArray) {
216   // Unlike the other formats, charArray isn't 1 array of N chars.
217   // It must be passed as N chars of 1 byte each.
218   // (eFormatVectorOfChar does this swap for you)
219   std::vector<char> data{'A', '\x01', '#'};
220   StreamString result;
221   DataBufferHeap dumpbuffer(&data[0], data.size());
222   DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
223                           endian::InlHostByteOrder(), /*addr_size=*/4);
224 
225   DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray,
226                     /*item_byte_size=*/1,
227                     /*item_count=*/data.size(),
228                     /*num_per_line=*/data.size(), 0, 0, 0);
229   ASSERT_EQ("0x00000000: A\\x01#", result.GetString());
230 
231   result.Clear();
232   DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, 1,
233                     data.size(), 1, 0, 0, 0);
234   // ASSERT macro thinks the split strings are multiple arguments so make a var.
235   const char *expected = "0x00000000: A\n"
236                          "0x00000001: \\x01\n"
237                          "0x00000002: #";
238   ASSERT_EQ(expected, result.GetString());
239 }
240 
241 template <typename T>
242 void TestDumpMultiLine(std::vector<T> data, lldb::Format format,
243                        size_t num_per_line, llvm::StringRef expected) {
244   size_t sz_bytes = data.size() * sizeof(T);
245   TestDumpImpl(&data[0], sz_bytes, data.size(), sz_bytes, num_per_line,
246                0x80000000, format, expected);
247 }
248 
249 template <typename T>
250 void TestDumpMultiLine(const T *data, size_t num_items, lldb::Format format,
251                        size_t num_per_line, llvm::StringRef expected) {
252   TestDumpImpl(data, sizeof(T) * num_items, sizeof(T), num_items, num_per_line,
253                0x80000000, format, expected);
254 }
255 
256 TEST(DumpDataExtractorTest, MultiLine) {
257   // A vector counts as 1 item regardless of size.
258   TestDumpMultiLine(std::vector<uint8_t>{0x11},
259                     lldb::Format::eFormatVectorOfUInt8, 1,
260                     "0x80000000: {0x11}");
261   TestDumpMultiLine(std::vector<uint8_t>{0x11, 0x22},
262                     lldb::Format::eFormatVectorOfUInt8, 1,
263                     "0x80000000: {0x11 0x22}");
264 
265   // If you have multiple vectors then that's multiple items.
266   // Here we say that these 2 bytes are actually 2 1 byte vectors.
267   const std::vector<uint8_t> vector_data{0x11, 0x22};
268   TestDumpMultiLine(vector_data.data(), 2, lldb::Format::eFormatVectorOfUInt8,
269                     1, "0x80000000: {0x11}\n0x80000001: {0x22}");
270 
271   // Single value formats can span multiple lines.
272   const std::vector<uint8_t> bytes{0x11, 0x22, 0x33};
273   const char *expected_bytes_3_line = "0x80000000: 0x11\n"
274                                       "0x80000001: 0x22\n"
275                                       "0x80000002: 0x33";
276   TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 1,
277                     expected_bytes_3_line);
278 
279   // Lines may not have the full number of items.
280   TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 4,
281                     "0x80000000: 0x11 0x22 0x33");
282   const char *expected_bytes_2_line = "0x80000000: 0x11 0x22\n"
283                                       "0x80000002: 0x33";
284   TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 2,
285                     expected_bytes_2_line);
286 
287   // The line address accounts for item sizes other than 1 byte.
288   const std::vector<uint16_t> shorts{0x1111, 0x2222, 0x3333};
289   const char *expected_shorts_2_line = "0x80000000: 0x1111 0x2222\n"
290                                        "0x80000004: 0x3333";
291   TestDumpMultiLine(shorts.data(), shorts.size(), lldb::Format::eFormatHex, 2,
292                     expected_shorts_2_line);
293 
294   // The ascii column is positioned using the maximum line length.
295   const std::vector<char> chars{'L', 'L', 'D', 'B'};
296   const char *expected_chars_2_lines = "0x80000000: 4c 4c 44  LLD\n"
297                                        "0x80000003: 42        B";
298   TestDumpMultiLine(chars.data(), chars.size(),
299                     lldb::Format::eFormatBytesWithASCII, 3,
300                     expected_chars_2_lines);
301 }
302 
303 void TestDumpWithItemByteSize(size_t item_byte_size, lldb::Format format,
304                               llvm::StringRef expected) {
305   // We won't be reading this data so anything will do.
306   uint8_t dummy = 0;
307   TestDumpImpl(&dummy, 1, item_byte_size, 1, 1, LLDB_INVALID_ADDRESS, format,
308                expected);
309 }
310 
311 TEST(DumpDataExtractorTest, ItemByteSizeErrors) {
312   TestDumpWithItemByteSize(
313       16, lldb::Format::eFormatBoolean,
314       "error: unsupported byte size (16) for boolean format");
315   TestDumpWithItemByteSize(21, lldb::Format::eFormatChar,
316                            "error: unsupported byte size (21) for char format");
317   TestDumpWithItemByteSize(
318       18, lldb::Format::eFormatComplexInteger,
319       "error: unsupported byte size (18) for complex integer format");
320 
321   // The code uses sizeof(long double) for these checks. This changes by host
322   // but we know it won't be >16.
323   TestDumpWithItemByteSize(
324       34, lldb::Format::eFormatComplex,
325       "error: unsupported byte size (34) for complex float format");
326   TestDumpWithItemByteSize(
327       18, lldb::Format::eFormatFloat,
328       "error: unsupported byte size (18) for float format");
329 
330   // We want sizes to exactly match one of float/double.
331   TestDumpWithItemByteSize(
332       14, lldb::Format::eFormatComplex,
333       "error: unsupported byte size (14) for complex float format");
334   TestDumpWithItemByteSize(3, lldb::Format::eFormatFloat,
335                            "error: unsupported byte size (3) for float format");
336 
337   // We only allow float and double size.
338   TestDumpWithItemByteSize(
339       1, lldb::Format::eFormatHexFloat,
340       "error: unsupported byte size (1) for hex float format");
341   TestDumpWithItemByteSize(
342       17, lldb::Format::eFormatHexFloat,
343       "error: unsupported byte size (17) for hex float format");
344 }
345