1 //===-- StringPrinter.h -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef liblldb_StringPrinter_h_
11 #define liblldb_StringPrinter_h_
12 
13 #include <functional>
14 #include <string>
15 
16 #include "lldb/lldb-forward.h"
17 
18 #include "lldb/Utility/DataExtractor.h"
19 
20 namespace lldb_private {
21 namespace formatters {
22 class StringPrinter {
23 public:
24   enum class StringElementType { ASCII, UTF8, UTF16, UTF32 };
25 
26   enum class GetPrintableElementType { ASCII, UTF8 };
27 
28   class ReadStringAndDumpToStreamOptions {
29   public:
ReadStringAndDumpToStreamOptions()30     ReadStringAndDumpToStreamOptions()
31         : m_location(0), m_process_sp(), m_stream(nullptr), m_prefix_token(),
32           m_suffix_token(), m_quote('"'), m_source_size(0),
33           m_needs_zero_termination(true), m_escape_non_printables(true),
34           m_ignore_max_length(false), m_zero_is_terminator(true),
35           m_language_type(lldb::eLanguageTypeUnknown) {}
36 
37     ReadStringAndDumpToStreamOptions(ValueObject &valobj);
38 
SetLocation(uint64_t l)39     ReadStringAndDumpToStreamOptions &SetLocation(uint64_t l) {
40       m_location = l;
41       return *this;
42     }
43 
GetLocation()44     uint64_t GetLocation() const { return m_location; }
45 
SetProcessSP(lldb::ProcessSP p)46     ReadStringAndDumpToStreamOptions &SetProcessSP(lldb::ProcessSP p) {
47       m_process_sp = p;
48       return *this;
49     }
50 
GetProcessSP()51     lldb::ProcessSP GetProcessSP() const { return m_process_sp; }
52 
SetStream(Stream * s)53     ReadStringAndDumpToStreamOptions &SetStream(Stream *s) {
54       m_stream = s;
55       return *this;
56     }
57 
GetStream()58     Stream *GetStream() const { return m_stream; }
59 
SetPrefixToken(const std::string & p)60     ReadStringAndDumpToStreamOptions &SetPrefixToken(const std::string &p) {
61       m_prefix_token = p;
62       return *this;
63     }
64 
SetPrefixToken(std::nullptr_t)65     ReadStringAndDumpToStreamOptions &SetPrefixToken(std::nullptr_t) {
66       m_prefix_token.clear();
67       return *this;
68     }
69 
GetPrefixToken()70     const char *GetPrefixToken() const { return m_prefix_token.c_str(); }
71 
SetSuffixToken(const std::string & p)72     ReadStringAndDumpToStreamOptions &SetSuffixToken(const std::string &p) {
73       m_suffix_token = p;
74       return *this;
75     }
76 
SetSuffixToken(std::nullptr_t)77     ReadStringAndDumpToStreamOptions &SetSuffixToken(std::nullptr_t) {
78       m_suffix_token.clear();
79       return *this;
80     }
81 
GetSuffixToken()82     const char *GetSuffixToken() const { return m_suffix_token.c_str(); }
83 
SetQuote(char q)84     ReadStringAndDumpToStreamOptions &SetQuote(char q) {
85       m_quote = q;
86       return *this;
87     }
88 
GetQuote()89     char GetQuote() const { return m_quote; }
90 
SetSourceSize(uint32_t s)91     ReadStringAndDumpToStreamOptions &SetSourceSize(uint32_t s) {
92       m_source_size = s;
93       return *this;
94     }
95 
GetSourceSize()96     uint32_t GetSourceSize() const { return m_source_size; }
97 
SetNeedsZeroTermination(bool z)98     ReadStringAndDumpToStreamOptions &SetNeedsZeroTermination(bool z) {
99       m_needs_zero_termination = z;
100       return *this;
101     }
102 
GetNeedsZeroTermination()103     bool GetNeedsZeroTermination() const { return m_needs_zero_termination; }
104 
SetBinaryZeroIsTerminator(bool e)105     ReadStringAndDumpToStreamOptions &SetBinaryZeroIsTerminator(bool e) {
106       m_zero_is_terminator = e;
107       return *this;
108     }
109 
GetBinaryZeroIsTerminator()110     bool GetBinaryZeroIsTerminator() const { return m_zero_is_terminator; }
111 
SetEscapeNonPrintables(bool e)112     ReadStringAndDumpToStreamOptions &SetEscapeNonPrintables(bool e) {
113       m_escape_non_printables = e;
114       return *this;
115     }
116 
GetEscapeNonPrintables()117     bool GetEscapeNonPrintables() const { return m_escape_non_printables; }
118 
SetIgnoreMaxLength(bool e)119     ReadStringAndDumpToStreamOptions &SetIgnoreMaxLength(bool e) {
120       m_ignore_max_length = e;
121       return *this;
122     }
123 
GetIgnoreMaxLength()124     bool GetIgnoreMaxLength() const { return m_ignore_max_length; }
125 
SetLanguage(lldb::LanguageType l)126     ReadStringAndDumpToStreamOptions &SetLanguage(lldb::LanguageType l) {
127       m_language_type = l;
128       return *this;
129     }
130 
GetLanguage()131     lldb::LanguageType GetLanguage() const
132 
133     {
134       return m_language_type;
135     }
136 
137   private:
138     uint64_t m_location;
139     lldb::ProcessSP m_process_sp;
140     Stream *m_stream;
141     std::string m_prefix_token;
142     std::string m_suffix_token;
143     char m_quote;
144     uint32_t m_source_size;
145     bool m_needs_zero_termination;
146     bool m_escape_non_printables;
147     bool m_ignore_max_length;
148     bool m_zero_is_terminator;
149     lldb::LanguageType m_language_type;
150   };
151 
152   class ReadBufferAndDumpToStreamOptions {
153   public:
ReadBufferAndDumpToStreamOptions()154     ReadBufferAndDumpToStreamOptions()
155         : m_data(), m_stream(nullptr), m_prefix_token(), m_suffix_token(),
156           m_quote('"'), m_source_size(0), m_escape_non_printables(true),
157           m_zero_is_terminator(true), m_is_truncated(false),
158           m_language_type(lldb::eLanguageTypeUnknown) {}
159 
160     ReadBufferAndDumpToStreamOptions(ValueObject &valobj);
161 
162     ReadBufferAndDumpToStreamOptions(
163         const ReadStringAndDumpToStreamOptions &options);
164 
SetData(DataExtractor d)165     ReadBufferAndDumpToStreamOptions &SetData(DataExtractor d) {
166       m_data = d;
167       return *this;
168     }
169 
GetData()170     lldb_private::DataExtractor GetData() const { return m_data; }
171 
SetStream(Stream * s)172     ReadBufferAndDumpToStreamOptions &SetStream(Stream *s) {
173       m_stream = s;
174       return *this;
175     }
176 
GetStream()177     Stream *GetStream() const { return m_stream; }
178 
SetPrefixToken(const std::string & p)179     ReadBufferAndDumpToStreamOptions &SetPrefixToken(const std::string &p) {
180       m_prefix_token = p;
181       return *this;
182     }
183 
SetPrefixToken(std::nullptr_t)184     ReadBufferAndDumpToStreamOptions &SetPrefixToken(std::nullptr_t) {
185       m_prefix_token.clear();
186       return *this;
187     }
188 
GetPrefixToken()189     const char *GetPrefixToken() const { return m_prefix_token.c_str(); }
190 
SetSuffixToken(const std::string & p)191     ReadBufferAndDumpToStreamOptions &SetSuffixToken(const std::string &p) {
192       m_suffix_token = p;
193       return *this;
194     }
195 
SetSuffixToken(std::nullptr_t)196     ReadBufferAndDumpToStreamOptions &SetSuffixToken(std::nullptr_t) {
197       m_suffix_token.clear();
198       return *this;
199     }
200 
GetSuffixToken()201     const char *GetSuffixToken() const { return m_suffix_token.c_str(); }
202 
SetQuote(char q)203     ReadBufferAndDumpToStreamOptions &SetQuote(char q) {
204       m_quote = q;
205       return *this;
206     }
207 
GetQuote()208     char GetQuote() const { return m_quote; }
209 
SetSourceSize(uint32_t s)210     ReadBufferAndDumpToStreamOptions &SetSourceSize(uint32_t s) {
211       m_source_size = s;
212       return *this;
213     }
214 
GetSourceSize()215     uint32_t GetSourceSize() const { return m_source_size; }
216 
SetEscapeNonPrintables(bool e)217     ReadBufferAndDumpToStreamOptions &SetEscapeNonPrintables(bool e) {
218       m_escape_non_printables = e;
219       return *this;
220     }
221 
GetEscapeNonPrintables()222     bool GetEscapeNonPrintables() const { return m_escape_non_printables; }
223 
SetBinaryZeroIsTerminator(bool e)224     ReadBufferAndDumpToStreamOptions &SetBinaryZeroIsTerminator(bool e) {
225       m_zero_is_terminator = e;
226       return *this;
227     }
228 
GetBinaryZeroIsTerminator()229     bool GetBinaryZeroIsTerminator() const { return m_zero_is_terminator; }
230 
SetIsTruncated(bool t)231     ReadBufferAndDumpToStreamOptions &SetIsTruncated(bool t) {
232       m_is_truncated = t;
233       return *this;
234     }
235 
GetIsTruncated()236     bool GetIsTruncated() const { return m_is_truncated; }
237 
SetLanguage(lldb::LanguageType l)238     ReadBufferAndDumpToStreamOptions &SetLanguage(lldb::LanguageType l) {
239       m_language_type = l;
240       return *this;
241     }
242 
GetLanguage()243     lldb::LanguageType GetLanguage() const
244 
245     {
246       return m_language_type;
247     }
248 
249   private:
250     DataExtractor m_data;
251     Stream *m_stream;
252     std::string m_prefix_token;
253     std::string m_suffix_token;
254     char m_quote;
255     uint32_t m_source_size;
256     bool m_escape_non_printables;
257     bool m_zero_is_terminator;
258     bool m_is_truncated;
259     lldb::LanguageType m_language_type;
260   };
261 
262   // I can't use a std::unique_ptr for this because the Deleter is a template
263   // argument there
264   // and I want the same type to represent both pointers I want to free and
265   // pointers I don't need to free - which is what this class essentially is
266   // It's very specialized to the needs of this file, and not suggested for
267   // general use
268   template <typename T = uint8_t, typename U = char, typename S = size_t>
269   struct StringPrinterBufferPointer {
270   public:
271     typedef std::function<void(const T *)> Deleter;
272 
StringPrinterBufferPointerStringPrinterBufferPointer273     StringPrinterBufferPointer(std::nullptr_t ptr)
274         : m_data(nullptr), m_size(0), m_deleter() {}
275 
276     StringPrinterBufferPointer(const T *bytes, S size,
277                                Deleter deleter = nullptr)
m_dataStringPrinterBufferPointer278         : m_data(bytes), m_size(size), m_deleter(deleter) {}
279 
280     StringPrinterBufferPointer(const U *bytes, S size,
281                                Deleter deleter = nullptr)
m_dataStringPrinterBufferPointer282         : m_data(reinterpret_cast<const T *>(bytes)), m_size(size),
283           m_deleter(deleter) {}
284 
StringPrinterBufferPointerStringPrinterBufferPointer285     StringPrinterBufferPointer(StringPrinterBufferPointer &&rhs)
286         : m_data(rhs.m_data), m_size(rhs.m_size), m_deleter(rhs.m_deleter) {
287       rhs.m_data = nullptr;
288     }
289 
StringPrinterBufferPointerStringPrinterBufferPointer290     StringPrinterBufferPointer(const StringPrinterBufferPointer &rhs)
291         : m_data(rhs.m_data), m_size(rhs.m_size), m_deleter(rhs.m_deleter) {
292       rhs.m_data = nullptr; // this is why m_data has to be mutable
293     }
294 
~StringPrinterBufferPointerStringPrinterBufferPointer295     ~StringPrinterBufferPointer() {
296       if (m_data && m_deleter)
297         m_deleter(m_data);
298       m_data = nullptr;
299     }
300 
GetBytesStringPrinterBufferPointer301     const T *GetBytes() const { return m_data; }
302 
GetSizeStringPrinterBufferPointer303     const S GetSize() const { return m_size; }
304 
305     StringPrinterBufferPointer &
306     operator=(const StringPrinterBufferPointer &rhs) {
307       if (m_data && m_deleter)
308         m_deleter(m_data);
309       m_data = rhs.m_data;
310       m_size = rhs.m_size;
311       m_deleter = rhs.m_deleter;
312       rhs.m_data = nullptr;
313       return *this;
314     }
315 
316   private:
317     mutable const T *m_data;
318     size_t m_size;
319     Deleter m_deleter;
320   };
321 
322   typedef std::function<StringPrinter::StringPrinterBufferPointer<
323       uint8_t, char, size_t>(uint8_t *, uint8_t *, uint8_t *&)>
324       EscapingHelper;
325   typedef std::function<EscapingHelper(GetPrintableElementType)>
326       EscapingHelperGenerator;
327 
328   static EscapingHelper
329   GetDefaultEscapingHelper(GetPrintableElementType elem_type);
330 
331   template <StringElementType element_type>
332   static bool
333   ReadStringAndDumpToStream(const ReadStringAndDumpToStreamOptions &options);
334 
335   template <StringElementType element_type>
336   static bool
337   ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options);
338 };
339 
340 } // namespace formatters
341 } // namespace lldb_private
342 
343 #endif // liblldb_StringPrinter_h_
344