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