1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #define pr_fmt(fmt) "UBSAN: " fmt |
4 | |
5 | #include "mos/syslog/printk.h" |
6 | |
7 | #include <mos/types.h> |
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 | struct source_location location; |
28 | struct type_descriptor *type; |
29 | ptr_t alignment; |
30 | u8 type_check_kind; |
31 | }; |
32 | |
33 | struct out_of_bounds_info |
34 | { |
35 | struct source_location location; |
36 | struct type_descriptor *array_type; |
37 | struct type_descriptor *index_type; |
38 | }; |
39 | |
40 | struct unreachable_data |
41 | { |
42 | struct source_location location; |
43 | }; |
44 | |
45 | static void log_location(struct source_location *location) |
46 | { |
47 | pr_emerg(" in file %s:%u, column %u" , location->file, location->line, location->column); |
48 | } |
49 | |
50 | void __ubsan_handle_type_mismatch(struct type_mismatch_info *type_mismatch, ptr_t pointer) |
51 | { |
52 | struct 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 | void __ubsan_handle_pointer_overflow(struct source_location *location, ptr_t pointer) |
65 | { |
66 | pr_emerg("pointer overflow, pointer=%p" , (void *) pointer); |
67 | log_location(location); |
68 | } |
69 | |
70 | void __ubsan_handle_type_mismatch_v1(struct type_mismatch_info *type_mismatch, ptr_t pointer) |
71 | { |
72 | __ubsan_handle_type_mismatch(type_mismatch, pointer); |
73 | } |
74 | |
75 | void __ubsan_handle_divrem_overflow(struct source_location *location, struct 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 | void __ubsan_handle_mul_overflow(struct source_location *location, struct 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 | void __ubsan_handle_add_overflow(struct source_location *location, struct 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 | void __ubsan_handle_sub_overflow(struct source_location *location, struct 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 | void __ubsan_handle_out_of_bounds(struct out_of_bounds_info *out_of_bounds) |
100 | { |
101 | struct 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 | void __ubsan_handle_negate_overflow(struct source_location *location, struct 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 | void __ubsan_handle_negate_overflow_v1(struct source_location *location, struct type_descriptor *type, ptr_t old_value) |
113 | { |
114 | __ubsan_handle_negate_overflow(location, type, old_value); |
115 | } |
116 | |
117 | void __ubsan_handle_load_invalid_value(struct source_location *location, struct type_descriptor *type, ptr_t value) |
118 | { |
119 | pr_emerg("load invalid value at address %p, value %p of type %s" , (void *) location, (void *) value, type->name); |
120 | log_location(location); |
121 | } |
122 | |
123 | void __ubsan_handle_shift_out_of_bounds(struct source_location *location, struct type_descriptor *lhs_type, ptr_t lhs, struct type_descriptor *rhs_type, ptr_t rhs) |
124 | { |
125 | pr_emerg("shift out of bounds, lhs=(%s) %p, rhs=(%s) %p" , lhs_type->name, (void *) lhs, rhs_type->name, (void *) rhs); |
126 | log_location(location); |
127 | } |
128 | |
129 | void __ubsan_handle_invalid_builtin(struct source_location *location) |
130 | { |
131 | pr_emerg("invalid builtin" ); |
132 | log_location(location); |
133 | } |
134 | |
135 | void __ubsan_handle_vla_bound_not_positive(struct source_location *location, struct type_descriptor *type, ptr_t bound) |
136 | { |
137 | pr_emerg("VLA bound not positive, bound=%p of type %s" , (void *) bound, type->name); |
138 | log_location(location); |
139 | } |
140 | |
141 | void __ubsan_handle_builtin_unreachable(struct unreachable_data *data) |
142 | { |
143 | pr_emerg("builtin unreachable was reached" ); |
144 | log_location(location: &data->location); |
145 | } |
146 | |