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
31using namespace lldb;
32using namespace lldb_private;
33using namespace lldb_private::formatters;
34
35using StringElementType = StringPrinter::StringElementType;
36
37static constexpr std::pair<const char *, Format>
38getElementTraits(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
51template <StringElementType ElemType>
52static 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
69template <StringElementType ElemType>
70static 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
97bool lldb_private::formatters::Char8StringSummaryProvider(
98    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
99  return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
100}
101
102bool lldb_private::formatters::Char16StringSummaryProvider(
103    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
104  return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
105}
106
107bool lldb_private::formatters::Char32StringSummaryProvider(
108    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
109  return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
110}
111
112bool 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
154bool lldb_private::formatters::Char8SummaryProvider(
155    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
156  return CharSummaryProvider<StringElementType::UTF8>(valobj, stream);
157}
158
159bool lldb_private::formatters::Char16SummaryProvider(
160    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
161  return CharSummaryProvider<StringElementType::UTF16>(valobj, stream);
162}
163
164bool lldb_private::formatters::Char32SummaryProvider(
165    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
166  return CharSummaryProvider<StringElementType::UTF32>(valobj, stream);
167}
168
169bool 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