DebuggerGlobalJSObject.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  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::get(const JS::PropertyName& name, JS::Value receiver, bool without_side_effects) const
  21. {
  22. if (m_variables.is_empty() || !name.is_string())
  23. return JS::Object::get(name, receiver, without_side_effects);
  24. auto it = m_variables.find_if([&](auto& variable) {
  25. return variable->name == name.as_string();
  26. });
  27. if (it.is_end())
  28. return JS::Object::get(name, receiver, without_side_effects);
  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", 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::put(const JS::PropertyName& name, JS::Value value, JS::Value receiver)
  38. {
  39. if (m_variables.is_empty() || !name.is_string())
  40. return JS::Object::put(name, value, receiver);
  41. auto it = m_variables.find_if([&](auto& variable) {
  42. return variable->name == name.as_string();
  43. });
  44. if (it.is_end())
  45. return JS::Object::put(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(), 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->put(member.name, member_value.value(), {});
  80. }
  81. object->finish_writing_properties();
  82. return JS::Value(object);
  83. }
  84. Optional<u32> DebuggerGlobalJSObject::js_to_debugger(JS::Value value, const Debug::DebugInfo::VariableInfo& variable) const
  85. {
  86. if (value.is_string() && variable.type_name == "char") {
  87. auto string = value.as_string().string();
  88. if (string.length() != 1)
  89. return {};
  90. return string[0];
  91. }
  92. if (value.is_number() && (variable.is_enum_type() || variable.type_name == "int"))
  93. return value.as_u32();
  94. if (value.is_boolean() && variable.type_name == "bool")
  95. return value.as_bool();
  96. return {};
  97. }
  98. }