blob: 5bc94f832bff82fc690c54bc34bce1d50ec8c969 [file] [log] [blame]
// Copyright 2020 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/mock_process_handle.h"
#include <string.h>
#include "src/developer/debug/ipc/records.h"
namespace debug_agent {
zx::process MockProcessHandle::null_handle_;
MockProcessHandle::MockProcessHandle(zx_koid_t process_koid, std::string name)
: process_koid_(process_koid), name_(std::move(name)) {
// Tests could accidentally write to this handle since it's returned as a mutable value in some
// cases. Catch accidents like that.
FX_DCHECK(!null_handle_);
}
std::vector<std::unique_ptr<ThreadHandle>> MockProcessHandle::GetChildThreads() const {
// Need to return a unique set of objects every time so make copies.
std::vector<std::unique_ptr<ThreadHandle>> result;
for (auto& thread : threads_)
result.push_back(std::make_unique<MockThreadHandle>(thread));
return result;
}
debug::Status MockProcessHandle::Kill() { return kill_status_; }
int64_t MockProcessHandle::GetReturnCode() const { return 0; }
debug::Status MockProcessHandle::Attach(ProcessHandleObserver* observer) {
is_attached_ = true;
return debug::Status();
}
void MockProcessHandle::Detach() { is_attached_ = false; }
uint64_t MockProcessHandle::GetLoaderBreakpointAddress() {
// Not currently implemented in this mock.
return 0;
}
std::vector<debug_ipc::AddressRegion> MockProcessHandle::GetAddressSpace(uint64_t address) const {
// Not currently implemented in this mock.
return {};
}
std::vector<debug_ipc::Module> MockProcessHandle::GetModules() const {
// Not currently implemented in this mock.
return {};
}
fitx::result<debug::Status, std::vector<debug_ipc::InfoHandle>> MockProcessHandle::GetHandles()
const {
// Not currently implemented in this mock.
return fitx::success(std::vector<debug_ipc::InfoHandle>());
}
debug::Status MockProcessHandle::ReadMemory(uintptr_t address, void* buffer, size_t len,
size_t* actual) const {
auto vect = mock_memory_.ReadMemory(address, len);
if (!vect.empty())
memcpy(buffer, vect.data(), vect.size());
*actual = vect.size();
return debug::Status();
}
debug::Status MockProcessHandle::WriteMemory(uintptr_t address, const void* buffer, size_t len,
size_t* actual) {
// This updates the underlying memory object to account for the change. Otherwise some tests
// become much more complex because they have to manually manage the memory expected by the
// code under test.
//
// The MockMemory object isn't necessarily designed for this and there will be some limitations.
// Calling AddMemory adds that span to the mapped memory, but does not necessarily combine it with
// other spans. If a larger region of memory is requested, the results may be invalid, but if the
// same sized block is always read and written, it will be fine. Since our main test use is for
// writing breakpoints which always use fixed sizes, this works fine for now. If this limitation
// is a problem, we should enhance MockMemory.
const uint8_t* src = static_cast<const uint8_t*>(buffer);
mock_memory_.AddMemory(address, std::vector<uint8_t>(src, src + len));
memory_writes_.emplace_back(address, std::vector<uint8_t>(src, &src[len]));
return debug::Status();
}
std::vector<debug_ipc::MemoryBlock> MockProcessHandle::ReadMemoryBlocks(uint64_t address,
uint32_t size) const {
auto mem_vect = mock_memory_.ReadMemory(address, size);
debug_ipc::MemoryBlock mem_block;
mem_block.data = std::move(mem_vect);
mem_block.size = size;
mem_block.valid = true;
mem_block.address = address;
std::vector<debug_ipc::MemoryBlock> mem_blocks;
mem_blocks.emplace_back(std::move(mem_block));
return mem_blocks;
}
} // namespace debug_agent