From 653342a30a98c83dd3af3b20bb593aab24f94ac4 Mon Sep 17 00:00:00 2001 From: flysand7 Date: Tue, 29 Aug 2023 18:57:34 +1100 Subject: [PATCH] loader retrieve stack bounds from /proc/self/maps --- arch/sysv_x86-64/loader-entry.asm | 2 +- include/linux/fcntl.h | 1 + include/linux/sys/syscall.h | 6 +- loader/loader.c | 10 ++ loader/stack.c | 224 ++++++++++++++++++++++++++++++ src/cia-sync/mutex.c | 6 +- tests/threaded.c | 4 - 7 files changed, 244 insertions(+), 9 deletions(-) create mode 100644 loader/stack.c diff --git a/arch/sysv_x86-64/loader-entry.asm b/arch/sysv_x86-64/loader-entry.asm index 9759162..5bf0b3b 100644 --- a/arch/sysv_x86-64/loader-entry.asm +++ b/arch/sysv_x86-64/loader-entry.asm @@ -14,5 +14,5 @@ _dlstart: ; `call` pushes 8-byte value onto the stack ; by pushing an 8-bit value ourselves we can make ; sure the stack is aligned after rbp push in prologue - sub rsp, 8 + push 0 diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index ce21075..0df76e0 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -16,3 +16,4 @@ #define O_FSYNC O_SYNC #define O_ASYNC 020000 #define O_CLOEXEC 02000000 +#define O_DIRECT 040000 \ No newline at end of file diff --git a/include/linux/sys/syscall.h b/include/linux/sys/syscall.h index 9cef5ec..ac10214 100644 --- a/include/linux/sys/syscall.h +++ b/include/linux/sys/syscall.h @@ -380,15 +380,15 @@ static inline i64 _syscall6(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5, i64 a #define SYS_rt_tgsigqueueinfo 297 #define SYS_perf_event_open 298 -static inline i64 sys_read(u32 fd, char *buf, u64 count) { +static inline i32 sys_read(u32 fd, char *buf, u64 count) { return syscall(SYS_read, fd, buf, count); } -static inline i64 sys_write(u32 fd, char const *buf, u64 count) { +static inline i32 sys_write(u32 fd, char const *buf, u64 count) { return syscall(SYS_write, fd, buf, count); } -static inline i64 sys_open(char const *filename, int flags, int mode) { +static inline i32 sys_open(char const *filename, int flags, int mode) { return syscall(SYS_open, filename, flags, mode); } diff --git a/loader/loader.c b/loader/loader.c index ead5367..c406d93 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -20,6 +20,8 @@ #include "../src/cia-mem/arena.c" #include "../src/cia-mem/pool.c" +#include "stack.c" + struct Elf_Image typedef Elf_Image; struct Elf_Image { Cia_Arena arena; @@ -148,6 +150,14 @@ void loader_entry(Loader_Info *ld_info) { if(fd != 0) { sys_close(fd); } + // Get the information about the main thread stack + if(linux_read_stack_info()) { + printf("ERROR: failed to read /proc/self/maps to get the stack info\n"); + sys_exit(1); + } + _dbg_printf("Received stack: %x-%x\n", stack_info.start_addr, stack_info.end_addr); + u64 *ptr = (void *)stack_info.start_addr; + // *ptr = 1245; // Find .dynamic section { u8 *phdr = (void *)aux[AT_PHDR]; diff --git a/loader/stack.c b/loader/stack.c new file mode 100644 index 0000000..1f7a188 --- /dev/null +++ b/loader/stack.c @@ -0,0 +1,224 @@ + +#define VM_READ 0x00000001 +#define VM_WRITE 0x00000002 +#define VM_EXEC 0x00000004 +#define VM_SHARED 0x00000008 + +struct File_Buffer typedef File_Buffer; +struct File_Buffer { + int fd; + char *data; + u64 data_size; + u64 last_read_size; + u64 offset; + int last_char; +}; + +struct Stack_Info typedef Stack_Info; +struct Stack_Info { + bool stack_found; + u64 start_addr; + u64 end_addr; + u32 flags; +}; + +static Stack_Info stack_info; + +static int read_char(File_Buffer *buffer) { + // If we need to read more stuff, fetch it from the file + if(buffer->offset >= buffer->last_read_size) { + int result = sys_read(buffer->fd, buffer->data, buffer->data_size); + if(result < 0) { + _dbg_printf("result < 0"); + return -1; + } + if(result == 0) { + buffer->last_char = -1; + return buffer->last_char; + } + int read_size = result; + buffer->data[read_size] = 0; + buffer->last_read_size = read_size; + buffer->offset = 0; + } + // Return the character from a buffer + u64 cur_offset = buffer->offset; + buffer->offset += 1; + buffer->last_char = buffer->data[cur_offset]; + _dbg_printf("%c", buffer->last_char); + return buffer->last_char; +} + +static int char_is_hex(int ch) { + if('0' <= ch && ch <= '9') return 1; + if('a' <= ch && ch <= 'f') return 1; + if('A' <= ch && ch <= 'F') return 1; + return 0; +} + +static int char_to_hex(int ch) { + if(ch <= '9') { + return ch - '0'; + } + return ch - 'a' + 10; +} + +static int read_hex(File_Buffer *buffer, u64 *out_result) { + u64 result = 0; + int n_digits = 0; + for(;;) { + int ch = buffer->last_char; + if(!char_is_hex(ch)) { + break; + } + result *= 16; + result += char_to_hex(ch); + read_char(buffer); + n_digits += 1; + } + *out_result = result; + if(n_digits == 0) { + return -1; + } + return 0; +} + +static int read_dec(File_Buffer *buffer, u64 *out_result) { + u64 result = 0; + int n_digits = 0; + for(;;) { + int ch = buffer->last_char; + if(!('0' <= ch && ch <= '9')) { + break; + } + result *= 10; + result += ch - '0'; + read_char(buffer); + n_digits += 1; + } + *out_result = result; + if(n_digits == 0) { + return -1; + } + return 0; +} + +static int linux_read_stack_info() { + bool stack_found = false; + // Initialize the buffer for buffered read + char line_buf[1024]; + File_Buffer buffer; + buffer.data = line_buf; + buffer.data_size = sizeof line_buf; + buffer.last_read_size = 0; + buffer.offset = 0; + // Open the file + buffer.fd = (i32)(u32)sys_open("/proc/self/maps", 0, O_RDONLY); + _dbg_printf("/proc/self/maps fd: %d\n", (i64)(i32)buffer.fd); + if((i64)(i32)buffer.fd < 0) { + return -1; + } + // Read the first character + if(read_char(&buffer) < 0) { + _dbg_printf("\nERROR: (/proc/self/maps) Failed reading char at offset %x\n", buffer.offset); + return -1; + } + // Start reading the lines until we hit the stack + char desired_name[] = "[stack]"; + while(!stack_found && buffer.last_char != -1) { + // If we're doing n-th iteration, consume the newline + if(buffer.last_char == '\n') { + read_char(&buffer); + } + // Read the start and end addr of the section + u64 start_addr = 0; + u64 end_addr = 0; + if(read_hex(&buffer, &start_addr)) { + _dbg_printf("|\nERROR: read_hex failed to read start_addr\n"); + return -1; + } + if(buffer.last_char != '-') { + _dbg_printf("|\nERROR: expected '-', didn't see it\n"); + return -1; + } + if(read_char(&buffer) < 0) { + _dbg_printf("|\nERROR: read_char failed after saw '-'\n"); + return -1; + } + if(read_hex(&buffer, &end_addr) < 0) { + _dbg_printf("|\nERROR: read_hex failed to read end_addr\n"); + return -1; + } + // Skip whitespace + if(read_char(&buffer) < 0) { + _dbg_printf("|\nERROR: read_char failed skipping whitespace after addrs\n"); + return -1; + } + // Read the flags + u32 flags = 0; + if(buffer.last_char == 'r') { + flags |= VM_READ; + } + read_char(&buffer); + if(buffer.last_char == 'w') { + flags |= VM_WRITE; + } + read_char(&buffer); + if(buffer.last_char == 'x') { + flags |= VM_EXEC; + } + read_char(&buffer); + if(buffer.last_char == 's') { + flags |= VM_SHARED; + } + read_char(&buffer); + // Skip 15 characters corresponding to `offset` and `device` fields + for(int i = 0; i != 16; ++i) { + read_char(&buffer); + } + // Read `inode` field + u64 inode = 0; + if(read_dec(&buffer, &inode)) { + _dbg_printf("|\nERROR reading inode field: %c\n", buffer.last_char); + return -1; + } + // If the line terminates here, skip this line + if(buffer.last_char == '\n' || buffer.last_char == -1) { + continue; + } + // Skip whitespace + while(buffer.last_char == ' ') { + read_char(&buffer); + } + // Read the name of the mapping + char name_buf[256]; + u64 name_buf_size = sizeof name_buf; + int name_len = 0; + while(name_len < name_buf_size && buffer.last_char != '\n' && buffer.last_char != -1) + { + name_buf[name_len] = buffer.last_char; + read_char(&buffer); + ++name_len; + } + name_buf[name_len] = 0; + // If the name is '[stack]' we pass the check and save the info + if(name_len != 7) { + continue; + } + for(int i = 0; i < 7; ++i) { + if(name_buf[i] != desired_name[i]) { + continue; + } + } + // We found the stack! + stack_info.stack_found = true; + stack_info.start_addr = start_addr; + stack_info.end_addr = end_addr; + stack_info.flags = flags; + sys_close(buffer.fd); + _dbg_printf("\nFound stack: %x-%x\n", start_addr, end_addr); + return 0; + } + sys_close(buffer.fd); + return 1; +} diff --git a/src/cia-sync/mutex.c b/src/cia-sync/mutex.c index 3dd9b48..71d08a0 100644 --- a/src/cia-sync/mutex.c +++ b/src/cia-sync/mutex.c @@ -15,9 +15,10 @@ void cia_mutex_lock(Cia_Mutex *mutex) { if(prev_tag == _CIA_MUTEX_FREE) { break; } +#if 0 // We should wait if: // (1) the mutex is contested - // (2) this thread locking the mutex makes it contested + // (2) bool should_wait = 0; should_wait |= (prev_tag == _CIA_MUTEX_CONT); should_wait |= (__sync_val_compare_and_swap(&mutex->tag, _CIA_MUTEX_LOCK, _CIA_MUTEX_CONT) != _CIA_MUTEX_FREE); @@ -25,6 +26,9 @@ void cia_mutex_lock(Cia_Mutex *mutex) { if(should_wait) { _rt_sync_wait(&mutex->tag, _CIA_MUTEX_CONT, _RT_SYNC_WAIT_INFINITE); } +#else + _rt_sync_wait(&mutex->tag, _CIA_MUTEX_LOCK, _RT_SYNC_WAIT_INFINITE); +#endif } } diff --git a/tests/threaded.c b/tests/threaded.c index bd5ed48..12dab2b 100644 --- a/tests/threaded.c +++ b/tests/threaded.c @@ -44,8 +44,6 @@ int thrd_func(void *arg) { for(int i = 0; i < 100000; ++i) { cia_mutex_lock(&g_mutex); counter += 1; - print_int(counter); - print_char('\n'); cia_mutex_unlock(&g_mutex); } atomic_fetch_add(&n_completed, 1); @@ -77,8 +75,6 @@ int main() { for(int i = 0; i < 100000; ++i) { cia_mutex_lock(&g_mutex); counter += 1; - print_int(counter); - print_char('\n'); cia_mutex_unlock(&g_mutex); } atomic_fetch_add(&n_completed, 1);