blob: 7cdc269d89d682f3904d940a0ba1592514e2c861 [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.
#include "src/developer/debug/zxdb/expr/eval_dwarf_expr.h"
#include <gtest/gtest.h>
#include "llvm/BinaryFormat/Dwarf.h"
#include "src/developer/debug/zxdb/common/test_with_loop.h"
#include "src/developer/debug/zxdb/expr/abi_null.h"
#include "src/developer/debug/zxdb/expr/eval_context_impl.h"
#include "src/developer/debug/zxdb/symbols/mock_symbol_data_provider.h"
#include "src/developer/debug/zxdb/symbols/process_symbols_test_setup.h"
#include "src/developer/debug/zxdb/symbols/type_test_support.h"
// This file currently contains some simpler smoketest for the AsyncDwarfExprEval. Most of the
// more complex symbol integration cases are tested by the EvalContextImpl tests which provides most
// of the frontend.
namespace zxdb {
namespace {
class AsyncDwarfExprEvalTest : public TestWithLoop {};
// Provides a way for us to know when the object was deleted.
class TrackedAsyncDwarfExprEval : public AsyncDwarfExprEvalValue {
public:
FRIEND_REF_COUNTED_THREAD_SAFE(TrackedAsyncDwarfExprEval);
FRIEND_MAKE_REF_COUNTED(TrackedAsyncDwarfExprEval);
// Sets the given boolean in the destructor. The pointer must outlive this class.
explicit TrackedAsyncDwarfExprEval(const fxl::RefPtr<EvalContext>& context,
fxl::RefPtr<Type> type, EvalCallback cb, bool* destroyed)
: AsyncDwarfExprEvalValue(std::move(context), std::move(type), std::move(cb)),
destroyed_(destroyed) {}
~TrackedAsyncDwarfExprEval() override { *destroyed_ = true; }
bool* destroyed_;
};
} // namespace
// The memory management of this class is tricky since it keeps itself alive for as long as the
// expression needs evaluating and potentially the pointer value to be fetched. This test validates
// that the object is deleted at the right time.
TEST_F(AsyncDwarfExprEvalTest, MemoryManagement) {
ProcessSymbolsTestSetup setup;
setup.InjectMockModule();
SymbolContext symbol_context(ProcessSymbolsTestSetup::kDefaultLoadAddress);
// The data provider will vend the memory at the address we'll compute.
auto data_provider = fxl::MakeRefCounted<MockSymbolDataProvider>();
constexpr uint8_t kRelativeAddress = 0x99;
constexpr uint64_t kAbsoluteAddress =
ProcessSymbolsTestSetup::kDefaultLoadAddress + kRelativeAddress;
// The thing the expression points to.
auto uint32_type = MakeInt32Type();
constexpr uint32_t kMemoryValue = 0x12345678;
data_provider->AddMemory(kAbsoluteAddress, {0x78, 0x56, 0x34, 0x12});
auto eval_context = fxl::MakeRefCounted<EvalContextImpl>(
std::make_shared<AbiNull>(), setup.process().GetWeakPtr(), data_provider, ExprLanguage::kC);
// This expression evaluates the relative address.
DwarfExpr expr({llvm::dwarf::DW_OP_addr, kRelativeAddress, 0, 0, 0, 0, 0, 0, 0});
bool called = false;
auto value_callback = [&called, kMemoryValue](ErrOrValue value) {
called = true;
EXPECT_TRUE(value.ok());
EXPECT_EQ(kMemoryValue, value.value().GetAs<uint32_t>());
};
bool destroyed = false;
auto eval = fxl::MakeRefCounted<TrackedAsyncDwarfExprEval>(eval_context, uint32_type,
value_callback, &destroyed);
eval->Eval(eval_context->GetDataProvider(), symbol_context, expr);
// Should evaluate asynchronously.
EXPECT_FALSE(called);
// Now that evaluation has started, we can release our reference and it should not be destroyed.
eval = nullptr;
ASSERT_FALSE(destroyed);
loop().RunUntilNoTasks();
// Async running should allow the result to be computed and the evaluator to be destroyed.
EXPECT_TRUE(called);
EXPECT_TRUE(destroyed);
}
} // namespace zxdb