tegrakernel/kernel/nvidia/drivers/misc/tegra-profiler/backtrace.h

145 lines
3.0 KiB
C

/*
* drivers/misc/tegra-profiler/backtrace.h
*
* Copyright (c) 2013-2020, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __QUADD_BACKTRACE_H
#define __QUADD_BACKTRACE_H
#include <linux/mm.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/tegra_profiler.h>
#define QUADD_MAX_STACK_DEPTH 64
#define QUADD_UNW_TYPES_SIZE \
DIV_ROUND_UP(QUADD_MAX_STACK_DEPTH * 4, sizeof(u32) * BITS_PER_BYTE)
struct quadd_hrt_ctx;
struct quadd_unw_methods {
unsigned int
fp:1,
ut:1,
ut_ce:1,
dwarf:1;
};
struct quadd_callchain {
int nr;
union {
u32 ip_32[QUADD_MAX_STACK_DEPTH];
u64 ip_64[QUADD_MAX_STACK_DEPTH];
};
u32 types[QUADD_UNW_TYPES_SIZE];
unsigned int cs_64:1;
struct quadd_unw_methods um;
unsigned int urc_fp;
unsigned int urc_ut;
unsigned int urc_dwarf;
unsigned long curr_sp;
unsigned long curr_fp;
unsigned long curr_fp_thumb;
unsigned long curr_pc;
unsigned long curr_lr;
struct quadd_hrt_ctx *hrt;
};
struct quadd_ctx;
struct quadd_event_context;
unsigned int
quadd_get_user_callchain(struct quadd_event_context *event_ctx,
struct quadd_callchain *cc,
struct quadd_ctx *ctx);
int
quadd_callchain_store(struct quadd_callchain *cc,
unsigned long ip, unsigned int type);
unsigned long
quadd_user_stack_pointer(struct pt_regs *regs);
unsigned long
quadd_get_user_frame_pointer(struct pt_regs *regs);
unsigned long
quadd_user_link_register(struct pt_regs *regs);
static inline int
is_vma_addr(unsigned long addr, struct vm_area_struct *vma,
unsigned long nbytes)
{
return vma &&
addr >= vma->vm_start &&
addr < vma->vm_end - nbytes;
}
static inline int
validate_pc_addr(unsigned long addr, unsigned long nbytes)
{
return addr && addr < TASK_SIZE - nbytes;
}
static inline int
validate_stack_addr(unsigned long addr,
struct vm_area_struct *vma,
unsigned long nbytes,
int is64)
{
unsigned int align_mask = is64 ? 0x07 : 0x03;
if (addr & align_mask)
return 0;
return is_vma_addr(addr, vma, nbytes);
}
static inline long
read_user_data(void *dst, const void __user *src, unsigned long n)
{
long err;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0))
if (unlikely(!access_ok(VERIFY_READ, src, n)))
#else
if (unlikely(!access_ok(src, n)))
#endif
return -QUADD_URC_EACCESS;
pagefault_disable();
err = __copy_from_user_inatomic(dst, src, n);
pagefault_enable();
if (unlikely(err)) {
pr_debug("%s: failed for address: %p\n",
__func__, src);
err = -QUADD_URC_EACCESS;
}
return err;
}
#endif /* __QUADD_BACKTRACE_H */