blob: a63a1fe922181499a0deb754a91bed1961ceb7d6 [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
12#include "lldb/Core/DataExtractor.h"
Enrico Granataebdc1ac2014-11-05 21:20:48 +000013#include "lldb/Core/Debugger.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000014#include "lldb/Core/Error.h"
Enrico Granataebdc1ac2014-11-05 21:20:48 +000015#include "lldb/Core/ValueObject.h"
Enrico Granataac494532015-09-09 22:30:24 +000016#include "lldb/Target/Language.h"
Enrico Granataca6c8ee2014-10-30 01:45:39 +000017#include "lldb/Target/Process.h"
18#include "lldb/Target/Target.h"
19
20#include "llvm/Support/ConvertUTF.h"
21
Enrico Granataca6c8ee2014-10-30 01:45:39 +000022#include <ctype.h>
Enrico Granataca6c8ee2014-10-30 01:45:39 +000023#include <locale>
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::formatters;
28
Enrico Granataca6c8ee2014-10-30 01:45:39 +000029// we define this for all values of type but only implement it for those we care about
30// that's good because we get linker errors for any unsupported type
Enrico Granataac494532015-09-09 22:30:24 +000031template <lldb_private::formatters::StringPrinter::StringElementType type>
Enrico Granataad650a12015-09-09 20:59:49 +000032static StringPrinter::StringPrinterBufferPointer<>
Enrico Granataca6c8ee2014-10-30 01:45:39 +000033GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next);
34
35// mimic isprint() for Unicode codepoints
36static bool
37isprint(char32_t codepoint)
38{
39 if (codepoint <= 0x1F || codepoint == 0x7F) // C0
40 {
41 return false;
42 }
43 if (codepoint >= 0x80 && codepoint <= 0x9F) // C1
44 {
45 return false;
46 }
47 if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators
48 {
49 return false;
50 }
51 if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control
52 {
53 return false;
54 }
55 if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials
56 {
57 return false;
58 }
59 return true;
60}
61
62template <>
Enrico Granataad650a12015-09-09 20:59:49 +000063StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +000064GetPrintableImpl<StringPrinter::StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +000065{
Enrico Granataad650a12015-09-09 20:59:49 +000066 StringPrinter::StringPrinterBufferPointer<> retval = {nullptr};
Enrico Granataca6c8ee2014-10-30 01:45:39 +000067
68 switch (*buffer)
69 {
Enrico Granatada04fbb2014-12-18 19:43:29 +000070 case 0:
71 retval = {"\\0",2};
72 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +000073 case '\a':
74 retval = {"\\a",2};
75 break;
76 case '\b':
77 retval = {"\\b",2};
78 break;
79 case '\f':
80 retval = {"\\f",2};
81 break;
82 case '\n':
83 retval = {"\\n",2};
84 break;
85 case '\r':
86 retval = {"\\r",2};
87 break;
88 case '\t':
89 retval = {"\\t",2};
90 break;
91 case '\v':
92 retval = {"\\v",2};
93 break;
94 case '\"':
95 retval = {"\\\"",2};
96 break;
97 case '\\':
98 retval = {"\\\\",2};
99 break;
100 default:
101 if (isprint(*buffer))
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000102 retval = {buffer,1};
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000103 else
104 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000105 uint8_t* data = new uint8_t[5];
106 sprintf((char*)data,"\\x%02x",*buffer);
107 retval = {data, 4, [] (const uint8_t* c) {delete[] c;} };
108 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000109 }
110 }
111
112 next = buffer + 1;
113 return retval;
114}
115
116static char32_t
117ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1)
118{
119 return (c0-192)*64+(c1-128);
120}
121static char32_t
122ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2)
123{
124 return (c0-224)*4096+(c1-128)*64+(c2-128);
125}
126static char32_t
127ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3)
128{
129 return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128);
130}
131
132template <>
Enrico Granataad650a12015-09-09 20:59:49 +0000133StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +0000134GetPrintableImpl<StringPrinter::StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000135{
Enrico Granataad650a12015-09-09 20:59:49 +0000136 StringPrinter::StringPrinterBufferPointer<> retval {nullptr};
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000137
138 unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer);
139
140 if (1+buffer_end-buffer < utf8_encoded_len)
141 {
142 // I don't have enough bytes - print whatever I have left
143 retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)};
144 next = buffer_end+1;
145 return retval;
146 }
147
148 char32_t codepoint = 0;
149 switch (utf8_encoded_len)
150 {
151 case 1:
152 // this is just an ASCII byte - ask ASCII
Enrico Granataac494532015-09-09 22:30:24 +0000153 return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000154 case 2:
155 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1));
156 break;
157 case 3:
158 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2));
159 break;
160 case 4:
161 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3));
162 break;
163 default:
164 // this is probably some bogus non-character thing
165 // just print it as-is and hope to sync up again soon
166 retval = {buffer,1};
167 next = buffer+1;
168 return retval;
169 }
170
171 if (codepoint)
172 {
173 switch (codepoint)
174 {
Enrico Granatada04fbb2014-12-18 19:43:29 +0000175 case 0:
176 retval = {"\\0",2};
177 break;
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000178 case '\a':
179 retval = {"\\a",2};
180 break;
181 case '\b':
182 retval = {"\\b",2};
183 break;
184 case '\f':
185 retval = {"\\f",2};
186 break;
187 case '\n':
188 retval = {"\\n",2};
189 break;
190 case '\r':
191 retval = {"\\r",2};
192 break;
193 case '\t':
194 retval = {"\\t",2};
195 break;
196 case '\v':
197 retval = {"\\v",2};
198 break;
199 case '\"':
200 retval = {"\\\"",2};
201 break;
202 case '\\':
203 retval = {"\\\\",2};
204 break;
205 default:
206 if (isprint(codepoint))
207 retval = {buffer,utf8_encoded_len};
208 else
209 {
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000210 uint8_t* data = new uint8_t[11];
211 sprintf((char*)data,"\\U%08x",codepoint);
212 retval = { data,10,[] (const uint8_t* c) {delete[] c;} };
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000213 break;
214 }
215 }
216
217 next = buffer + utf8_encoded_len;
218 return retval;
219 }
220
221 // this should not happen - but just in case.. try to resync at some point
222 retval = {buffer,1};
223 next = buffer+1;
224 return retval;
225}
226
227// Given a sequence of bytes, this function returns:
228// a sequence of bytes to actually print out + a length
229// the following unscanned position of the buffer is in next
Enrico Granataad650a12015-09-09 20:59:49 +0000230static StringPrinter::StringPrinterBufferPointer<>
Enrico Granataac494532015-09-09 22:30:24 +0000231GetPrintable(StringPrinter::StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000232{
233 if (!buffer)
234 return {nullptr};
235
236 switch (type)
237 {
Enrico Granataac494532015-09-09 22:30:24 +0000238 case StringPrinter::StringElementType::ASCII:
239 return GetPrintableImpl<StringPrinter::StringElementType::ASCII>(buffer, buffer_end, next);
240 case StringPrinter::StringElementType::UTF8:
241 return GetPrintableImpl<StringPrinter::StringElementType::UTF8>(buffer, buffer_end, next);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000242 default:
243 return {nullptr};
244 }
245}
246
Enrico Granataac494532015-09-09 22:30:24 +0000247StringPrinter::EscapingHelper
248StringPrinter::GetDefaultEscapingHelper (GetPrintableElementType elem_type)
249{
250 switch (elem_type)
251 {
252 case GetPrintableElementType::UTF8:
253 return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
254 return GetPrintable(StringPrinter::StringElementType::UTF8, buffer, buffer_end, next);
255 };
256 case GetPrintableElementType::ASCII:
257 return [] (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) -> StringPrinter::StringPrinterBufferPointer<> {
258 return GetPrintable(StringPrinter::StringElementType::ASCII, buffer, buffer_end, next);
259 };
260 }
261}
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 Granataca6c8ee2014-10-30 01:45:39 +0000377 return true;
378}
379
Enrico Granataac494532015-09-09 22:30:24 +0000380lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) :
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000381 ReadStringAndDumpToStreamOptions()
382{
383 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
384}
385
Enrico Granataac494532015-09-09 22:30:24 +0000386lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) :
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000387 ReadBufferAndDumpToStreamOptions()
388{
389 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
390}
391
Enrico Granataac494532015-09-09 22:30:24 +0000392lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const ReadStringAndDumpToStreamOptions& options) :
Enrico Granatad07f7552015-07-17 01:03:59 +0000393 ReadBufferAndDumpToStreamOptions()
394{
395 SetStream(options.GetStream());
396 SetPrefixToken(options.GetPrefixToken());
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000397 SetSuffixToken(options.GetSuffixToken());
Enrico Granatad07f7552015-07-17 01:03:59 +0000398 SetQuote(options.GetQuote());
399 SetEscapeNonPrintables(options.GetEscapeNonPrintables());
400 SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
Enrico Granataac494532015-09-09 22:30:24 +0000401 SetLanguage(options.GetLanguage());
Enrico Granatad07f7552015-07-17 01:03:59 +0000402}
403
Enrico Granataebdc1ac2014-11-05 21:20:48 +0000404
Shawn Bestfd137432014-11-04 22:43:34 +0000405namespace lldb_private
406{
407
408namespace formatters
409{
410
411template <>
412bool
Enrico Granataac494532015-09-09 22:30:24 +0000413StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options)
Shawn Bestfd137432014-11-04 22:43:34 +0000414{
415 assert(options.GetStream() && "need a Stream to print the string to");
416 Error my_error;
Shawn Bestfd137432014-11-04 22:43:34 +0000417
418 ProcessSP process_sp(options.GetProcessSP());
419
420 if (process_sp.get() == nullptr || options.GetLocation() == 0)
421 return false;
422
423 size_t size;
424
425 if (options.GetSourceSize() == 0)
426 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
Enrico Granata34042212014-11-18 22:54:45 +0000427 else if (!options.GetIgnoreMaxLength())
Shawn Bestfd137432014-11-04 22:43:34 +0000428 size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary());
Enrico Granata34042212014-11-18 22:54:45 +0000429 else
430 size = options.GetSourceSize();
Shawn Bestfd137432014-11-04 22:43:34 +0000431
432 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
433
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000434 process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error);
Shawn Bestfd137432014-11-04 22:43:34 +0000435
436 if (my_error.Fail())
437 return false;
438
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000439 const char* prefix_token = options.GetPrefixToken();
Shawn Bestfd137432014-11-04 22:43:34 +0000440 char quote = options.GetQuote();
441
442 if (prefix_token != 0)
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000443 options.GetStream()->Printf("%s%c",prefix_token,quote);
Shawn Bestfd137432014-11-04 22:43:34 +0000444 else if (quote != 0)
445 options.GetStream()->Printf("%c",quote);
446
447 uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize();
448
Enrico Granataac494532015-09-09 22:30:24 +0000449 const bool escape_non_printables = options.GetEscapeNonPrintables();
450 lldb_private::formatters::StringPrinter::EscapingHelper escaping_callback;
451 if (escape_non_printables)
452 {
453 if (Language *language = Language::FindPlugin(options.GetLanguage()))
454 escaping_callback = language->GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
455 else
456 escaping_callback = lldb_private::formatters::StringPrinter::GetDefaultEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType::ASCII);
457 }
458
Shawn Bestfd137432014-11-04 22:43:34 +0000459 // since we tend to accept partial data (and even partially malformed data)
460 // we might end up with no NULL terminator before the end_ptr
461 // hence we need to take a slower route and ensure we stay within boundaries
462 for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);)
463 {
Enrico Granataac494532015-09-09 22:30:24 +0000464 if (escape_non_printables)
Shawn Bestfd137432014-11-04 22:43:34 +0000465 {
466 uint8_t* next_data = nullptr;
Enrico Granataac494532015-09-09 22:30:24 +0000467 auto printable = escaping_callback(data, data_end, next_data);
Shawn Bestfd137432014-11-04 22:43:34 +0000468 auto printable_bytes = printable.GetBytes();
469 auto printable_size = printable.GetSize();
470 if (!printable_bytes || !next_data)
471 {
472 // GetPrintable() failed on us - print one byte in a desperate resync attempt
473 printable_bytes = data;
474 printable_size = 1;
475 next_data = data+1;
476 }
Andy Gibbs3acfe1a2014-12-29 13:03:19 +0000477 for (unsigned c = 0; c < printable_size; c++)
Shawn Bestfd137432014-11-04 22:43:34 +0000478 options.GetStream()->Printf("%c", *(printable_bytes+c));
479 data = (uint8_t*)next_data;
480 }
481 else
482 {
483 options.GetStream()->Printf("%c",*data);
484 data++;
485 }
486 }
Enrico Granatad54f7fb2015-10-07 02:06:48 +0000487
488 const char* suffix_token = options.GetSuffixToken();
489
490 if (suffix_token != 0)
491 options.GetStream()->Printf("%c%s",quote, suffix_token);
492 else if (quote != 0)
Shawn Bestfd137432014-11-04 22:43:34 +0000493 options.GetStream()->Printf("%c",quote);
494
495 return true;
496}
497
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000498template<typename SourceDataType>
499static bool
Enrico Granataac494532015-09-09 22:30:24 +0000500ReadUTFBufferAndDumpToStream (const StringPrinter::ReadStringAndDumpToStreamOptions& options,
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000501 ConversionResult (*ConvertFunction) (const SourceDataType**,
502 const SourceDataType*,
503 UTF8**,
504 UTF8*,
505 ConversionFlags))
506{
507 assert(options.GetStream() && "need a Stream to print the string to");
508
509 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
510 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000511
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000512 lldb::ProcessSP process_sp(options.GetProcessSP());
Shawn Bestfd137432014-11-04 22:43:34 +0000513
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000514 if (!process_sp)
515 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000516
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000517 const int type_width = sizeof(SourceDataType);
518 const int origin_encoding = 8 * type_width ;
519 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
520 return false;
521 // if not UTF8, I need a conversion function to return proper UTF8
522 if (origin_encoding != 8 && !ConvertFunction)
523 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000524
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000525 if (!options.GetStream())
526 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000527
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000528 uint32_t sourceSize = options.GetSourceSize();
529 bool needs_zero_terminator = options.GetNeedsZeroTermination();
Shawn Bestfd137432014-11-04 22:43:34 +0000530
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000531 if (!sourceSize)
532 {
533 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
534 needs_zero_terminator = true;
535 }
Enrico Granatab0e8a552015-05-01 22:57:38 +0000536 else if (!options.GetIgnoreMaxLength())
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000537 sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
Shawn Bestfd137432014-11-04 22:43:34 +0000538
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000539 const int bufferSPSize = sourceSize * type_width;
Shawn Bestfd137432014-11-04 22:43:34 +0000540
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000541 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
Shawn Bestfd137432014-11-04 22:43:34 +0000542
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000543 if (!buffer_sp->GetBytes())
544 return false;
Shawn Bestfd137432014-11-04 22:43:34 +0000545
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000546 Error error;
547 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
Shawn Bestfd137432014-11-04 22:43:34 +0000548
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000549 if (needs_zero_terminator)
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000550 process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000551 else
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000552 process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
Shawn Bestfd137432014-11-04 22:43:34 +0000553
Enrico Granata099263b2014-11-17 23:14:11 +0000554 if (error.Fail())
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000555 {
556 options.GetStream()->Printf("unable to read data");
557 return true;
558 }
Shawn Bestfd137432014-11-04 22:43:34 +0000559
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000560 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
Enrico Granatad07f7552015-07-17 01:03:59 +0000561
Enrico Granataac494532015-09-09 22:30:24 +0000562 StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options);
Enrico Granatad07f7552015-07-17 01:03:59 +0000563 dump_options.SetData(data);
564 dump_options.SetSourceSize(sourceSize);
Shawn Bestfd137432014-11-04 22:43:34 +0000565
Enrico Granatad07f7552015-07-17 01:03:59 +0000566 return DumpUTFBufferToStream(ConvertFunction, dump_options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000567}
568
569template <>
570bool
Enrico Granataac494532015-09-09 22:30:24 +0000571StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000572{
573 return ReadUTFBufferAndDumpToStream<UTF8>(options,
574 nullptr);
575}
576
577template <>
578bool
Enrico Granataac494532015-09-09 22:30:24 +0000579StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000580{
581 return ReadUTFBufferAndDumpToStream<UTF16>(options,
582 ConvertUTF16toUTF8);
583}
584
585template <>
586bool
Enrico Granataac494532015-09-09 22:30:24 +0000587StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000588{
589 return ReadUTFBufferAndDumpToStream<UTF32>(options,
590 ConvertUTF32toUTF8);
591}
592
593template <>
594bool
Enrico Granataac494532015-09-09 22:30:24 +0000595StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000596{
597 assert(options.GetStream() && "need a Stream to print the string to");
598
Enrico Granatad07f7552015-07-17 01:03:59 +0000599 return DumpUTFBufferToStream<UTF8>(nullptr, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000600}
601
602template <>
603bool
Enrico Granataac494532015-09-09 22:30:24 +0000604StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000605{
606 // treat ASCII the same as UTF8
607 // FIXME: can we optimize ASCII some more?
608 return ReadBufferAndDumpToStream<StringElementType::UTF8>(options);
609}
610
611template <>
612bool
Enrico Granataac494532015-09-09 22:30:24 +0000613StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000614{
615 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000616
Enrico Granatad07f7552015-07-17 01:03:59 +0000617 return DumpUTFBufferToStream(ConvertUTF16toUTF8, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000618}
619
620template <>
621bool
Enrico Granataac494532015-09-09 22:30:24 +0000622StringPrinter::ReadBufferAndDumpToStream<StringPrinter::StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options)
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000623{
624 assert(options.GetStream() && "need a Stream to print the string to");
Shawn Bestfd137432014-11-04 22:43:34 +0000625
Enrico Granatad07f7552015-07-17 01:03:59 +0000626 return DumpUTFBufferToStream(ConvertUTF32toUTF8, options);
Enrico Granataca6c8ee2014-10-30 01:45:39 +0000627}
Shawn Bestfd137432014-11-04 22:43:34 +0000628
629} // namespace formatters
630
631} // namespace lldb_private