blob: 10dcce5081658d26d3eb9662f95e6a27c36e2c4d [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 "src/developer/debug/debug_agent/debugged_thread.h"
#include <gtest/gtest.h>
#include "src/developer/debug/debug_agent/arch.h"
#include "src/developer/debug/debug_agent/debugged_process.h"
#include "src/developer/debug/debug_agent/mock_debug_agent_harness.h"
#include "src/developer/debug/debug_agent/mock_exception_handle.h"
#include "src/developer/debug/debug_agent/mock_process.h"
#include "src/developer/debug/debug_agent/mock_process_handle.h"
#include "src/developer/debug/debug_agent/mock_thread.h"
#include "src/developer/debug/debug_agent/mock_thread_handle.h"
#include "src/developer/debug/debug_agent/remote_api.h"
namespace debug_agent {
using namespace debug_ipc;
namespace {
TEST(DebuggedThread, Resume) {
MockDebugAgentHarness harness;
constexpr zx_koid_t kProcessKoid = 0x8723456;
MockProcess process(harness.debug_agent(), kProcessKoid);
constexpr zx_koid_t kThreadKoid = 0x8723457;
MockThread* thread = process.AddThread(kThreadKoid);
EXPECT_FALSE(thread->in_exception());
ExceptionHandle::Resolution resolution = ExceptionHandle::Resolution::kTryNext;
debug_ipc::ExceptionStrategy exception_strategy = debug_ipc::ExceptionStrategy::kNone;
auto exception = std::make_unique<MockExceptionHandle>(
[&resolution](ExceptionHandle::Resolution new_res) { resolution = new_res; },
[&exception_strategy](debug_ipc::ExceptionStrategy new_strategy) {
exception_strategy = new_strategy;
});
thread->set_exception_handle(std::move(exception));
EXPECT_TRUE(thread->in_exception());
thread->ClientResume(
debug_ipc::ResumeRequest{.how = debug_ipc::ResumeRequest::How::kResolveAndContinue});
EXPECT_FALSE(thread->in_exception());
EXPECT_EQ(resolution, ExceptionHandle::Resolution::kHandled);
EXPECT_EQ(exception_strategy, debug_ipc::ExceptionStrategy::kNone);
resolution = ExceptionHandle::Resolution::kTryNext;
exception_strategy = debug_ipc::ExceptionStrategy::kNone;
exception = std::make_unique<MockExceptionHandle>(
[&resolution](ExceptionHandle::Resolution new_res) { resolution = new_res; },
[&exception_strategy](debug_ipc::ExceptionStrategy new_strategy) {
exception_strategy = new_strategy;
});
thread->set_exception_handle(std::move(exception));
EXPECT_TRUE(thread->in_exception());
thread->ClientResume(
debug_ipc::ResumeRequest{.how = debug_ipc::ResumeRequest::How::kForwardAndContinue});
EXPECT_FALSE(thread->in_exception());
EXPECT_EQ(resolution, ExceptionHandle::Resolution::kTryNext);
EXPECT_EQ(exception_strategy, debug_ipc::ExceptionStrategy::kSecondChance);
}
TEST(DebuggedThread, OnException) {
MockDebugAgentHarness harness;
RemoteAPI* remote_api = harness.debug_agent();
constexpr zx_koid_t kProcessKoid = 0x8723456;
MockProcess process(harness.debug_agent(), kProcessKoid);
constexpr zx_koid_t kThreadKoid = 0x8723457;
MockThread* thread = process.AddThread(kThreadKoid);
EXPECT_FALSE(thread->in_exception());
// Policy: general exceptions initially handled as first-chance.
// Exception: general, first-chance.
// Expected: no applied strategy.
{
debug_ipc::ExceptionStrategy applied_strategy = debug_ipc::ExceptionStrategy::kNone;
auto exception = std::make_unique<MockExceptionHandle>(
[](ExceptionHandle::Resolution) {},
[&applied_strategy](debug_ipc::ExceptionStrategy new_strategy) {
applied_strategy = new_strategy;
});
exception->set_type(debug_ipc::ExceptionType::kGeneral);
exception->SetStrategy(debug_ipc::ExceptionStrategy::kFirstChance);
applied_strategy = debug_ipc::ExceptionStrategy::kNone; // Clear previously set.
thread->OnException(std::move(exception));
EXPECT_EQ(debug_ipc::ExceptionStrategy::kNone, applied_strategy);
}
// Policy: general exceptions initially handled as first-chance.
// Exception: general, second-chance.
// Expected: no applied strategy (as this isn't our initial handling).
{
debug_ipc::ExceptionStrategy applied_strategy = debug_ipc::ExceptionStrategy::kNone;
auto exception = std::make_unique<MockExceptionHandle>(
[](ExceptionHandle::Resolution) {},
[&applied_strategy](debug_ipc::ExceptionStrategy new_strategy) {
applied_strategy = new_strategy;
});
exception->set_type(debug_ipc::ExceptionType::kGeneral);
exception->SetStrategy(debug_ipc::ExceptionStrategy::kSecondChance);
applied_strategy = debug_ipc::ExceptionStrategy::kNone; // Clear previously set.
thread->OnException(std::move(exception));
EXPECT_EQ(debug_ipc::ExceptionStrategy::kNone, applied_strategy);
}
// Update policy so that general exceptions are handled initially as
// second-chance.
const debug_ipc::UpdateGlobalSettingsRequest request = {
.exception_strategies =
{
{
.type = debug_ipc::ExceptionType::kGeneral,
.value = debug_ipc::ExceptionStrategy::kSecondChance,
},
},
};
debug_ipc::UpdateGlobalSettingsReply reply;
remote_api->OnUpdateGlobalSettings(request, &reply);
EXPECT_EQ(ZX_OK, reply.status);
// Policy: general exceptions initially handled as second-chance.
// Exception: general, first-chance.
// Expected: applied strategy of second-chance.
{
debug_ipc::ExceptionStrategy applied_strategy = debug_ipc::ExceptionStrategy::kNone;
auto exception = std::make_unique<MockExceptionHandle>(
[](ExceptionHandle::Resolution) {},
[&applied_strategy](debug_ipc::ExceptionStrategy new_strategy) {
applied_strategy = new_strategy;
});
exception->set_type(debug_ipc::ExceptionType::kGeneral);
exception->SetStrategy(debug_ipc::ExceptionStrategy::kFirstChance);
applied_strategy = debug_ipc::ExceptionStrategy::kNone; // Clear previously set.
thread->OnException(std::move(exception));
EXPECT_EQ(debug_ipc::ExceptionStrategy::kSecondChance, applied_strategy);
// Since we didn't handle the exception, we expect it to have been closed.
EXPECT_EQ(nullptr, thread->exception_handle());
}
// Policy: general exceptions initially handled as second-chance.
// Exception: general, second-chance.
// Expected: no applied strategy.
{
debug_ipc::ExceptionStrategy applied_strategy = debug_ipc::ExceptionStrategy::kNone;
auto exception = std::make_unique<MockExceptionHandle>(
[](ExceptionHandle::Resolution) {},
[&applied_strategy](debug_ipc::ExceptionStrategy new_strategy) {
applied_strategy = new_strategy;
});
exception->set_type(debug_ipc::ExceptionType::kGeneral);
exception->SetStrategy(debug_ipc::ExceptionStrategy::kSecondChance);
applied_strategy = debug_ipc::ExceptionStrategy::kNone; // Clear previously set.
thread->OnException(std::move(exception));
EXPECT_EQ(debug_ipc::ExceptionStrategy::kNone, applied_strategy);
}
}
} // namespace
} // namespace debug_agent