1 //===-- Stream.cpp --------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Utility/Stream.h" 10 11 #include "lldb/Utility/Endian.h" 12 #include "lldb/Utility/VASPrintf.h" 13 #include "llvm/ADT/SmallString.h" 14 #include "llvm/Support/Format.h" 15 #include "llvm/Support/LEB128.h" 16 17 #include <string> 18 19 #include <cinttypes> 20 #include <cstddef> 21 22 using namespace lldb; 23 using namespace lldb_private; 24 25 Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, 26 bool colors) 27 : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order), 28 m_indent_level(0), m_forwarder(*this, colors) {} 29 30 Stream::Stream(bool colors) 31 : m_flags(0), m_byte_order(endian::InlHostByteOrder()), 32 m_forwarder(*this, colors) {} 33 34 // Destructor 35 Stream::~Stream() = default; 36 37 ByteOrder Stream::SetByteOrder(ByteOrder byte_order) { 38 ByteOrder old_byte_order = m_byte_order; 39 m_byte_order = byte_order; 40 return old_byte_order; 41 } 42 43 // Put an offset "uval" out to the stream using the printf format in "format". 44 void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); } 45 46 // Put an SLEB128 "uval" out to the stream using the printf format in "format". 47 size_t Stream::PutSLEB128(int64_t sval) { 48 if (m_flags.Test(eBinary)) 49 return llvm::encodeSLEB128(sval, m_forwarder); 50 else 51 return Printf("0x%" PRIi64, sval); 52 } 53 54 // Put an ULEB128 "uval" out to the stream using the printf format in "format". 55 size_t Stream::PutULEB128(uint64_t uval) { 56 if (m_flags.Test(eBinary)) 57 return llvm::encodeULEB128(uval, m_forwarder); 58 else 59 return Printf("0x%" PRIx64, uval); 60 } 61 62 // Print a raw NULL terminated C string to the stream. 63 size_t Stream::PutCString(llvm::StringRef str) { 64 size_t bytes_written = 0; 65 bytes_written = Write(str.data(), str.size()); 66 67 // when in binary mode, emit the NULL terminator 68 if (m_flags.Test(eBinary)) 69 bytes_written += PutChar('\0'); 70 return bytes_written; 71 } 72 73 // Print a double quoted NULL terminated C string to the stream using the 74 // printf format in "format". 75 void Stream::QuotedCString(const char *cstr, const char *format) { 76 Printf(format, cstr); 77 } 78 79 // Put an address "addr" out to the stream with optional prefix and suffix 80 // strings. 81 void lldb_private::DumpAddress(llvm::raw_ostream &s, uint64_t addr, 82 uint32_t addr_size, const char *prefix, 83 const char *suffix) { 84 if (prefix == nullptr) 85 prefix = ""; 86 if (suffix == nullptr) 87 suffix = ""; 88 s << prefix << llvm::format_hex(addr, 2 + 2 * addr_size) << suffix; 89 } 90 91 // Put an address range out to the stream with optional prefix and suffix 92 // strings. 93 void lldb_private::DumpAddressRange(llvm::raw_ostream &s, uint64_t lo_addr, 94 uint64_t hi_addr, uint32_t addr_size, 95 const char *prefix, const char *suffix) { 96 if (prefix && prefix[0]) 97 s << prefix; 98 DumpAddress(s, lo_addr, addr_size, "["); 99 DumpAddress(s, hi_addr, addr_size, "-", ")"); 100 if (suffix && suffix[0]) 101 s << suffix; 102 } 103 104 size_t Stream::PutChar(char ch) { return Write(&ch, 1); } 105 106 // Print some formatted output to the stream. 107 size_t Stream::Printf(const char *format, ...) { 108 va_list args; 109 va_start(args, format); 110 size_t result = PrintfVarArg(format, args); 111 va_end(args); 112 return result; 113 } 114 115 // Print some formatted output to the stream. 116 size_t Stream::PrintfVarArg(const char *format, va_list args) { 117 llvm::SmallString<1024> buf; 118 VASprintf(buf, format, args); 119 120 // Include the NULL termination byte for binary output 121 size_t length = buf.size(); 122 if (m_flags.Test(eBinary)) 123 ++length; 124 return Write(buf.c_str(), length); 125 } 126 127 // Print and End of Line character to the stream 128 size_t Stream::EOL() { return PutChar('\n'); } 129 130 size_t Stream::Indent(llvm::StringRef str) { 131 const size_t ind_length = PutCString(std::string(m_indent_level, ' ')); 132 const size_t str_length = PutCString(str); 133 return ind_length + str_length; 134 } 135 136 // Stream a character "ch" out to this stream. 137 Stream &Stream::operator<<(char ch) { 138 PutChar(ch); 139 return *this; 140 } 141 142 // Stream the NULL terminated C string out to this stream. 143 Stream &Stream::operator<<(const char *s) { 144 Printf("%s", s); 145 return *this; 146 } 147 148 Stream &Stream::operator<<(llvm::StringRef str) { 149 Write(str.data(), str.size()); 150 return *this; 151 } 152 153 // Stream the pointer value out to this stream. 154 Stream &Stream::operator<<(const void *p) { 155 Printf("0x%.*tx", static_cast<int>(sizeof(const void *)) * 2, (ptrdiff_t)p); 156 return *this; 157 } 158 159 // Get the current indentation level 160 unsigned Stream::GetIndentLevel() const { return m_indent_level; } 161 162 // Set the current indentation level 163 void Stream::SetIndentLevel(unsigned indent_level) { 164 m_indent_level = indent_level; 165 } 166 167 // Increment the current indentation level 168 void Stream::IndentMore(unsigned amount) { m_indent_level += amount; } 169 170 // Decrement the current indentation level 171 void Stream::IndentLess(unsigned amount) { 172 if (m_indent_level >= amount) 173 m_indent_level -= amount; 174 else 175 m_indent_level = 0; 176 } 177 178 // Get the address size in bytes 179 uint32_t Stream::GetAddressByteSize() const { return m_addr_size; } 180 181 // Set the address size in bytes 182 void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; } 183 184 // The flags get accessor 185 Flags &Stream::GetFlags() { return m_flags; } 186 187 // The flags const get accessor 188 const Flags &Stream::GetFlags() const { return m_flags; } 189 190 // The byte order get accessor 191 192 lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; } 193 194 size_t Stream::PrintfAsRawHex8(const char *format, ...) { 195 va_list args; 196 va_start(args, format); 197 198 llvm::SmallString<1024> buf; 199 VASprintf(buf, format, args); 200 201 ByteDelta delta(*this); 202 for (char C : buf) 203 _PutHex8(C, false); 204 205 va_end(args); 206 207 return *delta; 208 } 209 210 size_t Stream::PutNHex8(size_t n, uint8_t uvalue) { 211 ByteDelta delta(*this); 212 for (size_t i = 0; i < n; ++i) 213 _PutHex8(uvalue, false); 214 return *delta; 215 } 216 217 void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { 218 if (m_flags.Test(eBinary)) { 219 Write(&uvalue, 1); 220 } else { 221 if (add_prefix) 222 PutCString("0x"); 223 224 static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5', 225 '6', '7', '8', '9', 'a', 'b', 226 'c', 'd', 'e', 'f'}; 227 char nibble_chars[2]; 228 nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf]; 229 nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf]; 230 Write(nibble_chars, sizeof(nibble_chars)); 231 } 232 } 233 234 size_t Stream::PutHex8(uint8_t uvalue) { 235 ByteDelta delta(*this); 236 _PutHex8(uvalue, false); 237 return *delta; 238 } 239 240 size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) { 241 ByteDelta delta(*this); 242 243 if (byte_order == eByteOrderInvalid) 244 byte_order = m_byte_order; 245 246 if (byte_order == eByteOrderLittle) { 247 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 248 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 249 } else { 250 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 251 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 252 } 253 return *delta; 254 } 255 256 size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) { 257 ByteDelta delta(*this); 258 259 if (byte_order == eByteOrderInvalid) 260 byte_order = m_byte_order; 261 262 if (byte_order == eByteOrderLittle) { 263 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 264 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 265 } else { 266 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 267 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 268 } 269 return *delta; 270 } 271 272 size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) { 273 ByteDelta delta(*this); 274 275 if (byte_order == eByteOrderInvalid) 276 byte_order = m_byte_order; 277 278 if (byte_order == eByteOrderLittle) { 279 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 280 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 281 } else { 282 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 283 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 284 } 285 return *delta; 286 } 287 288 size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size, 289 lldb::ByteOrder byte_order) { 290 switch (byte_size) { 291 case 1: 292 return PutHex8(static_cast<uint8_t>(uvalue)); 293 case 2: 294 return PutHex16(static_cast<uint16_t>(uvalue), byte_order); 295 case 4: 296 return PutHex32(static_cast<uint32_t>(uvalue), byte_order); 297 case 8: 298 return PutHex64(uvalue, byte_order); 299 } 300 return 0; 301 } 302 303 size_t Stream::PutPointer(void *ptr) { 304 return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(), 305 endian::InlHostByteOrder()); 306 } 307 308 size_t Stream::PutFloat(float f, ByteOrder byte_order) { 309 if (byte_order == eByteOrderInvalid) 310 byte_order = m_byte_order; 311 312 return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order); 313 } 314 315 size_t Stream::PutDouble(double d, ByteOrder byte_order) { 316 if (byte_order == eByteOrderInvalid) 317 byte_order = m_byte_order; 318 319 return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order); 320 } 321 322 size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) { 323 if (byte_order == eByteOrderInvalid) 324 byte_order = m_byte_order; 325 326 return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order); 327 } 328 329 size_t Stream::PutRawBytes(const void *s, size_t src_len, 330 ByteOrder src_byte_order, ByteOrder dst_byte_order) { 331 ByteDelta delta(*this); 332 333 if (src_byte_order == eByteOrderInvalid) 334 src_byte_order = m_byte_order; 335 336 if (dst_byte_order == eByteOrderInvalid) 337 dst_byte_order = m_byte_order; 338 339 const uint8_t *src = static_cast<const uint8_t *>(s); 340 bool binary_was_set = m_flags.Test(eBinary); 341 if (!binary_was_set) 342 m_flags.Set(eBinary); 343 if (src_byte_order == dst_byte_order) { 344 for (size_t i = 0; i < src_len; ++i) 345 _PutHex8(src[i], false); 346 } else { 347 for (size_t i = src_len - 1; i < src_len; --i) 348 _PutHex8(src[i], false); 349 } 350 if (!binary_was_set) 351 m_flags.Clear(eBinary); 352 353 return *delta; 354 } 355 356 size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len, 357 ByteOrder src_byte_order, 358 ByteOrder dst_byte_order) { 359 ByteDelta delta(*this); 360 if (src_byte_order == eByteOrderInvalid) 361 src_byte_order = m_byte_order; 362 363 if (dst_byte_order == eByteOrderInvalid) 364 dst_byte_order = m_byte_order; 365 366 const uint8_t *src = static_cast<const uint8_t *>(s); 367 bool binary_is_set = m_flags.Test(eBinary); 368 m_flags.Clear(eBinary); 369 if (src_byte_order == dst_byte_order) { 370 for (size_t i = 0; i < src_len; ++i) 371 _PutHex8(src[i], false); 372 } else { 373 for (size_t i = src_len - 1; i < src_len; --i) 374 _PutHex8(src[i], false); 375 } 376 if (binary_is_set) 377 m_flags.Set(eBinary); 378 379 return *delta; 380 } 381 382 size_t Stream::PutStringAsRawHex8(llvm::StringRef s) { 383 ByteDelta delta(*this); 384 bool binary_is_set = m_flags.Test(eBinary); 385 m_flags.Clear(eBinary); 386 for (char c : s) 387 _PutHex8(c, false); 388 if (binary_is_set) 389 m_flags.Set(eBinary); 390 return *delta; 391 } 392