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 
GetAPInt(const DataExtractor & data,lldb::offset_t * offset_ptr,lldb::offset_t byte_size)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 
DumpAPInt(Stream * s,const DataExtractor & data,lldb::offset_t offset,lldb::offset_t byte_size,bool is_signed,unsigned radix)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.
DumpInstructions(const DataExtractor & DE,Stream * s,ExecutionContextScope * exe_scope,offset_t start_offset,uint64_t base_addr,size_t number_of_instructions)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.
TryDumpSpecialEscapedChar(Stream & s,const char c)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.
DumpCharacter(Stream & s,const char c)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.2hhx", c);
216 }
217 
218 /// Dump a floating point type.
219 template <typename FloatT>
DumpFloatingPoint(std::ostringstream & ss,FloatT f)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>
GetMemoryTags(lldb::addr_t addr,size_t length,ExecutionContextScope * exe_scope)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 
printMemoryTags(const DataExtractor & DE,Stream * s,lldb::addr_t addr,size_t len,const std::optional<MemoryTagMap> & memory_tag_map)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 
GetFloatSemantics(const TargetSP & target_sp,size_t byte_size)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 
DumpDataExtractor(const DataExtractor & DE,Stream * s,offset_t start_offset,lldb::Format item_format,size_t item_byte_size,size_t item_count,size_t num_per_line,uint64_t base_addr,uint32_t item_bit_size,uint32_t item_bit_offset,ExecutionContextScope * exe_scope,bool show_memory_tags)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         if (Target::GetGlobalProperties()
624                 .ShowHexVariableValuesWithLeadingZeroes()) {
625           s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
626                     (int)(2 * item_byte_size), (int)(2 * item_byte_size),
627                     DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
628                                          item_bit_offset));
629         } else {
630           s->Printf(wantsuppercase ? "0x%" PRIX64 : "0x%" PRIx64,
631                     DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
632                                          item_bit_offset));
633         }
634         break;
635       default: {
636         assert(item_bit_size == 0 && item_bit_offset == 0);
637         const uint8_t *bytes =
638             (const uint8_t *)DE.GetData(&offset, item_byte_size);
639         if (bytes) {
640           s->PutCString("0x");
641           uint32_t idx;
642           if (DE.GetByteOrder() == eByteOrderBig) {
643             for (idx = 0; idx < item_byte_size; ++idx)
644               s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
645           } else {
646             for (idx = 0; idx < item_byte_size; ++idx)
647               s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
648                         bytes[item_byte_size - 1 - idx]);
649           }
650         }
651       } break;
652       }
653     } break;
654 
655     case eFormatFloat: {
656       TargetSP target_sp;
657       if (exe_scope)
658         target_sp = exe_scope->CalculateTarget();
659 
660       std::optional<unsigned> format_max_padding;
661       if (target_sp)
662         format_max_padding = target_sp->GetMaxZeroPaddingInFloatFormat();
663 
664       // Show full precision when printing float values
665       const unsigned format_precision = 0;
666 
667       const llvm::fltSemantics &semantics =
668           GetFloatSemantics(target_sp, item_byte_size);
669 
670       // Recalculate the byte size in case of a difference. This is possible
671       // when item_byte_size is 16 (128-bit), because you could get back the
672       // x87DoubleExtended semantics which has a byte size of 10 (80-bit).
673       const size_t semantics_byte_size =
674           (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
675       std::optional<llvm::APInt> apint =
676           GetAPInt(DE, &offset, semantics_byte_size);
677       if (apint) {
678         llvm::APFloat apfloat(semantics, *apint);
679         llvm::SmallVector<char, 256> sv;
680         if (format_max_padding)
681           apfloat.toString(sv, format_precision, *format_max_padding);
682         else
683           apfloat.toString(sv, format_precision);
684         s->AsRawOstream() << sv;
685       } else {
686         s->Format("error: unsupported byte size ({0}) for float format",
687                   item_byte_size);
688         return offset;
689       }
690     } break;
691 
692     case eFormatUnicode16:
693       s->Printf("U+%4.4x", DE.GetU16(&offset));
694       break;
695 
696     case eFormatUnicode32:
697       s->Printf("U+0x%8.8x", DE.GetU32(&offset));
698       break;
699 
700     case eFormatAddressInfo: {
701       addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
702                                          item_bit_offset);
703       s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
704                 (int)(2 * item_byte_size), addr);
705       if (exe_scope) {
706         TargetSP target_sp(exe_scope->CalculateTarget());
707         lldb_private::Address so_addr;
708         if (target_sp) {
709           if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
710                                                                  so_addr)) {
711             s->PutChar(' ');
712             so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
713                          Address::DumpStyleModuleWithFileAddress);
714           } else {
715             so_addr.SetOffset(addr);
716             so_addr.Dump(s, exe_scope,
717                          Address::DumpStyleResolvedPointerDescription);
718             if (ProcessSP process_sp = exe_scope->CalculateProcess()) {
719               if (ABISP abi_sp = process_sp->GetABI()) {
720                 addr_t addr_fixed = abi_sp->FixCodeAddress(addr);
721                 if (target_sp->GetSectionLoadList().ResolveLoadAddress(
722                         addr_fixed, so_addr)) {
723                   s->PutChar(' ');
724                   s->Printf("(0x%*.*" PRIx64 ")", (int)(2 * item_byte_size),
725                             (int)(2 * item_byte_size), addr_fixed);
726                   s->PutChar(' ');
727                   so_addr.Dump(s, exe_scope,
728                                Address::DumpStyleResolvedDescription,
729                                Address::DumpStyleModuleWithFileAddress);
730                 }
731               }
732             }
733           }
734         }
735       }
736     } break;
737 
738     case eFormatHexFloat:
739       if (sizeof(float) == item_byte_size) {
740         char float_cstr[256];
741         llvm::APFloat ap_float(DE.GetFloat(&offset));
742         ap_float.convertToHexString(float_cstr, 0, false,
743                                     llvm::APFloat::rmNearestTiesToEven);
744         s->Printf("%s", float_cstr);
745         break;
746       } else if (sizeof(double) == item_byte_size) {
747         char float_cstr[256];
748         llvm::APFloat ap_float(DE.GetDouble(&offset));
749         ap_float.convertToHexString(float_cstr, 0, false,
750                                     llvm::APFloat::rmNearestTiesToEven);
751         s->Printf("%s", float_cstr);
752         break;
753       } else {
754         s->Printf("error: unsupported byte size (%" PRIu64
755                   ") for hex float format",
756                   (uint64_t)item_byte_size);
757         return offset;
758       }
759       break;
760 
761     // please keep the single-item formats below in sync with
762     // FormatManager::GetSingleItemFormat if you fail to do so, users will
763     // start getting different outputs depending on internal implementation
764     // details they should not care about ||
765     case eFormatVectorOfChar: //   ||
766       s->PutChar('{');        //   \/
767       offset =
768           DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size,
769                             item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
770       s->PutChar('}');
771       break;
772 
773     case eFormatVectorOfSInt8:
774       s->PutChar('{');
775       offset =
776           DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size,
777                             item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
778       s->PutChar('}');
779       break;
780 
781     case eFormatVectorOfUInt8:
782       s->PutChar('{');
783       offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size,
784                                  item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
785       s->PutChar('}');
786       break;
787 
788     case eFormatVectorOfSInt16:
789       s->PutChar('{');
790       offset = DumpDataExtractor(
791           DE, s, offset, eFormatDecimal, sizeof(uint16_t),
792           item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t),
793           LLDB_INVALID_ADDRESS, 0, 0);
794       s->PutChar('}');
795       break;
796 
797     case eFormatVectorOfUInt16:
798       s->PutChar('{');
799       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t),
800                                  item_byte_size / sizeof(uint16_t),
801                                  item_byte_size / sizeof(uint16_t),
802                                  LLDB_INVALID_ADDRESS, 0, 0);
803       s->PutChar('}');
804       break;
805 
806     case eFormatVectorOfSInt32:
807       s->PutChar('{');
808       offset = DumpDataExtractor(
809           DE, s, offset, eFormatDecimal, sizeof(uint32_t),
810           item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t),
811           LLDB_INVALID_ADDRESS, 0, 0);
812       s->PutChar('}');
813       break;
814 
815     case eFormatVectorOfUInt32:
816       s->PutChar('{');
817       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t),
818                                  item_byte_size / sizeof(uint32_t),
819                                  item_byte_size / sizeof(uint32_t),
820                                  LLDB_INVALID_ADDRESS, 0, 0);
821       s->PutChar('}');
822       break;
823 
824     case eFormatVectorOfSInt64:
825       s->PutChar('{');
826       offset = DumpDataExtractor(
827           DE, s, offset, eFormatDecimal, sizeof(uint64_t),
828           item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t),
829           LLDB_INVALID_ADDRESS, 0, 0);
830       s->PutChar('}');
831       break;
832 
833     case eFormatVectorOfUInt64:
834       s->PutChar('{');
835       offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t),
836                                  item_byte_size / sizeof(uint64_t),
837                                  item_byte_size / sizeof(uint64_t),
838                                  LLDB_INVALID_ADDRESS, 0, 0);
839       s->PutChar('}');
840       break;
841 
842     case eFormatVectorOfFloat16:
843       s->PutChar('{');
844       offset =
845           DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2,
846                             item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
847       s->PutChar('}');
848       break;
849 
850     case eFormatVectorOfFloat32:
851       s->PutChar('{');
852       offset =
853           DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4,
854                             item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
855       s->PutChar('}');
856       break;
857 
858     case eFormatVectorOfFloat64:
859       s->PutChar('{');
860       offset =
861           DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8,
862                             item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
863       s->PutChar('}');
864       break;
865 
866     case eFormatVectorOfUInt128:
867       s->PutChar('{');
868       offset =
869           DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16,
870                             item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
871       s->PutChar('}');
872       break;
873     }
874   }
875 
876   // If anything was printed we want to catch the end of the last line.
877   // Since we will exit the for loop above before we get a chance to append to
878   // it normally.
879   if (offset > line_start_offset) {
880     if (item_format == eFormatBytesWithASCII) {
881       s->Printf("%*s",
882                 static_cast<int>(
883                     (num_per_line - (offset - line_start_offset)) * 3 + 2),
884                 "");
885       DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
886                         offset - line_start_offset, SIZE_MAX,
887                         LLDB_INVALID_ADDRESS, 0, 0);
888     }
889 
890     if (base_addr != LLDB_INVALID_ADDRESS && memory_tag_map) {
891       size_t line_len = offset - line_start_offset;
892       lldb::addr_t line_base = base_addr + (offset - start_offset - line_len) /
893                                                DE.getTargetByteSize();
894       printMemoryTags(DE, s, line_base, line_len, memory_tag_map);
895     }
896   }
897 
898   return offset; // Return the offset at which we ended up
899 }
900 
DumpHexBytes(Stream * s,const void * src,size_t src_len,uint32_t bytes_per_line,lldb::addr_t base_addr)901 void lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len,
902                                 uint32_t bytes_per_line,
903                                 lldb::addr_t base_addr) {
904   DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4);
905   DumpDataExtractor(data, s,
906                     0,                  // Offset into "src"
907                     lldb::eFormatBytes, // Dump as hex bytes
908                     1,              // Size of each item is 1 for single bytes
909                     src_len,        // Number of bytes
910                     bytes_per_line, // Num bytes per line
911                     base_addr,      // Base address
912                     0, 0);          // Bitfield info
913 }
914