DebuggerGlobalJSObject.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright (c) 2021, Hunter Salyer <thefalsehonesty@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "DebuggerGlobalJSObject.h"
  7. #include "Debugger.h"
  8. #include "DebuggerVariableJSObject.h"
  9. #include <LibJS/Runtime/Completion.h>
  10. #include <LibJS/Runtime/Object.h>
  11. #include <LibJS/Runtime/ProxyObject.h>
  12. namespace HackStudio {
  13. DebuggerGlobalJSObject::DebuggerGlobalJSObject()
  14. {
  15. auto regs = Debugger::the().session()->get_registers();
  16. auto lib = Debugger::the().session()->library_at(regs.ip());
  17. if (!lib)
  18. return;
  19. m_variables = lib->debug_info->get_variables_in_current_scope(regs);
  20. }
  21. JS::ThrowCompletionOr<JS::Value> DebuggerGlobalJSObject::internal_get(JS::PropertyKey const& property_key, JS::Value receiver) const
  22. {
  23. if (m_variables.is_empty() || !property_key.is_string())
  24. return Base::internal_get(property_key, receiver);
  25. auto it = m_variables.find_if([&](auto& variable) {
  26. return variable->name == property_key.as_string();
  27. });
  28. if (it.is_end())
  29. return Base::internal_get(property_key, receiver);
  30. auto& target_variable = **it;
  31. auto js_value = debugger_to_js(target_variable);
  32. if (js_value.has_value())
  33. return js_value.value();
  34. auto error_string = String::formatted("Variable {} of type {} is not convertible to a JS Value", property_key.as_string(), target_variable.type_name);
  35. return vm().throw_completion<JS::TypeError>(const_cast<DebuggerGlobalJSObject&>(*this), move(error_string));
  36. }
  37. JS::ThrowCompletionOr<bool> DebuggerGlobalJSObject::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver)
  38. {
  39. if (m_variables.is_empty() || !property_key.is_string())
  40. return Base::internal_set(property_key, value, receiver);
  41. auto it = m_variables.find_if([&](auto& variable) {
  42. return variable->name == property_key.as_string();
  43. });
  44. if (it.is_end())
  45. return Base::internal_set(property_key, value, receiver);
  46. auto& target_variable = **it;
  47. auto debugger_value = js_to_debugger(value, target_variable);
  48. if (debugger_value.has_value())
  49. return Debugger::the().session()->poke(target_variable.location_data.address, debugger_value.value());
  50. auto error_string = String::formatted("Cannot convert JS value {} to variable {} of type {}", value.to_string_without_side_effects(), property_key.as_string(), target_variable.type_name);
  51. return vm().throw_completion<JS::TypeError>(const_cast<DebuggerGlobalJSObject&>(*this), move(error_string));
  52. }
  53. Optional<JS::Value> DebuggerGlobalJSObject::debugger_to_js(const Debug::DebugInfo::VariableInfo& variable) const
  54. {
  55. if (variable.location_type != Debug::DebugInfo::VariableInfo::LocationType::Address)
  56. return {};
  57. auto variable_address = variable.location_data.address;
  58. if (variable.is_enum_type() || variable.type_name == "int") {
  59. auto value = Debugger::the().session()->peek(variable_address);
  60. VERIFY(value.has_value());
  61. return JS::Value((i32)value.value());
  62. }
  63. if (variable.type_name == "char") {
  64. auto value = Debugger::the().session()->peek(variable_address);
  65. VERIFY(value.has_value());
  66. return JS::Value((char)value.value());
  67. }
  68. if (variable.type_name == "bool") {
  69. auto value = Debugger::the().session()->peek(variable_address);
  70. VERIFY(value.has_value());
  71. return JS::Value(value.value() != 0);
  72. }
  73. auto* object = DebuggerVariableJSObject::create(const_cast<DebuggerGlobalJSObject&>(*this), variable);
  74. for (auto& member : variable.members) {
  75. auto member_value = debugger_to_js(member);
  76. if (!member_value.has_value())
  77. continue;
  78. object->define_direct_property(member.name, member_value.value(), JS::default_attributes);
  79. }
  80. return JS::Value(object);
  81. }
  82. Optional<u32> DebuggerGlobalJSObject::js_to_debugger(JS::Value value, const Debug::DebugInfo::VariableInfo& variable) const
  83. {
  84. if (value.is_string() && variable.type_name == "char") {
  85. auto string = value.as_string().string();
  86. if (string.length() != 1)
  87. return {};
  88. return string[0];
  89. }
  90. if (value.is_number() && (variable.is_enum_type() || variable.type_name == "int"))
  91. return value.as_u32();
  92. if (value.is_boolean() && variable.type_name == "bool")
  93. return value.as_bool();
  94. return {};
  95. }
  96. }