1 //===-- CxxStringTypes.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 "CxxStringTypes.h"
10
11 #include "llvm/Support/ConvertUTF.h"
12
13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
14 #include "lldb/DataFormatters/FormattersHelpers.h"
15 #include "lldb/DataFormatters/StringPrinter.h"
16 #include "lldb/DataFormatters/TypeSummary.h"
17 #include "lldb/Host/Time.h"
18 #include "lldb/Target/SectionLoadList.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/DataBufferHeap.h"
22 #include "lldb/Utility/Endian.h"
23 #include "lldb/Utility/Status.h"
24 #include "lldb/Utility/Stream.h"
25 #include "lldb/ValueObject/ValueObject.h"
26 #include "lldb/ValueObject/ValueObjectConstResult.h"
27
28 #include <algorithm>
29 #include <optional>
30
31 using namespace lldb;
32 using namespace lldb_private;
33 using namespace lldb_private::formatters;
34
35 using StringElementType = StringPrinter::StringElementType;
36
37 static constexpr std::pair<const char *, Format>
getElementTraits(StringElementType ElemType)38 getElementTraits(StringElementType ElemType) {
39 switch (ElemType) {
40 case StringElementType::UTF8:
41 return std::make_pair("u8", lldb::eFormatUnicode8);
42 case StringElementType::UTF16:
43 return std::make_pair("u", lldb::eFormatUnicode16);
44 case StringElementType::UTF32:
45 return std::make_pair("U", lldb::eFormatUnicode32);
46 default:
47 return std::make_pair(nullptr, lldb::eFormatInvalid);
48 }
49 }
50
51 template <StringElementType ElemType>
CharStringSummaryProvider(ValueObject & valobj,Stream & stream)52 static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) {
53 Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
54 if (!valobj_addr.IsValid())
55 return false;
56
57 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
58 options.SetLocation(valobj_addr);
59 options.SetTargetSP(valobj.GetTargetSP());
60 options.SetStream(&stream);
61 options.SetPrefixToken(getElementTraits(ElemType).first);
62
63 if (!StringPrinter::ReadStringAndDumpToStream<ElemType>(options))
64 stream.Printf("Summary Unavailable");
65
66 return true;
67 }
68
69 template <StringElementType ElemType>
CharSummaryProvider(ValueObject & valobj,Stream & stream)70 static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) {
71 DataExtractor data;
72 Status error;
73 valobj.GetData(data, error);
74
75 if (error.Fail())
76 return false;
77
78 std::string value;
79 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
80
81 constexpr auto ElemTraits = getElementTraits(ElemType);
82 valobj.GetValueAsCString(ElemTraits.second, value);
83
84 if (!value.empty())
85 stream.Printf("%s ", value.c_str());
86
87 options.SetData(std::move(data));
88 options.SetStream(&stream);
89 options.SetPrefixToken(ElemTraits.first);
90 options.SetQuote('\'');
91 options.SetSourceSize(1);
92 options.SetBinaryZeroIsTerminator(false);
93
94 return StringPrinter::ReadBufferAndDumpToStream<ElemType>(options);
95 }
96
Char8StringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)97 bool lldb_private::formatters::Char8StringSummaryProvider(
98 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
99 return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
100 }
101
Char16StringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)102 bool lldb_private::formatters::Char16StringSummaryProvider(
103 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
104 return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
105 }
106
Char32StringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)107 bool lldb_private::formatters::Char32StringSummaryProvider(
108 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
109 return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
110 }
111
WCharStringSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)112 bool lldb_private::formatters::WCharStringSummaryProvider(
113 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
114 Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
115 if (!valobj_addr.IsValid())
116 return false;
117
118 // Get a wchar_t basic type from the current type system
119 std::optional<uint64_t> size = GetWCharByteSize(valobj);
120 if (!size)
121 return false;
122 const uint32_t wchar_size = *size;
123
124 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
125 options.SetLocation(valobj_addr);
126 options.SetTargetSP(valobj.GetTargetSP());
127 options.SetStream(&stream);
128 options.SetPrefixToken("L");
129
130 switch (wchar_size) {
131 case 1:
132 return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
133 options);
134 case 2:
135 return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
136 options);
137 case 4:
138 return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
139 options);
140 default:
141 stream.Printf("size for wchar_t is not valid");
142 return true;
143 }
144 return true;
145 }
146
Char8SummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)147 bool lldb_private::formatters::Char8SummaryProvider(
148 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
149 return CharSummaryProvider<StringElementType::UTF8>(valobj, stream);
150 }
151
Char16SummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)152 bool lldb_private::formatters::Char16SummaryProvider(
153 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
154 return CharSummaryProvider<StringElementType::UTF16>(valobj, stream);
155 }
156
Char32SummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)157 bool lldb_private::formatters::Char32SummaryProvider(
158 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
159 return CharSummaryProvider<StringElementType::UTF32>(valobj, stream);
160 }
161
WCharSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions &)162 bool lldb_private::formatters::WCharSummaryProvider(
163 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
164 DataExtractor data;
165 Status error;
166 valobj.GetData(data, error);
167
168 if (error.Fail())
169 return false;
170
171 // Get a wchar_t basic type from the current type system
172 std::optional<uint64_t> size = GetWCharByteSize(valobj);
173 if (!size)
174 return false;
175 const uint32_t wchar_size = *size;
176
177 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
178 options.SetData(std::move(data));
179 options.SetStream(&stream);
180 options.SetPrefixToken("L");
181 options.SetQuote('\'');
182 options.SetSourceSize(1);
183 options.SetBinaryZeroIsTerminator(false);
184
185 switch (wchar_size) {
186 case 1:
187 return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
188 options);
189 case 2:
190 return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
191 options);
192 case 4:
193 return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
194 options);
195 default:
196 stream.Printf("size for wchar_t is not valid");
197 return true;
198 }
199 return true;
200 }
201
202 std::optional<uint64_t>
GetWCharByteSize(ValueObject & valobj)203 lldb_private::formatters::GetWCharByteSize(ValueObject &valobj) {
204 return llvm::expectedToOptional(
205 valobj.GetCompilerType()
206 .GetBasicTypeFromAST(lldb::eBasicTypeWChar)
207 .GetByteSize(nullptr));
208 }
209
210 template <StringPrinter::StringElementType element_type>
StringBufferSummaryProvider(Stream & stream,const TypeSummaryOptions & summary_options,lldb::ValueObjectSP location_sp,uint64_t size,std::string prefix_token)211 bool lldb_private::formatters::StringBufferSummaryProvider(
212 Stream &stream, const TypeSummaryOptions &summary_options,
213 lldb::ValueObjectSP location_sp, uint64_t size, std::string prefix_token) {
214
215 if (size == 0) {
216 stream.PutCString(prefix_token);
217 stream.PutCString("\"\"");
218 return true;
219 }
220
221 if (!location_sp)
222 return false;
223
224 StringPrinter::ReadBufferAndDumpToStreamOptions options(*location_sp);
225
226 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
227 const auto max_size =
228 location_sp->GetTargetSP()->GetMaximumSizeOfStringSummary();
229 if (size > max_size) {
230 size = max_size;
231 options.SetIsTruncated(true);
232 }
233 }
234
235 {
236 DataExtractor extractor;
237 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
238 if (bytes_read < size)
239 return false;
240
241 options.SetData(std::move(extractor));
242 }
243 options.SetStream(&stream);
244 if (prefix_token.empty())
245 options.SetPrefixToken(nullptr);
246 else
247 options.SetPrefixToken(prefix_token);
248 options.SetQuote('"');
249 options.SetSourceSize(size);
250 options.SetBinaryZeroIsTerminator(false);
251 return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
252 }
253
254 // explicit instantiations for all string element types
255 template bool
256 lldb_private::formatters::StringBufferSummaryProvider<StringElementType::ASCII>(
257 Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
258 std::string);
259 template bool
260 lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF8>(
261 Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
262 std::string);
263 template bool
264 lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF16>(
265 Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
266 std::string);
267 template bool
268 lldb_private::formatters::StringBufferSummaryProvider<StringElementType::UTF32>(
269 Stream &, const TypeSummaryOptions &, lldb::ValueObjectSP, uint64_t,
270 std::string);
271