blob: 87f239ab5ceea2ef75435a0a5f53f58d5e0ad8ae [file] [log] [blame]
// Copyright 2022 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/console/commands/verb_stack_usage.h"
#include <gtest/gtest.h>
#include "src/developer/debug/zxdb/client/mock_frame.h"
#include "src/developer/debug/zxdb/client/session.h"
#include "src/developer/debug/zxdb/console/console_test.h"
namespace zxdb {
namespace {
class VerbStackUsage : public ConsoleTest {};
} // namespace
TEST_F(VerbStackUsage, GetThreadStackUsage) {
const uint64_t kPageSize = session().arch_info().page_size();
const uint64_t kStackBase = 0x100000; // HIGH address of stack region.
const uint64_t kStackSizeInPages = 20;
const uint64_t kStackSize = kStackSizeInPages * kPageSize;
// This test expects the page size to be larger than the used bytes for the below computations.
const uint64_t kUsedBytes = 0x5e;
ASSERT_GE(kPageSize, kUsedBytes);
const uint64_t kStackPointer = kStackBase - kUsedBytes;
// Same values for the unsafe stack.
const uint64_t kUnsafeStackBase = 0x9000000;
const uint64_t kUnsafeStackSizeInPages = 20;
const uint64_t kUnsafeStackSize = kUnsafeStackSizeInPages * kPageSize;
const uint64_t kUnsafeUsedBytes = 0x103;
ASSERT_GE(kPageSize, kUnsafeUsedBytes);
const uint64_t kUnsafeStackPointer = kUnsafeStackBase - kUnsafeUsedBytes;
// Set up the thread to be stopped with the given stack pointer.
std::vector<std::unique_ptr<Frame>> frames;
Location location(Location::State::kSymbolized, 0x1000);
frames.push_back(std::make_unique<MockFrame>(&session(), thread(), location, kStackPointer));
InjectExceptionWithStack(ConsoleTest::kProcessKoid, ConsoleTest::kThreadKoid,
debug_ipc::ExceptionType::kSingleStep, std::move(frames), true);
std::vector<debug_ipc::AddressRegion> aspace;
debug_ipc::AddressRegion& containing_region = aspace.emplace_back();
containing_region.base = 0;
containing_region.size = 0x100000000000ull;
containing_region.depth = 0;
debug_ipc::AddressRegion& other_region = aspace.emplace_back();
other_region.base = 0x1000;
other_region.size = 0x1000;
other_region.depth = 1;
other_region.vmo_koid = 1234;
// Safe stack region.
debug_ipc::AddressRegion& stack_region = aspace.emplace_back();
stack_region.base = kStackBase - kStackSize;
stack_region.size = kStackSize;
stack_region.depth = 1;
stack_region.vmo_koid = 45678;
const uint64_t kCommittedBytes = 3 * kPageSize;
stack_region.committed_bytes = kCommittedBytes;
// Unused region.
debug_ipc::AddressRegion& other_region2 = aspace.emplace_back();
other_region2.base = kStackBase + 0x1000;
other_region2.size = 0x1000;
other_region2.depth = 1;
other_region2.vmo_koid = 99990;
// Unsafe stack region.
debug_ipc::AddressRegion& unsafe_region = aspace.emplace_back();
unsafe_region.base = kUnsafeStackBase - kUnsafeStackSize;
unsafe_region.size = kUnsafeStackSize;
unsafe_region.depth = 1;
unsafe_region.vmo_koid = 64291;
const uint64_t kUnsafeCommittedBytes = 5 * kPageSize;
unsafe_region.committed_bytes = kUnsafeCommittedBytes;
// Good query.
ThreadStackUsage usage =
GetThreadStackUsage(&console().context(), aspace, thread(), kUnsafeStackPointer);
ASSERT_TRUE(usage.safe_stack.ok());
EXPECT_EQ(usage.safe_stack.value().total, kStackSize);
EXPECT_EQ(usage.safe_stack.value().used, kUsedBytes);
EXPECT_EQ(usage.safe_stack.value().committed, kCommittedBytes);
EXPECT_EQ(usage.safe_stack.value().wasted, kCommittedBytes - kUsedBytes);
ASSERT_TRUE(usage.unsafe_stack.ok());
EXPECT_EQ(usage.unsafe_stack.value().total, kUnsafeStackSize);
EXPECT_EQ(usage.unsafe_stack.value().used, kUnsafeUsedBytes);
EXPECT_EQ(usage.unsafe_stack.value().committed, kUnsafeCommittedBytes);
EXPECT_EQ(usage.unsafe_stack.value().wasted, kUnsafeCommittedBytes - kUnsafeUsedBytes);
}
} // namespace zxdb