1317027Sdim//===-- DumpDataExtractor.cpp -----------------------------------*- C++ -*-===//
2317027Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317027Sdim//
7317027Sdim//===----------------------------------------------------------------------===//
8317027Sdim
9317027Sdim#include "lldb/Core/DumpDataExtractor.h"
10317027Sdim
11344779Sdim#include "lldb/lldb-defines.h"
12344779Sdim#include "lldb/lldb-forward.h"
13317027Sdim
14344779Sdim#include "lldb/Core/Address.h"
15317027Sdim#include "lldb/Core/Disassembler.h"
16344779Sdim#include "lldb/Core/ModuleList.h"
17317027Sdim#include "lldb/Target/ExecutionContext.h"
18317027Sdim#include "lldb/Target/ExecutionContextScope.h"
19317027Sdim#include "lldb/Target/SectionLoadList.h"
20317027Sdim#include "lldb/Target/Target.h"
21317027Sdim#include "lldb/Utility/DataExtractor.h"
22360784Sdim#include "lldb/Utility/Log.h"
23317027Sdim#include "lldb/Utility/Stream.h"
24317027Sdim
25344779Sdim#include "llvm/ADT/APFloat.h"
26344779Sdim#include "llvm/ADT/APInt.h"
27344779Sdim#include "llvm/ADT/ArrayRef.h"
28360784Sdim#include "llvm/ADT/Optional.h"
29344779Sdim#include "llvm/ADT/SmallVector.h"
30317027Sdim
31344779Sdim#include <limits>
32344779Sdim#include <memory>
33344779Sdim#include <string>
34317027Sdim
35344779Sdim#include <assert.h>
36344779Sdim#include <ctype.h>
37344779Sdim#include <inttypes.h>
38344779Sdim#include <math.h>
39317027Sdim
40317027Sdim#include <bitset>
41317027Sdim#include <sstream>
42317027Sdim
43317027Sdimusing namespace lldb_private;
44317027Sdimusing namespace lldb;
45317027Sdim
46317027Sdim#define NON_PRINTABLE_CHAR '.'
47317027Sdim
48317027Sdimstatic float half2float(uint16_t half) {
49317027Sdim  union {
50317027Sdim    float f;
51317027Sdim    uint32_t u;
52317027Sdim  } u;
53317027Sdim  int32_t v = (int16_t)half;
54317027Sdim
55317027Sdim  if (0 == (v & 0x7c00)) {
56317027Sdim    u.u = v & 0x80007FFFU;
57317027Sdim    return u.f * ldexpf(1, 125);
58317027Sdim  }
59317027Sdim
60317027Sdim  v <<= 13;
61317027Sdim  u.u = v | 0x70000000U;
62317027Sdim  return u.f * ldexpf(1, -112);
63317027Sdim}
64317027Sdim
65360784Sdimstatic llvm::Optional<llvm::APInt> GetAPInt(const DataExtractor &data,
66360784Sdim                                            lldb::offset_t *offset_ptr,
67360784Sdim                                            lldb::offset_t byte_size) {
68360784Sdim  if (byte_size == 0)
69360784Sdim    return llvm::None;
70360784Sdim
71317027Sdim  llvm::SmallVector<uint64_t, 2> uint64_array;
72317027Sdim  lldb::offset_t bytes_left = byte_size;
73317027Sdim  uint64_t u64;
74317027Sdim  const lldb::ByteOrder byte_order = data.GetByteOrder();
75317027Sdim  if (byte_order == lldb::eByteOrderLittle) {
76317027Sdim    while (bytes_left > 0) {
77317027Sdim      if (bytes_left >= 8) {
78317027Sdim        u64 = data.GetU64(offset_ptr);
79317027Sdim        bytes_left -= 8;
80317027Sdim      } else {
81317027Sdim        u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
82317027Sdim        bytes_left = 0;
83317027Sdim      }
84317027Sdim      uint64_array.push_back(u64);
85317027Sdim    }
86360784Sdim    return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
87317027Sdim  } else if (byte_order == lldb::eByteOrderBig) {
88317027Sdim    lldb::offset_t be_offset = *offset_ptr + byte_size;
89317027Sdim    lldb::offset_t temp_offset;
90317027Sdim    while (bytes_left > 0) {
91317027Sdim      if (bytes_left >= 8) {
92317027Sdim        be_offset -= 8;
93317027Sdim        temp_offset = be_offset;
94317027Sdim        u64 = data.GetU64(&temp_offset);
95317027Sdim        bytes_left -= 8;
96317027Sdim      } else {
97317027Sdim        be_offset -= bytes_left;
98317027Sdim        temp_offset = be_offset;
99317027Sdim        u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
100317027Sdim        bytes_left = 0;
101317027Sdim      }
102317027Sdim      uint64_array.push_back(u64);
103317027Sdim    }
104317027Sdim    *offset_ptr += byte_size;
105360784Sdim    return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
106317027Sdim  }
107360784Sdim  return llvm::None;
108317027Sdim}
109317027Sdim
110317027Sdimstatic lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data,
111317027Sdim                                lldb::offset_t offset, lldb::offset_t byte_size,
112317027Sdim                                bool is_signed, unsigned radix) {
113360784Sdim  llvm::Optional<llvm::APInt> apint = GetAPInt(data, &offset, byte_size);
114360784Sdim  if (apint.hasValue()) {
115360784Sdim    std::string apint_str(apint.getValue().toString(radix, is_signed));
116317027Sdim    switch (radix) {
117317027Sdim    case 2:
118317027Sdim      s->Write("0b", 2);
119317027Sdim      break;
120317027Sdim    case 8:
121317027Sdim      s->Write("0", 1);
122317027Sdim      break;
123317027Sdim    case 10:
124317027Sdim      break;
125317027Sdim    }
126317027Sdim    s->Write(apint_str.c_str(), apint_str.size());
127317027Sdim  }
128317027Sdim  return offset;
129317027Sdim}
130317027Sdim
131317027Sdimlldb::offset_t lldb_private::DumpDataExtractor(
132317027Sdim    const DataExtractor &DE, Stream *s, offset_t start_offset,
133317027Sdim    lldb::Format item_format, size_t item_byte_size, size_t item_count,
134317027Sdim    size_t num_per_line, uint64_t base_addr,
135317027Sdim    uint32_t item_bit_size,   // If zero, this is not a bitfield value, if
136317027Sdim                              // non-zero, the value is a bitfield
137317027Sdim    uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the
138317027Sdim                              // shift amount to apply to a bitfield
139317027Sdim    ExecutionContextScope *exe_scope) {
140317027Sdim  if (s == nullptr)
141317027Sdim    return start_offset;
142317027Sdim
143317027Sdim  if (item_format == eFormatPointer) {
144317027Sdim    if (item_byte_size != 4 && item_byte_size != 8)
145317027Sdim      item_byte_size = s->GetAddressByteSize();
146317027Sdim  }
147317027Sdim
148317027Sdim  offset_t offset = start_offset;
149317027Sdim
150317027Sdim  if (item_format == eFormatInstruction) {
151317027Sdim    TargetSP target_sp;
152317027Sdim    if (exe_scope)
153317027Sdim      target_sp = exe_scope->CalculateTarget();
154317027Sdim    if (target_sp) {
155317027Sdim      DisassemblerSP disassembler_sp(Disassembler::FindPlugin(
156320970Sdim          target_sp->GetArchitecture(),
157320970Sdim          target_sp->GetDisassemblyFlavor(), nullptr));
158317027Sdim      if (disassembler_sp) {
159317027Sdim        lldb::addr_t addr = base_addr + start_offset;
160317027Sdim        lldb_private::Address so_addr;
161317027Sdim        bool data_from_file = true;
162317027Sdim        if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
163317027Sdim          data_from_file = false;
164317027Sdim        } else {
165317027Sdim          if (target_sp->GetSectionLoadList().IsEmpty() ||
166317027Sdim              !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
167317027Sdim            so_addr.SetRawAddress(addr);
168317027Sdim        }
169317027Sdim
170317027Sdim        size_t bytes_consumed = disassembler_sp->DecodeInstructions(
171317027Sdim            so_addr, DE, start_offset, item_count, false, data_from_file);
172317027Sdim
173317027Sdim        if (bytes_consumed) {
174317027Sdim          offset += bytes_consumed;
175317027Sdim          const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
176317027Sdim          const bool show_bytes = true;
177317027Sdim          ExecutionContext exe_ctx;
178317027Sdim          exe_scope->CalculateExecutionContext(exe_ctx);
179317027Sdim          disassembler_sp->GetInstructionList().Dump(s, show_address,
180317027Sdim                                                     show_bytes, &exe_ctx);
181317027Sdim        }
182317027Sdim      }
183317027Sdim    } else
184317027Sdim      s->Printf("invalid target");
185317027Sdim
186317027Sdim    return offset;
187317027Sdim  }
188317027Sdim
189317027Sdim  if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) &&
190317027Sdim      item_byte_size > 8)
191317027Sdim    item_format = eFormatHex;
192317027Sdim
193317027Sdim  lldb::offset_t line_start_offset = start_offset;
194317027Sdim  for (uint32_t count = 0; DE.ValidOffset(offset) && count < item_count;
195317027Sdim       ++count) {
196317027Sdim    if ((count % num_per_line) == 0) {
197317027Sdim      if (count > 0) {
198317027Sdim        if (item_format == eFormatBytesWithASCII &&
199317027Sdim            offset > line_start_offset) {
200317027Sdim          s->Printf("%*s",
201317027Sdim                    static_cast<int>(
202317027Sdim                        (num_per_line - (offset - line_start_offset)) * 3 + 2),
203317027Sdim                    "");
204317027Sdim          DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
205317027Sdim                            offset - line_start_offset, SIZE_MAX,
206317027Sdim                            LLDB_INVALID_ADDRESS, 0, 0);
207317027Sdim        }
208317027Sdim        s->EOL();
209317027Sdim      }
210317027Sdim      if (base_addr != LLDB_INVALID_ADDRESS)
211317027Sdim        s->Printf("0x%8.8" PRIx64 ": ",
212317027Sdim                  (uint64_t)(base_addr +
213317027Sdim                             (offset - start_offset) / DE.getTargetByteSize()));
214317027Sdim
215317027Sdim      line_start_offset = offset;
216317027Sdim    } else if (item_format != eFormatChar &&
217317027Sdim               item_format != eFormatCharPrintable &&
218317027Sdim               item_format != eFormatCharArray && count > 0) {
219317027Sdim      s->PutChar(' ');
220317027Sdim    }
221317027Sdim
222317027Sdim    switch (item_format) {
223317027Sdim    case eFormatBoolean:
224317027Sdim      if (item_byte_size <= 8)
225317027Sdim        s->Printf("%s", DE.GetMaxU64Bitfield(&offset, item_byte_size,
226317027Sdim                                             item_bit_size, item_bit_offset)
227317027Sdim                            ? "true"
228317027Sdim                            : "false");
229317027Sdim      else {
230317027Sdim        s->Printf("error: unsupported byte size (%" PRIu64
231317027Sdim                  ") for boolean format",
232317027Sdim                  (uint64_t)item_byte_size);
233317027Sdim        return offset;
234317027Sdim      }
235317027Sdim      break;
236317027Sdim
237317027Sdim    case eFormatBinary:
238317027Sdim      if (item_byte_size <= 8) {
239317027Sdim        uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
240317027Sdim                                               item_bit_size, item_bit_offset);
241341825Sdim        // Avoid std::bitset<64>::to_string() since it is missing in earlier
242341825Sdim        // C++ libraries
243317027Sdim        std::string binary_value(64, '0');
244317027Sdim        std::bitset<64> bits(uval64);
245317027Sdim        for (uint32_t i = 0; i < 64; ++i)
246317027Sdim          if (bits[i])
247317027Sdim            binary_value[64 - 1 - i] = '1';
248317027Sdim        if (item_bit_size > 0)
249317027Sdim          s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
250317027Sdim        else if (item_byte_size > 0 && item_byte_size <= 8)
251317027Sdim          s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
252317027Sdim      } else {
253317027Sdim        const bool is_signed = false;
254317027Sdim        const unsigned radix = 2;
255317027Sdim        offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
256317027Sdim      }
257317027Sdim      break;
258317027Sdim
259317027Sdim    case eFormatBytes:
260317027Sdim    case eFormatBytesWithASCII:
261317027Sdim      for (uint32_t i = 0; i < item_byte_size; ++i) {
262317027Sdim        s->Printf("%2.2x", DE.GetU8(&offset));
263317027Sdim      }
264317027Sdim
265341825Sdim      // Put an extra space between the groups of bytes if more than one is
266341825Sdim      // being dumped in a group (item_byte_size is more than 1).
267317027Sdim      if (item_byte_size > 1)
268317027Sdim        s->PutChar(' ');
269317027Sdim      break;
270317027Sdim
271317027Sdim    case eFormatChar:
272317027Sdim    case eFormatCharPrintable:
273317027Sdim    case eFormatCharArray: {
274327952Sdim      // Reject invalid item_byte_size.
275327952Sdim      if (item_byte_size > 8) {
276327952Sdim        s->Printf("error: unsupported byte size (%" PRIu64 ") for char format",
277327952Sdim                  (uint64_t)item_byte_size);
278327952Sdim        return offset;
279327952Sdim      }
280327952Sdim
281341825Sdim      // If we are only printing one character surround it with single quotes
282317027Sdim      if (item_count == 1 && item_format == eFormatChar)
283317027Sdim        s->PutChar('\'');
284317027Sdim
285317027Sdim      const uint64_t ch = DE.GetMaxU64Bitfield(&offset, item_byte_size,
286317027Sdim                                               item_bit_size, item_bit_offset);
287317027Sdim      if (isprint(ch))
288317027Sdim        s->Printf("%c", (char)ch);
289317027Sdim      else if (item_format != eFormatCharPrintable) {
290317027Sdim        switch (ch) {
291317027Sdim        case '\033':
292317027Sdim          s->Printf("\\e");
293317027Sdim          break;
294317027Sdim        case '\a':
295317027Sdim          s->Printf("\\a");
296317027Sdim          break;
297317027Sdim        case '\b':
298317027Sdim          s->Printf("\\b");
299317027Sdim          break;
300317027Sdim        case '\f':
301317027Sdim          s->Printf("\\f");
302317027Sdim          break;
303317027Sdim        case '\n':
304317027Sdim          s->Printf("\\n");
305317027Sdim          break;
306317027Sdim        case '\r':
307317027Sdim          s->Printf("\\r");
308317027Sdim          break;
309317027Sdim        case '\t':
310317027Sdim          s->Printf("\\t");
311317027Sdim          break;
312317027Sdim        case '\v':
313317027Sdim          s->Printf("\\v");
314317027Sdim          break;
315317027Sdim        case '\0':
316317027Sdim          s->Printf("\\0");
317317027Sdim          break;
318317027Sdim        default:
319317027Sdim          if (item_byte_size == 1)
320317027Sdim            s->Printf("\\x%2.2x", (uint8_t)ch);
321317027Sdim          else
322317027Sdim            s->Printf("%" PRIu64, ch);
323317027Sdim          break;
324317027Sdim        }
325317027Sdim      } else {
326317027Sdim        s->PutChar(NON_PRINTABLE_CHAR);
327317027Sdim      }
328317027Sdim
329317027Sdim      // If we are only printing one character surround it with single quotes
330317027Sdim      if (item_count == 1 && item_format == eFormatChar)
331317027Sdim        s->PutChar('\'');
332317027Sdim    } break;
333317027Sdim
334317027Sdim    case eFormatEnum: // Print enum value as a signed integer when we don't get
335317027Sdim                      // the enum type
336317027Sdim    case eFormatDecimal:
337317027Sdim      if (item_byte_size <= 8)
338317027Sdim        s->Printf("%" PRId64,
339317027Sdim                  DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
340317027Sdim                                       item_bit_offset));
341317027Sdim      else {
342317027Sdim        const bool is_signed = true;
343317027Sdim        const unsigned radix = 10;
344317027Sdim        offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
345317027Sdim      }
346317027Sdim      break;
347317027Sdim
348317027Sdim    case eFormatUnsigned:
349317027Sdim      if (item_byte_size <= 8)
350317027Sdim        s->Printf("%" PRIu64,
351317027Sdim                  DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
352317027Sdim                                       item_bit_offset));
353317027Sdim      else {
354317027Sdim        const bool is_signed = false;
355317027Sdim        const unsigned radix = 10;
356317027Sdim        offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
357317027Sdim      }
358317027Sdim      break;
359317027Sdim
360317027Sdim    case eFormatOctal:
361317027Sdim      if (item_byte_size <= 8)
362317027Sdim        s->Printf("0%" PRIo64,
363317027Sdim                  DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
364317027Sdim                                       item_bit_offset));
365317027Sdim      else {
366317027Sdim        const bool is_signed = false;
367317027Sdim        const unsigned radix = 8;
368317027Sdim        offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
369317027Sdim      }
370317027Sdim      break;
371317027Sdim
372317027Sdim    case eFormatOSType: {
373317027Sdim      uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
374317027Sdim                                             item_bit_size, item_bit_offset);
375317027Sdim      s->PutChar('\'');
376317027Sdim      for (uint32_t i = 0; i < item_byte_size; ++i) {
377317027Sdim        uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
378317027Sdim        if (isprint(ch))
379317027Sdim          s->Printf("%c", ch);
380317027Sdim        else {
381317027Sdim          switch (ch) {
382317027Sdim          case '\033':
383317027Sdim            s->Printf("\\e");
384317027Sdim            break;
385317027Sdim          case '\a':
386317027Sdim            s->Printf("\\a");
387317027Sdim            break;
388317027Sdim          case '\b':
389317027Sdim            s->Printf("\\b");
390317027Sdim            break;
391317027Sdim          case '\f':
392317027Sdim            s->Printf("\\f");
393317027Sdim            break;
394317027Sdim          case '\n':
395317027Sdim            s->Printf("\\n");
396317027Sdim            break;
397317027Sdim          case '\r':
398317027Sdim            s->Printf("\\r");
399317027Sdim            break;
400317027Sdim          case '\t':
401317027Sdim            s->Printf("\\t");
402317027Sdim            break;
403317027Sdim          case '\v':
404317027Sdim            s->Printf("\\v");
405317027Sdim            break;
406317027Sdim          case '\0':
407317027Sdim            s->Printf("\\0");
408317027Sdim            break;
409317027Sdim          default:
410317027Sdim            s->Printf("\\x%2.2x", ch);
411317027Sdim            break;
412317027Sdim          }
413317027Sdim        }
414317027Sdim      }
415317027Sdim      s->PutChar('\'');
416317027Sdim    } break;
417317027Sdim
418317027Sdim    case eFormatCString: {
419317027Sdim      const char *cstr = DE.GetCStr(&offset);
420317027Sdim
421317027Sdim      if (!cstr) {
422317027Sdim        s->Printf("NULL");
423317027Sdim        offset = LLDB_INVALID_OFFSET;
424317027Sdim      } else {
425317027Sdim        s->PutChar('\"');
426317027Sdim
427317027Sdim        while (const char c = *cstr) {
428317027Sdim          if (isprint(c)) {
429317027Sdim            s->PutChar(c);
430317027Sdim          } else {
431317027Sdim            switch (c) {
432317027Sdim            case '\033':
433317027Sdim              s->Printf("\\e");
434317027Sdim              break;
435317027Sdim            case '\a':
436317027Sdim              s->Printf("\\a");
437317027Sdim              break;
438317027Sdim            case '\b':
439317027Sdim              s->Printf("\\b");
440317027Sdim              break;
441317027Sdim            case '\f':
442317027Sdim              s->Printf("\\f");
443317027Sdim              break;
444317027Sdim            case '\n':
445317027Sdim              s->Printf("\\n");
446317027Sdim              break;
447317027Sdim            case '\r':
448317027Sdim              s->Printf("\\r");
449317027Sdim              break;
450317027Sdim            case '\t':
451317027Sdim              s->Printf("\\t");
452317027Sdim              break;
453317027Sdim            case '\v':
454317027Sdim              s->Printf("\\v");
455317027Sdim              break;
456317027Sdim            default:
457317027Sdim              s->Printf("\\x%2.2x", c);
458317027Sdim              break;
459317027Sdim            }
460317027Sdim          }
461317027Sdim
462317027Sdim          ++cstr;
463317027Sdim        }
464317027Sdim
465317027Sdim        s->PutChar('\"');
466317027Sdim      }
467317027Sdim    } break;
468317027Sdim
469317027Sdim    case eFormatPointer:
470360784Sdim      DumpAddress(s->AsRawOstream(),
471360784Sdim                  DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
472360784Sdim                                       item_bit_offset),
473360784Sdim                  sizeof(addr_t));
474317027Sdim      break;
475317027Sdim
476317027Sdim    case eFormatComplexInteger: {
477317027Sdim      size_t complex_int_byte_size = item_byte_size / 2;
478317027Sdim
479317027Sdim      if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) {
480317027Sdim        s->Printf("%" PRIu64,
481317027Sdim                  DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
482317027Sdim        s->Printf(" + %" PRIu64 "i",
483317027Sdim                  DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
484317027Sdim      } else {
485317027Sdim        s->Printf("error: unsupported byte size (%" PRIu64
486317027Sdim                  ") for complex integer format",
487317027Sdim                  (uint64_t)item_byte_size);
488317027Sdim        return offset;
489317027Sdim      }
490317027Sdim    } break;
491317027Sdim
492317027Sdim    case eFormatComplex:
493317027Sdim      if (sizeof(float) * 2 == item_byte_size) {
494317027Sdim        float f32_1 = DE.GetFloat(&offset);
495317027Sdim        float f32_2 = DE.GetFloat(&offset);
496317027Sdim
497317027Sdim        s->Printf("%g + %gi", f32_1, f32_2);
498317027Sdim        break;
499317027Sdim      } else if (sizeof(double) * 2 == item_byte_size) {
500317027Sdim        double d64_1 = DE.GetDouble(&offset);
501317027Sdim        double d64_2 = DE.GetDouble(&offset);
502317027Sdim
503317027Sdim        s->Printf("%lg + %lgi", d64_1, d64_2);
504317027Sdim        break;
505317027Sdim      } else if (sizeof(long double) * 2 == item_byte_size) {
506317027Sdim        long double ld64_1 = DE.GetLongDouble(&offset);
507317027Sdim        long double ld64_2 = DE.GetLongDouble(&offset);
508317027Sdim        s->Printf("%Lg + %Lgi", ld64_1, ld64_2);
509317027Sdim        break;
510317027Sdim      } else {
511317027Sdim        s->Printf("error: unsupported byte size (%" PRIu64
512317027Sdim                  ") for complex float format",
513317027Sdim                  (uint64_t)item_byte_size);
514317027Sdim        return offset;
515317027Sdim      }
516317027Sdim      break;
517317027Sdim
518317027Sdim    default:
519317027Sdim    case eFormatDefault:
520317027Sdim    case eFormatHex:
521317027Sdim    case eFormatHexUppercase: {
522317027Sdim      bool wantsuppercase = (item_format == eFormatHexUppercase);
523317027Sdim      switch (item_byte_size) {
524317027Sdim      case 1:
525317027Sdim      case 2:
526317027Sdim      case 4:
527317027Sdim      case 8:
528317027Sdim        s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
529317027Sdim                  (int)(2 * item_byte_size), (int)(2 * item_byte_size),
530317027Sdim                  DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
531317027Sdim                                       item_bit_offset));
532317027Sdim        break;
533317027Sdim      default: {
534317027Sdim        assert(item_bit_size == 0 && item_bit_offset == 0);
535317027Sdim        const uint8_t *bytes =
536317027Sdim            (const uint8_t *)DE.GetData(&offset, item_byte_size);
537317027Sdim        if (bytes) {
538317027Sdim          s->PutCString("0x");
539317027Sdim          uint32_t idx;
540317027Sdim          if (DE.GetByteOrder() == eByteOrderBig) {
541317027Sdim            for (idx = 0; idx < item_byte_size; ++idx)
542317027Sdim              s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
543317027Sdim          } else {
544317027Sdim            for (idx = 0; idx < item_byte_size; ++idx)
545317027Sdim              s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
546317027Sdim                        bytes[item_byte_size - 1 - idx]);
547317027Sdim          }
548317027Sdim        }
549317027Sdim      } break;
550317027Sdim      }
551317027Sdim    } break;
552317027Sdim
553317027Sdim    case eFormatFloat: {
554317027Sdim      TargetSP target_sp;
555353358Sdim      bool used_upfloat = false;
556317027Sdim      if (exe_scope)
557317027Sdim        target_sp = exe_scope->CalculateTarget();
558317027Sdim      if (target_sp) {
559360784Sdim        auto type_system_or_err =
560360784Sdim            target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
561360784Sdim        if (!type_system_or_err) {
562360784Sdim          llvm::consumeError(type_system_or_err.takeError());
563360784Sdim        } else {
564360784Sdim          auto &type_system = *type_system_or_err;
565360784Sdim          llvm::SmallVector<char, 256> sv;
566360784Sdim          // Show full precision when printing float values
567360784Sdim          const unsigned format_precision = 0;
568360784Sdim          const unsigned format_max_padding =
569360784Sdim              target_sp->GetMaxZeroPaddingInFloatFormat();
570317027Sdim
571360784Sdim          const auto &semantics =
572360784Sdim              type_system.GetFloatTypeSemantics(item_byte_size);
573317027Sdim
574360784Sdim          // Recalculate the byte size in case of a difference. This is possible
575360784Sdim          // when item_byte_size is 16 (128-bit), because you could get back the
576360784Sdim          // x87DoubleExtended semantics which has a byte size of 10 (80-bit).
577360784Sdim          const size_t semantics_byte_size =
578360784Sdim              (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
579360784Sdim          llvm::Optional<llvm::APInt> apint =
580360784Sdim              GetAPInt(DE, &offset, semantics_byte_size);
581360784Sdim          if (apint.hasValue()) {
582360784Sdim            llvm::APFloat apfloat(semantics, apint.getValue());
583360784Sdim            apfloat.toString(sv, format_precision, format_max_padding);
584317027Sdim            if (!sv.empty()) {
585317027Sdim              s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
586353358Sdim              used_upfloat = true;
587317027Sdim            }
588317027Sdim          }
589317027Sdim        }
590317027Sdim      }
591317027Sdim
592353358Sdim      if (!used_upfloat) {
593317027Sdim        std::ostringstream ss;
594317027Sdim        if (item_byte_size == sizeof(float) || item_byte_size == 2) {
595317027Sdim          float f;
596317027Sdim          if (item_byte_size == 2) {
597317027Sdim            uint16_t half = DE.GetU16(&offset);
598317027Sdim            f = half2float(half);
599317027Sdim          } else {
600317027Sdim            f = DE.GetFloat(&offset);
601317027Sdim          }
602317027Sdim          ss.precision(std::numeric_limits<float>::digits10);
603317027Sdim          ss << f;
604317027Sdim        } else if (item_byte_size == sizeof(double)) {
605317027Sdim          ss.precision(std::numeric_limits<double>::digits10);
606317027Sdim          ss << DE.GetDouble(&offset);
607317027Sdim        } else if (item_byte_size == sizeof(long double) ||
608317027Sdim                   item_byte_size == 10) {
609317027Sdim          ss.precision(std::numeric_limits<long double>::digits10);
610317027Sdim          ss << DE.GetLongDouble(&offset);
611317027Sdim        } else {
612317027Sdim          s->Printf("error: unsupported byte size (%" PRIu64
613317027Sdim                    ") for float format",
614317027Sdim                    (uint64_t)item_byte_size);
615317027Sdim          return offset;
616317027Sdim        }
617317027Sdim        ss.flush();
618317027Sdim        s->Printf("%s", ss.str().c_str());
619317027Sdim      }
620317027Sdim    } break;
621317027Sdim
622317027Sdim    case eFormatUnicode16:
623317027Sdim      s->Printf("U+%4.4x", DE.GetU16(&offset));
624317027Sdim      break;
625317027Sdim
626317027Sdim    case eFormatUnicode32:
627317027Sdim      s->Printf("U+0x%8.8x", DE.GetU32(&offset));
628317027Sdim      break;
629317027Sdim
630317027Sdim    case eFormatAddressInfo: {
631317027Sdim      addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
632317027Sdim                                         item_bit_offset);
633317027Sdim      s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
634317027Sdim                (int)(2 * item_byte_size), addr);
635317027Sdim      if (exe_scope) {
636317027Sdim        TargetSP target_sp(exe_scope->CalculateTarget());
637317027Sdim        lldb_private::Address so_addr;
638317027Sdim        if (target_sp) {
639317027Sdim          if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
640317027Sdim                                                                 so_addr)) {
641317027Sdim            s->PutChar(' ');
642317027Sdim            so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
643317027Sdim                         Address::DumpStyleModuleWithFileAddress);
644317027Sdim          } else {
645317027Sdim            so_addr.SetOffset(addr);
646317027Sdim            so_addr.Dump(s, exe_scope,
647317027Sdim                         Address::DumpStyleResolvedPointerDescription);
648317027Sdim          }
649317027Sdim        }
650317027Sdim      }
651317027Sdim    } break;
652317027Sdim
653317027Sdim    case eFormatHexFloat:
654317027Sdim      if (sizeof(float) == item_byte_size) {
655317027Sdim        char float_cstr[256];
656317027Sdim        llvm::APFloat ap_float(DE.GetFloat(&offset));
657317027Sdim        ap_float.convertToHexString(float_cstr, 0, false,
658317027Sdim                                    llvm::APFloat::rmNearestTiesToEven);
659317027Sdim        s->Printf("%s", float_cstr);
660317027Sdim        break;
661317027Sdim      } else if (sizeof(double) == item_byte_size) {
662317027Sdim        char float_cstr[256];
663317027Sdim        llvm::APFloat ap_float(DE.GetDouble(&offset));
664317027Sdim        ap_float.convertToHexString(float_cstr, 0, false,
665317027Sdim                                    llvm::APFloat::rmNearestTiesToEven);
666317027Sdim        s->Printf("%s", float_cstr);
667317027Sdim        break;
668317027Sdim      } else {
669317027Sdim        s->Printf("error: unsupported byte size (%" PRIu64
670317027Sdim                  ") for hex float format",
671317027Sdim                  (uint64_t)item_byte_size);
672317027Sdim        return offset;
673317027Sdim      }
674317027Sdim      break;
675317027Sdim
676317027Sdim    // please keep the single-item formats below in sync with
677341825Sdim    // FormatManager::GetSingleItemFormat if you fail to do so, users will
678341825Sdim    // start getting different outputs depending on internal implementation
679341825Sdim    // details they should not care about ||
680317027Sdim    case eFormatVectorOfChar: //   ||
681317027Sdim      s->PutChar('{');        //   \/
682317027Sdim      offset =
683317027Sdim          DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size,
684317027Sdim                            item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
685317027Sdim      s->PutChar('}');
686317027Sdim      break;
687317027Sdim
688317027Sdim    case eFormatVectorOfSInt8:
689317027Sdim      s->PutChar('{');
690317027Sdim      offset =
691317027Sdim          DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size,
692317027Sdim                            item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
693317027Sdim      s->PutChar('}');
694317027Sdim      break;
695317027Sdim
696317027Sdim    case eFormatVectorOfUInt8:
697317027Sdim      s->PutChar('{');
698317027Sdim      offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size,
699317027Sdim                                 item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
700317027Sdim      s->PutChar('}');
701317027Sdim      break;
702317027Sdim
703317027Sdim    case eFormatVectorOfSInt16:
704317027Sdim      s->PutChar('{');
705317027Sdim      offset = DumpDataExtractor(
706317027Sdim          DE, s, offset, eFormatDecimal, sizeof(uint16_t),
707317027Sdim          item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t),
708317027Sdim          LLDB_INVALID_ADDRESS, 0, 0);
709317027Sdim      s->PutChar('}');
710317027Sdim      break;
711317027Sdim
712317027Sdim    case eFormatVectorOfUInt16:
713317027Sdim      s->PutChar('{');
714317027Sdim      offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t),
715317027Sdim                                 item_byte_size / sizeof(uint16_t),
716317027Sdim                                 item_byte_size / sizeof(uint16_t),
717317027Sdim                                 LLDB_INVALID_ADDRESS, 0, 0);
718317027Sdim      s->PutChar('}');
719317027Sdim      break;
720317027Sdim
721317027Sdim    case eFormatVectorOfSInt32:
722317027Sdim      s->PutChar('{');
723317027Sdim      offset = DumpDataExtractor(
724317027Sdim          DE, s, offset, eFormatDecimal, sizeof(uint32_t),
725317027Sdim          item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t),
726317027Sdim          LLDB_INVALID_ADDRESS, 0, 0);
727317027Sdim      s->PutChar('}');
728317027Sdim      break;
729317027Sdim
730317027Sdim    case eFormatVectorOfUInt32:
731317027Sdim      s->PutChar('{');
732317027Sdim      offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t),
733317027Sdim                                 item_byte_size / sizeof(uint32_t),
734317027Sdim                                 item_byte_size / sizeof(uint32_t),
735317027Sdim                                 LLDB_INVALID_ADDRESS, 0, 0);
736317027Sdim      s->PutChar('}');
737317027Sdim      break;
738317027Sdim
739317027Sdim    case eFormatVectorOfSInt64:
740317027Sdim      s->PutChar('{');
741317027Sdim      offset = DumpDataExtractor(
742317027Sdim          DE, s, offset, eFormatDecimal, sizeof(uint64_t),
743317027Sdim          item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t),
744317027Sdim          LLDB_INVALID_ADDRESS, 0, 0);
745317027Sdim      s->PutChar('}');
746317027Sdim      break;
747317027Sdim
748317027Sdim    case eFormatVectorOfUInt64:
749317027Sdim      s->PutChar('{');
750317027Sdim      offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t),
751317027Sdim                                 item_byte_size / sizeof(uint64_t),
752317027Sdim                                 item_byte_size / sizeof(uint64_t),
753317027Sdim                                 LLDB_INVALID_ADDRESS, 0, 0);
754317027Sdim      s->PutChar('}');
755317027Sdim      break;
756317027Sdim
757317027Sdim    case eFormatVectorOfFloat16:
758317027Sdim      s->PutChar('{');
759317027Sdim      offset =
760317027Sdim          DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2,
761317027Sdim                            item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
762317027Sdim      s->PutChar('}');
763317027Sdim      break;
764317027Sdim
765317027Sdim    case eFormatVectorOfFloat32:
766317027Sdim      s->PutChar('{');
767317027Sdim      offset =
768317027Sdim          DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4,
769317027Sdim                            item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
770317027Sdim      s->PutChar('}');
771317027Sdim      break;
772317027Sdim
773317027Sdim    case eFormatVectorOfFloat64:
774317027Sdim      s->PutChar('{');
775317027Sdim      offset =
776317027Sdim          DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8,
777317027Sdim                            item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
778317027Sdim      s->PutChar('}');
779317027Sdim      break;
780317027Sdim
781317027Sdim    case eFormatVectorOfUInt128:
782317027Sdim      s->PutChar('{');
783317027Sdim      offset =
784317027Sdim          DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16,
785317027Sdim                            item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
786317027Sdim      s->PutChar('}');
787317027Sdim      break;
788317027Sdim    }
789317027Sdim  }
790317027Sdim
791317027Sdim  if (item_format == eFormatBytesWithASCII && offset > line_start_offset) {
792317027Sdim    s->Printf("%*s", static_cast<int>(
793317027Sdim                         (num_per_line - (offset - line_start_offset)) * 3 + 2),
794317027Sdim              "");
795317027Sdim    DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
796317027Sdim                      offset - line_start_offset, SIZE_MAX,
797317027Sdim                      LLDB_INVALID_ADDRESS, 0, 0);
798317027Sdim  }
799317027Sdim  return offset; // Return the offset at which we ended up
800317027Sdim}
801317027Sdim
802317027Sdimvoid lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len,
803317027Sdim                                uint32_t bytes_per_line,
804317027Sdim                                lldb::addr_t base_addr) {
805317027Sdim  DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4);
806317027Sdim  DumpDataExtractor(data, s,
807317027Sdim                    0,                  // Offset into "src"
808317027Sdim                    lldb::eFormatBytes, // Dump as hex bytes
809317027Sdim                    1,              // Size of each item is 1 for single bytes
810317027Sdim                    src_len,        // Number of bytes
811317027Sdim                    bytes_per_line, // Num bytes per line
812317027Sdim                    base_addr,      // Base address
813317027Sdim                    0, 0);          // Bitfield info
814317027Sdim}
815