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