blob: f7ac5c90c4296e5c5aea387623d6c625cee66684 [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_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_ARM64_HELPERS_UNITTEST_H_
#define SRC_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_ARM64_HELPERS_UNITTEST_H_
#include <stdint.h>
#include <zircon/hw/debug/arm64.h>
#include <zircon/status.h>
#include <zircon/syscalls/debug.h>
#include <gtest/gtest.h>
#include "src/developer/debug/debug_agent/arch_arm64_helpers.h"
namespace debug_agent {
namespace arch {
constexpr uint32_t kWatchpointCount = 4;
inline bool ResultVerification(zx_thread_state_debug_regs_t* regs, uint64_t address, uint64_t size,
debug_ipc::BreakpointType type,
WatchpointInstallationResult expected) {
WatchpointInstallationResult result =
SetupWatchpoint(regs, type, {address, address + size}, kWatchpointCount);
if (result.status != expected.status) {
ADD_FAILURE() << "Status failed. Expected: " << zx_status_get_string(expected.status)
<< ", got: " << zx_status_get_string(result.status);
return false;
}
if (result.installed_range != expected.installed_range) {
ADD_FAILURE() << "Range failed. Expected: " << expected.installed_range.ToString()
<< ", got: " << result.installed_range.ToString();
return false;
}
if (result.slot != expected.slot) {
ADD_FAILURE() << "Slot failed. Expected: " << expected.slot << ", got: " << result.slot;
return false;
}
return true;
}
inline bool Check(zx_thread_state_debug_regs_t* regs, uint64_t address, uint64_t size,
debug_ipc::BreakpointType type, WatchpointInstallationResult expected,
uint32_t expected_bas = 0) {
if (!ResultVerification(regs, address, size, type, expected))
return false;
// If no installation was made, we don't compare against BAS.
if (expected.slot == -1)
return true;
uint32_t bas = ARM64_DBGWCR_BAS_GET(regs->hw_wps[expected.slot].dbgwcr);
if (bas != expected_bas) {
ADD_FAILURE() << "BAS check failed. Expected: 0x" << std::hex << expected_bas << ", got: 0x"
<< bas;
return false;
}
return true;
}
inline bool ResetCheck(zx_thread_state_debug_regs_t* regs, uint64_t address, uint64_t size,
debug_ipc::BreakpointType type, WatchpointInstallationResult expected,
uint32_t expected_bas = 0) {
// Restart the registers.
*regs = {};
return Check(regs, address, size, type, expected, expected_bas);
}
inline bool CheckAddresses(const zx_thread_state_debug_regs_t& regs,
std::vector<uint64_t> addresses) {
for (uint32_t i = 0; i < addresses.size(); i++) {
if (regs.hw_wps[i].dbgwvr != addresses[i]) {
ADD_FAILURE() << "Reg " << i << " mismatch. Expected: 0x" << std::hex << addresses[i]
<< ", got: " << regs.hw_wps[i].dbgwvr;
return false;
}
}
return true;
}
inline uint32_t CountBASBits(uint32_t bas) {
switch (bas) {
case 0b0000000:
return 0;
case 0b00000001:
case 0b00000010:
case 0b00000100:
case 0b00001000:
case 0b00010000:
case 0b00100000:
case 0b01000000:
case 0b10000000:
return 1;
case 0b00000011:
case 0b00001100:
case 0b00110000:
case 0b11000000:
return 2;
case 0b00001111:
case 0b11110000:
return 4;
case 0b11111111:
return 8;
default:
FXL_NOTREACHED() << "Invalid bas: 0x" << std::hex << bas;
return 0;
}
}
inline bool CheckLengths(const zx_thread_state_debug_regs_t& regs, std::vector<uint32_t> lengths) {
for (uint32_t i = 0; i < lengths.size(); i++) {
uint32_t bas = ARM64_DBGWCR_BAS_GET(regs.hw_wps[i].dbgwcr);
uint32_t length = CountBASBits(bas);
if (length != lengths[i]) {
ADD_FAILURE() << "Reg " << i << " wrong length. Expected " << lengths[i]
<< ", got: " << length;
return false;
}
}
return true;
}
inline bool CheckEnabled(const zx_thread_state_debug_regs& regs, std::vector<uint32_t> enabled) {
for (uint32_t i = 0; i < enabled.size(); i++) {
uint32_t e = ARM64_DBGWCR_E_GET(regs.hw_wps[i].dbgwcr);
if (e != enabled[i]) {
ADD_FAILURE() << "Reg " << i << " wrong enable. Expected: " << enabled[i] << ", got: " << e;
return false;
}
}
return true;
}
constexpr uint32_t kRead = 0b01;
constexpr uint32_t kWrite = 0b10;
constexpr uint32_t kReadWrite = 0b11;
inline bool CheckTypes(const zx_thread_state_debug_regs& regs, std::vector<uint32_t> types) {
for (uint32_t i = 0; i < types.size(); i++) {
uint32_t type = ARM64_DBGWCR_LSC_GET(regs.hw_wps[i].dbgwcr);
if (type != types[i]) {
ADD_FAILURE() << "Reg " << i << " wrong type. Expected: " << types[i] << ", got: " << type;
return false;
}
}
return true;
}
} // namespace arch
} // namespace debug_agent
#endif // SRC_DEVELOPER_DEBUG_DEBUG_AGENT_ARCH_ARM64_HELPERS_UNITTEST_H_