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