forked from Bananymous/banan-os
Kernel: Add ubsan
My brain has been melting since I'm getting very random bugs. I hope I can debug them better with ubsan :)
This commit is contained in:
parent
e480f9c195
commit
06db890d49
|
@ -18,6 +18,8 @@ export INCLUDEDIR=$PREFIX/include
|
||||||
export CFLAGS='-O2 -g'
|
export CFLAGS='-O2 -g'
|
||||||
export CPPFLAGS='--std=c++20'
|
export CPPFLAGS='--std=c++20'
|
||||||
|
|
||||||
|
export UBSAN=1
|
||||||
|
|
||||||
# Configure the cross-compiler to use the desired system root.
|
# Configure the cross-compiler to use the desired system root.
|
||||||
export SYSROOT="$(pwd)/sysroot"
|
export SYSROOT="$(pwd)/sysroot"
|
||||||
export CC="$CC --sysroot=$SYSROOT"
|
export CC="$CC --sysroot=$SYSROOT"
|
||||||
|
|
|
@ -27,6 +27,10 @@ CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
|
||||||
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
|
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
|
||||||
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
|
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
|
||||||
|
|
||||||
|
ifeq ($(UBSAN), 1)
|
||||||
|
CFLAGS:=$(CFLAGS) -fsanitize=undefined
|
||||||
|
endif
|
||||||
|
|
||||||
BUILDDIR=$(abspath build)
|
BUILDDIR=$(abspath build)
|
||||||
|
|
||||||
KERNEL_OBJS= \
|
KERNEL_OBJS= \
|
||||||
|
@ -58,6 +62,7 @@ kernel/Thread.o \
|
||||||
kernel/TTY.o \
|
kernel/TTY.o \
|
||||||
kernel/VesaTerminalDriver.o \
|
kernel/VesaTerminalDriver.o \
|
||||||
icxxabi.o \
|
icxxabi.o \
|
||||||
|
ubsan.o \
|
||||||
|
|
||||||
OBJS= \
|
OBJS= \
|
||||||
$(ARCHDIR)/crti.o \
|
$(ARCHDIR)/crti.o \
|
||||||
|
|
|
@ -47,9 +47,9 @@ MMU::MMU()
|
||||||
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and identity map first 4 MiB
|
// create and identity map first 6 MiB
|
||||||
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
|
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
|
||||||
for (uint64_t i = 0; i < 2; i++)
|
for (uint64_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
uint64_t* page_table = allocate_page_aligned_page();
|
uint64_t* page_table = allocate_page_aligned_page();
|
||||||
for (uint64_t j = 0; j < 512; j++)
|
for (uint64_t j = 0; j < 512; j++)
|
||||||
|
|
|
@ -118,9 +118,10 @@ enable_sse:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# identity map first 4 MiB
|
# identity map first 6 MiB
|
||||||
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
|
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
|
||||||
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
|
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
|
||||||
|
movl $(0x00400000 + 0x83), boot_page_directory1 + 16
|
||||||
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
|
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
|
||||||
|
|
||||||
# enable PAE
|
# enable PAE
|
||||||
|
|
|
@ -35,7 +35,7 @@ static uint64_t* allocate_page_aligned_page()
|
||||||
|
|
||||||
MMU::MMU()
|
MMU::MMU()
|
||||||
{
|
{
|
||||||
// Identity map from 4 KiB -> 4 MiB
|
// Identity map from 4 KiB -> 6 MiB
|
||||||
m_highest_paging_struct = allocate_page_aligned_page();
|
m_highest_paging_struct = allocate_page_aligned_page();
|
||||||
|
|
||||||
uint64_t* pdpt = allocate_page_aligned_page();
|
uint64_t* pdpt = allocate_page_aligned_page();
|
||||||
|
@ -44,7 +44,7 @@ MMU::MMU()
|
||||||
uint64_t* pd = allocate_page_aligned_page();
|
uint64_t* pd = allocate_page_aligned_page();
|
||||||
pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present;
|
pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 2; i++)
|
for (uint32_t i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
uint64_t* pt = allocate_page_aligned_page();
|
uint64_t* pt = allocate_page_aligned_page();
|
||||||
for (uint64_t j = 0; j < 512; j++)
|
for (uint64_t j = 0; j < 512; j++)
|
||||||
|
|
|
@ -41,9 +41,9 @@
|
||||||
# we will identity map first 4 MiB
|
# we will identity map first 4 MiB
|
||||||
|
|
||||||
# 0 MiB -> 1 MiB: bootloader stuff
|
# 0 MiB -> 1 MiB: bootloader stuff
|
||||||
# 1 MiB -> 2 MiB: kernel
|
# 1 MiB -> 4 MiB: kernel
|
||||||
# 2 MiB -> 3 MiB: kmalloc
|
# 4 MiB -> 5 MiB: kmalloc
|
||||||
# 3 MiB -> 4 MiB: kmalloc_fixed
|
# 5 MiB -> 6 MiB: kmalloc_fixed
|
||||||
.align 4096
|
.align 4096
|
||||||
boot_pml4:
|
boot_pml4:
|
||||||
.skip 512 * 8
|
.skip 512 * 8
|
||||||
|
@ -127,9 +127,10 @@ enable_sse:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
initialize_paging:
|
initialize_paging:
|
||||||
# identity map first 4 MiB
|
# identity map first 6 MiB
|
||||||
movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0
|
movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0
|
||||||
movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8
|
movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8
|
||||||
|
movl $(0x00400000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 16
|
||||||
|
|
||||||
# set pdpte1 and pml4e1
|
# set pdpte1 and pml4e1
|
||||||
movl $(boot_pd1 + PG_READ_WRITE + PG_PRESENT), boot_pdpt1
|
movl $(boot_pd1 + PG_READ_WRITE + PG_PRESENT), boot_pdpt1
|
||||||
|
|
|
@ -65,7 +65,7 @@ private:
|
||||||
static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align);
|
static_assert(sizeof(kmalloc_node) == s_kmalloc_min_align);
|
||||||
struct kmalloc_info
|
struct kmalloc_info
|
||||||
{
|
{
|
||||||
static constexpr uintptr_t base = 0x00200000;
|
static constexpr uintptr_t base = 0x00400000;
|
||||||
static constexpr size_t size = 1 * MB;
|
static constexpr size_t size = 1 * MB;
|
||||||
static constexpr uintptr_t end = base + size;
|
static constexpr uintptr_t end = base + size;
|
||||||
|
|
||||||
|
@ -313,11 +313,10 @@ void* kmalloc(size_t size, size_t align)
|
||||||
if (size == 0 || size >= info.size)
|
if (size == 0 || size >= info.size)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ASSERT(align);
|
|
||||||
ASSERT(is_power_of_two(align));
|
ASSERT(is_power_of_two(align));
|
||||||
|
|
||||||
// if the size fits into fixed node, we will try to use that since it is faster
|
// if the size fits into fixed node, we will try to use that since it is faster
|
||||||
if (align == s_kmalloc_min_align && size < sizeof(kmalloc_fixed_info::node::data))
|
if (align == s_kmalloc_min_align && size <= sizeof(kmalloc_fixed_info::node::data))
|
||||||
if (void* result = kmalloc_fixed())
|
if (void* result = kmalloc_fixed())
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
#include <kernel/Debug.h>
|
||||||
|
#include <kernel/Panic.h>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
struct source_location
|
||||||
|
{
|
||||||
|
const char *file;
|
||||||
|
uint32_t line;
|
||||||
|
uint32_t column;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_descriptor
|
||||||
|
{
|
||||||
|
uint16_t kind;
|
||||||
|
uint16_t info;
|
||||||
|
char name[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type_mismatch_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
const type_descriptor& type;
|
||||||
|
uint8_t alignment;
|
||||||
|
uint8_t type_check_kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct out_of_bounds_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
const type_descriptor& left_type;
|
||||||
|
const type_descriptor& right_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct shift_out_of_bounds_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
const type_descriptor& left_type;
|
||||||
|
const type_descriptor& right_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pointer_overflow_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct invalid_value_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
const type_descriptor& type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct overflow_data
|
||||||
|
{
|
||||||
|
source_location location;
|
||||||
|
const type_descriptor& type;
|
||||||
|
};
|
||||||
|
|
||||||
|
using value_handle = uintptr_t;
|
||||||
|
|
||||||
|
static const char* type_check_kinds[] = {
|
||||||
|
"load of", "store to", "reference binding to", "member access within",
|
||||||
|
"member call on", "constructor call on", "downcast of", "downcast of",
|
||||||
|
"upcast of", "cast to virtual base of", "_Nonnull binding to",
|
||||||
|
"dynamic operation on"
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HANDLER(handler, fatal, ...) \
|
||||||
|
void handler(__VA_ARGS__) \
|
||||||
|
{ \
|
||||||
|
if constexpr(fatal) \
|
||||||
|
Kernel::panic("{}:{} {}", data->location.file, data->location.line, __FUNCTION__); \
|
||||||
|
else \
|
||||||
|
derrorln("{}:{} {}", data->location.file, data->location.line, __FUNCTION__); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_location_impl(const source_location& location, const char* function)
|
||||||
|
{
|
||||||
|
derrorln("{}:{} {}", location.file, location.line, function);
|
||||||
|
}
|
||||||
|
#define print_location(location) print_location_impl(location, __FUNCTION__)
|
||||||
|
|
||||||
|
HANDLER(__ubsan_handle_pointer_overflow, false, pointer_overflow_data* data, value_handle, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_load_invalid_value, false, invalid_value_data* data, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_out_of_bounds, false, out_of_bounds_data* data, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_shift_out_of_bounds, false, shift_out_of_bounds_data* data, value_handle, value_handle)
|
||||||
|
|
||||||
|
HANDLER(__ubsan_handle_add_overflow, false, overflow_data* data, value_handle, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_sub_overflow, false, overflow_data* data, value_handle, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_mul_overflow, false, overflow_data* data, value_handle, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_divrem_overflow, false, overflow_data* data, value_handle, value_handle)
|
||||||
|
HANDLER(__ubsan_handle_negate_overflow, false, overflow_data* data, value_handle)
|
||||||
|
|
||||||
|
void __ubsan_handle_type_mismatch_v1(type_mismatch_data* data, value_handle pointer)
|
||||||
|
{
|
||||||
|
print_location(data->location);
|
||||||
|
const char* kind = type_check_kinds[data->type_check_kind];
|
||||||
|
uintptr_t alignment = (uintptr_t)1 << data->alignment;
|
||||||
|
if (!pointer)
|
||||||
|
derrorln("{} null pointer of type {}", kind, data->type.name);
|
||||||
|
else if (pointer & (alignment - 1))
|
||||||
|
derrorln("{} misaligned address {} for type {}, which requires {} byte alignment", kind, (void*)pointer, data->type.name, alignment);
|
||||||
|
else
|
||||||
|
derrorln("{} address {} with insufficient space for an object of type {}", kind, (void*)pointer, data->type.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue