summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-05-23 15:55:30 -0400
committerGHC GitLab CI <ghc-ci@gitlab-haskell.org>2022-05-23 23:05:26 -0400
commitf390cfc51ca93ef883a454308942ca3f8497ae31 (patch)
treeafbe6f3d48d7facd80a47b388a90066d4ddcb91b
parent1ca1efdc8758458a28414f6d00c679b8f9a6bd0a (diff)
downloadhaskell-wip/gdb-jit-object.tar.gz
(cherry picked from commit 07c9532947a623a065d43ef5f69e530ca762f986)
-rw-r--r--rts/linker/BufferBuilder.c61
-rw-r--r--rts/linker/BufferBuilder.h37
-rw-r--r--rts/linker/JitObject.c11
-rw-r--r--rts/linker/JitObject.h8
-rw-r--r--rts/linker/JitObjectCoff.c47
-rw-r--r--rts/linker/JitObjectElf.c258
-rw-r--r--rts/rts.cabal.in8
7 files changed, 186 insertions, 244 deletions
diff --git a/rts/linker/BufferBuilder.c b/rts/linker/BufferBuilder.c
deleted file mode 100644
index 9f6ff04277..0000000000
--- a/rts/linker/BufferBuilder.c
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "Rts.h"
-#include "RtsUtils.h"
-#include "BufferBuilder.h"
-#include <string.h>
-
-struct BufferBuilder buffer_builder_new(size_t initial_sz)
-{
- uint8_t *buffer = stgMallocBytes(initial_sz, "new_buffer_builder");
- return (struct BufferBuilder) {
- .buffer = buffer,
- .head = buffer,
- .end = buffer + initial_sz,
- };
-}
-
-void buffer_builder_free(struct BufferBuilder *bb)
-{
- stgFree(bb->buffer);
- bb->buffer = NULL;
- bb->head = NULL;
- bb->end = NULL;
-}
-
-size_t buffer_builder_filled_size(struct BufferBuilder *bb)
-{
- return bb->head - bb->buffer;
-}
-
-size_t buffer_builder_reserved_size(struct BufferBuilder *bb)
-{
- return bb->end - bb->buffer;
-}
-
-void buffer_builder_realloc(struct BufferBuilder *bb, size_t new_sz)
-{
- size_t filled_sz = buffer_builder_filled_size(bb);
- ASSERT(filled_sz <= new_sz);
- uint8_t *buffer = stgReallocBytes(bb->buffer, new_sz, "new_buffer_builder");
- bb->buffer = buffer;
- bb->head = buffer + filled_sz;
- bb->end = buffer + new_sz;
-}
-
-uint8_t *buffer_builder_push(struct BufferBuilder *bb, uint8_t *x, size_t sz)
-{
- if (bb->head + sz > bb->end) {
- buffer_builder_realloc(bb, 2*buffer_builder_reserved_size(bb));
- }
-
- memcpy(bb->head, x, sz);
- uint8_t *ret = bb->head;
- bb->head += sz;
- return ret;
-}
-
-void buffer_builder_append(struct BufferBuilder *bb, struct BufferBuilder *src)
-{
- size_t sz = buffer_builder_filled_size(src);
- buffer_builder_push(bb, bb->buffer, sz);
-}
-
diff --git a/rts/linker/BufferBuilder.h b/rts/linker/BufferBuilder.h
deleted file mode 100644
index facccb8335..0000000000
--- a/rts/linker/BufferBuilder.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct BufferBuilder {
- uint8_t *buffer; // start of buffer
- uint8_t *head; // next unfilled byte
- uint8_t *end; // end of buffer
-};
-
-struct BufferBuilder buffer_builder_new(size_t initial_sz);
-void buffer_builder_free(struct BufferBuilder *bb);
-size_t buffer_builder_filled_size(struct BufferBuilder *bb);
-size_t buffer_builder_reserved_size(struct BufferBuilder *bb);
-void buffer_builder_realloc(struct BufferBuilder *bb, size_t new_sz);
-uint8_t *buffer_builder_push(struct BufferBuilder *bb, uint8_t *x, size_t sz);
-void buffer_builder_append(struct BufferBuilder *bb, struct BufferBuilder *src);
-
-#define buffer_builder_push_struct(bb, x) \
- (typeof(x)*) buffer_builder_push(bb, (uint8_t *) &x, sizeof(x))
-
-#define DEFINE_BUILDER(ty) \
- static inline ty ## _t* buffer_builder_ ## ty(struct BufferBuilder *bb, ty ## _t x) \
- { return (ty ## _t *) buffer_builder_push(bb, (uint8_t *) &x, sizeof(x)); }
-
-DEFINE_BUILDER(uint8);
-DEFINE_BUILDER(uint16);
-DEFINE_BUILDER(uint32);
-DEFINE_BUILDER(uint64);
-DEFINE_BUILDER(int8);
-DEFINE_BUILDER(int16);
-DEFINE_BUILDER(int32);
-DEFINE_BUILDER(int64);
-
-#undef DEFINE_BUILDER
-
diff --git a/rts/linker/JitObject.c b/rts/linker/JitObject.c
index 48652283b7..08c1bc987c 100644
--- a/rts/linker/JitObject.c
+++ b/rts/linker/JitObject.c
@@ -1,4 +1,3 @@
-#include "BufferBuilder.h"
#include "JitObject.h"
#include "LinkerInternals.h"
#include "RtsUtils.h"
@@ -46,13 +45,17 @@ struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
void register_jit_object(ObjectCode *oc)
{
- struct BufferBuilder buf = build_jit_object(oc);
+ struct JitObject obj = build_jit_object(oc);
+ if (obj.buffer == NULL) {
+ debugBelch("Failed to build JIT object for %s\n", OC_INFORMATIVE_FILENAME(oc));
+ return;
+ }
struct jit_code_entry *code_entry = stgMallocBytes(sizeof(struct jit_code_entry), "register_jit_object");
code_entry->next_entry = __jit_debug_descriptor.first_entry;
code_entry->prev_entry = NULL;
- code_entry->symfile_addr = (const char *) buf.buffer;
- code_entry->symfile_size = buffer_builder_filled_size(&buf);
+ code_entry->symfile_addr = (const char *) obj.buffer;
+ code_entry->symfile_size = obj.size;
__jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
__jit_debug_descriptor.first_entry = code_entry;
diff --git a/rts/linker/JitObject.h b/rts/linker/JitObject.h
index 1f21ee28c8..0b89674026 100644
--- a/rts/linker/JitObject.h
+++ b/rts/linker/JitObject.h
@@ -1,5 +1,9 @@
#include "LinkerInternals.h"
-#include "BufferBuilder.h"
+
+struct JitObject {
+ uint8_t *buffer;
+ size_t size;
+};
void register_jit_object(ObjectCode *oc);
-struct BufferBuilder build_jit_object(ObjectCode *oc);
+struct JitObject build_jit_object(ObjectCode *oc);
diff --git a/rts/linker/JitObjectCoff.c b/rts/linker/JitObjectCoff.c
deleted file mode 100644
index 77ce9fecc9..0000000000
--- a/rts/linker/JitObjectCoff.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "BufferBuilder.h"
-#include "JitObject.h"
-#include "LinkerInternals.h"
-#include "RtsUtils.h"
-
-struct BufferBuilder build_jit_object(ObjectCode *oc)
-{
- struct BufferBuilder bb = buffer_builder_new(4096);
-
- // COFF header
- buffer_builder_uint16(&bb, IMAGE_FILE_MACHINE_AMD64);
- buffer_builder_uint16(&bb, 1); // NumberOfSections
- buffer_builder_uint32(&bb, 0); // TimeDateStamp
- uint32_t *ptr_to_symbol_table = buffer_builder_uint32(&bb, 0); // PointerToSymbolTable
- buffer_builder_uint32(&bb, n_syms); // NumberOfSymbols
- buffer_builder_uint16(&bb, 0); // SizeOfOptionalHeader
- buffer_builder_uint16(&bb, 0); // Characteristics
-
- // Sections
- buffer_builder_push(&bb, ".text\0\0\0", 8); // Name
- buffer_builder_uint32(&bb, sect_sz); // VirtualSize
- buffer_builder_uint32(&bb, sect_base); // VirtualAddress
- buffer_builder_uint32(&bb, 0); // SizeOfRawData
- buffer_builder_uint32(&bb, 0); // PointerToRawData
- buffer_builder_uint32(&bb, 0); // PointerToRelocations
- buffer_builder_uint32(&bb, 0); // PointerToLinenumbers
- buffer_builder_uint16(&bb, 0); // NumberOfRelocations
- buffer_builder_uint16(&bb, 0); // NumberOfLinenumbers
- buffer_builder_uint32(&bb, 0); // Characteristics
-
- struct BufferBuilder strings = buffer_builder_new(4096);
- for (int i=0; i < oc->n_symbols; i++) {
- Symbol_t *sym = &oc->symbols[i];
- size_t offset = buffer_builder_filled_size(&strings);
- buffer_builder_push(&strings, sym->name, strlen(sym->name));
- buffer_builder_uint32(&bb, 0);
- buffer_builder_uint32(&bb, offset); // RawName index
- buffer_builder_uint32(&bb, value); // Value
- buffer_builder_uint16(&bb, 1); // SectionNumber
- buffer_builder_uint8(&bb, 0x20); // StorageClass
- buffer_builder_uint8(&bb, 0); // NumberOfAuxSymbols
- }
-
- buffer_builder_append(&bb, strings);
- return bb;
-}
-
diff --git a/rts/linker/JitObjectElf.c b/rts/linker/JitObjectElf.c
index 41653ad45e..37d042c0b2 100644
--- a/rts/linker/JitObjectElf.c
+++ b/rts/linker/JitObjectElf.c
@@ -1,4 +1,11 @@
-#include "BufferBuilder.h"
+/*
+ * GDB JIT object interface
+ *
+ * This module is responsible for generating and registering dummy interface
+ * files with gdb for reporting symbols loaded by GHC's runtime linker.
+ */
+
+#include "Rts.h"
#include "elf_compat.h"
#include "linker/Elf.h"
#include "JitObject.h"
@@ -7,99 +14,176 @@
#include <string.h>
-#define TEXT_SECTION_IDX 1
+#define CC WSTR("clang")
+
+struct temp_file {
+ pathchar *path;
+ FILE *handle;
+};
-struct BufferBuilder build_jit_object(ObjectCode *oc)
+static struct temp_file create_temp_file(pathchar *prefix, pathchar *suffix)
{
- struct BufferBuilder bb = buffer_builder_new(4096);
-
- // ELF header
- Elf64_Ehdr ehdr = {
- .e_ident = {
- ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
- ELFCLASS64,
- ELFDATA2LSB,
- EV_CURRENT,
- },
- .e_type = ET_REL,
- .e_machine = EM_386,
- .e_version = EV_CURRENT,
- .e_entry = 0,
- .e_phoff = 0,
- .e_shoff = 0, // will be filled in later
- .e_flags = 0,
- .e_ehsize = sizeof(Elf64_Ehdr),
- .e_phentsize = sizeof(Elf64_Phdr),
- .e_phnum = 0,
- .e_shentsize = sizeof(Elf64_Shdr),
- .e_shnum = 2,
- .e_shstrndx = 0,
- };
+#if defined(mingw32_HOST_OS)
+ // Windows doesn't have a sane temporary file interface that allows setting
+ // of a file suffix. Doing this correctly is quite tiresome so we instead
+ // use this hack since this is just a debugging facility.
+ GUID guid;
+ ZeroMemory(&guid, sizeof (guid));
+ if (CoCreateGuid(&guid) != S_OK) {
+ goto fail;
+ }
+
+ RPC_WSTR guid_str;
+ if (UuidToStringW ((UUID*)&guid, &guid_str) != S_OK) {
+ goto fail;
+ }
- Elf64_Ehdr *ehdr_ptr = buffer_builder_push_struct(&bb, ehdr);
-
- // String table
- struct BufferBuilder strings = buffer_builder_new(4096);
- buffer_builder_uint8(&strings, 0);
-
- // Section table
- struct BufferBuilder shtab = buffer_builder_new(4096);
- Elf64_Shdr shtab_zero_ent = {
- .sh_name = 0,
- .sh_type = SHT_NULL,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = SHN_UNDEF,
- .sh_info = 0,
- .sh_addralign = 0,
- .sh_entsize = 0,
+ size_t path_len = pathlen(prefix) + pathlen(guid_str) + pathlen(suffix) + 1;
+ CHECK(path_len < MAX_PATH);
+ pathchar *path = stgMallocBytes(sizeof(pathchar) * path_len, "create_temp_file");
+ pathcopy(path, prefix);
+ pathcopy(path + pathlen(path), guid_str);
+ pathcopy(path + pathlen(path), suffix);
+
+ FILE *handle = pathopen(path, WSTR("w+"));
+ if (handle == NULL) {
+ debugBelch("build_asm: Failed to create temporary file handle: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ return (struct temp_file) {
+ .path = path,
+ .handle = handle,
};
- buffer_builder_push_struct(&shtab, shtab_zero_ent);
-
- Elf64_Shdr shtab_text_ent = {
- .sh_name = 1,
- .sh_type = SHT_NULL,
- .sh_flags = SHF_ALLOC | SHF_EXECINSTR,
- .sh_addr = 0,
- .sh_offset = 0, // will be filled in later
- .sh_size = 0,
- .sh_link = SHN_UNDEF,
- .sh_info = 0,
- .sh_addralign = 0,
- .sh_entsize = 0,
+#else
+ size_t path_len = strlen(prefix) + 6 + strlen(suffix) + 1;
+ char *path = stgMallocBytes(path_len, "create_temp_file");
+ snprintf(path, path_len, "%sXXXXXX%s", prefix, suffix);
+
+ int fd = mkstemp(path);
+ if (fd == -1) {
+ debugBelch("build_asm: Failed to create temporary file: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ FILE *handle = fdopen(fd, "w+");
+ if (handle == NULL) {
+ debugBelch("build_asm: Failed to create temporary file handle: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ return (struct temp_file) {
+ .path = path,
+ .handle = handle,
};
- buffer_builder_push_struct(&shtab, shtab_zero_ent);
-
- // Symbol table
- struct BufferBuilder symtab = buffer_builder_new(4096);
- Elf64_Sym symtab_zero_ent = {
- .st_name = 0,
- .st_value = 0,
- .st_size = 0,
- .st_info = 0,
- .st_other = 0,
- .st_shndx = SHN_UNDEF,
+#endif
+
+fail:
+ return (struct temp_file) {
+ .path = NULL,
+ .handle = NULL,
};
- buffer_builder_push_struct(&symtab, symtab_zero_ent);
+}
+/* Returns path to assembler source file */
+static pathchar* build_asm(ObjectCode *oc)
+{
+ struct temp_file f = create_temp_file(WSTR("jit-object"), WSTR(".s"));
+ if (f.path == NULL) {
+ debugBelch("Failed to open JIT object source file: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ //fprintf(f.handle, ".text\n");
for (int i=0; i < oc->n_symbols; i++) {
- Symbol_t *sym = &oc->symbols[i];
- size_t sym_name_offset = buffer_builder_filled_size(&strings);
- buffer_builder_push(&strings, sym->name, strlen(sym->name)+1);
-
- Elf64_Sym symtab_ent = {
- .st_name = sym_name_offset,
- .st_value = hi,
- .st_size = 0,
- .st_info = 0,
- .st_other = 0,
- .st_shndx = TEXT_SECTION_IDX,
- };
- buffer_builder_push_struct(&symtab, symtab_ent);
- }
-
- return bb;
+ const Symbol_t *sym = &oc->symbols[i];
+ if (sym->name) {
+ fprintf(f.handle, ".global %s\n", sym->name);
+#if defined(OBJFORMAT_PEi386)
+ //fprintf(f.handle, ".def %s; .scl 2; .type 32; .endef\n", sym->name);
+#else
+ fprintf(f.handle, ".type %s, %%object\n", sym->name);
+#endif
+ fprintf(f.handle, ".set %s, 0x%" PRIxPTR "\n", sym->name, (uintptr_t) sym->addr);
+ }
+ }
+
+ fclose(f.handle);
+ return f.path;
}
+static ssize_t get_file_size(FILE *f) {
+ long orig_off = ftell(f);
+ if (orig_off == -1) {
+ return -1;
+ }
+ if (fseek(f, 0L, SEEK_END) == -1) {
+ return -1;
+ }
+ long sz = ftell(f);
+ if (sz == -1) {
+ return -1;
+ }
+
+ if (fseek(f, 0L, SEEK_SET) == -1) {
+ return -1;
+ }
+ return sz;
+}
+
+struct JitObject build_jit_object(ObjectCode *oc)
+{
+ pathchar *s_path = build_asm(oc);
+ if (s_path == NULL) {
+ goto fail;
+ }
+
+ struct temp_file f = create_temp_file(WSTR("jit-object"), WSTR(".o"));
+ if (f.path == NULL) {
+ debugBelch("build_jit_object: Failed to create temporary file: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ // Assemble it
+ const int sz = snprintf(NULL, 0, "%" PATH_FMT" -c %" PATH_FMT" -o %" PATH_FMT, CC, s_path, f.path);
+ char *cmdline = malloc(sz+1);
+ snprintf(cmdline, sz+1, "%" PATH_FMT " -c %" PATH_FMT " -o %" PATH_FMT, CC, s_path, f.path);
+ int ret = system(cmdline);
+ free(cmdline);
+ free(s_path);
+ free(f.path);
+
+ if (ret != 0) {
+ debugBelch("Error assembling JIT object (exit code %d)\n", ret);
+ fclose(f.handle);
+ goto fail;
+ }
+
+ // Read the resulting object
+ ssize_t o_size = get_file_size(f.handle);
+ if (o_size == -1) {
+ debugBelch("Error reading JIT object: %s\n", strerror(errno));
+ goto fail;
+ } else if (o_size == 0) {
+ debugBelch("Assembler produced empty object\n");
+ goto fail;
+ }
+
+ uint8_t *buffer = stgMallocBytes(o_size, "build_jit_object");
+ if (fread(buffer, 1, o_size, f.handle) != (size_t) o_size) {
+ debugBelch("Error reading JIT object: %s\n", strerror(errno));
+ goto fail;
+ }
+ fclose(f.handle);
+
+ return (struct JitObject) {
+ .buffer = buffer,
+ .size = o_size,
+ };
+
+fail:
+ return (struct JitObject) {
+ .buffer = NULL,
+ .size = 0,
+ };
+}
diff --git a/rts/rts.cabal.in b/rts/rts.cabal.in
index e2f0bf11fa..d69ed22c25 100644
--- a/rts/rts.cabal.in
+++ b/rts/rts.cabal.in
@@ -471,11 +471,8 @@ library
asm-sources: StgCRunAsm.S
-- gdb JIT object logic
- if os(mingw32)
- c-sources: linker/JitObjectCoff.c
- else
- if os(linux) || os(freebsd)
- c-sources: linker/JitObjectElf.c
+ if os(linux) || os(freebsd)
+ c-sources: linker/JitObjectElf.c
c-sources: Adjustor.c
adjustor/AdjustorPool.c
@@ -555,7 +552,6 @@ library
hooks/OnExit.c
hooks/OutOfHeap.c
hooks/StackOverflow.c
- linker/BufferBuilder.c
linker/CacheFlush.c
linker/Elf.c
linker/JitObject.c