mb/google/brya: Create rull variant
[coreboot2.git] / src / lib / ubsan.c
blob560493cfc21199c8b2a4411b43c1a5c5e0ed3d20
1 /* SPDX-License-Identifier: ISC */
2 /* ubsan/ubsan.c
3 * Undefined behavior sanitizer runtime support.
5 * Adapted from:
6 * https://gitlab.com/sortix/sortix/raw/master/libc/ubsan/ubsan.c
8 * Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
12 #include <stdint.h>
13 #include <console/console.h>
15 struct ubsan_source_location {
16 const char *filename;
17 uint32_t line;
18 uint32_t column;
21 struct ubsan_type_descriptor {
22 uint16_t type_kind;
23 uint16_t type_info;
24 char type_name[];
27 typedef uintptr_t ubsan_value_handle_t;
30 * Keep the compiler happy -- it wants prototypes but nobody
31 * except the compiler should be touching these functions.
33 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
35 static void __noreturn ubsan_abort(const struct ubsan_source_location *location,
36 const char *violation) {
37 static const struct ubsan_source_location unknown_location = {
38 "<unknown file>",
43 if (!location || !location->filename)
44 location = &unknown_location;
45 printk(BIOS_ERR, "%s %s:%lu:%lu\n", violation, location->filename,
46 (unsigned long int)location->line,
47 (unsigned long int)location->column);
48 die("ubsan: unrecoverable error.\n");
51 #define ABORT_VARIANT(name, params, call) \
52 __noreturn void __ubsan_handle_##name##_abort params; \
53 __noreturn void __ubsan_handle_##name##_abort params { \
54 __ubsan_handle_##name call; \
55 __builtin_unreachable(); \
58 #define ABORT_VARIANT_VP(name) \
59 ABORT_VARIANT(name, (void *a), (a))
60 #define ABORT_VARIANT_VP_VP(name) \
61 ABORT_VARIANT(name, (void *a, void *b), (a, b))
62 #define ABORT_VARIANT_VP_IP(name) \
63 ABORT_VARIANT(name, (void *a, intptr_t b), (a, b))
64 #define ABORT_VARIANT_VP_VP_VP(name) \
65 ABORT_VARIANT(name, (void *a, void *b, void *c), (a, b, c))
67 struct ubsan_type_mismatch_data {
68 struct ubsan_source_location location;
69 struct ubsan_type_descriptor *type;
70 uintptr_t alignment;
71 unsigned char type_check_kind;
74 void __ubsan_handle_type_mismatch_v1(void *data_raw, void *pointer_raw)
76 const struct ubsan_type_mismatch_data *data =
77 (struct ubsan_type_mismatch_data *)data_raw;
78 ubsan_value_handle_t pointer = (ubsan_value_handle_t)pointer_raw;
79 const char *violation = "type mismatch";
80 if (!pointer)
81 violation = "null pointer access";
82 else if (data->alignment && (pointer & (data->alignment - 1)))
83 violation = "unaligned access";
84 ubsan_abort(&data->location, violation);
87 ABORT_VARIANT_VP_VP(type_mismatch_v1);
89 struct ubsan_overflow_data {
90 struct ubsan_source_location location;
91 struct ubsan_type_descriptor *type;
94 void __ubsan_handle_add_overflow(void *data_raw, void *lhs_raw,
95 void *rhs_raw)
97 const struct ubsan_overflow_data *data
98 = (struct ubsan_overflow_data *)data_raw;
99 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
100 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
101 (void)lhs;
102 (void)rhs;
103 ubsan_abort(&data->location, "addition overflow");
106 ABORT_VARIANT_VP_VP_VP(add_overflow);
108 void __ubsan_handle_sub_overflow(void *data_raw, void *lhs_raw,
109 void *rhs_raw)
111 const struct ubsan_overflow_data *data
112 = (struct ubsan_overflow_data *)data_raw;
113 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
114 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
115 (void)lhs;
116 (void)rhs;
117 ubsan_abort(&data->location, "subtraction overflow");
120 ABORT_VARIANT_VP_VP_VP(sub_overflow);
122 void __ubsan_handle_mul_overflow(void *data_raw, void *lhs_raw,
123 void *rhs_raw)
125 const struct ubsan_overflow_data *data
126 = (struct ubsan_overflow_data *)data_raw;
127 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
128 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
129 (void)lhs;
130 (void)rhs;
131 ubsan_abort(&data->location, "multiplication overflow");
134 ABORT_VARIANT_VP_VP_VP(mul_overflow);
136 void __ubsan_handle_negate_overflow(void *data_raw, void *old_value_raw)
138 const struct ubsan_overflow_data *data
139 = (struct ubsan_overflow_data *)data_raw;
140 ubsan_value_handle_t old_value
141 = (ubsan_value_handle_t)old_value_raw;
142 (void) old_value;
143 ubsan_abort(&data->location, "negation overflow");
146 ABORT_VARIANT_VP_VP(negate_overflow);
148 void __ubsan_handle_divrem_overflow(void *data_raw, void *lhs_raw,
149 void *rhs_raw)
151 const struct ubsan_overflow_data *data
152 = (struct ubsan_overflow_data *)data_raw;
153 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
154 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
155 (void)lhs;
156 (void)rhs;
157 ubsan_abort(&data->location, "division remainder overflow");
160 ABORT_VARIANT_VP_VP_VP(divrem_overflow);
162 struct ubsan_pointer_overflow_data {
163 struct ubsan_source_location location;
166 void __ubsan_handle_pointer_overflow(void *data_raw, void *base_raw, void *result_raw)
168 const struct ubsan_pointer_overflow_data *data =
169 (struct ubsan_pointer_overflow_data *)data_raw;
170 ubsan_value_handle_t base = (ubsan_value_handle_t)base_raw;
171 ubsan_value_handle_t result = (ubsan_value_handle_t)result_raw;
172 (void)base;
173 (void)result;
174 ubsan_abort(&data->location, "pointer overflow");
177 ABORT_VARIANT_VP_VP_VP(pointer_overflow);
179 struct ubsan_shift_out_of_bounds_data {
180 struct ubsan_source_location location;
181 struct ubsan_type_descriptor *lhs_type;
182 struct ubsan_type_descriptor *rhs_type;
185 void __ubsan_handle_shift_out_of_bounds(void *data_raw, void *lhs_raw,
186 void *rhs_raw)
188 const struct ubsan_shift_out_of_bounds_data *data =
189 (struct ubsan_shift_out_of_bounds_data *)data_raw;
190 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
191 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
192 (void)lhs;
193 (void)rhs;
194 ubsan_abort(&data->location, "shift out of bounds");
197 ABORT_VARIANT_VP_VP_VP(shift_out_of_bounds);
199 struct ubsan_out_of_bounds_data {
200 struct ubsan_source_location location;
201 struct ubsan_type_descriptor *array_type;
202 struct ubsan_type_descriptor *index_type;
205 void __ubsan_handle_out_of_bounds(void *data_raw, void *index_raw)
207 const struct ubsan_out_of_bounds_data *data =
208 (struct ubsan_out_of_bounds_data *)data_raw;
209 ubsan_value_handle_t index = (ubsan_value_handle_t)index_raw;
210 (void)index;
211 ubsan_abort(&data->location, "out of bounds");
214 ABORT_VARIANT_VP_VP(out_of_bounds);
216 struct ubsan_unreachable_data {
217 struct ubsan_source_location location;
220 void __noreturn __ubsan_handle_builtin_unreachable(void *data_raw)
222 struct ubsan_unreachable_data *data =
223 (struct ubsan_unreachable_data *)data_raw;
224 ubsan_abort(&data->location, "reached unreachable");
227 void __noreturn __ubsan_handle_missing_return(void *data_raw)
229 const struct ubsan_unreachable_data *data =
230 (struct ubsan_unreachable_data *)data_raw;
231 ubsan_abort(&data->location, "missing return");
234 struct ubsan_vla_bound_data {
235 struct ubsan_source_location location;
236 struct ubsan_type_descriptor *type;
239 void __ubsan_handle_vla_bound_not_positive(void *data_raw, void *bound_raw)
241 const struct ubsan_vla_bound_data *data
242 = (struct ubsan_vla_bound_data *)data_raw;
243 ubsan_value_handle_t bound = (ubsan_value_handle_t)bound_raw;
244 (void)bound;
245 ubsan_abort(&data->location, "negative variable array length");
248 ABORT_VARIANT_VP_VP(vla_bound_not_positive);
250 struct ubsan_float_cast_overflow_data {
251 struct ubsan_source_location location;
252 struct ubsan_type_descriptor *from_type;
253 struct ubsan_type_descriptor *to_type;
256 void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw)
258 struct ubsan_float_cast_overflow_data *data =
259 (struct ubsan_float_cast_overflow_data *)data_raw;
260 ubsan_value_handle_t from = (ubsan_value_handle_t)from_raw;
261 (void) from;
262 ubsan_abort(&data->location, "float cast overflow");
265 ABORT_VARIANT_VP_VP(float_cast_overflow);
267 struct ubsan_invalid_value_data {
268 struct ubsan_source_location location;
269 struct ubsan_type_descriptor *type;
272 void __ubsan_handle_load_invalid_value(void *data_raw, void *value_raw)
274 const struct ubsan_invalid_value_data *data =
275 (struct ubsan_invalid_value_data *)data_raw;
276 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
277 (void)value;
278 ubsan_abort(&data->location, "invalid value load");
281 ABORT_VARIANT_VP_VP(load_invalid_value);
283 struct ubsan_function_type_mismatch_data {
284 struct ubsan_source_location location;
285 struct ubsan_type_descriptor *type;
288 void __ubsan_handle_function_type_mismatch(void *data_raw, void *value_raw)
290 const struct ubsan_function_type_mismatch_data *data =
291 (struct ubsan_function_type_mismatch_data *)data_raw;
292 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
293 (void)value;
294 ubsan_abort(&data->location, "function type mismatch");
297 ABORT_VARIANT_VP_VP(function_type_mismatch);
299 struct ubsan_nonnull_return_data {
300 struct ubsan_source_location location;
301 struct ubsan_source_location attr_location;
304 void __ubsan_handle_nonnull_return(void *data_raw)
306 const struct ubsan_nonnull_return_data *data =
307 (struct ubsan_nonnull_return_data *)data_raw;
308 ubsan_abort(&data->location, "null return");
311 ABORT_VARIANT_VP(nonnull_return);
313 struct ubsan_nonnull_arg_data {
314 struct ubsan_source_location location;
315 struct ubsan_source_location attr_location;
319 * TODO: GCC's libubsan does not have the second parameter, but its builtin
320 * somehow has it and conflict if we don't match it.
322 void __ubsan_handle_nonnull_arg(void *data_raw, intptr_t index_raw)
324 const struct ubsan_nonnull_arg_data *data =
325 (struct ubsan_nonnull_arg_data *)data_raw;
326 ubsan_value_handle_t index = (ubsan_value_handle_t)index_raw;
327 (void)index;
328 ubsan_abort(&data->location, "null argument");
331 ABORT_VARIANT_VP_IP(nonnull_arg);
333 struct ubsan_cfi_bad_icall_data {
334 struct ubsan_source_location location;
335 struct ubsan_type_descriptor *type;
338 void __ubsan_handle_cfi_bad_icall(void *data_raw, void *value_raw)
340 static const char *abort_text
341 = "cfi: integrity failure during indirect call.";
342 const struct ubsan_cfi_bad_icall_data *data =
343 (struct ubsan_cfi_bad_icall_data *)data_raw;
344 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
345 (void)value;
346 ubsan_abort(&data->location, abort_text);
349 ABORT_VARIANT_VP_VP(cfi_bad_icall);