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/Process.h"
21 #include "lldb/Target/SectionLoadList.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Utility/DataExtractor.h"
24 #include "lldb/Utility/Log.h"
25 #include "lldb/Utility/Stream.h"
26 
27 #include "llvm/ADT/APFloat.h"
28 #include "llvm/ADT/APInt.h"
29 #include "llvm/ADT/ArrayRef.h"
30 #include "llvm/ADT/Optional.h"
31 #include "llvm/ADT/SmallVector.h"
32 
33 #include <limits>
34 #include <memory>
35 #include <string>
36 
37 #include <assert.h>
38 #include <ctype.h>
39 #include <inttypes.h>
40 #include <math.h>
41 
42 #include <bitset>
43 #include <sstream>
44 
45 using namespace lldb_private;
46 using namespace lldb;
47 
48 #define NON_PRINTABLE_CHAR '.'
49 
50 static float half2float(uint16_t half) {
51   union {
52     float f;
53     uint32_t u;
54   } u;
55   int32_t v = (int16_t)half;
56 
57   if (0 == (v & 0x7c00)) {
58     u.u = v & 0x80007FFFU;
59     return u.f * ldexpf(1, 125);
60   }
61 
62   v <<= 13;
63   u.u = v | 0x70000000U;
64   return u.f * ldexpf(1, -112);
65 }
66 
67 static llvm::Optional<llvm::APInt> GetAPInt(const DataExtractor &data,
68                                             lldb::offset_t *offset_ptr,
69                                             lldb::offset_t byte_size) {
70   if (byte_size == 0)
71     return llvm::None;
72 
73   llvm::SmallVector<uint64_t, 2> uint64_array;
74   lldb::offset_t bytes_left = byte_size;
75   uint64_t u64;
76   const lldb::ByteOrder byte_order = data.GetByteOrder();
77   if (byte_order == lldb::eByteOrderLittle) {
78     while (bytes_left > 0) {
79       if (bytes_left >= 8) {
80         u64 = data.GetU64(offset_ptr);
81         bytes_left -= 8;
82       } else {
83         u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
84         bytes_left = 0;
85       }
86       uint64_array.push_back(u64);
87     }
88     return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
89   } else if (byte_order == lldb::eByteOrderBig) {
90     lldb::offset_t be_offset = *offset_ptr + byte_size;
91     lldb::offset_t temp_offset;
92     while (bytes_left > 0) {
93       if (bytes_left >= 8) {
94         be_offset -= 8;
95         temp_offset = be_offset;
96         u64 = data.GetU64(&temp_offset);
97         bytes_left -= 8;
98       } else {
99         be_offset -= bytes_left;
100         temp_offset = be_offset;
101         u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
102         bytes_left = 0;
103       }
104       uint64_array.push_back(u64);
105     }
106     *offset_ptr += byte_size;
107     return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
108   }
109   return llvm::None;
110 }
111 
112 static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data,
113                                 lldb::offset_t offset, lldb::offset_t byte_size,
114                                 bool is_signed, unsigned radix) {
115   llvm::Optional<llvm::APInt> apint = GetAPInt(data, &offset, byte_size);
116   if (apint.hasValue()) {
117     std::string apint_str(apint.getValue().toString(radix, is_signed));
118     switch (radix) {
119     case 2:
120       s->Write("0b", 2);
121       break;
122     case 8:
123       s->Write("0", 1);
124       break;
125     case 10:
126       break;
127     }
128     s->Write(apint_str.c_str(), apint_str.size());
129   }
130   return offset;
131 }
132 
133 /// Dumps decoded instructions to a stream.
134 static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s,
135                                        ExecutionContextScope *exe_scope,
136                                        offset_t start_offset,
137                                        uint64_t base_addr,
138                                        size_t number_of_instructions) {
139   offset_t offset = start_offset;
140 
141   TargetSP target_sp;
142   if (exe_scope)
143     target_sp = exe_scope->CalculateTarget();
144   if (target_sp) {
145     DisassemblerSP disassembler_sp(
146         Disassembler::FindPlugin(target_sp->GetArchitecture(),
147                                  target_sp->GetDisassemblyFlavor(), nullptr));
148     if (disassembler_sp) {
149       lldb::addr_t addr = base_addr + start_offset;
150       lldb_private::Address so_addr;
151       bool data_from_file = true;
152       if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
153         data_from_file = false;
154       } else {
155         if (target_sp->GetSectionLoadList().IsEmpty() ||
156             !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
157           so_addr.SetRawAddress(addr);
158       }
159 
160       size_t bytes_consumed = disassembler_sp->DecodeInstructions(
161           so_addr, DE, start_offset, number_of_instructions, false,
162           data_from_file);
163 
164       if (bytes_consumed) {
165         offset += bytes_consumed;
166         const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
167         const bool show_bytes = true;
168         ExecutionContext exe_ctx;
169         exe_scope->CalculateExecutionContext(exe_ctx);
170         disassembler_sp->GetInstructionList().Dump(s, show_address, show_bytes,
171                                                    &exe_ctx);
172       }
173     }
174   } else
175     s->Printf("invalid target");
176 
177   return offset;
178 }
179 
180 /// Prints the specific escape sequence of the given character to the stream.
181 /// If the character doesn't have a known specific escape sequence (e.g., '\a',
182 /// '\n' but not generic escape sequences such as'\x12'), this function will
183 /// not modify the stream and return false.
184 static bool TryDumpSpecialEscapedChar(Stream &s, const char c) {
185   switch (c) {
186   case '\033':
187     // Common non-standard escape code for 'escape'.
188     s.Printf("\\e");
189     return true;
190   case '\a':
191     s.Printf("\\a");
192     return true;
193   case '\b':
194     s.Printf("\\b");
195     return true;
196   case '\f':
197     s.Printf("\\f");
198     return true;
199   case '\n':
200     s.Printf("\\n");
201     return true;
202   case '\r':
203     s.Printf("\\r");
204     return true;
205   case '\t':
206     s.Printf("\\t");
207     return true;
208   case '\v':
209     s.Printf("\\v");
210     return true;
211   case '\0':
212     s.Printf("\\0");
213     return true;
214   default:
215     return false;
216   }
217 }
218 
219 /// Dump the character to a stream. A character that is not printable will be
220 /// represented by its escape sequence.
221 static void DumpCharacter(Stream &s, const char c) {
222   if (TryDumpSpecialEscapedChar(s, c))
223     return;
224   if (llvm::isPrint(c)) {
225     s.PutChar(c);
226     return;
227   }
228   s.Printf("\\x%2.2x", c);
229 }
230 
231 lldb::offset_t lldb_private::DumpDataExtractor(
232     const DataExtractor &DE, Stream *s, offset_t start_offset,
233     lldb::Format item_format, size_t item_byte_size, size_t item_count,
234     size_t num_per_line, uint64_t base_addr,
235     uint32_t item_bit_size,   // If zero, this is not a bitfield value, if
236                               // non-zero, the value is a bitfield
237     uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the
238                               // shift amount to apply to a bitfield
239     ExecutionContextScope *exe_scope) {
240   if (s == nullptr)
241     return start_offset;
242 
243   if (item_format == eFormatPointer) {
244     if (item_byte_size != 4 && item_byte_size != 8)
245       item_byte_size = s->GetAddressByteSize();
246   }
247 
248   offset_t offset = start_offset;
249 
250   if (item_format == eFormatInstruction)
251     return DumpInstructions(DE, s, exe_scope, start_offset, base_addr,
252                             item_count);
253 
254   if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) &&
255       item_byte_size > 8)
256     item_format = eFormatHex;
257 
258   lldb::offset_t line_start_offset = start_offset;
259   for (uint32_t count = 0; DE.ValidOffset(offset) && count < item_count;
260        ++count) {
261     if ((count % num_per_line) == 0) {
262       if (count > 0) {
263         if (item_format == eFormatBytesWithASCII &&
264             offset > line_start_offset) {
265           s->Printf("%*s",
266                     static_cast<int>(
267                         (num_per_line - (offset - line_start_offset)) * 3 + 2),
268                     "");
269           DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
270                             offset - line_start_offset, SIZE_MAX,
271                             LLDB_INVALID_ADDRESS, 0, 0);
272         }
273         s->EOL();
274       }
275       if (base_addr != LLDB_INVALID_ADDRESS)
276         s->Printf("0x%8.8" PRIx64 ": ",
277                   (uint64_t)(base_addr +
278                              (offset - start_offset) / DE.getTargetByteSize()));
279 
280       line_start_offset = offset;
281     } else if (item_format != eFormatChar &&
282                item_format != eFormatCharPrintable &&
283                item_format != eFormatCharArray && count > 0) {
284       s->PutChar(' ');
285     }
286 
287     switch (item_format) {
288     case eFormatBoolean:
289       if (item_byte_size <= 8)
290         s->Printf("%s", DE.GetMaxU64Bitfield(&offset, item_byte_size,
291                                              item_bit_size, item_bit_offset)
292                             ? "true"
293                             : "false");
294       else {
295         s->Printf("error: unsupported byte size (%" PRIu64
296                   ") for boolean format",
297                   (uint64_t)item_byte_size);
298         return offset;
299       }
300       break;
301 
302     case eFormatBinary:
303       if (item_byte_size <= 8) {
304         uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
305                                                item_bit_size, item_bit_offset);
306         // Avoid std::bitset<64>::to_string() since it is missing in earlier
307         // C++ libraries
308         std::string binary_value(64, '0');
309         std::bitset<64> bits(uval64);
310         for (uint32_t i = 0; i < 64; ++i)
311           if (bits[i])
312             binary_value[64 - 1 - i] = '1';
313         if (item_bit_size > 0)
314           s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
315         else if (item_byte_size > 0 && item_byte_size <= 8)
316           s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
317       } else {
318         const bool is_signed = false;
319         const unsigned radix = 2;
320         offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
321       }
322       break;
323 
324     case eFormatBytes:
325     case eFormatBytesWithASCII:
326       for (uint32_t i = 0; i < item_byte_size; ++i) {
327         s->Printf("%2.2x", DE.GetU8(&offset));
328       }
329 
330       // Put an extra space between the groups of bytes if more than one is
331       // being dumped in a group (item_byte_size is more than 1).
332       if (item_byte_size > 1)
333         s->PutChar(' ');
334       break;
335 
336     case eFormatChar:
337     case eFormatCharPrintable:
338     case eFormatCharArray: {
339       // Reject invalid item_byte_size.
340       if (item_byte_size > 8) {
341         s->Printf("error: unsupported byte size (%" PRIu64 ") for char format",
342                   (uint64_t)item_byte_size);
343         return offset;
344       }
345 
346       // If we are only printing one character surround it with single quotes
347       if (item_count == 1 && item_format == eFormatChar)
348         s->PutChar('\'');
349 
350       const uint64_t ch = DE.GetMaxU64Bitfield(&offset, item_byte_size,
351                                                item_bit_size, item_bit_offset);
352       if (llvm::isPrint(ch))
353         s->Printf("%c", (char)ch);
354       else if (item_format != eFormatCharPrintable) {
355         if (!TryDumpSpecialEscapedChar(*s, ch)) {
356           if (item_byte_size == 1)
357             s->Printf("\\x%2.2x", (uint8_t)ch);
358           else
359             s->Printf("%" PRIu64, ch);
360         }
361       } else {
362         s->PutChar(NON_PRINTABLE_CHAR);
363       }
364 
365       // If we are only printing one character surround it with single quotes
366       if (item_count == 1 && item_format == eFormatChar)
367         s->PutChar('\'');
368     } break;
369 
370     case eFormatEnum: // Print enum value as a signed integer when we don't get
371                       // the enum type
372     case eFormatDecimal:
373       if (item_byte_size <= 8)
374         s->Printf("%" PRId64,
375                   DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
376                                        item_bit_offset));
377       else {
378         const bool is_signed = true;
379         const unsigned radix = 10;
380         offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
381       }
382       break;
383 
384     case eFormatUnsigned:
385       if (item_byte_size <= 8)
386         s->Printf("%" PRIu64,
387                   DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
388                                        item_bit_offset));
389       else {
390         const bool is_signed = false;
391         const unsigned radix = 10;
392         offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
393       }
394       break;
395 
396     case eFormatOctal:
397       if (item_byte_size <= 8)
398         s->Printf("0%" PRIo64,
399                   DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
400                                        item_bit_offset));
401       else {
402         const bool is_signed = false;
403         const unsigned radix = 8;
404         offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
405       }
406       break;
407 
408     case eFormatOSType: {
409       uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
410                                              item_bit_size, item_bit_offset);
411       s->PutChar('\'');
412       for (uint32_t i = 0; i < item_byte_size; ++i) {
413         uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
414         DumpCharacter(*s, ch);
415       }
416       s->PutChar('\'');
417     } break;
418 
419     case eFormatCString: {
420       const char *cstr = DE.GetCStr(&offset);
421 
422       if (!cstr) {
423         s->Printf("NULL");
424         offset = LLDB_INVALID_OFFSET;
425       } else {
426         s->PutChar('\"');
427 
428         while (const char c = *cstr) {
429           DumpCharacter(*s, c);
430           ++cstr;
431         }
432 
433         s->PutChar('\"');
434       }
435     } break;
436 
437     case eFormatPointer:
438       DumpAddress(s->AsRawOstream(),
439                   DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
440                                        item_bit_offset),
441                   sizeof(addr_t));
442       break;
443 
444     case eFormatComplexInteger: {
445       size_t complex_int_byte_size = item_byte_size / 2;
446 
447       if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) {
448         s->Printf("%" PRIu64,
449                   DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
450         s->Printf(" + %" PRIu64 "i",
451                   DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
452       } else {
453         s->Printf("error: unsupported byte size (%" PRIu64
454                   ") for complex integer format",
455                   (uint64_t)item_byte_size);
456         return offset;
457       }
458     } break;
459 
460     case eFormatComplex:
461       if (sizeof(float) * 2 == item_byte_size) {
462         float f32_1 = DE.GetFloat(&offset);
463         float f32_2 = DE.GetFloat(&offset);
464 
465         s->Printf("%g + %gi", f32_1, f32_2);
466         break;
467       } else if (sizeof(double) * 2 == item_byte_size) {
468         double d64_1 = DE.GetDouble(&offset);
469         double d64_2 = DE.GetDouble(&offset);
470 
471         s->Printf("%lg + %lgi", d64_1, d64_2);
472         break;
473       } else if (sizeof(long double) * 2 == item_byte_size) {
474         long double ld64_1 = DE.GetLongDouble(&offset);
475         long double ld64_2 = DE.GetLongDouble(&offset);
476         s->Printf("%Lg + %Lgi", ld64_1, ld64_2);
477         break;
478       } else {
479         s->Printf("error: unsupported byte size (%" PRIu64
480                   ") for complex float format",
481                   (uint64_t)item_byte_size);
482         return offset;
483       }
484       break;
485 
486     default:
487     case eFormatDefault:
488     case eFormatHex:
489     case eFormatHexUppercase: {
490       bool wantsuppercase = (item_format == eFormatHexUppercase);
491       switch (item_byte_size) {
492       case 1:
493       case 2:
494       case 4:
495       case 8:
496         s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
497                   (int)(2 * item_byte_size), (int)(2 * item_byte_size),
498                   DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
499                                        item_bit_offset));
500         break;
501       default: {
502         assert(item_bit_size == 0 && item_bit_offset == 0);
503         const uint8_t *bytes =
504             (const uint8_t *)DE.GetData(&offset, item_byte_size);
505         if (bytes) {
506           s->PutCString("0x");
507           uint32_t idx;
508           if (DE.GetByteOrder() == eByteOrderBig) {
509             for (idx = 0; idx < item_byte_size; ++idx)
510               s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
511           } else {
512             for (idx = 0; idx < item_byte_size; ++idx)
513               s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
514                         bytes[item_byte_size - 1 - idx]);
515           }
516         }
517       } break;
518       }
519     } break;
520 
521     case eFormatFloat: {
522       TargetSP target_sp;
523       bool used_upfloat = false;
524       if (exe_scope)
525         target_sp = exe_scope->CalculateTarget();
526       if (target_sp) {
527         auto type_system_or_err =
528             target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
529         if (!type_system_or_err) {
530           llvm::consumeError(type_system_or_err.takeError());
531         } else {
532           auto &type_system = *type_system_or_err;
533           llvm::SmallVector<char, 256> sv;
534           // Show full precision when printing float values
535           const unsigned format_precision = 0;
536           const unsigned format_max_padding =
537               target_sp->GetMaxZeroPaddingInFloatFormat();
538 
539           const auto &semantics =
540               type_system.GetFloatTypeSemantics(item_byte_size);
541 
542           // Recalculate the byte size in case of a difference. This is possible
543           // when item_byte_size is 16 (128-bit), because you could get back the
544           // x87DoubleExtended semantics which has a byte size of 10 (80-bit).
545           const size_t semantics_byte_size =
546               (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
547           llvm::Optional<llvm::APInt> apint =
548               GetAPInt(DE, &offset, semantics_byte_size);
549           if (apint.hasValue()) {
550             llvm::APFloat apfloat(semantics, apint.getValue());
551             apfloat.toString(sv, format_precision, format_max_padding);
552             if (!sv.empty()) {
553               s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
554               used_upfloat = true;
555             }
556           }
557         }
558       }
559 
560       if (!used_upfloat) {
561         std::ostringstream ss;
562         if (item_byte_size == sizeof(float) || item_byte_size == 2) {
563           float f;
564           if (item_byte_size == 2) {
565             uint16_t half = DE.GetU16(&offset);
566             f = half2float(half);
567           } else {
568             f = DE.GetFloat(&offset);
569           }
570           ss.precision(std::numeric_limits<float>::digits10);
571           ss << f;
572         } else if (item_byte_size == sizeof(double)) {
573           ss.precision(std::numeric_limits<double>::digits10);
574           ss << DE.GetDouble(&offset);
575         } else if (item_byte_size == sizeof(long double) ||
576                    item_byte_size == 10) {
577           ss.precision(std::numeric_limits<long double>::digits10);
578           ss << DE.GetLongDouble(&offset);
579         } else {
580           s->Printf("error: unsupported byte size (%" PRIu64
581                     ") for float format",
582                     (uint64_t)item_byte_size);
583           return offset;
584         }
585         ss.flush();
586         s->Printf("%s", ss.str().c_str());
587       }
588     } break;
589 
590     case eFormatUnicode16:
591       s->Printf("U+%4.4x", DE.GetU16(&offset));
592       break;
593 
594     case eFormatUnicode32:
595       s->Printf("U+0x%8.8x", DE.GetU32(&offset));
596       break;
597 
598     case eFormatAddressInfo: {
599       addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
600                                          item_bit_offset);
601       s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
602                 (int)(2 * item_byte_size), addr);
603       if (exe_scope) {
604         TargetSP target_sp(exe_scope->CalculateTarget());
605         lldb_private::Address so_addr;
606         if (target_sp) {
607           if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
608                                                                  so_addr)) {
609             s->PutChar(' ');
610             so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
611                          Address::DumpStyleModuleWithFileAddress);
612           } else {
613             so_addr.SetOffset(addr);
614             so_addr.Dump(s, exe_scope,
615                          Address::DumpStyleResolvedPointerDescription);
616             if (ProcessSP process_sp = exe_scope->CalculateProcess()) {
617               if (ABISP abi_sp = process_sp->GetABI()) {
618                 addr_t addr_fixed = abi_sp->FixCodeAddress(addr);
619                 if (target_sp->GetSectionLoadList().ResolveLoadAddress(
620                         addr_fixed, so_addr)) {
621                   s->PutChar(' ');
622                   s->Printf("(0x%*.*" PRIx64 ")", (int)(2 * item_byte_size),
623                             (int)(2 * item_byte_size), addr_fixed);
624                   s->PutChar(' ');
625                   so_addr.Dump(s, exe_scope,
626                                Address::DumpStyleResolvedDescription,
627                                Address::DumpStyleModuleWithFileAddress);
628                 }
629               }
630             }
631           }
632         }
633       }
634     } break;
635 
636     case eFormatHexFloat:
637       if (sizeof(float) == item_byte_size) {
638         char float_cstr[256];
639         llvm::APFloat ap_float(DE.GetFloat(&offset));
640         ap_float.convertToHexString(float_cstr, 0, false,
641                                     llvm::APFloat::rmNearestTiesToEven);
642         s->Printf("%s", float_cstr);
643         break;
644       } else if (sizeof(double) == item_byte_size) {
645         char float_cstr[256];
646         llvm::APFloat ap_float(DE.GetDouble(&offset));
647         ap_float.convertToHexString(float_cstr, 0, false,
648                                     llvm::APFloat::rmNearestTiesToEven);
649         s->Printf("%s", float_cstr);
650         break;
651       } else {
652         s->Printf("error: unsupported byte size (%" PRIu64
653                   ") for hex float format",
654                   (uint64_t)item_byte_size);
655         return offset;
656       }
657       break;
658 
659     // please keep the single-item formats below in sync with
660     // FormatManager::GetSingleItemFormat if you fail to do so, users will
661     // start getting different outputs depending on internal implementation
662     // details they should not care about ||
663     case eFormatVectorOfChar: //   ||
664       s->PutChar('{');        //   \/
665       offset =
666           DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size,
667                             item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
668       s->PutChar('}');
669       break;
670 
671     case eFormatVectorOfSInt8:
672       s->PutChar('{');
673       offset =
674           DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size,
675                             item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
676       s->PutChar('}');
677       break;
678 
679     case eFormatVectorOfUInt8:
680       s->PutChar('{');
681       offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size,
682                                  item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
683       s->PutChar('}');
684       break;
685 
686     case eFormatVectorOfSInt16:
687       s->PutChar('{');
688       offset = DumpDataExtractor(
689           DE, s, offset, eFormatDecimal, sizeof(uint16_t),
690           item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t),
691           LLDB_INVALID_ADDRESS, 0, 0);
692       s->PutChar('}');
693       break;
694 
695     case eFormatVectorOfUInt16:
696       s->PutChar('{');
697       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t),
698                                  item_byte_size / sizeof(uint16_t),
699                                  item_byte_size / sizeof(uint16_t),
700                                  LLDB_INVALID_ADDRESS, 0, 0);
701       s->PutChar('}');
702       break;
703 
704     case eFormatVectorOfSInt32:
705       s->PutChar('{');
706       offset = DumpDataExtractor(
707           DE, s, offset, eFormatDecimal, sizeof(uint32_t),
708           item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t),
709           LLDB_INVALID_ADDRESS, 0, 0);
710       s->PutChar('}');
711       break;
712 
713     case eFormatVectorOfUInt32:
714       s->PutChar('{');
715       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t),
716                                  item_byte_size / sizeof(uint32_t),
717                                  item_byte_size / sizeof(uint32_t),
718                                  LLDB_INVALID_ADDRESS, 0, 0);
719       s->PutChar('}');
720       break;
721 
722     case eFormatVectorOfSInt64:
723       s->PutChar('{');
724       offset = DumpDataExtractor(
725           DE, s, offset, eFormatDecimal, sizeof(uint64_t),
726           item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t),
727           LLDB_INVALID_ADDRESS, 0, 0);
728       s->PutChar('}');
729       break;
730 
731     case eFormatVectorOfUInt64:
732       s->PutChar('{');
733       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t),
734                                  item_byte_size / sizeof(uint64_t),
735                                  item_byte_size / sizeof(uint64_t),
736                                  LLDB_INVALID_ADDRESS, 0, 0);
737       s->PutChar('}');
738       break;
739 
740     case eFormatVectorOfFloat16:
741       s->PutChar('{');
742       offset =
743           DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2,
744                             item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
745       s->PutChar('}');
746       break;
747 
748     case eFormatVectorOfFloat32:
749       s->PutChar('{');
750       offset =
751           DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4,
752                             item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
753       s->PutChar('}');
754       break;
755 
756     case eFormatVectorOfFloat64:
757       s->PutChar('{');
758       offset =
759           DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8,
760                             item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
761       s->PutChar('}');
762       break;
763 
764     case eFormatVectorOfUInt128:
765       s->PutChar('{');
766       offset =
767           DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16,
768                             item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
769       s->PutChar('}');
770       break;
771     }
772   }
773 
774   if (item_format == eFormatBytesWithASCII && offset > line_start_offset) {
775     s->Printf("%*s", static_cast<int>(
776                          (num_per_line - (offset - line_start_offset)) * 3 + 2),
777               "");
778     DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
779                       offset - line_start_offset, SIZE_MAX,
780                       LLDB_INVALID_ADDRESS, 0, 0);
781   }
782   return offset; // Return the offset at which we ended up
783 }
784 
785 void lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len,
786                                 uint32_t bytes_per_line,
787                                 lldb::addr_t base_addr) {
788   DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4);
789   DumpDataExtractor(data, s,
790                     0,                  // Offset into "src"
791                     lldb::eFormatBytes, // Dump as hex bytes
792                     1,              // Size of each item is 1 for single bytes
793                     src_len,        // Number of bytes
794                     bytes_per_line, // Num bytes per line
795                     base_addr,      // Base address
796                     0, 0);          // Bitfield info
797 }
798