Path: blob/main/contrib/llvm-project/lldb/source/Utility/Stream.cpp
39587 views
//===-- Stream.cpp --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Utility/Stream.h"910#include "lldb/Utility/AnsiTerminal.h"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#include "llvm/Support/Regex.h"1718#include <string>1920#include <cinttypes>21#include <cstddef>2223using namespace lldb;24using namespace lldb_private;2526Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order,27bool colors)28: m_flags(flags), m_addr_size(addr_size), m_byte_order(byte_order),29m_forwarder(*this, colors) {}3031Stream::Stream(bool colors)32: m_flags(0), m_byte_order(endian::InlHostByteOrder()),33m_forwarder(*this, colors) {}3435// Destructor36Stream::~Stream() = default;3738ByteOrder Stream::SetByteOrder(ByteOrder byte_order) {39ByteOrder old_byte_order = m_byte_order;40m_byte_order = byte_order;41return old_byte_order;42}4344// Put an offset "uval" out to the stream using the printf format in "format".45void Stream::Offset(uint32_t uval, const char *format) { Printf(format, uval); }4647// Put an SLEB128 "uval" out to the stream using the printf format in "format".48size_t Stream::PutSLEB128(int64_t sval) {49if (m_flags.Test(eBinary))50return llvm::encodeSLEB128(sval, m_forwarder);51else52return Printf("0x%" PRIi64, sval);53}5455// Put an ULEB128 "uval" out to the stream using the printf format in "format".56size_t Stream::PutULEB128(uint64_t uval) {57if (m_flags.Test(eBinary))58return llvm::encodeULEB128(uval, m_forwarder);59else60return Printf("0x%" PRIx64, uval);61}6263// Print a raw NULL terminated C string to the stream.64size_t Stream::PutCString(llvm::StringRef str) {65size_t bytes_written = 0;66bytes_written = Write(str.data(), str.size());6768// when in binary mode, emit the NULL terminator69if (m_flags.Test(eBinary))70bytes_written += PutChar('\0');71return bytes_written;72}7374void Stream::PutCStringColorHighlighted(75llvm::StringRef text, std::optional<HighlightSettings> pattern_info) {76// Only apply color formatting when a pattern information is specified.77// Otherwise, output the text without color formatting.78if (!pattern_info.has_value()) {79PutCString(text);80return;81}8283llvm::Regex reg_pattern(pattern_info->pattern);84llvm::SmallVector<llvm::StringRef, 1> matches;85llvm::StringRef remaining = text;86std::string format_str = lldb_private::ansi::FormatAnsiTerminalCodes(87pattern_info->prefix.str() + "%.*s" + pattern_info->suffix.str());88while (reg_pattern.match(remaining, &matches)) {89llvm::StringRef match = matches[0];90size_t match_start_pos = match.data() - remaining.data();91PutCString(remaining.take_front(match_start_pos));92Printf(format_str.c_str(), match.size(), match.data());93remaining = remaining.drop_front(match_start_pos + match.size());94}95if (remaining.size())96PutCString(remaining);97}9899// Print a double quoted NULL terminated C string to the stream using the100// printf format in "format".101void Stream::QuotedCString(const char *cstr, const char *format) {102Printf(format, cstr);103}104105// Put an address "addr" out to the stream with optional prefix and suffix106// strings.107void lldb_private::DumpAddress(llvm::raw_ostream &s, uint64_t addr,108uint32_t addr_size, const char *prefix,109const char *suffix) {110if (prefix == nullptr)111prefix = "";112if (suffix == nullptr)113suffix = "";114s << prefix << llvm::format_hex(addr, 2 + 2 * addr_size) << suffix;115}116117// Put an address range out to the stream with optional prefix and suffix118// strings.119void lldb_private::DumpAddressRange(llvm::raw_ostream &s, uint64_t lo_addr,120uint64_t hi_addr, uint32_t addr_size,121const char *prefix, const char *suffix) {122if (prefix && prefix[0])123s << prefix;124DumpAddress(s, lo_addr, addr_size, "[");125DumpAddress(s, hi_addr, addr_size, "-", ")");126if (suffix && suffix[0])127s << suffix;128}129130size_t Stream::PutChar(char ch) { return Write(&ch, 1); }131132// Print some formatted output to the stream.133size_t Stream::Printf(const char *format, ...) {134va_list args;135va_start(args, format);136size_t result = PrintfVarArg(format, args);137va_end(args);138return result;139}140141// Print some formatted output to the stream.142size_t Stream::PrintfVarArg(const char *format, va_list args) {143llvm::SmallString<1024> buf;144VASprintf(buf, format, args);145146// Include the NULL termination byte for binary output147size_t length = buf.size();148if (m_flags.Test(eBinary))149++length;150return Write(buf.c_str(), length);151}152153// Print and End of Line character to the stream154size_t Stream::EOL() { return PutChar('\n'); }155156size_t Stream::Indent(llvm::StringRef str) {157const size_t ind_length = PutCString(std::string(m_indent_level, ' '));158const size_t str_length = PutCString(str);159return ind_length + str_length;160}161162// Stream a character "ch" out to this stream.163Stream &Stream::operator<<(char ch) {164PutChar(ch);165return *this;166}167168// Stream the NULL terminated C string out to this stream.169Stream &Stream::operator<<(const char *s) {170Printf("%s", s);171return *this;172}173174Stream &Stream::operator<<(llvm::StringRef str) {175Write(str.data(), str.size());176return *this;177}178179// Stream the pointer value out to this stream.180Stream &Stream::operator<<(const void *p) {181Printf("0x%.*tx", static_cast<int>(sizeof(const void *)) * 2, (ptrdiff_t)p);182return *this;183}184185// Get the current indentation level186unsigned Stream::GetIndentLevel() const { return m_indent_level; }187188// Set the current indentation level189void Stream::SetIndentLevel(unsigned indent_level) {190m_indent_level = indent_level;191}192193// Increment the current indentation level194void Stream::IndentMore(unsigned amount) { m_indent_level += amount; }195196// Decrement the current indentation level197void Stream::IndentLess(unsigned amount) {198if (m_indent_level >= amount)199m_indent_level -= amount;200else201m_indent_level = 0;202}203204// Get the address size in bytes205uint32_t Stream::GetAddressByteSize() const { return m_addr_size; }206207// Set the address size in bytes208void Stream::SetAddressByteSize(uint32_t addr_size) { m_addr_size = addr_size; }209210// The flags get accessor211Flags &Stream::GetFlags() { return m_flags; }212213// The flags const get accessor214const Flags &Stream::GetFlags() const { return m_flags; }215216// The byte order get accessor217218lldb::ByteOrder Stream::GetByteOrder() const { return m_byte_order; }219220size_t Stream::PrintfAsRawHex8(const char *format, ...) {221va_list args;222va_start(args, format);223224llvm::SmallString<1024> buf;225VASprintf(buf, format, args);226227ByteDelta delta(*this);228for (char C : buf)229_PutHex8(C, false);230231va_end(args);232233return *delta;234}235236size_t Stream::PutNHex8(size_t n, uint8_t uvalue) {237ByteDelta delta(*this);238for (size_t i = 0; i < n; ++i)239_PutHex8(uvalue, false);240return *delta;241}242243void Stream::_PutHex8(uint8_t uvalue, bool add_prefix) {244if (m_flags.Test(eBinary)) {245Write(&uvalue, 1);246} else {247if (add_prefix)248PutCString("0x");249250static char g_hex_to_ascii_hex_char[16] = {'0', '1', '2', '3', '4', '5',251'6', '7', '8', '9', 'a', 'b',252'c', 'd', 'e', 'f'};253char nibble_chars[2];254nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf];255nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf];256Write(nibble_chars, sizeof(nibble_chars));257}258}259260size_t Stream::PutHex8(uint8_t uvalue) {261ByteDelta delta(*this);262_PutHex8(uvalue, false);263return *delta;264}265266size_t Stream::PutHex16(uint16_t uvalue, ByteOrder byte_order) {267ByteDelta delta(*this);268269if (byte_order == eByteOrderInvalid)270byte_order = m_byte_order;271272if (byte_order == eByteOrderLittle) {273for (size_t byte = 0; byte < sizeof(uvalue); ++byte)274_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);275} else {276for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)277_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);278}279return *delta;280}281282size_t Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order) {283ByteDelta delta(*this);284285if (byte_order == eByteOrderInvalid)286byte_order = m_byte_order;287288if (byte_order == eByteOrderLittle) {289for (size_t byte = 0; byte < sizeof(uvalue); ++byte)290_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);291} else {292for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)293_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);294}295return *delta;296}297298size_t Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order) {299ByteDelta delta(*this);300301if (byte_order == eByteOrderInvalid)302byte_order = m_byte_order;303304if (byte_order == eByteOrderLittle) {305for (size_t byte = 0; byte < sizeof(uvalue); ++byte)306_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);307} else {308for (size_t byte = sizeof(uvalue) - 1; byte < sizeof(uvalue); --byte)309_PutHex8(static_cast<uint8_t>(uvalue >> (byte * 8)), false);310}311return *delta;312}313314size_t Stream::PutMaxHex64(uint64_t uvalue, size_t byte_size,315lldb::ByteOrder byte_order) {316switch (byte_size) {317case 1:318return PutHex8(static_cast<uint8_t>(uvalue));319case 2:320return PutHex16(static_cast<uint16_t>(uvalue), byte_order);321case 4:322return PutHex32(static_cast<uint32_t>(uvalue), byte_order);323case 8:324return PutHex64(uvalue, byte_order);325}326return 0;327}328329size_t Stream::PutPointer(void *ptr) {330return PutRawBytes(&ptr, sizeof(ptr), endian::InlHostByteOrder(),331endian::InlHostByteOrder());332}333334size_t Stream::PutFloat(float f, ByteOrder byte_order) {335if (byte_order == eByteOrderInvalid)336byte_order = m_byte_order;337338return PutRawBytes(&f, sizeof(f), endian::InlHostByteOrder(), byte_order);339}340341size_t Stream::PutDouble(double d, ByteOrder byte_order) {342if (byte_order == eByteOrderInvalid)343byte_order = m_byte_order;344345return PutRawBytes(&d, sizeof(d), endian::InlHostByteOrder(), byte_order);346}347348size_t Stream::PutLongDouble(long double ld, ByteOrder byte_order) {349if (byte_order == eByteOrderInvalid)350byte_order = m_byte_order;351352return PutRawBytes(&ld, sizeof(ld), endian::InlHostByteOrder(), byte_order);353}354355size_t Stream::PutRawBytes(const void *s, size_t src_len,356ByteOrder src_byte_order, ByteOrder dst_byte_order) {357ByteDelta delta(*this);358359if (src_byte_order == eByteOrderInvalid)360src_byte_order = m_byte_order;361362if (dst_byte_order == eByteOrderInvalid)363dst_byte_order = m_byte_order;364365const uint8_t *src = static_cast<const uint8_t *>(s);366bool binary_was_set = m_flags.Test(eBinary);367if (!binary_was_set)368m_flags.Set(eBinary);369if (src_byte_order == dst_byte_order) {370for (size_t i = 0; i < src_len; ++i)371_PutHex8(src[i], false);372} else {373for (size_t i = src_len; i > 0; --i)374_PutHex8(src[i - 1], false);375}376if (!binary_was_set)377m_flags.Clear(eBinary);378379return *delta;380}381382size_t Stream::PutBytesAsRawHex8(const void *s, size_t src_len,383ByteOrder src_byte_order,384ByteOrder dst_byte_order) {385ByteDelta delta(*this);386387if (src_byte_order == eByteOrderInvalid)388src_byte_order = m_byte_order;389390if (dst_byte_order == eByteOrderInvalid)391dst_byte_order = m_byte_order;392393const uint8_t *src = static_cast<const uint8_t *>(s);394bool binary_is_set = m_flags.Test(eBinary);395m_flags.Clear(eBinary);396if (src_byte_order == dst_byte_order) {397for (size_t i = 0; i < src_len; ++i)398_PutHex8(src[i], false);399} else {400for (size_t i = src_len; i > 0; --i)401_PutHex8(src[i - 1], false);402}403if (binary_is_set)404m_flags.Set(eBinary);405406return *delta;407}408409size_t Stream::PutStringAsRawHex8(llvm::StringRef s) {410ByteDelta delta(*this);411bool binary_is_set = m_flags.Test(eBinary);412m_flags.Clear(eBinary);413for (char c : s)414_PutHex8(c, false);415if (binary_is_set)416m_flags.Set(eBinary);417return *delta;418}419420421