xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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