1 //===-- 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" 13 #include "lldb/Core/Error.h" 14 #include "lldb/Target/Process.h" 15 #include "lldb/Target/Target.h" 16 17 #include "llvm/Support/ConvertUTF.h" 18 19 #include <codecvt> 20 #include <ctype.h> 21 #include <functional> 22 #include <locale> 23 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace lldb_private::formatters; 27 28 // I can't use a std::unique_ptr for this because the Deleter is a template argument there 29 // and I want the same type to represent both pointers I want to free and pointers I don't need 30 // to free - which is what this class essentially is 31 // It's very specialized to the needs of this file, and not suggested for general use 32 template <typename T = uint8_t, typename U = char, typename S = size_t> 33 struct StringPrinterBufferPointer 34 { 35 public: 36 37 typedef std::function<void(const T*)> Deleter; 38 39 StringPrinterBufferPointer (std::nullptr_t ptr) : 40 m_data(nullptr), 41 m_size(0), 42 m_deleter() 43 {} 44 45 StringPrinterBufferPointer(const T* bytes, S size, Deleter deleter = nullptr) : 46 m_data(bytes), 47 m_size(size), 48 m_deleter(deleter) 49 {} 50 51 StringPrinterBufferPointer(const U* bytes, S size, Deleter deleter = nullptr) : 52 m_data((T*)bytes), 53 m_size(size), 54 m_deleter(deleter) 55 {} 56 57 StringPrinterBufferPointer(StringPrinterBufferPointer&& rhs) : 58 m_data(rhs.m_data), 59 m_size(rhs.m_size), 60 m_deleter(rhs.m_deleter) 61 { 62 rhs.m_data = nullptr; 63 } 64 65 StringPrinterBufferPointer(const StringPrinterBufferPointer& rhs) : 66 m_data(rhs.m_data), 67 m_size(rhs.m_size), 68 m_deleter(rhs.m_deleter) 69 { 70 rhs.m_data = nullptr; // this is why m_data has to be mutable 71 } 72 73 const T* 74 GetBytes () const 75 { 76 return m_data; 77 } 78 79 const S 80 GetSize () const 81 { 82 return m_size; 83 } 84 85 ~StringPrinterBufferPointer () 86 { 87 if (m_data && m_deleter) 88 m_deleter(m_data); 89 m_data = nullptr; 90 } 91 92 StringPrinterBufferPointer& 93 operator = (const StringPrinterBufferPointer& rhs) 94 { 95 if (m_data && m_deleter) 96 m_deleter(m_data); 97 m_data = rhs.m_data; 98 m_size = rhs.m_size; 99 m_deleter = rhs.m_deleter; 100 rhs.m_data = nullptr; 101 return *this; 102 } 103 104 private: 105 mutable const T* m_data; 106 size_t m_size; 107 Deleter m_deleter; 108 }; 109 110 // we define this for all values of type but only implement it for those we care about 111 // that's good because we get linker errors for any unsupported type 112 template <StringElementType type> 113 static StringPrinterBufferPointer<> 114 GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next); 115 116 // mimic isprint() for Unicode codepoints 117 static bool 118 isprint(char32_t codepoint) 119 { 120 if (codepoint <= 0x1F || codepoint == 0x7F) // C0 121 { 122 return false; 123 } 124 if (codepoint >= 0x80 && codepoint <= 0x9F) // C1 125 { 126 return false; 127 } 128 if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators 129 { 130 return false; 131 } 132 if (codepoint == 0x200E || codepoint == 0x200F || (codepoint >= 0x202A && codepoint <= 0x202E)) // bidirectional text control 133 { 134 return false; 135 } 136 if (codepoint >= 0xFFF9 && codepoint <= 0xFFFF) // interlinears and generally specials 137 { 138 return false; 139 } 140 return true; 141 } 142 143 template <> 144 StringPrinterBufferPointer<> 145 GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 146 { 147 StringPrinterBufferPointer<> retval = {nullptr}; 148 149 switch (*buffer) 150 { 151 case '\a': 152 retval = {"\\a",2}; 153 break; 154 case '\b': 155 retval = {"\\b",2}; 156 break; 157 case '\f': 158 retval = {"\\f",2}; 159 break; 160 case '\n': 161 retval = {"\\n",2}; 162 break; 163 case '\r': 164 retval = {"\\r",2}; 165 break; 166 case '\t': 167 retval = {"\\t",2}; 168 break; 169 case '\v': 170 retval = {"\\v",2}; 171 break; 172 case '\"': 173 retval = {"\\\"",2}; 174 break; 175 case '\\': 176 retval = {"\\\\",2}; 177 break; 178 default: 179 if (isprint(*buffer)) 180 retval = {buffer,1}; 181 else 182 { 183 retval = { new uint8_t[5],4,[] (const uint8_t* c) {delete[] c;} }; 184 sprintf((char*)retval.GetBytes(),"\\x%02x",*buffer); 185 break; 186 } 187 } 188 189 next = buffer + 1; 190 return retval; 191 } 192 193 static char32_t 194 ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1) 195 { 196 return (c0-192)*64+(c1-128); 197 } 198 static char32_t 199 ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2) 200 { 201 return (c0-224)*4096+(c1-128)*64+(c2-128); 202 } 203 static char32_t 204 ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3) 205 { 206 return (c0-240)*262144+(c2-128)*4096+(c2-128)*64+(c3-128); 207 } 208 209 template <> 210 StringPrinterBufferPointer<> 211 GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 212 { 213 StringPrinterBufferPointer<> retval {nullptr}; 214 215 unsigned utf8_encoded_len = getNumBytesForUTF8(*buffer); 216 217 if (1+buffer_end-buffer < utf8_encoded_len) 218 { 219 // I don't have enough bytes - print whatever I have left 220 retval = {buffer,static_cast<size_t>(1+buffer_end-buffer)}; 221 next = buffer_end+1; 222 return retval; 223 } 224 225 char32_t codepoint = 0; 226 switch (utf8_encoded_len) 227 { 228 case 1: 229 // this is just an ASCII byte - ask ASCII 230 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); 231 case 2: 232 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1)); 233 break; 234 case 3: 235 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2)); 236 break; 237 case 4: 238 codepoint = ConvertUTF8ToCodePoint((unsigned char)*buffer, (unsigned char)*(buffer+1), (unsigned char)*(buffer+2), (unsigned char)*(buffer+3)); 239 break; 240 default: 241 // this is probably some bogus non-character thing 242 // just print it as-is and hope to sync up again soon 243 retval = {buffer,1}; 244 next = buffer+1; 245 return retval; 246 } 247 248 if (codepoint) 249 { 250 switch (codepoint) 251 { 252 case '\a': 253 retval = {"\\a",2}; 254 break; 255 case '\b': 256 retval = {"\\b",2}; 257 break; 258 case '\f': 259 retval = {"\\f",2}; 260 break; 261 case '\n': 262 retval = {"\\n",2}; 263 break; 264 case '\r': 265 retval = {"\\r",2}; 266 break; 267 case '\t': 268 retval = {"\\t",2}; 269 break; 270 case '\v': 271 retval = {"\\v",2}; 272 break; 273 case '\"': 274 retval = {"\\\"",2}; 275 break; 276 case '\\': 277 retval = {"\\\\",2}; 278 break; 279 default: 280 if (isprint(codepoint)) 281 retval = {buffer,utf8_encoded_len}; 282 else 283 { 284 retval = { new uint8_t[11],10,[] (const uint8_t* c) {delete[] c;} }; 285 sprintf((char*)retval.GetBytes(),"\\U%08x",codepoint); 286 break; 287 } 288 } 289 290 next = buffer + utf8_encoded_len; 291 return retval; 292 } 293 294 // this should not happen - but just in case.. try to resync at some point 295 retval = {buffer,1}; 296 next = buffer+1; 297 return retval; 298 } 299 300 // Given a sequence of bytes, this function returns: 301 // a sequence of bytes to actually print out + a length 302 // the following unscanned position of the buffer is in next 303 static StringPrinterBufferPointer<> 304 GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 305 { 306 if (!buffer) 307 return {nullptr}; 308 309 switch (type) 310 { 311 case StringElementType::ASCII: 312 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); 313 case StringElementType::UTF8: 314 return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next); 315 default: 316 return {nullptr}; 317 } 318 } 319 320 template <> 321 bool 322 lldb_private::formatters::ReadStringAndDumpToStream<StringElementType::ASCII> (ReadStringAndDumpToStreamOptions options) 323 { 324 assert(options.GetStream() && "need a Stream to print the string to"); 325 Error my_error; 326 size_t my_data_read; 327 328 ProcessSP process_sp(options.GetProcessSP()); 329 330 if (process_sp.get() == nullptr || options.GetLocation() == 0) 331 return false; 332 333 size_t size; 334 335 if (options.GetSourceSize() == 0) 336 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 337 else 338 size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary()); 339 340 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); 341 342 my_data_read = process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error); 343 344 if (my_error.Fail()) 345 return false; 346 347 char prefix_token = options.GetPrefixToken(); 348 char quote = options.GetQuote(); 349 350 if (prefix_token != 0) 351 options.GetStream()->Printf("%c%c",prefix_token,quote); 352 else if (quote != 0) 353 options.GetStream()->Printf("%c",quote); 354 355 uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize(); 356 357 // since we tend to accept partial data (and even partially malformed data) 358 // we might end up with no NULL terminator before the end_ptr 359 // hence we need to take a slower route and ensure we stay within boundaries 360 for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);) 361 { 362 if (options.GetEscapeNonPrintables()) 363 { 364 uint8_t* next_data = nullptr; 365 auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data); 366 auto printable_bytes = printable.GetBytes(); 367 auto printable_size = printable.GetSize(); 368 if (!printable_bytes || !next_data) 369 { 370 // GetPrintable() failed on us - print one byte in a desperate resync attempt 371 printable_bytes = data; 372 printable_size = 1; 373 next_data = data+1; 374 } 375 for (int c = 0; c < printable_size; c++) 376 options.GetStream()->Printf("%c", *(printable_bytes+c)); 377 data = (uint8_t*)next_data; 378 } 379 else 380 { 381 options.GetStream()->Printf("%c",*data); 382 data++; 383 } 384 } 385 386 if (quote != 0) 387 options.GetStream()->Printf("%c",quote); 388 389 return true; 390 } 391 392 // use this call if you already have an LLDB-side buffer for the data 393 template<typename SourceDataType> 394 static bool 395 DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 396 const SourceDataType*, 397 UTF8**, 398 UTF8*, 399 ConversionFlags), 400 const DataExtractor& data, 401 Stream& stream, 402 char prefix_token, 403 char quote, 404 uint32_t sourceSize, 405 bool escapeNonPrintables) 406 { 407 if (prefix_token != 0) 408 stream.Printf("%c",prefix_token); 409 if (quote != 0) 410 stream.Printf("%c",quote); 411 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) 412 { 413 const int bufferSPSize = data.GetByteSize(); 414 if (sourceSize == 0) 415 { 416 const int origin_encoding = 8*sizeof(SourceDataType); 417 sourceSize = bufferSPSize/(origin_encoding / 4); 418 } 419 420 SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart(); 421 SourceDataType *data_end_ptr = data_ptr + sourceSize; 422 423 while (data_ptr < data_end_ptr) 424 { 425 if (!*data_ptr) 426 { 427 data_end_ptr = data_ptr; 428 break; 429 } 430 data_ptr++; 431 } 432 433 data_ptr = (SourceDataType*)data.GetDataStart(); 434 435 lldb::DataBufferSP utf8_data_buffer_sp; 436 UTF8* utf8_data_ptr = nullptr; 437 UTF8* utf8_data_end_ptr = nullptr; 438 439 if (ConvertFunction) 440 { 441 utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0)); 442 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); 443 utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize(); 444 ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); 445 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr 446 } 447 else 448 { 449 // just copy the pointers - the cast is necessary to make the compiler happy 450 // but this should only happen if we are reading UTF8 data 451 utf8_data_ptr = (UTF8*)data_ptr; 452 utf8_data_end_ptr = (UTF8*)data_end_ptr; 453 } 454 455 // since we tend to accept partial data (and even partially malformed data) 456 // we might end up with no NULL terminator before the end_ptr 457 // hence we need to take a slower route and ensure we stay within boundaries 458 for (;utf8_data_ptr < utf8_data_end_ptr;) 459 { 460 if (!*utf8_data_ptr) 461 break; 462 463 if (escapeNonPrintables) 464 { 465 uint8_t* next_data = nullptr; 466 auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data); 467 auto printable_bytes = printable.GetBytes(); 468 auto printable_size = printable.GetSize(); 469 if (!printable_bytes || !next_data) 470 { 471 // GetPrintable() failed on us - print one byte in a desperate resync attempt 472 printable_bytes = utf8_data_ptr; 473 printable_size = 1; 474 next_data = utf8_data_ptr+1; 475 } 476 for (int c = 0; c < printable_size; c++) 477 stream.Printf("%c", *(printable_bytes+c)); 478 utf8_data_ptr = (uint8_t*)next_data; 479 } 480 else 481 { 482 stream.Printf("%c",*utf8_data_ptr); 483 utf8_data_ptr++; 484 } 485 } 486 } 487 if (quote != 0) 488 stream.Printf("%c",quote); 489 return true; 490 } 491 492 template<typename SourceDataType> 493 static bool 494 ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, 495 ConversionResult (*ConvertFunction) (const SourceDataType**, 496 const SourceDataType*, 497 UTF8**, 498 UTF8*, 499 ConversionFlags)) 500 { 501 assert(options.GetStream() && "need a Stream to print the string to"); 502 503 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS) 504 return false; 505 506 lldb::ProcessSP process_sp(options.GetProcessSP()); 507 508 if (!process_sp) 509 return false; 510 511 const int type_width = sizeof(SourceDataType); 512 const int origin_encoding = 8 * type_width ; 513 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) 514 return false; 515 // if not UTF8, I need a conversion function to return proper UTF8 516 if (origin_encoding != 8 && !ConvertFunction) 517 return false; 518 519 if (!options.GetStream()) 520 return false; 521 522 uint32_t sourceSize = options.GetSourceSize(); 523 bool needs_zero_terminator = options.GetNeedsZeroTermination(); 524 525 if (!sourceSize) 526 { 527 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 528 needs_zero_terminator = true; 529 } 530 else 531 sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary()); 532 533 const int bufferSPSize = sourceSize * type_width; 534 535 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); 536 537 if (!buffer_sp->GetBytes()) 538 return false; 539 540 Error error; 541 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes()); 542 543 size_t data_read = 0; 544 if (needs_zero_terminator) 545 data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width); 546 else 547 data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error); 548 549 if (error.Fail() || data_read == 0) 550 { 551 options.GetStream()->Printf("unable to read data"); 552 return true; 553 } 554 555 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 556 557 return DumpUTFBufferToStream(ConvertFunction, data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize, options.GetEscapeNonPrintables()); 558 } 559 560 template <> 561 bool 562 lldb_private::formatters::ReadStringAndDumpToStream<StringElementType::UTF8> (ReadStringAndDumpToStreamOptions options) 563 { 564 return ReadUTFBufferAndDumpToStream<UTF8>(options, 565 nullptr); 566 } 567 568 template <> 569 bool 570 lldb_private::formatters::ReadStringAndDumpToStream<StringElementType::UTF16> (ReadStringAndDumpToStreamOptions options) 571 { 572 return ReadUTFBufferAndDumpToStream<UTF16>(options, 573 ConvertUTF16toUTF8); 574 } 575 576 template <> 577 bool 578 lldb_private::formatters::ReadStringAndDumpToStream<StringElementType::UTF32> (ReadStringAndDumpToStreamOptions options) 579 { 580 return ReadUTFBufferAndDumpToStream<UTF32>(options, 581 ConvertUTF32toUTF8); 582 } 583 584 template <> 585 bool 586 lldb_private::formatters::ReadBufferAndDumpToStream<StringElementType::UTF8> (ReadBufferAndDumpToStreamOptions options) 587 { 588 assert(options.GetStream() && "need a Stream to print the string to"); 589 590 return DumpUTFBufferToStream<UTF8>(nullptr, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); 591 } 592 593 template <> 594 bool 595 lldb_private::formatters::ReadBufferAndDumpToStream<StringElementType::ASCII> (ReadBufferAndDumpToStreamOptions options) 596 { 597 // treat ASCII the same as UTF8 598 // FIXME: can we optimize ASCII some more? 599 return ReadBufferAndDumpToStream<StringElementType::UTF8>(options); 600 } 601 602 template <> 603 bool 604 lldb_private::formatters::ReadBufferAndDumpToStream<StringElementType::UTF16> (ReadBufferAndDumpToStreamOptions options) 605 { 606 assert(options.GetStream() && "need a Stream to print the string to"); 607 608 return DumpUTFBufferToStream(ConvertUTF16toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); 609 } 610 611 template <> 612 bool 613 lldb_private::formatters::ReadBufferAndDumpToStream<StringElementType::UTF32> (ReadBufferAndDumpToStreamOptions options) 614 { 615 assert(options.GetStream() && "need a Stream to print the string to"); 616 617 return DumpUTFBufferToStream(ConvertUTF32toUTF8, options.GetData(), *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), options.GetSourceSize(), options.GetEscapeNonPrintables()); 618 } 619