blob: 56821f1bfad8c7312f0d9df76d1891a1ec4032d3 [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/ipc/client_protocol.h"
#include <lib/syslog/cpp/macros.h>
#include "src/developer/debug/ipc/message_reader.h"
#include "src/developer/debug/ipc/message_writer.h"
#include "src/developer/debug/ipc/protocol_helpers.h"
namespace debug_ipc {
// Record deserializers ----------------------------------------------------------------------------
bool Deserialize(MessageReader* reader, ProcessTreeRecord* record) {
if (!reader->ReadUint32(reinterpret_cast<uint32_t*>(&record->type)))
return false;
if (!reader->ReadUint64(&record->koid))
return false;
if (!reader->ReadString(&record->name))
return false;
if (record->type == ProcessTreeRecord::Type::kJob) {
if (!reader->ReadString(&record->component_url))
return false;
if (!reader->ReadString(&record->component_moniker))
return false;
if (!Deserialize(reader, &record->children))
return false;
}
return true;
}
bool Deserialize(MessageReader* reader, ThreadRecord* record) {
if (!Deserialize(reader, &record->id))
return false;
if (!reader->ReadString(&record->name))
return false;
uint32_t state;
if (!reader->ReadUint32(&state))
return false;
if (state >= static_cast<uint32_t>(ThreadRecord::State::kLast))
return false;
record->state = static_cast<ThreadRecord::State>(state);
uint32_t blocked_reason;
if (!reader->ReadUint32(&blocked_reason))
return false;
if (state >= static_cast<uint32_t>(ThreadRecord::BlockedReason::kLast))
return false;
record->blocked_reason = static_cast<ThreadRecord::BlockedReason>(blocked_reason);
uint32_t stack_amount;
if (!reader->ReadUint32(&stack_amount))
return false;
if (stack_amount >= static_cast<uint32_t>(ThreadRecord::StackAmount::kLast))
return false;
record->stack_amount = static_cast<ThreadRecord::StackAmount>(stack_amount);
if (!Deserialize(reader, &record->frames))
return false;
return true;
}
bool Deserialize(MessageReader* reader, ProcessRecord* record) {
if (!reader->ReadUint64(&record->process_koid) || !reader->ReadString(&record->process_name)) {
return false;
}
return Deserialize(reader, &record->threads);
}
bool Deserialize(MessageReader* reader, MemoryBlock* block) {
if (!reader->ReadUint64(&block->address))
return false;
if (!reader->ReadBool(&block->valid))
return false;
if (!reader->ReadUint32(&block->size))
return false;
if (block->valid) {
if (block->size > reader->remaining())
return false;
block->data.resize(block->size);
if (!reader->ReadBytes(block->size, block->data.data()))
return false;
}
return true;
}
bool Deserialize(MessageReader* reader, Module* module) {
if (!reader->ReadString(&module->name))
return false;
if (!reader->ReadUint64(&module->base))
return false;
if (!reader->ReadUint64(&module->debug_address))
return false;
if (!reader->ReadString(&module->build_id))
return false;
return true;
}
bool Deserialize(MessageReader* reader, StackFrame* frame) {
if (!reader->ReadUint64(&frame->ip))
return false;
if (!reader->ReadUint64(&frame->sp))
return false;
if (!reader->ReadUint64(&frame->cfa))
return false;
return Deserialize(reader, &frame->regs);
}
bool Deserialize(MessageReader* reader, BreakpointStats* stats) {
if (!reader->ReadUint32(&stats->id))
return false;
if (!reader->ReadUint32(&stats->hit_count))
return false;
return reader->ReadBool(&stats->should_delete);
}
bool Deserialize(MessageReader* reader, AddressRegion* region) {
if (!reader->ReadString(&region->name))
return false;
if (!reader->ReadUint64(&region->base))
return false;
if (!reader->ReadUint64(&region->size))
return false;
if (!reader->ReadUint64(&region->depth))
return false;
return true;
}
// Record serializers ------------------------------------------------------------------------------
void Serialize(const ProcessBreakpointSettings& settings, MessageWriter* writer) {
Serialize(settings.id, writer);
writer->WriteUint64(settings.address);
Serialize(settings.address_range, writer);
}
void Serialize(const debug_ipc::AutomationOperand& operand, MessageWriter* writer) {
writer->WriteUint32(static_cast<uint32_t>(operand.kind()));
writer->WriteUint32(operand.index());
writer->WriteUint32(operand.value());
}
void Serialize(const debug_ipc::AutomationCondition& condition, MessageWriter* writer) {
writer->WriteUint32(static_cast<uint32_t>(condition.kind()));
Serialize(condition.operand(), writer);
writer->WriteUint64(condition.constant());
writer->WriteUint64(condition.mask());
}
void Serialize(const debug_ipc::AutomationInstruction& instruction, MessageWriter* writer) {
writer->WriteUint32(static_cast<uint32_t>(instruction.kind()));
Serialize(instruction.address(), writer);
Serialize(instruction.length(), writer);
Serialize(instruction.extra_1(), writer);
Serialize(instruction.extra_2(), writer);
writer->WriteUint32(instruction.value());
Serialize(instruction.conditions(), writer);
}
void Serialize(const BreakpointSettings& settings, MessageWriter* writer) {
writer->WriteUint32(settings.id);
writer->WriteUint32(static_cast<uint32_t>(settings.type));
writer->WriteString(settings.name);
writer->WriteBool(settings.one_shot);
writer->WriteUint32(static_cast<uint32_t>(settings.stop));
Serialize(settings.locations, writer);
writer->WriteBool(settings.has_automation);
Serialize(settings.instructions, writer);
}
void Serialize(const ConfigAction& action, MessageWriter* writer) {
writer->WriteUint32(static_cast<uint32_t>(action.type));
writer->WriteString(action.value);
}
// Hello -------------------------------------------------------------------------------------------
void WriteRequest(const HelloRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kHello, transaction_id);
}
bool ReadReply(MessageReader* reader, HelloReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return reader->ReadBytes(sizeof(HelloReply), reply);
}
// Status ------------------------------------------------------------------------------------------
void WriteRequest(const StatusRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kStatus, transaction_id);
}
bool ReadReply(MessageReader* reader, StatusReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!Deserialize(reader, &reply->processes))
return false;
return Deserialize(reader, &reply->limbo);
}
// ProcessStatus -----------------------------------------------------------------------------------
void WriteRequest(const ProcessStatusRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kProcessStatus, transaction_id);
writer->WriteUint64(request.process_koid);
}
bool ReadReply(MessageReader* reader, ProcessStatusReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!Deserialize(reader, &reply->status))
return false;
return true;
}
// Launch ------------------------------------------------------------------------------------------
void WriteRequest(const LaunchRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kLaunch, transaction_id);
writer->WriteUint32(static_cast<uint32_t>(request.inferior_type));
Serialize(request.argv, writer);
}
bool ReadReply(MessageReader* reader, LaunchReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!reader->ReadUint64(&reply->timestamp))
return false;
uint32_t inferior_type;
if (!reader->ReadUint32(&inferior_type) ||
inferior_type >= static_cast<uint32_t>(InferiorType::kLast)) {
return false;
}
reply->inferior_type = static_cast<InferiorType>(inferior_type);
if (!Deserialize(reader, &reply->status))
return false;
if (!reader->ReadUint64(&reply->process_id))
return false;
if (!reader->ReadUint64(&reply->component_id))
return false;
if (!reader->ReadString(&reply->process_name))
return false;
return true;
}
// Kill --------------------------------------------------------------------------------------------
void WriteRequest(const KillRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kKill, transaction_id);
writer->WriteUint64(request.process_koid);
}
bool ReadReply(MessageReader* reader, KillReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!reader->ReadUint64(&reply->timestamp))
return false;
if (!Deserialize(reader, &reply->status))
return false;
return true;
}
// Attach ------------------------------------------------------------------------------------------
void WriteRequest(const AttachRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kAttach, transaction_id);
writer->WriteUint32(static_cast<uint32_t>(request.type));
writer->WriteUint64(request.koid);
}
bool ReadReply(MessageReader* reader, AttachReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!reader->ReadUint64(&reply->timestamp))
return false;
if (!reader->ReadUint64(&reply->koid))
return false;
if (!Deserialize(reader, &reply->status))
return false;
if (!reader->ReadString(&reply->name))
return false;
return true;
}
// Detach ------------------------------------------------------------------------------------------
void WriteRequest(const DetachRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kDetach, transaction_id);
writer->WriteUint32(static_cast<uint32_t>(request.type));
writer->WriteUint64(request.koid);
}
bool ReadReply(MessageReader* reader, DetachReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!reader->ReadUint64(&reply->timestamp))
return false;
if (!Deserialize(reader, &reply->status))
return false;
return true;
}
// Pause -------------------------------------------------------------------------------------------
void WriteRequest(const PauseRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kPause, transaction_id);
Serialize(request.ids, writer);
}
bool ReadReply(MessageReader* reader, PauseReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->threads);
}
// QuitAgent ---------------------------------------------------------------------------------------
void WriteRequest(const QuitAgentRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kQuitAgent, transaction_id);
}
bool ReadReply(MessageReader* reader, QuitAgentReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return true;
}
// Resume ------------------------------------------------------------------------------------------
void WriteRequest(const ResumeRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kResume, transaction_id);
Serialize(request.ids, writer);
writer->WriteUint32(static_cast<uint32_t>(request.how));
writer->WriteUint64(request.range_begin);
writer->WriteUint64(request.range_end);
}
bool ReadReply(MessageReader* reader, ResumeReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return true;
}
// ProcessTree -------------------------------------------------------------------------------------
void WriteRequest(const ProcessTreeRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kProcessTree, transaction_id);
writer->WriteBytes(&request, sizeof(ProcessTreeRequest));
}
bool ReadReply(MessageReader* reader, ProcessTreeReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->root);
}
// Threads -----------------------------------------------------------------------------------------
void WriteRequest(const ThreadsRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kThreads, transaction_id);
writer->WriteBytes(&request, sizeof(ThreadsRequest));
}
bool ReadReply(MessageReader* reader, ThreadsReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->threads);
}
// ReadMemory --------------------------------------------------------------------------------------
void WriteRequest(const ReadMemoryRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kReadMemory, transaction_id);
writer->WriteBytes(&request, sizeof(ReadMemoryRequest));
}
bool ReadReply(MessageReader* reader, ReadMemoryReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->blocks);
}
// ReadRegisters -----------------------------------------------------------------------------------
void WriteRequest(const ReadRegistersRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kReadRegisters, transaction_id);
Serialize(request.id, writer);
Serialize(request.categories, writer);
}
bool ReadReply(MessageReader* reader, ReadRegistersReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->registers);
}
// WriteRegisters ----------------------------------------------------------------------------------
void WriteRequest(const WriteRegistersRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kWriteRegisters, transaction_id);
Serialize(request.id, writer);
Serialize(request.registers, writer);
}
bool ReadReply(MessageReader* reader, WriteRegistersReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!Deserialize(reader, &reply->status))
return false;
return Deserialize(reader, &reply->registers);
}
// AddOrChangeBreakpoint ---------------------------------------------------------------------------
void WriteRequest(const AddOrChangeBreakpointRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kAddOrChangeBreakpoint, transaction_id);
Serialize(request.breakpoint, writer);
}
bool ReadReply(MessageReader* reader, AddOrChangeBreakpointReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->status);
}
// RemoveBreakpoint --------------------------------------------------------------------------------
void WriteRequest(const RemoveBreakpointRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kRemoveBreakpoint, transaction_id);
writer->WriteBytes(&request, sizeof(RemoveBreakpointRequest));
}
bool ReadReply(MessageReader* reader, RemoveBreakpointReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return true;
}
// SysInfo -----------------------------------------------------------------------------------------
void WriteRequest(const SysInfoRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kSysInfo, transaction_id);
}
bool ReadReply(MessageReader* reader, SysInfoReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!reader->ReadString(&reply->version) || !reader->ReadUint32(&reply->num_cpus) ||
!reader->ReadUint32(&reply->memory_mb) || !reader->ReadUint32(&reply->hw_breakpoint_count) ||
!reader->ReadUint32(&reply->hw_watchpoint_count)) {
return false;
}
return true;
}
// ThreadStatus ------------------------------------------------------------------------------------
void WriteRequest(const ThreadStatusRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kThreadStatus, transaction_id);
writer->WriteBytes(&request, sizeof(ThreadStatusRequest));
}
bool ReadReply(MessageReader* reader, ThreadStatusReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
Deserialize(reader, &reply->record);
return true;
}
// Modules -----------------------------------------------------------------------------------------
void WriteRequest(const ModulesRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kModules, transaction_id);
writer->WriteBytes(&request, sizeof(ModulesRequest));
}
bool ReadReply(MessageReader* reader, ModulesReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
Deserialize(reader, &reply->modules);
return true;
}
// Address Space -----------------------------------------------------------------------------------
void WriteRequest(const AddressSpaceRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kAddressSpace, transaction_id);
writer->WriteBytes(&request, sizeof(AddressSpaceRequest));
}
bool ReadReply(MessageReader* reader, AddressSpaceReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->map);
}
// JobFilter --------------------------------------------------------------------------------------
void WriteRequest(const JobFilterRequest& request, uint32_t transaction_id, MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kJobFilter, transaction_id);
writer->WriteUint64(request.job_koid);
return Serialize(request.filters, writer);
}
bool ReadReply(MessageReader* reader, JobFilterReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!Deserialize(reader, &reply->status))
return false;
return Deserialize(reader, &reply->matched_processes);
}
// WriteMemory -------------------------------------------------------------------------------------
void WriteRequest(const WriteMemoryRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kWriteMemory, transaction_id);
writer->WriteUint64(request.process_koid);
writer->WriteUint64(request.address);
return Serialize(request.data, writer);
}
bool ReadReply(MessageReader* reader, WriteMemoryReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->status);
}
// LoadInfoHandleTable -----------------------------------------------------------------------------
void WriteRequest(const LoadInfoHandleTableRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kLoadInfoHandleTable, transaction_id);
writer->WriteBytes(&request, sizeof(LoadInfoHandleTableRequest));
}
bool ReadReply(MessageReader* reader, LoadInfoHandleTableReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
if (!Deserialize(reader, &reply->status))
return false;
return Deserialize(reader, &reply->handles);
}
// UpdateGlobalSettings ---------------------------------------------------------------------------
void WriteRequest(const UpdateGlobalSettingsRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kUpdateGlobalSettings, transaction_id);
Serialize(request.exception_strategies, writer);
}
bool ReadReply(MessageReader* reader, UpdateGlobalSettingsReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->status);
}
// ConfigAgent -------------------------------------------------------------------------------------
void WriteRequest(const ConfigAgentRequest& request, uint32_t transaction_id,
MessageWriter* writer) {
writer->WriteHeader(MsgHeader::Type::kConfigAgent, transaction_id);
Serialize(request.actions, writer);
}
bool ReadReply(MessageReader* reader, ConfigAgentReply* reply, uint32_t* transaction_id) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
*transaction_id = header.transaction_id;
return Deserialize(reader, &reply->results);
}
// Notifications -----------------------------------------------------------------------------------
bool ReadNotifyProcessExiting(MessageReader* reader, NotifyProcessExiting* process) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&process->timestamp))
return false;
if (!reader->ReadUint64(&process->process_koid))
return false;
if (!reader->ReadInt64(&process->return_code))
return false;
return true;
}
bool ReadNotifyProcessStarting(MessageReader* reader, NotifyProcessStarting* process) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&process->timestamp))
return false;
uint32_t type = UINT32_MAX;
if (!reader->ReadUint32(&type) ||
type >= static_cast<uint32_t>(NotifyProcessStarting::Type::kLast)) {
return false;
}
process->type = static_cast<NotifyProcessStarting::Type>(type);
if (!reader->ReadUint64(&process->koid))
return false;
if (!reader->ReadUint32(&process->component_id))
return false;
if (!reader->ReadString(&process->name))
return false;
return true;
}
bool ReadNotifyThread(MessageReader* reader, NotifyThread* notify) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&notify->timestamp))
return false;
return Deserialize(reader, &notify->record);
}
bool ReadNotifyException(MessageReader* reader, NotifyException* notify) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&notify->timestamp))
return false;
if (!Deserialize(reader, &notify->thread))
return false;
if (!Deserialize(reader, &notify->type))
return false;
if (!reader->ReadBytes(sizeof(notify->exception), &notify->exception))
return false;
if (!Deserialize(reader, &notify->hit_breakpoints))
return false;
if (!Deserialize(reader, &notify->other_affected_threads))
return false;
return Deserialize(reader, &notify->memory_blocks);
}
bool ReadNotifyModules(MessageReader* reader, NotifyModules* notify) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&notify->timestamp))
return false;
if (!reader->ReadUint64(&notify->process_koid))
return false;
if (!Deserialize(reader, &notify->modules))
return false;
return Deserialize(reader, &notify->stopped_threads);
}
bool ReadNotifyIO(MessageReader* reader, NotifyIO* notify) {
MsgHeader header;
if (!reader->ReadHeader(&header))
return false;
if (!reader->ReadUint64(&notify->timestamp))
return false;
if (!reader->ReadUint64(&notify->process_koid))
return false;
uint32_t type;
if (!reader->ReadUint32(&type) || type >= static_cast<uint32_t>(NotifyIO::Type::kLast)) {
return false;
}
notify->type = static_cast<NotifyIO::Type>(type);
if (!reader->ReadString(&notify->data) || !reader->ReadBool(&notify->more_data_available)) {
return false;
}
return true;
}
} // namespace debug_ipc