blob: c7f9e37dd580bcd047377a78d0185466f4f6bb30 [file] [log] [blame]
// Copyright 2018 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 <inttypes.h>
#include "garnet/bin/zxdb/client/register.h"
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/bin/zxdb/console/format_register.h"
#include "garnet/bin/zxdb/console/format_register_arm64.h"
#include "garnet/bin/zxdb/console/format_table.h"
#include "garnet/bin/zxdb/console/output_buffer.h"
#include "garnet/bin/zxdb/console/string_formatters.h"
#include "garnet/lib/debug_ipc/helper/arch_arm64.h"
#include "lib/fxl/strings/string_printf.h"
using debug_ipc::RegisterCategory;
using debug_ipc::RegisterID;
namespace zxdb {
namespace {
#define FLAG_VALUE(value, shift, mask) (uint8_t)((value >> shift) & mask)
TextForegroundColor GetRowColor(size_t table_len) {
return table_len % 2 == 0 ? TextForegroundColor::kDefault
: TextForegroundColor::kLightGray;
}
// Format General Registers
// -----------------------------------------------------
std::vector<OutputBuffer> DescribeCPSR(const Register& cpsr,
TextForegroundColor color) {
std::vector<OutputBuffer> result;
result.emplace_back(RegisterIDToString(cpsr.id()), color);
uint64_t value = cpsr.GetValue();
// Hex value: rflags is a 32 bit value.
result.emplace_back(fxl::StringPrintf("0x%08" PRIx64, value), color);
// Decode individual flags.
result.emplace_back(fxl::StringPrintf("V=%d, C=%d, Z=%d, N=%d",
ARM64_FLAG_VALUE(value, Cpsr, V),
ARM64_FLAG_VALUE(value, Cpsr, C),
ARM64_FLAG_VALUE(value, Cpsr, Z),
ARM64_FLAG_VALUE(value, Cpsr, N)),
color);
return result;
}
std::vector<OutputBuffer> DescribeCPSRExtended(const Register& cpsr,
TextForegroundColor color) {
std::vector<OutputBuffer> result;
result.reserve(3);
result.emplace_back(OutputBuffer());
result.emplace_back(OutputBuffer());
uint64_t value = cpsr.GetValue();
result.emplace_back(
fxl::StringPrintf(
"EL=%d, F=%d, I=%d, A=%d, D=%d, IL=%d, SS=%d, PAN=%d, UAO=%d",
ARM64_FLAG_VALUE(value, Cpsr, EL), ARM64_FLAG_VALUE(value, Cpsr, F),
ARM64_FLAG_VALUE(value, Cpsr, I), ARM64_FLAG_VALUE(value, Cpsr, A),
ARM64_FLAG_VALUE(value, Cpsr, D), ARM64_FLAG_VALUE(value, Cpsr, IL),
ARM64_FLAG_VALUE(value, Cpsr, SS), ARM64_FLAG_VALUE(value, Cpsr, PAN),
ARM64_FLAG_VALUE(value, Cpsr, UAO)),
color);
return result;
}
void FormatGeneralRegisters(const FormatRegisterOptions& options,
const std::vector<Register>& registers,
OutputBuffer* out) {
std::vector<std::vector<OutputBuffer>> rows;
for (const Register& reg : registers) {
auto color = GetRowColor(rows.size());
if (reg.id() == RegisterID::kARMv8_cpsr) {
rows.push_back(DescribeCPSR(reg, color));
if (options.extended)
rows.push_back(DescribeCPSRExtended(reg, color));
} else {
rows.push_back(DescribeRegister(reg, color));
}
}
// Output the tables.
if (!rows.empty()) {
std::vector<ColSpec> colspecs({ColSpec(Align::kRight),
ColSpec(Align::kRight, 0, std::string(), 1),
ColSpec()});
FormatTable(colspecs, rows, out);
}
}
// DBGBCR ----------------------------------------------------------------------
std::vector<OutputBuffer> FormatDBGBCR(const Register& reg,
TextForegroundColor color) {
std::vector<OutputBuffer> row;
row.reserve(3);
row.emplace_back(RegisterIDToString(reg.id()), color);
uint64_t value = reg.GetValue();
row.emplace_back(fxl::StringPrintf("0x%08" PRIx64, value), color);
row.emplace_back(
fxl::StringPrintf("E=%d, PMC=%d, BAS=%d, HMC=%d, SSC=%d, LBN=%d, BT=%d",
ARM64_FLAG_VALUE(value, DBGBCR, E),
ARM64_FLAG_VALUE(value, DBGBCR, PMC),
ARM64_FLAG_VALUE(value, DBGBCR, BAS),
ARM64_FLAG_VALUE(value, DBGBCR, HMC),
ARM64_FLAG_VALUE(value, DBGBCR, SSC),
ARM64_FLAG_VALUE(value, DBGBCR, LBN),
ARM64_FLAG_VALUE(value, DBGBCR, BT)),
color);
return row;
}
// ID_AA64DFR0_EL1 -------------------------------------------------------------
std::vector<OutputBuffer> FormatID_AA64FR0_EL1(const Register& reg,
TextForegroundColor color) {
std::vector<OutputBuffer> row;
row.reserve(3);
row.emplace_back(RegisterIDToString(reg.id()), color);
uint64_t value = reg.GetValue();
row.emplace_back(fxl::StringPrintf("0x%08" PRIx64, value), color);
row.emplace_back(
fxl::StringPrintf(
"DV=%d, TV=%d, PMUV=%d, BRP=%d, WRP=%d, CTX_CMP=%d, PMSV=%d",
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, DV),
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, TV),
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, PMUV),
// The register count values have 1 substracted to them.
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, BRP) + 1,
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, WRP) + 1,
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, CTX_CMP) + 1,
ARM64_FLAG_VALUE(value, ID_AA64DFR0_EL1, PMSV)),
color);
return row;
}
// MDSCR -----------------------------------------------------------------------
std::vector<OutputBuffer> FormatMDSCR(const Register& reg,
TextForegroundColor color) {
std::vector<OutputBuffer> row;
row.reserve(3);
row.emplace_back(RegisterIDToString(reg.id()), color);
uint64_t value = reg.GetValue();
row.emplace_back(fxl::StringPrintf("0x%08" PRIx64, value), color);
row.emplace_back(
fxl::StringPrintf("SS=%d, TDCC=%d, KDE=%d, HDE=%d, MDE=%d, RAZ/WI=%d, "
"TDA=%d, INTdis=%d, "
"TXU=%d, RXO=%d, TXfull=%d, RXfull=%d",
ARM64_FLAG_VALUE(value, MDSCR_EL1, SS),
ARM64_FLAG_VALUE(value, MDSCR_EL1, TDCC),
ARM64_FLAG_VALUE(value, MDSCR_EL1, KDE),
ARM64_FLAG_VALUE(value, MDSCR_EL1, HDE),
ARM64_FLAG_VALUE(value, MDSCR_EL1, MDE),
ARM64_FLAG_VALUE(value, MDSCR_EL1, RAZ_WI),
ARM64_FLAG_VALUE(value, MDSCR_EL1, TDA),
ARM64_FLAG_VALUE(value, MDSCR_EL1, INTdis),
ARM64_FLAG_VALUE(value, MDSCR_EL1, TXU),
ARM64_FLAG_VALUE(value, MDSCR_EL1, RXO),
ARM64_FLAG_VALUE(value, MDSCR_EL1, TXfull),
ARM64_FLAG_VALUE(value, MDSCR_EL1, RXfull)),
color);
return row;
}
void FormatDebugRegisters(const FormatRegisterOptions& options,
const std::vector<Register>& registers,
OutputBuffer* out) {
std::vector<std::vector<OutputBuffer>> rows;
for (const Register& reg : registers) {
auto color = GetRowColor(rows.size() + 1);
switch (reg.id()) {
case RegisterID::kARMv8_dbgbcr0_el1:
case RegisterID::kARMv8_dbgbcr1_el1:
case RegisterID::kARMv8_dbgbcr2_el1:
case RegisterID::kARMv8_dbgbcr3_el1:
case RegisterID::kARMv8_dbgbcr4_el1:
case RegisterID::kARMv8_dbgbcr5_el1:
case RegisterID::kARMv8_dbgbcr6_el1:
case RegisterID::kARMv8_dbgbcr7_el1:
case RegisterID::kARMv8_dbgbcr8_el1:
case RegisterID::kARMv8_dbgbcr9_el1:
case RegisterID::kARMv8_dbgbcr10_el1:
case RegisterID::kARMv8_dbgbcr11_el1:
case RegisterID::kARMv8_dbgbcr12_el1:
case RegisterID::kARMv8_dbgbcr13_el1:
case RegisterID::kARMv8_dbgbcr14_el1:
case RegisterID::kARMv8_dbgbcr15_el1:
rows.push_back(FormatDBGBCR(reg, color));
break;
case RegisterID::kARMv8_id_aa64dfr0_el1:
rows.push_back(FormatID_AA64FR0_EL1(reg, color));
break;
case RegisterID::kARMv8_mdscr_el1:
rows.push_back(FormatMDSCR(reg, color));
break;
default:
rows.push_back(DescribeRegister(reg, color));
}
}
// Output the tables.
if (!rows.empty()) {
std::vector<ColSpec> colspecs({ColSpec(Align::kRight),
ColSpec(Align::kRight, 0, std::string(), 1),
ColSpec()});
FormatTable(colspecs, rows, out);
}
}
} // namespace
bool FormatCategoryARM64(const FormatRegisterOptions& options,
debug_ipc::RegisterCategory::Type category,
const std::vector<Register>& registers,
OutputBuffer* out, Err* err) {
switch (category) {
case RegisterCategory::Type::kGeneral:
FormatGeneralRegisters(options, registers, out);
return true;
case RegisterCategory::Type::kDebug:
FormatDebugRegisters(options, registers, out);
return true;
default:
return false;
}
return true;
}
} // namespace zxdb