blob: b114add50640d26aa072fe6a1fbbf2b555c72ddc [file] [log] [blame]
Enrico Granataca6c8ee2014-10-30 01:45:39 +00001//===-- StringPrinter.cpp ----------------------------------------*- 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#include "lldb/DataFormatters/StringPrinter.h"
11
Enrico Granataebdc1ac2014-11-05 21:20:48 +000012#include "lldb/Core/Debugger.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000013#include "lldb/Core/Error.h"
Enrico Granataebdc1ac2014-11-05 21:20:48 +000014#include "lldb/Core/ValueObject.h"
Enrico Granataac494532015-09-09 22:30:24 +000015#include "lldb/Target/Language.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000016#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
18
19#include "llvm/Support/ConvertUTF.h"
20
Enrico Granataca6c8ee2014-10-30 01:45:39 +000021#include <ctype.h>
Enrico Granataca6c8ee2014-10-30 01:45:39 +000022#include <locale>
23
24using namespace lldb;
25using namespace lldb_private;
26using namespace lldb_private::formatters;
27
Enrico Granataca6c8ee2014-10-30 01:45:39 +000028// we define this for all values of type but only implement it for those we care about
29// that's good because we get linker errors for any unsupported type
Enrico Granataac494532015-09-09 22:30:24 +000030template <lldb_private::formatters::StringPrinter::StringElementType type>
Enrico Granataad650a12015-09-09 20:59:49 +000031static StringPrinter::StringPrinterBufferPointer<>
Enrico Granataca6c8ee2014-10-30 01:45:39 +000032GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
33
34// mimic isprint() for Unicode codepoints
35static bool
36isprint(char32_t codepoint)
37{
38 if (codepoint <= 0x1F || codepoint == 0x7F) // C0
39 {
40 return false;
41 }
42 if (codepoint >= 0x80 && codepoint <= 0x9F) // C1
43 {
44 return false;
45 }
46 if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators
47 {
48 return false;
49 }
50 if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control
51 {
52 return false;
53 }
54 if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials
55 {
56 return false;
57 }
58 return true;
59}
60
61template <>
Enrico Granataad650a12015-09-09 20:59:49 +000062StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +000063GetPrintableImpl<StringPrinter::StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +000064{
Enrico Granataad650a12015-09-09 20:59:49 +000065 StringPrinter::StringPrinterBufferPointer<> retval = {nullptr};
Enrico Granataca6c8ee2014-10-30 01:45:39 +000066
67 switch (*buffer)
68 {
Enrico Granatada04fbb2014-12-18 19:43:29 +000069 case 0:
70 retval = {"\\0",2};
71 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +000072 case '\a':
73 retval = {"\\a",2};
74 break;
75 case '\b':
76 retval = {"\\b",2};
77 break;
78 case '\f':
79 retval = {"\\f",2};
80 break;
81 case '\n':
82 retval = {"\\n",2};
83 break;
84 case '\r':
85 retval = {"\\r",2};
86 break;
87 case '\t':
88 retval = {"\\t",2};
89 break;
90 case '\v':
91 retval = {"\\v",2};
92 break;
93 case '\"':
94 retval = {"\\\"",2};
95 break;
96 case '\\':
97 retval = {"\\\\",2};
98 break;
99 default:
100 if (isprint(*buffer))
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000101 retval = {buffer,1};
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000102 else
103 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000104 uint8_t* data = new uint8_t[5];
105 sprintf((char*)data,"\\x%02x",*buffer);
106 retval = {data, 4, [] (const uint8_t* c) {delete[] c;} };
107 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000108 }
109 }
110
111 next = buffer + 1;
112 return retval;
113}
114
115static char32_t
116ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1)
117{
118 return (c0-192)*64+(c1-128);
119}
120static char32_t
121ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2)
122{
123 return (c0-224)*4096+(c1-128)*64+(c2-128);
124}
125static char32_t
126ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3)
127{
128 return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128);
129}
130
131template <>
Enrico Granataad650a12015-09-09 20:59:49 +0000132StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +0000133GetPrintableImpl<StringPrinter::StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000134{
Enrico Granataad650a12015-09-09 20:59:49 +0000135 StringPrinter::StringPrinterBufferPointer<> retval {nullptr};
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000136
137 unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer);
138
139 if (1+buffer_end-buffer < utf8_encoded_len)
140 {
141 // I don't have enough bytes - print whatever I have left
142 retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)};
143 next = buffer_end+1;
144 return retval;
145 }
146
147 char32_t codepoint = 0;
148 switch (utf8_encoded_len)
149 {
150 case 1:
151 // this is just an ASCII byte - ask ASCII
Enrico Granataac494532015-09-09 22:30:24 +0000152 return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000153 case 2:
154 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1));
155 break;
156 case 3:
157 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2));
158 break;
159 case 4:
160 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3));
161 break;
162 default:
163 // this is probably some bogus non-character thing
164 // just print it as-is and hope to sync up again soon
165 retval = {buffer,1};
166 next = buffer+1;
167 return retval;
168 }
169
170 if (codepoint)
171 {
172 switch (codepoint)
173 {
Enrico Granatada04fbb2014-12-18 19:43:29 +0000174 case 0:
175 retval = {"\\0",2};
176 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000177 case '\a':
178 retval = {"\\a",2};
179 break;
180 case '\b':
181 retval = {"\\b",2};
182 break;
183 case '\f':
184 retval = {"\\f",2};
185 break;
186 case '\n':
187 retval = {"\\n",2};
188 break;
189 case '\r':
190 retval = {"\\r",2};
191 break;
192 case '\t':
193 retval = {"\\t",2};
194 break;
195 case '\v':
196 retval = {"\\v",2};
197 break;
198 case '\"':
199 retval = {"\\\"",2};
200 break;
201 case '\\':
202 retval = {"\\\\",2};
203 break;
204 default:
205 if (isprint(codepoint))
206 retval = {buffer,utf8_encoded_len};
207 else
208 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000209 uint8_t* data = new uint8_t[11];
210 sprintf((char*)data,"\\U%08x",codepoint);
211 retval = { data,10,[] (const uint8_t* c) {delete[] c;} };
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000212 break;
213 }
214 }
215
216 next = buffer + utf8_encoded_len;
217 return retval;
218 }
219
220 // this should not happen - but just in case.. try to resync at some point
221 retval = {buffer,1};
222 next = buffer+1;
223 return retval;
224}
225
226// Given a sequence of bytes, this function returns:
227// a sequence of bytes to actually print out + a length
228// the following unscanned position of the buffer is in next
Enrico Granataad650a12015-09-09 20:59:49 +0000229static StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +0000230GetPrintable(StringPrinter::StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000231{
232 if (!buffer)
233 return {nullptr};
234
235 switch (type)
236 {
Enrico Granataac494532015-09-09 22:30:24 +0000237 case StringPrinter::StringElementType::ASCII:
238 return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
239 case StringPrinter::StringElementType::UTF8:
240 return GetPrintableImpl<StringPrinter::StringElementType::UTF8>(buffer, buffer_end, next);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000241 default:
242 return {nullptr};
243 }
244}
245
Enrico Granataac494532015-09-09 22:30:24 +0000246StringPrinter::EscapingHelper
247StringPrinter::GetDefaultEscapingHelper (GetPrintableElementType elem_type)
248{
249 switch (elem_type)
250 {
251 case GetPrintableElementType::UTF8:
252 return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
253 return GetPrintable(StringPrinter::StringElementType::UTF8, buffer, buffer_end, next);
254 };
255 case GetPrintableElementType::ASCII:
256 return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
257 return GetPrintable(StringPrinter::StringElementType::ASCII, buffer, buffer_end, next);
258 };
259 }
Saleem Abdulrasool43d3a7a2015-10-18 20:51:18 +0000260 llvm_unreachable("bad element type");
Enrico Granataac494532015-09-09 22:30:24 +0000261}
262
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000263// use this call if you already have an LLDB-side buffer for the data
264template<typename SourceDataType>
265static bool
266DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
267 const SourceDataType*,
268 UTF8**,
269 UTF8*,
270 ConversionFlags),
Enrico Granataac494532015-09-09 22:30:24 +0000271 const StringPrinter::ReadBufferAndDumpToStreamOptions& dump_options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000272{
Enrico Granatad07f7552015-07-17 01:03:59 +0000273 Stream &stream(*dump_options.GetStream());
274 if (dump_options.GetPrefixToken() != 0)
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000275 stream.Printf("%s",dump_options.GetPrefixToken());
Enrico Granatad07f7552015-07-17 01:03:59 +0000276 if (dump_options.GetQuote() != 0)
277 stream.Printf("%c",dump_options.GetQuote());
278 auto data(dump_options.GetData());
279 auto source_size(dump_options.GetSourceSize());
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000280 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
281 {
282 const int bufferSPSize = data.GetByteSize();
Enrico Granatad07f7552015-07-17 01:03:59 +0000283 if (dump_options.GetSourceSize() == 0)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000284 {
285 const int origin_encoding = 8*sizeof(SourceDataType);
Enrico Granatad07f7552015-07-17 01:03:59 +0000286 source_size = bufferSPSize/(origin_encoding / 4);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000287 }
288
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000289 const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart();
Enrico Granatad07f7552015-07-17 01:03:59 +0000290 const SourceDataType *data_end_ptr = data_ptr + source_size;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000291
Enrico Granatad07f7552015-07-17 01:03:59 +0000292 const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator();
293
294 if (zero_is_terminator)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000295 {
Enrico Granatad07f7552015-07-17 01:03:59 +0000296 while (data_ptr < data_end_ptr)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000297 {
Enrico Granatad07f7552015-07-17 01:03:59 +0000298 if (!*data_ptr)
299 {
300 data_end_ptr = data_ptr;
301 break;
302 }
303 data_ptr++;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000304 }
Enrico Granatad07f7552015-07-17 01:03:59 +0000305
306 data_ptr = (const SourceDataType*)data.GetDataStart();
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000307 }
308
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000309 lldb::DataBufferSP utf8_data_buffer_sp;
310 UTF8* utf8_data_ptr = nullptr;
311 UTF8* utf8_data_end_ptr = nullptr;
312
313 if (ConvertFunction)
314 {
315 utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0));
316 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
317 utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000318 ConvertFunction ( &data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
Enrico Granata8101f572015-07-17 01:56:25 +0000319 if (false == zero_is_terminator)
320 utf8_data_end_ptr = utf8_data_ptr;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000321 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
322 }
323 else
324 {
325 // just copy the pointers - the cast is necessary to make the compiler happy
326 // but this should only happen if we are reading UTF8 data
Saleem Abdulrasoolba507b02015-10-18 19:34:38 +0000327 utf8_data_ptr = const_cast<UTF8 *>(reinterpret_cast<const UTF8*>(data_ptr));
328 utf8_data_end_ptr = const_cast<UTF8 *>(reinterpret_cast<const UTF8*>(data_end_ptr));
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000329 }
330
Enrico Granatad07f7552015-07-17 01:03:59 +0000331 const bool escape_non_printables = dump_options.GetEscapeNonPrintables();
Enrico Granataac494532015-09-09 22:30:24 +0000332 lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback;
333 if (escape_non_printables)
334 {
335 if (Language *language = Language::FindPlugin(dump_options.GetLanguage()))
336 escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8);
337 else
338 escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::UTF8);
339 }
Enrico Granatad07f7552015-07-17 01:03:59 +0000340
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000341 // since we tend to accept partial data (and even partially malformed data)
342 // we might end up with no NULL terminator before the end_ptr
343 // hence we need to take a slower route and ensure we stay within boundaries
344 for (;utf8_data_ptr < utf8_data_end_ptr;)
345 {
Enrico Granatad07f7552015-07-17 01:03:59 +0000346 if (zero_is_terminator && !*utf8_data_ptr)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000347 break;
348
Enrico Granatad07f7552015-07-17 01:03:59 +0000349 if (escape_non_printables)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000350 {
351 uint8_t* next_data = nullptr;
Enrico Granataac494532015-09-09 22:30:24 +0000352 auto printable = escaping_callback(utf8_data_ptr, utf8_data_end_ptr, next_data);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000353 auto printable_bytes = printable.GetBytes();
354 auto printable_size = printable.GetSize();
355 if (!printable_bytes || !next_data)
356 {
357 // GetPrintable() failed on us - print one byte in a desperate resync attempt
358 printable_bytes = utf8_data_ptr;
359 printable_size = 1;
360 next_data = utf8_data_ptr+1;
361 }
Andy Gibbs3acfe1a2014-12-29 13:03:19 +0000362 for (unsigned c = 0; c < printable_size; c++)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000363 stream.Printf("%c", *(printable_bytes+c));
364 utf8_data_ptr = (uint8_t*)next_data;
365 }
366 else
367 {
368 stream.Printf("%c",*utf8_data_ptr);
369 utf8_data_ptr++;
370 }
371 }
372 }
Enrico Granatad07f7552015-07-17 01:03:59 +0000373 if (dump_options.GetQuote() != 0)
374 stream.Printf("%c",dump_options.GetQuote());
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000375 if (dump_options.GetSuffixToken() != 0)
376 stream.Printf("%s",dump_options.GetSuffixToken());
Enrico Granatab7662922015-11-04 00:02:08 +0000377 if (dump_options.GetIsTruncated())
378 stream.Printf("...");
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000379 return true;
380}
381
Enrico Granataac494532015-09-09 22:30:24 +0000382lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000383 ReadStringAndDumpToStreamOptions()
384{
385 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
386}
387
Enrico Granataac494532015-09-09 22:30:24 +0000388lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000389 ReadBufferAndDumpToStreamOptions()
390{
391 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
392}
393
Enrico Granataac494532015-09-09 22:30:24 +0000394lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options) :
Enrico Granatad07f7552015-07-17 01:03:59 +0000395 ReadBufferAndDumpToStreamOptions()
396{
397 SetStream(options.GetStream());
398 SetPrefixToken(options.GetPrefixToken());
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000399 SetSuffixToken(options.GetSuffixToken());
Enrico Granatad07f7552015-07-17 01:03:59 +0000400 SetQuote(options.GetQuote());
401 SetEscapeNonPrintables(options.GetEscapeNonPrintables());
402 SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
Enrico Granataac494532015-09-09 22:30:24 +0000403 SetLanguage(options.GetLanguage());
Enrico Granatad07f7552015-07-17 01:03:59 +0000404}
405
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000406
Shawn Bestfd137432014-11-04 22:43:34 +0000407namespace lldb_private
408{
409
410namespace formatters
411{
412
413template <>
414bool
Enrico Granataac494532015-09-09 22:30:24 +0000415StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
Shawn Bestfd137432014-11-04 22:43:34 +0000416{
417 assert(options.GetStream() && "need a Stream to print the string to");
418 Error my_error;
Shawn Bestfd137432014-11-04 22:43:34 +0000419
420 ProcessSP process_sp(options.GetProcessSP());
421
422 if (process_sp.get() == nullptr || options.GetLocation() == 0)
423 return false;
424
425 size_t size;
Enrico Granatab7662922015-11-04 00:02:08 +0000426 const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
427 bool is_truncated = false;
Shawn Bestfd137432014-11-04 22:43:34 +0000428
429 if (options.GetSourceSize() == 0)
Enrico Granatab7662922015-11-04 00:02:08 +0000430 size = max_size;
Enrico Granata34042212014-11-18 22:54:45 +0000431 else if (!options.GetIgnoreMaxLength())
Enrico Granatab7662922015-11-04 00:02:08 +0000432 {
433 size = options.GetSourceSize();
434 if (size > max_size)
435 {
436 size = max_size;
437 is_truncated = true;
438 }
439 }
Enrico Granata34042212014-11-18 22:54:45 +0000440 else
441 size = options.GetSourceSize();
Shawn Bestfd137432014-11-04 22:43:34 +0000442
443 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
444
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000445 process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
Shawn Bestfd137432014-11-04 22:43:34 +0000446
447 if (my_error.Fail())
448 return false;
449
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000450 const char* prefix_token = options.GetPrefixToken();
Shawn Bestfd137432014-11-04 22:43:34 +0000451 char quote = options.GetQuote();
452
453 if (prefix_token != 0)
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000454 options.GetStream()->Printf("%s%c",prefix_token,quote);
Shawn Bestfd137432014-11-04 22:43:34 +0000455 else if (quote != 0)
456 options.GetStream()->Printf("%c",quote);
457
458 uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize();
459
Enrico Granataac494532015-09-09 22:30:24 +0000460 const bool escape_non_printables = options.GetEscapeNonPrintables();
461 lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback;
462 if (escape_non_printables)
463 {
464 if (Language *language = Language::FindPlugin(options.GetLanguage()))
465 escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
466 else
467 escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
468 }
469
Shawn Bestfd137432014-11-04 22:43:34 +0000470 // since we tend to accept partial data (and even partially malformed data)
471 // we might end up with no NULL terminator before the end_ptr
472 // hence we need to take a slower route and ensure we stay within boundaries
473 for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);)
474 {
Enrico Granataac494532015-09-09 22:30:24 +0000475 if (escape_non_printables)
Shawn Bestfd137432014-11-04 22:43:34 +0000476 {
477 uint8_t* next_data = nullptr;
Enrico Granataac494532015-09-09 22:30:24 +0000478 auto printable = escaping_callback(data, data_end, next_data);
Shawn Bestfd137432014-11-04 22:43:34 +0000479 auto printable_bytes = printable.GetBytes();
480 auto printable_size = printable.GetSize();
481 if (!printable_bytes || !next_data)
482 {
483 // GetPrintable() failed on us - print one byte in a desperate resync attempt
484 printable_bytes = data;
485 printable_size = 1;
486 next_data = data+1;
487 }
Andy Gibbs3acfe1a2014-12-29 13:03:19 +0000488 for (unsigned c = 0; c < printable_size; c++)
Shawn Bestfd137432014-11-04 22:43:34 +0000489 options.GetStream()->Printf("%c", *(printable_bytes+c));
490 data = (uint8_t*)next_data;
491 }
492 else
493 {
494 options.GetStream()->Printf("%c",*data);
495 data++;
496 }
497 }
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000498
499 const char* suffix_token = options.GetSuffixToken();
500
501 if (suffix_token != 0)
502 options.GetStream()->Printf("%c%s",quote, suffix_token);
503 else if (quote != 0)
Shawn Bestfd137432014-11-04 22:43:34 +0000504 options.GetStream()->Printf("%c",quote);
505
Enrico Granatab7662922015-11-04 00:02:08 +0000506 if (is_truncated)
507 options.GetStream()->Printf("...");
508
Shawn Bestfd137432014-11-04 22:43:34 +0000509 return true;
510}
511
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000512template<typename SourceDataType>
513static bool
Enrico Granataac494532015-09-09 22:30:24 +0000514ReadUTFBufferAndDumpToStream (const StringPrinter::ReadStringAndDumpToStreamOptions& options,
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000515 ConversionResult (*ConvertFunction) (const SourceDataType**,
516 const SourceDataType*,
517 UTF8**,
518 UTF8*,
519 ConversionFlags))
520{
521 assert(options.GetStream() && "need a Stream to print the string to");
522
523 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
524 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000525
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000526 lldb::ProcessSP process_sp(options.GetProcessSP());
Shawn Bestfd137432014-11-04 22:43:34 +0000527
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000528 if (!process_sp)
529 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000530
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000531 const int type_width = sizeof(SourceDataType);
532 const int origin_encoding = 8 * type_width ;
533 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
534 return false;
535 // if not UTF8, I need a conversion function to return proper UTF8
536 if (origin_encoding != 8 && !ConvertFunction)
537 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000538
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000539 if (!options.GetStream())
540 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000541
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000542 uint32_t sourceSize = options.GetSourceSize();
543 bool needs_zero_terminator = options.GetNeedsZeroTermination();
Enrico Granatab7662922015-11-04 00:02:08 +0000544
545 bool is_truncated = false;
546 const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
Shawn Bestfd137432014-11-04 22:43:34 +0000547
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000548 if (!sourceSize)
549 {
Enrico Granatab7662922015-11-04 00:02:08 +0000550 sourceSize = max_size;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000551 needs_zero_terminator = true;
552 }
Enrico Granatab0e8a552015-05-01 22:57:38 +0000553 else if (!options.GetIgnoreMaxLength())
Enrico Granatab7662922015-11-04 00:02:08 +0000554 {
555 if (sourceSize > max_size)
556 {
557 sourceSize = max_size;
558 is_truncated = true;
559 }
560 }
Shawn Bestfd137432014-11-04 22:43:34 +0000561
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000562 const int bufferSPSize = sourceSize * type_width;
Shawn Bestfd137432014-11-04 22:43:34 +0000563
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000564 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
Shawn Bestfd137432014-11-04 22:43:34 +0000565
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000566 if (!buffer_sp->GetBytes())
567 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000568
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000569 Error error;
570 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
Shawn Bestfd137432014-11-04 22:43:34 +0000571
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000572 if (needs_zero_terminator)
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000573 process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000574 else
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000575 process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
Shawn Bestfd137432014-11-04 22:43:34 +0000576
Enrico Granata099263b2014-11-17 23:14:11 +0000577 if (error.Fail())
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000578 {
579 options.GetStream()->Printf("unable to read data");
580 return true;
581 }
Shawn Bestfd137432014-11-04 22:43:34 +0000582
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000583 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
Enrico Granatad07f7552015-07-17 01:03:59 +0000584
Enrico Granataac494532015-09-09 22:30:24 +0000585 StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options);
Enrico Granatad07f7552015-07-17 01:03:59 +0000586 dump_options.SetData(data);
587 dump_options.SetSourceSize(sourceSize);
Enrico Granatab7662922015-11-04 00:02:08 +0000588 dump_options.SetIsTruncated(is_truncated);
Shawn Bestfd137432014-11-04 22:43:34 +0000589
Enrico Granatad07f7552015-07-17 01:03:59 +0000590 return DumpUTFBufferToStream(ConvertFunction, dump_options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000591}
592
593template <>
594bool
Enrico Granataac494532015-09-09 22:30:24 +0000595StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000596{
597 return ReadUTFBufferAndDumpToStream<UTF8>(options,
598 nullptr);
599}
600
601template <>
602bool
Enrico Granataac494532015-09-09 22:30:24 +0000603StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000604{
605 return ReadUTFBufferAndDumpToStream<UTF16>(options,
606 ConvertUTF16toUTF8);
607}
608
609template <>
610bool
Enrico Granataac494532015-09-09 22:30:24 +0000611StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000612{
613 return ReadUTFBufferAndDumpToStream<UTF32>(options,
614 ConvertUTF32toUTF8);
615}
616
617template <>
618bool
Enrico Granataac494532015-09-09 22:30:24 +0000619StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000620{
621 assert(options.GetStream() && "need a Stream to print the string to");
622
Enrico Granatad07f7552015-07-17 01:03:59 +0000623 return DumpUTFBufferToStream<UTF8>(nullptr, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000624}
625
626template <>
627bool
Enrico Granataac494532015-09-09 22:30:24 +0000628StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000629{
630 // treat ASCII the same as UTF8
631 // FIXME: can we optimize ASCII some more?
632 return ReadBufferAndDumpToStream<StringElementType::UTF8>(options);
633}
634
635template <>
636bool
Enrico Granataac494532015-09-09 22:30:24 +0000637StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000638{
639 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000640
Enrico Granatad07f7552015-07-17 01:03:59 +0000641 return DumpUTFBufferToStream(ConvertUTF16toUTF8, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000642}
643
644template <>
645bool
Enrico Granataac494532015-09-09 22:30:24 +0000646StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000647{
648 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000649
Enrico Granatad07f7552015-07-17 01:03:59 +0000650 return DumpUTFBufferToStream(ConvertUTF32toUTF8, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000651}
Shawn Bestfd137432014-11-04 22:43:34 +0000652
653} // namespace formatters
654
655} // namespace lldb_private