summaryrefslogtreecommitdiff
path: root/tools/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/common.c')
-rw-r--r--tools/common.c427
1 files changed, 427 insertions, 0 deletions
diff --git a/tools/common.c b/tools/common.c
new file mode 100644
index 0000000..00f7d3c
--- /dev/null
+++ b/tools/common.c
@@ -0,0 +1,427 @@
+#define START "_start"
+#include <crt_arch.h>
+#include <bits/syscall.h.in>
+#include <syscall_arch.h>
+
+#include <stdarg.h>
+
+#include "common.h"
+
+enum {
+ flush_on_newline = 1
+};
+
+int errno = 0;
+char *progname;
+
+static long sysret(unsigned long r)
+{
+ if (r > -4096UL) {
+ errno = -r;
+ return -1;
+ }
+ return r;
+}
+
+void exit(int code)
+{
+ __syscall1(__NR_exit, code);
+}
+
+static void *brk(void *addr)
+{
+ return (void *)__syscall1(__NR_brk, (long)addr);
+}
+
+int write(int fd, char *buf, int len)
+{
+ return sysret(__syscall3(__NR_write, fd, (long)buf, len));
+}
+
+int read(int fd, char *buf, int len)
+{
+ return sysret(__syscall3(__NR_read, fd, (long)buf, len));
+}
+
+int open(char *fname, int flags, int mode)
+{
+ int o_largefile = 0100000;
+ return sysret(__syscall3(__NR_open, (long)fname,
+ flags|o_largefile, mode));
+}
+
+int stat(char *fname, struct stat *st)
+{
+ return sysret(__syscall2(__NR_stat, (long)fname, (long)st));
+}
+
+int fstat(int fd, struct stat *st)
+{
+ return sysret(__syscall2(__NR_fstat, (long)fd, (long)st));
+}
+
+int close(int fd)
+{
+ return sysret(__syscall1(__NR_close, fd));
+}
+
+void *mmap(char *addr, unsigned long length, int prot, int flags, int fd,
+ unsigned long offset)
+{
+ return (void*)sysret(__syscall6(__NR_mmap, (long)addr, length,
+ prot, flags, fd, offset));
+}
+
+int munmap(char *addr, int length)
+{
+ return sysret(__syscall2(__NR_munmap, (long)addr, length));
+}
+
+#define MREMAP_MAYMOVE 1
+
+int mremap(void *old_addr, unsigned long old_size, unsigned long new_size,
+ int flags, void *new_addr)
+{
+ return sysret(__syscall5(__NR_mremap, (long)old_addr, old_size,
+ new_size, flags, (long)new_addr));
+}
+
+int strzlen(char *s)
+{
+ char *sc = s;
+ for (; *s; ++s)
+ ;
+ return s - sc;
+}
+
+int strzeq(char *s1, char *s2)
+{
+ for (; *s1 && *s1 == *s2; ++s1, ++s2)
+ ;
+ return *s1 == 0 && *s2 == 0;
+}
+
+int streq(struct str *s1, struct str *s2)
+{
+ int i;
+ if (s1->end - s1->start != s2->end - s2->start)
+ return 0;
+ for (i = 0; s1->start + i < s1->end; ++i) {
+ if (s1->start[i] != s2->start[i])
+ return 0;
+ }
+ return 1;
+}
+
+void memmove(char *dest, char *src, int len)
+{
+ int i;
+ if (dest < src) {
+ for (i = 0; i < len; ++i)
+ dest[i] = src[i];
+ } else {
+ for (i = len - 1; i >= 0; --i)
+ dest[i] = src[i];
+ }
+}
+
+void memcpy(void *dest, void *src, int len)
+{
+ int i;
+ char *d = dest;
+ char *s = src;
+ for (i = 0; i < len; ++i)
+ d[i] = s[i];
+}
+
+void memset(void *dest, char c, int len)
+{
+ char *tmp = dest;
+ for (; tmp < (char*)dest + len; ++tmp)
+ *tmp = c;
+}
+
+#define E(e, s) [e] = s,
+
+char *estrings[256] = {
+#include "../src/errno/__strerror.h"
+};
+#undef E
+
+void perror(char *s)
+{
+ int idx = errno;
+ if (errno > 256 || estrings[errno] == NULL)
+ idx = 0;
+ eprintf("%s: %s\n", s, estrings[idx]);
+}
+
+void syscall_error(char *fname)
+{
+ perror(fname);
+ hexit(1);
+}
+
+enum {
+ buflen = 32 * 1024
+};
+
+struct iobuf {
+ int fd;
+ char buf[buflen];
+ int len;
+};
+
+struct iobuf stdout = { 1 };
+struct iobuf stderr = { 2 };
+
+static void flush(struct iobuf *buf)
+{
+ int ret = write(buf->fd, buf->buf, buf->len);
+ if (ret != buf->len) {
+ write(2, _S("some stdout/stderr error\n"));
+ exit(3);
+ }
+ buf->len = 0;
+}
+
+static void putchar(struct iobuf *buf, char c)
+{
+ if (buf->len == buflen)
+ flush(buf);
+ buf->buf[buf->len] = c;
+ ++buf->len;
+
+ if (flush_on_newline && c == '\n')
+ flush(buf);
+}
+
+void hexit(int code)
+{
+ flush(&stdout);
+ flush(&stderr);
+ exit(code);
+}
+
+static void print_int(struct iobuf *buf, int nsigned, int byte4,
+ unsigned long n)
+{
+ char tmpbuf[64];
+ char *p = tmpbuf;
+ unsigned long k;
+
+ if (nsigned) {
+ if (byte4) {
+ int tmp = n;
+ if (tmp < 0) {
+ putchar(buf, '-');
+ tmp = -tmp;
+ }
+ k = tmp;
+ } else {
+ if ((signed long)n < 0) {
+ putchar(buf, '-');
+ n = -n;
+ }
+ k = n;
+ }
+ } else {
+ k = n;
+ }
+
+ if (k == 0) {
+ putchar(buf, '0');
+ return;
+ }
+
+ for (; k > 0; k /= 10) {
+ *p = k % 10 + '0';
+ ++p;
+ }
+ for (--p;; --p) {
+ putchar(buf, *p);
+ if (p == tmpbuf)
+ break;
+ }
+}
+
+void print_strz(struct iobuf *buf, char *s)
+{
+ for (; *s; ++s)
+ putchar(buf, *s);
+}
+
+void print_str(struct iobuf *buf, struct str *s)
+{
+ char *tmp = s->start;
+ for (; tmp != s->end; ++tmp)
+ putchar(buf, *tmp);
+}
+
+static void format(struct iobuf *buf, char c, va_list vl)
+{
+ switch(c) {
+ unsigned long arg;
+ case '%':
+ putchar(buf, '%');
+ break;
+ case 'd':
+ case 'u':
+ arg = va_arg(vl, unsigned int);
+ print_int(buf, c == 'd', 1, arg);
+ break;
+ case 'D':
+ case 'U':
+ arg = va_arg(vl, unsigned long);
+ print_int(buf, c == 'D', 0, arg);
+ break;
+ case 's':
+ print_strz(buf, va_arg(vl, char*));
+ break;
+ case 'S':
+ print_str(buf, va_arg(vl, struct str *));
+ break;
+ case 'c':
+ arg = va_arg(vl, int);
+ putchar(buf, arg);
+ break;
+ default:
+ write(2, _S("printf: unexpected format option \n"));
+ hexit(2);
+ }
+}
+
+static void __printf(struct iobuf *buf, char *s, va_list vl)
+{
+ for (; *s; ++s) {
+ if (*s == '%') {
+ if (s[1] == 0) {
+ write(2, _S("printf: nothing comes after '%'"));
+ hexit(2);
+ }
+ format(buf, s[1], vl);
+ ++s;
+ } else {
+ putchar(buf, *s);
+ }
+ }
+ return;
+}
+
+void printf(char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ __printf(&stdout, fmt, vl);
+ va_end(vl);
+}
+
+void evprintf(char *fmt, va_list vl)
+{
+ print_strz(&stderr, progname);
+ print_strz(&stderr, ": ");
+ __printf(&stderr, fmt, vl);
+}
+
+void eprintf(char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ evprintf(fmt, vl);
+ va_end(vl);
+}
+
+/* Memory management */
+
+struct mem_buffer {
+ char *cur, *end;
+ char *saved;
+};
+
+static struct mem_buffer mem_buf;
+
+static void mem_buffer_init()
+{
+ mem_buf.cur = mem_buf.end = brk(NULL);
+ mem_buf.saved = NULL;
+}
+
+void save_heap_offset()
+{
+ if (mem_buf.saved != NULL) {
+ eprintf("mem_buffer: offset already saved\n");
+ hexit(2);
+ }
+ mem_buf.saved = mem_buf.cur;
+}
+
+void restore_heap_offset()
+{
+ if (mem_buf.saved == NULL) {
+ eprintf("mem_buffer: no offset was saved\n");
+ hexit(2);
+ }
+ mem_buf.cur = mem_buf.saved;
+ mem_buf.saved = NULL;
+}
+
+static int get_alignment(int n)
+{
+ if (n >= 16)
+ return 16;
+ if (n >= 8)
+ return 8;
+ if (n >= 4)
+ return 4;
+ if (n >= 2)
+ return 2;
+ return 1;
+}
+
+static void mem_buf_grow(int size)
+{
+ char *tmp;
+ if (size < 128*1024) {
+ size = 128*1024;
+ } else {
+ size *= 2;
+ size &= -4096;
+ }
+ /*printf("Growing (%d)\n", size);*/
+ tmp = brk(mem_buf.end + size);
+ if (tmp == mem_buf.end) {
+ eprintf("mem_buf: unable to allocate memory\n");
+ hexit(1);
+ }
+ mem_buf.end = tmp;
+}
+
+#define ALIGN(v, align) \
+ (void*)(((unsigned long)(v) + (align) - 1ul) & -(align))
+
+void *malloc(int size)
+{
+ int align = get_alignment(size);
+ char *tmp = ALIGN(mem_buf.cur, align);
+ int diff = tmp + size - mem_buf.end;
+
+ if (diff > 0)
+ mem_buf_grow(diff);
+
+ mem_buf.cur = tmp + size;
+ return tmp;
+}
+
+int main(int argc, char **argv, char **envp);
+
+void _start_c(unsigned long *p)
+{
+ int argc = p[0];
+ char **argv = (void *)(p + 1);
+ char **envp = argv + argc + 1;
+
+ progname = argv[0];
+ mem_buffer_init();
+
+ hexit(main(argc, argv, envp));
+}