blob: e7317757146b56f2dff00ea4ccdd6f694584907a [file] [log] [blame]
// Copyright 2021 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/automation_instruction_executor.h"
namespace debug_agent {
std::vector<debug_ipc::MemoryBlock> AutomationInstructionExecutor::ExecuteInstructionVect(
const std::vector<debug_ipc::AutomationInstruction>& instructions, const GeneralRegisters& regs,
const ProcessHandle& handle) {
std::vector<debug_ipc::MemoryBlock> out_block_vect;
for (auto instr : instructions) {
if (EvalConditionVect(instr.conditions(), regs, handle)) {
switch (instr.kind()) {
case debug_ipc::AutomationInstructionKind::kNop:
break;
case debug_ipc::AutomationInstructionKind::kLoadMemory: {
std::vector<debug_ipc::MemoryBlock> temp_block_vect =
handle.ReadMemoryBlocks(EvalOperand(instr.address(), regs, handle),
EvalOperand(instr.length(), regs, handle));
out_block_vect.insert(out_block_vect.begin(), temp_block_vect.begin(),
temp_block_vect.end());
break;
}
case debug_ipc::AutomationInstructionKind::kLoopLoadMemory: {
std::vector<debug_ipc::MemoryBlock> temp_block_vect =
ExecuteLoopLoadMemory(instr, regs, handle);
out_block_vect.insert(out_block_vect.begin(), temp_block_vect.begin(),
temp_block_vect.end());
break;
}
case debug_ipc::AutomationInstructionKind::kComputeAndStore:
stored_values_.emplace(instr.slot_index(),
EvalOperand(instr.store_value(), regs, handle));
break;
case debug_ipc::AutomationInstructionKind::kClearStoredValues:
stored_values_.clear();
break;
}
}
}
return out_block_vect;
}
std::vector<debug_ipc::MemoryBlock> AutomationInstructionExecutor::ExecuteLoopLoadMemory(
const debug_ipc::AutomationInstruction& instr, const GeneralRegisters& regs,
const ProcessHandle& handle) {
std::vector<debug_ipc::MemoryBlock> out_block_vect;
uint64_t address_val = EvalOperand(instr.address(), regs, handle);
uint64_t length_val = EvalOperand(instr.length(), regs, handle);
std::vector<debug_ipc::MemoryBlock> struct_array_vect =
handle.ReadMemoryBlocks(address_val, length_val * instr.item_size());
if (!struct_array_vect[0].valid) {
return out_block_vect;
}
for (uint32_t i = 0; i < length_val; i++) {
uint64_t cur_struct_base = instr.item_size() * i;
uint64_t address_from_struct = EvalOperand(instr.struct_pointer_offset(), regs, handle,
struct_array_vect[0], cur_struct_base);
uint64_t length_from_struct = EvalOperand(instr.struct_length_offset(), regs, handle,
struct_array_vect[0], cur_struct_base);
std::vector<debug_ipc::MemoryBlock> inner_block_vect =
handle.ReadMemoryBlocks(address_from_struct, length_from_struct);
out_block_vect.insert(out_block_vect.begin(), inner_block_vect.begin(), inner_block_vect.end());
}
out_block_vect.insert(out_block_vect.begin(), struct_array_vect.begin(), struct_array_vect.end());
return out_block_vect;
}
bool AutomationInstructionExecutor::EvalConditionVect(
const std::vector<debug_ipc::AutomationCondition>& conditions, const GeneralRegisters& regs,
const ProcessHandle& handle) {
for (auto condition : conditions) {
if (!EvalCondition(condition, regs, handle)) {
return false;
}
}
return true;
}
bool AutomationInstructionExecutor::EvalCondition(const debug_ipc::AutomationCondition& condition,
const GeneralRegisters& regs,
const ProcessHandle& handle) {
switch (condition.kind()) {
case debug_ipc::AutomationConditionKind::kFalse:
return false;
case debug_ipc::AutomationConditionKind::kEquals:
return EvalOperand(condition.operand(), regs, handle) == condition.constant();
case debug_ipc::AutomationConditionKind::kNotEquals:
return EvalOperand(condition.operand(), regs, handle) != condition.constant();
case debug_ipc::AutomationConditionKind::kMaskAndEquals:
return (EvalOperand(condition.operand(), regs, handle) & condition.mask()) ==
condition.constant();
case debug_ipc::AutomationConditionKind::kMaskAndNotEquals:
return (EvalOperand(condition.operand(), regs, handle) & condition.mask()) !=
condition.constant();
}
}
uint64_t AutomationInstructionExecutor::EvalOperand(const debug_ipc::AutomationOperand& operand,
const GeneralRegisters& regs,
const ProcessHandle& handle) {
switch (operand.kind()) {
case debug_ipc::AutomationOperandKind::kZero:
return 0;
case debug_ipc::AutomationOperandKind::kRegister:
return regs.GetRegister(operand.register_index()).value_or(0);
case debug_ipc::AutomationOperandKind::kConstant:
return operand.value();
case debug_ipc::AutomationOperandKind::kStackSlot: {
uint64_t result = 0;
size_t result_size;
handle.ReadMemory(regs.sp() + operand.slot_offset(), &result, sizeof(result), &result_size);
if (result_size == sizeof(result))
return result;
return 0;
}
case debug_ipc::AutomationOperandKind::kRegisterTimesConstant:
return regs.GetRegister(operand.register_index()).value_or(0) * operand.value();
case debug_ipc::AutomationOperandKind::kIndirectUInt32: {
uint32_t result = 0;
size_t result_size;
handle.ReadMemory(regs.GetRegister(operand.register_index()).value_or(0) + operand.offset(),
&result, sizeof(result), &result_size);
if (result_size == sizeof(result))
return result;
return 0;
}
case debug_ipc::AutomationOperandKind::kIndirectUInt64: {
uint64_t result = 0;
size_t result_size;
handle.ReadMemory(regs.GetRegister(operand.register_index()).value_or(0) + operand.offset(),
&result, sizeof(result), &result_size);
if (result_size == sizeof(result))
return result;
return 0;
}
case debug_ipc::AutomationOperandKind::kIndirectUInt32Loop:
return 0;
case debug_ipc::AutomationOperandKind::kIndirectUInt64Loop:
return 0;
case debug_ipc::AutomationOperandKind::kStoredValue:
if (stored_values_.find(operand.slot_offset()) != stored_values_.end())
return stored_values_.at(operand.slot_offset());
return 0;
}
}
uint64_t AutomationInstructionExecutor::EvalOperand(const debug_ipc::AutomationOperand& operand,
const GeneralRegisters& regs,
const ProcessHandle& handle,
const debug_ipc::MemoryBlock& loop_block,
uint64_t struct_base_pointer) {
switch (operand.kind()) {
case debug_ipc::AutomationOperandKind::kIndirectUInt32Loop: {
return GetValueFromBytes<uint32_t>(loop_block.data, struct_base_pointer + operand.offset());
}
case debug_ipc::AutomationOperandKind::kIndirectUInt64Loop: {
return GetValueFromBytes<uint64_t>(loop_block.data, struct_base_pointer + operand.offset());
}
default:
return EvalOperand(operand, regs, handle);
}
}
} // namespace debug_agent