1317027Sdim//===-- Stream.cpp ----------------------------------------------*- C++ -*-===// 2317027Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317027Sdim// 7317027Sdim//===----------------------------------------------------------------------===// 8317027Sdim 9317027Sdim#include "lldb/Utility/Stream.h" 10317027Sdim 11317027Sdim#include "lldb/Utility/Endian.h" 12317027Sdim#include "lldb/Utility/VASPrintf.h" 13344779Sdim#include "llvm/ADT/SmallString.h" 14360784Sdim#include "llvm/Support/Format.h" 15344779Sdim#include "llvm/Support/LEB128.h" 16317027Sdim 17317027Sdim#include <string> 18317027Sdim 19317027Sdim#include <inttypes.h> 20317027Sdim#include <stddef.h> 21317027Sdim 22317027Sdimusing namespace lldb; 23317027Sdimusing namespace lldb_private; 24317027Sdim 25317027SdimStream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) 26317027Sdim : m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order), 27344779Sdim m_indent_level(0), m_forwarder(*this) {} 28317027Sdim 29317027SdimStream::Stream() 30317027Sdim : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()), 31344779Sdim m_indent_level(0), m_forwarder(*this) {} 32317027Sdim 33317027Sdim// Destructor 34317027SdimStream::~Stream() {} 35317027Sdim 36317027SdimByteOrder Stream::SetByteOrder(ByteOrder byte_order) { 37317027Sdim ByteOrder old_byte_order = m_byte_order; 38317027Sdim m_byte_order = byte_order; 39317027Sdim return old_byte_order; 40317027Sdim} 41317027Sdim 42341825Sdim// Put an offset "uval" out to the stream using the printf format in "format". 43317027Sdimvoid Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); } 44317027Sdim 45341825Sdim// Put an SLEB128 "uval" out to the stream using the printf format in "format". 46317027Sdimsize_t Stream::PutSLEB128(int64_t sval) { 47344779Sdim if (m_flags.Test(eBinary)) 48344779Sdim return llvm::encodeSLEB128(sval, m_forwarder); 49344779Sdim else 50344779Sdim return Printf("0x%" PRIi64, sval); 51317027Sdim} 52317027Sdim 53341825Sdim// Put an ULEB128 "uval" out to the stream using the printf format in "format". 54317027Sdimsize_t Stream::PutULEB128(uint64_t uval) { 55344779Sdim if (m_flags.Test(eBinary)) 56344779Sdim return llvm::encodeULEB128(uval, m_forwarder); 57344779Sdim else 58344779Sdim return Printf("0x%" PRIx64, uval); 59317027Sdim} 60317027Sdim 61317027Sdim// Print a raw NULL terminated C string to the stream. 62317027Sdimsize_t Stream::PutCString(llvm::StringRef str) { 63317027Sdim size_t bytes_written = 0; 64317027Sdim bytes_written = Write(str.data(), str.size()); 65317027Sdim 66317027Sdim // when in binary mode, emit the NULL terminator 67317027Sdim if (m_flags.Test(eBinary)) 68317027Sdim bytes_written += PutChar('\0'); 69317027Sdim return bytes_written; 70317027Sdim} 71317027Sdim 72341825Sdim// Print a double quoted NULL terminated C string to the stream using the 73341825Sdim// printf format in "format". 74317027Sdimvoid Stream::QuotedCString(const char *cstr, const char *format) { 75317027Sdim Printf(format, cstr); 76317027Sdim} 77317027Sdim 78341825Sdim// Put an address "addr" out to the stream with optional prefix and suffix 79341825Sdim// strings. 80360784Sdimvoid lldb_private::DumpAddress(llvm::raw_ostream &s, uint64_t addr, 81360784Sdim uint32_t addr_size, const char *prefix, 82360784Sdim const char *suffix) { 83344779Sdim if (prefix == nullptr) 84317027Sdim prefix = ""; 85344779Sdim if (suffix == nullptr) 86317027Sdim suffix = ""; 87360784Sdim s << prefix << llvm::format_hex(addr, 2 + 2 * addr_size) << suffix; 88317027Sdim} 89317027Sdim 90341825Sdim// Put an address range out to the stream with optional prefix and suffix 91341825Sdim// strings. 92360784Sdimvoid lldb_private::DumpAddressRange(llvm::raw_ostream &s, uint64_t lo_addr, 93360784Sdim uint64_t hi_addr, uint32_t addr_size, 94360784Sdim const char *prefix, const char *suffix) { 95317027Sdim if (prefix && prefix[0]) 96360784Sdim s << prefix; 97360784Sdim DumpAddress(s, lo_addr, addr_size, "["); 98360784Sdim DumpAddress(s, hi_addr, addr_size, "-", ")"); 99317027Sdim if (suffix && suffix[0]) 100360784Sdim s << suffix; 101317027Sdim} 102317027Sdim 103317027Sdimsize_t Stream::PutChar(char ch) { return Write(&ch, 1); } 104317027Sdim 105317027Sdim// Print some formatted output to the stream. 106317027Sdimsize_t Stream::Printf(const char *format, ...) { 107317027Sdim va_list args; 108317027Sdim va_start(args, format); 109317027Sdim size_t result = PrintfVarArg(format, args); 110317027Sdim va_end(args); 111317027Sdim return result; 112317027Sdim} 113317027Sdim 114317027Sdim// Print some formatted output to the stream. 115317027Sdimsize_t Stream::PrintfVarArg(const char *format, va_list args) { 116317027Sdim llvm::SmallString<1024> buf; 117317027Sdim VASprintf(buf, format, args); 118317027Sdim 119317027Sdim // Include the NULL termination byte for binary output 120317027Sdim size_t length = buf.size(); 121317027Sdim if (m_flags.Test(eBinary)) 122317027Sdim ++length; 123317027Sdim return Write(buf.c_str(), length); 124317027Sdim} 125317027Sdim 126317027Sdim// Print and End of Line character to the stream 127317027Sdimsize_t Stream::EOL() { return PutChar('\n'); } 128317027Sdim 129341825Sdim// Indent the current line using the current indentation level and print an 130341825Sdim// optional string following the indentation spaces. 131317027Sdimsize_t Stream::Indent(const char *s) { 132317027Sdim return Printf("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : ""); 133317027Sdim} 134317027Sdim 135317027Sdimsize_t Stream::Indent(llvm::StringRef str) { 136317027Sdim return Printf("%*.*s%s", m_indent_level, m_indent_level, "", 137317027Sdim str.str().c_str()); 138317027Sdim} 139317027Sdim 140317027Sdim// Stream a character "ch" out to this stream. 141317027SdimStream &Stream::operator<<(char ch) { 142317027Sdim PutChar(ch); 143317027Sdim return *this; 144317027Sdim} 145317027Sdim 146317027Sdim// Stream the NULL terminated C string out to this stream. 147317027SdimStream &Stream::operator<<(const char *s) { 148317027Sdim Printf("%s", s); 149317027Sdim return *this; 150317027Sdim} 151317027Sdim 152317027SdimStream &Stream::operator<<(llvm::StringRef str) { 153317027Sdim Write(str.data(), str.size()); 154317027Sdim return *this; 155317027Sdim} 156317027Sdim 157317027Sdim// Stream the pointer value out to this stream. 158317027SdimStream &Stream::operator<<(const void *p) { 159353358Sdim Printf("0x%.*tx", static_cast<int>(sizeof(const void *)) * 2, (ptrdiff_t)p); 160317027Sdim return *this; 161317027Sdim} 162317027Sdim 163317027Sdim// Get the current indentation level 164360784Sdimunsigned Stream::GetIndentLevel() const { return m_indent_level; } 165317027Sdim 166317027Sdim// Set the current indentation level 167360784Sdimvoid Stream::SetIndentLevel(unsigned indent_level) { 168360784Sdim m_indent_level = indent_level; 169360784Sdim} 170317027Sdim 171317027Sdim// Increment the current indentation level 172360784Sdimvoid Stream::IndentMore(unsigned amount) { m_indent_level += amount; } 173317027Sdim 174317027Sdim// Decrement the current indentation level 175360784Sdimvoid Stream::IndentLess(unsigned amount) { 176317027Sdim if (m_indent_level >= amount) 177317027Sdim m_indent_level -= amount; 178317027Sdim else 179317027Sdim m_indent_level = 0; 180317027Sdim} 181317027Sdim 182317027Sdim// Get the address size in bytes 183317027Sdimuint32_t Stream::GetAddressByteSize() const { return m_addr_size; } 184317027Sdim 185317027Sdim// Set the address size in bytes 186317027Sdimvoid Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; } 187317027Sdim 188317027Sdim// The flags get accessor 189317027SdimFlags &Stream::GetFlags() { return m_flags; } 190317027Sdim 191317027Sdim// The flags const get accessor 192317027Sdimconst Flags &Stream::GetFlags() const { return m_flags; } 193317027Sdim 194317027Sdim// The byte order get accessor 195317027Sdim 196317027Sdimlldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; } 197317027Sdim 198317027Sdimsize_t Stream::PrintfAsRawHex8(const char *format, ...) { 199317027Sdim va_list args; 200317027Sdim va_start(args, format); 201317027Sdim 202317027Sdim llvm::SmallString<1024> buf; 203317027Sdim VASprintf(buf, format, args); 204317027Sdim 205344779Sdim ByteDelta delta(*this); 206317027Sdim for (char C : buf) 207344779Sdim _PutHex8(C, false); 208317027Sdim 209317027Sdim va_end(args); 210317027Sdim 211344779Sdim return *delta; 212317027Sdim} 213317027Sdim 214317027Sdimsize_t Stream::PutNHex8(size_t n, uint8_t uvalue) { 215344779Sdim ByteDelta delta(*this); 216317027Sdim for (size_t i = 0; i < n; ++i) 217344779Sdim _PutHex8(uvalue, false); 218344779Sdim return *delta; 219317027Sdim} 220317027Sdim 221344779Sdimvoid Stream::_PutHex8(uint8_t uvalue, bool add_prefix) { 222317027Sdim if (m_flags.Test(eBinary)) { 223344779Sdim Write(&uvalue, 1); 224317027Sdim } else { 225317027Sdim if (add_prefix) 226317027Sdim PutCString("0x"); 227317027Sdim 228317027Sdim static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5', 229317027Sdim '6', '7', '8', '9', 'a', 'b', 230317027Sdim 'c', 'd', 'e', 'f'}; 231317027Sdim char nibble_chars[2]; 232317027Sdim nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf]; 233317027Sdim nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf]; 234344779Sdim Write(nibble_chars, sizeof(nibble_chars)); 235317027Sdim } 236317027Sdim} 237317027Sdim 238344779Sdimsize_t Stream::PutHex8(uint8_t uvalue) { 239344779Sdim ByteDelta delta(*this); 240344779Sdim _PutHex8(uvalue, false); 241344779Sdim return *delta; 242344779Sdim} 243317027Sdim 244317027Sdimsize_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) { 245344779Sdim ByteDelta delta(*this); 246344779Sdim 247317027Sdim if (byte_order == eByteOrderInvalid) 248317027Sdim byte_order = m_byte_order; 249317027Sdim 250317027Sdim if (byte_order == eByteOrderLittle) { 251317027Sdim for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 252353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 253317027Sdim } else { 254317027Sdim for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 255353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 256317027Sdim } 257344779Sdim return *delta; 258317027Sdim} 259317027Sdim 260317027Sdimsize_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) { 261344779Sdim ByteDelta delta(*this); 262344779Sdim 263317027Sdim if (byte_order == eByteOrderInvalid) 264317027Sdim byte_order = m_byte_order; 265317027Sdim 266317027Sdim if (byte_order == eByteOrderLittle) { 267317027Sdim for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 268353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 269317027Sdim } else { 270317027Sdim for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 271353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 272317027Sdim } 273344779Sdim return *delta; 274317027Sdim} 275317027Sdim 276317027Sdimsize_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) { 277344779Sdim ByteDelta delta(*this); 278344779Sdim 279317027Sdim if (byte_order == eByteOrderInvalid) 280317027Sdim byte_order = m_byte_order; 281317027Sdim 282317027Sdim if (byte_order == eByteOrderLittle) { 283317027Sdim for (size_t byte = 0; byte < sizeof(uvalue); ++byte) 284353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 285317027Sdim } else { 286317027Sdim for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte) 287353358Sdim _PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false); 288317027Sdim } 289344779Sdim return *delta; 290317027Sdim} 291317027Sdim 292317027Sdimsize_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size, 293317027Sdim lldb::ByteOrder byte_order) { 294317027Sdim switch (byte_size) { 295317027Sdim case 1: 296353358Sdim return PutHex8(static_cast<uint8_t>(uvalue)); 297317027Sdim case 2: 298353358Sdim return PutHex16(static_cast<uint16_t>(uvalue), byte_order); 299317027Sdim case 4: 300353358Sdim return PutHex32(static_cast<uint32_t>(uvalue), byte_order); 301317027Sdim case 8: 302344779Sdim return PutHex64(uvalue, byte_order); 303317027Sdim } 304317027Sdim return 0; 305317027Sdim} 306317027Sdim 307317027Sdimsize_t Stream::PutPointer(void *ptr) { 308317027Sdim return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(), 309317027Sdim endian::InlHostByteOrder()); 310317027Sdim} 311317027Sdim 312317027Sdimsize_t Stream::PutFloat(float f, ByteOrder byte_order) { 313317027Sdim if (byte_order == eByteOrderInvalid) 314317027Sdim byte_order = m_byte_order; 315317027Sdim 316317027Sdim return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order); 317317027Sdim} 318317027Sdim 319317027Sdimsize_t Stream::PutDouble(double d, ByteOrder byte_order) { 320317027Sdim if (byte_order == eByteOrderInvalid) 321317027Sdim byte_order = m_byte_order; 322317027Sdim 323317027Sdim return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order); 324317027Sdim} 325317027Sdim 326317027Sdimsize_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) { 327317027Sdim if (byte_order == eByteOrderInvalid) 328317027Sdim byte_order = m_byte_order; 329317027Sdim 330317027Sdim return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order); 331317027Sdim} 332317027Sdim 333317027Sdimsize_t Stream::PutRawBytes(const void *s, size_t src_len, 334317027Sdim ByteOrder src_byte_order, ByteOrder dst_byte_order) { 335344779Sdim ByteDelta delta(*this); 336344779Sdim 337317027Sdim if (src_byte_order == eByteOrderInvalid) 338317027Sdim src_byte_order = m_byte_order; 339317027Sdim 340317027Sdim if (dst_byte_order == eByteOrderInvalid) 341317027Sdim dst_byte_order = m_byte_order; 342317027Sdim 343353358Sdim const uint8_t *src = static_cast<const uint8_t *>(s); 344317027Sdim bool binary_was_set = m_flags.Test(eBinary); 345317027Sdim if (!binary_was_set) 346317027Sdim m_flags.Set(eBinary); 347317027Sdim if (src_byte_order == dst_byte_order) { 348317027Sdim for (size_t i = 0; i < src_len; ++i) 349344779Sdim _PutHex8(src[i], false); 350317027Sdim } else { 351317027Sdim for (size_t i = src_len - 1; i < src_len; --i) 352344779Sdim _PutHex8(src[i], false); 353317027Sdim } 354317027Sdim if (!binary_was_set) 355317027Sdim m_flags.Clear(eBinary); 356317027Sdim 357344779Sdim return *delta; 358317027Sdim} 359317027Sdim 360317027Sdimsize_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len, 361317027Sdim ByteOrder src_byte_order, 362317027Sdim ByteOrder dst_byte_order) { 363344779Sdim ByteDelta delta(*this); 364317027Sdim if (src_byte_order == eByteOrderInvalid) 365317027Sdim src_byte_order = m_byte_order; 366317027Sdim 367317027Sdim if (dst_byte_order == eByteOrderInvalid) 368317027Sdim dst_byte_order = m_byte_order; 369317027Sdim 370353358Sdim const uint8_t *src = static_cast<const uint8_t *>(s); 371317027Sdim bool binary_is_set = m_flags.Test(eBinary); 372317027Sdim m_flags.Clear(eBinary); 373317027Sdim if (src_byte_order == dst_byte_order) { 374317027Sdim for (size_t i = 0; i < src_len; ++i) 375344779Sdim _PutHex8(src[i], false); 376317027Sdim } else { 377317027Sdim for (size_t i = src_len - 1; i < src_len; --i) 378344779Sdim _PutHex8(src[i], false); 379317027Sdim } 380317027Sdim if (binary_is_set) 381317027Sdim m_flags.Set(eBinary); 382317027Sdim 383344779Sdim return *delta; 384317027Sdim} 385317027Sdim 386353358Sdimsize_t Stream::PutStringAsRawHex8(llvm::StringRef s) { 387344779Sdim ByteDelta delta(*this); 388317027Sdim bool binary_is_set = m_flags.Test(eBinary); 389317027Sdim m_flags.Clear(eBinary); 390353358Sdim for (char c : s) 391353358Sdim _PutHex8(c, false); 392317027Sdim if (binary_is_set) 393317027Sdim m_flags.Set(eBinary); 394344779Sdim return *delta; 395317027Sdim} 396