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