/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/DumpDataExtractor.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- DumpDataExtractor.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 | | |
11 | | #include "lldb/lldb-defines.h" |
12 | | #include "lldb/lldb-forward.h" |
13 | | |
14 | | #include "lldb/Core/Address.h" |
15 | | #include "lldb/Core/Disassembler.h" |
16 | | #include "lldb/Core/ModuleList.h" |
17 | | #include "lldb/Target/ABI.h" |
18 | | #include "lldb/Target/ExecutionContext.h" |
19 | | #include "lldb/Target/ExecutionContextScope.h" |
20 | | #include "lldb/Target/MemoryRegionInfo.h" |
21 | | #include "lldb/Target/MemoryTagManager.h" |
22 | | #include "lldb/Target/MemoryTagMap.h" |
23 | | #include "lldb/Target/Process.h" |
24 | | #include "lldb/Target/SectionLoadList.h" |
25 | | #include "lldb/Target/Target.h" |
26 | | #include "lldb/Utility/DataExtractor.h" |
27 | | #include "lldb/Utility/Log.h" |
28 | | #include "lldb/Utility/Stream.h" |
29 | | |
30 | | #include "llvm/ADT/APFloat.h" |
31 | | #include "llvm/ADT/APInt.h" |
32 | | #include "llvm/ADT/ArrayRef.h" |
33 | | #include "llvm/ADT/SmallVector.h" |
34 | | |
35 | | #include <limits> |
36 | | #include <memory> |
37 | | #include <string> |
38 | | |
39 | | #include <cassert> |
40 | | #include <cctype> |
41 | | #include <cinttypes> |
42 | | #include <cmath> |
43 | | |
44 | | #include <bitset> |
45 | | #include <optional> |
46 | | #include <sstream> |
47 | | |
48 | | using namespace lldb_private; |
49 | | using namespace lldb; |
50 | | |
51 | 523 | #define NON_PRINTABLE_CHAR '.' |
52 | | |
53 | | static std::optional<llvm::APInt> GetAPInt(const DataExtractor &data, |
54 | | lldb::offset_t *offset_ptr, |
55 | 1.92k | lldb::offset_t byte_size) { |
56 | 1.92k | if (byte_size == 0) |
57 | 4 | return std::nullopt; |
58 | | |
59 | 1.92k | llvm::SmallVector<uint64_t, 2> uint64_array; |
60 | 1.92k | lldb::offset_t bytes_left = byte_size; |
61 | 1.92k | uint64_t u64; |
62 | 1.92k | const lldb::ByteOrder byte_order = data.GetByteOrder(); |
63 | 1.92k | if (byte_order == lldb::eByteOrderLittle) { |
64 | 3.86k | while (bytes_left > 0) { |
65 | 1.94k | if (bytes_left >= 8) { |
66 | 921 | u64 = data.GetU64(offset_ptr); |
67 | 921 | bytes_left -= 8; |
68 | 1.02k | } else { |
69 | 1.02k | u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left); |
70 | 1.02k | bytes_left = 0; |
71 | 1.02k | } |
72 | 1.94k | uint64_array.push_back(u64); |
73 | 1.94k | } |
74 | 1.92k | return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array)); |
75 | 1.92k | } else if (0 byte_order == lldb::eByteOrderBig0 ) { |
76 | 0 | lldb::offset_t be_offset = *offset_ptr + byte_size; |
77 | 0 | lldb::offset_t temp_offset; |
78 | 0 | while (bytes_left > 0) { |
79 | 0 | if (bytes_left >= 8) { |
80 | 0 | be_offset -= 8; |
81 | 0 | temp_offset = be_offset; |
82 | 0 | u64 = data.GetU64(&temp_offset); |
83 | 0 | bytes_left -= 8; |
84 | 0 | } else { |
85 | 0 | be_offset -= bytes_left; |
86 | 0 | temp_offset = be_offset; |
87 | 0 | u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left); |
88 | 0 | bytes_left = 0; |
89 | 0 | } |
90 | 0 | uint64_array.push_back(u64); |
91 | 0 | } |
92 | 0 | *offset_ptr += byte_size; |
93 | 0 | return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array)); |
94 | 0 | } |
95 | 0 | return std::nullopt; |
96 | 1.92k | } |
97 | | |
98 | | static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data, |
99 | | lldb::offset_t offset, lldb::offset_t byte_size, |
100 | 12 | bool is_signed, unsigned radix) { |
101 | 12 | std::optional<llvm::APInt> apint = GetAPInt(data, &offset, byte_size); |
102 | 12 | if (apint) { |
103 | 12 | std::string apint_str = toString(*apint, radix, is_signed); |
104 | 12 | switch (radix) { |
105 | 1 | case 2: |
106 | 1 | s->Write("0b", 2); |
107 | 1 | break; |
108 | 1 | case 8: |
109 | 1 | s->Write("0", 1); |
110 | 1 | break; |
111 | 10 | case 10: |
112 | 10 | break; |
113 | 12 | } |
114 | 12 | s->Write(apint_str.c_str(), apint_str.size()); |
115 | 12 | } |
116 | 12 | return offset; |
117 | 12 | } |
118 | | |
119 | | /// Dumps decoded instructions to a stream. |
120 | | static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s, |
121 | | ExecutionContextScope *exe_scope, |
122 | | offset_t start_offset, |
123 | | uint64_t base_addr, |
124 | 2 | size_t number_of_instructions) { |
125 | 2 | offset_t offset = start_offset; |
126 | | |
127 | 2 | TargetSP target_sp; |
128 | 2 | if (exe_scope) |
129 | 1 | target_sp = exe_scope->CalculateTarget(); |
130 | 2 | if (target_sp) { |
131 | 1 | DisassemblerSP disassembler_sp( |
132 | 1 | Disassembler::FindPlugin(target_sp->GetArchitecture(), |
133 | 1 | target_sp->GetDisassemblyFlavor(), nullptr)); |
134 | 1 | if (disassembler_sp) { |
135 | 1 | lldb::addr_t addr = base_addr + start_offset; |
136 | 1 | lldb_private::Address so_addr; |
137 | 1 | bool data_from_file = true; |
138 | 1 | if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) { |
139 | 0 | data_from_file = false; |
140 | 1 | } else { |
141 | 1 | if (target_sp->GetSectionLoadList().IsEmpty() || |
142 | 1 | !target_sp->GetImages().ResolveFileAddress(addr, so_addr)0 ) |
143 | 1 | so_addr.SetRawAddress(addr); |
144 | 1 | } |
145 | | |
146 | 1 | size_t bytes_consumed = disassembler_sp->DecodeInstructions( |
147 | 1 | so_addr, DE, start_offset, number_of_instructions, false, |
148 | 1 | data_from_file); |
149 | | |
150 | 1 | if (bytes_consumed) { |
151 | 1 | offset += bytes_consumed; |
152 | 1 | const bool show_address = base_addr != LLDB_INVALID_ADDRESS; |
153 | 1 | const bool show_bytes = true; |
154 | 1 | const bool show_control_flow_kind = true; |
155 | 1 | ExecutionContext exe_ctx; |
156 | 1 | exe_scope->CalculateExecutionContext(exe_ctx); |
157 | 1 | disassembler_sp->GetInstructionList().Dump( |
158 | 1 | s, show_address, show_bytes, show_control_flow_kind, &exe_ctx); |
159 | 1 | } |
160 | 1 | } |
161 | 1 | } else |
162 | 1 | s->Printf("invalid target"); |
163 | | |
164 | 2 | return offset; |
165 | 2 | } |
166 | | |
167 | | /// Prints the specific escape sequence of the given character to the stream. |
168 | | /// If the character doesn't have a known specific escape sequence (e.g., '\a', |
169 | | /// '\n' but not generic escape sequences such as'\x12'), this function will |
170 | | /// not modify the stream and return false. |
171 | 907 | static bool TryDumpSpecialEscapedChar(Stream &s, const char c) { |
172 | 907 | switch (c) { |
173 | 4 | case '\033': |
174 | | // Common non-standard escape code for 'escape'. |
175 | 4 | s.Printf("\\e"); |
176 | 4 | return true; |
177 | 20 | case '\a': |
178 | 20 | s.Printf("\\a"); |
179 | 20 | return true; |
180 | 4 | case '\b': |
181 | 4 | s.Printf("\\b"); |
182 | 4 | return true; |
183 | 8 | case '\f': |
184 | 8 | s.Printf("\\f"); |
185 | 8 | return true; |
186 | 468 | case '\n': |
187 | 468 | s.Printf("\\n"); |
188 | 468 | return true; |
189 | 7 | case '\r': |
190 | 7 | s.Printf("\\r"); |
191 | 7 | return true; |
192 | 50 | case '\t': |
193 | 50 | s.Printf("\\t"); |
194 | 50 | return true; |
195 | 7 | case '\v': |
196 | 7 | s.Printf("\\v"); |
197 | 7 | return true; |
198 | 171 | case '\0': |
199 | 171 | s.Printf("\\0"); |
200 | 171 | return true; |
201 | 168 | default: |
202 | 168 | return false; |
203 | 907 | } |
204 | 907 | } |
205 | | |
206 | | /// Dump the character to a stream. A character that is not printable will be |
207 | | /// represented by its escape sequence. |
208 | 100 | static void DumpCharacter(Stream &s, const char c) { |
209 | 100 | if (TryDumpSpecialEscapedChar(s, c)) |
210 | 19 | return; |
211 | 81 | if (llvm::isPrint(c)) { |
212 | 75 | s.PutChar(c); |
213 | 75 | return; |
214 | 75 | } |
215 | 6 | s.Printf("\\x%2.2hhx", c); |
216 | 6 | } |
217 | | |
218 | | /// Dump a floating point type. |
219 | | template <typename FloatT> |
220 | | void DumpFloatingPoint(std::ostringstream &ss, FloatT f) { |
221 | | static_assert(std::is_floating_point<FloatT>::value, |
222 | | "Only floating point types can be dumped."); |
223 | | // NaN and Inf are potentially implementation defined and on Darwin it |
224 | | // seems NaNs are printed without their sign. Manually implement dumping them |
225 | | // here to avoid having to deal with platform differences. |
226 | | if (std::isnan(f)) { |
227 | | if (std::signbit(f)) |
228 | | ss << '-'; |
229 | | ss << "nan"; |
230 | | return; |
231 | | } |
232 | | if (std::isinf(f)) { |
233 | | if (std::signbit(f)) |
234 | | ss << '-'; |
235 | | ss << "inf"; |
236 | | return; |
237 | | } |
238 | | ss << f; |
239 | | } |
240 | | |
241 | | static std::optional<MemoryTagMap> |
242 | | GetMemoryTags(lldb::addr_t addr, size_t length, |
243 | 0 | ExecutionContextScope *exe_scope) { |
244 | 0 | assert(addr != LLDB_INVALID_ADDRESS); |
245 | | |
246 | 0 | if (!exe_scope) |
247 | 0 | return std::nullopt; |
248 | | |
249 | 0 | TargetSP target_sp = exe_scope->CalculateTarget(); |
250 | 0 | if (!target_sp) |
251 | 0 | return std::nullopt; |
252 | | |
253 | 0 | ProcessSP process_sp = target_sp->CalculateProcess(); |
254 | 0 | if (!process_sp) |
255 | 0 | return std::nullopt; |
256 | | |
257 | 0 | llvm::Expected<const MemoryTagManager *> tag_manager_or_err = |
258 | 0 | process_sp->GetMemoryTagManager(); |
259 | 0 | if (!tag_manager_or_err) { |
260 | 0 | llvm::consumeError(tag_manager_or_err.takeError()); |
261 | 0 | return std::nullopt; |
262 | 0 | } |
263 | | |
264 | 0 | MemoryRegionInfos memory_regions; |
265 | | // Don't check return status, list will be just empty if an error happened. |
266 | 0 | process_sp->GetMemoryRegions(memory_regions); |
267 | |
|
268 | 0 | llvm::Expected<std::vector<MemoryTagManager::TagRange>> tagged_ranges_or_err = |
269 | 0 | (*tag_manager_or_err) |
270 | 0 | ->MakeTaggedRanges(addr, addr + length, memory_regions); |
271 | | // Here we know that our range will not be inverted but we must still check |
272 | | // for an error. |
273 | 0 | if (!tagged_ranges_or_err) { |
274 | 0 | llvm::consumeError(tagged_ranges_or_err.takeError()); |
275 | 0 | return std::nullopt; |
276 | 0 | } |
277 | 0 | if (tagged_ranges_or_err->empty()) |
278 | 0 | return std::nullopt; |
279 | | |
280 | 0 | MemoryTagMap memory_tag_map(*tag_manager_or_err); |
281 | 0 | for (const MemoryTagManager::TagRange &range : *tagged_ranges_or_err) { |
282 | 0 | llvm::Expected<std::vector<lldb::addr_t>> tags_or_err = |
283 | 0 | process_sp->ReadMemoryTags(range.GetRangeBase(), range.GetByteSize()); |
284 | |
|
285 | 0 | if (tags_or_err) |
286 | 0 | memory_tag_map.InsertTags(range.GetRangeBase(), *tags_or_err); |
287 | 0 | else |
288 | 0 | llvm::consumeError(tags_or_err.takeError()); |
289 | 0 | } |
290 | |
|
291 | 0 | if (memory_tag_map.Empty()) |
292 | 0 | return std::nullopt; |
293 | | |
294 | 0 | return memory_tag_map; |
295 | 0 | } |
296 | | |
297 | | static void printMemoryTags(const DataExtractor &DE, Stream *s, |
298 | | lldb::addr_t addr, size_t len, |
299 | 0 | const std::optional<MemoryTagMap> &memory_tag_map) { |
300 | 0 | std::vector<std::optional<lldb::addr_t>> tags = |
301 | 0 | memory_tag_map->GetTags(addr, len); |
302 | | |
303 | | // Only print if there is at least one tag for this line |
304 | 0 | if (tags.empty()) |
305 | 0 | return; |
306 | | |
307 | 0 | s->Printf(" (tag%s:", tags.size() > 1 ? "s" : ""); |
308 | | // Some granules may not be tagged but print something for them |
309 | | // so that the ordering remains intact. |
310 | 0 | for (auto tag : tags) { |
311 | 0 | if (tag) |
312 | 0 | s->Printf(" 0x%" PRIx64, *tag); |
313 | 0 | else |
314 | 0 | s->PutCString(" <no tag>"); |
315 | 0 | } |
316 | 0 | s->PutCString(")"); |
317 | 0 | } |
318 | | |
319 | | static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp, |
320 | 1.91k | size_t byte_size) { |
321 | 1.91k | if (target_sp) { |
322 | 1.84k | auto type_system_or_err = |
323 | 1.84k | target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); |
324 | 1.84k | if (!type_system_or_err) |
325 | 0 | llvm::consumeError(type_system_or_err.takeError()); |
326 | 1.84k | else if (auto ts = *type_system_or_err) |
327 | 1.84k | return ts->GetFloatTypeSemantics(byte_size); |
328 | 1.84k | } |
329 | | // No target, just make a reasonable guess |
330 | 70 | switch(byte_size) { |
331 | 19 | case 2: |
332 | 19 | return llvm::APFloat::IEEEhalf(); |
333 | 40 | case 4: |
334 | 40 | return llvm::APFloat::IEEEsingle(); |
335 | 9 | case 8: |
336 | 9 | return llvm::APFloat::IEEEdouble(); |
337 | 70 | } |
338 | 2 | return llvm::APFloat::Bogus(); |
339 | 70 | } |
340 | | |
341 | | lldb::offset_t lldb_private::DumpDataExtractor( |
342 | | const DataExtractor &DE, Stream *s, offset_t start_offset, |
343 | | lldb::Format item_format, size_t item_byte_size, size_t item_count, |
344 | | size_t num_per_line, uint64_t base_addr, |
345 | | uint32_t item_bit_size, // If zero, this is not a bitfield value, if |
346 | | // non-zero, the value is a bitfield |
347 | | uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the |
348 | | // shift amount to apply to a bitfield |
349 | 103k | ExecutionContextScope *exe_scope, bool show_memory_tags) { |
350 | 103k | if (s == nullptr) |
351 | 1 | return start_offset; |
352 | | |
353 | 103k | if (item_format == eFormatPointer) { |
354 | 12 | if (item_byte_size != 4 && item_byte_size != 810 ) |
355 | 1 | item_byte_size = s->GetAddressByteSize(); |
356 | 12 | } |
357 | | |
358 | 103k | offset_t offset = start_offset; |
359 | | |
360 | 103k | std::optional<MemoryTagMap> memory_tag_map; |
361 | 103k | if (show_memory_tags && base_addr != 0 LLDB_INVALID_ADDRESS0 ) |
362 | 0 | memory_tag_map = |
363 | 0 | GetMemoryTags(base_addr, DE.GetByteSize() - offset, exe_scope); |
364 | | |
365 | 103k | if (item_format == eFormatInstruction) |
366 | 2 | return DumpInstructions(DE, s, exe_scope, start_offset, base_addr, |
367 | 2 | item_count); |
368 | | |
369 | 103k | if ((item_format == eFormatOSType || item_format == eFormatAddressInfo103k ) && |
370 | 103k | item_byte_size > 832 ) |
371 | 1 | item_format = eFormatHex; |
372 | | |
373 | 103k | lldb::offset_t line_start_offset = start_offset; |
374 | 1.58M | for (uint32_t count = 0; DE.ValidOffset(offset) && count < item_count1.54M ; |
375 | 1.48M | ++count1.48M ) { |
376 | | // If we are at the beginning or end of a line |
377 | | // Note that the last line is handled outside this for loop. |
378 | 1.48M | if ((count % num_per_line) == 0) { |
379 | | // If we are at the end of a line |
380 | 103k | if (count > 0) { |
381 | 833 | if (item_format == eFormatBytesWithASCII && |
382 | 833 | offset > line_start_offset12 ) { |
383 | 12 | s->Printf("%*s", |
384 | 12 | static_cast<int>( |
385 | 12 | (num_per_line - (offset - line_start_offset)) * 3 + 2), |
386 | 12 | ""); |
387 | 12 | DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1, |
388 | 12 | offset - line_start_offset, SIZE_MAX, |
389 | 12 | LLDB_INVALID_ADDRESS, 0, 0); |
390 | 12 | } |
391 | | |
392 | 833 | if (base_addr != LLDB_INVALID_ADDRESS && memory_tag_map832 ) { |
393 | 0 | size_t line_len = offset - line_start_offset; |
394 | 0 | lldb::addr_t line_base = |
395 | 0 | base_addr + |
396 | 0 | (offset - start_offset - line_len) / DE.getTargetByteSize(); |
397 | 0 | printMemoryTags(DE, s, line_base, line_len, memory_tag_map); |
398 | 0 | } |
399 | | |
400 | 833 | s->EOL(); |
401 | 833 | } |
402 | 103k | if (base_addr != LLDB_INVALID_ADDRESS) |
403 | 955 | s->Printf("0x%8.8" PRIx64 ": ", |
404 | 955 | (uint64_t)(base_addr + |
405 | 955 | (offset - start_offset) / DE.getTargetByteSize())); |
406 | | |
407 | 103k | line_start_offset = offset; |
408 | 1.37M | } else if (item_format != eFormatChar && |
409 | 1.37M | item_format != eFormatCharPrintable37.0k && |
410 | 1.37M | item_format != eFormatCharArray36.2k && count > 036.1k ) { |
411 | 36.1k | s->PutChar(' '); |
412 | 36.1k | } |
413 | | |
414 | 1.48M | switch (item_format) { |
415 | 6.98k | case eFormatBoolean: |
416 | 6.98k | if (item_byte_size <= 8) |
417 | 6.97k | s->Printf("%s", DE.GetMaxU64Bitfield(&offset, item_byte_size, |
418 | 6.97k | item_bit_size, item_bit_offset) |
419 | 6.97k | ? "true"1.47k |
420 | 6.97k | : "false"5.50k ); |
421 | 2 | else { |
422 | 2 | s->Printf("error: unsupported byte size (%" PRIu64 |
423 | 2 | ") for boolean format", |
424 | 2 | (uint64_t)item_byte_size); |
425 | 2 | return offset; |
426 | 2 | } |
427 | 6.97k | break; |
428 | | |
429 | 6.97k | case eFormatBinary: |
430 | 10 | if (item_byte_size <= 8) { |
431 | 9 | uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size, |
432 | 9 | item_bit_size, item_bit_offset); |
433 | | // Avoid std::bitset<64>::to_string() since it is missing in earlier |
434 | | // C++ libraries |
435 | 9 | std::string binary_value(64, '0'); |
436 | 9 | std::bitset<64> bits(uval64); |
437 | 585 | for (uint32_t i = 0; i < 64; ++i576 ) |
438 | 576 | if (bits[i]) |
439 | 27 | binary_value[64 - 1 - i] = '1'; |
440 | 9 | if (item_bit_size > 0) |
441 | 0 | s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size); |
442 | 9 | else if (item_byte_size > 0 && item_byte_size <= 8) |
443 | 9 | s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8); |
444 | 9 | } else { |
445 | 1 | const bool is_signed = false; |
446 | 1 | const unsigned radix = 2; |
447 | 1 | offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix); |
448 | 1 | } |
449 | 10 | break; |
450 | | |
451 | 673 | case eFormatBytes: |
452 | 1.59k | case eFormatBytesWithASCII: |
453 | 3.18k | for (uint32_t i = 0; i < item_byte_size; ++i1.59k ) { |
454 | 1.59k | s->Printf("%2.2x", DE.GetU8(&offset)); |
455 | 1.59k | } |
456 | | |
457 | | // Put an extra space between the groups of bytes if more than one is |
458 | | // being dumped in a group (item_byte_size is more than 1). |
459 | 1.59k | if (item_byte_size > 1) |
460 | 0 | s->PutChar(' '); |
461 | 1.59k | break; |
462 | | |
463 | 1.40M | case eFormatChar: |
464 | 1.40M | case eFormatCharPrintable: |
465 | 1.40M | case eFormatCharArray: { |
466 | | // Reject invalid item_byte_size. |
467 | 1.40M | if (item_byte_size > 8) { |
468 | 1 | s->Printf("error: unsupported byte size (%" PRIu64 ") for char format", |
469 | 1 | (uint64_t)item_byte_size); |
470 | 1 | return offset; |
471 | 1 | } |
472 | | |
473 | | // If we are only printing one character surround it with single quotes |
474 | 1.40M | if (item_count == 1 && item_format == eFormatChar1.86k ) |
475 | 1.84k | s->PutChar('\''); |
476 | | |
477 | 1.40M | const uint64_t ch = DE.GetMaxU64Bitfield(&offset, item_byte_size, |
478 | 1.40M | item_bit_size, item_bit_offset); |
479 | 1.40M | if (llvm::isPrint(ch)) |
480 | 1.40M | s->Printf("%c", (char)ch); |
481 | 1.33k | else if (item_format != eFormatCharPrintable) { |
482 | 807 | if (!TryDumpSpecialEscapedChar(*s, ch)) { |
483 | 87 | if (item_byte_size == 1) |
484 | 87 | s->Printf("\\x%2.2x", (uint8_t)ch); |
485 | 0 | else |
486 | 0 | s->Printf("%" PRIu64, ch); |
487 | 87 | } |
488 | 807 | } else { |
489 | 523 | s->PutChar(NON_PRINTABLE_CHAR); |
490 | 523 | } |
491 | | |
492 | | // If we are only printing one character surround it with single quotes |
493 | 1.40M | if (item_count == 1 && item_format == eFormatChar1.86k ) |
494 | 1.84k | s->PutChar('\''); |
495 | 1.40M | } break; |
496 | | |
497 | 4 | case eFormatEnum: // Print enum value as a signed integer when we don't get |
498 | | // the enum type |
499 | 12.1k | case eFormatDecimal: |
500 | 12.1k | if (item_byte_size <= 8) |
501 | 12.1k | s->Printf("%" PRId64, |
502 | 12.1k | DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, |
503 | 12.1k | item_bit_offset)); |
504 | 7 | else { |
505 | 7 | const bool is_signed = true; |
506 | 7 | const unsigned radix = 10; |
507 | 7 | offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix); |
508 | 7 | } |
509 | 12.1k | break; |
510 | | |
511 | 2.36k | case eFormatUnsigned: |
512 | 2.36k | if (item_byte_size <= 8) |
513 | 2.35k | s->Printf("%" PRIu64, |
514 | 2.35k | DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, |
515 | 2.35k | item_bit_offset)); |
516 | 3 | else { |
517 | 3 | const bool is_signed = false; |
518 | 3 | const unsigned radix = 10; |
519 | 3 | offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix); |
520 | 3 | } |
521 | 2.36k | break; |
522 | | |
523 | 4 | case eFormatOctal: |
524 | 4 | if (item_byte_size <= 8) |
525 | 3 | s->Printf("0%" PRIo64, |
526 | 3 | DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, |
527 | 3 | item_bit_offset)); |
528 | 1 | else { |
529 | 1 | const bool is_signed = false; |
530 | 1 | const unsigned radix = 8; |
531 | 1 | offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix); |
532 | 1 | } |
533 | 4 | break; |
534 | | |
535 | 11 | case eFormatOSType: { |
536 | 11 | uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size, |
537 | 11 | item_bit_size, item_bit_offset); |
538 | 11 | s->PutChar('\''); |
539 | 63 | for (uint32_t i = 0; i < item_byte_size; ++i52 ) { |
540 | 52 | uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8)); |
541 | 52 | DumpCharacter(*s, ch); |
542 | 52 | } |
543 | 11 | s->PutChar('\''); |
544 | 11 | } break; |
545 | | |
546 | 7 | case eFormatCString: { |
547 | 7 | const char *cstr = DE.GetCStr(&offset); |
548 | | |
549 | 7 | if (!cstr) { |
550 | 0 | s->Printf("NULL"); |
551 | 0 | offset = LLDB_INVALID_OFFSET; |
552 | 7 | } else { |
553 | 7 | s->PutChar('\"'); |
554 | | |
555 | 55 | while (const char c = *cstr) { |
556 | 48 | DumpCharacter(*s, c); |
557 | 48 | ++cstr; |
558 | 48 | } |
559 | | |
560 | 7 | s->PutChar('\"'); |
561 | 7 | } |
562 | 7 | } break; |
563 | | |
564 | 12 | case eFormatPointer: |
565 | 12 | DumpAddress(s->AsRawOstream(), |
566 | 12 | DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, |
567 | 12 | item_bit_offset), |
568 | 12 | sizeof(addr_t)); |
569 | 12 | break; |
570 | | |
571 | 9 | case eFormatComplexInteger: { |
572 | 9 | size_t complex_int_byte_size = item_byte_size / 2; |
573 | | |
574 | 9 | if (complex_int_byte_size > 0 && complex_int_byte_size <= 88 ) { |
575 | 7 | s->Printf("%" PRIu64, |
576 | 7 | DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); |
577 | 7 | s->Printf(" + %" PRIu64 "i", |
578 | 7 | DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); |
579 | 7 | } else { |
580 | 2 | s->Printf("error: unsupported byte size (%" PRIu64 |
581 | 2 | ") for complex integer format", |
582 | 2 | (uint64_t)item_byte_size); |
583 | 2 | return offset; |
584 | 2 | } |
585 | 9 | } break7 ; |
586 | | |
587 | 10 | case eFormatComplex: |
588 | 10 | if (sizeof(float) * 2 == item_byte_size) { |
589 | 3 | float f32_1 = DE.GetFloat(&offset); |
590 | 3 | float f32_2 = DE.GetFloat(&offset); |
591 | | |
592 | 3 | s->Printf("%g + %gi", f32_1, f32_2); |
593 | 3 | break; |
594 | 7 | } else if (sizeof(double) * 2 == item_byte_size) { |
595 | 3 | double d64_1 = DE.GetDouble(&offset); |
596 | 3 | double d64_2 = DE.GetDouble(&offset); |
597 | | |
598 | 3 | s->Printf("%lg + %lgi", d64_1, d64_2); |
599 | 3 | break; |
600 | 4 | } else if (sizeof(long double) * 2 == item_byte_size) { |
601 | 1 | long double ld64_1 = DE.GetLongDouble(&offset); |
602 | 1 | long double ld64_2 = DE.GetLongDouble(&offset); |
603 | 1 | s->Printf("%Lg + %Lgi", ld64_1, ld64_2); |
604 | 1 | break; |
605 | 3 | } else { |
606 | 3 | s->Printf("error: unsupported byte size (%" PRIu64 |
607 | 3 | ") for complex float format", |
608 | 3 | (uint64_t)item_byte_size); |
609 | 3 | return offset; |
610 | 3 | } |
611 | 0 | break; |
612 | | |
613 | 30 | default: |
614 | 77 | case eFormatDefault: |
615 | 47.0k | case eFormatHex: |
616 | 47.0k | case eFormatHexUppercase: { |
617 | 47.0k | bool wantsuppercase = (item_format == eFormatHexUppercase); |
618 | 47.0k | switch (item_byte_size) { |
619 | 37.6k | case 1: |
620 | 38.6k | case 2: |
621 | 40.6k | case 4: |
622 | 47.0k | case 8: |
623 | 47.0k | if (Target::GetGlobalProperties() |
624 | 47.0k | .ShowHexVariableValuesWithLeadingZeroes()) { |
625 | 46.9k | s->Printf(wantsuppercase ? "0x%*.*" PRIX6420 : "0x%*.*" PRIx6446.9k , |
626 | 46.9k | (int)(2 * item_byte_size), (int)(2 * item_byte_size), |
627 | 46.9k | DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, |
628 | 46.9k | item_bit_offset)); |
629 | 46.9k | } else { |
630 | 4 | s->Printf(wantsuppercase ? "0x%" PRIX640 : "0x%" PRIx64, |
631 | 4 | DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, |
632 | 4 | item_bit_offset)); |
633 | 4 | } |
634 | 47.0k | break; |
635 | 73 | default: { |
636 | 73 | assert(item_bit_size == 0 && item_bit_offset == 0); |
637 | 73 | const uint8_t *bytes = |
638 | 73 | (const uint8_t *)DE.GetData(&offset, item_byte_size); |
639 | 73 | if (bytes) { |
640 | 73 | s->PutCString("0x"); |
641 | 73 | uint32_t idx; |
642 | 73 | if (DE.GetByteOrder() == eByteOrderBig) { |
643 | 0 | for (idx = 0; idx < item_byte_size; ++idx) |
644 | 0 | s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]); |
645 | 73 | } else { |
646 | 1.24k | for (idx = 0; idx < item_byte_size; ++idx1.16k ) |
647 | 1.16k | s->Printf(wantsuppercase ? "%2.2X"0 : "%2.2x", |
648 | 1.16k | bytes[item_byte_size - 1 - idx]); |
649 | 73 | } |
650 | 73 | } |
651 | 73 | } break; |
652 | 47.0k | } |
653 | 47.0k | } break; |
654 | | |
655 | 47.0k | case eFormatFloat: { |
656 | 1.91k | TargetSP target_sp; |
657 | 1.91k | if (exe_scope) |
658 | 1.84k | target_sp = exe_scope->CalculateTarget(); |
659 | | |
660 | 1.91k | std::optional<unsigned> format_max_padding; |
661 | 1.91k | if (target_sp) |
662 | 1.84k | format_max_padding = target_sp->GetMaxZeroPaddingInFloatFormat(); |
663 | | |
664 | | // Show full precision when printing float values |
665 | 1.91k | const unsigned format_precision = 0; |
666 | | |
667 | 1.91k | const llvm::fltSemantics &semantics = |
668 | 1.91k | GetFloatSemantics(target_sp, item_byte_size); |
669 | | |
670 | | // Recalculate the byte size in case of a difference. This is possible |
671 | | // when item_byte_size is 16 (128-bit), because you could get back the |
672 | | // x87DoubleExtended semantics which has a byte size of 10 (80-bit). |
673 | 1.91k | const size_t semantics_byte_size = |
674 | 1.91k | (llvm::APFloat::getSizeInBits(semantics) + 7) / 8; |
675 | 1.91k | std::optional<llvm::APInt> apint = |
676 | 1.91k | GetAPInt(DE, &offset, semantics_byte_size); |
677 | 1.91k | if (apint) { |
678 | 1.91k | llvm::APFloat apfloat(semantics, *apint); |
679 | 1.91k | llvm::SmallVector<char, 256> sv; |
680 | 1.91k | if (format_max_padding) |
681 | 1.84k | apfloat.toString(sv, format_precision, *format_max_padding); |
682 | 68 | else |
683 | 68 | apfloat.toString(sv, format_precision); |
684 | 1.91k | s->AsRawOstream() << sv; |
685 | 1.91k | } else { |
686 | 4 | s->Format("error: unsupported byte size ({0}) for float format", |
687 | 4 | item_byte_size); |
688 | 4 | return offset; |
689 | 4 | } |
690 | 1.91k | } break1.91k ; |
691 | | |
692 | 1.91k | case eFormatUnicode16: |
693 | 259 | s->Printf("U+%4.4x", DE.GetU16(&offset)); |
694 | 259 | break; |
695 | | |
696 | 23 | case eFormatUnicode32: |
697 | 23 | s->Printf("U+0x%8.8x", DE.GetU32(&offset)); |
698 | 23 | break; |
699 | | |
700 | 28 | case eFormatAddressInfo: { |
701 | 28 | addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, |
702 | 28 | item_bit_offset); |
703 | 28 | s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size), |
704 | 28 | (int)(2 * item_byte_size), addr); |
705 | 28 | if (exe_scope) { |
706 | 27 | TargetSP target_sp(exe_scope->CalculateTarget()); |
707 | 27 | lldb_private::Address so_addr; |
708 | 27 | if (target_sp) { |
709 | 27 | if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, |
710 | 27 | so_addr)) { |
711 | 4 | s->PutChar(' '); |
712 | 4 | so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription, |
713 | 4 | Address::DumpStyleModuleWithFileAddress); |
714 | 23 | } else { |
715 | 23 | so_addr.SetOffset(addr); |
716 | 23 | so_addr.Dump(s, exe_scope, |
717 | 23 | Address::DumpStyleResolvedPointerDescription); |
718 | 23 | if (ProcessSP process_sp = exe_scope->CalculateProcess()) { |
719 | 23 | if (ABISP abi_sp = process_sp->GetABI()) { |
720 | 23 | addr_t addr_fixed = abi_sp->FixCodeAddress(addr); |
721 | 23 | if (target_sp->GetSectionLoadList().ResolveLoadAddress( |
722 | 23 | addr_fixed, so_addr)) { |
723 | 0 | s->PutChar(' '); |
724 | 0 | s->Printf("(0x%*.*" PRIx64 ")", (int)(2 * item_byte_size), |
725 | 0 | (int)(2 * item_byte_size), addr_fixed); |
726 | 0 | s->PutChar(' '); |
727 | 0 | so_addr.Dump(s, exe_scope, |
728 | 0 | Address::DumpStyleResolvedDescription, |
729 | 0 | Address::DumpStyleModuleWithFileAddress); |
730 | 0 | } |
731 | 23 | } |
732 | 23 | } |
733 | 23 | } |
734 | 27 | } |
735 | 27 | } |
736 | 28 | } break; |
737 | | |
738 | 8 | case eFormatHexFloat: |
739 | 8 | if (sizeof(float) == item_byte_size) { |
740 | 2 | char float_cstr[256]; |
741 | 2 | llvm::APFloat ap_float(DE.GetFloat(&offset)); |
742 | 2 | ap_float.convertToHexString(float_cstr, 0, false, |
743 | 2 | llvm::APFloat::rmNearestTiesToEven); |
744 | 2 | s->Printf("%s", float_cstr); |
745 | 2 | break; |
746 | 6 | } else if (sizeof(double) == item_byte_size) { |
747 | 2 | char float_cstr[256]; |
748 | 2 | llvm::APFloat ap_float(DE.GetDouble(&offset)); |
749 | 2 | ap_float.convertToHexString(float_cstr, 0, false, |
750 | 2 | llvm::APFloat::rmNearestTiesToEven); |
751 | 2 | s->Printf("%s", float_cstr); |
752 | 2 | break; |
753 | 4 | } else { |
754 | 4 | s->Printf("error: unsupported byte size (%" PRIu64 |
755 | 4 | ") for hex float format", |
756 | 4 | (uint64_t)item_byte_size); |
757 | 4 | return offset; |
758 | 4 | } |
759 | 0 | break; |
760 | | |
761 | | // please keep the single-item formats below in sync with |
762 | | // FormatManager::GetSingleItemFormat if you fail to do so, users will |
763 | | // start getting different outputs depending on internal implementation |
764 | | // details they should not care about || |
765 | 18 | case eFormatVectorOfChar: // || |
766 | 18 | s->PutChar('{'); // \/ |
767 | 18 | offset = |
768 | 18 | DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size, |
769 | 18 | item_byte_size, LLDB_INVALID_ADDRESS, 0, 0); |
770 | 18 | s->PutChar('}'); |
771 | 18 | break; |
772 | | |
773 | 2 | case eFormatVectorOfSInt8: |
774 | 2 | s->PutChar('{'); |
775 | 2 | offset = |
776 | 2 | DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size, |
777 | 2 | item_byte_size, LLDB_INVALID_ADDRESS, 0, 0); |
778 | 2 | s->PutChar('}'); |
779 | 2 | break; |
780 | | |
781 | 1.86k | case eFormatVectorOfUInt8: |
782 | 1.86k | s->PutChar('{'); |
783 | 1.86k | offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size, |
784 | 1.86k | item_byte_size, LLDB_INVALID_ADDRESS, 0, 0); |
785 | 1.86k | s->PutChar('}'); |
786 | 1.86k | break; |
787 | | |
788 | 2 | case eFormatVectorOfSInt16: |
789 | 2 | s->PutChar('{'); |
790 | 2 | offset = DumpDataExtractor( |
791 | 2 | DE, s, offset, eFormatDecimal, sizeof(uint16_t), |
792 | 2 | item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t), |
793 | 2 | LLDB_INVALID_ADDRESS, 0, 0); |
794 | 2 | s->PutChar('}'); |
795 | 2 | break; |
796 | | |
797 | 2 | case eFormatVectorOfUInt16: |
798 | 2 | s->PutChar('{'); |
799 | 2 | offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t), |
800 | 2 | item_byte_size / sizeof(uint16_t), |
801 | 2 | item_byte_size / sizeof(uint16_t), |
802 | 2 | LLDB_INVALID_ADDRESS, 0, 0); |
803 | 2 | s->PutChar('}'); |
804 | 2 | break; |
805 | | |
806 | 5 | case eFormatVectorOfSInt32: |
807 | 5 | s->PutChar('{'); |
808 | 5 | offset = DumpDataExtractor( |
809 | 5 | DE, s, offset, eFormatDecimal, sizeof(uint32_t), |
810 | 5 | item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t), |
811 | 5 | LLDB_INVALID_ADDRESS, 0, 0); |
812 | 5 | s->PutChar('}'); |
813 | 5 | break; |
814 | | |
815 | 27 | case eFormatVectorOfUInt32: |
816 | 27 | s->PutChar('{'); |
817 | 27 | offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t), |
818 | 27 | item_byte_size / sizeof(uint32_t), |
819 | 27 | item_byte_size / sizeof(uint32_t), |
820 | 27 | LLDB_INVALID_ADDRESS, 0, 0); |
821 | 27 | s->PutChar('}'); |
822 | 27 | break; |
823 | | |
824 | 2 | case eFormatVectorOfSInt64: |
825 | 2 | s->PutChar('{'); |
826 | 2 | offset = DumpDataExtractor( |
827 | 2 | DE, s, offset, eFormatDecimal, sizeof(uint64_t), |
828 | 2 | item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t), |
829 | 2 | LLDB_INVALID_ADDRESS, 0, 0); |
830 | 2 | s->PutChar('}'); |
831 | 2 | break; |
832 | | |
833 | 2 | case eFormatVectorOfUInt64: |
834 | 2 | s->PutChar('{'); |
835 | 2 | offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t), |
836 | 2 | item_byte_size / sizeof(uint64_t), |
837 | 2 | item_byte_size / sizeof(uint64_t), |
838 | 2 | LLDB_INVALID_ADDRESS, 0, 0); |
839 | 2 | s->PutChar('}'); |
840 | 2 | break; |
841 | | |
842 | 9 | case eFormatVectorOfFloat16: |
843 | 9 | s->PutChar('{'); |
844 | 9 | offset = |
845 | 9 | DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2, |
846 | 9 | item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0); |
847 | 9 | s->PutChar('}'); |
848 | 9 | break; |
849 | | |
850 | 33 | case eFormatVectorOfFloat32: |
851 | 33 | s->PutChar('{'); |
852 | 33 | offset = |
853 | 33 | DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4, |
854 | 33 | item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0); |
855 | 33 | s->PutChar('}'); |
856 | 33 | break; |
857 | | |
858 | 3 | case eFormatVectorOfFloat64: |
859 | 3 | s->PutChar('{'); |
860 | 3 | offset = |
861 | 3 | DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8, |
862 | 3 | item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0); |
863 | 3 | s->PutChar('}'); |
864 | 3 | break; |
865 | | |
866 | 2 | case eFormatVectorOfUInt128: |
867 | 2 | s->PutChar('{'); |
868 | 2 | offset = |
869 | 2 | DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16, |
870 | 2 | item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0); |
871 | 2 | s->PutChar('}'); |
872 | 2 | break; |
873 | 1.48M | } |
874 | 1.48M | } |
875 | | |
876 | | // If anything was printed we want to catch the end of the last line. |
877 | | // Since we will exit the for loop above before we get a chance to append to |
878 | | // it normally. |
879 | 103k | if (offset > line_start_offset) { |
880 | 103k | if (item_format == eFormatBytesWithASCII) { |
881 | 115 | s->Printf("%*s", |
882 | 115 | static_cast<int>( |
883 | 115 | (num_per_line - (offset - line_start_offset)) * 3 + 2), |
884 | 115 | ""); |
885 | 115 | DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1, |
886 | 115 | offset - line_start_offset, SIZE_MAX, |
887 | 115 | LLDB_INVALID_ADDRESS, 0, 0); |
888 | 115 | } |
889 | | |
890 | 103k | if (base_addr != LLDB_INVALID_ADDRESS && memory_tag_map121 ) { |
891 | 0 | size_t line_len = offset - line_start_offset; |
892 | 0 | lldb::addr_t line_base = base_addr + (offset - start_offset - line_len) / |
893 | 0 | DE.getTargetByteSize(); |
894 | 0 | printMemoryTags(DE, s, line_base, line_len, memory_tag_map); |
895 | 0 | } |
896 | 103k | } |
897 | | |
898 | 103k | return offset; // Return the offset at which we ended up |
899 | 103k | } |
900 | | |
901 | | void lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len, |
902 | | uint32_t bytes_per_line, |
903 | 104 | lldb::addr_t base_addr) { |
904 | 104 | DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4); |
905 | 104 | DumpDataExtractor(data, s, |
906 | 104 | 0, // Offset into "src" |
907 | 104 | lldb::eFormatBytes, // Dump as hex bytes |
908 | 104 | 1, // Size of each item is 1 for single bytes |
909 | 104 | src_len, // Number of bytes |
910 | 104 | bytes_per_line, // Num bytes per line |
911 | 104 | base_addr, // Base address |
912 | 104 | 0, 0); // Bitfield info |
913 | 104 | } |