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
11struct source_location
12{
13 const char *file;
14 u32 line;
15 u32 column;
16};
17
18struct type_descriptor
19{
20 u16 kind;
21 u16 info;
22 char name[];
23};
24
25struct 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
33struct out_of_bounds_info
34{
35 struct source_location location;
36 struct type_descriptor *array_type;
37 struct type_descriptor *index_type;
38};
39
40struct unreachable_data
41{
42 struct source_location location;
43};
44
45static 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
50void __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
64void __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
70void __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
75void __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
81void __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
87void __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
93void __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
99void __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
106void __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
112void __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
117void __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
123void __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
129void __ubsan_handle_invalid_builtin(struct source_location *location)
130{
131 pr_emerg("invalid builtin");
132 log_location(location);
133}
134
135void __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
141void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
142{
143 pr_emerg("builtin unreachable was reached");
144 log_location(location: &data->location);
145}
146