1 // Copyright (c) 2016, Linaro Limited
2 // Modified for HelenOS use by Jiří Zárevúcky.
3 // Adaptations for ESP-IDF Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26
27 #include <stdbool.h>
28 #include <inttypes.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include "esp_system.h"
34 #include "esp_rom_sys.h"
35 #include "esp_cpu.h"
36
37
38 struct source_location {
39 const char *file_name;
40 uint32_t line;
41 uint32_t column;
42 };
43
44 struct type_descriptor {
45 uint16_t type_kind;
46 uint16_t type_info;
47 char type_name[];
48 };
49
50 struct type_mismatch_data {
51 struct source_location loc;
52 struct type_descriptor *type;
53 unsigned long alignment;
54 unsigned char type_check_kind;
55 };
56
57 struct type_mismatch_data_v1 {
58 struct source_location loc;
59 struct type_descriptor *type;
60 unsigned char log_alignment;
61 unsigned char type_check_kind;
62 };
63
64 struct overflow_data {
65 struct source_location loc;
66 struct type_descriptor *type;
67 };
68
69 struct shift_out_of_bounds_data {
70 struct source_location loc;
71 struct type_descriptor *lhs_type;
72 struct type_descriptor *rhs_type;
73 };
74
75 struct out_of_bounds_data {
76 struct source_location loc;
77 struct type_descriptor *array_type;
78 struct type_descriptor *index_type;
79 };
80
81 struct unreachable_data {
82 struct source_location loc;
83 };
84
85 struct vla_bound_data {
86 struct source_location loc;
87 struct type_descriptor *type;
88 };
89
90 struct invalid_value_data {
91 struct source_location loc;
92 struct type_descriptor *type;
93 };
94
95 struct nonnull_arg_data {
96 struct source_location loc;
97 };
98
99 struct nonnull_return_data {
100 struct source_location loc;
101 struct source_location attr_loc;
102 };
103
104 struct pointer_overflow_data {
105 struct source_location loc;
106 };
107
108 struct invalid_builtin_data {
109 struct source_location loc;
110 unsigned char kind;
111 };
112
113
114 static void __ubsan_default_handler(struct source_location *loc, const char *func) __attribute__((noreturn));
115
116 /*
117 * When compiling with -fsanitize=undefined the compiler expects functions
118 * with the following signatures. The functions are never called directly,
119 * only when undefined behavior is detected in instrumented code.
120 */
121 void __ubsan_handle_type_mismatch(void *data_, void *ptr_);
122 void __ubsan_handle_type_mismatch_v1(void *data_, void *ptr_);
123 void __ubsan_handle_add_overflow(void *data_, void *lhs_, void *rhs_);
124 void __ubsan_handle_sub_overflow(void *data_, void *lhs_, void *rhs_);
125 void __ubsan_handle_mul_overflow(void *data_, void *lhs_, void *rhs_);
126 void __ubsan_handle_negate_overflow(void *data_, void *old_val_);
127 void __ubsan_handle_divrem_overflow(void *data_, void *lhs_, void *rhs_);
128 void __ubsan_handle_shift_out_of_bounds(void *data_, void *lhs_, void *rhs_);
129 void __ubsan_handle_out_of_bounds(void *data_, void *idx_);
130 void __ubsan_handle_missing_return(void *data_);
131 void __ubsan_handle_vla_bound_not_positive(void *data_, void *bound_);
132 void __ubsan_handle_load_invalid_value(void *data_, void *val_);
133 void __ubsan_handle_nonnull_arg(void *data_);
134 void __ubsan_handle_nonnull_return(void *data_);
135 void __ubsan_handle_builtin_unreachable(void *data_);
136 void __ubsan_handle_pointer_overflow(void *data_, void *base_, void *result_);
137 void __ubsan_handle_invalid_builtin(void *data_);
138
__ubsan_maybe_debugbreak(void)139 static void __ubsan_maybe_debugbreak(void)
140 {
141 if (esp_cpu_dbgr_is_attached()) {
142 esp_cpu_dbgr_break();
143 }
144 }
145
__ubsan_default_handler(struct source_location * loc,const char * func)146 static void __ubsan_default_handler(struct source_location *loc, const char *func)
147 {
148 /* Although the source location is available here, it is not printed:
149 *
150 * - We could use "snprintf", but that uses a lot of stack, and may allocate memory,
151 * so is not safe from UBSAN handler.
152 * - Alternatively, "itoa" could be used. However itoa doesn't take the remaining
153 * string length as as argument and is therefore unsafe (nor does it return
154 * the number of characters written). itoa is also not present in ESP32-S2 ROM,
155 * and would need to be placed into IRAM on that chip.
156 * - Third option is to print the message using esp_rom_printf, and not pass anything
157 * to esp_system_abort. However we'd like to capture this information, e.g. for the
158 * purpose of including the abort reason into core dumps.
159 *
160 * Since the source file and line number are already printed while decoding
161 * the panic backtrace, not printing the line number here seems to be an okay choice.
162 */
163 char msg[60] = {};
164 (void) strlcat(msg, "Undefined behavior of type ", sizeof(msg));
165 (void) strlcat(msg, func + strlen("__ubsan_handle_"), sizeof(msg));
166 esp_system_abort(msg);
167 }
168
__ubsan_handle_type_mismatch(void * data_,void * ptr_)169 void __ubsan_handle_type_mismatch(void *data_,
170 void *ptr_)
171 {
172 struct type_mismatch_data *data = data_;
173 __ubsan_maybe_debugbreak();
174 __ubsan_default_handler(&data->loc, __func__);
175 }
176
__ubsan_handle_type_mismatch_v1(void * data_,void * ptr)177 void __ubsan_handle_type_mismatch_v1(void *data_,
178 void *ptr)
179 {
180 struct type_mismatch_data_v1 *data = data_;
181 __ubsan_maybe_debugbreak();
182 __ubsan_default_handler(&data->loc, __func__);
183 }
184
__ubsan_handle_add_overflow(void * data_,void * lhs_,void * rhs_)185 void __ubsan_handle_add_overflow(void *data_,
186 void *lhs_,
187 void *rhs_)
188 {
189 struct overflow_data *data = data_;
190 __ubsan_maybe_debugbreak();
191 __ubsan_default_handler(&data->loc, __func__);
192 }
193
__ubsan_handle_sub_overflow(void * data_,void * lhs_,void * rhs_)194 void __ubsan_handle_sub_overflow(void *data_,
195 void *lhs_,
196 void *rhs_)
197 {
198 struct overflow_data *data = data_;
199 __ubsan_maybe_debugbreak();
200 __ubsan_default_handler(&data->loc, __func__);
201 }
202
__ubsan_handle_mul_overflow(void * data_,void * lhs_,void * rhs_)203 void __ubsan_handle_mul_overflow(void *data_,
204 void *lhs_,
205 void *rhs_)
206 {
207 struct overflow_data *data = data_;
208 __ubsan_maybe_debugbreak();
209 __ubsan_default_handler(&data->loc, __func__);
210 }
211
__ubsan_handle_negate_overflow(void * data_,void * old_val_)212 void __ubsan_handle_negate_overflow(void *data_,
213 void *old_val_)
214 {
215 struct overflow_data *data = data_;
216 __ubsan_maybe_debugbreak();
217 __ubsan_default_handler(&data->loc, __func__);
218 }
219
__ubsan_handle_divrem_overflow(void * data_,void * lhs_,void * rhs_)220 void __ubsan_handle_divrem_overflow(void *data_,
221 void *lhs_,
222 void *rhs_)
223 {
224 struct overflow_data *data = data_;
225 __ubsan_maybe_debugbreak();
226 __ubsan_default_handler(&data->loc, __func__);
227 }
228
__ubsan_handle_shift_out_of_bounds(void * data_,void * lhs_,void * rhs_)229 void __ubsan_handle_shift_out_of_bounds(void *data_,
230 void *lhs_,
231 void *rhs_)
232 {
233 struct shift_out_of_bounds_data *data = data_;
234 unsigned int rhs = (unsigned int)rhs_;
235 if (rhs == 32) {
236 return;
237 }
238 __ubsan_maybe_debugbreak();
239 __ubsan_default_handler(&data->loc, __func__);
240 }
241
__ubsan_handle_out_of_bounds(void * data_,void * idx_)242 void __ubsan_handle_out_of_bounds(void *data_,
243 void *idx_)
244 {
245 struct out_of_bounds_data *data = data_;
246 __ubsan_maybe_debugbreak();
247 __ubsan_default_handler(&data->loc, __func__);
248 }
249
__ubsan_handle_missing_return(void * data_)250 void __ubsan_handle_missing_return(void *data_)
251 {
252 struct unreachable_data *data = data_;
253 __ubsan_maybe_debugbreak();
254 __ubsan_default_handler(&data->loc, __func__);
255 }
256
__ubsan_handle_vla_bound_not_positive(void * data_,void * bound_)257 void __ubsan_handle_vla_bound_not_positive(void *data_,
258 void *bound_)
259 {
260 struct vla_bound_data *data = data_;
261 __ubsan_maybe_debugbreak();
262 __ubsan_default_handler(&data->loc, __func__);
263 }
264
__ubsan_handle_load_invalid_value(void * data_,void * val_)265 void __ubsan_handle_load_invalid_value(void *data_,
266 void *val_)
267 {
268 struct invalid_value_data *data = data_;
269 __ubsan_maybe_debugbreak();
270 __ubsan_default_handler(&data->loc, __func__);
271 }
272
__ubsan_handle_nonnull_arg(void * data_)273 void __ubsan_handle_nonnull_arg(void *data_)
274 {
275 struct nonnull_arg_data *data = data_;
276 __ubsan_maybe_debugbreak();
277 __ubsan_default_handler(&data->loc, __func__);
278 }
279
__ubsan_handle_nonnull_return(void * data_)280 void __ubsan_handle_nonnull_return(void *data_)
281 {
282 struct nonnull_return_data *data = data_;
283 __ubsan_maybe_debugbreak();
284 __ubsan_default_handler(&data->loc, __func__);
285 }
286
__ubsan_handle_builtin_unreachable(void * data_)287 void __ubsan_handle_builtin_unreachable(void *data_)
288 {
289 struct unreachable_data *data = data_;
290 __ubsan_maybe_debugbreak();
291 __ubsan_default_handler(&data->loc, __func__);
292 }
293
__ubsan_handle_pointer_overflow(void * data_,void * base_,void * result_)294 void __ubsan_handle_pointer_overflow(void *data_,
295 void *base_,
296 void *result_)
297 {
298 struct pointer_overflow_data *data = data_;
299 __ubsan_maybe_debugbreak();
300 __ubsan_default_handler(&data->loc, __func__);
301 }
302
__ubsan_handle_invalid_builtin(void * data_)303 void __ubsan_handle_invalid_builtin(void *data_)
304 {
305 struct invalid_builtin_data *data = data_;
306 __ubsan_maybe_debugbreak();
307 __ubsan_default_handler(&data->loc, __func__);
308 }
309
310 /* Hook for the linker to include this object file */
__ubsan_include(void)311 void __ubsan_include(void)
312 {
313 }
314