From be5127feda0c5f755c52b8f2896626cbb24c3a4f Mon Sep 17 00:00:00 2001 From: Nav Date: Sat, 24 Dec 2022 02:40:57 +0000 Subject: [PATCH] CaptureMemorySnapshot insight worker task --- src/Insight/CMakeLists.txt | 1 + .../Tasks/CaptureMemorySnapshot.cpp | 107 ++++++++++++++++++ .../Tasks/CaptureMemorySnapshot.hpp | 42 +++++++ 3 files changed, 150 insertions(+) create mode 100644 src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.cpp create mode 100644 src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp diff --git a/src/Insight/CMakeLists.txt b/src/Insight/CMakeLists.txt index efbad715..1e241429 100755 --- a/src/Insight/CMakeLists.txt +++ b/src/Insight/CMakeLists.txt @@ -32,6 +32,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/GetTargetState.cpp ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/GetTargetDescriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/ConstructHexViewerByteItems.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/CaptureMemorySnapshot.cpp # Error dialogue window ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp diff --git a/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.cpp b/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.cpp new file mode 100644 index 00000000..8c3e2bf5 --- /dev/null +++ b/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.cpp @@ -0,0 +1,107 @@ +#include "CaptureMemorySnapshot.hpp" + +#include +#include +#include + +#include "src/Helpers/Paths.hpp" +#include "src/Helpers/EnumToStringMappings.hpp" +#include "src/Logger/Logger.hpp" + +namespace Bloom +{ + using TargetController::TargetControllerConsole; + + CaptureMemorySnapshot::CaptureMemorySnapshot( + const QString& name, + const QString& description, + Targets::TargetMemoryType memoryType, + const std::vector& focusedRegions, + const std::vector& excludedRegions, + const std::optional& data + ) + : name(name) + , description(description) + , memoryType(memoryType) + , focusedRegions(focusedRegions) + , excludedRegions(excludedRegions) + , data(data) + {} + + void CaptureMemorySnapshot::run(TargetControllerConsole& targetControllerConsole) { + using Targets::TargetMemorySize; + + Logger::info("Capturing snapshot"); + + const auto& targetDescriptor = targetControllerConsole.getTargetDescriptor(); + const auto memoryDescriptorIt = targetDescriptor.memoryDescriptorsByType.find(this->memoryType); + + if (memoryDescriptorIt == targetDescriptor.memoryDescriptorsByType.end()) { + throw Exceptions::Exception("Invalid memory type"); + } + + const auto& memoryDescriptor = memoryDescriptorIt->second; + const auto memorySize = memoryDescriptor.size(); + + if (!this->data.has_value()) { + Logger::info("Reading data for snapshot capture"); + + this->data = Targets::TargetMemoryBuffer(); + this->data->reserve(memorySize); + + const auto readSize = std::max( + TargetMemorySize(256), + memoryDescriptor.pageSize.value_or(TargetMemorySize(0)) + ); + const auto readsRequired = static_cast( + std::ceil(static_cast(memorySize) / static_cast(readSize)) + ); + + for (std::uint32_t i = 0; i < readsRequired; i++) { + auto dataSegment = targetControllerConsole.readMemory( + this->memoryType, + memoryDescriptor.addressRange.startAddress + static_cast(readSize * i), + (memorySize - this->data->size()) >= readSize + ? readSize + : static_cast(memorySize - this->data->size()), + {} + ); + + std::move(dataSegment.begin(), dataSegment.end(), std::back_inserter(*this->data)); + } + } + + assert(this->data->size() == memorySize); + + auto snapshot = MemorySnapshot( + std::move(this->name), + std::move(this->description), + this->memoryType, + std::move(*this->data), + targetControllerConsole.getProgramCounter(), + std::move(this->focusedRegions), + std::move(this->excludedRegions) + ); + + const auto snapshotDirPath = QString::fromStdString(Paths::projectSettingsDirPath()) + + "/memory_snapshots/" + EnumToStringMappings::targetMemoryTypes.at(snapshot.memoryType); + + QDir().mkpath(snapshotDirPath); + + const auto snapshotFilePath = snapshotDirPath + "/" + snapshot.id + ".json"; + + auto outputFile = QFile(snapshotFilePath); + + if (!outputFile.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { + Logger::error("Failed to save snapshot - cannot open " + snapshotFilePath.toStdString()); + return; + } + + outputFile.write(QJsonDocument(snapshot.toJson()).toJson(QJsonDocument::JsonFormat::Compact)); + outputFile.close(); + + Logger::info("Snapshot captured - UUID: " + snapshot.id.toStdString()); + + emit this->memorySnapshotCaptured(std::move(snapshot)); + } +} diff --git a/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp b/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp new file mode 100644 index 00000000..66c25869 --- /dev/null +++ b/src/Insight/InsightWorker/Tasks/CaptureMemorySnapshot.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "InsightWorkerTask.hpp" + +#include "src/Targets/TargetMemory.hpp" +#include "src/Insight/UserInterfaces/InsightWindow/Widgets/TargetMemoryInspectionPane/MemorySnapshot.hpp" + +namespace Bloom +{ + class CaptureMemorySnapshot: public InsightWorkerTask + { + Q_OBJECT + + public: + CaptureMemorySnapshot( + const QString& name, + const QString& description, + Targets::TargetMemoryType memoryType, + const std::vector& focusedRegions, + const std::vector& excludedRegions, + const std::optional& data + ); + + signals: + void memorySnapshotCaptured(MemorySnapshot snapshot); + + protected: + void run(TargetController::TargetControllerConsole& targetControllerConsole) override; + + private: + QString name; + QString description; + Targets::TargetMemoryType memoryType; + std::vector focusedRegions; + std::vector excludedRegions; + + std::optional data; + }; +}