blob: 622fc5e1b8b0721f21d6f8dd137c47caafcce41e [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 "garnet/bin/debug_agent/arch.h"
#include "garnet/bin/debug_agent/debugged_process.h"
#include "garnet/bin/debug_agent/debugged_thread.h"
#include "gtest/gtest.h"
namespace debug_agent {
using debug_ipc::RegisterCategory;
namespace {
class FakeArchProvider : public arch::ArchProvider {
public:
bool GetRegisters(const debug_ipc::RegisterCategory::Type& type,
const zx::thread&,
std::vector<debug_ipc::Register>* out) override {
auto it = categories_.find(type);
if (it == categories_.end())
return false;
*out = it->second.registers;
return true;
}
void AddCategory(RegisterCategory::Type type, size_t reg_count) {
auto& cat = categories_[type];
cat.type = type;
cat.registers.reserve(reg_count);
for (uint32_t i = 0; i < reg_count; i++) {
auto& reg = cat.registers.emplace_back();
reg.id = static_cast<debug_ipc::RegisterID>(i);
// No data for now.
}
}
private:
std::map<RegisterCategory::Type, RegisterCategory> categories_;
};
class ScopedFakeArchProvider {
public:
ScopedFakeArchProvider() {
auto fake_arch = std::make_unique<FakeArchProvider>();
fake_arch_ = fake_arch.get();
arch::ArchProvider::Set(std::move(fake_arch));
}
~ScopedFakeArchProvider() { arch::ArchProvider::Set(nullptr); }
FakeArchProvider* get() const { return fake_arch_; }
private:
FakeArchProvider* fake_arch_;
};
class FakeProcess : public DebuggedProcess {
public:
FakeProcess(zx_koid_t koid) : DebuggedProcess(nullptr, koid, zx::process()) {}
~FakeProcess() = default;
DebuggedThread* CreateThread(zx_koid_t tid) {
if (!thread_) {
thread_ = std::make_unique<DebuggedThread>(this, zx::thread(), 1, false);
}
return thread_.get();
}
private:
std::unique_ptr<DebuggedThread> thread_;
};
TEST(DebuggedThread, GetsRegisters) {
ScopedFakeArchProvider scoped_arch_provider;
FakeArchProvider* arch = scoped_arch_provider.get();
constexpr size_t kGeneralCount = 12u;
arch->AddCategory(RegisterCategory::Type::kGeneral, kGeneralCount);
FakeProcess fake_process(1u);
DebuggedThread* thread = fake_process.CreateThread(1u);
std::vector<RegisterCategory::Type> cats_to_get = {
RegisterCategory::Type::kGeneral};
std::vector<RegisterCategory> categories;
thread->GetRegisters(cats_to_get, &categories);
ASSERT_EQ(categories.size(), 1u);
auto& cat = categories.front();
EXPECT_EQ(cat.type, RegisterCategory::Type::kGeneral);
EXPECT_EQ(cat.registers.size(), kGeneralCount);
}
TEST(DebuggedThread, GettingErrorShouldStillReturnTheRest) {
ScopedFakeArchProvider scoped_arch_provider;
FakeArchProvider* arch = scoped_arch_provider.get();
FakeProcess fake_process(1u);
DebuggedThread* thread = fake_process.CreateThread(1u);
constexpr size_t kGeneralCount = 12u;
constexpr size_t kDebugCount = 33u;
arch->AddCategory(RegisterCategory::Type::kGeneral, kGeneralCount);
arch->AddCategory(RegisterCategory::Type::kDebug, kDebugCount);
std::vector<RegisterCategory::Type> cats_to_get = {
RegisterCategory::Type::kGeneral, RegisterCategory::Type::kVector,
RegisterCategory::Type::kDebug};
std::vector<RegisterCategory> categories;
thread->GetRegisters(cats_to_get, &categories);
ASSERT_EQ(categories.size(), 2u);
EXPECT_EQ(categories[0].type, RegisterCategory::Type::kGeneral);
EXPECT_EQ(categories[0].registers.size(), kGeneralCount);
EXPECT_EQ(categories[1].type, RegisterCategory::Type::kDebug);
EXPECT_EQ(categories[1].registers.size(), kDebugCount);
}
} // namespace
} // namespace debug_agent