Przeglądaj źródła

LibJS/JIT: Produce & register an ELF image for GDB JIT Interface

Using the code that it has just produced, the JIT::Compiler can build an
ELF image so that we can attach meaningful symbols to JITted code, and
thus enable GDB to display more information about the code that we're
running.
Jesús (gsus) Lapastora 1 rok temu
rodzic
commit
f0b984567a

+ 10 - 1
Userland/Libraries/LibJS/JIT/Compiler.cpp

@@ -1,12 +1,14 @@
 /*
 /*
  * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
  * Copyright (c) 2023, Simon Wanner <simon@skyrising.xyz>
  * Copyright (c) 2023, Simon Wanner <simon@skyrising.xyz>
+ * Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
 #include <AK/OwnPtr.h>
 #include <AK/OwnPtr.h>
 #include <AK/Platform.h>
 #include <AK/Platform.h>
+#include <LibJIT/GDB.h>
 #include <LibJS/Bytecode/CommonImplementations.h>
 #include <LibJS/Bytecode/CommonImplementations.h>
 #include <LibJS/Bytecode/Instruction.h>
 #include <LibJS/Bytecode/Instruction.h>
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibJS/Bytecode/Interpreter.h>
@@ -3757,7 +3759,14 @@ OwnPtr<NativeExecutable> Compiler::compile(Bytecode::Executable& bytecode_execut
         dbgln("\033[32;1mJIT compilation succeeded!\033[0m {}", bytecode_executable.name);
         dbgln("\033[32;1mJIT compilation succeeded!\033[0m {}", bytecode_executable.name);
     }
     }
 
 
-    auto executable = make<NativeExecutable>(executable_memory, compiler.m_output.size(), mapping);
+    auto const code = ReadonlyBytes {
+        executable_memory,
+        compiler.m_output.size(),
+    };
+
+    auto gdb_object = ::JIT::GDB::build_gdb_image(code, "LibJS JIT"sv, "LibJS JITted code"sv);
+
+    auto executable = make<NativeExecutable>(executable_memory, compiler.m_output.size(), mapping, move(gdb_object));
     if constexpr (DUMP_JIT_DISASSEMBLY)
     if constexpr (DUMP_JIT_DISASSEMBLY)
         executable->dump_disassembly(bytecode_executable);
         executable->dump_disassembly(bytecode_executable);
     return executable;
     return executable;

+ 7 - 1
Userland/Libraries/LibJS/JIT/NativeExecutable.cpp

@@ -6,6 +6,7 @@
  */
  */
 
 
 #include <AK/BinarySearch.h>
 #include <AK/BinarySearch.h>
+#include <LibJIT/GDB.h>
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibJS/Bytecode/Interpreter.h>
 #include <LibJS/JIT/NativeExecutable.h>
 #include <LibJS/JIT/NativeExecutable.h>
 #include <LibJS/Runtime/VM.h>
 #include <LibJS/Runtime/VM.h>
@@ -14,10 +15,11 @@
 
 
 namespace JS::JIT {
 namespace JS::JIT {
 
 
-NativeExecutable::NativeExecutable(void* code, size_t size, Vector<BytecodeMapping> mapping)
+NativeExecutable::NativeExecutable(void* code, size_t size, Vector<BytecodeMapping> mapping, Optional<FixedArray<u8>> gdb_object)
     : m_code(code)
     : m_code(code)
     , m_size(size)
     , m_size(size)
     , m_mapping(move(mapping))
     , m_mapping(move(mapping))
+    , m_gdb_object(move(gdb_object))
 {
 {
     // Translate block index to instruction address, so the native code can just jump to it.
     // Translate block index to instruction address, so the native code can just jump to it.
     for (auto const& entry : m_mapping) {
     for (auto const& entry : m_mapping) {
@@ -28,10 +30,14 @@ NativeExecutable::NativeExecutable(void* code, size_t size, Vector<BytecodeMappi
             m_block_entry_points.append(bit_cast<FlatPtr>(m_code) + entry.native_offset);
             m_block_entry_points.append(bit_cast<FlatPtr>(m_code) + entry.native_offset);
         }
         }
     }
     }
+    if (m_gdb_object.has_value())
+        ::JIT::GDB::register_into_gdb(m_gdb_object.value().span());
 }
 }
 
 
 NativeExecutable::~NativeExecutable()
 NativeExecutable::~NativeExecutable()
 {
 {
+    if (m_gdb_object.has_value())
+        ::JIT::GDB::unregister_from_gdb(m_gdb_object.value().span());
     munmap(m_code, m_size);
     munmap(m_code, m_size);
 }
 }
 
 

+ 3 - 1
Userland/Libraries/LibJS/JIT/NativeExecutable.h

@@ -6,6 +6,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AK/FixedArray.h>
 #include <AK/Noncopyable.h>
 #include <AK/Noncopyable.h>
 #include <AK/Types.h>
 #include <AK/Types.h>
 #include <LibJS/Bytecode/Instruction.h>
 #include <LibJS/Bytecode/Instruction.h>
@@ -28,7 +29,7 @@ class NativeExecutable {
     AK_MAKE_NONMOVABLE(NativeExecutable);
     AK_MAKE_NONMOVABLE(NativeExecutable);
 
 
 public:
 public:
-    NativeExecutable(void* code, size_t size, Vector<BytecodeMapping>);
+    NativeExecutable(void* code, size_t size, Vector<BytecodeMapping>, Optional<FixedArray<u8>> gdb_object = {});
     ~NativeExecutable();
     ~NativeExecutable();
 
 
     void run(VM&, size_t entry_point) const;
     void run(VM&, size_t entry_point) const;
@@ -44,6 +45,7 @@ private:
     Vector<BytecodeMapping> m_mapping;
     Vector<BytecodeMapping> m_mapping;
     Vector<FlatPtr> m_block_entry_points;
     Vector<FlatPtr> m_block_entry_points;
     mutable OwnPtr<Bytecode::InstructionStreamIterator> m_instruction_stream_iterator;
     mutable OwnPtr<Bytecode::InstructionStreamIterator> m_instruction_stream_iterator;
+    Optional<FixedArray<u8>> m_gdb_object;
 };
 };
 
 
 }
 }