TypeFormat.cpp revision 360784
1//===-- TypeFormat.cpp ----------------------------------------*- C++ -*-===//
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/DataFormatters/TypeFormat.h"
10
11
12
13
14#include "lldb/lldb-enumerations.h"
15#include "lldb/lldb-public.h"
16
17#include "lldb/Core/DumpDataExtractor.h"
18#include "lldb/DataFormatters/FormatManager.h"
19#include "lldb/Symbol/CompilerType.h"
20#include "lldb/Symbol/SymbolContext.h"
21#include "lldb/Symbol/SymbolFile.h"
22#include "lldb/Symbol/TypeList.h"
23#include "lldb/Target/Target.h"
24#include "lldb/Utility/DataExtractor.h"
25#include "lldb/Utility/StreamString.h"
26
27using namespace lldb;
28using namespace lldb_private;
29
30TypeFormatImpl::TypeFormatImpl(const Flags &flags)
31    : m_flags(flags), m_my_revision(0) {}
32
33TypeFormatImpl::~TypeFormatImpl() {}
34
35TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f,
36                                             const TypeFormatImpl::Flags &flags)
37    : TypeFormatImpl(flags), m_format(f) {}
38
39TypeFormatImpl_Format::~TypeFormatImpl_Format() {}
40
41bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
42                                         std::string &dest) const {
43  if (!valobj)
44    return false;
45  if (valobj->CanProvideValue()) {
46    Value &value(valobj->GetValue());
47    const Value::ContextType context_type = value.GetContextType();
48    ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
49    DataExtractor data;
50
51    if (context_type == Value::eContextTypeRegisterInfo) {
52      const RegisterInfo *reg_info = value.GetRegisterInfo();
53      if (reg_info) {
54        Status error;
55        valobj->GetData(data, error);
56        if (error.Fail())
57          return false;
58
59        StreamString reg_sstr;
60        DumpDataExtractor(data, &reg_sstr, 0, GetFormat(), reg_info->byte_size,
61                          1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0,
62                          exe_ctx.GetBestExecutionContextScope());
63        dest = reg_sstr.GetString();
64      }
65    } else {
66      CompilerType compiler_type = value.GetCompilerType();
67      if (compiler_type) {
68        // put custom bytes to display in the DataExtractor to override the
69        // default value logic
70        if (GetFormat() == eFormatCString) {
71          lldb_private::Flags type_flags(compiler_type.GetTypeInfo(
72              nullptr)); // disambiguate w.r.t. TypeFormatImpl::Flags
73          if (type_flags.Test(eTypeIsPointer) &&
74              !type_flags.Test(eTypeIsObjC)) {
75            // if we are dumping a pointer as a c-string, get the pointee data
76            // as a string
77            TargetSP target_sp(valobj->GetTargetSP());
78            if (target_sp) {
79              size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
80              Status error;
81              DataBufferSP buffer_sp(new DataBufferHeap(max_len + 1, 0));
82              Address address(valobj->GetPointerValue());
83              if (target_sp->ReadCStringFromMemory(
84                      address, (char *)buffer_sp->GetBytes(), max_len, error) &&
85                  error.Success())
86                data.SetData(buffer_sp);
87            }
88          }
89        } else {
90          Status error;
91          valobj->GetData(data, error);
92          if (error.Fail())
93            return false;
94        }
95
96        ExecutionContextScope *exe_scope =
97            exe_ctx.GetBestExecutionContextScope();
98        llvm::Optional<uint64_t> size = compiler_type.GetByteSize(exe_scope);
99        if (!size)
100          return false;
101        StreamString sstr;
102        compiler_type.DumpTypeValue(
103            &sstr,                          // The stream to use for display
104            GetFormat(),                    // Format to display this type with
105            data,                           // Data to extract from
106            0,                              // Byte offset into "m_data"
107            *size,                          // Byte size of item in "m_data"
108            valobj->GetBitfieldBitSize(),   // Bitfield bit size
109            valobj->GetBitfieldBitOffset(), // Bitfield bit offset
110            exe_scope);
111        // Given that we do not want to set the ValueObject's m_error for a
112        // formatting error (or else we wouldn't be able to reformat until a
113        // next update), an empty string is treated as a "false" return from
114        // here, but that's about as severe as we get
115        // CompilerType::DumpTypeValue() should always return something, even
116        // if that something is an error message
117        dest = sstr.GetString();
118      }
119    }
120    return !dest.empty();
121  } else
122    return false;
123}
124
125std::string TypeFormatImpl_Format::GetDescription() {
126  StreamString sstr;
127  sstr.Printf("%s%s%s%s", FormatManager::GetFormatAsCString(GetFormat()),
128              Cascades() ? "" : " (not cascading)",
129              SkipsPointers() ? " (skip pointers)" : "",
130              SkipsReferences() ? " (skip references)" : "");
131  return sstr.GetString();
132}
133
134TypeFormatImpl_EnumType::TypeFormatImpl_EnumType(
135    ConstString type_name, const TypeFormatImpl::Flags &flags)
136    : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {}
137
138TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() {}
139
140bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
141                                           std::string &dest) const {
142  dest.clear();
143  if (!valobj)
144    return false;
145  if (!valobj->CanProvideValue())
146    return false;
147  ProcessSP process_sp;
148  TargetSP target_sp;
149  void *valobj_key = (process_sp = valobj->GetProcessSP()).get();
150  if (!valobj_key)
151    valobj_key = (target_sp = valobj->GetTargetSP()).get();
152  else
153    target_sp = process_sp->GetTarget().shared_from_this();
154  if (!valobj_key)
155    return false;
156  auto iter = m_types.find(valobj_key), end = m_types.end();
157  CompilerType valobj_enum_type;
158  if (iter == end) {
159    // probably a redundant check
160    if (!target_sp)
161      return false;
162    const ModuleList &images(target_sp->GetImages());
163    TypeList types;
164    llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
165    images.FindTypes(nullptr, m_enum_type, false, UINT32_MAX,
166                     searched_symbol_files, types);
167    if (types.Empty())
168      return false;
169    for (lldb::TypeSP type_sp : types.Types()) {
170      if (!type_sp)
171        continue;
172      if ((type_sp->GetForwardCompilerType().GetTypeInfo() &
173           eTypeIsEnumeration) == eTypeIsEnumeration) {
174        valobj_enum_type = type_sp->GetFullCompilerType();
175        m_types.emplace(valobj_key, valobj_enum_type);
176        break;
177      }
178    }
179  } else
180    valobj_enum_type = iter->second;
181  if (!valobj_enum_type.IsValid())
182    return false;
183  DataExtractor data;
184  Status error;
185  valobj->GetData(data, error);
186  if (error.Fail())
187    return false;
188  ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
189  StreamString sstr;
190  valobj_enum_type.DumpTypeValue(&sstr, lldb::eFormatEnum, data, 0,
191                                 data.GetByteSize(), 0, 0,
192                                 exe_ctx.GetBestExecutionContextScope());
193  if (!sstr.GetString().empty())
194    dest = sstr.GetString();
195  return !dest.empty();
196}
197
198std::string TypeFormatImpl_EnumType::GetDescription() {
199  StreamString sstr;
200  sstr.Printf("as type %s%s%s%s", m_enum_type.AsCString("<invalid type>"),
201              Cascades() ? "" : " (not cascading)",
202              SkipsPointers() ? " (skip pointers)" : "",
203              SkipsReferences() ? " (skip references)" : "");
204  return sstr.GetString();
205}
206