1 | //===-- TypeFormat.cpp ----------------------------------------------------===// |
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 | #include <optional> |
27 | |
28 | using namespace lldb; |
29 | using namespace lldb_private; |
30 | |
31 | TypeFormatImpl::TypeFormatImpl(const Flags &flags) : m_flags(flags) {} |
32 | |
33 | TypeFormatImpl::~TypeFormatImpl() = default; |
34 | |
35 | TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f, |
36 | const TypeFormatImpl::Flags &flags) |
37 | : TypeFormatImpl(flags), m_format(f) {} |
38 | |
39 | TypeFormatImpl_Format::~TypeFormatImpl_Format() = default; |
40 | |
41 | bool 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::ContextType::RegisterInfo) { |
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(DE: data, s: ®_sstr, offset: 0, item_format: GetFormat(), item_byte_size: reg_info->byte_size, |
61 | item_count: 1, UINT32_MAX, LLDB_INVALID_ADDRESS, item_bit_size: 0, item_bit_offset: 0, |
62 | exe_scope: exe_ctx.GetBestExecutionContextScope()); |
63 | dest = std::string(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 | pointee_or_element_compiler_type: nullptr)); // disambiguate w.r.t. TypeFormatImpl::Flags |
73 | if (type_flags.Test(bit: eTypeIsPointer) && |
74 | !type_flags.Test(bit: 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 | WritableDataBufferSP buffer_sp( |
82 | new DataBufferHeap(max_len + 1, 0)); |
83 | Address address(valobj->GetPointerValue()); |
84 | target_sp->ReadCStringFromMemory( |
85 | addr: address, dst: (char *)buffer_sp->GetBytes(), dst_max_len: max_len, result_error&: error); |
86 | if (error.Success()) |
87 | data.SetData(data_sp: buffer_sp); |
88 | } |
89 | } |
90 | } else { |
91 | Status error; |
92 | valobj->GetData(data, error); |
93 | if (error.Fail()) |
94 | return false; |
95 | } |
96 | |
97 | ExecutionContextScope *exe_scope = |
98 | exe_ctx.GetBestExecutionContextScope(); |
99 | std::optional<uint64_t> size = compiler_type.GetByteSize(exe_scope); |
100 | if (!size) |
101 | return false; |
102 | StreamString sstr; |
103 | compiler_type.DumpTypeValue( |
104 | s: &sstr, // The stream to use for display |
105 | format: GetFormat(), // Format to display this type with |
106 | data, // Data to extract from |
107 | data_offset: 0, // Byte offset into "m_data" |
108 | data_byte_size: *size, // Byte size of item in "m_data" |
109 | bitfield_bit_size: valobj->GetBitfieldBitSize(), // Bitfield bit size |
110 | bitfield_bit_offset: valobj->GetBitfieldBitOffset(), // Bitfield bit offset |
111 | exe_scope); |
112 | // Given that we do not want to set the ValueObject's m_error for a |
113 | // formatting error (or else we wouldn't be able to reformat until a |
114 | // next update), an empty string is treated as a "false" return from |
115 | // here, but that's about as severe as we get |
116 | // CompilerType::DumpTypeValue() should always return something, even |
117 | // if that something is an error message |
118 | dest = std::string(sstr.GetString()); |
119 | } |
120 | } |
121 | return !dest.empty(); |
122 | } else |
123 | return false; |
124 | } |
125 | |
126 | std::string TypeFormatImpl_Format::GetDescription() { |
127 | StreamString sstr; |
128 | sstr.Printf(format: "%s%s%s%s" , FormatManager::GetFormatAsCString(format: GetFormat()), |
129 | Cascades() ? "" : " (not cascading)" , |
130 | SkipsPointers() ? " (skip pointers)" : "" , |
131 | SkipsReferences() ? " (skip references)" : "" ); |
132 | return std::string(sstr.GetString()); |
133 | } |
134 | |
135 | TypeFormatImpl_EnumType::TypeFormatImpl_EnumType( |
136 | ConstString type_name, const TypeFormatImpl::Flags &flags) |
137 | : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {} |
138 | |
139 | TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() = default; |
140 | |
141 | bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj, |
142 | std::string &dest) const { |
143 | dest.clear(); |
144 | if (!valobj) |
145 | return false; |
146 | if (!valobj->CanProvideValue()) |
147 | return false; |
148 | ProcessSP process_sp; |
149 | TargetSP target_sp; |
150 | void *valobj_key = (process_sp = valobj->GetProcessSP()).get(); |
151 | if (!valobj_key) |
152 | valobj_key = (target_sp = valobj->GetTargetSP()).get(); |
153 | else |
154 | target_sp = process_sp->GetTarget().shared_from_this(); |
155 | if (!valobj_key) |
156 | return false; |
157 | auto iter = m_types.find(x: valobj_key), end = m_types.end(); |
158 | CompilerType valobj_enum_type; |
159 | if (iter == end) { |
160 | // probably a redundant check |
161 | if (!target_sp) |
162 | return false; |
163 | const ModuleList &images(target_sp->GetImages()); |
164 | TypeQuery query(m_enum_type.GetStringRef()); |
165 | TypeResults results; |
166 | images.FindTypes(search_first: nullptr, query, results); |
167 | if (results.GetTypeMap().Empty()) |
168 | return false; |
169 | for (lldb::TypeSP type_sp : results.GetTypeMap().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(args&: valobj_key, args&: 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(s: &sstr, format: lldb::eFormatEnum, data, data_offset: 0, |
191 | data_byte_size: data.GetByteSize(), bitfield_bit_size: 0, bitfield_bit_offset: 0, |
192 | exe_scope: exe_ctx.GetBestExecutionContextScope()); |
193 | if (!sstr.GetString().empty()) |
194 | dest = std::string(sstr.GetString()); |
195 | return !dest.empty(); |
196 | } |
197 | |
198 | std::string TypeFormatImpl_EnumType::GetDescription() { |
199 | StreamString sstr; |
200 | sstr.Printf(format: "as type %s%s%s%s" , m_enum_type.AsCString(value_if_empty: "<invalid type>" ), |
201 | Cascades() ? "" : " (not cascading)" , |
202 | SkipsPointers() ? " (skip pointers)" : "" , |
203 | SkipsReferences() ? " (skip references)" : "" ); |
204 | return std::string(sstr.GetString()); |
205 | } |
206 | |