blob: dfd086e5ea65b392d0b949a747cb6be988434ed4 [file] [log] [blame]
// Copyright 2020 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.
#include "src/lib/fidl_codec/printer.h"
#include <fuchsia/io/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <sys/stat.h>
#include <zircon/syscalls/exception.h>
#include <zircon/syscalls/iommu.h>
#include <zircon/syscalls/object.h>
#include <zircon/syscalls/pci.h>
#include <zircon/syscalls/policy.h>
#include <zircon/syscalls/port.h>
#include <zircon/syscalls/profile.h>
#include <zircon/syscalls/system.h>
#include "src/lib/fidl_codec/display_handle.h"
#include "src/lib/fidl_codec/status.h"
#include "src/lib/fidl_codec/syscall_prop_stubs.h"
namespace fidl_codec {
constexpr int kCharactersPerByte = 2;
const Colors WithoutColors("", "", "", "", "", "");
const Colors WithColors(/*new_reset=*/"\u001b[0m", /*new_red=*/"\u001b[31m",
/*new_green=*/"\u001b[32m", /*new_blue=*/"\u001b[34m",
/*new_white_on_magenta=*/"\u001b[45m\u001b[37m",
/*new_yellow_background=*/"\u001b[103m");
PrettyPrinter::PrettyPrinter(std::ostream& os, const Colors& colors, bool pretty_print,
std::string_view line_header, int max_line_size,
bool header_on_every_line, int tabulations)
: os_(os),
colors_(colors),
pretty_print_(pretty_print),
line_header_(line_header),
max_line_size_(max_line_size),
header_on_every_line_(header_on_every_line),
tabulations_(tabulations),
remaining_size_(max_line_size - tabulations * kTabSize) {
// Computes the displayed size of the header. The header can contain escape sequences (to add some
// colors) which don't count as displayed characters. Here we count the number of characters in
// the line header skiping everything between escape ('\u001b') and 'm'.
size_t i = 0;
while (i < line_header.size()) {
if (line_header[i] == '\u001b') {
i = line_header.find_first_of('m', i + 1);
if (i == std::string_view::npos) {
break;
}
++i;
} else {
++i;
++line_header_size_;
}
}
}
void PrettyPrinter::DisplayHandle(const zx_handle_disposition_t& handle) {
fidl_codec::DisplayHandle(handle, *this);
}
#define BtiPermCase(name) \
if ((perm & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayBtiPerm(uint32_t perm) {
if (perm == 0) {
*this << Red << "0" << ResetColor;
return;
}
*this << Blue;
const char* separator = "";
BtiPermCase(ZX_BTI_PERM_READ);
BtiPermCase(ZX_BTI_PERM_WRITE);
BtiPermCase(ZX_BTI_PERM_EXECUTE);
BtiPermCase(ZX_BTI_COMPRESS);
BtiPermCase(ZX_BTI_CONTIGUOUS);
*this << ResetColor;
}
#define CachePolicyCase(name) \
case name: \
*this << Blue << #name << ResetColor; \
return
void PrettyPrinter::DisplayCachePolicy(uint32_t cache_policy) {
switch (cache_policy) {
CachePolicyCase(ZX_CACHE_POLICY_CACHED);
CachePolicyCase(ZX_CACHE_POLICY_UNCACHED);
CachePolicyCase(ZX_CACHE_POLICY_UNCACHED_DEVICE);
CachePolicyCase(ZX_CACHE_POLICY_WRITE_COMBINING);
default:
*this << Red << cache_policy << ResetColor;
return;
}
}
#define ChannelOptionCase(name) \
if ((options & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayChannelOption(uint32_t options) {
if (options == 0) {
*this << Blue << "0" << ResetColor;
return;
}
*this << Blue;
const char* separator = "";
ChannelOptionCase(ZX_CHANNEL_READ_MAY_DISCARD);
ChannelOptionCase(ZX_CHANNEL_WRITE_USE_IOVEC);
*this << ResetColor;
}
#define ClockCase(name) \
case name: \
*this << Blue << #name << ResetColor; \
return
void PrettyPrinter::DisplayClock(zx_clock_t clock) {
switch (clock) {
ClockCase(ZX_CLOCK_MONOTONIC);
default:
*this << Red << clock << ResetColor;
return;
}
}
void PrettyPrinter::DisplayDuration(zx_duration_t duration_ns) {
if (duration_ns == ZX_TIME_INFINITE) {
*this << Blue << "ZX_TIME_INFINITE" << ResetColor;
return;
}
if (duration_ns == ZX_TIME_INFINITE_PAST) {
*this << Blue << "ZX_TIME_INFINITE_PAST" << ResetColor;
return;
}
*this << Blue;
if (duration_ns < 0) {
*this << '-';
duration_ns = -duration_ns;
}
const char* separator = "";
int64_t nanoseconds = duration_ns % kOneBillion;
int64_t seconds = duration_ns / kOneBillion;
if (seconds != 0) {
int64_t minutes = seconds / kSecondsPerMinute;
if (minutes != 0) {
int64_t hours = minutes / kMinutesPerHour;
if (hours != 0) {
int64_t days = hours / kHoursPerDay;
if (days != 0) {
*this << days << " days";
separator = ", ";
}
*this << separator << (hours % kHoursPerDay) << " hours";
separator = ", ";
}
*this << separator << (minutes % kMinutesPerHour) << " minutes";
separator = ", ";
}
*this << separator << (seconds % kSecondsPerMinute) << " seconds";
if (nanoseconds != 0) {
*this << " and " << nanoseconds << " nano seconds";
}
} else if (nanoseconds != 0) {
*this << nanoseconds << " nano seconds";
} else {
*this << "0 seconds";
}
*this << ResetColor;
}
#define ExceptionChannelTypeCase(name) \
case name: \
*this << #name; \
break
void PrettyPrinter::DisplayExceptionChannelType(uint32_t type) {
*this << Blue;
switch (type) {
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_NONE);
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_DEBUGGER);
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_THREAD);
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_PROCESS);
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_JOB);
ExceptionChannelTypeCase(ZX_EXCEPTION_CHANNEL_TYPE_JOB_DEBUGGER);
default:
*this << static_cast<uint32_t>(type);
break;
}
*this << ResetColor;
}
#define ExceptionStateCase(name) \
case name: \
*this << #name; \
break
void PrettyPrinter::DisplayExceptionState(uint32_t state) {
*this << Blue;
switch (state) {
ExceptionStateCase(ZX_EXCEPTION_STATE_TRY_NEXT);
ExceptionStateCase(ZX_EXCEPTION_STATE_HANDLED);
default:
*this << static_cast<uint32_t>(state);
break;
}
*this << ResetColor;
}
#define FeatureKindCase(name) \
case name: \
*this << #name; \
break
void PrettyPrinter::DisplayFeatureKind(uint32_t kind) {
*this << Red;
switch (kind) {
FeatureKindCase(ZX_FEATURE_KIND_CPU);
FeatureKindCase(ZX_FEATURE_KIND_HW_BREAKPOINT_COUNT);
FeatureKindCase(ZX_FEATURE_KIND_HW_WATCHPOINT_COUNT);
default:
*this << static_cast<uint32_t>(kind);
break;
}
*this << ResetColor;
}
#define GuestTrapCase(name) \
case name: \
*this << #name; \
break
void PrettyPrinter::DisplayGuestTrap(uint32_t trap_id) {
*this << Red;
switch (trap_id) {
GuestTrapCase(ZX_GUEST_TRAP_BELL);
GuestTrapCase(ZX_GUEST_TRAP_IO);
GuestTrapCase(ZX_GUEST_TRAP_MEM);
default:
*this << static_cast<uint32_t>(trap_id);
break;
}
*this << ResetColor;
}
#define KoidCase(name) \
case name: \
*this << #name << " (" << static_cast<uint64_t>(value) << ")"; \
break
void PrettyPrinter::DisplayKoid(uint64_t value) {
*this << Red;
switch (value) {
KoidCase(ZX_KOID_INVALID);
KoidCase(ZX_KOID_KERNEL);
default:
*this << static_cast<uint64_t>(value);
break;
}
*this << ResetColor;
}
void PrettyPrinter::DisplayHexa8(uint8_t value) {
std::vector<char> buffer(sizeof(uint8_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%02" PRIx8, value);
*this << Blue << buffer.data() << ResetColor;
}
void PrettyPrinter::DisplayHexa16(uint16_t value) {
std::vector<char> buffer(sizeof(uint16_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%04" PRIx16, value);
*this << Blue << buffer.data() << ResetColor;
}
void PrettyPrinter::DisplayHexa32(uint32_t value) {
std::vector<char> buffer(sizeof(uint32_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%08" PRIx32, value);
*this << Blue << buffer.data() << ResetColor;
}
void PrettyPrinter::DisplayHexa64(uint64_t value) {
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%016" PRIx64, value);
*this << Blue << buffer.data() << ResetColor;
}
#define InfoMapsTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayInfoMapsType(zx_info_maps_type_t type) {
*this << Red;
switch (type) {
InfoMapsTypeCase(ZX_INFO_MAPS_TYPE_NONE);
InfoMapsTypeCase(ZX_INFO_MAPS_TYPE_ASPACE);
InfoMapsTypeCase(ZX_INFO_MAPS_TYPE_VMAR);
InfoMapsTypeCase(ZX_INFO_MAPS_TYPE_MAPPING);
default:
*this << type << ResetColor;
return;
}
}
#define InterruptFlagsCase(name) \
case name: \
*this << #name; \
break
#define InterruptFlagsFlag(name) \
if ((flags & (name)) == (name)) { \
*this << " | " << #name; \
}
void PrettyPrinter::DisplayInterruptFlags(uint32_t flags) {
*this << Red;
switch (flags & ZX_INTERRUPT_MODE_MASK) {
InterruptFlagsCase(ZX_INTERRUPT_MODE_DEFAULT);
InterruptFlagsCase(ZX_INTERRUPT_MODE_EDGE_LOW);
InterruptFlagsCase(ZX_INTERRUPT_MODE_EDGE_HIGH);
InterruptFlagsCase(ZX_INTERRUPT_MODE_LEVEL_LOW);
InterruptFlagsCase(ZX_INTERRUPT_MODE_LEVEL_HIGH);
InterruptFlagsCase(ZX_INTERRUPT_MODE_EDGE_BOTH);
default:
*this << (flags & ZX_INTERRUPT_MODE_MASK);
break;
}
InterruptFlagsFlag(ZX_INTERRUPT_REMAP_IRQ);
InterruptFlagsFlag(ZX_INTERRUPT_VIRTUAL);
*this << ResetColor;
}
#define IommuTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayIommuType(uint32_t type) {
*this << Red;
switch (type) {
IommuTypeCase(ZX_IOMMU_TYPE_DUMMY);
IommuTypeCase(ZX_IOMMU_TYPE_INTEL);
default:
*this << type << ResetColor;
return;
}
}
#define KtraceControlActionCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayKtraceControlAction(uint32_t action) {
constexpr uint32_t KTRACE_ACTION_START = 1;
constexpr uint32_t KTRACE_ACTION_STOP = 2;
constexpr uint32_t KTRACE_ACTION_REWIND = 3;
constexpr uint32_t KTRACE_ACTION_NEW_PROBE = 4;
*this << Blue;
switch (action) {
KtraceControlActionCase(KTRACE_ACTION_START);
KtraceControlActionCase(KTRACE_ACTION_STOP);
KtraceControlActionCase(KTRACE_ACTION_REWIND);
KtraceControlActionCase(KTRACE_ACTION_NEW_PROBE);
default:
*this << action << ResetColor;
return;
}
}
#define TopicCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayObjectInfoTopic(uint32_t topic) {
*this << Blue;
switch (topic) {
TopicCase(ZX_INFO_NONE);
TopicCase(ZX_INFO_HANDLE_VALID);
TopicCase(ZX_INFO_HANDLE_BASIC);
TopicCase(ZX_INFO_PROCESS);
TopicCase(ZX_INFO_PROCESS_THREADS);
TopicCase(ZX_INFO_VMAR);
TopicCase(ZX_INFO_JOB_CHILDREN);
TopicCase(ZX_INFO_JOB_PROCESSES);
TopicCase(ZX_INFO_THREAD);
TopicCase(ZX_INFO_THREAD_EXCEPTION_REPORT);
TopicCase(ZX_INFO_TASK_STATS);
TopicCase(ZX_INFO_PROCESS_MAPS);
TopicCase(ZX_INFO_PROCESS_VMOS);
TopicCase(ZX_INFO_THREAD_STATS);
TopicCase(ZX_INFO_CPU_STATS);
TopicCase(ZX_INFO_KMEM_STATS);
TopicCase(ZX_INFO_RESOURCE);
TopicCase(ZX_INFO_HANDLE_COUNT);
TopicCase(ZX_INFO_BTI);
TopicCase(ZX_INFO_PROCESS_HANDLE_STATS);
TopicCase(ZX_INFO_SOCKET);
TopicCase(ZX_INFO_VMO);
TopicCase(ZX_INFO_JOB);
default:
*this << "topic=" << topic << ResetColor;
return;
}
}
#define ObjTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayObjType(zx_obj_type_t obj_type) {
*this << Blue;
switch (obj_type) {
ObjTypeCase(ZX_OBJ_TYPE_NONE);
ObjTypeCase(ZX_OBJ_TYPE_PROCESS);
ObjTypeCase(ZX_OBJ_TYPE_THREAD);
ObjTypeCase(ZX_OBJ_TYPE_VMO);
ObjTypeCase(ZX_OBJ_TYPE_CHANNEL);
ObjTypeCase(ZX_OBJ_TYPE_EVENT);
ObjTypeCase(ZX_OBJ_TYPE_PORT);
ObjTypeCase(ZX_OBJ_TYPE_INTERRUPT);
ObjTypeCase(ZX_OBJ_TYPE_PCI_DEVICE);
ObjTypeCase(ZX_OBJ_TYPE_LOG);
ObjTypeCase(ZX_OBJ_TYPE_SOCKET);
ObjTypeCase(ZX_OBJ_TYPE_RESOURCE);
ObjTypeCase(ZX_OBJ_TYPE_EVENTPAIR);
ObjTypeCase(ZX_OBJ_TYPE_JOB);
ObjTypeCase(ZX_OBJ_TYPE_VMAR);
ObjTypeCase(ZX_OBJ_TYPE_FIFO);
ObjTypeCase(ZX_OBJ_TYPE_GUEST);
ObjTypeCase(ZX_OBJ_TYPE_VCPU);
ObjTypeCase(ZX_OBJ_TYPE_TIMER);
ObjTypeCase(ZX_OBJ_TYPE_IOMMU);
ObjTypeCase(ZX_OBJ_TYPE_BTI);
ObjTypeCase(ZX_OBJ_TYPE_PROFILE);
ObjTypeCase(ZX_OBJ_TYPE_PMT);
ObjTypeCase(ZX_OBJ_TYPE_SUSPEND_TOKEN);
ObjTypeCase(ZX_OBJ_TYPE_PAGER);
ObjTypeCase(ZX_OBJ_TYPE_EXCEPTION);
ObjTypeCase(ZX_OBJ_TYPE_CLOCK);
ObjTypeCase(ZX_OBJ_TYPE_STREAM);
ObjTypeCase(ZX_OBJ_TYPE_MSI);
default:
*this << obj_type << ResetColor;
return;
}
}
void PrettyPrinter::DisplayPaddr(zx_paddr_t addr) {
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
#ifdef __MACH__
snprintf(buffer.data(), buffer.size(), "%016" PRIxPTR, addr);
#else
snprintf(buffer.data(), buffer.size(), "%016" PRIx64, addr);
#endif
*this << Blue << buffer.data() << ResetColor;
}
#define PacketGuestVcpuTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayPacketGuestVcpuType(uint8_t type) {
*this << Blue;
switch (type) {
PacketGuestVcpuTypeCase(ZX_PKT_GUEST_VCPU_INTERRUPT);
PacketGuestVcpuTypeCase(ZX_PKT_GUEST_VCPU_STARTUP);
default:
*this << static_cast<uint32_t>(type) << ResetColor;
return;
}
}
#define PacketPageRequestCommandCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayPacketPageRequestCommand(uint16_t command) {
*this << Blue;
switch (command) {
PacketPageRequestCommandCase(ZX_PAGER_VMO_READ);
PacketPageRequestCommandCase(ZX_PAGER_VMO_COMPLETE);
default:
*this << static_cast<uint32_t>(command) << ResetColor;
return;
}
}
#define PciBarTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayPciBarType(uint32_t type) {
*this << Blue;
switch (type) {
PciBarTypeCase(ZX_PCI_BAR_TYPE_UNUSED);
PciBarTypeCase(ZX_PCI_BAR_TYPE_MMIO);
PciBarTypeCase(ZX_PCI_BAR_TYPE_PIO);
default:
*this << static_cast<uint32_t>(type) << ResetColor;
return;
}
}
#define PolicyCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayPolicyAction(uint32_t action) {
*this << Blue;
switch (action) {
PolicyCase(ZX_POL_ACTION_ALLOW);
PolicyCase(ZX_POL_ACTION_DENY);
PolicyCase(ZX_POL_ACTION_ALLOW_EXCEPTION);
PolicyCase(ZX_POL_ACTION_DENY_EXCEPTION);
PolicyCase(ZX_POL_ACTION_KILL);
default:
*this << action << ResetColor;
return;
}
}
void PrettyPrinter::DisplayPolicyCondition(uint32_t condition) {
*this << Blue;
switch (condition) {
PolicyCase(ZX_POL_BAD_HANDLE);
PolicyCase(ZX_POL_WRONG_OBJECT);
PolicyCase(ZX_POL_VMAR_WX);
PolicyCase(ZX_POL_NEW_ANY);
PolicyCase(ZX_POL_NEW_VMO);
PolicyCase(ZX_POL_NEW_CHANNEL);
PolicyCase(ZX_POL_NEW_EVENT);
PolicyCase(ZX_POL_NEW_EVENTPAIR);
PolicyCase(ZX_POL_NEW_PORT);
PolicyCase(ZX_POL_NEW_SOCKET);
PolicyCase(ZX_POL_NEW_FIFO);
PolicyCase(ZX_POL_NEW_TIMER);
PolicyCase(ZX_POL_NEW_PROCESS);
PolicyCase(ZX_POL_NEW_PROFILE);
PolicyCase(ZX_POL_AMBIENT_MARK_VMO_EXEC);
default:
*this << condition << ResetColor;
return;
}
}
void PrettyPrinter::DisplayPolicyTopic(uint32_t topic) {
*this << Blue;
switch (topic) {
PolicyCase(ZX_JOB_POL_BASIC);
PolicyCase(ZX_JOB_POL_TIMER_SLACK);
default:
*this << topic << ResetColor;
return;
}
}
#define ProfileInfoFlagsCase(name) \
if ((flags & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayProfileInfoFlags(uint32_t flags) {
*this << Blue;
if (flags == 0) {
*this << "0" << ResetColor;
return;
}
const char* separator = "";
ProfileInfoFlagsCase(ZX_PROFILE_INFO_FLAG_PRIORITY);
ProfileInfoFlagsCase(ZX_PROFILE_INFO_FLAG_CPU_MASK);
*this << ResetColor;
}
#define PortPacketTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayPortPacketType(uint32_t type) {
*this << Blue;
switch (type) {
PortPacketTypeCase(ZX_PKT_TYPE_USER);
PortPacketTypeCase(ZX_PKT_TYPE_SIGNAL_ONE);
PortPacketTypeCase(ZX_PKT_TYPE_GUEST_BELL);
PortPacketTypeCase(ZX_PKT_TYPE_GUEST_MEM);
PortPacketTypeCase(ZX_PKT_TYPE_GUEST_IO);
PortPacketTypeCase(ZX_PKT_TYPE_GUEST_VCPU);
PortPacketTypeCase(ZX_PKT_TYPE_INTERRUPT);
PortPacketTypeCase(ZX_PKT_TYPE_PAGE_REQUEST);
default:
*this << "port_packet_type=" << type << ResetColor;
return;
}
}
// ZX_PROP_REGISTER_GS and ZX_PROP_REGISTER_FS are defined in
// <zircon/system/public/zircon/syscalls/object.h>
// but only available for amd64.
// We need these values in all the environments.
#ifndef ZX_PROP_REGISTER_GS
#define ZX_PROP_REGISTER_GS ((uint32_t)2u)
#endif
#ifndef ZX_PROP_REGISTER_FS
#define ZX_PROP_REGISTER_FS ((uint32_t)4u)
#endif
#define PropTypeCase(name) \
case name: \
*this << #name; \
*this << ResetColor; \
return
void PrettyPrinter::DisplayPropType(uint32_t type) {
*this << Blue;
switch (type) {
PropTypeCase(ZX_PROP_NAME);
PropTypeCase(ZX_PROP_REGISTER_FS);
PropTypeCase(ZX_PROP_REGISTER_GS);
PropTypeCase(ZX_PROP_PROCESS_DEBUG_ADDR);
PropTypeCase(ZX_PROP_PROCESS_VDSO_BASE_ADDRESS);
PropTypeCase(ZX_PROP_SOCKET_RX_THRESHOLD);
PropTypeCase(ZX_PROP_SOCKET_TX_THRESHOLD);
PropTypeCase(ZX_PROP_JOB_KILL_ON_OOM);
PropTypeCase(ZX_PROP_EXCEPTION_STATE);
default:
*this << type << ResetColor;
return;
}
}
#define RightsCase(name) \
if ((rights & (name)) != 0) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayRights(uint32_t rights) {
*this << Blue;
if (rights == 0) {
*this << "ZX_RIGHT_NONE" << ResetColor;
return;
}
const char* separator = "";
RightsCase(ZX_RIGHT_DUPLICATE);
RightsCase(ZX_RIGHT_TRANSFER);
RightsCase(ZX_RIGHT_READ);
RightsCase(ZX_RIGHT_WRITE);
RightsCase(ZX_RIGHT_EXECUTE);
RightsCase(ZX_RIGHT_MAP);
RightsCase(ZX_RIGHT_GET_PROPERTY);
RightsCase(ZX_RIGHT_SET_PROPERTY);
RightsCase(ZX_RIGHT_ENUMERATE);
RightsCase(ZX_RIGHT_DESTROY);
RightsCase(ZX_RIGHT_SET_POLICY);
RightsCase(ZX_RIGHT_GET_POLICY);
RightsCase(ZX_RIGHT_SIGNAL);
RightsCase(ZX_RIGHT_SIGNAL_PEER);
RightsCase(ZX_RIGHT_WAIT);
RightsCase(ZX_RIGHT_INSPECT);
RightsCase(ZX_RIGHT_MANAGE_JOB);
RightsCase(ZX_RIGHT_MANAGE_PROCESS);
RightsCase(ZX_RIGHT_MANAGE_THREAD);
RightsCase(ZX_RIGHT_APPLY_PROFILE);
RightsCase(ZX_RIGHT_MANAGE_SOCKET);
RightsCase(ZX_RIGHT_SAME_RIGHTS);
*this << ResetColor;
}
#define RsrcKindCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayRsrcKind(zx_rsrc_kind_t kind) {
*this << Blue;
switch (kind) {
RsrcKindCase(ZX_RSRC_KIND_MMIO);
RsrcKindCase(ZX_RSRC_KIND_IRQ);
RsrcKindCase(ZX_RSRC_KIND_IOPORT);
RsrcKindCase(ZX_RSRC_KIND_ROOT);
RsrcKindCase(ZX_RSRC_KIND_SMC);
RsrcKindCase(ZX_RSRC_KIND_SYSTEM);
RsrcKindCase(ZX_RSRC_KIND_COUNT);
default:
*this << kind << ResetColor;
return;
}
}
#define SignalCase(name) \
if ((signals & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplaySignals(zx_signals_t signals) {
*this << Blue;
if (signals == 0) {
*this << "0" << ResetColor;
return;
}
if (signals == __ZX_OBJECT_SIGNAL_ALL) {
*this << "__ZX_OBJECT_SIGNAL_ALL" << ResetColor;
return;
}
const char* separator = "";
SignalCase(__ZX_OBJECT_READABLE);
SignalCase(__ZX_OBJECT_WRITABLE);
SignalCase(__ZX_OBJECT_PEER_CLOSED);
SignalCase(__ZX_OBJECT_SIGNALED);
SignalCase(__ZX_OBJECT_SIGNAL_4);
SignalCase(__ZX_OBJECT_SIGNAL_5);
SignalCase(__ZX_OBJECT_SIGNAL_6);
SignalCase(__ZX_OBJECT_SIGNAL_7);
SignalCase(__ZX_OBJECT_SIGNAL_8);
SignalCase(__ZX_OBJECT_SIGNAL_9);
SignalCase(__ZX_OBJECT_SIGNAL_10);
SignalCase(__ZX_OBJECT_SIGNAL_11);
SignalCase(__ZX_OBJECT_SIGNAL_12);
SignalCase(__ZX_OBJECT_SIGNAL_13);
SignalCase(__ZX_OBJECT_SIGNAL_14);
SignalCase(__ZX_OBJECT_SIGNAL_15);
SignalCase(__ZX_OBJECT_SIGNAL_16);
SignalCase(__ZX_OBJECT_SIGNAL_17);
SignalCase(__ZX_OBJECT_SIGNAL_18);
SignalCase(__ZX_OBJECT_SIGNAL_19);
SignalCase(__ZX_OBJECT_SIGNAL_20);
SignalCase(__ZX_OBJECT_SIGNAL_21);
SignalCase(__ZX_OBJECT_SIGNAL_22);
SignalCase(__ZX_OBJECT_HANDLE_CLOSED);
SignalCase(ZX_USER_SIGNAL_0);
SignalCase(ZX_USER_SIGNAL_1);
SignalCase(ZX_USER_SIGNAL_2);
SignalCase(ZX_USER_SIGNAL_3);
SignalCase(ZX_USER_SIGNAL_4);
SignalCase(ZX_USER_SIGNAL_5);
SignalCase(ZX_USER_SIGNAL_6);
SignalCase(ZX_USER_SIGNAL_7);
*this << ResetColor;
}
#define SocketCreateOptionsCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplaySocketCreateOptions(uint32_t options) {
*this << Blue;
switch (options) {
SocketCreateOptionsCase(ZX_SOCKET_STREAM);
SocketCreateOptionsCase(ZX_SOCKET_DATAGRAM);
default:
*this << static_cast<uint32_t>(options) << ResetColor;
return;
}
}
#define SocketReadOptionsCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplaySocketReadOptions(uint32_t options) {
*this << Blue;
switch (options) {
SocketReadOptionsCase(ZX_SOCKET_PEEK);
default:
*this << static_cast<uint32_t>(options) << ResetColor;
return;
}
}
#define SocketDispositionCase(name) \
if ((disposition & (name)) == (name)) { \
disposition ^= (name); \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplaySocketDisposition(uint32_t disposition) {
*this << Blue;
if (disposition == 0) {
*this << "0" << ResetColor;
return;
}
const char* separator = "";
SocketDispositionCase(ZX_SOCKET_DISPOSITION_WRITE_DISABLED);
SocketDispositionCase(ZX_SOCKET_DISPOSITION_WRITE_ENABLED);
if (disposition) {
*this << separator << disposition;
}
*this << ResetColor;
}
void PrettyPrinter::DisplayStatus(zx_status_t status) {
if (status == ZX_OK) {
*this << Green;
} else {
*this << Red;
}
*this << StatusName(status) << ResetColor;
}
void PrettyPrinter::DisplayString(std::string_view string) {
if (string.data() == nullptr) {
*this << "nullptr\n";
} else {
*this << Red << '"';
for (char value : string) {
switch (value) {
case 0:
break;
case '\\':
*this << "\\\\";
break;
case '\n':
*this << "\\n";
break;
default:
*this << value;
break;
}
}
*this << '"' << ResetColor;
}
}
#define SystemEventTypeCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplaySystemEventType(zx_system_event_type_t type) {
*this << Blue;
switch (type) {
SystemEventTypeCase(ZX_SYSTEM_EVENT_OUT_OF_MEMORY);
default:
*this << type << ResetColor;
return;
}
}
#define SystemPowerctlCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplaySystemPowerctl(uint32_t powerctl) {
*this << Blue;
switch (powerctl) {
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_ENABLE_ALL_CPUS);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_DISABLE_ALL_CPUS_BUT_PRIMARY);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_ACPI_TRANSITION_S_STATE);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_X86_SET_PKG_PL1);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_REBOOT);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_REBOOT_BOOTLOADER);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_REBOOT_RECOVERY);
SystemPowerctlCase(ZX_SYSTEM_POWERCTL_SHUTDOWN);
default:
*this << powerctl << ResetColor;
return;
}
}
#define ThreadStateCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayThreadState(uint32_t state) {
*this << Blue;
switch (state) {
ThreadStateCase(ZX_THREAD_STATE_NEW);
ThreadStateCase(ZX_THREAD_STATE_RUNNING);
ThreadStateCase(ZX_THREAD_STATE_SUSPENDED);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED);
ThreadStateCase(ZX_THREAD_STATE_DYING);
ThreadStateCase(ZX_THREAD_STATE_DEAD);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_EXCEPTION);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_SLEEPING);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_FUTEX);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_PORT);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_CHANNEL);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_WAIT_ONE);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_WAIT_MANY);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_INTERRUPT);
ThreadStateCase(ZX_THREAD_STATE_BLOCKED_PAGER);
default:
*this << static_cast<uint32_t>(state) << ResetColor;
return;
}
}
#define ThreadStateTopicCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayThreadStateTopic(zx_thread_state_topic_t topic) {
*this << Blue;
switch (topic) {
ThreadStateTopicCase(ZX_THREAD_STATE_GENERAL_REGS);
ThreadStateTopicCase(ZX_THREAD_STATE_FP_REGS);
ThreadStateTopicCase(ZX_THREAD_STATE_VECTOR_REGS);
ThreadStateTopicCase(ZX_THREAD_STATE_DEBUG_REGS);
ThreadStateTopicCase(ZX_THREAD_STATE_SINGLE_STEP);
default:
*this << static_cast<uint32_t>(topic) << ResetColor;
return;
}
}
void PrettyPrinter::DisplayTime(zx_time_t time_ns) {
if (time_ns == ZX_TIME_INFINITE) {
(*this) << Blue << "ZX_TIME_INFINITE" << ResetColor;
} else if (time_ns == ZX_TIME_INFINITE_PAST) {
(*this) << Blue << "ZX_TIME_INFINITE_PAST" << ResetColor;
} else {
// Gets the time in seconds.
time_t value = time_ns / kOneBillion;
struct tm tm;
if (localtime_r(&value, &tm) == &tm) {
char buffer[100];
strftime(buffer, sizeof(buffer), "%c", &tm);
// And now, displays the nano seconds.
(*this) << Blue << buffer << " and ";
snprintf(buffer, sizeof(buffer), "%09" PRId64, time_ns % kOneBillion);
(*this) << buffer << " ns" << ResetColor;
} else {
(*this) << Red << "unknown time" << ResetColor;
}
}
}
#define TimerOptionCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayTimerOption(uint32_t option) {
*this << Blue;
switch (option) {
TimerOptionCase(ZX_TIMER_SLACK_CENTER);
TimerOptionCase(ZX_TIMER_SLACK_EARLY);
TimerOptionCase(ZX_TIMER_SLACK_LATE);
default:
*this << option << ResetColor;
return;
}
}
#ifdef __MACH__
void PrettyPrinter::DisplayUintptr(uintptr_t ptr) {
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%016" PRIxPTR, ptr);
*this << Blue << buffer.data() << ResetColor;
}
#else
void PrettyPrinter::DisplayUintptr(uint64_t ptr) {
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%016" PRIx64, ptr);
*this << Blue << buffer.data() << ResetColor;
}
#endif
void PrettyPrinter::DisplayVaddr(zx_vaddr_t addr) {
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
#ifdef __MACH__
snprintf(buffer.data(), buffer.size(), "%016" PRIxPTR, addr);
#else
snprintf(buffer.data(), buffer.size(), "%016" PRIx64, addr);
#endif
*this << Blue << buffer.data() << ResetColor;
}
void PrettyPrinter::DisplayGpAddr(zx_gpaddr_t addr) {
#ifdef __MACH__
std::vector<char> buffer(sizeof(uintptr_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%016" PRIxPTR, addr);
#else
std::vector<char> buffer(sizeof(uint64_t) * kCharactersPerByte + 1);
snprintf(buffer.data(), buffer.size(), "%016" PRIx64, addr);
#endif
*this << Blue << buffer.data() << ResetColor;
}
#define VcpuCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayVcpu(uint32_t type) {
*this << Red;
switch (type) {
VcpuCase(ZX_VCPU_STATE);
VcpuCase(ZX_VCPU_IO);
default:
*this << type << ResetColor;
return;
}
}
#define VmOptionAlign(name) \
case name: \
*this << #name; \
separator = " | "; \
break;
#define VmOptionCase(name) \
if ((option & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayVmOption(zx_vm_option_t option) {
*this << Red;
if (option == 0) {
*this << "0" << ResetColor;
return;
}
const char* separator = "";
switch (option & ~((1 << ZX_VM_ALIGN_BASE) - 1)) {
VmOptionAlign(ZX_VM_ALIGN_1KB);
VmOptionAlign(ZX_VM_ALIGN_2KB);
VmOptionAlign(ZX_VM_ALIGN_4KB);
VmOptionAlign(ZX_VM_ALIGN_8KB);
VmOptionAlign(ZX_VM_ALIGN_16KB);
VmOptionAlign(ZX_VM_ALIGN_32KB);
VmOptionAlign(ZX_VM_ALIGN_64KB);
VmOptionAlign(ZX_VM_ALIGN_128KB);
VmOptionAlign(ZX_VM_ALIGN_256KB);
VmOptionAlign(ZX_VM_ALIGN_512KB);
VmOptionAlign(ZX_VM_ALIGN_1MB);
VmOptionAlign(ZX_VM_ALIGN_2MB);
VmOptionAlign(ZX_VM_ALIGN_4MB);
VmOptionAlign(ZX_VM_ALIGN_8MB);
VmOptionAlign(ZX_VM_ALIGN_16MB);
VmOptionAlign(ZX_VM_ALIGN_32MB);
VmOptionAlign(ZX_VM_ALIGN_64MB);
VmOptionAlign(ZX_VM_ALIGN_128MB);
VmOptionAlign(ZX_VM_ALIGN_256MB);
VmOptionAlign(ZX_VM_ALIGN_512MB);
VmOptionAlign(ZX_VM_ALIGN_1GB);
VmOptionAlign(ZX_VM_ALIGN_2GB);
VmOptionAlign(ZX_VM_ALIGN_4GB);
default:
if ((option >> ZX_VM_ALIGN_BASE) != 0) {
*this << (option >> ZX_VM_ALIGN_BASE);
}
break;
}
VmOptionCase(ZX_VM_PERM_READ);
VmOptionCase(ZX_VM_PERM_WRITE);
VmOptionCase(ZX_VM_PERM_EXECUTE);
VmOptionCase(ZX_VM_COMPACT);
VmOptionCase(ZX_VM_SPECIFIC);
VmOptionCase(ZX_VM_SPECIFIC_OVERWRITE);
VmOptionCase(ZX_VM_CAN_MAP_SPECIFIC);
VmOptionCase(ZX_VM_CAN_MAP_READ);
VmOptionCase(ZX_VM_CAN_MAP_WRITE);
VmOptionCase(ZX_VM_CAN_MAP_EXECUTE);
VmOptionCase(ZX_VM_MAP_RANGE);
VmOptionCase(ZX_VM_REQUIRE_NON_RESIZABLE);
VmOptionCase(ZX_VM_ALLOW_FAULTS);
*this << ResetColor;
}
#define VmoCreationOptionCase(name) \
if ((options & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayVmoCreationOption(uint32_t options) {
*this << Blue;
if (options == 0) {
*this << "0" << ResetColor;
return;
}
const char* separator = "";
VmoCreationOptionCase(ZX_VMO_RESIZABLE);
*this << ResetColor;
}
#define VmoOpCase(name) \
case name: \
*this << #name << ResetColor; \
return
void PrettyPrinter::DisplayVmoOp(uint32_t op) {
*this << Blue;
switch (op) {
VmoOpCase(ZX_VMO_OP_COMMIT);
VmoOpCase(ZX_VMO_OP_DECOMMIT);
VmoOpCase(ZX_VMO_OP_LOCK);
VmoOpCase(ZX_VMO_OP_UNLOCK);
VmoOpCase(ZX_VMO_OP_CACHE_SYNC);
VmoOpCase(ZX_VMO_OP_CACHE_INVALIDATE);
VmoOpCase(ZX_VMO_OP_CACHE_CLEAN);
VmoOpCase(ZX_VMO_OP_CACHE_CLEAN_INVALIDATE);
default:
*this << op << ResetColor;
return;
}
}
#define VmoOptionCase(name) \
if ((options & (name)) == (name)) { \
*this << separator << #name; \
separator = " | "; \
}
void PrettyPrinter::DisplayVmoOption(uint32_t options) {
*this << Blue;
if (options == 0) {
*this << "0" << ResetColor;
return;
}
const char* separator = "";
VmoOptionCase(ZX_VMO_CHILD_SNAPSHOT);
VmoOptionCase(ZX_VMO_CHILD_RESIZABLE);
VmoOptionCase(ZX_VMO_CHILD_SLICE);
VmoOptionCase(ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE);
*this << ResetColor;
}
#define VmoTypeCase(name) \
if ((type & (name)) == (name)) { \
*this << " | " << #name; \
}
void PrettyPrinter::DisplayVmoType(uint32_t type) {
*this << Blue;
if ((type & 1) == ZX_INFO_VMO_TYPE_PHYSICAL) {
*this << "ZX_INFO_VMO_TYPE_PHYSICAL";
} else {
*this << "ZX_INFO_VMO_TYPE_PAGED";
}
VmoTypeCase(ZX_INFO_VMO_RESIZABLE);
VmoTypeCase(ZX_INFO_VMO_IS_COW_CLONE);
VmoTypeCase(ZX_INFO_VMO_VIA_HANDLE);
VmoTypeCase(ZX_INFO_VMO_VIA_MAPPING);
VmoTypeCase(ZX_INFO_VMO_PAGER_BACKED);
VmoTypeCase(ZX_INFO_VMO_CONTIGUOUS);
*this << ResetColor;
}
void PrettyPrinter::IncrementTabulations() {
++tabulations_;
if (need_to_print_header_) {
remaining_size_ -= kTabSize;
}
}
void PrettyPrinter::DecrementTabulations() {
--tabulations_;
if (need_to_print_header_) {
remaining_size_ += kTabSize;
}
}
void PrettyPrinter::NeedHeader() {
remaining_size_ = max_line_size_ - line_header_size_ - tabulations_ * kTabSize;
need_to_print_header_ = true;
}
void PrettyPrinter::PrintHeader(char first_character) {
FX_DCHECK(need_to_print_header_);
need_to_print_header_ = false;
if (line_header_size_ > 0) {
os_ << line_header_;
if (!header_on_every_line_) {
line_header_size_ = 0;
}
}
if (first_character != '\n') {
for (int tab = tabulations_ * kTabSize; tab > 0; --tab) {
os_ << ' ';
}
}
}
PrettyPrinter& PrettyPrinter::operator<<(std::string_view data) {
if (data.empty()) {
return *this;
}
if (need_to_print_header_) {
PrintHeader(data[0]);
}
size_t end_of_line = data.find('\n', 0);
if (end_of_line == std::string_view::npos) {
os_ << data;
remaining_size_ -= data.size();
return *this;
}
size_t current = 0;
for (;;) {
std::string_view tmp = data.substr(current, end_of_line - current + 1);
os_ << tmp;
NeedHeader();
current = end_of_line + 1;
if (current >= data.size()) {
return *this;
}
end_of_line = data.find('\n', current);
if (end_of_line == std::string_view::npos) {
os_ << data;
remaining_size_ -= data.size();
return *this;
}
PrintHeader(data[current]);
}
}
} // namespace fidl_codec