mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
![Max Filippov](/assets/img/avatar_default.png)
Use perf framework to manage hardware instruction and data breakpoints. Add two new ptrace calls: PTRACE_GETHBPREGS and PTRACE_SETHBPREGS to query and set instruction and data breakpoints. Address bit 0 choose instruction (0) or data (1) break register, bits 31..1 are the register number. Both calls transfer two 32-bit words: address (0) and control (1). Instruction breakpoint contorl word is 0 to clear breakpoint, 1 to set. Data breakpoint control word bit 31 is 'trigger on store', bit 30 is 'trigger on load, bits 29..0 are length. Length 0 is used to clear a breakpoint. To set a breakpoint length must be a power of 2 in the range 1..64 and the address must be length-aligned. Introduce new thread_info flag: TIF_DB_DISABLED. Set it if debug exception is raised by the kernel code accessing watched userspace address and disable corresponding data breakpoint. On exit to userspace check that flag and, if set, restore all data breakpoints. Handle debug exceptions raised with PS.EXCM set. This may happen when window overflow/underflow handler or fast exception handler hits data breakpoint, in which case save and disable all data breakpoints, single-step faulting instruction and restore data breakpoints. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
133 lines
5.4 KiB
C
133 lines
5.4 KiB
C
/*
|
|
* arch/xtensa/kernel/asm-offsets.c
|
|
*
|
|
* Generates definitions from c-type structures used by assembly sources.
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
* for more details.
|
|
*
|
|
* Copyright (C) 2005 Tensilica Inc.
|
|
*
|
|
* Chris Zankel <chris@zankel.net>
|
|
*/
|
|
|
|
#include <asm/processor.h>
|
|
#include <asm/coprocessor.h>
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/thread_info.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/kbuild.h>
|
|
|
|
#include <asm/ptrace.h>
|
|
#include <asm/traps.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
int main(void)
|
|
{
|
|
/* struct pt_regs */
|
|
DEFINE(PT_PC, offsetof (struct pt_regs, pc));
|
|
DEFINE(PT_PS, offsetof (struct pt_regs, ps));
|
|
DEFINE(PT_DEPC, offsetof (struct pt_regs, depc));
|
|
DEFINE(PT_EXCCAUSE, offsetof (struct pt_regs, exccause));
|
|
DEFINE(PT_EXCVADDR, offsetof (struct pt_regs, excvaddr));
|
|
DEFINE(PT_DEBUGCAUSE, offsetof (struct pt_regs, debugcause));
|
|
DEFINE(PT_WMASK, offsetof (struct pt_regs, wmask));
|
|
DEFINE(PT_LBEG, offsetof (struct pt_regs, lbeg));
|
|
DEFINE(PT_LEND, offsetof (struct pt_regs, lend));
|
|
DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount));
|
|
DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
|
|
DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel));
|
|
DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
|
|
DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1));
|
|
DEFINE(PT_THREADPTR, offsetof(struct pt_regs, threadptr));
|
|
DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
|
|
DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
|
|
DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
|
|
DEFINE(PT_AREG2, offsetof (struct pt_regs, areg[2]));
|
|
DEFINE(PT_AREG3, offsetof (struct pt_regs, areg[3]));
|
|
DEFINE(PT_AREG4, offsetof (struct pt_regs, areg[4]));
|
|
DEFINE(PT_AREG5, offsetof (struct pt_regs, areg[5]));
|
|
DEFINE(PT_AREG6, offsetof (struct pt_regs, areg[6]));
|
|
DEFINE(PT_AREG7, offsetof (struct pt_regs, areg[7]));
|
|
DEFINE(PT_AREG8, offsetof (struct pt_regs, areg[8]));
|
|
DEFINE(PT_AREG9, offsetof (struct pt_regs, areg[9]));
|
|
DEFINE(PT_AREG10, offsetof (struct pt_regs, areg[10]));
|
|
DEFINE(PT_AREG11, offsetof (struct pt_regs, areg[11]));
|
|
DEFINE(PT_AREG12, offsetof (struct pt_regs, areg[12]));
|
|
DEFINE(PT_AREG13, offsetof (struct pt_regs, areg[13]));
|
|
DEFINE(PT_AREG14, offsetof (struct pt_regs, areg[14]));
|
|
DEFINE(PT_AREG15, offsetof (struct pt_regs, areg[15]));
|
|
DEFINE(PT_WINDOWBASE, offsetof (struct pt_regs, windowbase));
|
|
DEFINE(PT_WINDOWSTART, offsetof(struct pt_regs, windowstart));
|
|
DEFINE(PT_SIZE, sizeof(struct pt_regs));
|
|
DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
|
|
DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
|
|
DEFINE(PT_XTREGS_OPT, offsetof(struct pt_regs, xtregs_opt));
|
|
DEFINE(XTREGS_OPT_SIZE, sizeof(xtregs_opt_t));
|
|
|
|
/* struct task_struct */
|
|
DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
|
|
DEFINE(TASK_MM, offsetof (struct task_struct, mm));
|
|
DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
|
|
DEFINE(TASK_PID, offsetof (struct task_struct, pid));
|
|
DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
|
|
DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
|
|
DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
|
|
|
|
/* offsets in thread_info struct */
|
|
OFFSET(TI_TASK, thread_info, task);
|
|
OFFSET(TI_FLAGS, thread_info, flags);
|
|
OFFSET(TI_STSTUS, thread_info, status);
|
|
OFFSET(TI_CPU, thread_info, cpu);
|
|
OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
|
|
OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
|
|
|
|
/* struct thread_info (offset from start_struct) */
|
|
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
|
|
DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
|
|
DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
|
|
#if XTENSA_HAVE_COPROCESSORS
|
|
DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp));
|
|
DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp));
|
|
#endif
|
|
DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
|
|
DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
|
|
DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, \
|
|
thread.current_ds));
|
|
|
|
/* struct mm_struct */
|
|
DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
|
|
DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
|
|
DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
|
|
|
|
/* struct page */
|
|
DEFINE(PAGE_FLAGS, offsetof(struct page, flags));
|
|
|
|
/* constants */
|
|
DEFINE(_CLONE_VM, CLONE_VM);
|
|
DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
|
|
DEFINE(PG_ARCH_1, PG_arch_1);
|
|
|
|
/* struct debug_table */
|
|
DEFINE(DT_DEBUG_EXCEPTION,
|
|
offsetof(struct debug_table, debug_exception));
|
|
DEFINE(DT_DEBUG_SAVE, offsetof(struct debug_table, debug_save));
|
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
|
DEFINE(DT_DBREAKC_SAVE, offsetof(struct debug_table, dbreakc_save));
|
|
DEFINE(DT_ICOUNT_SAVE, offsetof(struct debug_table, icount_save));
|
|
DEFINE(DT_ICOUNT_LEVEL_SAVE,
|
|
offsetof(struct debug_table, icount_level_save));
|
|
#endif
|
|
|
|
return 0;
|
|
}
|