mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Support copy address and value in Struct viewer
Reorganize add breakpoint menu Style fixes
This commit is contained in:
parent
3182cc29e4
commit
f9d7e426f8
@ -74,7 +74,7 @@ bool GhidraClient::FetchSymbols() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto pEntry: entries) {
|
for (const auto pEntry : entries) {
|
||||||
JsonGet entry = pEntry->value;
|
JsonGet entry = pEntry->value;
|
||||||
|
|
||||||
GhidraSymbol symbol;
|
GhidraSymbol symbol;
|
||||||
@ -104,7 +104,7 @@ bool GhidraClient::FetchTypes() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto pEntry: entries) {
|
for (const auto pEntry : entries) {
|
||||||
const JsonGet entry = pEntry->value;
|
const JsonGet entry = pEntry->value;
|
||||||
|
|
||||||
GhidraType type;
|
GhidraType type;
|
||||||
@ -124,7 +124,7 @@ bool GhidraClient::FetchTypes() {
|
|||||||
pendingResult_.error = "missing enum members";
|
pendingResult_.error = "missing enum members";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const JsonNode* pEnumEntry: enumEntries->value) {
|
for (const JsonNode* pEnumEntry : enumEntries->value) {
|
||||||
JsonGet enumEntry = pEnumEntry->value;
|
JsonGet enumEntry = pEnumEntry->value;
|
||||||
GhidraEnumMember member;
|
GhidraEnumMember member;
|
||||||
member.name = enumEntry.getStringOr("name", "");
|
member.name = enumEntry.getStringOr("name", "");
|
||||||
@ -153,7 +153,7 @@ bool GhidraClient::FetchTypes() {
|
|||||||
pendingResult_.error = "missing composite members";
|
pendingResult_.error = "missing composite members";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const JsonNode* pCompositeEntry: compositeEntries->value) {
|
for (const JsonNode* pCompositeEntry : compositeEntries->value) {
|
||||||
JsonGet compositeEntry = pCompositeEntry->value;
|
JsonGet compositeEntry = pCompositeEntry->value;
|
||||||
GhidraCompositeMember member;
|
GhidraCompositeMember member;
|
||||||
member.fieldName = compositeEntry.getStringOr("fieldName", "");
|
member.fieldName = compositeEntry.getStringOr("fieldName", "");
|
||||||
|
@ -63,13 +63,13 @@ struct GhidraType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class GhidraClient {
|
class GhidraClient {
|
||||||
public:
|
|
||||||
enum class Status {
|
enum class Status {
|
||||||
Idle,
|
Idle,
|
||||||
Pending,
|
Pending,
|
||||||
Ready,
|
Ready,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
struct Result {
|
struct Result {
|
||||||
std::vector<GhidraSymbol> symbols;
|
std::vector<GhidraSymbol> symbols;
|
||||||
std::unordered_map<std::string, GhidraType> types;
|
std::unordered_map<std::string, GhidraType> types;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "ext/imgui/imgui.h"
|
#include "ext/imgui/imgui.h"
|
||||||
|
|
||||||
|
#include "Common/System/Request.h"
|
||||||
#include "Core/MemMap.h"
|
#include "Core/MemMap.h"
|
||||||
#include "Core/Debugger/Breakpoints.h"
|
#include "Core/Debugger/Breakpoints.h"
|
||||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||||
@ -190,7 +191,7 @@ static constexpr int COLUMN_CONTENT = 2;
|
|||||||
|
|
||||||
void ImStructViewer::Draw(MIPSDebugInterface* mipsDebug, bool* open) {
|
void ImStructViewer::Draw(MIPSDebugInterface* mipsDebug, bool* open) {
|
||||||
mipsDebug_ = mipsDebug;
|
mipsDebug_ = mipsDebug;
|
||||||
ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
|
ImGui::SetNextWindowSize(ImVec2(750, 550), ImGuiCond_FirstUseEver);
|
||||||
if (!ImGui::Begin("Struct viewer", open) || !mipsDebug->isAlive() || !Memory::IsActive()) {
|
if (!ImGui::Begin("Struct viewer", open) || !mipsDebug->isAlive() || !Memory::IsActive()) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return;
|
return;
|
||||||
@ -275,7 +276,7 @@ void ImStructViewer::DrawGlobals() {
|
|||||||
ImGui::TableSetupColumn("Content");
|
ImGui::TableSetupColumn("Content");
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
for (const auto& symbol: ghidraClient_.result.symbols) {
|
for (const auto& symbol : ghidraClient_.result.symbols) {
|
||||||
if (!symbol.label || !symbol.userDefined || symbol.dataTypePathName.empty()) {
|
if (!symbol.label || !symbol.userDefined || symbol.dataTypePathName.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -304,7 +305,7 @@ void ImStructViewer::DrawWatch() {
|
|||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
int watchIndex = -1;
|
int watchIndex = -1;
|
||||||
for (const auto& watch: watches_) {
|
for (const auto& watch : watches_) {
|
||||||
watchIndex++;
|
watchIndex++;
|
||||||
if (!watchFilter_.PassFilter(watch.name.c_str())) {
|
if (!watchFilter_.PassFilter(watch.name.c_str())) {
|
||||||
continue;
|
continue;
|
||||||
@ -313,10 +314,9 @@ void ImStructViewer::DrawWatch() {
|
|||||||
if (!watch.expression.empty()) {
|
if (!watch.expression.empty()) {
|
||||||
u32 val;
|
u32 val;
|
||||||
PostfixExpression postfix;
|
PostfixExpression postfix;
|
||||||
if (mipsDebug_->initExpression(watch.expression.c_str(), postfix)) {
|
if (mipsDebug_->initExpression(watch.expression.c_str(), postfix)
|
||||||
if (mipsDebug_->parseExpression(postfix, val)) {
|
&& mipsDebug_->parseExpression(postfix, val)) {
|
||||||
address = val;
|
address = val;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
address = watch.address;
|
address = watch.address;
|
||||||
@ -346,7 +346,7 @@ void ImStructViewer::DrawNewWatchEntry() {
|
|||||||
ImGui::SetKeyboardFocusHere(0);
|
ImGui::SetKeyboardFocusHere(0);
|
||||||
}
|
}
|
||||||
newWatch_.typeFilter.Draw();
|
newWatch_.typeFilter.Draw();
|
||||||
for (const auto& entry: ghidraClient_.result.types) {
|
for (const auto& entry : ghidraClient_.result.types) {
|
||||||
const auto& type = entry.second;
|
const auto& type = entry.second;
|
||||||
if (newWatch_.typeFilter.PassFilter(type.displayName.c_str())) {
|
if (newWatch_.typeFilter.PassFilter(type.displayName.c_str())) {
|
||||||
ImGui::PushID(type.pathName.c_str());
|
ImGui::PushID(type.pathName.c_str());
|
||||||
@ -498,7 +498,7 @@ static void DrawPointerContent(
|
|||||||
static std::string FormatEnumValue(const std::vector<GhidraEnumMember>& enumMembers, const u64 value) {
|
static std::string FormatEnumValue(const std::vector<GhidraEnumMember>& enumMembers, const u64 value) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
bool hasPrevious = false;
|
bool hasPrevious = false;
|
||||||
for (const auto& member: enumMembers) {
|
for (const auto& member : enumMembers) {
|
||||||
if (value & member.value) {
|
if (value & member.value) {
|
||||||
if (hasPrevious) {
|
if (hasPrevious) {
|
||||||
ss << " | ";
|
ss << " | ";
|
||||||
@ -559,12 +559,12 @@ void ImStructViewer::DrawType(
|
|||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
// Flags used for nodes that can't be further opened
|
// Flags used for nodes that can't be further opened
|
||||||
const ImGuiTreeNodeFlags leafFlags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen |
|
const ImGuiTreeNodeFlags leafFlags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen |
|
||||||
ImGuiTreeNodeFlags_Bullet | extraTreeNodeFlags;
|
extraTreeNodeFlags;
|
||||||
|
|
||||||
// Type is missing in fetched types, this can happen e.g. if type used for watch is removed from Ghidra
|
// Type is missing in fetched types, this can happen e.g. if type used for watch is removed from Ghidra
|
||||||
if (!hasType) {
|
if (!hasType) {
|
||||||
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, 0, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, 0, typePathName, name, watchIndex, nullptr);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_RED);
|
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_RED);
|
||||||
DrawTypeColumn("<missing type: %s>", typePathName, base, offset);
|
DrawTypeColumn("<missing type: %s>", typePathName, base, offset);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
@ -580,7 +580,7 @@ void ImStructViewer::DrawType(
|
|||||||
// Handle cases where pointers or expressions point to invalid memory
|
// Handle cases where pointers or expressions point to invalid memory
|
||||||
if (!Memory::IsValidAddress(address)) {
|
if (!Memory::IsValidAddress(address)) {
|
||||||
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, nullptr);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_GRAY);
|
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_GRAY);
|
||||||
@ -596,23 +596,24 @@ void ImStructViewer::DrawType(
|
|||||||
switch (type.kind) {
|
switch (type.kind) {
|
||||||
case ENUM: {
|
case ENUM: {
|
||||||
ImGui::TreeNodeEx("Enum", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Enum", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
const u64 enumValue = ReadMemoryInt(address, type.length);
|
||||||
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, &enumValue);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
const u64 value = ReadMemoryInt(address, type.length);
|
const std::string enumString = FormatEnumValue(type.enumMembers, enumValue);
|
||||||
const std::string stringValue = FormatEnumValue(type.enumMembers, value);
|
ImGui::Text("= %llx (%s)", enumValue, enumString.c_str());
|
||||||
ImGui::Text("= %llx (%s)", value, stringValue.c_str());
|
|
||||||
DrawIntBuiltInEditPopup(address, type.length);
|
DrawIntBuiltInEditPopup(address, type.length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case POINTER: {
|
case POINTER: {
|
||||||
const bool nodeOpen = ImGui::TreeNodeEx("Pointer", extraTreeNodeFlags, "%s", name);
|
const bool nodeOpen = ImGui::TreeNodeEx("Pointer", extraTreeNodeFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
const u32 pointer = Memory::Read_U32(address);
|
||||||
|
const u64 pointer64 = pointer;
|
||||||
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, &pointer64);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
const u32 pointer = Memory::Read_U32(address);
|
|
||||||
DrawPointerContent(types, type, pointer);
|
DrawPointerContent(types, type, pointer);
|
||||||
|
|
||||||
if (nodeOpen) {
|
if (nodeOpen) {
|
||||||
@ -649,7 +650,7 @@ void ImStructViewer::DrawType(
|
|||||||
}
|
}
|
||||||
case ARRAY: {
|
case ARRAY: {
|
||||||
const bool nodeOpen = ImGui::TreeNodeEx("Array", extraTreeNodeFlags, "%s", name);
|
const bool nodeOpen = ImGui::TreeNodeEx("Array", extraTreeNodeFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, nullptr);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
@ -669,11 +670,11 @@ void ImStructViewer::DrawType(
|
|||||||
case STRUCTURE:
|
case STRUCTURE:
|
||||||
case UNION: {
|
case UNION: {
|
||||||
const bool nodeOpen = ImGui::TreeNodeEx("Composite", extraTreeNodeFlags, "%s", name);
|
const bool nodeOpen = ImGui::TreeNodeEx("Composite", extraTreeNodeFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, nullptr);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
|
|
||||||
if (nodeOpen) {
|
if (nodeOpen) {
|
||||||
for (const auto& member: type.compositeMembers) {
|
for (const auto& member : type.compositeMembers) {
|
||||||
DrawType(base, offset + member.offset, member.typePathName, nullptr,
|
DrawType(base, offset + member.offset, member.typePathName, nullptr,
|
||||||
member.fieldName.c_str(), -1);
|
member.fieldName.c_str(), -1);
|
||||||
}
|
}
|
||||||
@ -683,7 +684,7 @@ void ImStructViewer::DrawType(
|
|||||||
}
|
}
|
||||||
case FUNCTION_DEFINITION:
|
case FUNCTION_DEFINITION:
|
||||||
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, nullptr);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
@ -691,9 +692,11 @@ void ImStructViewer::DrawType(
|
|||||||
break;
|
break;
|
||||||
case BUILT_IN: {
|
case BUILT_IN: {
|
||||||
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
|
||||||
|
|
||||||
if (knownBuiltIns.count(typePathName)) {
|
if (knownBuiltIns.count(typePathName)) {
|
||||||
|
// This will copy float as int, but we can live with that for now
|
||||||
|
const u64 value = ReadMemoryInt(address, type.alignedLength);
|
||||||
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, &value);
|
||||||
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
DrawTypeColumn("%s", typeDisplayName, base, offset);
|
||||||
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
ImGui::TableSetColumnIndex(COLUMN_CONTENT);
|
||||||
DrawBuiltInContent(knownBuiltIns.at(typePathName), address);
|
DrawBuiltInContent(knownBuiltIns.at(typePathName), address);
|
||||||
@ -709,7 +712,7 @@ void ImStructViewer::DrawType(
|
|||||||
// At this point there is most likely some issue in the Ghidra plugin and the type wasn't
|
// At this point there is most likely some issue in the Ghidra plugin and the type wasn't
|
||||||
// classified to any category
|
// classified to any category
|
||||||
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
ImGui::TreeNodeEx("Field", leafFlags, "%s", name);
|
||||||
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex);
|
DrawContextMenu(base, offset, type.alignedLength, typePathName, name, watchIndex, nullptr);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_RED);
|
ImGui::PushStyleColor(ImGuiCol_Text, COLOR_RED);
|
||||||
DrawTypeColumn("<not implemented type: %s>", typeDisplayName, base, offset);
|
DrawTypeColumn("<not implemented type: %s>", typeDisplayName, base, offset);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
@ -721,18 +724,33 @@ void ImStructViewer::DrawType(
|
|||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CopyHexNumberToClipboard(u64 value) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::hex << value;
|
||||||
|
const std::string valueString = ss.str();
|
||||||
|
System_CopyStringToClipboard(valueString);
|
||||||
|
}
|
||||||
|
|
||||||
void ImStructViewer::DrawContextMenu(
|
void ImStructViewer::DrawContextMenu(
|
||||||
const u32 base,
|
const u32 base,
|
||||||
const u32 offset,
|
const u32 offset,
|
||||||
const int length,
|
const int length,
|
||||||
const std::string& typePathName,
|
const std::string& typePathName,
|
||||||
const char* name,
|
const char* name,
|
||||||
const int watchIndex
|
const int watchIndex,
|
||||||
|
const u64* value
|
||||||
) {
|
) {
|
||||||
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
|
ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight);
|
||||||
if (ImGui::BeginPopup("context")) {
|
if (ImGui::BeginPopup("context")) {
|
||||||
const u32 address = base + offset;
|
const u32 address = base + offset;
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Copy address")) {
|
||||||
|
CopyHexNumberToClipboard(address);
|
||||||
|
}
|
||||||
|
if (value && ImGui::MenuItem("Copy value")) {
|
||||||
|
CopyHexNumberToClipboard(*value);
|
||||||
|
}
|
||||||
|
|
||||||
// This might be called when iterating over existing watches so can't modify the watch vector directly here
|
// This might be called when iterating over existing watches so can't modify the watch vector directly here
|
||||||
if (watchIndex < 0) {
|
if (watchIndex < 0) {
|
||||||
if (ImGui::MenuItem("Add watch")) {
|
if (ImGui::MenuItem("Add watch")) {
|
||||||
@ -760,21 +778,25 @@ void ImStructViewer::DrawContextMenu(
|
|||||||
CBreakPoints::RemoveMemCheck(address, end);
|
CBreakPoints::RemoveMemCheck(address, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasMemCheck || !(memCheck.cond & MEMCHECK_READ)) {
|
const bool canAddRead = !hasMemCheck || !(memCheck.cond & MEMCHECK_READ);
|
||||||
if (ImGui::MenuItem("Add memory read breakpoint")) {
|
const bool canAddWrite = !hasMemCheck || !(memCheck.cond & MEMCHECK_WRITE);
|
||||||
|
const bool canAddWriteOnChange = !hasMemCheck || !(memCheck.cond & MEMCHECK_WRITE_ONCHANGE);
|
||||||
|
if ((canAddRead || canAddWrite || canAddWriteOnChange) && ImGui::BeginMenu("Add memory breakpoint")) {
|
||||||
|
if (canAddRead && canAddWrite && ImGui::MenuItem("Read/Write")) {
|
||||||
|
constexpr auto cond = static_cast<MemCheckCondition>(MEMCHECK_READ | MEMCHECK_WRITE);
|
||||||
|
CBreakPoints::AddMemCheck(address, end, cond, BREAK_ACTION_PAUSE);
|
||||||
|
}
|
||||||
|
if (canAddRead && ImGui::MenuItem("Read")) {
|
||||||
CBreakPoints::AddMemCheck(address, end, MEMCHECK_READ, BREAK_ACTION_PAUSE);
|
CBreakPoints::AddMemCheck(address, end, MEMCHECK_READ, BREAK_ACTION_PAUSE);
|
||||||
}
|
}
|
||||||
}
|
if (canAddWrite && ImGui::MenuItem("Write")) {
|
||||||
if (!hasMemCheck || !(memCheck.cond & MEMCHECK_WRITE)) {
|
|
||||||
if (ImGui::MenuItem("Add memory write breakpoint")) {
|
|
||||||
CBreakPoints::AddMemCheck(address, end, MEMCHECK_WRITE, BREAK_ACTION_PAUSE);
|
CBreakPoints::AddMemCheck(address, end, MEMCHECK_WRITE, BREAK_ACTION_PAUSE);
|
||||||
}
|
}
|
||||||
}
|
if (canAddWriteOnChange && ImGui::MenuItem("Write Change")) {
|
||||||
if (!hasMemCheck || !(memCheck.cond & MEMCHECK_WRITE_ONCHANGE)) {
|
|
||||||
if (ImGui::MenuItem("Add memory write on change breakpoint")) {
|
|
||||||
constexpr auto cond = static_cast<MemCheckCondition>(MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE);
|
constexpr auto cond = static_cast<MemCheckCondition>(MEMCHECK_WRITE | MEMCHECK_WRITE_ONCHANGE);
|
||||||
CBreakPoints::AddMemCheck(address, end, cond, BREAK_ACTION_PAUSE);
|
CBreakPoints::AddMemCheck(address, end, cond, BREAK_ACTION_PAUSE);
|
||||||
}
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,5 +67,6 @@ private:
|
|||||||
int length,
|
int length,
|
||||||
const std::string& typePathName,
|
const std::string& typePathName,
|
||||||
const char* name,
|
const char* name,
|
||||||
int watchIndex);
|
int watchIndex,
|
||||||
|
const u64* value);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user