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