blob: ad623101fb2b5de95fce6aaf3de90e101da0bb2b [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 <utility>
#include <vector>
#include "garnet/bin/debug_agent/breakpoint.h"
#include "gtest/gtest.h"
namespace debug_agent {
using CallPair = std::pair<zx_koid_t, uint64_t>;
using CallVector = std::vector<CallPair>;
class TestProcessDelegate : public Breakpoint::ProcessDelegate {
public:
const CallVector& register_calls() const { return register_calls_; }
const CallVector& unregister_calls() const { return unregister_calls_; }
void Clear() {
register_calls_.clear();
unregister_calls_.clear();
}
zx_status_t RegisterBreakpoint(Breakpoint*, zx_koid_t process_koid,
uint64_t address) override {
register_calls_.push_back(std::make_pair(process_koid, address));
return ZX_OK;
}
void UnregisterBreakpoint(Breakpoint*, zx_koid_t process_koid,
uint64_t address) override {
unregister_calls_.push_back(std::make_pair(process_koid, address));
}
private:
CallVector register_calls_;
CallVector unregister_calls_;
};
TEST(Breakpoint, Registration) {
TestProcessDelegate delegate;
Breakpoint bp(&delegate);
debug_ipc::BreakpointSettings settings;
settings.breakpoint_id = 1;
settings.locations.resize(1);
constexpr zx_koid_t kProcess1 = 1;
constexpr uint64_t kAddress1 = 0x1234;
debug_ipc::ProcessBreakpointSettings& pr_settings = settings.locations.back();
pr_settings.process_koid = kProcess1;
pr_settings.thread_koid = 0;
pr_settings.address = kAddress1;
// Apply the settings.
ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
delegate.register_calls());
EXPECT_TRUE(delegate.unregister_calls().empty());
delegate.Clear();
// Change the settings to move the breakpoint.
constexpr zx_koid_t kProcess2 = 2;
constexpr uint64_t kAddress2 = 0x5678;
pr_settings.process_koid = kProcess2;
pr_settings.thread_koid = 0;
pr_settings.address = kAddress2;
ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
EXPECT_EQ(CallVector({CallPair{kProcess2, kAddress2}}),
delegate.register_calls());
EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
delegate.unregister_calls());
// Add a new location
delegate.Clear();
// Add the old breakpoint and a new one
debug_ipc::ProcessBreakpointSettings old_pr_settings;
old_pr_settings.process_koid = kProcess1;
old_pr_settings.thread_koid = 0;
old_pr_settings.address = kAddress1;
constexpr zx_koid_t kProcess3 = 3;
constexpr uint64_t kAddress3 = 0x9ABC;
debug_ipc::ProcessBreakpointSettings new_pr_settings;
new_pr_settings.process_koid = kProcess3;
new_pr_settings.thread_koid = 0;
new_pr_settings.address = kAddress3;
settings.locations.clear();
settings.locations.push_back(old_pr_settings);
settings.locations.push_back(new_pr_settings);
ASSERT_EQ(ZX_OK, bp.SetSettings(settings));
EXPECT_EQ(CallVector({{kProcess1, kAddress1}, {kProcess3, kAddress3}}),
delegate.register_calls());
EXPECT_EQ(CallVector({{kProcess2, kAddress2}}), delegate.unregister_calls());
}
// The destructor should clear breakpoint locations.
TEST(Breakpoint, Destructor) {
TestProcessDelegate delegate;
std::unique_ptr<Breakpoint> bp = std::make_unique<Breakpoint>(&delegate);
debug_ipc::BreakpointSettings settings;
settings.breakpoint_id = 1;
settings.locations.resize(1);
constexpr zx_koid_t kProcess1 = 1;
constexpr uint64_t kAddress1 = 0x1234;
debug_ipc::ProcessBreakpointSettings& pr_settings = settings.locations.back();
pr_settings.process_koid = kProcess1;
pr_settings.thread_koid = 0;
pr_settings.address = kAddress1;
// Apply the settings.
ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
delegate.register_calls());
EXPECT_TRUE(delegate.unregister_calls().empty());
delegate.Clear();
// Delete the breakpoint to make sure the locations get updated.
delegate.Clear();
bp.reset();
EXPECT_EQ(CallVector({CallPair{kProcess1, kAddress1}}),
delegate.unregister_calls());
}
TEST(Breakpoint, HitCount) {
TestProcessDelegate delegate;
std::unique_ptr<Breakpoint> bp = std::make_unique<Breakpoint>(&delegate);
constexpr uint32_t kBreakpointId = 12;
debug_ipc::BreakpointSettings settings;
settings.breakpoint_id = kBreakpointId;
settings.locations.resize(1);
constexpr zx_koid_t kProcess1 = 1;
constexpr uint64_t kAddress1 = 0x1234;
debug_ipc::ProcessBreakpointSettings& pr_settings = settings.locations.back();
pr_settings.process_koid = kProcess1;
pr_settings.thread_koid = 0;
pr_settings.address = kAddress1;
// Apply the settings.
ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
delegate.Clear();
EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
EXPECT_EQ(0u, bp->stats().hit_count);
EXPECT_EQ(Breakpoint::HitResult::kHit, bp->OnHit());
EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
EXPECT_EQ(1u, bp->stats().hit_count);
EXPECT_FALSE(bp->stats().should_delete);
EXPECT_EQ(Breakpoint::HitResult::kHit, bp->OnHit());
EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
EXPECT_EQ(2u, bp->stats().hit_count);
EXPECT_FALSE(bp->stats().should_delete);
}
TEST(Breakpoint, OneShot) {
TestProcessDelegate delegate;
std::unique_ptr<Breakpoint> bp = std::make_unique<Breakpoint>(&delegate);
constexpr uint32_t kBreakpointId = 12;
debug_ipc::BreakpointSettings settings;
settings.breakpoint_id = kBreakpointId;
settings.one_shot = true;
settings.locations.resize(1);
constexpr zx_koid_t kProcess = 1;
constexpr uint64_t kAddress = 0x1234;
debug_ipc::ProcessBreakpointSettings& pr_settings = settings.locations.back();
pr_settings.process_koid = kProcess;
pr_settings.thread_koid = 0;
pr_settings.address = kAddress;
// Apply the settings.
ASSERT_EQ(ZX_OK, bp->SetSettings(settings));
delegate.Clear();
EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
EXPECT_EQ(0u, bp->stats().hit_count);
EXPECT_FALSE(bp->stats().should_delete);
// The hit count and "should delete" flag should be set.
EXPECT_EQ(Breakpoint::HitResult::kOneShotHit, bp->OnHit());
EXPECT_EQ(kBreakpointId, bp->stats().breakpoint_id);
EXPECT_EQ(1u, bp->stats().hit_count);
EXPECT_TRUE(bp->stats().should_delete);
}
} // namespace debug_agent