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/Core/ValueObject.h"
15 #include "lldb/Core/ValueObjectConstResult.h"
16 #include "lldb/DataFormatters/FormattersHelpers.h"
17 #include "lldb/DataFormatters/StringPrinter.h"
18 #include "lldb/DataFormatters/TypeSummary.h"
19 #include "lldb/Host/Time.h"
20 #include "lldb/Target/SectionLoadList.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Utility/DataBufferHeap.h"
24 #include "lldb/Utility/Endian.h"
25 #include "lldb/Utility/Status.h"
26 #include "lldb/Utility/Stream.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>
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>
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>
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 
97 bool lldb_private::formatters::Char8StringSummaryProvider(
98     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
99   return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
100 }
101 
102 bool lldb_private::formatters::Char16StringSummaryProvider(
103     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
104   return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
105 }
106 
107 bool lldb_private::formatters::Char32StringSummaryProvider(
108     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
109   return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
110 }
111 
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   CompilerType wchar_compiler_type =
120       valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
121 
122   if (!wchar_compiler_type)
123     return false;
124 
125   // Safe to pass nullptr for exe_scope here.
126   std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
127   if (!size)
128     return false;
129   const uint32_t wchar_size = *size;
130 
131   StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
132   options.SetLocation(valobj_addr);
133   options.SetTargetSP(valobj.GetTargetSP());
134   options.SetStream(&stream);
135   options.SetPrefixToken("L");
136 
137   switch (wchar_size) {
138   case 8:
139     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
140         options);
141   case 16:
142     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
143         options);
144   case 32:
145     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
146         options);
147   default:
148     stream.Printf("size for wchar_t is not valid");
149     return true;
150   }
151   return true;
152 }
153 
154 bool lldb_private::formatters::Char8SummaryProvider(
155     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
156   return CharSummaryProvider<StringElementType::UTF8>(valobj, stream);
157 }
158 
159 bool lldb_private::formatters::Char16SummaryProvider(
160     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
161   return CharSummaryProvider<StringElementType::UTF16>(valobj, stream);
162 }
163 
164 bool lldb_private::formatters::Char32SummaryProvider(
165     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
166   return CharSummaryProvider<StringElementType::UTF32>(valobj, stream);
167 }
168 
169 bool lldb_private::formatters::WCharSummaryProvider(
170     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
171   DataExtractor data;
172   Status error;
173   valobj.GetData(data, error);
174 
175   if (error.Fail())
176     return false;
177 
178   // Get a wchar_t basic type from the current type system
179   CompilerType wchar_compiler_type =
180       valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
181 
182   if (!wchar_compiler_type)
183     return false;
184 
185     // Safe to pass nullptr for exe_scope here.
186   std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
187   if (!size)
188     return false;
189   const uint32_t wchar_size = *size;
190 
191   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
192   options.SetData(std::move(data));
193   options.SetStream(&stream);
194   options.SetPrefixToken("L");
195   options.SetQuote('\'');
196   options.SetSourceSize(1);
197   options.SetBinaryZeroIsTerminator(false);
198 
199   switch (wchar_size) {
200   case 8:
201     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
202         options);
203   case 16:
204     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
205         options);
206   case 32:
207     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
208         options);
209   default:
210     stream.Printf("size for wchar_t is not valid");
211     return true;
212   }
213   return true;
214 }
215