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/ProcessStructReader.h"
21 #include "lldb/Target/SectionLoadList.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Target/Thread.h"
24 #include "lldb/Utility/DataBufferHeap.h"
25 #include "lldb/Utility/Endian.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/Stream.h"
28 
29 #include <algorithm>
30 #include <optional>
31 
32 using namespace lldb;
33 using namespace lldb_private;
34 using namespace lldb_private::formatters;
35 
36 using StringElementType = StringPrinter::StringElementType;
37 
38 static constexpr std::pair<const char *, Format>
39 getElementTraits(StringElementType ElemType) {
40   switch (ElemType) {
41   case StringElementType::UTF8:
42     return std::make_pair("u8", lldb::eFormatUnicode8);
43   case StringElementType::UTF16:
44     return std::make_pair("u", lldb::eFormatUnicode16);
45   case StringElementType::UTF32:
46     return std::make_pair("U", lldb::eFormatUnicode32);
47   default:
48     return std::make_pair(nullptr, lldb::eFormatInvalid);
49   }
50 }
51 
52 template <StringElementType ElemType>
53 static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) {
54   Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
55   if (!valobj_addr.IsValid())
56     return false;
57 
58   StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
59   options.SetLocation(valobj_addr);
60   options.SetTargetSP(valobj.GetTargetSP());
61   options.SetStream(&stream);
62   options.SetPrefixToken(getElementTraits(ElemType).first);
63 
64   if (!StringPrinter::ReadStringAndDumpToStream<ElemType>(options))
65     stream.Printf("Summary Unavailable");
66 
67   return true;
68 }
69 
70 template <StringElementType ElemType>
71 static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) {
72   DataExtractor data;
73   Status error;
74   valobj.GetData(data, error);
75 
76   if (error.Fail())
77     return false;
78 
79   std::string value;
80   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
81 
82   constexpr auto ElemTraits = getElementTraits(ElemType);
83   valobj.GetValueAsCString(ElemTraits.second, value);
84 
85   if (!value.empty())
86     stream.Printf("%s ", value.c_str());
87 
88   options.SetData(std::move(data));
89   options.SetStream(&stream);
90   options.SetPrefixToken(ElemTraits.first);
91   options.SetQuote('\'');
92   options.SetSourceSize(1);
93   options.SetBinaryZeroIsTerminator(false);
94 
95   return StringPrinter::ReadBufferAndDumpToStream<ElemType>(options);
96 }
97 
98 bool lldb_private::formatters::Char8StringSummaryProvider(
99     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
100   return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
101 }
102 
103 bool lldb_private::formatters::Char16StringSummaryProvider(
104     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
105   return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
106 }
107 
108 bool lldb_private::formatters::Char32StringSummaryProvider(
109     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
110   return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
111 }
112 
113 bool lldb_private::formatters::WCharStringSummaryProvider(
114     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
115   Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
116   if (!valobj_addr.IsValid())
117     return false;
118 
119   // Get a wchar_t basic type from the current type system
120   CompilerType wchar_compiler_type =
121       valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
122 
123   if (!wchar_compiler_type)
124     return false;
125 
126   // Safe to pass nullptr for exe_scope here.
127   std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
128   if (!size)
129     return false;
130   const uint32_t wchar_size = *size;
131 
132   StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
133   options.SetLocation(valobj_addr);
134   options.SetTargetSP(valobj.GetTargetSP());
135   options.SetStream(&stream);
136   options.SetPrefixToken("L");
137 
138   switch (wchar_size) {
139   case 8:
140     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
141         options);
142   case 16:
143     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
144         options);
145   case 32:
146     return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
147         options);
148   default:
149     stream.Printf("size for wchar_t is not valid");
150     return true;
151   }
152   return true;
153 }
154 
155 bool lldb_private::formatters::Char8SummaryProvider(
156     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
157   return CharSummaryProvider<StringElementType::UTF8>(valobj, stream);
158 }
159 
160 bool lldb_private::formatters::Char16SummaryProvider(
161     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
162   return CharSummaryProvider<StringElementType::UTF16>(valobj, stream);
163 }
164 
165 bool lldb_private::formatters::Char32SummaryProvider(
166     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
167   return CharSummaryProvider<StringElementType::UTF32>(valobj, stream);
168 }
169 
170 bool lldb_private::formatters::WCharSummaryProvider(
171     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
172   DataExtractor data;
173   Status error;
174   valobj.GetData(data, error);
175 
176   if (error.Fail())
177     return false;
178 
179   // Get a wchar_t basic type from the current type system
180   CompilerType wchar_compiler_type =
181       valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
182 
183   if (!wchar_compiler_type)
184     return false;
185 
186     // Safe to pass nullptr for exe_scope here.
187   std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
188   if (!size)
189     return false;
190   const uint32_t wchar_size = *size;
191 
192   StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
193   options.SetData(std::move(data));
194   options.SetStream(&stream);
195   options.SetPrefixToken("L");
196   options.SetQuote('\'');
197   options.SetSourceSize(1);
198   options.SetBinaryZeroIsTerminator(false);
199 
200   switch (wchar_size) {
201   case 8:
202     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
203         options);
204   case 16:
205     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
206         options);
207   case 32:
208     return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
209         options);
210   default:
211     stream.Printf("size for wchar_t is not valid");
212     return true;
213   }
214   return true;
215 }
216