blob: 0c60b3f6f84640fa6ce7bfdffcf4baf95f1a8c1c [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_TEST_DATA_HW_BREAKPOINTER_HELPERS_H_
#define SRC_DEVELOPER_DEBUG_DEBUG_AGENT_TEST_DATA_HW_BREAKPOINTER_HELPERS_H_
#include <lib/fit/defer.h>
#include <lib/zx/event.h>
#include <lib/zx/exception.h>
#include <lib/zx/port.h>
#include <lib/zx/thread.h>
#include <unistd.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/debug.h>
#include <zircon/syscalls/exception.h>
#include <zircon/threads.h>
#include <iostream>
#include <mutex>
#include <thread>
#include "src/lib/files/path.h"
#include "src/lib/fxl/logging.h"
#include "src/lib/fxl/strings/string_printf.h"
// auto base_name = files::GetBaseName(__FILE__); \
// std::cout << "[" << base_name << ":" << __LINE__ << "][t: " << std::this_thread::get_id()
#define PRINT_CLEAN(...) \
{ std::cout << fxl::StringPrintf(__VA_ARGS__) << std::endl << std::flush; }
#define PRINT(...) \
{ \
std::cout << "[" << __FILE__ << ":" << __LINE__ << "][t: " << std::this_thread::get_id() \
<< "] " << fxl::StringPrintf(__VA_ARGS__) << std::endl \
<< std::flush; \
}
#define DEFER_PRINT(...) auto __defer = fit::defer([=]() { PRINT(__VA_ARGS__); });
#define CHECK_OK(stmt) \
{ \
zx_status_t __res = (stmt); \
FXL_DCHECK(__res == ZX_OK) << zx_status_get_string(__res); \
}
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a))[0])
constexpr char kBeacon[] = "Counter: Thread running.\n";
constexpr int kPortKey = 0x2312451;
constexpr uint32_t kHarnessToThread = ZX_USER_SIGNAL_0;
constexpr uint32_t kThreadToHarness = ZX_USER_SIGNAL_1;
// Control struct for each running test case.
struct ThreadSetup {
using Function = int (*)(void*);
~ThreadSetup();
zx::event event;
zx::thread thread;
thrd_t c_thread;
std::atomic<bool> test_running = false;
void* user = nullptr;
};
std::unique_ptr<ThreadSetup> CreateTestSetup(ThreadSetup::Function func, void* user = nullptr);
std::pair<zx::port, zx::channel> CreateExceptionChannel(const zx::thread&);
zx_thread_state_general_regs_t ReadGeneralRegs(const zx::thread& thread);
void WriteGeneralRegs(const zx::thread& thread, const zx_thread_state_debug_regs_t& regs);
std::optional<zx_port_packet_t> WaitOnPort(const zx::port& port, zx_signals_t signals,
zx::time deadline = zx::time::infinite());
struct Exception {
zx::process process;
zx::thread thread;
zx::exception handle;
zx_exception_info_t info;
zx_thread_state_general_regs_t regs;
uint64_t pc = 0;
};
Exception GetException(const zx::channel& exception_channel);
std::optional<Exception> WaitForException(const zx::port& port,
const zx::channel& exception_channel,
zx::time deadline = zx::time::infinite());
void ResumeException(const zx::thread& thread, Exception&& exception, bool handled = true);
void WaitAsyncOnExceptionChannel(const zx::port& port, const zx::channel& exception_channel);
bool IsOnException(const zx::thread& thread);
// NOTE: This might return an invalid (empty) suspend_token.
// If that happens, it means that |thread| is on an exception.
zx::suspend_token Suspend(const zx::thread& thread);
void InstallHWBreakpoint(const zx::thread& thread, uint64_t address);
void RemoveHWBreakpoint(const zx::thread& thread);
// Length is how many bytes to hit.
// Must be a power of 2 (1, 2, 4, 8 bytes).
void InstallWatchpoint(const zx::thread& thread, uint64_t address, uint32_t length);
void RemoveWatchpoint(const zx::thread& thread);
#endif // SRC_DEVELOPER_DEBUG_DEBUG_AGENT_TEST_DATA_HW_BREAKPOINTER_HELPERS_H_