Merge "Add UBSAN support and handlers" into integration
diff --git a/Makefile b/Makefile
index 43ff8d2..043e751 100644
--- a/Makefile
+++ b/Makefile
@@ -278,6 +278,14 @@
 				-ffreestanding -fno-builtin -Wall -std=gnu99	\
 				-Os -ffunction-sections -fdata-sections
 
+ifeq (${SANITIZE_UB},on)
+TF_CFLAGS		+=	-fsanitize=undefined -fno-sanitize-recover
+endif
+ifeq (${SANITIZE_UB},trap)
+TF_CFLAGS		+=	-fsanitize=undefined -fno-sanitize-recover	\
+				-fsanitize-undefined-trap-on-error
+endif
+
 GCC_V_OUTPUT		:=	$(shell $(CC) -v 2>&1)
 
 ifneq ($(findstring armlink,$(notdir $(LD))),)
@@ -313,6 +321,10 @@
 BL_COMMON_SOURCES	+=	lib/${ARCH}/armclang_printf.S
 endif
 
+ifeq (${SANITIZE_UB},on)
+BL_COMMON_SOURCES	+=	plat/common/ubsan.c
+endif
+
 INCLUDES		+=	-Iinclude				\
 				-Iinclude/arch/${ARCH}			\
 				-Iinclude/lib/cpus/${ARCH}		\
@@ -673,6 +685,10 @@
 $(eval $(call assert_numeric,ARM_ARCH_MINOR))
 $(eval $(call assert_numeric,BRANCH_PROTECTION))
 
+ifeq ($(filter $(SANITIZE_UB), on off trap),)
+        $(error "Invalid value for SANITIZE_UB: can be one of on, off, trap")
+endif
+
 ################################################################################
 # Add definitions to the cpp preprocessor based on the current build options.
 # This is done after including the platform specific makefile to allow the
@@ -724,6 +740,10 @@
 $(eval $(call add_define,BL2_AT_EL3))
 $(eval $(call add_define,BL2_IN_XIP_MEM))
 
+ifeq (${SANITIZE_UB},trap)
+        $(eval $(call add_define,MONITOR_TRAPS))
+endif
+
 # Define the EL3_PAYLOAD_BASE flag only if it is provided.
 ifdef EL3_PAYLOAD_BASE
         $(eval $(call add_define,EL3_PAYLOAD_BASE))
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index fd7656e2..1cbec8f 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -220,6 +220,19 @@
 	 * ---------------------------------------------------------------------
 	 */
 vector_entry sync_exception_sp_el0
+#ifdef MONITOR_TRAPS
+	stp x29, x30, [sp, #-16]!
+
+	mrs	x30, esr_el3
+	ubfx	x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
+
+	/* Check for BRK */
+	cmp	x30, #EC_BRK
+	b.eq	brk_handler
+
+	ldp x29, x30, [sp], #16
+#endif /* MONITOR_TRAPS */
+
 	/* We don't expect any synchronous exceptions from EL3 */
 	b	report_unhandled_exception
 end_vector_entry sync_exception_sp_el0
@@ -328,6 +341,14 @@
 	b	enter_lower_el_async_ea
 end_vector_entry serror_aarch32
 
+#ifdef MONITOR_TRAPS
+	.section .rodata.brk_string, "aS"
+brk_location:
+	.asciz "Error at instruction 0x"
+brk_message:
+	.asciz "Unexpected BRK instruction with value 0x"
+#endif /* MONITOR_TRAPS */
+
 	/* ---------------------------------------------------------------------
 	 * The following code handles secure monitor calls.
 	 * Depending upon the execution state from where the SMC has been
@@ -455,3 +476,39 @@
 	msr	spsel, #1
 	no_ret	report_unhandled_exception
 endfunc smc_handler
+
+	/* ---------------------------------------------------------------------
+	 * The following code handles exceptions caused by BRK instructions.
+	 * Following a BRK instruction, the only real valid cause of action is
+	 * to print some information and panic, as the code that caused it is
+	 * likely in an inconsistent internal state.
+	 *
+	 * This is initially intended to be used in conjunction with
+	 * __builtin_trap.
+	 * ---------------------------------------------------------------------
+	 */
+#ifdef MONITOR_TRAPS
+func brk_handler
+	/* Extract the ISS */
+	mrs	x10, esr_el3
+	ubfx	x10, x10, #ESR_ISS_SHIFT, #ESR_ISS_LENGTH
+
+	/* Ensure the console is initialized */
+	bl	plat_crash_console_init
+
+	adr	x4, brk_location
+	bl	asm_print_str
+	mrs	x4, elr_el3
+	bl	asm_print_hex
+	bl	asm_print_newline
+
+	adr	x4, brk_message
+	bl	asm_print_str
+	mov	x4, x10
+	mov	x5, #28
+	bl	asm_print_hex_bits
+	bl	asm_print_newline
+
+	no_ret	plat_panic_handler
+endfunc brk_handler
+#endif /* MONITOR_TRAPS */
diff --git a/docs/getting_started/user-guide.rst b/docs/getting_started/user-guide.rst
index b447f14..1cfd4c7 100644
--- a/docs/getting_started/user-guide.rst
+++ b/docs/getting_started/user-guide.rst
@@ -684,6 +684,21 @@
    file that contains the ROT private key in PEM format. If ``SAVE_KEYS=1``, this
    file name will be used to save the key.
 
+-  ``SANITIZE_UB``: This option enables the Undefined Behaviour sanitizer. It
+   can take 3 values: 'off' (default), 'on' and 'trap'. When using 'trap',
+   gcc and clang will insert calls to ``__builtin_trap`` on detected
+   undefined behaviour, which defaults to a ``brk`` instruction. When using
+   'on', undefined behaviour is translated to a call to special handlers which
+   prints the exact location of the problem and its cause and then panics.
+
+    .. note::
+        Because of the space penalty of the Undefined Behaviour sanitizer,
+        this option will increase the size of the binary. Depending on the
+        memory constraints of the target platform, it may not be possible to
+        enable the sanitizer for all images (BL1 and BL2 are especially
+        likely to be memory constrained). We recommend that the
+        sanitizer is enabled only in debug builds.
+
 -  ``SAVE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the
    certificate generation tool to save the keys used to establish the Chain of
    Trust. Allowed options are '0' or '1'. Default is '0' (do not save).
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 5f84ece..0a26fab 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -598,6 +598,8 @@
 #define ESR_EC_SHIFT			U(26)
 #define ESR_EC_MASK			U(0x3f)
 #define ESR_EC_LENGTH			U(6)
+#define ESR_ISS_SHIFT			U(0)
+#define ESR_ISS_LENGTH			U(25)
 #define EC_UNKNOWN			U(0x0)
 #define EC_WFE_WFI			U(0x1)
 #define EC_AARCH32_CP15_MRC_MCR		U(0x3)
@@ -624,6 +626,7 @@
 #define EC_AARCH32_FP			U(0x28)
 #define EC_AARCH64_FP			U(0x2c)
 #define EC_SERROR			U(0x2f)
+#define EC_BRK				U(0x3c)
 
 /*
  * External Abort bit in Instruction and Data Aborts synchronous exception
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index f63e46f..fa21335 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -224,3 +224,5 @@
 else
     override ENABLE_SVE_FOR_NS	:= 0
 endif
+
+SANITIZE_UB := off
diff --git a/plat/common/ubsan.c b/plat/common/ubsan.c
new file mode 100644
index 0000000..45b0f7c
--- /dev/null
+++ b/plat/common/ubsan.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * Copyright (c) 2019, ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <arch_helpers.h>
+#include <context.h>
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+struct source_location {
+	const char *file_name;
+	uint32_t line;
+	uint32_t column;
+};
+
+struct type_descriptor {
+	uint16_t type_kind;
+	uint16_t type_info;
+	char type_name[1];
+};
+
+struct type_mismatch_data {
+	struct source_location loc;
+	struct type_descriptor *type;
+	unsigned long alignment;
+	unsigned char type_check_kind;
+};
+
+struct overflow_data {
+	struct source_location loc;
+	struct type_descriptor *type;
+};
+
+struct shift_out_of_bounds_data {
+	struct source_location loc;
+	struct type_descriptor *lhs_type;
+	struct type_descriptor *rhs_type;
+};
+
+struct out_of_bounds_data {
+	struct source_location loc;
+	struct type_descriptor *array_type;
+	struct type_descriptor *index_type;
+};
+
+struct unreachable_data {
+	struct source_location loc;
+};
+
+struct vla_bound_data {
+	struct source_location loc;
+	struct type_descriptor *type;
+};
+
+struct invalid_value_data {
+	struct source_location loc;
+	struct type_descriptor *type;
+};
+
+struct nonnull_arg_data {
+	struct source_location loc;
+};
+
+/*
+ * When compiling with -fsanitize=undefined the compiler expects functions
+ * with the following signatures. The functions are never called directly,
+ * only when undefined behavior is detected in instrumented code.
+ */
+void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data,
+					unsigned long ptr);
+void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data,
+					   unsigned long ptr);
+void __ubsan_handle_add_overflow_abort(struct overflow_data *data,
+					unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_sub_overflow_abort(struct overflow_data *data,
+				       unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_mul_overflow_abort(struct overflow_data *data,
+				       unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_negate_overflow_abort(struct overflow_data *data,
+					  unsigned long old_val);
+void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data,
+					   unsigned long old_val);
+void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data,
+					  unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data,
+					      unsigned long lhs, unsigned long rhs);
+void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data,
+					unsigned long idx);
+void __ubsan_handle_unreachable_abort(struct unreachable_data *data);
+void __ubsan_handle_missing_return_abort(struct unreachable_data *data);
+void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data,
+						 unsigned long bound);
+void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data,
+					     unsigned long val);
+void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data
+#if __GCC_VERSION < 60000
+				    , size_t arg_no
+#endif
+				      );
+
+static void print_loc(const char *func, struct source_location *loc)
+{
+	ERROR("Undefined behavior at %s:%d col %d (%s)",
+		loc->file_name, loc->line, loc->column, func);
+}
+
+
+void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data,
+					unsigned long ptr __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data,
+					unsigned long ptr __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_add_overflow_abort(struct overflow_data *data,
+				       unsigned long lhs __unused,
+				       unsigned long rhs __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_sub_overflow_abort(struct overflow_data *data,
+				       unsigned long lhs __unused,
+				       unsigned long rhs __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_mul_overflow_abort(struct overflow_data *data,
+				       unsigned long lhs __unused,
+				       unsigned long rhs __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_negate_overflow_abort(struct overflow_data *data,
+					  unsigned long old_val __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data,
+					  unsigned long old_val __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data,
+					  unsigned long lhs __unused,
+					  unsigned long rhs __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data,
+					      unsigned long lhs __unused,
+					      unsigned long rhs __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data,
+					unsigned long idx __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_unreachable_abort(struct unreachable_data *data)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_missing_return_abort(struct unreachable_data *data)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data,
+						 unsigned long bound __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data,
+					     unsigned long val __unused)
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}
+
+void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data
+#if __GCC_VERSION < 60000
+				   , size_t arg_no __unused
+#endif
+				     )
+{
+	print_loc(__func__, &data->loc);
+	plat_panic_handler();
+}