138 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| #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;
 | |
| 	};
 | |
| 
 | |
| 	struct vla_bound_data
 | |
| 	{
 | |
| 		source_location location;
 | |
| 		const type_descriptor& type;
 | |
| 	};
 | |
| 
 | |
| 	enum builtin_check_kind : unsigned char
 | |
| 	{
 | |
| 		BCK_CTZPassedZero,
 | |
| 		BCK_CLZPassedZero,
 | |
| 	};
 | |
| 
 | |
| 	struct invalid_builtin_data
 | |
| 	{
 | |
| 		source_location location;
 | |
| 		builtin_check_kind kind;
 | |
| 	};
 | |
| 
 | |
| 	struct unreachable_data
 | |
| 	{
 | |
| 		struct source_location location;
 | |
| 	};
 | |
| 
 | |
| 	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)
 | |
| 
 | |
| 	HANDLER(__ubsan_handle_vla_bound_not_positive, false, vla_bound_data* data, value_handle);
 | |
| 
 | |
| 	HANDLER(__ubsan_handle_invalid_builtin, false, invalid_builtin_data* data);
 | |
| 
 | |
| 	HANDLER(__ubsan_handle_builtin_unreachable, true, unreachable_data* data);
 | |
| 
 | |
| 	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);
 | |
| 	}
 | |
| 
 | |
| }
 |