loader retrieve stack bounds from /proc/self/maps

This commit is contained in:
flysand7 2023-08-29 18:57:34 +11:00
parent 7929779df6
commit 653342a30a
7 changed files with 244 additions and 9 deletions

View File

@ -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

View File

@ -16,3 +16,4 @@
#define O_FSYNC O_SYNC
#define O_ASYNC 020000
#define O_CLOEXEC 02000000
#define O_DIRECT 040000

View File

@ -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);
}

View File

@ -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];

224
loader/stack.c Normal file
View File

@ -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;
}

View File

@ -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
}
}

View File

@ -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);