VariablesModel.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. GUI::ModelIndex VariablesModel::index(int row, int column, const GUI::ModelIndex& parent_index) const
  30. {
  31. if (!parent_index.is_valid())
  32. return create_index(row, column, &m_variables[row]);
  33. auto* parent = static_cast<const DebugInfo::VariableInfo*>(parent_index.internal_data());
  34. auto* child = &parent->members[row];
  35. return create_index(row, column, child);
  36. }
  37. GUI::ModelIndex VariablesModel::parent_index(const GUI::ModelIndex& index) const
  38. {
  39. if (!index.is_valid())
  40. return {};
  41. auto* child = static_cast<const DebugInfo::VariableInfo*>(index.internal_data());
  42. auto* parent = child->parent;
  43. if (parent == nullptr)
  44. return {};
  45. if (parent->parent == nullptr) {
  46. for (size_t row = 0; row < m_variables.size(); row++)
  47. if (m_variables.ptr_at(row).ptr() == parent)
  48. return create_index(row, 0, parent);
  49. ASSERT_NOT_REACHED();
  50. }
  51. for (size_t row = 0; row < parent->parent->members.size(); row++) {
  52. DebugInfo::VariableInfo* child_at_row = parent->parent->members.ptr_at(row).ptr();
  53. if (child_at_row == parent)
  54. return create_index(row, 0, parent);
  55. }
  56. ASSERT_NOT_REACHED();
  57. }
  58. int VariablesModel::row_count(const GUI::ModelIndex& index) const
  59. {
  60. if (!index.is_valid())
  61. return m_variables.size();
  62. auto* node = static_cast<const DebugInfo::VariableInfo*>(index.internal_data());
  63. return node->members.size();
  64. }
  65. String variable_value_as_string(const DebugInfo::VariableInfo& variable)
  66. {
  67. if (variable.location_type != DebugInfo::VariableInfo::LocationType::Address)
  68. return "N/A";
  69. auto variable_address = variable.location_data.address;
  70. if (variable.is_enum_type()) {
  71. auto value = Debugger::the().session()->peek((u32*)variable_address);
  72. ASSERT(value.has_value());
  73. auto it = variable.type->members.find([enumerator_value = value.value()](auto& enumerator) {
  74. return enumerator->constant_data.as_u32 == enumerator_value;
  75. });
  76. ASSERT(!it.is_end());
  77. return String::format("%s::%s", variable.type_name.characters(), (*it)->name.characters());
  78. }
  79. if (variable.type_name == "int") {
  80. auto value = Debugger::the().session()->peek((u32*)variable_address);
  81. ASSERT(value.has_value());
  82. return String::format("%d", static_cast<int>(value.value()));
  83. }
  84. if (variable.type_name == "char") {
  85. auto value = Debugger::the().session()->peek((u32*)variable_address);
  86. ASSERT(value.has_value());
  87. return String::format("'%c' (%d)", static_cast<char>(value.value()), static_cast<char>(value.value()));
  88. }
  89. if (variable.type_name == "bool") {
  90. auto value = Debugger::the().session()->peek((u32*)variable_address);
  91. ASSERT(value.has_value());
  92. return (value.value() & 1) ? "true" : "false";
  93. }
  94. return String::format("type: %s @ %08x, ", variable.type_name.characters(), variable_address);
  95. }
  96. static Optional<u32> string_to_variable_value(const StringView& string_value, const DebugInfo::VariableInfo& variable)
  97. {
  98. if (variable.is_enum_type()) {
  99. auto prefix_string = String::format("%s::", variable.type_name.characters());
  100. auto string_to_use = string_value;
  101. if (string_value.starts_with(prefix_string))
  102. string_to_use = string_value.substring_view(prefix_string.length(), string_value.length() - prefix_string.length());
  103. auto it = variable.type->members.find([string_to_use](auto& enumerator) {
  104. return enumerator->name == string_to_use;
  105. });
  106. if (it.is_end())
  107. return {};
  108. return (*it)->constant_data.as_u32;
  109. }
  110. if (variable.type_name == "int") {
  111. bool success = false;
  112. auto value = string_value.to_int(success);
  113. return success ? value : Optional<u32>();
  114. }
  115. if (variable.type_name == "bool") {
  116. if (string_value == "true")
  117. return true;
  118. if (string_value == "false")
  119. return false;
  120. return {};
  121. }
  122. return {};
  123. }
  124. void VariablesModel::set_variable_value(const GUI::ModelIndex& index, const StringView& string_value, GUI::Window* parent_window)
  125. {
  126. auto variable = static_cast<const DebugInfo::VariableInfo*>(index.internal_data());
  127. auto value = string_to_variable_value(string_value, *variable);
  128. if (value.has_value()) {
  129. auto success = Debugger::the().session()->poke((u32*)variable->location_data.address, value.value());
  130. ASSERT(success);
  131. return;
  132. }
  133. GUI::MessageBox::show(
  134. String::format("String value \"%s\" could not be converted to a value of type %s.", string_value.to_string().characters(), variable->type_name.characters()),
  135. "Set value failed",
  136. GUI::MessageBox::Type::Error,
  137. GUI::MessageBox::InputType::OK,
  138. parent_window);
  139. }
  140. GUI::Variant VariablesModel::data(const GUI::ModelIndex& index, Role role) const
  141. {
  142. auto* variable = static_cast<const DebugInfo::VariableInfo*>(index.internal_data());
  143. switch (role) {
  144. case Role::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 Role::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. }