text: //===-- TypeFormat.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/DataFormatters/TypeFormat.h"
  
  
  
  
  #include "lldb/lldb-enumerations.h"
  #include "lldb/lldb-public.h"
  
  #include "lldb/Core/DumpDataExtractor.h"
  #include "lldb/DataFormatters/FormatManager.h"
  #include "lldb/Symbol/CompilerType.h"
  #include "lldb/Symbol/SymbolContext.h"
  #include "lldb/Symbol/SymbolFile.h"
  #include "lldb/Symbol/TypeList.h"
  #include "lldb/Target/Target.h"
  #include "lldb/Utility/DataExtractor.h"
  #include "lldb/Utility/StreamString.h"
  
  using namespace lldb;
  using namespace lldb_private;
  
  TypeFormatImpl::TypeFormatImpl(const Flags &flags)
      : m_flags(flags), m_my_revision(0) {}
  
  TypeFormatImpl::~TypeFormatImpl() {}
  
  TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f,
                                               const TypeFormatImpl::Flags &flags)
      : TypeFormatImpl(flags), m_format(f) {}
  
  TypeFormatImpl_Format::~TypeFormatImpl_Format() {}
  
  bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
                                           std::string &dest) const {
    if (!valobj)
      return false;
    if (valobj->CanProvideValue()) {
      Value &value(valobj->GetValue());
      const Value::ContextType context_type = value.GetContextType();
      ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
      DataExtractor data;
  
      if (context_type == Value::ContextType::RegisterInfo) {
        const RegisterInfo *reg_info = value.GetRegisterInfo();
        if (reg_info) {
          Status error;
          valobj->GetData(data, error);
          if (error.Fail())
            return false;
  
          StreamString reg_sstr;
          DumpDataExtractor(data, &reg_sstr, 0, GetFormat(), reg_info->byte_size,
                            1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0,
                            exe_ctx.GetBestExecutionContextScope());
          dest = std::string(reg_sstr.GetString());
        }
      } else {
        CompilerType compiler_type = value.GetCompilerType();
        if (compiler_type) {
          // put custom bytes to display in the DataExtractor to override the
          // default value logic
          if (GetFormat() == eFormatCString) {
            lldb_private::Flags type_flags(compiler_type.GetTypeInfo(
                nullptr)); // disambiguate w.r.t. TypeFormatImpl::Flags
            if (type_flags.Test(eTypeIsPointer) &&
                !type_flags.Test(eTypeIsObjC)) {
              // if we are dumping a pointer as a c-string, get the pointee data
              // as a string
              TargetSP target_sp(valobj->GetTargetSP());
              if (target_sp) {
                size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
                Status error;
                DataBufferSP buffer_sp(new DataBufferHeap(max_len + 1, 0));
                Address address(valobj->GetPointerValue());
                if (target_sp->ReadCStringFromMemory(
                        address, (char *)buffer_sp->GetBytes(), max_len, error) &&
                    error.Success())
                  data.SetData(buffer_sp);
              }
            }
          } else {
            Status error;
            valobj->GetData(data, error);
            if (error.Fail())
              return false;
          }
  
          ExecutionContextScope *exe_scope =
              exe_ctx.GetBestExecutionContextScope();
          llvm::Optional<uint64_t> size = compiler_type.GetByteSize(exe_scope);
          if (!size)
            return false;
          StreamString sstr;
          compiler_type.DumpTypeValue(
              &sstr,                          // The stream to use for display
              GetFormat(),                    // Format to display this type with
              data,                           // Data to extract from
              0,                              // Byte offset into "m_data"
              *size,                          // Byte size of item in "m_data"
              valobj->GetBitfieldBitSize(),   // Bitfield bit size
              valobj->GetBitfieldBitOffset(), // Bitfield bit offset
              exe_scope);
          // Given that we do not want to set the ValueObject's m_error for a
          // formatting error (or else we wouldn't be able to reformat until a
          // next update), an empty string is treated as a "false" return from
          // here, but that's about as severe as we get
          // CompilerType::DumpTypeValue() should always return something, even
          // if that something is an error message
          dest = std::string(sstr.GetString());
        }
      }
      return !dest.empty();
    } else
      return false;
  }
  
  std::string TypeFormatImpl_Format::GetDescription() {
    StreamString sstr;
    sstr.Printf("%s%s%s%s", FormatManager::GetFormatAsCString(GetFormat()),
                Cascades() ? "" : " (not cascading)",
                SkipsPointers() ? " (skip pointers)" : "",
                SkipsReferences() ? " (skip references)" : "");
    return std::string(sstr.GetString());
  }
  
  TypeFormatImpl_EnumType::TypeFormatImpl_EnumType(
      ConstString type_name, const TypeFormatImpl::Flags &flags)
      : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {}
  
  TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() {}
  
  bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
                                             std::string &dest) const {
    dest.clear();
    if (!valobj)
      return false;
    if (!valobj->CanProvideValue())
      return false;
    ProcessSP process_sp;
    TargetSP target_sp;
    void *valobj_key = (process_sp = valobj->GetProcessSP()).get();
    if (!valobj_key)
      valobj_key = (target_sp = valobj->GetTargetSP()).get();
    else
      target_sp = process_sp->GetTarget().shared_from_this();
    if (!valobj_key)
      return false;
    auto iter = m_types.find(valobj_key), end = m_types.end();
    CompilerType valobj_enum_type;
    if (iter == end) {
      // probably a redundant check
      if (!target_sp)
        return false;
      const ModuleList &images(target_sp->GetImages());
      TypeList types;
      llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
      images.FindTypes(nullptr, m_enum_type, false, UINT32_MAX,
                       searched_symbol_files, types);
      if (types.Empty())
        return false;
      for (lldb::TypeSP type_sp : types.Types()) {
        if (!type_sp)
          continue;
        if ((type_sp->GetForwardCompilerType().GetTypeInfo() &
             eTypeIsEnumeration) == eTypeIsEnumeration) {
          valobj_enum_type = type_sp->GetFullCompilerType();
          m_types.emplace(valobj_key, valobj_enum_type);
          break;
        }
      }
    } else
      valobj_enum_type = iter->second;
    if (!valobj_enum_type.IsValid())
      return false;
    DataExtractor data;
    Status error;
    valobj->GetData(data, error);
    if (error.Fail())
      return false;
    ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
    StreamString sstr;
    valobj_enum_type.DumpTypeValue(&sstr, lldb::eFormatEnum, data, 0,
                                   data.GetByteSize(), 0, 0,
                                   exe_ctx.GetBestExecutionContextScope());
    if (!sstr.GetString().empty())
      dest = std::string(sstr.GetString());
    return !dest.empty();
  }
  
  std::string TypeFormatImpl_EnumType::GetDescription() {
    StreamString sstr;
    sstr.Printf("as type %s%s%s%s", m_enum_type.AsCString("<invalid type>"),
                Cascades() ? "" : " (not cascading)",
                SkipsPointers() ? " (skip pointers)" : "",
                SkipsReferences() ? " (skip references)" : "");
    return std::string(sstr.GetString());
  }
  