Serenity Operating System
at master 175 lines 6.2 kB view raw
1/* 2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include "VariablesModel.h" 8#include <LibGUI/Application.h> 9#include <LibGUI/MessageBox.h> 10 11namespace HackStudio { 12 13GUI::ModelIndex VariablesModel::index(int row, int column, const GUI::ModelIndex& parent_index) const 14{ 15 if (!parent_index.is_valid()) { 16 if (static_cast<size_t>(row) >= m_variables.size()) 17 return {}; 18 return create_index(row, column, &m_variables[row]); 19 } 20 auto* parent = static_cast<Debug::DebugInfo::VariableInfo const*>(parent_index.internal_data()); 21 if (static_cast<size_t>(row) >= parent->members.size()) 22 return {}; 23 auto* child = &parent->members[row]; 24 return create_index(row, column, child); 25} 26 27GUI::ModelIndex VariablesModel::parent_index(const GUI::ModelIndex& index) const 28{ 29 if (!index.is_valid()) 30 return {}; 31 auto* child = static_cast<Debug::DebugInfo::VariableInfo const*>(index.internal_data()); 32 auto* parent = child->parent; 33 if (parent == nullptr) 34 return {}; 35 36 if (parent->parent == nullptr) { 37 for (size_t row = 0; row < m_variables.size(); row++) 38 if (m_variables[row].ptr() == parent) 39 return create_index(row, 0, parent); 40 VERIFY_NOT_REACHED(); 41 } 42 for (size_t row = 0; row < parent->parent->members.size(); row++) { 43 Debug::DebugInfo::VariableInfo* child_at_row = parent->parent->members[row].ptr(); 44 if (child_at_row == parent) 45 return create_index(row, 0, parent); 46 } 47 VERIFY_NOT_REACHED(); 48} 49 50int VariablesModel::row_count(const GUI::ModelIndex& index) const 51{ 52 if (!index.is_valid()) 53 return m_variables.size(); 54 auto* node = static_cast<Debug::DebugInfo::VariableInfo const*>(index.internal_data()); 55 return node->members.size(); 56} 57 58static DeprecatedString variable_value_as_string(Debug::DebugInfo::VariableInfo const& variable) 59{ 60 if (variable.location_type != Debug::DebugInfo::VariableInfo::LocationType::Address) 61 return "N/A"; 62 63 auto variable_address = variable.location_data.address; 64 65 if (variable.is_enum_type()) { 66 auto value = Debugger::the().session()->peek(variable_address); 67 VERIFY(value.has_value()); 68 auto it = variable.type->members.find_if([&enumerator_value = value.value()](auto const& enumerator) { 69 return enumerator->constant_data.as_u32 == enumerator_value; 70 }); 71 if (it.is_end()) 72 return DeprecatedString::formatted("Unknown ({})", value.value()); 73 return DeprecatedString::formatted("{}::{}", variable.type_name, (*it)->name); 74 } 75 76 if (variable.type_name == "int") { 77 auto value = Debugger::the().session()->peek(variable_address); 78 VERIFY(value.has_value()); 79 return DeprecatedString::formatted("{}", static_cast<int>(value.value())); 80 } 81 82 if (variable.type_name == "char") { 83 auto value = Debugger::the().session()->peek(variable_address); 84 VERIFY(value.has_value()); 85 return DeprecatedString::formatted("'{0:c}'", (char)value.value()); 86 } 87 88 if (variable.type_name == "bool") { 89 auto value = Debugger::the().session()->peek(variable_address); 90 VERIFY(value.has_value()); 91 return (value.value() & 1) ? "true" : "false"; 92 } 93 94 return DeprecatedString::formatted("type: {} @ {:p}, ", variable.type_name, variable_address); 95} 96 97static Optional<u32> string_to_variable_value(StringView string_value, Debug::DebugInfo::VariableInfo const& variable) 98{ 99 if (variable.is_enum_type()) { 100 auto prefix_string = DeprecatedString::formatted("{}::", variable.type_name); 101 auto string_to_use = string_value; 102 if (string_value.starts_with(prefix_string)) 103 string_to_use = string_value.substring_view(prefix_string.length(), string_value.length() - prefix_string.length()); 104 105 auto it = variable.type->members.find_if([string_to_use](auto const& enumerator) { 106 return enumerator->name == string_to_use; 107 }); 108 109 if (it.is_end()) 110 return {}; 111 return (*it)->constant_data.as_u32; 112 } 113 114 if (variable.type_name == "int") { 115 auto value = string_value.to_int(); 116 if (value.has_value()) 117 return value.value(); 118 return {}; 119 } 120 121 if (variable.type_name == "bool") { 122 if (string_value == "true") 123 return true; 124 if (string_value == "false") 125 return false; 126 return {}; 127 } 128 129 return {}; 130} 131 132void VariablesModel::set_variable_value(const GUI::ModelIndex& index, StringView string_value, GUI::Window* parent_window) 133{ 134 auto variable = static_cast<Debug::DebugInfo::VariableInfo const*>(index.internal_data()); 135 136 auto value = string_to_variable_value(string_value, *variable); 137 138 if (value.has_value()) { 139 auto success = Debugger::the().session()->poke(variable->location_data.address, value.value()); 140 VERIFY(success); 141 return; 142 } 143 144 GUI::MessageBox::show( 145 parent_window, 146 DeprecatedString::formatted("String value \"{}\" could not be converted to a value of type {}.", string_value, variable->type_name), 147 "Set value failed"sv, 148 GUI::MessageBox::Type::Error); 149} 150 151GUI::Variant VariablesModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const 152{ 153 auto* variable = static_cast<Debug::DebugInfo::VariableInfo const*>(index.internal_data()); 154 switch (role) { 155 case GUI::ModelRole::Display: { 156 auto value_as_string = variable_value_as_string(*variable); 157 return DeprecatedString::formatted("{}: {}", variable->name, value_as_string); 158 } 159 case GUI::ModelRole::Icon: 160 return m_variable_icon; 161 default: 162 return {}; 163 } 164} 165 166RefPtr<VariablesModel> VariablesModel::create(Debug::ProcessInspector& inspector, PtraceRegisters const& regs) 167{ 168 auto lib = inspector.library_at(regs.ip()); 169 if (!lib) 170 return nullptr; 171 auto variables = lib->debug_info->get_variables_in_current_scope(regs).release_value_but_fixme_should_propagate_errors(); 172 return adopt_ref(*new VariablesModel(inspector, move(variables), regs)); 173} 174 175}