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