| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #define pr_fmt(fmt) "UBSAN: " fmt |
| 4 | |
| 5 | #include "mos/syslog/printk.hpp" |
| 6 | |
| 7 | #include <mos/types.hpp> |
| 8 | |
| 9 | #undef mos_panic |
| 10 | |
| 11 | struct source_location |
| 12 | { |
| 13 | const char *file; |
| 14 | u32 line; |
| 15 | u32 column; |
| 16 | }; |
| 17 | |
| 18 | struct type_descriptor |
| 19 | { |
| 20 | u16 kind; |
| 21 | u16 info; |
| 22 | char name[]; |
| 23 | }; |
| 24 | |
| 25 | struct type_mismatch_info |
| 26 | { |
| 27 | source_location location; |
| 28 | type_descriptor *type; |
| 29 | ptr_t alignment; |
| 30 | u8 type_check_kind; |
| 31 | }; |
| 32 | |
| 33 | struct out_of_bounds_info |
| 34 | { |
| 35 | source_location location; |
| 36 | type_descriptor *array_type; |
| 37 | type_descriptor *index_type; |
| 38 | }; |
| 39 | |
| 40 | struct unreachable_data |
| 41 | { |
| 42 | source_location location; |
| 43 | }; |
| 44 | |
| 45 | static void log_location(source_location *location) |
| 46 | { |
| 47 | pr_emerg(" in file %s:%u, column %u" , location->file, location->line, location->column); |
| 48 | } |
| 49 | |
| 50 | MOSAPI void __ubsan_handle_type_mismatch(type_mismatch_info *type_mismatch, ptr_t pointer) |
| 51 | { |
| 52 | source_location *location = &type_mismatch->location; |
| 53 | pr_emerg(); |
| 54 | if (pointer == 0) |
| 55 | pr_emerg("NULL pointer access" ); |
| 56 | else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment)) |
| 57 | pr_emerg("unaligned memory access" ); // Most useful on architectures with stricter memory alignment requirements, like ARM. |
| 58 | else |
| 59 | pr_emerg("insufficient size" ); |
| 60 | pr_emerg("kind=%d, address %p, for object of type %s" , type_mismatch->type_check_kind, (void *) pointer, type_mismatch->type->name); |
| 61 | log_location(location); |
| 62 | } |
| 63 | |
| 64 | MOSAPI void __ubsan_handle_pointer_overflow(source_location *location, ptr_t pointer) |
| 65 | { |
| 66 | pr_emerg("pointer overflow, pointer=%p" , (void *) pointer); |
| 67 | log_location(location); |
| 68 | } |
| 69 | |
| 70 | MOSAPI void __ubsan_handle_type_mismatch_v1(type_mismatch_info *type_mismatch, ptr_t pointer) |
| 71 | { |
| 72 | __ubsan_handle_type_mismatch(type_mismatch, pointer); |
| 73 | } |
| 74 | |
| 75 | MOSAPI void __ubsan_handle_divrem_overflow(source_location *location, type_descriptor *type, ptr_t left, ptr_t right) |
| 76 | { |
| 77 | pr_emerg("division overflow, left=%p, right=%p of type %s" , (void *) left, (void *) right, type->name); |
| 78 | log_location(location); |
| 79 | } |
| 80 | |
| 81 | MOSAPI void __ubsan_handle_mul_overflow(source_location *location, type_descriptor *type, ptr_t left, ptr_t right) |
| 82 | { |
| 83 | pr_emerg("multiplication overflow, left=%p, right=%p of type %s" , (void *) left, (void *) right, type->name); |
| 84 | log_location(location); |
| 85 | } |
| 86 | |
| 87 | MOSAPI void __ubsan_handle_add_overflow(source_location *location, type_descriptor *type, ptr_t left, ptr_t right) |
| 88 | { |
| 89 | pr_emerg("addition overflow, left=%p, right=%p of type %s" , (void *) left, (void *) right, type->name); |
| 90 | log_location(location); |
| 91 | } |
| 92 | |
| 93 | MOSAPI void __ubsan_handle_sub_overflow(source_location *location, type_descriptor *type, ptr_t left, ptr_t right) |
| 94 | { |
| 95 | pr_emerg("subtraction overflow, left=%p, right=%p of type %s" , (void *) left, (void *) right, type->name); |
| 96 | log_location(location); |
| 97 | } |
| 98 | |
| 99 | MOSAPI void __ubsan_handle_out_of_bounds(out_of_bounds_info *out_of_bounds) |
| 100 | { |
| 101 | source_location *location = &out_of_bounds->location; |
| 102 | pr_emerg("out of bounds, array type %s, index type %s" , out_of_bounds->array_type->name, out_of_bounds->index_type->name); |
| 103 | log_location(location); |
| 104 | } |
| 105 | |
| 106 | MOSAPI void __ubsan_handle_negate_overflow(source_location *location, type_descriptor *type, ptr_t old_value) |
| 107 | { |
| 108 | pr_emerg("negate overflow, old value %p of type %s" , (void *) old_value, type->name); |
| 109 | log_location(location); |
| 110 | } |
| 111 | |
| 112 | MOSAPI void __ubsan_handle_negate_overflow_v1(source_location *location, type_descriptor *type, ptr_t old_value) |
| 113 | { |
| 114 | __ubsan_handle_negate_overflow(location, type, old_value); |
| 115 | } |
| 116 | |
| 117 | MOSAPI void __ubsan_handle_load_invalid_value(void *data, ptr_t value) |
| 118 | { |
| 119 | pr_emerg("load invalid value at %p of value %llu" , data, value); |
| 120 | } |
| 121 | |
| 122 | MOSAPI void __ubsan_handle_shift_out_of_bounds(source_location *location, type_descriptor *lhs_type, ptr_t lhs, type_descriptor *rhs_type, ptr_t rhs) |
| 123 | { |
| 124 | pr_emerg("shift out of bounds, lhs=(%s) %p, rhs=(%s) %p" , lhs_type->name, (void *) lhs, rhs_type->name, (void *) rhs); |
| 125 | log_location(location); |
| 126 | } |
| 127 | |
| 128 | MOSAPI void __ubsan_handle_invalid_builtin(source_location *location) |
| 129 | { |
| 130 | pr_emerg("invalid builtin" ); |
| 131 | log_location(location); |
| 132 | } |
| 133 | |
| 134 | MOSAPI void __ubsan_handle_vla_bound_not_positive(source_location *location, type_descriptor *type, ptr_t bound) |
| 135 | { |
| 136 | pr_emerg("VLA bound not positive, bound=%p of type %s" , (void *) bound, type->name); |
| 137 | log_location(location); |
| 138 | } |
| 139 | |
| 140 | MOSAPI void __ubsan_handle_builtin_unreachable(unreachable_data *data) |
| 141 | { |
| 142 | pr_emerg("builtin unreachable was reached" ); |
| 143 | log_location(location: &data->location); |
| 144 | } |
| 145 | |