/*
* Kernel Debugger Architecture Independent Support Functions
*
* 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) 1999-2004 Silicon Graphics, Inc. All Rights Reserved.
*/
#include <linux/config.h>
#include <linux/string.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kdb.h>
#include <linux/kdbprivate.h>
#include <asm/kdebug.h>
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/uaccess.h>
#include <asm/mach_apic.h>
#include <asm/hw_irq.h>
#define SP_SANITY(ss, sp) 1
#define SS(sp) ((sp) & -THREAD_SIZE) /* XXX */
/*
* kdba_find_return
*
* Given a starting point on the stack and symtab data for the
* current function, scan up the stack looking for a return
* address for this function.
* Inputs:
* sp Starting stack pointer for scan
* ss Start of stack for current process
* symtab kallsyms symbol data for the function
* Outputs:
* None.
* Returns:
* Position on stack of return address, 0 if not found.
* Locking:
* None.
* Remarks:
* This is sensitive to the calling sequence generated by gcc.
*/
static kdb_machreg_t
kdba_find_return(kdb_machreg_t sp, kdb_machreg_t ss, const kdb_symtab_t *symtab)
{
kdb_machreg_t ret;
kdb_symtab_t caller_symtab;
unsigned long disp8;
unsigned long disp32;
unsigned char code[7];
#define retaddr(off) code[sizeof(code)+(off)]
if (KDB_DEBUG(ARA)) {
kdb_printf(" kdba_find_return: start\n");
}
if (SP_SANITY(ss, sp) == 0) {
kdb_printf(" sp is in wrong stack 0x%lx\n", sp);
return(0);
}
if ((sp & (THREAD_SIZE - 1)) < sizeof(struct task_struct)) {
kdb_printf(" sp is inside task_struct\n");
return(0);
}
for (;ret = 0, sp & (THREAD_SIZE-1);sp += 8) {
if (KDB_DEBUG(ARA)) {
kdb_printf(" sp=0x%lx", sp);
}
if (kdb_getword(&ret, sp, 8))
break;
kdbnearsym(ret, &caller_symtab);
if (KDB_DEBUG(ARA)) {
kdb_printf(" ret=");
kdb_symbol_print(ret, &caller_symtab, KDB_SP_DEFAULT|KDB_SP_SYMSIZE);
}
if (!caller_symtab.sym_name) {
if (KDB_DEBUG(ARA)) {
kdb_printf("\n");
}
continue; /* not a valid kernel address */
}
KDB_STATE_SET(SUPPRESS);
if (kdb_getarea(code, ret-sizeof(code)) ||
kdb_getword(&disp32, ret-4, 4) ||
kdb_getword(&disp8, ret-1, 1))
continue; /* not a valid return address */
if (retaddr(-5) == 0xe8) {
/* call disp32 */
if (KDB_DEBUG(ARA)) {
kdb_printf(" call disp32");
}
if (ret + (s32) disp32 == symtab->sym_start) {
if (KDB_DEBUG(ARA)) {
kdb_printf(" matched\n");
}
break; /* call to this function */
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" failed");
}
} else if (retaddr(-7) == 0xff && retaddr(-6) == 0x14 && retaddr(-5) == 0x85) {
/* call *disp32(,%rax,4), used by syscall.
* Cannot calculate address, assume it is valid
* if the current function name starts with
* 'sys_' or 'old_'.
*/
if (KDB_DEBUG(ARA)) {
/* XXX FIXME */
kdb_printf(" call *0xnnnn(,%%rax,4)");
}
if (strncmp(symtab->sym_name, "sys_", 4) == 0 ||
strncmp(symtab->sym_name, "old_", 4) == 0) {
if (KDB_DEBUG(ARA)) {
kdb_printf(" matched\n");
}
break; /* probably call to this function */
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" failed");
}
} else if (retaddr(-2) == 0xff && (retaddr(-1) & 0xf8) == 0xd0) {
/* call *%reg. Cannot validate, have to assume
* it is valid.
*/
if (KDB_DEBUG(ARA)) {
kdb_printf(" call *%%reg, assume valid\n");
}
break; /* hope it is a call to this function */
} else if (retaddr(-3) == 0xff && (retaddr(-2) & 0xf8) == 0x50) {
/* call *disp8(%reg). Cannot validate, have to assume
* it is valid.
*/
if (KDB_DEBUG(ARA)) {
kdb_printf(" call *disp8(%%reg), assume valid\n");
}
break; /* hope it is a call to this function */
} else if (retaddr(-5) == 0xe9) {
/* jmp disp32. I have been told that gcc may
* do function tail optimization and replace
* call with jmp.
*/
if (KDB_DEBUG(ARA)) {
kdb_printf(" jmp disp32\n");
}
if (ret + (s32) disp32 == symtab->sym_start) {
if (KDB_DEBUG(ARA)) {
kdb_printf(" matched\n");
}
break; /* jmp to this function */
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" failed");
}
} else if (retaddr(-2) == 0xeb) {
/* jmp disp8 */
if (KDB_DEBUG(ARA)) {
kdb_printf(" jmp disp8\n");
}
if (ret + (s8) disp8 == symtab->sym_start) {
if (KDB_DEBUG(ARA)) {
kdb_printf(" matched\n");
}
break; /* jmp to this function */
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" failed");
}
} else if (strcmp(caller_symtab.sym_name, "ret_from_intr") == 0
&& ret == caller_symtab.sym_start) {
/* ret_from_intr is pushed on stack for interrupts */
if (KDB_DEBUG(ARA)) {
kdb_printf(" ret_from_intr matched\n");
}
break; /* special case, hand crafted frame */
}
if (KDB_DEBUG(ARA)) {
kdb_printf("\n");
}
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" end ret=0x%lx sp=0x%lx\n", ret, sp);
}
if (ret)
return(sp);
return(0);
}
/*
* kdba_prologue
*
* This function analyzes a gcc-generated function prototype
* with or without frame pointers to determine the amount of
* automatic storage and register save storage is used on the
* stack of the target function. It only counts instructions
* that have been executed up to but excluding the current rip.
* Inputs:
* code Start address of function code to analyze
* pc Current program counter within function
* sp Current stack pointer for function
* ss Start of stack for current process
* fp Current frame pointer for function, may not be valid
* caller 1 if looking for data on the caller frame, 0 for callee.
* Outputs:
* ar Activation record, all fields may be set. fp and oldfp
* are 0 if they cannot be extracted. return is 0 if the
* code cannot find a valid return address. args and arg0
* are 0 if the number of arguments cannot be safely
* calculated.
* Returns:
* 1 if prologue is valid, 0 otherwise. If pc is 0 treat it as a
* valid prologue to allow bt on wild branches.
* Locking:
* None.
* Remarks:
*
* x86_64 prologues
*
* kdba_prologue():
* push %r15
* mov %rdi,%r15
* push %r14
* mov %rsi,%r14
* push %r13
* push %r12
* push %rbp
* mov %rdx,%rbp
*
* leaf fn w/ 1 arg:
* push %rbp
* mov %rsp,%rbp
* mov %rdi,0xfffffffffffffff8(%rbp)
*
*/
int
kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp,
kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar)
{
kdb_machreg_t ret_p, code = symtab->sym_start;
int oldfp_present = 0, unwound = 0;
unsigned char instruction[6];
if (KDB_DEBUG(ARA)) {
kdb_printf("kdba_prologue: code=0x%lx %s pc=0x%lx sp=0x%lx fp=0x%lx\n",
code, symtab->sym_name, pc, sp, fp);
}
/* Special case for wild branches. Assumes top of stack is return address */
if (pc == 0) {
memset(ar, 0, sizeof(*ar));
ar->setup = 8;
ar->end = sp;
ar->start = ar->end + 8;
kdb_getword(&(ar->ret), sp, 8);
if (KDB_DEBUG(ARA)) {
kdb_printf(" pc==0: ret=0x%lx\n", ar->ret);
}
return(1);
}
if (code == 0 || sp & 3 || (SP_SANITY(ss, sp) == 0))
return(0);
ar->end = sp; /* End of activation record +1 */
/* Special cases galore when the caller pc is within entry.S.
* The return address for these routines is outside the kernel,
* so the normal algorithm to find the frame does not work.
* Hand craft the frame to no setup, regs, locals etc, assume 6
* parameters.
* This list was extracted from entry.S by looking for all call
* instructions that were eventually followed by RESTORE_ALL,
* take the label before each such instruction.
*/
if (caller &&
(strcmp(symtab->sym_name, "lcall7") == 0 ||
strcmp(symtab->sym_name, "lcall27") == 0 ||
strcmp(symtab->sym_name, "kdb_call") == 0 ||
strcmp(symtab->sym_name, "system_call") == 0 ||
strcmp(symtab->sym_name, "tracesys") == 0 ||
strcmp(symtab->sym_name, "signal_return") == 0 ||
strcmp(symtab->sym_name, "v86_signal_return") == 0 ||
strcmp(symtab->sym_name, "tracesys") == 0 ||
strcmp(symtab->sym_name, "tracesys_exit") == 0 ||
strcmp(symtab->sym_name, "handle_softirq") == 0 ||
strcmp(symtab->sym_name, "reschedule") == 0 ||
strcmp(symtab->sym_name, "error_code") == 0 ||
strcmp(symtab->sym_name, "device_not_available") == 0 ||
strcmp(symtab->sym_name, "nmi") == 0)) {
ar->start = ar->end + 6*8; /* 6 parameters */
if (SP_SANITY(ss, ar->start) == 0)
ar->start = 0;
return(1);
}
ar->setup = 8; /* Return address is always on stack */
/* Kludge. If we are sitting on 'ret' then the stack has been unwound,
* ignore all the startup code.
*/
if (kdb_getarea(instruction[0], pc))
return(0);
if (instruction[0] == 0xc3) {
/* ret */
unwound = 1;
}
if (kdb_getarea(instruction, code))
return(0);
if (!unwound && code < pc && instruction[0] == 0x55) {
/* pushl %rbp */
ar->setup += 8; /* Frame pointer is on stack */
oldfp_present = 1;
++code;
if (KDB_DEBUG(ARA)) {
kdb_printf(" pushq %%rbp\n");
}
if (code < pc && instruction[0] == 0x89 && instruction[1] == 0xe5) {
/* movl %esp,%ebp */
if (fp >= sp && SP_SANITY(ss, fp))
ar->fp = fp; /* %rbp has been set */
code += 2;
if (KDB_DEBUG(ARA)) {
kdb_printf(" movq %%rsp,%%rbp, fp=0x%lx\n", ar->fp);
}
}
}
if (!unwound && code < pc) {
if (instruction[0] == 0x83 && instruction[1] == 0xec) {
/* subl $xx,%rsp */
kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 1);
code += 3;
if (KDB_DEBUG(ARA)) {
kdb_printf(" subl $xx,%%rsp, locals=%ld\n", ar->locals);
}
} else if (instruction[0] == 0x81 && instruction[1] == 0xec) {
/* subl $xxxxxxxx,%rsp */
kdb_getword(&(ar->locals), (unsigned long)(instruction+2), 8);
code += 6;
if (KDB_DEBUG(ARA)) {
kdb_printf(" subl $xxxxxxxx,%%rsp, locals=%ld\n", ar->locals);
}
}
}
while (!unwound && code < pc &&
kdb_getarea(instruction, code) == 0 &&
(instruction[0] & 0xf8) == 0x50) {
/* pushl %reg */
ar->regs += 8;
++code;
if (KDB_DEBUG(ARA)) {
kdb_printf(" pushq %%reg, regs=%ld\n", ar->regs);
}
}
/* Check the return address. It must point within the kernel
* and the code at that location must be a valid entry sequence.
*/
if (ar->fp) {
ret_p = ar->fp + ar->setup;
}
else {
ret_p = ar->end + ar->regs + ar->locals + ar->setup;
}
ret_p -= 8;
if (KDB_DEBUG(ARA)) {
kdb_printf(" ret_p(0)=0x%lx\n", ret_p);
}
ar->ret = 0;
if ((SP_SANITY(ss, ret_p) != 0) &&
(ret_p = kdba_find_return(ret_p, ss, symtab))) {
kdb_getword(&(ar->ret), ret_p, 8);
}
if (KDB_DEBUG(ARA)) {
kdb_printf(" ret_p(1)=0x%lx ret=0x%lx\n", ret_p, ar->ret);
}
if (ar->ret) {
ar->fp = ret_p - ar->setup + 8; /* "accurate" fp */
ar->start = ret_p + 8;
if (KDB_DEBUG(ARA)) {
kdb_printf(" fp=0x%lx start=0x%lx\n", ar->fp, ar->start);
}
}
if (oldfp_present) {
if (ar->fp)
kdb_getword(&(ar->oldfp), ar->fp, 8);
if (KDB_DEBUG(ARA)) {
kdb_printf(" oldfp=0x%lx", ar->oldfp);
}
if (ar->oldfp <= ar->fp || (SP_SANITY(ss, ar->oldfp) == 0)) {
ar->oldfp = 0;
if (KDB_DEBUG(ARA)) {
kdb_printf(" (out of range)");
}
}
if (KDB_DEBUG(ARA)) {
kdb_printf("\n");
}
}
return(1);
}
kdb_machreg_t
kdba_getdr6(void)
{
return kdba_getdr(6);
}
kdb_machreg_t
kdba_getdr7(void)
{
return kdba_getdr(7);
}
void
kdba_putdr6(kdb_machreg_t contents)
{
kdba_putdr(6, contents);
}
static void
kdba_putdr7(kdb_machreg_t contents)
{
kdba_putdr(7, contents);
}
void
kdba_installdbreg(kdb_bp_t *bp)
{
kdb_machreg_t dr7;
dr7 = kdba_getdr7();
kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr);
dr7 |= DR7_GE;
if (cpu_has_de)
set_in_cr4(X86_CR4_DE);
switch (bp->bp_hard->bph_reg){
case 0:
DR7_RW0SET(dr7,bp->bp_hard->bph_mode);
DR7_LEN0SET(dr7,bp->bp_hard->bph_length);
DR7_G0SET(dr7);
break;
case 1:
DR7_RW1SET(dr7,bp->bp_hard->bph_mode);
DR7_LEN1SET(dr7,bp->bp_hard->bph_length);
DR7_G1SET(dr7);
break;
case 2:
DR7_RW2SET(dr7,bp->bp_hard->bph_mode);
DR7_LEN2SET(dr7,bp->bp_hard->bph_length);
DR7_G2SET(dr7);
break;
case 3:
DR7_RW3SET(dr7,bp->bp_hard->bph_mode);
DR7_LEN3SET(dr7,bp->bp_hard->bph_length);
DR7_G3SET(dr7);
break;
default:
kdb_printf("kdb: Bad debug register!! %ld\n",
bp->bp_hard->bph_reg);
break;
}
kdba_putdr7(dr7);
return;
}
void
kdba_removedbreg(kdb_bp_t *bp)
{
int regnum;
kdb_machreg_t dr7;
if (!bp->bp_hard)
return;
regnum = bp->bp_hard->bph_reg;
dr7 = kdba_getdr7();
kdba_putdr(regnum, 0);
switch (regnum) {
case 0:
DR7_G0CLR(dr7);
DR7_L0CLR(dr7);
break;
case 1:
DR7_G1CLR(dr7);
DR7_L1CLR(dr7);
break;
case 2:
DR7_G2CLR(dr7);
DR7_L2CLR(dr7);
break;
case 3:
DR7_G3CLR(dr7);
DR7_L3CLR(dr7);
break;
default:
kdb_printf("kdb: Bad debug register!! %d\n", regnum);
break;
}
kdba_putdr7(dr7);
}
kdb_machreg_t
kdba_getdr(int regnum)
{
kdb_machreg_t contents = 0;
switch(regnum) {
case 0:
__asm__ ("movq %%db0,%0\n\t":"=r"(contents));
break;
case 1:
__asm__ ("movq %%db1,%0\n\t":"=r"(contents));
break;
case 2:
__asm__ ("movq %%db2,%0\n\t":"=r"(contents));
break;
case 3:
__asm__ ("movq %%db3,%0\n\t":"=r"(contents));
break;
case 4:
case 5:
break;
case 6:
__asm__ ("movq %%db6,%0\n\t":"=r"(contents));
break;
case 7:
__asm__ ("movq %%db7,%0\n\t":"=r"(contents));
break;
default:
break;
}
return contents;
}
kdb_machreg_t
kdb_getcr(int regnum)
{
kdb_machreg_t contents = 0;
switch(regnum) {
case 0:
__asm__ ("movq %%cr0,%0\n\t":"=r"(contents));
break;
case 1:
break;
case 2:
__asm__ ("movq %%cr2,%0\n\t":"=r"(contents));
break;
case 3:
__asm__ ("movq %%cr3,%0\n\t":"=r"(contents));
break;
case 4:
__asm__ ("movq %%cr4,%0\n\t":"=r"(contents));
break;
default:
break;
}
return contents;
}
void
kdba_putdr(int regnum, kdb_machreg_t contents)
{
switch(regnum) {
case 0:
__asm__ ("movq %0,%%db0\n\t"::"r"(contents));
break;
case 1:
__asm__ ("movq %0,%%db1\n\t"::"r"(contents));
break;
case 2:
__asm__ ("movq %0,%%db2\n\t"::"r"(contents));
break;
case 3:
__asm__ ("movq %0,%%db3\n\t"::"r"(contents));
break;
case 4:
case 5:
break;
case 6:
__asm__ ("movq %0,%%db6\n\t"::"r"(contents));
break;
case 7:
__asm__ ("movq %0,%%db7\n\t"::"r"(contents));
break;
default:
break;
}
}
/*
* kdba_getregcontents
*
* Return the contents of the register specified by the
* input string argument. Return an error if the string
* does not match a machine register.
*
* The following pseudo register names are supported:
* ®s - Prints address of exception frame
* krsp - Prints kernel stack pointer at time of fault
* crsp - Prints current kernel stack pointer, inside kdb
* ceflags - Prints current flags, inside kdb
* %<regname> - Uses the value of the registers at the
* last time the user process entered kernel
* mode, instead of the registers at the time
* kdb was entered.
*
* Parameters:
* regname Pointer to string naming register
* regs Pointer to structure containing registers.
* Outputs:
* *contents Pointer to unsigned long to recieve register contents
* Returns:
* 0 Success
* KDB_BADREG Invalid register name
* Locking:
* None.
* Remarks:
* If kdb was entered via an interrupt from the kernel itself then
* ss and rsp are *not* on the stack.
*/
static struct kdbregs {
char *reg_name;
size_t reg_offset;
} kdbreglist[] = {
{ "r15", offsetof(struct pt_regs, r15) },
{ "r14", offsetof(struct pt_regs, r14) },
{ "r13", offsetof(struct pt_regs, r13) },
{ "r12", offsetof(struct pt_regs, r12) },
{ "rbp", offsetof(struct pt_regs, rbp) },
{ "rbx", offsetof(struct pt_regs, rbx) },
{ "r11", offsetof(struct pt_regs, r11) },
{ "r10", offsetof(struct pt_regs, r10) },
{ "r9", offsetof(struct pt_regs, r9) },
{ "r8", offsetof(struct pt_regs, r8) },
{ "rax", offsetof(struct pt_regs, rax) },
{ "rcx", offsetof(struct pt_regs, rcx) },
{ "rdx", offsetof(struct pt_regs, rdx) },
{ "rsi", offsetof(struct pt_regs, rsi) },
{ "rdi", offsetof(struct pt_regs, rdi) },
{ "orig_rax", offsetof(struct pt_regs, orig_rax) },
{ "rip", offsetof(struct pt_regs, rip) },
{ "cs", offsetof(struct pt_regs, cs) },
{ "eflags", offsetof(struct pt_regs, eflags) },
{ "rsp", offsetof(struct pt_regs, rsp) },
{ "ss", offsetof(struct pt_regs, ss) },
};
static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs);
static struct kdbregs dbreglist[] = {
{ "dr0", 0 },
{ "dr1", 1 },
{ "dr2", 2 },
{ "dr3", 3 },
{ "dr6", 6 },
{ "dr7", 7 },
};
static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs);
int
kdba_getregcontents(const char *regname,
struct pt_regs *regs,
kdb_machreg_t *contents)
{
int i;
if (strcmp(regname, "®s") == 0) {
*contents = (unsigned long)regs;
return 0;
}
if (strcmp(regname, "krsp") == 0) {
*contents = (unsigned long)regs + sizeof(struct pt_regs);
if ((regs->cs & 0xffff) == __KERNEL_CS) {
/* rsp and ss are not on stack */
*contents -= 2*4;
}
return 0;
}
if (strcmp(regname, "crsp") == 0) {
asm volatile("movq %%rsp,%0":"=m" (*contents));
return 0;
}
if (strcmp(regname, "ceflags") == 0) {
unsigned long flags;
local_save_flags(flags);
*contents = flags;
return 0;
}
if (regname[0] == '%') {
/* User registers: %%r[a-c]x, etc */
regname++;
regs = (struct pt_regs *)
(current->thread.rsp0 - sizeof(struct pt_regs));
}
for (i=0; i<nkdbreglist; i++) {
if (strnicmp(kdbreglist[i].reg_name,
regname,
strlen(regname)) == 0)
break;
}
if ((i < nkdbreglist)
&& (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
if ((regs->cs & 0xffff) == __KERNEL_CS) {
/* No cpl switch, rsp is not on stack */
if (strcmp(kdbreglist[i].reg_name, "rsp") == 0) {
*contents = (kdb_machreg_t)regs +
sizeof(struct pt_regs) - 2*8;
return(0);
}
if (strcmp(kdbreglist[i].reg_name, "ss") == 0) {
kdb_machreg_t r;
r = (kdb_machreg_t)regs +
sizeof(struct pt_regs) - 2*8;
*contents = (kdb_machreg_t)SS(r); /* XXX */
return(0);
}
}
*contents = *(unsigned long *)((unsigned long)regs +
kdbreglist[i].reg_offset);
return(0);
}
for (i=0; i<ndbreglist; i++) {
if (strnicmp(dbreglist[i].reg_name,
regname,
strlen(regname)) == 0)
break;
}
if ((i < ndbreglist)
&& (strlen(dbreglist[i].reg_name) == strlen(regname))) {
*contents = kdba_getdr(dbreglist[i].reg_offset);
return 0;
}
return KDB_BADREG;
}
/*
* kdba_setregcontents
*
* Set the contents of the register specified by the
* input string argument. Return an error if the string
* does not match a machine register.
*
* Supports modification of user-mode registers via
* %<register-name>
*
* Parameters:
* regname Pointer to string naming register
* regs Pointer to structure containing registers.
* contents Unsigned long containing new register contents
* Outputs:
* Returns:
* 0 Success
* KDB_BADREG Invalid register name
* Locking:
* None.
* Remarks:
*/
int
kdba_setregcontents(const char *regname,
struct pt_regs *regs,
unsigned long contents)
{
int i;
if (regname[0] == '%') {
regname++;
regs = (struct pt_regs *)
(current->thread.rsp0 - sizeof(struct pt_regs));
}
for (i=0; i<nkdbreglist; i++) {
if (strnicmp(kdbreglist[i].reg_name,
regname,
strlen(regname)) == 0)
break;
}
if ((i < nkdbreglist)
&& (strlen(kdbreglist[i].reg_name) == strlen(regname))) {
*(unsigned long *)((unsigned long)regs
+ kdbreglist[i].reg_offset) = contents;
return 0;
}
for (i=0; i<ndbreglist; i++) {
if (strnicmp(dbreglist[i].reg_name,
regname,
strlen(regname)) == 0)
break;
}
if ((i < ndbreglist)
&& (strlen(dbreglist[i].reg_name) == strlen(regname))) {
kdba_putdr(dbreglist[i].reg_offset, contents);
return 0;
}
return KDB_BADREG;
}
/*
* kdba_dumpregs
*
* Dump the specified register set to the display.
*
* Parameters:
* regs Pointer to structure containing registers.
* type Character string identifying register set to dump
* extra string further identifying register (optional)
* Outputs:
* Returns:
* 0 Success
* Locking:
* None.
* Remarks:
* This function will dump the general register set if the type
* argument is NULL (struct pt_regs). The alternate register
* set types supported by this function:
*
* d Debug registers
* c Control registers
* u User registers at most recent entry to kernel
* Following not yet implemented:
* m Model Specific Registers (extra defines register #)
* r Memory Type Range Registers (extra defines register)
*/
int
kdba_dumpregs(struct pt_regs *regs,
const char *type,
const char *extra)
{
int i;
int count = 0;
if (type
&& (type[0] == 'u')) {
type = NULL;
regs = (struct pt_regs *)
(current->thread.rsp0 - sizeof(struct pt_regs));
}
if (type == NULL) {
struct kdbregs *rlp;
kdb_machreg_t contents;
for (i=0, rlp=kdbreglist; i<nkdbreglist; i++,rlp++) {
kdb_printf("%8s = ", rlp->reg_name);
kdba_getregcontents(rlp->reg_name, regs, &contents);
kdb_printf("0x%016lx ", contents);
if ((++count % 2) == 0)
kdb_printf("\n");
}
kdb_printf("®s = 0x%p\n", regs);
return 0;
}
switch (type[0]) {
case 'd':
{
unsigned long dr[8];
for(i=0; i<8; i++) {
if ((i == 4) || (i == 5)) continue;
dr[i] = kdba_getdr(i);
}
kdb_printf("dr0 = 0x%08lx dr1 = 0x%08lx dr2 = 0x%08lx dr3 = 0x%08lx\n",
dr[0], dr[1], dr[2], dr[3]);
kdb_printf("dr6 = 0x%08lx dr7 = 0x%08lx\n",
dr[6], dr[7]);
return 0;
}
case 'c':
{
unsigned long cr[5];
for (i=0; i<5; i++) {
cr[i] = kdb_getcr(i);
}
kdb_printf("cr0 = 0x%08lx cr1 = 0x%08lx cr2 = 0x%08lx cr3 = 0x%08lx\ncr4 = 0x%08lx\n",
cr[0], cr[1], cr[2], cr[3], cr[4]);
return 0;
}
case 'm':
break;
case 'r':
break;
default:
return KDB_BADREG;
}
/* NOTREACHED */
return 0;
}
kdb_machreg_t
kdba_getpc(struct pt_regs *regs)
{
return regs->rip;
}
int
kdba_setpc(struct pt_regs *regs, kdb_machreg_t newpc)
{
if (KDB_NULL_REGS(regs))
return KDB_BADREG;
regs->rip = newpc;
KDB_STATE_SET(IP_ADJUSTED);
return 0;
}
/*
* kdba_main_loop
*
* Do any architecture specific set up before entering the main kdb loop.
* The primary function of this routine is to make all processes look the
* same to kdb, kdb must be able to list a process without worrying if the
* process is running or blocked, so make all process look as though they
* are blocked.
*
* Inputs:
* reason The reason KDB was invoked
* error The hardware-defined error code
* error2 kdb's current reason code. Initially error but can change
* acording to kdb state.
* db_result Result from break or debug point.
* ef The exception frame at time of fault/breakpoint. If reason
* is KDB_REASON_SILENT then ef is NULL, otherwise it should
* always be valid.
* Returns:
* 0 KDB was invoked for an event which it wasn't responsible
* 1 KDB handled the event for which it was invoked.
* Outputs:
* Sets rip and rsp in current->thread.
* Locking:
* None.
* Remarks:
* none.
*/
int
kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error,
kdb_dbtrap_t db_result, struct pt_regs *regs)
{
int ret;
if (regs)
kdba_getregcontents("rsp", regs, &(current->thread.rsp));
kdb_save_running(regs);
ret = kdb_main_loop(reason, reason2, error, db_result, regs);
kdb_unsave_running(regs);
return ret;
}
void
kdba_disableint(kdb_intstate_t *state)
{
unsigned long *fp = (unsigned long *)state;
unsigned long flags;
local_irq_save(flags);
*fp = flags;
}
void
kdba_restoreint(kdb_intstate_t *state)
{
unsigned long flags = *(unsigned long *)state;
local_irq_restore(flags);
}
void
kdba_setsinglestep(struct pt_regs *regs)
{
if (KDB_NULL_REGS(regs))
return;
if (regs->eflags & EF_IE)
KDB_STATE_SET(A_IF);
else
KDB_STATE_CLEAR(A_IF);
regs->eflags = (regs->eflags | EF_TF) & ~EF_IE;
}
void
kdba_clearsinglestep(struct pt_regs *regs)
{
if (KDB_NULL_REGS(regs))
return;
if (KDB_STATE(A_IF))
regs->eflags |= EF_IE;
else
regs->eflags &= ~EF_IE;
}
#ifdef KDB_HAVE_LONGJMP
int asmlinkage
kdba_setjmp(kdb_jmp_buf *jb)
{
#if defined(CONFIG_FRAME_POINTER)
__asm__("movq %rbx, (0*8)(%rdi);"
"movq %rbp, (1*8)(%rdi);"
"movq %r12, (2*8)(%rdi);"
"movq %r13, (3*8)(%rdi);"
"movq %r14, (4*8)(%rdi);"
"movq %r15, (5*8)(%rdi);"
"leaq 16(%rsp), %rdx;"
"movq %rdx, (6*8)(%rdi);"
"movq (%rsp), %rax;"
"movq %rax, (7*8)(%rdi)");
#else /* CONFIG_FRAME_POINTER */
__asm__("movq %rbx, (0*8)(%rdi);"
"movq %rbp, (1*8)(%rdi);"
"movq %r12, (2*8)(%rdi);"
"movq %r13, (3*8)(%rdi);"
"movq %r14, (4*8)(%rdi);"
"movq %r15, (5*8)(%rdi);"
"leaq 8(%rsp), %rdx;"
"movq %rdx, (6*8)(%rdi);"
"movq (%rsp), %rax;"
"movq %rax, (7*8)(%rdi)");
#endif /* CONFIG_FRAME_POINTER */
KDB_STATE_SET(LONGJMP);
return 0;
}
void asmlinkage
kdba_longjmp(kdb_jmp_buf *jb, int reason)
{
#if defined(CONFIG_FRAME_POINTER)
__asm__("movq (0*8)(%rdi),%rbx;"
"movq (1*8)(%rdi),%rbp;"
"movq (2*8)(%rdi),%r12;"
"movq (3*8)(%rdi),%r13;"
"movq (4*8)(%rdi),%r14;"
"movq (5*8)(%rdi),%r15;"
"test %esi,%esi;"
"mov $01,%eax;"
"cmove %eax,%esi;"
"mov %esi, %eax;"
"movq (7*8)(%rdi),%rdx;"
"movq (6*8)(%rdi),%rsp;"
"jmpq *%rdx");
#else /* CONFIG_FRAME_POINTER */
__asm__("movq (0*8)(%rdi),%rbx;"
"movq (1*8)(%rdi),%rbp;"
"movq (2*8)(%rdi),%r12;"
"movq (3*8)(%rdi),%r13;"
"movq (4*8)(%rdi),%r14;"
"movq (5*8)(%rdi),%r15;"
"test %esi,%esi;"
"mov $01,%eax;"
"cmove %eax,%esi;"
"mov %esi, %eax;"
"movq (7*8)(%rdi),%rdx;"
"movq (6*8)(%rdi),%rsp;"
"jmpq *%rdx");
#endif /* CONFIG_FRAME_POINTER */
}
#endif /* KDB_HAVE_LONGJMP */
/*
* kdba_enable_lbr
*
* Enable last branch recording.
*
* Parameters:
* None.
* Returns:
* None
* Locking:
* None
* Remarks:
* None.
*/
static unsigned char lbr_warned;
void
kdba_enable_lbr(void)
{
u32 lv, hv;
if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) {
if (lbr_warned) {
kdb_printf("kdb: machine does not support last branch recording\n");
lbr_warned = 1;
}
return;
}
rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
lv |= 0x1; /* Set LBR enable */
wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
}
/*
* kdba_disable_lbr
*
* disable last branch recording.
*
* Parameters:
* None.
* Returns:
* None
* Locking:
* None
* Remarks:
* None.
*/
void
kdba_disable_lbr(void)
{
u32 lv, hv;
if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) {
if (lbr_warned) {
kdb_printf("kdb: machine does not support last branch recording\n");
lbr_warned = 1;
}
return;
}
rdmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
lv &= ~0x1; /* Set LBR disable */
wrmsr(MSR_IA32_DEBUGCTLMSR, lv, hv);
}
/*
* kdba_print_lbr
*
* Print last branch and last exception addresses
*
* Parameters:
* None.
* Returns:
* None
* Locking:
* None
* Remarks:
* None.
*/
void
kdba_print_lbr(void)
{
u32 from, to, dummy;
if (!test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability))
return;
rdmsr(MSR_IA32_LASTBRANCHFROMIP, from, dummy);
rdmsr(MSR_IA32_LASTBRANCHTOIP, to, dummy);
kdb_printf("Last Branch IP, from: ");
kdb_symbol_print(from, NULL, KDB_SP_DEFAULT);
kdb_printf(" to: ");
kdb_symbol_print(to, NULL, KDB_SP_DEFAULT);
kdb_printf("\n");
rdmsr(MSR_IA32_LASTINTFROMIP, from, dummy);
rdmsr(MSR_IA32_LASTINTTOIP, to, dummy);
kdb_printf("Last Int IP, from: ");
kdb_symbol_print(from, NULL, KDB_SP_DEFAULT);
kdb_printf(" to: ");
kdb_symbol_print(to, NULL, KDB_SP_DEFAULT);
kdb_printf("\n");
}
/*
* kdba_entry
*
* This is the interface routine between
* the notifier die_chain and kdb
*/
static int kdba_entry( struct notifier_block *b, unsigned long val, void *v)
{
struct die_args *args = v;
int err, trap, ret = 0;
struct pt_regs *regs;
regs = args->regs;
err = args->err;
trap = args->trapnr;
switch (val){
#if defined(CONFIG_SMP)
case DIE_NMI_IPI:
ret = kdb_ipi(regs, NULL);
break;
#endif
case DIE_OOPS:
ret = kdb(KDB_REASON_OOPS, err, regs);
break;
case DIE_CALL:
ret = kdb(KDB_REASON_ENTER, err, regs);
break;
case DIE_DEBUG:
ret = kdb(KDB_REASON_DEBUG, err, regs);
break;
case DIE_INT3:
ret = kdb(KDB_REASON_BREAK, err, regs);
// falls thru
default:
break;
}
return (ret ? NOTIFY_STOP : NOTIFY_DONE);
}
/*
* notifier block for kdb entry
*/
static struct notifier_block kdba_notifier = {
.notifier_call = kdba_entry
};
/*
* kdba_init
*
* Architecture specific initialization.
*
* Parameters:
* None.
* Returns:
* None.
* Locking:
* None.
* Remarks:
* None.
*/
void __init
kdba_init(void)
{
kdba_enable_lbr();
atomic_notifier_chain_register(&die_chain, &kdba_notifier);
return;
}
/*
* kdba_adjust_ip
*
* Architecture specific adjustment of instruction pointer before leaving
* kdb.
*
* Parameters:
* reason The reason KDB was invoked
* error The hardware-defined error code
* ef The exception frame at time of fault/breakpoint. If reason
* is KDB_REASON_SILENT then ef is NULL, otherwise it should
* always be valid.
* Returns:
* None.
* Locking:
* None.
* Remarks:
* noop on ix86.
*/
void
kdba_adjust_ip(kdb_reason_t reason, int error, struct pt_regs *ef)
{
return;
}
/* dummy code to make common layer happy for now */
void
kdba_enable_mce(void)
{
}
void
kdba_set_current_task(const struct task_struct *p)
{
kdb_current_task = p;
if (kdb_task_has_cpu(p)) {
struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p);
kdb_current_regs = krp->regs;
return;
}
kdb_current_regs = NULL;
}
#ifdef CONFIG_SMP // This is a hack, sigh...
void
smp_kdb_stop(void)
{
send_IPI_allbutself(NMI_VECTOR);
}
#endif