| //===-- 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) {} |
| |
| TypeFormatImpl::~TypeFormatImpl() = default; |
| |
| TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f, |
| const TypeFormatImpl::Flags &flags) |
| : TypeFormatImpl(flags), m_format(f) {} |
| |
| TypeFormatImpl_Format::~TypeFormatImpl_Format() = default; |
| |
| 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, ®_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() = default; |
| |
| 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()); |
| } |