diff options
-rw-r--r-- | rts/linker/BufferBuilder.c | 61 | ||||
-rw-r--r-- | rts/linker/BufferBuilder.h | 37 | ||||
-rw-r--r-- | rts/linker/JitObject.c | 11 | ||||
-rw-r--r-- | rts/linker/JitObject.h | 8 | ||||
-rw-r--r-- | rts/linker/JitObjectCoff.c | 47 | ||||
-rw-r--r-- | rts/linker/JitObjectElf.c | 258 | ||||
-rw-r--r-- | rts/rts.cabal.in | 8 |
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 |