[RFC Patch v1 39/55] ARC: kernel diagnostics: show_regs() etc
From: Vineet Gupta Signed-off-by: Vineet Gupta --- arch/arc/kernel/troubleshoot.c | 304 arch/arc/mm/tlbex.S| 20 +++ 2 files changed, 324 insertions(+), 0 deletions(-) diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index 80bfe2a..8a816f2 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -6,12 +6,316 @@ */ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25) + * -Prints 3 regs per line and a CR. + * -To continue, callee regs right after scratch, special handling of CR + */ +static noinline void print_reg_file(long *reg_rev, int start_num) +{ + unsigned int i; + char buf[512]; + int n = 0, len = sizeof(buf); + + /* weird loop because pt_regs regs rev r12..r0, r25..r13 */ + for (i = start_num; i < start_num + 13; i++) { + n += scnprintf(buf + n, len - n, "r%02u: 0x%08lx\t", + i, (unsigned long)*reg_rev); + + if (((i + 1) % 3) == 0) + n += scnprintf(buf + n, len - n, "\n"); + + reg_rev--; + } + + if (start_num != 0) + n += scnprintf(buf + n, len - n, "\n\n"); + + pr_info("%s", buf); +} + +static void show_callee_regs(struct callee_regs *cregs) +{ + print_reg_file(&(cregs->r13), 13); +} + +void print_task_path_n_nm(struct task_struct *task, char *buf) +{ + struct path path; + char *nm = NULL; + struct mm_struct *mm; + struct file *exe_file; + char comm_buf[TASK_COMM_LEN]; + + mm = get_task_mm(task); + if (!mm) + goto done; + + exe_file = get_mm_exe_file(mm); + mmput(mm); + + if (exe_file) { + path = exe_file->f_path; + path_get(_file->f_path); + fput(exe_file); + nm = d_path(, buf, 255); + path_put(); + } + +done: + pr_info("task = %s '%s', TGID %u PID = %u\n", nm, + get_task_comm(comm_buf, task), task->tgid, task->pid); +} +EXPORT_SYMBOL(print_task_path_n_nm); + +static void show_faulting_vma(unsigned long address, char *buf) +{ + struct vm_area_struct *vma; + struct inode *inode; + unsigned long ino = 0; + dev_t dev = 0; + char *nm = buf; + + vma = find_vma(current->active_mm, address); + + /* check against the find_vma( ) behaviour which returns the next VMA +* if the container VMA is not found +*/ + if (vma && (vma->vm_start <= address)) { + struct file *file = vma->vm_file; + if (file) { + struct path *path = >f_path; + nm = d_path(path, buf, PAGE_SIZE - 1); + inode = vma->vm_file->f_path.dentry->d_inode; + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } + pr_info("@off 0x%lx in [%s]\n" + "VMA: 0x%08lx to 0x%08lx\n\n", + address - vma->vm_start, nm, vma->vm_start, vma->vm_end); + } else + pr_info("@No matching VMA found\n"); +} + +static void show_ecr_verbose(struct pt_regs *regs) +{ + unsigned int vec, cause_code, cause_reg; + unsigned long address; + + cause_reg = current->thread.cause_code; + pr_info("\n[ECR]: 0x%08x => ", cause_reg); + + /* For Data fault, this is data address not instruction addr */ + address = current->thread.fault_address; + + vec = cause_reg >> 16; + cause_code = (cause_reg >> 8) & 0xFF; + + /* For DTLB Miss or ProtV, display the memory involved too */ + if (vec == ECR_V_DTLB_MISS) { + pr_cont("Invalid (%s) @ 0x%08lx by insn @ 0x%08lx\n", + (cause_code == 0x01) ? "Read From" : + ((cause_code == 0x02) ? "Write to" : "EX"), + address, regs->ret); + } else if (vec == ECR_V_ITLB_MISS) { + pr_cont("Insn could not be fetched\n"); + } else if (vec == ECR_V_MACH_CHK) { + pr_cont("%s\n", (cause_code == 0x0) ? + "Double Fault" : "Other Fatal Err"); + + } else if (vec == ECR_V_PROTV) { + if (cause_code == ECR_C_PROTV_INST_FETCH) + pr_cont("Execute from Non-exec Page\n"); + else if (cause_code == ECR_C_PROTV_LOAD) + pr_cont("Read from Non-readable Page\n"); + else if (cause_code == ECR_C_PROTV_STORE) + pr_cont("Write to Non-writable Page\n"); + else if (cause_code == ECR_C_PROTV_XCHG) + pr_cont("Data exchange protection violation\n"); +
[RFC Patch v1 39/55] ARC: kernel diagnostics: show_regs() etc
From: Vineet Gupta vgu...@synopsys.com Signed-off-by: Vineet Gupta vgu...@synopsys.com --- arch/arc/kernel/troubleshoot.c | 304 arch/arc/mm/tlbex.S| 20 +++ 2 files changed, 324 insertions(+), 0 deletions(-) diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index 80bfe2a..8a816f2 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -6,12 +6,316 @@ */ #include linux/ptrace.h +#include linux/module.h +#include linux/mm.h +#include linux/fs.h +#include linux/kdev_t.h +#include linux/fs_struct.h +#include linux/proc_fs.h +#include linux/file.h +#include asm/arcregs.h +#include asm/event-log.h + +/* + * Common routine to print scratch regs (r0-r12) or callee regs (r13-r25) + * -Prints 3 regs per line and a CR. + * -To continue, callee regs right after scratch, special handling of CR + */ +static noinline void print_reg_file(long *reg_rev, int start_num) +{ + unsigned int i; + char buf[512]; + int n = 0, len = sizeof(buf); + + /* weird loop because pt_regs regs rev r12..r0, r25..r13 */ + for (i = start_num; i start_num + 13; i++) { + n += scnprintf(buf + n, len - n, r%02u: 0x%08lx\t, + i, (unsigned long)*reg_rev); + + if (((i + 1) % 3) == 0) + n += scnprintf(buf + n, len - n, \n); + + reg_rev--; + } + + if (start_num != 0) + n += scnprintf(buf + n, len - n, \n\n); + + pr_info(%s, buf); +} + +static void show_callee_regs(struct callee_regs *cregs) +{ + print_reg_file((cregs-r13), 13); +} + +void print_task_path_n_nm(struct task_struct *task, char *buf) +{ + struct path path; + char *nm = NULL; + struct mm_struct *mm; + struct file *exe_file; + char comm_buf[TASK_COMM_LEN]; + + mm = get_task_mm(task); + if (!mm) + goto done; + + exe_file = get_mm_exe_file(mm); + mmput(mm); + + if (exe_file) { + path = exe_file-f_path; + path_get(exe_file-f_path); + fput(exe_file); + nm = d_path(path, buf, 255); + path_put(path); + } + +done: + pr_info(task = %s '%s', TGID %u PID = %u\n, nm, + get_task_comm(comm_buf, task), task-tgid, task-pid); +} +EXPORT_SYMBOL(print_task_path_n_nm); + +static void show_faulting_vma(unsigned long address, char *buf) +{ + struct vm_area_struct *vma; + struct inode *inode; + unsigned long ino = 0; + dev_t dev = 0; + char *nm = buf; + + vma = find_vma(current-active_mm, address); + + /* check against the find_vma( ) behaviour which returns the next VMA +* if the container VMA is not found +*/ + if (vma (vma-vm_start = address)) { + struct file *file = vma-vm_file; + if (file) { + struct path *path = file-f_path; + nm = d_path(path, buf, PAGE_SIZE - 1); + inode = vma-vm_file-f_path.dentry-d_inode; + dev = inode-i_sb-s_dev; + ino = inode-i_ino; + } + pr_info(@off 0x%lx in [%s]\n + VMA: 0x%08lx to 0x%08lx\n\n, + address - vma-vm_start, nm, vma-vm_start, vma-vm_end); + } else + pr_info(@No matching VMA found\n); +} + +static void show_ecr_verbose(struct pt_regs *regs) +{ + unsigned int vec, cause_code, cause_reg; + unsigned long address; + + cause_reg = current-thread.cause_code; + pr_info(\n[ECR]: 0x%08x = , cause_reg); + + /* For Data fault, this is data address not instruction addr */ + address = current-thread.fault_address; + + vec = cause_reg 16; + cause_code = (cause_reg 8) 0xFF; + + /* For DTLB Miss or ProtV, display the memory involved too */ + if (vec == ECR_V_DTLB_MISS) { + pr_cont(Invalid (%s) @ 0x%08lx by insn @ 0x%08lx\n, + (cause_code == 0x01) ? Read From : + ((cause_code == 0x02) ? Write to : EX), + address, regs-ret); + } else if (vec == ECR_V_ITLB_MISS) { + pr_cont(Insn could not be fetched\n); + } else if (vec == ECR_V_MACH_CHK) { + pr_cont(%s\n, (cause_code == 0x0) ? + Double Fault : Other Fatal Err); + + } else if (vec == ECR_V_PROTV) { + if (cause_code == ECR_C_PROTV_INST_FETCH) + pr_cont(Execute from Non-exec Page\n); + else if (cause_code == ECR_C_PROTV_LOAD) + pr_cont(Read from Non-readable Page\n); + else if (cause_code == ECR_C_PROTV_STORE) + pr_cont(Write to Non-writable Page\n); +