mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:27:35 +00:00
LibJIT: Integrate GDB JIT Interface with ELF builders
Provide a function to create an ELF image in a format GDB expects. Outside of ELF platforms this image doesn't make much sense, and in MacOS a Mach-O memory image is required: see https://chromium.googlesource.com/v8/v8.git/+/refs/heads/main/src/diagnostics/gdb-jit.cc#1802 Since GDB requires active runtime addresses for the code, copying the generated code into the image will not help. Instead, `build_gdb_image` writes the runtime addresses of the code into a NOBITS `.text` section.
This commit is contained in:
parent
48a9d0ede8
commit
149e382735
4 changed files with 122 additions and 0 deletions
|
@ -2,6 +2,14 @@ set(SOURCES
|
||||||
Assembler.cpp
|
Assembler.cpp
|
||||||
GDB.cpp
|
GDB.cpp
|
||||||
)
|
)
|
||||||
|
if(NOT APPLE AND NOT WIN32 AND NOT EMSCRIPTEN)
|
||||||
|
list(APPEND SOURCES GDBElf.cpp)
|
||||||
|
else()
|
||||||
|
list(APPEND SOURCES GDBUnsupported.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
serenity_lib(LibJIT jit)
|
serenity_lib(LibJIT jit)
|
||||||
|
if(NOT APPLE AND NOT WIN32 AND NOT EMSCRIPTEN)
|
||||||
|
target_link_libraries(LibJIT PRIVATE LibELF)
|
||||||
|
endif()
|
||||||
target_link_libraries(LibJIT PRIVATE LibCore)
|
target_link_libraries(LibJIT PRIVATE LibCore)
|
||||||
|
|
|
@ -6,10 +6,23 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/FixedArray.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
|
#include <AK/StringView.h>
|
||||||
|
|
||||||
namespace JIT::GDB {
|
namespace JIT::GDB {
|
||||||
|
|
||||||
void register_into_gdb(ReadonlyBytes data);
|
void register_into_gdb(ReadonlyBytes data);
|
||||||
void unregister_from_gdb(ReadonlyBytes data);
|
void unregister_from_gdb(ReadonlyBytes data);
|
||||||
|
|
||||||
|
// Build a GDB compatible image to register with the GDB JIT Interface.
|
||||||
|
// Returns Optional since the platform may not be supported.
|
||||||
|
// The `code` must be the region of memory that will be executed, since the
|
||||||
|
// image will hold direct references to addresses within the code. This way GDB
|
||||||
|
// will be able to identify the code region and insert breakpoints into it.
|
||||||
|
// Both `file_symbol_name` and `code_symbol_name` will end up in the symbol
|
||||||
|
// table of the image. They represent a file name for the image and a name for
|
||||||
|
// the region of code that is being executed.
|
||||||
|
Optional<FixedArray<u8>> build_gdb_image(ReadonlyBytes code, StringView file_symbol_name, StringView code_symbol_name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
87
Userland/Libraries/LibJIT/GDBElf.cpp
Normal file
87
Userland/Libraries/LibJIT/GDBElf.cpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibELF/ELFBuild.h>
|
||||||
|
#include <LibJIT/GDB.h>
|
||||||
|
|
||||||
|
namespace JIT::GDB {
|
||||||
|
|
||||||
|
Optional<FixedArray<u8>> build_gdb_image(ReadonlyBytes code, StringView file_symbol_name, StringView code_symbol_name)
|
||||||
|
{
|
||||||
|
Vector<Elf64_Sym> symbols;
|
||||||
|
ELF::StringTable section_names;
|
||||||
|
ELF::StringTable symbol_names;
|
||||||
|
ELF::SectionTable sections;
|
||||||
|
|
||||||
|
auto const null_section = sections.build_null();
|
||||||
|
|
||||||
|
// empty name so that its name in the dump isn't confused with '.text'.
|
||||||
|
sections.header_at(null_section).sh_name = section_names.insert(""sv);
|
||||||
|
|
||||||
|
// Build .text as a NOBITS section since the code isn't loaded inside the
|
||||||
|
// image. The image just holds the addresses for the executable region.
|
||||||
|
auto const text = sections.build_nobits([&](Elf64_Shdr& text) {
|
||||||
|
text.sh_name = section_names.insert(".text"sv);
|
||||||
|
text.sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||||
|
text.sh_addr = bit_cast<u64>(code.offset(0));
|
||||||
|
text.sh_size = code.size();
|
||||||
|
text.sh_link = 0;
|
||||||
|
text.sh_info = 0;
|
||||||
|
text.sh_addralign = 1;
|
||||||
|
text.sh_entsize = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Without this, GDB won't show the symbol names for our code.
|
||||||
|
Elf64_Sym file;
|
||||||
|
{
|
||||||
|
file.st_name = symbol_names.insert(file_symbol_name);
|
||||||
|
file.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FILE);
|
||||||
|
file.st_other = STV_DEFAULT;
|
||||||
|
file.st_shndx = SHN_ABS;
|
||||||
|
file.st_value = 0;
|
||||||
|
file.st_size = code.size();
|
||||||
|
}
|
||||||
|
symbols.append(file);
|
||||||
|
|
||||||
|
// The index of the first symbol that does not have a `STB_LOCAL` binding.
|
||||||
|
// Note that all non-local bindings must come before all local bindings.
|
||||||
|
auto const first_non_local_symbol_index = symbols.size();
|
||||||
|
Elf64_Sym code_sym;
|
||||||
|
{
|
||||||
|
code_sym.st_name = symbol_names.insert(code_symbol_name);
|
||||||
|
code_sym.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
|
||||||
|
code_sym.st_other = STV_DEFAULT;
|
||||||
|
code_sym.st_shndx = text.index,
|
||||||
|
code_sym.st_value = 0; // 0 bytes relative to .text
|
||||||
|
code_sym.st_size = code.size();
|
||||||
|
}
|
||||||
|
symbols.append(code_sym);
|
||||||
|
|
||||||
|
auto const strtab = symbol_names.emit_into_builder(
|
||||||
|
section_names.insert(".strtab"sv), sections);
|
||||||
|
|
||||||
|
sections.build<Elf64_Sym>(symbols.span(),
|
||||||
|
[§ion_names, first_non_local_symbol_index, strtab](Elf64_Shdr& symtab) {
|
||||||
|
symtab.sh_name = section_names.insert(".symtab"sv);
|
||||||
|
symtab.sh_type = SHT_SYMTAB;
|
||||||
|
symtab.sh_flags = 0;
|
||||||
|
symtab.sh_addr = 0;
|
||||||
|
symtab.sh_info = first_non_local_symbol_index;
|
||||||
|
symtab.sh_link = strtab.raw_index();
|
||||||
|
symtab.sh_addralign = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make sure we find where the name for .shstrtab resides before we insert
|
||||||
|
// it into the image.
|
||||||
|
auto const shstrtab_name_index = section_names.insert(".shstrtab"sv);
|
||||||
|
auto const shstrtab = section_names.emit_into_builder(
|
||||||
|
shstrtab_name_index, sections);
|
||||||
|
|
||||||
|
// Set the type to an "object" file, as GDB seems to request it:
|
||||||
|
// https://sourceware.org/gdb/current/onlinedocs/gdb.html/Registering-Code.html#Registering-Code
|
||||||
|
return ELF::build_elf_image(shstrtab.raw_index(), ET_REL, sections.span());
|
||||||
|
}
|
||||||
|
}
|
14
Userland/Libraries/LibJIT/GDBUnsupported.cpp
Normal file
14
Userland/Libraries/LibJIT/GDBUnsupported.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibJIT/GDB.h>
|
||||||
|
|
||||||
|
namespace JIT::GDB {
|
||||||
|
Optional<FixedArray<u8>> build_gdb_image(ReadonlyBytes, StringView, StringView)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue