VariablesModel.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "VariablesModel.h"
  27. #include <LibGUI/Application.h>
  28. #include <LibGUI/MessageBox.h>
  29. namespace HackStudio {
  30. GUI::ModelIndex VariablesModel::index(int row, int column, const GUI::ModelIndex& parent_index) const
  31. {
  32. if (!parent_index.is_valid())
  33. return create_index(row, column, &m_variables[row]);
  34. auto* parent = static_cast<const Debug::DebugInfo::VariableInfo*>(parent_index.internal_data());
  35. auto* child = &parent->members[row];
  36. return create_index(row, column, child);
  37. }
  38. GUI::ModelIndex VariablesModel::parent_index(const GUI::ModelIndex& index) const
  39. {
  40. if (!index.is_valid())
  41. return {};
  42. auto* child = static_cast<const Debug::DebugInfo::VariableInfo*>(index.internal_data());
  43. auto* parent = child->parent;
  44. if (parent == nullptr)
  45. return {};
  46. if (parent->parent == nullptr) {
  47. for (size_t row = 0; row < m_variables.size(); row++)
  48. if (m_variables.ptr_at(row).ptr() == parent)
  49. return create_index(row, 0, parent);
  50. ASSERT_NOT_REACHED();
  51. }
  52. for (size_t row = 0; row < parent->parent->members.size(); row++) {
  53. Debug::DebugInfo::VariableInfo* child_at_row = parent->parent->members.ptr_at(row).ptr();
  54. if (child_at_row == parent)
  55. return create_index(row, 0, parent);
  56. }
  57. ASSERT_NOT_REACHED();
  58. }
  59. int VariablesModel::row_count(const GUI::ModelIndex& index) const
  60. {
  61. if (!index.is_valid())
  62. return m_variables.size();
  63. auto* node = static_cast<const Debug::DebugInfo::VariableInfo*>(index.internal_data());
  64. return node->members.size();
  65. }
  66. static String variable_value_as_string(const Debug::DebugInfo::VariableInfo& variable)
  67. {
  68. if (variable.location_type != Debug::DebugInfo::VariableInfo::LocationType::Address)
  69. return "N/A";
  70. auto variable_address = variable.location_data.address;
  71. if (variable.is_enum_type()) {
  72. auto value = Debugger::the().session()->peek((u32*)variable_address);
  73. ASSERT(value.has_value());
  74. auto it = variable.type->members.find([enumerator_value = value.value()](auto& enumerator) {
  75. return enumerator->constant_data.as_u32 == enumerator_value;
  76. });
  77. ASSERT(!it.is_end());
  78. return String::format("%s::%s", variable.type_name.characters(), (*it)->name.characters());
  79. }
  80. if (variable.type_name == "int") {
  81. auto value = Debugger::the().session()->peek((u32*)variable_address);
  82. ASSERT(value.has_value());
  83. return String::format("%d", static_cast<int>(value.value()));
  84. }
  85. if (variable.type_name == "char") {
  86. auto value = Debugger::the().session()->peek((u32*)variable_address);
  87. ASSERT(value.has_value());
  88. return String::format("'%c' (%d)", static_cast<char>(value.value()), static_cast<char>(value.value()));
  89. }
  90. if (variable.type_name == "bool") {
  91. auto value = Debugger::the().session()->peek((u32*)variable_address);
  92. ASSERT(value.has_value());
  93. return (value.value() & 1) ? "true" : "false";
  94. }
  95. return String::format("type: %s @ %08x, ", variable.type_name.characters(), variable_address);
  96. }
  97. static Optional<u32> string_to_variable_value(const StringView& string_value, const Debug::DebugInfo::VariableInfo& variable)
  98. {
  99. if (variable.is_enum_type()) {
  100. auto prefix_string = String::format("%s::", variable.type_name.characters());
  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. auto it = variable.type->members.find([string_to_use](auto& enumerator) {
  105. return enumerator->name == string_to_use;
  106. });
  107. if (it.is_end())
  108. return {};
  109. return (*it)->constant_data.as_u32;
  110. }
  111. if (variable.type_name == "int") {
  112. auto value = string_value.to_int();
  113. if (value.has_value())
  114. return value.value();
  115. return {};
  116. }
  117. if (variable.type_name == "bool") {
  118. if (string_value == "true")
  119. return true;
  120. if (string_value == "false")
  121. return false;
  122. return {};
  123. }
  124. return {};
  125. }
  126. void VariablesModel::set_variable_value(const GUI::ModelIndex& index, const StringView& string_value, GUI::Window* parent_window)
  127. {
  128. auto variable = static_cast<const Debug::DebugInfo::VariableInfo*>(index.internal_data());
  129. auto value = string_to_variable_value(string_value, *variable);
  130. if (value.has_value()) {
  131. auto success = Debugger::the().session()->poke((u32*)variable->location_data.address, value.value());
  132. ASSERT(success);
  133. return;
  134. }
  135. GUI::MessageBox::show(parent_window,
  136. String::format("String value \"%s\" could not be converted to a value of type %s.", string_value.to_string().characters(), variable->type_name.characters()),
  137. "Set value failed",
  138. GUI::MessageBox::Type::Error);
  139. }
  140. GUI::Variant VariablesModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
  141. {
  142. auto* variable = static_cast<const Debug::DebugInfo::VariableInfo*>(index.internal_data());
  143. switch (role) {
  144. case GUI::ModelRole::Display: {
  145. auto value_as_string = variable_value_as_string(*variable);
  146. return String::format("%s: %s", variable->name.characters(), value_as_string.characters());
  147. }
  148. case GUI::ModelRole::Icon:
  149. return m_variable_icon;
  150. default:
  151. return {};
  152. }
  153. }
  154. void VariablesModel::update()
  155. {
  156. did_update();
  157. }
  158. RefPtr<VariablesModel> VariablesModel::create(const PtraceRegisters& regs)
  159. {
  160. auto variables = Debugger::the().session()->debug_info().get_variables_in_current_scope(regs);
  161. return adopt(*new VariablesModel(move(variables), regs));
  162. }
  163. }