This commit is contained in:
2025-09-27 15:16:26 +02:00
parent 5af7c5276a
commit 3b1bb9d531
63 changed files with 1087 additions and 407 deletions

View File

@ -14,6 +14,8 @@ SRCFILES := $(call GRABSRC, \
sync \
args \
util \
ubsan \
write \
)
CFLAGS += -isystem $(ROOT)/share -isystem $(ROOT)/ulib -isystem $(ROOT)/std/include \

View File

@ -2,10 +2,13 @@
#include <stddef.h>
#include <system/system.h>
#include <sysdefs/processctl.h>
#include <sysdefs/devctl.h>
#include <errors.h>
#include <dlmalloc/malloc.h>
#include <uprintf.h>
#include <log.h>
#include <util/util.h>
#include <devids.h>
extern void main(void);
extern uint8_t _bss_start[];
@ -18,24 +21,28 @@ void clearbss(void) {
}
}
char **_args;
#define MAX_ARGS 15
static char *_args[MAX_ARGS];
size_t _argslen;
char **args(void) {
return _args;
return (char **)_args;
}
size_t argslen(void) {
return _argslen;
}
Dev_t termdev;
// ulib initialization goes here
void _premain(void) {
clearbss();
#define MAX_ARGS 30
_args = (char **)dlmalloc(MAX_ARGS * sizeof(char *));
for (size_t i = 0; i < MAX_ARGS; i++) {
devctl(&termdev, DEVCTL_GET_HANDLE, (uint8_t *)DEV_TERMDEV, 0, 0);
for (size_t i = 0; i < ARRLEN(_args); i++) {
_args[i] = dlmalloc(PROC_ARG_MAX);
}

View File

@ -5,35 +5,89 @@
#include <string/conv.h>
#include <string/string.h>
#include <uprintf.h>
#include <errors.h>
int32_t parse_args(char **argv, size_t argc, Arg *defs) {
#define CONSUME_TK() i++
if (!argv || !defs) {
return E_INVALIDARGUMENT;
}
for (size_t i = 0; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] != '\0') {
char *optname = argv[i];
char *arg = argv[i];
if (!arg) {
continue;
}
if (arg[0] == '-' && arg[1] != '\0') {
size_t j = 0;
while (!defs[j].end) {
Arg *def = &defs[j];
if (string_strcmp(def->shortname, optname) == 0) {
if (i < argc - 1) {
switch (def->expected_value) {
case ARG_STRING:
*((char **)def->ptr) = argv[i+1];
break;
case ARG_BOOL:
*((bool *)def->ptr) = string_strcmp(argv[i+1], "yes") == 0;
break;
case ARG_INT: {
char *end;
*((int32_t *)def->ptr) = string_conv_strtol(argv[i+1], &end, 10);
} break;
}
i++;
}
if (!def->shortname || !def->ptr) {
j++;
continue;
}
if (string_strcmp(def->shortname, arg) == 0) {
bool have_next = (i + 1) < argc && argv[i + 1] != NULL;
char *nexttk = have_next ? argv[i + 1] : NULL;
if (nexttk && nexttk[0] == '-' && nexttk[1] != '\0') {
have_next = false;
nexttk = NULL;
}
switch (def->expected_value) {
case ARG_STRING:
if (!have_next) {
break;
}
*((char **)def->ptr) = nexttk;
CONSUME_TK();
break;
case ARG_BOOL:
if (!have_next) {
*((bool *)def->ptr) = true;
} else {
if (string_strcmp(nexttk, "yes") == 0) {
*((bool *)def->ptr) = true;
CONSUME_TK();
} else if (string_strcmp(nexttk, "no") == 0) {
*((bool *)def->ptr) = false;
CONSUME_TK();
} else {
*((bool *)def->ptr) = true;
}
}
break;
case ARG_INT:
if (!have_next) {
break;
}
char *endptr = NULL;
long val = string_conv_strtol(nexttk, &endptr, 10);
if (endptr == NULL) {
break;
}
if (*endptr != '\0') {
break;
}
*((int32_t *)def->ptr) = (int32_t)val;
CONSUME_TK();
break;
default:
break;
}
break;
}
j++;
}
}
}
return ARGP_OK;
return E_OK;
}

View File

@ -28,10 +28,6 @@ typedef struct {
#define ARG_END() ((Arg){ .end = true, })
enum {
ARGP_OK = 0,
};
int32_t parse_args(char **argv, size_t argc, Arg *defs);
#endif // ULIB_ARGS_H_

15
ulib/assert.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef ULIB_ASSERT_H_
#define ULIB_ASSERT_H_
#include <uprintf.h>
#include <util/util.h>
#define ASSERT(X, fmt, ...) \
do { \
if (!(X)) { \
uprintf("ASSERT %s:%d in %s "fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
quit(); \
} \
} while(0)
#endif // ULIB_ASSERT_H_

8
ulib/devids.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ULIB_DEVIDS_H_
#define ULIB_DEVIDS_H_
enum {
DEV_TERMDEV = 0x10,
};
#endif // ULIB_DEVIDS_H_

View File

@ -8,6 +8,7 @@
#include <string/string.h>
#include <sysdefs/mman.h>
#include <system/system.h>
#include <write/write.h>
#define USE_DL_PREFIX 1
#define LACKS_SYS_TYPES_H 1
@ -23,7 +24,7 @@
#define LACKS_SCHED_H 1
#define HAVE_MMAP 1
#define HAVE_MORECORE 0
#define ABORT uprintf("dlmalloc: Aborting...\n")
#define ABORT writefmt("dlmalloc: Aborting...\n")
#define MALLOC_FAILURE_ACTION
#define USE_LOCKS 2
#define malloc_getpagesize 0x1000
@ -61,8 +62,9 @@ static size_t _roundpage(size_t sz) {
#define O_RDWR 0
#define EMUL_DEV_ZERO_FD 123
#define EMUL_MAP_FAILED ((void *)-1)
int open(char *path, int flags) {
int open(const char *path, int flags, ...) {
return EMUL_DEV_ZERO_FD;
}
@ -73,7 +75,7 @@ void *mmap(void *addr, size_t len, int prot, int flags, int fd, int off) {
int32_t err = mman_map(NULL, need, MMAN_MAP_PF_RW, 0, &outaddr);
if (err != E_OK || outaddr == NULL) {
return NULL;
return EMUL_MAP_FAILED;
}
if (fd == EMUL_DEV_ZERO_FD) {

View File

@ -53,14 +53,14 @@
} while(0)
#define LL_FOREACH_SAFE(head, var, tmp) \
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
for (var = (head), tmp = (var ? var->next : NULL); \
var != NULL; \
var = tmp, tmp = (var ? var->next : NULL) \
)
#define LL_FOREACH_SAFE_IDX(head, var, tmp, idx) \
for (typeof(head) var = (head), tmp = (var ? var->next : NULL); \
var != NULL && ((idx) = 0, 1); \
for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
var != NULL; \
var = tmp, tmp = (var ? var->next : NULL), (idx)++)
#define LL_FOREACH_SAFE_IDX_LIMIT(head, var, tmp, idx, max) \

View File

@ -2,6 +2,7 @@
#define ULIB_LOG_H_
#include <uprintf.h>
#include <write/write.h>
enum {
LOG_ERR,
@ -12,6 +13,6 @@ enum {
static const char *_LOG_STR[] = { "ERROR", "DEBUG", "INFO", "WARNING" };
#define LOG(mode, fmt, ...) uprintf("%s: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
#define LOG(mode, fmt, ...) writefmt("{s}: "fmt, _LOG_STR[(mode)], ##__VA_ARGS__);
#endif // ULIB_LOG_H_

View File

@ -1,9 +1,11 @@
#include <stdint.h>
#include <system/system.h>
#include <sysdefs/ipcpipe.h>
#include <sysdefs/devctl.h>
#include <printf/printf.h>
extern Dev_t termdev;
void putchar_(char c) {
char buf = c;
ipcpipe(IPCPIPE_SELFPID, IPCPIPE_OUT, IPCPIPE_WRITE, (uint8_t *)&buf, sizeof(buf));
devctl(&termdev, 0x00, (uint8_t *)&c, 1, 0);
}

View File

@ -1,5 +1,6 @@
#include <stddef.h>
#include <string/string.h>
#include <dlmalloc/malloc.h>
size_t string_len(const char *s) {
size_t l = 0;
@ -130,3 +131,35 @@ int string_strncmp( const char * s1, const char * s2, size_t n )
return ( *(unsigned char *)s1 - *(unsigned char *)s2 );
}
}
#define STRING_TOKENIZEALLOC_TOK_SIZE 0xff
char *string_tokenizealloc(char *s, char *delim) {
static int curridx = 0;
if (!s || !delim || !s[curridx]) {
return NULL;
}
char *w = (char *)dlmalloc(sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
string_memset(w, 0, sizeof(char) * STRING_TOKENIZEALLOC_TOK_SIZE);
int i = curridx, k = 0, j = 0;
while (s[i] != '\0') {
j = 0;
while (delim[j] != '\0') {
if (s[i] != delim[j]) {
w[k] = s[i];
} else {
goto it;
}
j++;
}
i++;
k++;
}
it: {
w[i] = 0;
curridx = i + 1;
return w;
}
}

View File

@ -16,6 +16,7 @@ size_t string_strspn(const char *s, const char *accept);
char *string_strcpy(char *dest, const char *src);
char *string_strchr(const char *s, int c);
int string_strncmp(const char * s1, const char * s2, size_t n);
char *string_tokenizealloc(char *s, char *delim);
#endif

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include <uprintf.h>
uint64_t syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) {

View File

@ -5,6 +5,7 @@
#include <sysdefs/ioctl.h>
#include <sysdefs/processctl.h>
#include <sysdefs/ipcpipe.h>
#include <sysdefs/devctl.h>
#include <uprintf.h>
void debugprint(const char *string) {
@ -34,3 +35,7 @@ int32_t mman_unmap(uint8_t *addr) {
int32_t schedrelease(void) {
return syscall(SYS_SCHEDRELEASE, 0, 0, 0, 0, 0, 0);
}
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra) {
return syscall(SYS_DEVCTL, (uint64_t)devh, cmd, (uint64_t)buffer, (uint64_t)len, (uint64_t)extra, 0);
}

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#include <stddef.h>
#include <sysdefs/devctl.h>
void debugprint(const char *string);
int32_t ioctl(uint64_t ioh, uint64_t cmd, uint64_t arg1, uint64_t arg2, uint64_t arg3);
@ -11,5 +12,6 @@ int32_t ipcpipe(uint64_t pid, uint64_t pipenum, uint64_t cmd, uint8_t *buffer, s
int32_t mman_map(uint8_t *addr, size_t size, uint64_t prot, uint64_t flags, uint8_t **out);
int32_t mman_unmap(uint8_t *addr);
int32_t schedrelease(void);
int32_t devctl(Dev_t *devh, uint64_t cmd, uint8_t *buffer, size_t len, uint64_t extra);
#endif // ULIB_SYSTEM_SYSTEM_H_

224
ulib/ubsan/ubsan.c Normal file
View File

@ -0,0 +1,224 @@
// REFERENCES:
// https://wiki.osdev.org/Undefined_Behavior_Sanitization
#include <stdint.h>
#include <stddef.h>
#include <uprintf.h>
struct source_location {
const char *file;
uint32_t line;
uint32_t column;
};
struct type_descriptor {
uint16_t type_kind;
uint16_t type_info;
char *type_name;
};
struct type_mismatch_data {
struct source_location loc;
struct type_descriptor *type;
unsigned long alignment;
unsigned char type_check_kind;
};
struct type_mismatch_data_v1 {
struct source_location loc;
struct type_descriptor *type;
unsigned char alignment;
unsigned char type_check_kind;
};
struct overflow_data {
struct source_location loc;
struct type_descriptor *type;
};
struct shift_out_of_bounds_data {
struct source_location loc;
struct type_descriptor *lhs_type;
struct type_descriptor *rhs_type;
};
struct out_of_bounds_data {
struct source_location loc;
struct type_descriptor *array_type;
struct type_descriptor *index_type;
};
struct unreachable_data {
struct source_location loc;
};
struct vla_bound_data {
struct source_location loc;
struct type_descriptor *type;
};
struct invalid_value_data {
struct source_location loc;
struct type_descriptor *type;
};
struct nonnull_arg_data {
struct source_location loc;
};
struct nonnull_return_data {
struct source_location loc;
struct source_location attr_loc;
};
struct invalid_builtin_data {
struct source_location loc;
uint8_t kind;
};
struct pointer_overflow_data {
struct source_location loc;
};
static void ubsan_print(struct source_location *loc, const char *message)
{
uprintf("UBSAN error %s:%d:%d %s\n", loc->file, loc->line, loc->column, message);
}
void __ubsan_handle_add_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "addition overflow");
}
void __ubsan_handle_sub_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "subtraction overflow");
}
void __ubsan_handle_mul_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "multiplication overflow");
}
void __ubsan_handle_divrem_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "division overflow");
}
void __ubsan_handle_negate_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "negation overflow");
}
void __ubsan_handle_pointer_overflow(struct overflow_data *data)
{
ubsan_print(&data->loc, "pointer overflow");
}
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data)
{
ubsan_print(&data->loc, "shift out of bounds");
}
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data)
{
ubsan_print(&data->loc, "array out of bounds");
}
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data)
{
ubsan_print(&data->loc, "invalid load value");
}
void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, uintptr_t ptr)
{
if (ptr == (uintptr_t)NULL) {
ubsan_print(&data->loc, "null pointer access");
}
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
ubsan_print(&data->loc, "misaligned pointer is used");
}
else {
ubsan_print(&data->loc, "insufficient space for an object");
}
}
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, uintptr_t ptr)
{
if (ptr == (uintptr_t)NULL) {
ubsan_print(&data->loc, "null pointer access");
}
else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) {
ubsan_print(&data->loc, "misaligned pointer is used");
}
else {
ubsan_print(&data->loc, "insufficient space for an object");
}
}
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data)
{
ubsan_print(&data->loc, "variable-length argument out of bounds");
}
void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
{
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
}
void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data, struct source_location *loc)
{
ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified");
}
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
{
ubsan_print(&data->loc, "non-null argument is null");
}
void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
{
ubsan_print(&data->loc, "unreachable code reached");
}
void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
{
ubsan_print(&data->loc, "invalid builtin");
}
void __ubsan_handle_missing_return(struct unreachable_data *data)
{
ubsan_print(&data->loc, "missing return value");
}

View File

@ -13,6 +13,8 @@
#include <uprintf.h>
#include <linklist.h>
#include <log.h>
#include <assert.h>
#include <write/write.h>
#include <errors.h>
#include <sysdefs/ioctl.h>

View File

@ -5,11 +5,7 @@
#define ARRLEN(X) (sizeof((X))/sizeof((X)[0]))
#define ZERO(X) \
({ \
string_memset((X), 0, sizeof(*(X))); \
*(X); \
}) \
#define ZERO(X) string_memset((X), 0, sizeof(*(X)))
#define MIN(a, b) \
({ \

161
ulib/write/write.c Normal file
View File

@ -0,0 +1,161 @@
#include <stdarg.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <limits.h>
#include <system/system.h>
#include <sysdefs/devctl.h>
#include <write/write.h>
char *utoa(uintmax_t v, int base, bool uppercase) {
if (base < 2 || base > 36) {
return NULL;
}
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
size_t i = sizeof(buf) - 1;
buf[i] = '\0';
if (v == 0) {
buf[--i] = '0';
return &buf[i];
}
while (v != 0) {
if (i == 0) {
return NULL;
}
buf[--i] = digits[v % base];
v /= base;
}
return &buf[i];
}
char *itoa(intmax_t v, int base, bool uppercase) {
if (base < 2 || base > 36) {
return NULL;
}
static char buf[sizeof(uintmax_t) * CHAR_BIT + 3];
const char *digits = uppercase ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz";
size_t i = sizeof(buf) - 1;
buf[i] = '\0';
if (v == 0) {
buf[--i] = '0';
return &buf[i];
}
bool neg = (v < 0);
uintmax_t u;
if (neg) {
u = (uintmax_t)(-(v + 1)) + 1;
} else {
u = (uintmax_t)v;
}
while (u != 0) {
if (i == 0) {
return NULL;
}
buf[--i] = digits[u % base];
u /= base;
}
if (neg) {
if (i == 0) {
return NULL;
}
buf[--i] = '-';
}
return &buf[i];
}
#define FMTBUF_MAX 2048
extern Dev_t termdev;
enum {
WRITE_FORMATMODE,
WRITE_NORMALMODE,
};
const char *convstr1 = "0123456789abcdef";
const char *convstr2 = "0123456789ABCDEF";
void writefmt(char *fmt, ...) {
va_list list;
va_start(list, fmt);
writevfmt(fmt, list);
va_end(list);
}
#define ITOA_BUF_SIZE 32
void writevsfmt(char *buf, char *fmt, va_list list) {
size_t c = 0;
int WRITE_STATE = WRITE_NORMALMODE;
for (size_t i = 0; fmt[i] != '\0'; i++) {
if (WRITE_STATE == WRITE_NORMALMODE) {
switch (fmt[i]) {
case '{':
WRITE_STATE = WRITE_FORMATMODE;
break;
default:
buf[c++] = fmt[i];
break;
}
} else if (WRITE_STATE == WRITE_FORMATMODE) {
switch (fmt[i]) {
case '}':
WRITE_STATE = WRITE_NORMALMODE;
break;
case 's': {
char *string = va_arg(list, char *);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'd': {
int int1 = va_arg(list, int);
char *string = itoa(int1, 10, false);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'x': {
unsigned int int1 = va_arg(list, unsigned int);
char *string = utoa(int1, 16, false);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'X': {
unsigned int int1 = va_arg(list, unsigned int);
char *string = utoa(int1, 16, true);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'p': {
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
char *string = utoa(ptr, 16, false);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'P': {
uintptr_t ptr = (uintptr_t)va_arg(list, void *);
char *string = utoa(ptr, 16, true);
while (*string) { buf[c++] = *string; string++; }
} break;
case 'c': {
char c1 = (char)va_arg(list, char);
buf[c++] = c1;
} break;
}
}
}
}
void writevfmt(char *fmt, va_list list) {
char buf[FMTBUF_MAX];
writevsfmt(buf, fmt, list);
devctl(&termdev, 0x00, buf, sizeof(buf), 0);
}

10
ulib/write/write.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef ULIB_WRITE_WRITE_H_
#define ULIB_WRITE_WRITE_H_
#include <stdarg.h>
void writefmt(char *fmt, ...);
void writevfmt(char *fmt, va_list list);
void writevsfmt(char *buf, char *fmt, va_list list);
#endif // ULIB_WRITE_WRITE_H_