GDBElf.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /*
  2. * Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibELF/ELFBuild.h>
  7. #include <LibJIT/GDB.h>
  8. namespace JIT::GDB {
  9. Optional<FixedArray<u8>> build_gdb_image(ReadonlyBytes code, StringView file_symbol_name, StringView code_symbol_name)
  10. {
  11. Vector<Elf64_Sym> symbols;
  12. ELF::StringTable section_names;
  13. ELF::StringTable symbol_names;
  14. ELF::SectionTable sections;
  15. auto const null_section = sections.build_null();
  16. // empty name so that its name in the dump isn't confused with '.text'.
  17. sections.header_at(null_section).sh_name = section_names.insert(""sv);
  18. // Build .text as a NOBITS section since the code isn't loaded inside the
  19. // image. The image just holds the addresses for the executable region.
  20. auto const text = sections.build_nobits([&](Elf64_Shdr& text) {
  21. text.sh_name = section_names.insert(".text"sv);
  22. text.sh_flags = SHF_EXECINSTR | SHF_ALLOC;
  23. text.sh_addr = bit_cast<uintptr_t>(code.offset(0));
  24. text.sh_size = code.size();
  25. text.sh_link = 0;
  26. text.sh_info = 0;
  27. text.sh_addralign = 1;
  28. text.sh_entsize = 0;
  29. });
  30. // Without this, GDB won't show the symbol names for our code.
  31. Elf64_Sym file;
  32. {
  33. file.st_name = symbol_names.insert(file_symbol_name);
  34. file.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FILE);
  35. file.st_other = STV_DEFAULT;
  36. file.st_shndx = SHN_ABS;
  37. file.st_value = 0;
  38. file.st_size = code.size();
  39. }
  40. symbols.append(file);
  41. // The index of the first symbol that does not have a `STB_LOCAL` binding.
  42. // Note that all non-local bindings must come before all local bindings.
  43. auto const first_non_local_symbol_index = symbols.size();
  44. Elf64_Sym code_sym;
  45. {
  46. code_sym.st_name = symbol_names.insert(code_symbol_name);
  47. code_sym.st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
  48. code_sym.st_other = STV_DEFAULT;
  49. code_sym.st_shndx = text.index,
  50. code_sym.st_value = 0; // 0 bytes relative to .text
  51. code_sym.st_size = code.size();
  52. }
  53. symbols.append(code_sym);
  54. auto const strtab = symbol_names.emit_into_builder(
  55. section_names.insert(".strtab"sv), sections);
  56. sections.build<Elf64_Sym>(symbols.span(),
  57. [&section_names, first_non_local_symbol_index, strtab](Elf64_Shdr& symtab) {
  58. symtab.sh_name = section_names.insert(".symtab"sv);
  59. symtab.sh_type = SHT_SYMTAB;
  60. symtab.sh_flags = 0;
  61. symtab.sh_addr = 0;
  62. symtab.sh_info = first_non_local_symbol_index;
  63. symtab.sh_link = strtab.raw_index();
  64. symtab.sh_addralign = 0;
  65. });
  66. // Make sure we find where the name for .shstrtab resides before we insert
  67. // it into the image.
  68. auto const shstrtab_name_index = section_names.insert(".shstrtab"sv);
  69. auto const shstrtab = section_names.emit_into_builder(
  70. shstrtab_name_index, sections);
  71. // Set the type to an "object" file, as GDB seems to request it:
  72. // https://sourceware.org/gdb/current/onlinedocs/gdb.html/Registering-Code.html#Registering-Code
  73. return ELF::build_elf_image(shstrtab.raw_index(), ET_REL, sections.span());
  74. }
  75. }