GDB.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Checked.h>
  7. #include <AK/OwnPtr.h>
  8. #include <AK/Span.h>
  9. #include <LibJIT/GDB.h>
  10. namespace JIT::GDB {
  11. // Declarations from https://sourceware.org/gdb/current/onlinedocs/gdb.html/Declarations.html#Declarations.
  12. enum class JitActions : u32 {
  13. NoAction = 0,
  14. RegisterFn = 1,
  15. UnregisterFn = 2,
  16. };
  17. struct JitCodeEntry {
  18. JitCodeEntry* next_entry;
  19. JitCodeEntry* prev_entry;
  20. char const* symfile_addr;
  21. u64 symfile_size;
  22. };
  23. struct JitDescriptor {
  24. u32 version;
  25. JitActions action_flag;
  26. JitCodeEntry* relevant_entry;
  27. JitCodeEntry* first_entry;
  28. };
  29. extern "C" {
  30. // GDB puts a breakpoint in this function.
  31. // Use an __asm__ statement to prevent compilers from inlining/removing this
  32. // function.
  33. // From V8:
  34. // https://github.com/v8/v8/blob/1c7d3a94fc051e0fd69584b930faab448026941e/src/diagnostics/gdb-jit.cc#L1742
  35. void __attribute__((noinline)) __jit_debug_register_code();
  36. void __attribute__((noinline)) __jit_debug_register_code() { __asm__(""); }
  37. // Make sure to specify the version statically, because the debugger may check
  38. // the version before we can set it.
  39. // NOTE: If the JIT is multi-threaded, then it is important that the JIT synchronize any modifications to this global data properly, which can easily be done by putting a global mutex around modifications to these structures.
  40. JitDescriptor __jit_debug_descriptor = { 1, JitActions::NoAction, nullptr, nullptr };
  41. }
  42. static JitCodeEntry* find_code_entry(ReadonlyBytes data)
  43. {
  44. auto const search_addr = bit_cast<uintptr_t>(data.offset(0));
  45. for (JitCodeEntry* curr = __jit_debug_descriptor.first_entry; curr != NULL; curr = curr->next_entry) {
  46. auto const entry_addr = bit_cast<uintptr_t>(curr->symfile_addr);
  47. if (entry_addr == search_addr) {
  48. VERIFY(curr->symfile_size == data.size());
  49. return curr;
  50. }
  51. }
  52. return NULL;
  53. }
  54. void unregister_from_gdb(ReadonlyBytes data)
  55. {
  56. // Following steps from:
  57. // https://sourceware.org/gdb/current/onlinedocs/gdb.html/Unregistering-Code.html#Unregistering-Code
  58. auto may_have_entry = AK::adopt_own_if_nonnull(find_code_entry(data));
  59. VERIFY(may_have_entry);
  60. auto entry = may_have_entry.release_nonnull();
  61. if (entry->prev_entry) {
  62. entry->prev_entry->next_entry = entry->next_entry;
  63. }
  64. if (entry->next_entry) {
  65. entry->next_entry->prev_entry = entry->prev_entry;
  66. }
  67. if (entry == __jit_debug_descriptor.first_entry) {
  68. __jit_debug_descriptor.first_entry = entry->next_entry;
  69. }
  70. __jit_debug_descriptor.relevant_entry = entry;
  71. __jit_debug_descriptor.action_flag = JitActions::UnregisterFn;
  72. __jit_debug_register_code();
  73. }
  74. void register_into_gdb(ReadonlyBytes data)
  75. {
  76. // Following steps from:
  77. // https://sourceware.org/gdb/current/onlinedocs/gdb.html/Registering-Code.html#Registering-Code
  78. auto* const leaked_entry = make<JitCodeEntry>().leak_ptr();
  79. // Add it to the linked list in the JIT descriptor.
  80. leaked_entry->symfile_addr = reinterpret_cast<char const*>(data.data());
  81. leaked_entry->symfile_size = data.size();
  82. leaked_entry->next_entry = __jit_debug_descriptor.first_entry;
  83. leaked_entry->prev_entry = NULL;
  84. if (__jit_debug_descriptor.first_entry) {
  85. VERIFY(__jit_debug_descriptor.first_entry->prev_entry == nullptr);
  86. __jit_debug_descriptor.first_entry->prev_entry = leaked_entry;
  87. }
  88. __jit_debug_descriptor.first_entry = leaked_entry;
  89. __jit_debug_descriptor.relevant_entry = leaked_entry;
  90. __jit_debug_descriptor.action_flag = JitActions::RegisterFn;
  91. __jit_debug_register_code();
  92. }
  93. }