Linux debugging

Check our new training course

Linux debugging, tracing, profiling & perf. analysis

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2016, Linaro Limited
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <types_ext.h>
#include <kernel/panic.h>
#include <trace.h>
#include <string.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(struct type_mismatch_data *data,
				  unsigned long ptr);
void __ubsan_handle_add_overflow(struct overflow_data *data,
				  unsigned long lhs, unsigned long rhs);
void __ubsan_handle_sub_overflow(struct overflow_data *data,
				  unsigned long lhs, unsigned long rhs);
void __ubsan_handle_mul_overflow(struct overflow_data *data,
				  unsigned long lhs, unsigned long rhs);
void __ubsan_handle_negate_overflow(struct overflow_data *data,
				    unsigned long old_val);
void __ubsan_handle_divrem_overflow(struct overflow_data *data,
				    unsigned long lhs, unsigned long rhs);
void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
					unsigned long lhs, unsigned long rhs);
void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
				  unsigned long idx);
void __ubsan_handle_unreachable(struct unreachable_data *data);
void __ubsan_handle_missing_return(struct unreachable_data *data);
void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
					   unsigned long bound);
void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
				       unsigned long val);
void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data, size_t arg_no);

static void print_loc(const char *func, struct source_location *loc)
{
	const char *f = func;
	const char func_prefix[] = "__ubsan_handle";

	if (!memcmp(f, func_prefix, sizeof(func_prefix) - 1))
		f += sizeof(func_prefix);

	EMSG_RAW("Undefined behavior %s at %s:%" PRIu32 " col %" PRIu32,
		 f, loc->file_name, loc->line, loc->column);
}


static volatile bool ubsan_panic = true;

void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
				  unsigned long ptr __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_add_overflow(struct overflow_data *data,
				 unsigned long lhs __unused,
				 unsigned long rhs __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_sub_overflow(struct overflow_data *data,
				 unsigned long lhs __unused,
				 unsigned long rhs __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_mul_overflow(struct overflow_data *data,
				 unsigned long lhs __unused,
				 unsigned long rhs __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_negate_overflow(struct overflow_data *data,
				    unsigned long old_val __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_divrem_overflow(struct overflow_data *data,
				    unsigned long lhs __unused,
				    unsigned long rhs __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
					unsigned long lhs __unused,
					unsigned long rhs __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
				  unsigned long idx __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_unreachable(struct unreachable_data *data)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __noreturn __ubsan_handle_missing_return(struct unreachable_data *data)
{
	print_loc(__func__, &data->loc);
	panic();
}

void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
					   unsigned long bound __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
				       unsigned long val __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}

void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data,
				size_t arg_no __unused)
{
	print_loc(__func__, &data->loc);
	if (ubsan_panic)
		panic();
}