DebuggerGlobalJSObject.cpp 4.3 KB

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