blob: e8e95faa2ef66f12cacc4bb38b86386054a294c7 [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 FS_DEBUG_H_
#define FS_DEBUG_H_
#include <zircon/device/vfs.h>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <utility>
#include <fbl/string_buffer.h>
#include <fs/trace.h>
#include <fs/vfs_types.h>
#ifdef __Fuchsia__
#include <lib/fidl/llcpp/string_view.h>
#endif // __Fuchsia__
// debug-only header defining utility functions for logging flags and paths.
namespace fs {
// Marker type for pretty-printing flags
struct ZxFlags {
public:
explicit ZxFlags(uint32_t flags) : value(flags) {}
uint32_t value;
};
struct Path {
Path(const char* path, size_t size) : str(path), size(size) {}
const char* str;
size_t size;
};
namespace debug_internal {
constexpr const char* FlagToString(uint32_t flag) {
switch (flag) {
case ZX_FS_RIGHT_ADMIN:
return "RIGHT_ADMIN";
case ZX_FS_RIGHT_READABLE:
return "RIGHT_READABLE";
case ZX_FS_RIGHT_WRITABLE:
return "RIGHT_WRITABLE";
case ZX_FS_RIGHT_EXECUTABLE:
return "RIGHT_EXECUTABLE";
case ZX_FS_RIGHTS:
return "RIGHTS";
case ZX_FS_FLAG_CREATE:
return "FLAG_CREATE";
case ZX_FS_FLAG_EXCLUSIVE:
return "FLAG_EXCLUSIVE";
case ZX_FS_FLAG_TRUNCATE:
return "FLAG_TRUNCATE";
case ZX_FS_FLAG_DIRECTORY:
return "FLAG_DIRECTORY";
case ZX_FS_FLAG_APPEND:
return "FLAG_APPEND";
case ZX_FS_FLAG_NOREMOTE:
return "FLAG_NOREMOTE";
case ZX_FS_FLAG_VNODE_REF_ONLY:
return "FLAG_VNODE_REF_ONLY";
case ZX_FS_FLAG_DESCRIBE:
return "FLAG_DESCRIBE";
case ZX_FS_FLAG_POSIX:
return "FLAG_POSIX";
case ZX_FS_FLAG_NOT_DIRECTORY:
return "FLAG_NOT_DIRECTORY";
case ZX_FS_FLAG_CLONE_SAME_RIGHTS:
return "FLAG_CLONE_SAME_RIGHTS";
default:
return "(Unknown flag)";
}
}
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, ZxFlags flags) {
bool first = true;
uint32_t bit = 1;
for (int i = 0; i < 32; i++) {
const uint32_t flag = flags.value & bit;
if (flag) {
const char* desc = FlagToString(flag);
if (!first) {
sb->Append(" | ");
}
first = false;
sb->Append(desc);
}
bit = bit << 1U;
}
}
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.no_remote)
append("no_remote");
if (options.flags.node_reference)
append("node_reference");
if (options.flags.describe)
append("describe");
if (options.flags.posix)
append("posix");
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.admin)
append("admin");
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, Path path) {
sb->Append(path.str, path.size);
}
#ifdef __Fuchsia__
template <size_t N>
void PrintIntoStringBuffer(fbl::StringBuffer<N>* sb, fidl::StringView path) {
sb->Append(path.data(), path.size());
}
#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...);
}
template <typename... Args>
void ConnectionTraceDebug(Args... args) {
constexpr size_t kMaxSize = 2000;
auto str = std::make_unique<fbl::StringBuffer<kMaxSize>>();
PrintEach(str.get(), args...);
FS_TRACE_DEBUG("%s\n", str->c_str());
}
} // namespace debug_internal
} // namespace fs
#if FS_TRACE_DEBUG_ENABLED
#define FS_PRETTY_TRACE_DEBUG(args...) fs::debug_internal::ConnectionTraceDebug(args)
#else
// Explicitly expand FS_PRETTY_TRACE_DEBUG into nothing when not debugging, to ensure zero overhead.
#define FS_PRETTY_TRACE_DEBUG(args...)
#endif
#endif // FS_DEBUG_H_