aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp913
1 files changed, 913 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp b/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp
new file mode 100644
index 000000000000..826edd7bab04
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp
@@ -0,0 +1,913 @@
+//===-- DumpDataExtractor.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DumpDataExtractor.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-forward.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/MemoryTagManager.h"
+#include "lldb/Target/MemoryTagMap.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Stream.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include <limits>
+#include <memory>
+#include <string>
+
+#include <cassert>
+#include <cctype>
+#include <cinttypes>
+#include <cmath>
+
+#include <bitset>
+#include <optional>
+#include <sstream>
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define NON_PRINTABLE_CHAR '.'
+
+static std::optional<llvm::APInt> GetAPInt(const DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ lldb::offset_t byte_size) {
+ if (byte_size == 0)
+ return std::nullopt;
+
+ llvm::SmallVector<uint64_t, 2> uint64_array;
+ lldb::offset_t bytes_left = byte_size;
+ uint64_t u64;
+ const lldb::ByteOrder byte_order = data.GetByteOrder();
+ if (byte_order == lldb::eByteOrderLittle) {
+ while (bytes_left > 0) {
+ if (bytes_left >= 8) {
+ u64 = data.GetU64(offset_ptr);
+ bytes_left -= 8;
+ } else {
+ u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ } else if (byte_order == lldb::eByteOrderBig) {
+ lldb::offset_t be_offset = *offset_ptr + byte_size;
+ lldb::offset_t temp_offset;
+ while (bytes_left > 0) {
+ if (bytes_left >= 8) {
+ be_offset -= 8;
+ temp_offset = be_offset;
+ u64 = data.GetU64(&temp_offset);
+ bytes_left -= 8;
+ } else {
+ be_offset -= bytes_left;
+ temp_offset = be_offset;
+ u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ *offset_ptr += byte_size;
+ return llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ }
+ return std::nullopt;
+}
+
+static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data,
+ lldb::offset_t offset, lldb::offset_t byte_size,
+ bool is_signed, unsigned radix) {
+ std::optional<llvm::APInt> apint = GetAPInt(data, &offset, byte_size);
+ if (apint) {
+ std::string apint_str = toString(*apint, radix, is_signed);
+ switch (radix) {
+ case 2:
+ s->Write("0b", 2);
+ break;
+ case 8:
+ s->Write("0", 1);
+ break;
+ case 10:
+ break;
+ }
+ s->Write(apint_str.c_str(), apint_str.size());
+ }
+ return offset;
+}
+
+/// Dumps decoded instructions to a stream.
+static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s,
+ ExecutionContextScope *exe_scope,
+ offset_t start_offset,
+ uint64_t base_addr,
+ size_t number_of_instructions) {
+ offset_t offset = start_offset;
+
+ TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp) {
+ DisassemblerSP disassembler_sp(
+ Disassembler::FindPlugin(target_sp->GetArchitecture(),
+ target_sp->GetDisassemblyFlavor(), nullptr));
+ if (disassembler_sp) {
+ lldb::addr_t addr = base_addr + start_offset;
+ lldb_private::Address so_addr;
+ bool data_from_file = true;
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) {
+ data_from_file = false;
+ } else {
+ if (target_sp->GetSectionLoadList().IsEmpty() ||
+ !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
+ so_addr.SetRawAddress(addr);
+ }
+
+ size_t bytes_consumed = disassembler_sp->DecodeInstructions(
+ so_addr, DE, start_offset, number_of_instructions, false,
+ data_from_file);
+
+ if (bytes_consumed) {
+ offset += bytes_consumed;
+ const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
+ const bool show_bytes = false;
+ const bool show_control_flow_kind = false;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ disassembler_sp->GetInstructionList().Dump(
+ s, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
+ }
+ }
+ } else
+ s->Printf("invalid target");
+
+ return offset;
+}
+
+/// Prints the specific escape sequence of the given character to the stream.
+/// If the character doesn't have a known specific escape sequence (e.g., '\a',
+/// '\n' but not generic escape sequences such as'\x12'), this function will
+/// not modify the stream and return false.
+static bool TryDumpSpecialEscapedChar(Stream &s, const char c) {
+ switch (c) {
+ case '\033':
+ // Common non-standard escape code for 'escape'.
+ s.Printf("\\e");
+ return true;
+ case '\a':
+ s.Printf("\\a");
+ return true;
+ case '\b':
+ s.Printf("\\b");
+ return true;
+ case '\f':
+ s.Printf("\\f");
+ return true;
+ case '\n':
+ s.Printf("\\n");
+ return true;
+ case '\r':
+ s.Printf("\\r");
+ return true;
+ case '\t':
+ s.Printf("\\t");
+ return true;
+ case '\v':
+ s.Printf("\\v");
+ return true;
+ case '\0':
+ s.Printf("\\0");
+ return true;
+ default:
+ return false;
+ }
+}
+
+/// Dump the character to a stream. A character that is not printable will be
+/// represented by its escape sequence.
+static void DumpCharacter(Stream &s, const char c) {
+ if (TryDumpSpecialEscapedChar(s, c))
+ return;
+ if (llvm::isPrint(c)) {
+ s.PutChar(c);
+ return;
+ }
+ s.Printf("\\x%2.2hhx", c);
+}
+
+/// Dump a floating point type.
+template <typename FloatT>
+void DumpFloatingPoint(std::ostringstream &ss, FloatT f) {
+ static_assert(std::is_floating_point<FloatT>::value,
+ "Only floating point types can be dumped.");
+ // NaN and Inf are potentially implementation defined and on Darwin it
+ // seems NaNs are printed without their sign. Manually implement dumping them
+ // here to avoid having to deal with platform differences.
+ if (std::isnan(f)) {
+ if (std::signbit(f))
+ ss << '-';
+ ss << "nan";
+ return;
+ }
+ if (std::isinf(f)) {
+ if (std::signbit(f))
+ ss << '-';
+ ss << "inf";
+ return;
+ }
+ ss << f;
+}
+
+static std::optional<MemoryTagMap>
+GetMemoryTags(lldb::addr_t addr, size_t length,
+ ExecutionContextScope *exe_scope) {
+ assert(addr != LLDB_INVALID_ADDRESS);
+
+ if (!exe_scope)
+ return std::nullopt;
+
+ TargetSP target_sp = exe_scope->CalculateTarget();
+ if (!target_sp)
+ return std::nullopt;
+
+ ProcessSP process_sp = target_sp->CalculateProcess();
+ if (!process_sp)
+ return std::nullopt;
+
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ process_sp->GetMemoryTagManager();
+ if (!tag_manager_or_err) {
+ llvm::consumeError(tag_manager_or_err.takeError());
+ return std::nullopt;
+ }
+
+ MemoryRegionInfos memory_regions;
+ // Don't check return status, list will be just empty if an error happened.
+ process_sp->GetMemoryRegions(memory_regions);
+
+ llvm::Expected<std::vector<MemoryTagManager::TagRange>> tagged_ranges_or_err =
+ (*tag_manager_or_err)
+ ->MakeTaggedRanges(addr, addr + length, memory_regions);
+ // Here we know that our range will not be inverted but we must still check
+ // for an error.
+ if (!tagged_ranges_or_err) {
+ llvm::consumeError(tagged_ranges_or_err.takeError());
+ return std::nullopt;
+ }
+ if (tagged_ranges_or_err->empty())
+ return std::nullopt;
+
+ MemoryTagMap memory_tag_map(*tag_manager_or_err);
+ for (const MemoryTagManager::TagRange &range : *tagged_ranges_or_err) {
+ llvm::Expected<std::vector<lldb::addr_t>> tags_or_err =
+ process_sp->ReadMemoryTags(range.GetRangeBase(), range.GetByteSize());
+
+ if (tags_or_err)
+ memory_tag_map.InsertTags(range.GetRangeBase(), *tags_or_err);
+ else
+ llvm::consumeError(tags_or_err.takeError());
+ }
+
+ if (memory_tag_map.Empty())
+ return std::nullopt;
+
+ return memory_tag_map;
+}
+
+static void printMemoryTags(const DataExtractor &DE, Stream *s,
+ lldb::addr_t addr, size_t len,
+ const std::optional<MemoryTagMap> &memory_tag_map) {
+ std::vector<std::optional<lldb::addr_t>> tags =
+ memory_tag_map->GetTags(addr, len);
+
+ // Only print if there is at least one tag for this line
+ if (tags.empty())
+ return;
+
+ s->Printf(" (tag%s:", tags.size() > 1 ? "s" : "");
+ // Some granules may not be tagged but print something for them
+ // so that the ordering remains intact.
+ for (auto tag : tags) {
+ if (tag)
+ s->Printf(" 0x%" PRIx64, *tag);
+ else
+ s->PutCString(" <no tag>");
+ }
+ s->PutCString(")");
+}
+
+static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp,
+ size_t byte_size) {
+ if (target_sp) {
+ auto type_system_or_err =
+ target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC);
+ if (!type_system_or_err)
+ llvm::consumeError(type_system_or_err.takeError());
+ else if (auto ts = *type_system_or_err)
+ return ts->GetFloatTypeSemantics(byte_size);
+ }
+ // No target, just make a reasonable guess
+ switch(byte_size) {
+ case 2:
+ return llvm::APFloat::IEEEhalf();
+ case 4:
+ return llvm::APFloat::IEEEsingle();
+ case 8:
+ return llvm::APFloat::IEEEdouble();
+ }
+ return llvm::APFloat::Bogus();
+}
+
+lldb::offset_t lldb_private::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, // If zero, this is not a bitfield value, if
+ // non-zero, the value is a bitfield
+ uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the
+ // shift amount to apply to a bitfield
+ ExecutionContextScope *exe_scope, bool show_memory_tags) {
+ if (s == nullptr)
+ return start_offset;
+
+ if (item_format == eFormatPointer) {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ offset_t offset = start_offset;
+
+ std::optional<MemoryTagMap> memory_tag_map;
+ if (show_memory_tags && base_addr != LLDB_INVALID_ADDRESS)
+ memory_tag_map =
+ GetMemoryTags(base_addr, DE.GetByteSize() - offset, exe_scope);
+
+ if (item_format == eFormatInstruction)
+ return DumpInstructions(DE, s, exe_scope, start_offset, base_addr,
+ item_count);
+
+ if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) &&
+ item_byte_size > 8)
+ item_format = eFormatHex;
+
+ lldb::offset_t line_start_offset = start_offset;
+ for (uint32_t count = 0; DE.ValidOffset(offset) && count < item_count;
+ ++count) {
+ // If we are at the beginning or end of a line
+ // Note that the last line is handled outside this for loop.
+ if ((count % num_per_line) == 0) {
+ // If we are at the end of a line
+ if (count > 0) {
+ if (item_format == eFormatBytesWithASCII &&
+ offset > line_start_offset) {
+ s->Printf("%*s",
+ static_cast<int>(
+ (num_per_line - (offset - line_start_offset)) * 3 + 2),
+ "");
+ DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
+ offset - line_start_offset, SIZE_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
+ }
+
+ if (base_addr != LLDB_INVALID_ADDRESS && memory_tag_map) {
+ size_t line_len = offset - line_start_offset;
+ lldb::addr_t line_base =
+ base_addr +
+ (offset - start_offset - line_len) / DE.getTargetByteSize();
+ printMemoryTags(DE, s, line_base, line_len, memory_tag_map);
+ }
+
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf("0x%8.8" PRIx64 ": ",
+ (uint64_t)(base_addr +
+ (offset - start_offset) / DE.getTargetByteSize()));
+
+ line_start_offset = offset;
+ } else if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ item_format != eFormatCharArray && count > 0) {
+ s->PutChar(' ');
+ }
+
+ switch (item_format) {
+ case eFormatBoolean:
+ if (item_byte_size <= 8)
+ s->Printf("%s", DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset)
+ ? "true"
+ : "false");
+ else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for boolean format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ case eFormatBinary:
+ if (item_byte_size <= 8) {
+ uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ // Avoid std::bitset<64>::to_string() since it is missing in earlier
+ // C++ libraries
+ std::string binary_value(64, '0');
+ std::bitset<64> bits(uval64);
+ for (uint32_t i = 0; i < 64; ++i)
+ if (bits[i])
+ binary_value[64 - 1 - i] = '1';
+ if (item_bit_size > 0)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
+ else if (item_byte_size > 0 && item_byte_size <= 8)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
+ } else {
+ const bool is_signed = false;
+ const unsigned radix = 2;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ for (uint32_t i = 0; i < item_byte_size; ++i) {
+ s->Printf("%2.2x", DE.GetU8(&offset));
+ }
+
+ // Put an extra space between the groups of bytes if more than one is
+ // being dumped in a group (item_byte_size is more than 1).
+ if (item_byte_size > 1)
+ s->PutChar(' ');
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray: {
+ // Reject invalid item_byte_size.
+ if (item_byte_size > 8) {
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for char format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+
+ // If we are only printing one character surround it with single quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ const uint64_t ch = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ if (llvm::isPrint(ch))
+ s->Printf("%c", (char)ch);
+ else if (item_format != eFormatCharPrintable) {
+ if (!TryDumpSpecialEscapedChar(*s, ch)) {
+ if (item_byte_size == 1)
+ s->Printf("\\x%2.2x", (uint8_t)ch);
+ else
+ s->Printf("%" PRIu64, ch);
+ }
+ } else {
+ s->PutChar(NON_PRINTABLE_CHAR);
+ }
+
+ // If we are only printing one character surround it with single quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+ } break;
+
+ case eFormatEnum: // Print enum value as a signed integer when we don't get
+ // the enum type
+ case eFormatDecimal:
+ if (item_byte_size <= 8)
+ s->Printf("%" PRId64,
+ DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = true;
+ const unsigned radix = 10;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8)
+ s->Printf("%" PRIu64,
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = false;
+ const unsigned radix = 10;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8)
+ s->Printf("0%" PRIo64,
+ DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ else {
+ const bool is_signed = false;
+ const unsigned radix = 8;
+ offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOSType: {
+ uint64_t uval64 = DE.GetMaxU64Bitfield(&offset, item_byte_size,
+ item_bit_size, item_bit_offset);
+ s->PutChar('\'');
+ for (uint32_t i = 0; i < item_byte_size; ++i) {
+ uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
+ DumpCharacter(*s, ch);
+ }
+ s->PutChar('\'');
+ } break;
+
+ case eFormatCString: {
+ const char *cstr = DE.GetCStr(&offset);
+
+ if (!cstr) {
+ s->Printf("NULL");
+ offset = LLDB_INVALID_OFFSET;
+ } else {
+ s->PutChar('\"');
+
+ while (const char c = *cstr) {
+ DumpCharacter(*s, c);
+ ++cstr;
+ }
+
+ s->PutChar('\"');
+ }
+ } break;
+
+ case eFormatPointer:
+ DumpAddress(s->AsRawOstream(),
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset),
+ sizeof(addr_t));
+ break;
+
+ case eFormatComplexInteger: {
+ size_t complex_int_byte_size = item_byte_size / 2;
+
+ if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) {
+ s->Printf("%" PRIu64,
+ DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ s->Printf(" + %" PRIu64 "i",
+ DE.GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for complex integer format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ } break;
+
+ case eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size) {
+ float f32_1 = DE.GetFloat(&offset);
+ float f32_2 = DE.GetFloat(&offset);
+
+ s->Printf("%g + %gi", f32_1, f32_2);
+ break;
+ } else if (sizeof(double) * 2 == item_byte_size) {
+ double d64_1 = DE.GetDouble(&offset);
+ double d64_2 = DE.GetDouble(&offset);
+
+ s->Printf("%lg + %lgi", d64_1, d64_2);
+ break;
+ } else if (sizeof(long double) * 2 == item_byte_size) {
+ long double ld64_1 = DE.GetLongDouble(&offset);
+ long double ld64_2 = DE.GetLongDouble(&offset);
+ s->Printf("%Lg + %Lgi", ld64_1, ld64_2);
+ break;
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for complex float format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ default:
+ case eFormatDefault:
+ case eFormatHex:
+ case eFormatHexUppercase: {
+ bool wantsuppercase = (item_format == eFormatHexUppercase);
+ switch (item_byte_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ if (Target::GetGlobalProperties()
+ .ShowHexVariableValuesWithLeadingZeroes()) {
+ s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64,
+ (int)(2 * item_byte_size), (int)(2 * item_byte_size),
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ } else {
+ s->Printf(wantsuppercase ? "0x%" PRIX64 : "0x%" PRIx64,
+ DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset));
+ }
+ break;
+ default: {
+ assert(item_bit_size == 0 && item_bit_offset == 0);
+ const uint8_t *bytes =
+ (const uint8_t *)DE.GetData(&offset, item_byte_size);
+ if (bytes) {
+ s->PutCString("0x");
+ uint32_t idx;
+ if (DE.GetByteOrder() == eByteOrderBig) {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
+ } else {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x",
+ bytes[item_byte_size - 1 - idx]);
+ }
+ }
+ } break;
+ }
+ } break;
+
+ case eFormatFloat: {
+ TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+
+ std::optional<unsigned> format_max_padding;
+ if (target_sp)
+ format_max_padding = target_sp->GetMaxZeroPaddingInFloatFormat();
+
+ // Show full precision when printing float values
+ const unsigned format_precision = 0;
+
+ const llvm::fltSemantics &semantics =
+ GetFloatSemantics(target_sp, item_byte_size);
+
+ // Recalculate the byte size in case of a difference. This is possible
+ // when item_byte_size is 16 (128-bit), because you could get back the
+ // x87DoubleExtended semantics which has a byte size of 10 (80-bit).
+ const size_t semantics_byte_size =
+ (llvm::APFloat::getSizeInBits(semantics) + 7) / 8;
+ std::optional<llvm::APInt> apint =
+ GetAPInt(DE, &offset, semantics_byte_size);
+ if (apint) {
+ llvm::APFloat apfloat(semantics, *apint);
+ llvm::SmallVector<char, 256> sv;
+ if (format_max_padding)
+ apfloat.toString(sv, format_precision, *format_max_padding);
+ else
+ apfloat.toString(sv, format_precision);
+ s->AsRawOstream() << sv;
+ } else {
+ s->Format("error: unsupported byte size ({0}) for float format",
+ item_byte_size);
+ return offset;
+ }
+ } break;
+
+ case eFormatUnicode16:
+ s->Printf("U+%4.4x", DE.GetU16(&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("U+0x%8.8x", DE.GetU32(&offset));
+ break;
+
+ case eFormatAddressInfo: {
+ addr_t addr = DE.GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size,
+ item_bit_offset);
+ s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size),
+ (int)(2 * item_byte_size), addr);
+ if (exe_scope) {
+ TargetSP target_sp(exe_scope->CalculateTarget());
+ lldb_private::Address so_addr;
+ if (target_sp) {
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr,
+ so_addr)) {
+ s->PutChar(' ');
+ so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress);
+ } else {
+ so_addr.SetOffset(addr);
+ so_addr.Dump(s, exe_scope,
+ Address::DumpStyleResolvedPointerDescription);
+ if (ProcessSP process_sp = exe_scope->CalculateProcess()) {
+ if (ABISP abi_sp = process_sp->GetABI()) {
+ addr_t addr_fixed = abi_sp->FixCodeAddress(addr);
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(
+ addr_fixed, so_addr)) {
+ s->PutChar(' ');
+ s->Printf("(0x%*.*" PRIx64 ")", (int)(2 * item_byte_size),
+ (int)(2 * item_byte_size), addr_fixed);
+ s->PutChar(' ');
+ so_addr.Dump(s, exe_scope,
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress);
+ }
+ }
+ }
+ }
+ }
+ }
+ } break;
+
+ case eFormatHexFloat:
+ if (sizeof(float) == item_byte_size) {
+ char float_cstr[256];
+ llvm::APFloat ap_float(DE.GetFloat(&offset));
+ ap_float.convertToHexString(float_cstr, 0, false,
+ llvm::APFloat::rmNearestTiesToEven);
+ s->Printf("%s", float_cstr);
+ break;
+ } else if (sizeof(double) == item_byte_size) {
+ char float_cstr[256];
+ llvm::APFloat ap_float(DE.GetDouble(&offset));
+ ap_float.convertToHexString(float_cstr, 0, false,
+ llvm::APFloat::rmNearestTiesToEven);
+ s->Printf("%s", float_cstr);
+ break;
+ } else {
+ s->Printf("error: unsupported byte size (%" PRIu64
+ ") for hex float format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+ break;
+
+ // please keep the single-item formats below in sync with
+ // FormatManager::GetSingleItemFormat if you fail to do so, users will
+ // start getting different outputs depending on internal implementation
+ // details they should not care about ||
+ case eFormatVectorOfChar: // ||
+ s->PutChar('{'); // \/
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatCharArray, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatDecimal, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, 1, item_byte_size,
+ item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt16:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t),
+ item_byte_size / sizeof(uint16_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt32:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt32:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t),
+ item_byte_size / sizeof(uint32_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt64:
+ s->PutChar('{');
+ offset = DumpDataExtractor(
+ DE, s, offset, eFormatDecimal, sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt64:
+ s->PutChar('{');
+ offset = DumpDataExtractor(DE, s, offset, eFormatHex, sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t),
+ item_byte_size / sizeof(uint64_t),
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat16:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 2, item_byte_size / 2,
+ item_byte_size / 2, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 4, item_byte_size / 4,
+ item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat64:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatFloat, 8, item_byte_size / 8,
+ item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt128:
+ s->PutChar('{');
+ offset =
+ DumpDataExtractor(DE, s, offset, eFormatHex, 16, item_byte_size / 16,
+ item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+ }
+ }
+
+ // If anything was printed we want to catch the end of the last line.
+ // Since we will exit the for loop above before we get a chance to append to
+ // it normally.
+ if (offset > line_start_offset) {
+ if (item_format == eFormatBytesWithASCII) {
+ s->Printf("%*s",
+ static_cast<int>(
+ (num_per_line - (offset - line_start_offset)) * 3 + 2),
+ "");
+ DumpDataExtractor(DE, s, line_start_offset, eFormatCharPrintable, 1,
+ offset - line_start_offset, SIZE_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
+ }
+
+ if (base_addr != LLDB_INVALID_ADDRESS && memory_tag_map) {
+ size_t line_len = offset - line_start_offset;
+ lldb::addr_t line_base = base_addr + (offset - start_offset - line_len) /
+ DE.getTargetByteSize();
+ printMemoryTags(DE, s, line_base, line_len, memory_tag_map);
+ }
+ }
+
+ return offset; // Return the offset at which we ended up
+}
+
+void lldb_private::DumpHexBytes(Stream *s, const void *src, size_t src_len,
+ uint32_t bytes_per_line,
+ lldb::addr_t base_addr) {
+ DataExtractor data(src, src_len, lldb::eByteOrderLittle, 4);
+ DumpDataExtractor(data, s,
+ 0, // Offset into "src"
+ lldb::eFormatBytes, // Dump as hex bytes
+ 1, // Size of each item is 1 for single bytes
+ src_len, // Number of bytes
+ bytes_per_line, // Num bytes per line
+ base_addr, // Base address
+ 0, 0); // Bitfield info
+}