blob: 0b1c9824ed67813710895e73a0a26aef8c43f7ca [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_STORAGE_VFS_CPP_DEBUG_H_
#define SRC_LIB_STORAGE_VFS_CPP_DEBUG_H_
#include <bitset>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <string_view>
#include <utility>
#include <fbl/string_buffer.h>
#include "src/lib/storage/vfs/cpp/trace.h"
#include "src/lib/storage/vfs/cpp/vfs_types.h"
#ifdef __Fuchsia__
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fidl/llcpp/string_view.h>
#endif // __Fuchsia__
// Debug-only header defining utility functions for logging flags and strings.
// May be used on both Fuchsia and host-only builds.
namespace fs {
namespace debug_internal {
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, VnodeConnectionOptions options) {
auto make_append = [sb] {
return [sb, first = true](const char* str) mutable {
if (!first) {
sb->Append(", ");
}
sb->Append(str);
first = false;
};
};
{
auto append = make_append();
sb->Append("[flags: ");
if (options.flags.create)
append("create");
if (options.flags.fail_if_exists)
append("fail_if_exists");
if (options.flags.truncate)
append("truncate");
if (options.flags.directory)
append("directory");
if (options.flags.not_directory)
append("not_directory");
if (options.flags.append)
append("append");
if (options.flags.node_reference)
append("node_reference");
if (options.flags.describe)
append("describe");
if (options.flags.posix_write)
append("posix_write");
if (options.flags.posix_execute)
append("posix_execute");
if (options.flags.clone_same_rights)
append("clone_same_rights");
}
{
auto append = make_append();
sb->Append(", rights: ");
if (options.rights.read)
append("read");
if (options.rights.write)
append("write");
if (options.rights.execute)
append("execute");
sb->Append("]");
}
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, const char* str) {
sb->Append(str);
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, std::string_view view) {
sb->Append(view.data(), view.size());
}
#ifdef __Fuchsia__
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, fidl::StringView view) {
sb->Append(view.data(), view.size());
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, fuchsia_io::wire::NodeAttributeFlags flags) {
constexpr std::pair<fuchsia_io::wire::NodeAttributeFlags, std::string_view> flagToString[] = {
{fuchsia_io::wire::NodeAttributeFlags::kCreationTime, "CREATION_TIME"},
{fuchsia_io::wire::NodeAttributeFlags::kModificationTime, "MODIFICATION_TIME"},
};
bool first = true;
for (const auto& [flag, desc] : flagToString) {
if (flags & flag) {
if (!first) {
sb->Append(" | ");
}
first = false;
sb->Append(desc);
}
flags ^= flag;
}
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, fuchsia_io::wire::OpenFlags flags) {
constexpr std::pair<fuchsia_io::wire::OpenFlags, std::string_view> flagToString[] = {
{fuchsia_io::wire::OpenFlags::kRightReadable, "RIGHT_READABLE"},
{fuchsia_io::wire::OpenFlags::kRightWritable, "RIGHT_WRITABLE"},
{fuchsia_io::wire::OpenFlags::kRightExecutable, "RIGHT_EXECUTABLE"},
{fuchsia_io::wire::OpenFlags::kCreate, "CREATE"},
{fuchsia_io::wire::OpenFlags::kCreateIfAbsent, "CREATE_IF_ABSENT"},
{fuchsia_io::wire::OpenFlags::kTruncate, "TRUNCATE"},
{fuchsia_io::wire::OpenFlags::kDirectory, "DIRECTORY"},
{fuchsia_io::wire::OpenFlags::kAppend, "APPEND"},
{fuchsia_io::wire::OpenFlags::kNodeReference, "NODE_REFERENCE"},
{fuchsia_io::wire::OpenFlags::kDescribe, "DESCRIBE"},
{fuchsia_io::wire::OpenFlags::kPosixDeprecated, "POSIX_DEPRECATED"},
{fuchsia_io::wire::OpenFlags::kPosixWritable, "POSIX_WRITABLE"},
{fuchsia_io::wire::OpenFlags::kPosixExecutable, "POSIX_EXECUTABLE"},
{fuchsia_io::wire::OpenFlags::kNotDirectory, "NOT_DIRECTORY"},
{fuchsia_io::wire::OpenFlags::kCloneSameRights, "CLONE_SAME_RIGHTS"},
};
bool first = true;
for (const auto& [flag, desc] : flagToString) {
if (flags & flag) {
if (!first) {
sb->Append(" | ");
}
first = false;
sb->Append(desc);
}
flags ^= flag;
}
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, fuchsia_io::wire::VmoFlags flags) {
constexpr std::pair<fuchsia_io::wire::VmoFlags, std::string_view> flagToString[] = {
{fuchsia_io::wire::VmoFlags::kRead, "READ"},
{fuchsia_io::wire::VmoFlags::kWrite, "WRITE"},
{fuchsia_io::wire::VmoFlags::kExecute, "EXECUTE"},
{fuchsia_io::wire::VmoFlags::kPrivateClone, "PRIVATE_CLONE"},
{fuchsia_io::wire::VmoFlags::kSharedBuffer, "SHARED_BUFFER"},
};
bool first = true;
for (const auto& [flag, desc] : flagToString) {
if (flags & flag) {
if (!first) {
sb->Append(" | ");
}
first = false;
sb->Append(desc);
}
flags ^= flag;
}
}
#endif // __Fuchsia__
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, uint32_t num) {
sb->AppendPrintf("%u", num);
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, void* p) {
sb->AppendPrintf("%p", p);
}
template <size_t N>
void PrintEach(fbl::StringBuffer<N>* sb) {}
template <size_t N, typename T, typename... Args>
void PrintEach(fbl::StringBuffer<N>* sb, T val, Args... args) {
PrintIntoStringBuffer(sb, val);
PrintEach(sb, args...);
}
void Log(std::string_view buffer);
template <typename... Args>
void ConnectionTraceDebug(Args... args) {
constexpr size_t kMaxSize = 2000;
auto str = std::make_unique<fbl::StringBuffer<kMaxSize>>();
PrintEach(str.get(), args...);
Log(*str);
}
} // namespace debug_internal
} // namespace fs
#define FS_PRETTY_TRACE_DEBUG(args...) \
do { \
if (fs::trace_debug_enabled()) \
fs::debug_internal::ConnectionTraceDebug(args); \
} while (0)
#endif // SRC_LIB_STORAGE_VFS_CPP_DEBUG_H_