|  | // 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/async_dwarf_expr_eval.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/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 AsyncDwarfExprEval { | 
|  | 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(EvalCallback cb, fxl::RefPtr<Type> type, bool* destroyed) | 
|  | : AsyncDwarfExprEval(std::move(cb), std::move(type)), 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>(setup.process().GetWeakPtr(), | 
|  | data_provider, ExprLanguage::kC); | 
|  |  | 
|  | // This expression evaluates the relative address. | 
|  | std::vector<uint8_t> 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>(value_callback, uint32_type, &destroyed); | 
|  | eval->Eval(eval_context, 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 |