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/Debugger.h" 14 #include "lldb/Core/Error.h" 15 #include "lldb/Core/ValueObject.h" 16 #include "lldb/Target/Process.h" 17 #include "lldb/Target/Target.h" 18 19 #include "llvm/Support/ConvertUTF.h" 20 21 #include <ctype.h> 22 #include <locale> 23 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace lldb_private::formatters; 27 28 // 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 30 template <StringElementType type> 31 static StringPrinter::StringPrinterBufferPointer<> 32 GetPrintableImpl(uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next); 33 34 // mimic isprint() for Unicode codepoints 35 static bool 36 isprint(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 61 template <> 62 StringPrinter::StringPrinterBufferPointer<> 63 GetPrintableImpl<StringElementType::ASCII> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 64 { 65 StringPrinter::StringPrinterBufferPointer<> retval = {nullptr}; 66 67 switch (*buffer) 68 { 69 case 0: 70 retval = {"\\0",2}; 71 break; 72 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)) 101 retval = {buffer,1}; 102 else 103 { 104 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; 108 } 109 } 110 111 next = buffer + 1; 112 return retval; 113 } 114 115 static char32_t 116 ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1) 117 { 118 return (c0-192)*64+(c1-128); 119 } 120 static char32_t 121 ConvertUTF8ToCodePoint (unsigned char c0, unsigned char c1, unsigned char c2) 122 { 123 return (c0-224)*4096+(c1-128)*64+(c2-128); 124 } 125 static char32_t 126 ConvertUTF8ToCodePoint (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 131 template <> 132 StringPrinter::StringPrinterBufferPointer<> 133 GetPrintableImpl<StringElementType::UTF8> (uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 134 { 135 StringPrinter::StringPrinterBufferPointer<> retval {nullptr}; 136 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 152 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); 153 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 { 174 case 0: 175 retval = {"\\0",2}; 176 break; 177 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 { 209 uint8_t* data = new uint8_t[11]; 210 sprintf((char*)data,"\\U%08x",codepoint); 211 retval = { data,10,[] (const uint8_t* c) {delete[] c;} }; 212 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 229 static StringPrinter::StringPrinterBufferPointer<> 230 GetPrintable(StringElementType type, uint8_t* buffer, uint8_t* buffer_end, uint8_t*& next) 231 { 232 if (!buffer) 233 return {nullptr}; 234 235 switch (type) 236 { 237 case StringElementType::ASCII: 238 return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next); 239 case StringElementType::UTF8: 240 return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next); 241 default: 242 return {nullptr}; 243 } 244 } 245 246 // use this call if you already have an LLDB-side buffer for the data 247 template<typename SourceDataType> 248 static bool 249 DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 250 const SourceDataType*, 251 UTF8**, 252 UTF8*, 253 ConversionFlags), 254 const ReadBufferAndDumpToStreamOptions& dump_options) 255 { 256 Stream &stream(*dump_options.GetStream()); 257 if (dump_options.GetPrefixToken() != 0) 258 stream.Printf("%c",dump_options.GetPrefixToken()); 259 if (dump_options.GetQuote() != 0) 260 stream.Printf("%c",dump_options.GetQuote()); 261 auto data(dump_options.GetData()); 262 auto source_size(dump_options.GetSourceSize()); 263 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) 264 { 265 const int bufferSPSize = data.GetByteSize(); 266 if (dump_options.GetSourceSize() == 0) 267 { 268 const int origin_encoding = 8*sizeof(SourceDataType); 269 source_size = bufferSPSize/(origin_encoding / 4); 270 } 271 272 const SourceDataType *data_ptr = (const SourceDataType*)data.GetDataStart(); 273 const SourceDataType *data_end_ptr = data_ptr + source_size; 274 275 const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator(); 276 277 if (zero_is_terminator) 278 { 279 while (data_ptr < data_end_ptr) 280 { 281 if (!*data_ptr) 282 { 283 data_end_ptr = data_ptr; 284 break; 285 } 286 data_ptr++; 287 } 288 289 data_ptr = (const SourceDataType*)data.GetDataStart(); 290 } 291 292 lldb::DataBufferSP utf8_data_buffer_sp; 293 UTF8* utf8_data_ptr = nullptr; 294 UTF8* utf8_data_end_ptr = nullptr; 295 296 if (ConvertFunction) 297 { 298 utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0)); 299 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); 300 utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize(); 301 ConvertFunction ( &data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); 302 if (false == zero_is_terminator) 303 utf8_data_end_ptr = utf8_data_ptr; 304 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr 305 } 306 else 307 { 308 // just copy the pointers - the cast is necessary to make the compiler happy 309 // but this should only happen if we are reading UTF8 data 310 utf8_data_ptr = (UTF8*)data_ptr; 311 utf8_data_end_ptr = (UTF8*)data_end_ptr; 312 } 313 314 const bool escape_non_printables = dump_options.GetEscapeNonPrintables(); 315 316 // since we tend to accept partial data (and even partially malformed data) 317 // we might end up with no NULL terminator before the end_ptr 318 // hence we need to take a slower route and ensure we stay within boundaries 319 for (;utf8_data_ptr < utf8_data_end_ptr;) 320 { 321 if (zero_is_terminator && !*utf8_data_ptr) 322 break; 323 324 if (escape_non_printables) 325 { 326 uint8_t* next_data = nullptr; 327 auto printable = GetPrintable(StringElementType::UTF8, utf8_data_ptr, utf8_data_end_ptr, next_data); 328 auto printable_bytes = printable.GetBytes(); 329 auto printable_size = printable.GetSize(); 330 if (!printable_bytes || !next_data) 331 { 332 // GetPrintable() failed on us - print one byte in a desperate resync attempt 333 printable_bytes = utf8_data_ptr; 334 printable_size = 1; 335 next_data = utf8_data_ptr+1; 336 } 337 for (unsigned c = 0; c < printable_size; c++) 338 stream.Printf("%c", *(printable_bytes+c)); 339 utf8_data_ptr = (uint8_t*)next_data; 340 } 341 else 342 { 343 stream.Printf("%c",*utf8_data_ptr); 344 utf8_data_ptr++; 345 } 346 } 347 } 348 if (dump_options.GetQuote() != 0) 349 stream.Printf("%c",dump_options.GetQuote()); 350 return true; 351 } 352 353 lldb_private::formatters::ReadStringAndDumpToStreamOptions::ReadStringAndDumpToStreamOptions (ValueObject& valobj) : 354 ReadStringAndDumpToStreamOptions() 355 { 356 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); 357 } 358 359 lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (ValueObject& valobj) : 360 ReadBufferAndDumpToStreamOptions() 361 { 362 SetEscapeNonPrintables(valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables()); 363 } 364 365 lldb_private::formatters::ReadBufferAndDumpToStreamOptions::ReadBufferAndDumpToStreamOptions (const lldb_private::formatters::ReadStringAndDumpToStreamOptions& options) : 366 ReadBufferAndDumpToStreamOptions() 367 { 368 SetStream(options.GetStream()); 369 SetPrefixToken(options.GetPrefixToken()); 370 SetQuote(options.GetQuote()); 371 SetEscapeNonPrintables(options.GetEscapeNonPrintables()); 372 SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator()); 373 } 374 375 376 namespace lldb_private 377 { 378 379 namespace formatters 380 { 381 382 template <> 383 bool 384 StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII> (const ReadStringAndDumpToStreamOptions& options) 385 { 386 assert(options.GetStream() && "need a Stream to print the string to"); 387 Error my_error; 388 389 ProcessSP process_sp(options.GetProcessSP()); 390 391 if (process_sp.get() == nullptr || options.GetLocation() == 0) 392 return false; 393 394 size_t size; 395 396 if (options.GetSourceSize() == 0) 397 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 398 else if (!options.GetIgnoreMaxLength()) 399 size = std::min(options.GetSourceSize(),process_sp->GetTarget().GetMaximumSizeOfStringSummary()); 400 else 401 size = options.GetSourceSize(); 402 403 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); 404 405 process_sp->ReadCStringFromMemory(options.GetLocation(), (char*)buffer_sp->GetBytes(), size, my_error); 406 407 if (my_error.Fail()) 408 return false; 409 410 char prefix_token = options.GetPrefixToken(); 411 char quote = options.GetQuote(); 412 413 if (prefix_token != 0) 414 options.GetStream()->Printf("%c%c",prefix_token,quote); 415 else if (quote != 0) 416 options.GetStream()->Printf("%c",quote); 417 418 uint8_t* data_end = buffer_sp->GetBytes()+buffer_sp->GetByteSize(); 419 420 // since we tend to accept partial data (and even partially malformed data) 421 // we might end up with no NULL terminator before the end_ptr 422 // hence we need to take a slower route and ensure we stay within boundaries 423 for (uint8_t* data = buffer_sp->GetBytes(); *data && (data < data_end);) 424 { 425 if (options.GetEscapeNonPrintables()) 426 { 427 uint8_t* next_data = nullptr; 428 auto printable = GetPrintable(StringElementType::ASCII, data, data_end, next_data); 429 auto printable_bytes = printable.GetBytes(); 430 auto printable_size = printable.GetSize(); 431 if (!printable_bytes || !next_data) 432 { 433 // GetPrintable() failed on us - print one byte in a desperate resync attempt 434 printable_bytes = data; 435 printable_size = 1; 436 next_data = data+1; 437 } 438 for (unsigned c = 0; c < printable_size; c++) 439 options.GetStream()->Printf("%c", *(printable_bytes+c)); 440 data = (uint8_t*)next_data; 441 } 442 else 443 { 444 options.GetStream()->Printf("%c",*data); 445 data++; 446 } 447 } 448 449 if (quote != 0) 450 options.GetStream()->Printf("%c",quote); 451 452 return true; 453 } 454 455 template<typename SourceDataType> 456 static bool 457 ReadUTFBufferAndDumpToStream (const ReadStringAndDumpToStreamOptions& options, 458 ConversionResult (*ConvertFunction) (const SourceDataType**, 459 const SourceDataType*, 460 UTF8**, 461 UTF8*, 462 ConversionFlags)) 463 { 464 assert(options.GetStream() && "need a Stream to print the string to"); 465 466 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS) 467 return false; 468 469 lldb::ProcessSP process_sp(options.GetProcessSP()); 470 471 if (!process_sp) 472 return false; 473 474 const int type_width = sizeof(SourceDataType); 475 const int origin_encoding = 8 * type_width ; 476 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) 477 return false; 478 // if not UTF8, I need a conversion function to return proper UTF8 479 if (origin_encoding != 8 && !ConvertFunction) 480 return false; 481 482 if (!options.GetStream()) 483 return false; 484 485 uint32_t sourceSize = options.GetSourceSize(); 486 bool needs_zero_terminator = options.GetNeedsZeroTermination(); 487 488 if (!sourceSize) 489 { 490 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 491 needs_zero_terminator = true; 492 } 493 else if (!options.GetIgnoreMaxLength()) 494 sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary()); 495 496 const int bufferSPSize = sourceSize * type_width; 497 498 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); 499 500 if (!buffer_sp->GetBytes()) 501 return false; 502 503 Error error; 504 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes()); 505 506 if (needs_zero_terminator) 507 process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width); 508 else 509 process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error); 510 511 if (error.Fail()) 512 { 513 options.GetStream()->Printf("unable to read data"); 514 return true; 515 } 516 517 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 518 519 ReadBufferAndDumpToStreamOptions dump_options(options); 520 dump_options.SetData(data); 521 dump_options.SetSourceSize(sourceSize); 522 523 return DumpUTFBufferToStream(ConvertFunction, dump_options); 524 } 525 526 template <> 527 bool 528 StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8> (const ReadStringAndDumpToStreamOptions& options) 529 { 530 return ReadUTFBufferAndDumpToStream<UTF8>(options, 531 nullptr); 532 } 533 534 template <> 535 bool 536 StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16> (const ReadStringAndDumpToStreamOptions& options) 537 { 538 return ReadUTFBufferAndDumpToStream<UTF16>(options, 539 ConvertUTF16toUTF8); 540 } 541 542 template <> 543 bool 544 StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32> (const ReadStringAndDumpToStreamOptions& options) 545 { 546 return ReadUTFBufferAndDumpToStream<UTF32>(options, 547 ConvertUTF32toUTF8); 548 } 549 550 template <> 551 bool 552 StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8> (const ReadBufferAndDumpToStreamOptions& options) 553 { 554 assert(options.GetStream() && "need a Stream to print the string to"); 555 556 return DumpUTFBufferToStream<UTF8>(nullptr, options); 557 } 558 559 template <> 560 bool 561 StringPrinter::ReadBufferAndDumpToStream<StringElementType::ASCII> (const ReadBufferAndDumpToStreamOptions& options) 562 { 563 // treat ASCII the same as UTF8 564 // FIXME: can we optimize ASCII some more? 565 return ReadBufferAndDumpToStream<StringElementType::UTF8>(options); 566 } 567 568 template <> 569 bool 570 StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16> (const ReadBufferAndDumpToStreamOptions& options) 571 { 572 assert(options.GetStream() && "need a Stream to print the string to"); 573 574 return DumpUTFBufferToStream(ConvertUTF16toUTF8, options); 575 } 576 577 template <> 578 bool 579 StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32> (const ReadBufferAndDumpToStreamOptions& options) 580 { 581 assert(options.GetStream() && "need a Stream to print the string to"); 582 583 return DumpUTFBufferToStream(ConvertUTF32toUTF8, options); 584 } 585 586 } // namespace formatters 587 588 } // namespace lldb_private 589