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 const size_t ind_length = PutCString(std::string(m_indent_level, ' ')); 131 const size_t str_length = PutCString(str); 132 return ind_length + str_length; 133 } 134 135 // Stream a character "ch" out to this stream. 136 Stream &Stream::operator<<(char ch) { 137 PutChar(ch); 138 return *this; 139 } 140 141 // Stream the NULL terminated C string out to this stream. 142 Stream &Stream::operator<<(const char *s) { 143 Printf("%s", s); 144 return *this; 145 } 146 147 Stream &Stream::operator<<(llvm::StringRef str) { 148 Write(str.data(), str.size()); 149 return *this; 150 } 151 152 // Stream the pointer value out to this stream. 153 Stream &Stream::operator<<(const void *p) { 154 Printf("0x%.*tx", static_cast<int>(sizeof(const void *)) * 2, (ptrdiff_t)p); 155 return *this; 156 } 157 158 // Get the current indentation level 159 unsigned Stream::GetIndentLevel() const { return m_indent_level; } 160 161 // Set the current indentation level 162 void Stream::SetIndentLevel(unsigned indent_level) { 163 m_indent_level = indent_level; 164 } 165 166 // Increment the current indentation level 167 void Stream::IndentMore(unsigned amount) { m_indent_level += amount; } 168 169 // Decrement the current indentation level 170 void Stream::IndentLess(unsigned amount) { 171 if (m_indent_level >= amount) 172 m_indent_level -= amount; 173 else 174 m_indent_level = 0; 175 } 176 177 // Get the address size in bytes 178 uint32_t Stream::GetAddressByteSize() const { return m_addr_size; } 179 180 // Set the address size in bytes 181 void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; } 182 183 // The flags get accessor 184 Flags &Stream::GetFlags() { return m_flags; } 185 186 // The flags const get accessor 187 const Flags &Stream::GetFlags() const { return m_flags; } 188 189 // The byte order get accessor 190 191 lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; } 192 193 size_t Stream::PrintfAsRawHex8(const char *format, ...) { 194 va_list args; 195 va_start(args, format); 196 197 llvm::SmallString<1024> buf; 198 VASprintf(buf, format, args); 199 200 ByteDelta delta(*this); 201 for (char C : buf) 202 _PutHex8(C, false); 203 204 va_end(args); 205 206 return *delta; 207 } 208 209 size_t Stream::PutNHex8(size_t n, uint8_t uvalue) { 210 ByteDelta delta(*this); 211 for (size_t i = 0; i < n; ++i) 212 _PutHex8(uvalue, false); 213 return *delta; 214 } 215 216 void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { 217 if (m_flags.Test(eBinary)) { 218 Write(&uvalue, 1); 219 } else { 220 if (add_prefix) 221 PutCString("0x"); 222 223 static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5', 224 '6', '7', '8', '9', 'a', 'b', 225 'c', 'd', 'e', 'f'}; 226 char nibble_chars[2]; 227 nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf]; 228 nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf]; 229 Write(nibble_chars, sizeof(nibble_chars)); 230 } 231 } 232 233 size_t Stream::PutHex8(uint8_t uvalue) { 234 ByteDelta delta(*this); 235 _PutHex8(uvalue, false); 236 return *delta; 237 } 238 239 size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) { 240 ByteDelta delta(*this); 241 242 if (byte_order == eByteOrderInvalid) 243 byte_order = m_byte_order; 244 245 if (byte_order == eByteOrderLittle) { 246 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 247 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 248 } else { 249 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 250 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 251 } 252 return *delta; 253 } 254 255 size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) { 256 ByteDelta delta(*this); 257 258 if (byte_order == eByteOrderInvalid) 259 byte_order = m_byte_order; 260 261 if (byte_order == eByteOrderLittle) { 262 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 263 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 264 } else { 265 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 266 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 267 } 268 return *delta; 269 } 270 271 size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) { 272 ByteDelta delta(*this); 273 274 if (byte_order == eByteOrderInvalid) 275 byte_order = m_byte_order; 276 277 if (byte_order == eByteOrderLittle) { 278 for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 279 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 280 } else { 281 for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 282 _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 283 } 284 return *delta; 285 } 286 287 size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size, 288 lldb::ByteOrder byte_order) { 289 switch (byte_size) { 290 case 1: 291 return PutHex8(static_cast<uint8_t>(uvalue)); 292 case 2: 293 return PutHex16(static_cast<uint16_t>(uvalue), byte_order); 294 case 4: 295 return PutHex32(static_cast<uint32_t>(uvalue), byte_order); 296 case 8: 297 return PutHex64(uvalue, byte_order); 298 } 299 return 0; 300 } 301 302 size_t Stream::PutPointer(void *ptr) { 303 return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(), 304 endian::InlHostByteOrder()); 305 } 306 307 size_t Stream::PutFloat(float f, ByteOrder byte_order) { 308 if (byte_order == eByteOrderInvalid) 309 byte_order = m_byte_order; 310 311 return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order); 312 } 313 314 size_t Stream::PutDouble(double d, ByteOrder byte_order) { 315 if (byte_order == eByteOrderInvalid) 316 byte_order = m_byte_order; 317 318 return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order); 319 } 320 321 size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) { 322 if (byte_order == eByteOrderInvalid) 323 byte_order = m_byte_order; 324 325 return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order); 326 } 327 328 size_t Stream::PutRawBytes(const void *s, size_t src_len, 329 ByteOrder src_byte_order, ByteOrder dst_byte_order) { 330 ByteDelta delta(*this); 331 332 if (src_byte_order == eByteOrderInvalid) 333 src_byte_order = m_byte_order; 334 335 if (dst_byte_order == eByteOrderInvalid) 336 dst_byte_order = m_byte_order; 337 338 const uint8_t *src = static_cast<const uint8_t *>(s); 339 bool binary_was_set = m_flags.Test(eBinary); 340 if (!binary_was_set) 341 m_flags.Set(eBinary); 342 if (src_byte_order == dst_byte_order) { 343 for (size_t i = 0; i < src_len; ++i) 344 _PutHex8(src[i], false); 345 } else { 346 for (size_t i = src_len - 1; i < src_len; --i) 347 _PutHex8(src[i], false); 348 } 349 if (!binary_was_set) 350 m_flags.Clear(eBinary); 351 352 return *delta; 353 } 354 355 size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len, 356 ByteOrder src_byte_order, 357 ByteOrder dst_byte_order) { 358 ByteDelta delta(*this); 359 if (src_byte_order == eByteOrderInvalid) 360 src_byte_order = m_byte_order; 361 362 if (dst_byte_order == eByteOrderInvalid) 363 dst_byte_order = m_byte_order; 364 365 const uint8_t *src = static_cast<const uint8_t *>(s); 366 bool binary_is_set = m_flags.Test(eBinary); 367 m_flags.Clear(eBinary); 368 if (src_byte_order == dst_byte_order) { 369 for (size_t i = 0; i < src_len; ++i) 370 _PutHex8(src[i], false); 371 } else { 372 for (size_t i = src_len - 1; i < src_len; --i) 373 _PutHex8(src[i], false); 374 } 375 if (binary_is_set) 376 m_flags.Set(eBinary); 377 378 return *delta; 379 } 380 381 size_t Stream::PutStringAsRawHex8(llvm::StringRef s) { 382 ByteDelta delta(*this); 383 bool binary_is_set = m_flags.Test(eBinary); 384 m_flags.Clear(eBinary); 385 for (char c : s) 386 _PutHex8(c, false); 387 if (binary_is_set) 388 m_flags.Set(eBinary); 389 return *delta; 390 } 391