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