soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / lib / ubsan.c
blob1037b1b17ac0b2ebf83c8454fac90f2fb2710ba7
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
7 */
9 #include <stdint.h>
10 #include <console/console.h>
12 struct ubsan_source_location {
13 const char *filename;
14 uint32_t line;
15 uint32_t column;
18 struct ubsan_type_descriptor {
19 uint16_t type_kind;
20 uint16_t type_info;
21 char type_name[];
24 typedef uintptr_t ubsan_value_handle_t;
27 * Keep the compiler happy -- it wants prototypes but nobody
28 * except the compiler should be touching these functions.
30 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
32 static void __noreturn ubsan_abort(const struct ubsan_source_location *location,
33 const char *violation) {
34 static const struct ubsan_source_location unknown_location = {
35 "<unknown file>",
40 if (!location || !location->filename)
41 location = &unknown_location;
42 printk(BIOS_ERR, "%s %s:%lu:%lu\n", violation, location->filename,
43 (unsigned long int)location->line,
44 (unsigned long int)location->column);
45 die("ubsan: unrecoverable error.\n");
48 #define ABORT_VARIANT(name, params, call) \
49 __noreturn void __ubsan_handle_##name##_abort params; \
50 __noreturn void __ubsan_handle_##name##_abort params { \
51 __ubsan_handle_##name call; \
52 __builtin_unreachable(); \
55 #define ABORT_VARIANT_VP(name) \
56 ABORT_VARIANT(name, (void *a), (a))
57 #define ABORT_VARIANT_VP_VP(name) \
58 ABORT_VARIANT(name, (void *a, void *b), (a, b))
59 #define ABORT_VARIANT_VP_IP(name) \
60 ABORT_VARIANT(name, (void *a, intptr_t b), (a, b))
61 #define ABORT_VARIANT_VP_VP_VP(name) \
62 ABORT_VARIANT(name, (void *a, void *b, void *c), (a, b, c))
64 struct ubsan_type_mismatch_data {
65 struct ubsan_source_location location;
66 struct ubsan_type_descriptor *type;
67 uintptr_t alignment;
68 unsigned char type_check_kind;
71 void __ubsan_handle_type_mismatch_v1(void *data_raw, void *pointer_raw)
73 const struct ubsan_type_mismatch_data *data =
74 (struct ubsan_type_mismatch_data *)data_raw;
75 ubsan_value_handle_t pointer = (ubsan_value_handle_t)pointer_raw;
76 const char *violation = "type mismatch";
77 if (!pointer)
78 violation = "null pointer access";
79 else if (data->alignment && (pointer & (data->alignment - 1)))
80 violation = "unaligned access";
81 ubsan_abort(&data->location, violation);
84 ABORT_VARIANT_VP_VP(type_mismatch_v1);
86 struct ubsan_overflow_data {
87 struct ubsan_source_location location;
88 struct ubsan_type_descriptor *type;
91 void __ubsan_handle_add_overflow(void *data_raw, void *lhs_raw,
92 void *rhs_raw)
94 const struct ubsan_overflow_data *data
95 = (struct ubsan_overflow_data *)data_raw;
96 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
97 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
98 (void)lhs;
99 (void)rhs;
100 ubsan_abort(&data->location, "addition overflow");
103 ABORT_VARIANT_VP_VP_VP(add_overflow);
105 void __ubsan_handle_sub_overflow(void *data_raw, void *lhs_raw,
106 void *rhs_raw)
108 const struct ubsan_overflow_data *data
109 = (struct ubsan_overflow_data *)data_raw;
110 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
111 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
112 (void)lhs;
113 (void)rhs;
114 ubsan_abort(&data->location, "subtraction overflow");
117 ABORT_VARIANT_VP_VP_VP(sub_overflow);
119 void __ubsan_handle_mul_overflow(void *data_raw, void *lhs_raw,
120 void *rhs_raw)
122 const struct ubsan_overflow_data *data
123 = (struct ubsan_overflow_data *)data_raw;
124 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
125 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
126 (void)lhs;
127 (void)rhs;
128 ubsan_abort(&data->location, "multiplication overflow");
131 ABORT_VARIANT_VP_VP_VP(mul_overflow);
133 void __ubsan_handle_negate_overflow(void *data_raw, void *old_value_raw)
135 const struct ubsan_overflow_data *data
136 = (struct ubsan_overflow_data *)data_raw;
137 ubsan_value_handle_t old_value
138 = (ubsan_value_handle_t)old_value_raw;
139 (void) old_value;
140 ubsan_abort(&data->location, "negation overflow");
143 ABORT_VARIANT_VP_VP(negate_overflow);
145 void __ubsan_handle_divrem_overflow(void *data_raw, void *lhs_raw,
146 void *rhs_raw)
148 const struct ubsan_overflow_data *data
149 = (struct ubsan_overflow_data *)data_raw;
150 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
151 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
152 (void)lhs;
153 (void)rhs;
154 ubsan_abort(&data->location, "division remainder overflow");
157 ABORT_VARIANT_VP_VP_VP(divrem_overflow);
159 struct ubsan_pointer_overflow_data {
160 struct ubsan_source_location location;
163 void __ubsan_handle_pointer_overflow(void *data_raw, void *base_raw, void *result_raw)
165 const struct ubsan_pointer_overflow_data *data =
166 (struct ubsan_pointer_overflow_data *)data_raw;
167 ubsan_value_handle_t base = (ubsan_value_handle_t)base_raw;
168 ubsan_value_handle_t result = (ubsan_value_handle_t)result_raw;
169 (void)base;
170 (void)result;
171 ubsan_abort(&data->location, "pointer overflow");
174 ABORT_VARIANT_VP_VP_VP(pointer_overflow);
176 struct ubsan_shift_out_of_bounds_data {
177 struct ubsan_source_location location;
178 struct ubsan_type_descriptor *lhs_type;
179 struct ubsan_type_descriptor *rhs_type;
182 void __ubsan_handle_shift_out_of_bounds(void *data_raw, void *lhs_raw,
183 void *rhs_raw)
185 const struct ubsan_shift_out_of_bounds_data *data =
186 (struct ubsan_shift_out_of_bounds_data *)data_raw;
187 ubsan_value_handle_t lhs = (ubsan_value_handle_t)lhs_raw;
188 ubsan_value_handle_t rhs = (ubsan_value_handle_t)rhs_raw;
189 (void)lhs;
190 (void)rhs;
191 ubsan_abort(&data->location, "shift out of bounds");
194 ABORT_VARIANT_VP_VP_VP(shift_out_of_bounds);
196 struct ubsan_out_of_bounds_data {
197 struct ubsan_source_location location;
198 struct ubsan_type_descriptor *array_type;
199 struct ubsan_type_descriptor *index_type;
202 void __ubsan_handle_out_of_bounds(void *data_raw, void *index_raw)
204 const struct ubsan_out_of_bounds_data *data =
205 (struct ubsan_out_of_bounds_data *)data_raw;
206 ubsan_value_handle_t index = (ubsan_value_handle_t)index_raw;
207 (void)index;
208 ubsan_abort(&data->location, "out of bounds");
211 ABORT_VARIANT_VP_VP(out_of_bounds);
213 struct ubsan_unreachable_data {
214 struct ubsan_source_location location;
217 void __noreturn __ubsan_handle_builtin_unreachable(void *data_raw)
219 struct ubsan_unreachable_data *data =
220 (struct ubsan_unreachable_data *)data_raw;
221 ubsan_abort(&data->location, "reached unreachable");
224 void __noreturn __ubsan_handle_missing_return(void *data_raw)
226 const struct ubsan_unreachable_data *data =
227 (struct ubsan_unreachable_data *)data_raw;
228 ubsan_abort(&data->location, "missing return");
231 struct ubsan_vla_bound_data {
232 struct ubsan_source_location location;
233 struct ubsan_type_descriptor *type;
236 void __ubsan_handle_vla_bound_not_positive(void *data_raw, void *bound_raw)
238 const struct ubsan_vla_bound_data *data
239 = (struct ubsan_vla_bound_data *)data_raw;
240 ubsan_value_handle_t bound = (ubsan_value_handle_t)bound_raw;
241 (void)bound;
242 ubsan_abort(&data->location, "negative variable array length");
245 ABORT_VARIANT_VP_VP(vla_bound_not_positive);
247 struct ubsan_float_cast_overflow_data {
248 struct ubsan_source_location location;
249 struct ubsan_type_descriptor *from_type;
250 struct ubsan_type_descriptor *to_type;
253 void __ubsan_handle_float_cast_overflow(void *data_raw, void *from_raw)
255 struct ubsan_float_cast_overflow_data *data =
256 (struct ubsan_float_cast_overflow_data *)data_raw;
257 ubsan_value_handle_t from = (ubsan_value_handle_t)from_raw;
258 (void) from;
259 ubsan_abort(&data->location, "float cast overflow");
262 ABORT_VARIANT_VP_VP(float_cast_overflow);
264 struct ubsan_invalid_value_data {
265 struct ubsan_source_location location;
266 struct ubsan_type_descriptor *type;
269 void __ubsan_handle_load_invalid_value(void *data_raw, void *value_raw)
271 const struct ubsan_invalid_value_data *data =
272 (struct ubsan_invalid_value_data *)data_raw;
273 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
274 (void)value;
275 ubsan_abort(&data->location, "invalid value load");
278 ABORT_VARIANT_VP_VP(load_invalid_value);
280 struct ubsan_function_type_mismatch_data {
281 struct ubsan_source_location location;
282 struct ubsan_type_descriptor *type;
285 void __ubsan_handle_function_type_mismatch(void *data_raw, void *value_raw)
287 const struct ubsan_function_type_mismatch_data *data =
288 (struct ubsan_function_type_mismatch_data *)data_raw;
289 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
290 (void)value;
291 ubsan_abort(&data->location, "function type mismatch");
294 ABORT_VARIANT_VP_VP(function_type_mismatch);
296 struct ubsan_nonnull_return_data {
297 struct ubsan_source_location location;
298 struct ubsan_source_location attr_location;
301 void __ubsan_handle_nonnull_return(void *data_raw)
303 const struct ubsan_nonnull_return_data *data =
304 (struct ubsan_nonnull_return_data *)data_raw;
305 ubsan_abort(&data->location, "null return");
308 ABORT_VARIANT_VP(nonnull_return);
310 struct ubsan_nonnull_arg_data {
311 struct ubsan_source_location location;
312 struct ubsan_source_location attr_location;
316 * TODO: GCC's libubsan does not have the second parameter, but its builtin
317 * somehow has it and conflict if we don't match it.
319 void __ubsan_handle_nonnull_arg(void *data_raw, intptr_t index_raw)
321 const struct ubsan_nonnull_arg_data *data =
322 (struct ubsan_nonnull_arg_data *)data_raw;
323 ubsan_value_handle_t index = (ubsan_value_handle_t)index_raw;
324 (void)index;
325 ubsan_abort(&data->location, "null argument");
328 ABORT_VARIANT_VP_IP(nonnull_arg);
330 struct ubsan_cfi_bad_icall_data {
331 struct ubsan_source_location location;
332 struct ubsan_type_descriptor *type;
335 void __ubsan_handle_cfi_bad_icall(void *data_raw, void *value_raw)
337 static const char *abort_text
338 = "cfi: integrity failure during indirect call.";
339 const struct ubsan_cfi_bad_icall_data *data =
340 (struct ubsan_cfi_bad_icall_data *)data_raw;
341 ubsan_value_handle_t value = (ubsan_value_handle_t)value_raw;
342 (void)value;
343 ubsan_abort(&data->location, abort_text);
346 ABORT_VARIANT_VP_VP(cfi_bad_icall);