/*************************************************************************** * * Copyright (C) 2001 International Business Machines * All rights reserved. * * This file is part of the GPFS mmfslinux kernel module. * * 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * *************************************************************************** */ /* @(#)62 1.41.1.3 src/avs/fs/mmfs/ts/kernext/gpl-linux/kdump-kern.c, mmfs, avs_rgpfs24, rgpfs24s011a 3/14/07 10:56:41 */ /* Code for program to dump kernel memory that needs to include kernel header files. */ /* * Contents: * KernInit * GenericGet * GetDentry * FreeDentry * GetInode * GetVFSMount * GetSuperBlock * GetRootSuperBlock * GetPage * GetAddressSpace * GetVMAreaStruct * GetMMStruct * GetTaskStruct * GetTaskStructByPID * P_HEADER * PrintDentry * PrintDentryTree * PrintInode * PrintSuperBlock * PrintPage * PrintAddressSpace * PrintVMAreaStruct * PrintMMStruct * PrintTaskStruct * VirtToReal * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NOSTABS /* Address of header of the list of all super_blocks */ unsigned long super_blocks_addr = 0x103; /* Address of a task_struct on the list of all tasks */ unsigned long TaskAddress = 0x104; /* Address of the struct page of the first page in memory */ unsigned long MemMapAddr; extern unsigned long HighSymbolAddr; /* Maco for printing some number of spaces */ static char *blanksP = " "; #define BLANKS(n) (blanksP + strlen(blanksP) - (n)) /* A structure to keep track of current position when stepping through all threads. */ struct threadIter { unsigned long taskAddr, threadAddr; struct task_struct *taskP, *threadP; }; /* initialize thread iterator */ static void tiInit(struct threadIter *ti) { ti->taskAddr = ti->threadAddr = TaskAddress; ti->taskP = ti->threadP = GetTaskStruct(ti->taskAddr); } unsigned long GetOffset(int fMap) { #if defined(GPFS_ARCH_X86_64) && LINUX_KERNEL_VERSION >= 2061600 /* rw_verify_area does not allow kernel addr range, so a read() will fail with EINVAL. We subtract the base base kernel addr here and add it back in the read file op in tracelin.c */ if (fMap) return(__START_KERNEL_map); else return(__PAGE_OFFSET); #else return(0); #endif } /* Free threadIter memory. If tiNext returns false, then it isn't necessary to call this. */ static void tiDone(struct threadIter *ti) { kFree(ti->taskP); if (ti->threadP != ti->taskP) kFree(ti->threadP); ti->taskP = ti->threadP = NULL; } /* Step to next thread in current task. If no more threads, step to next task. If no more tasks, return false. */ static Boolean tiNext(struct threadIter *ti) { #if LINUX_KERNEL_VERSION >= 2060000 #if LINUX_KERNEL_VERSION < 2060900 unsigned long pidAddr, headAddr, nextAddr; struct pid_link *linkP; assert(ti->taskP != NULL); linkP = &ti->threadP->pids[PIDTYPE_TGID]; pidAddr = (unsigned long) linkP->pidptr; headAddr = pidAddr + offsetof(struct pid, task_list); nextAddr = (unsigned long) linkP->pid_chain.next; if (nextAddr == headAddr) { struct pid *pidP = GenericGet(pidAddr, sizeof(struct pid), 0); nextAddr = (unsigned long) pidP->task_list.next; kFree(pidP); } #else //unsigned long nextAddr; //nextAddr = (unsigned long) ti->threadP->pids[PIDTYPE_TGID].pid_list.next; #endif //ti->threadAddr = (unsigned long) pid_task((struct list_head *) nextAddr, // PIDTYPE_TGID); ti->threadAddr = (unsigned long) next_thread(ti->threadP); if (ti->threadAddr != ti->taskAddr) { if (ti->threadP != ti->taskP) kFree(ti->threadP); ti->threadP = GetTaskStruct(ti->threadAddr); } else { ti->taskAddr = ti->threadAddr = (unsigned long) NEXT_TASK(ti->taskP); kFree(ti->taskP); if (ti->threadP != ti->taskP) kFree(ti->threadP); ti->taskP = ti->threadP = (ti->taskAddr == TaskAddress) ? NULL : GetTaskStruct(ti->taskAddr); } return ti->threadP != NULL; #else assert(ti->taskP != NULL); ti->taskAddr = ti->threadAddr = (unsigned long) NEXT_TASK(ti->taskP); kFree(ti->taskP); ti->taskP = ti->threadP = (ti->taskAddr == TaskAddress) ? NULL : GetTaskStruct(ti->taskAddr); return ti->threadP != NULL; #endif } /* Routine to initialize stuff needing access to kernel declarations */ void KernInit() { struct Symbol* sP; int rc; struct vm_struct * vmlist; struct vm_struct v; struct vmStruct* aListP; struct vmStruct** prevPP; unsigned long highMem; unsigned long endAddr; /* Set bounds of valid kernel memory */ sP = LookupSymbolByName("_stext"); assert(sP != 0); LowKernelAddr = sP->addr; #if defined(GPFS_ARCH_I386) || defined(GPFS_ARCH_X86_64) LowKernelAddr = PAGE_OFFSET; #endif rc = GetSymbolValue("high_memory", &highMem, sizeof(HighKernelAddr)); assert(rc == 0); sP = LookupSymbolByName("_end"); assert(sP != 0); endAddr = sP->addr; if (endAddr > highMem) HighKernelAddr = endAddr; else HighKernelAddr = highMem; if (!isCore) { /* Traverse vm_struct list in kernel starting at vmlist and build corresponding list of vmStructs describing valid kernel addresses */ rc = GetSymbolValue("vmlist", &vmlist, sizeof(vmlist)); assert(rc == 0); vmListHeadP = NULL; prevPP = &vmListHeadP; while (vmlist != NULL) { rc = ReadKernel((unsigned long)vmlist, &v, sizeof(v), 0); assert(rc == 0); aListP = (struct vmStruct*) kMalloc(sizeof(struct vmStruct)); assert(aListP != NULL); DBG(printf("vm_struct addr 0x%lX size %d\n", v.addr, v.size)); aListP->startAddr = (unsigned long) v.addr; aListP->areaLen = (unsigned long) v.size - PAGE_SIZE; aListP->nextAreaP = NULL; *prevPP = aListP; prevPP = &aListP->nextAreaP; vmlist = v.next; } } /* Get address of super_blocks, the head of the list of super_blocks threaded through the s_list field */ sP = LookupSymbolByName("super_blocks"); if (sP != NULL) super_blocks_addr = sP->addr; /* Get address of a task_struct on the list of all tasks */ sP = LookupSymbolByName("init_task_union"); if (sP == NULL) sP = LookupSymbolByName("init_task"); assert(sP != NULL); TaskAddress = sP->addr; /* Get address of the base of the array of struct pages */ #ifndef CONFIG_DISCONTIGMEM rc = GetSymbolValue("mem_map", &MemMapAddr, sizeof(MemMapAddr)); assert(rc == 0); #else MemMapAddr = 0; #endif } /* Generic get routine for kernel objects. Mallocs storage of the given size, then reads into the malloc'ed storage from the kernel address. Frees the object and returns NULL if the address was invalid. */ void* GenericGet(unsigned long addr, int len, int fMap) { int rc; void* p; DBG(printf("GenericGet: addr 0x%lX len %d\n", addr, len)); p = kMalloc(len); assert(p != NULL); rc = ReadKernel(addr, p, len, fMap); if (rc != 0) { kFree(p); return NULL; } return p; } /* Read a dentry from the kernel. Space may need to be allocated for the name string. */ void* GetDentry(unsigned long addr) { struct dentry* dP; char* nameP; int rc; dP = (struct dentry*) GenericGet(addr, sizeof(struct dentry), 0); if (dP != NULL) { if (dP->d_name.len > 1024) { kFree(dP); return NULL; } else if (dname_external(dP)) dP->d_name.name = dP->d_iname; else { nameP = (char*) kMalloc(dP->d_name.len+1); assert(nameP != NULL); rc = ReadKernel((unsigned long)dP->d_name.name, nameP, dP->d_name.len+1, 0); if (rc != 0) { kFree(nameP); kFree(dP); return NULL; } dP->d_name.name = nameP; } } return dP; } /* Free a dentry, including the name string */ void FreeDentry(void* p) { struct dentry* dP = (struct dentry*) p; if (dP == NULL) return; if (dname_external(dP)) kFree((void*)dP->d_name.name); kFree(dP); } /* Read an inode from the kernel */ void* GetInode(unsigned long addr) { return GenericGet(addr, sizeof(struct inode), 0); } /* Read an vfsmount from the kernel */ void* GetVFSMount(unsigned long addr) { return GenericGet(addr, sizeof(struct vfsmount), 0); } /* Read an fs_struct from the kernel */ void* GetFSStruct(unsigned long addr) { return GenericGet(addr, sizeof(struct fs_struct), 0); } /* Read a superblock from the kernel */ void* GetSuperBlock(unsigned long addr) { return GenericGet(addr, sizeof(struct super_block), 0); } /* Read first superblock on the superblock list */ void * GetRootSuperBlock(unsigned long * addrP) { struct list_head *listP; listP = (struct list_head *)GenericGet(super_blocks_addr, sizeof(struct list_head), 1); if (listP == NULL) { *addrP = 0; return NULL; } if ((unsigned long)listP->next == super_blocks_addr) { /* super block list is empty */ *addrP = 0; return NULL; } *addrP = (unsigned long)list_entry(listP->next, struct super_block, s_list); return GetSuperBlock(*addrP); } /* Read a struct page from the kernel */ void* GetPage(unsigned long addr) { return GenericGet(addr, sizeof(struct page), 0); } /* Read an address_space from the kernel */ void* GetAddressSpace(unsigned long addr) { return GenericGet(addr, sizeof(struct address_space), 0); } /* Read a vm_area_struct from the kernel */ void* GetVMAreaStruct(unsigned long addr) { return GenericGet(addr, sizeof(struct vm_area_struct), 0); } /* Read an mm_struct from the kernel */ void* GetMMStruct(unsigned long addr) { return GenericGet(addr, sizeof(struct mm_struct), 0); } /* Read a task_struct from the kernel */ void* GetTaskStruct(unsigned long addr) { return GenericGet(addr, sizeof(struct task_struct), addr == TaskAddress?1:0); } /* Read a task_struct from the kernel given its pid */ void* GetTaskStructByPID(unsigned long pid, unsigned long * addrP) { struct threadIter ti; struct task_struct *taskP; tiInit(&ti); do { if (ti.threadP->pid == pid) { *addrP = ti.threadAddr; taskP = ti.threadP; ti.threadP = NULL; if (ti.taskP == taskP) ti.taskP = NULL; tiDone(&ti); return taskP; } } while (tiNext(&ti)); fprintf(stderr, "PID %ld not found\n", pid); return NULL; } /* Print a dentry. Parameter may be NULL. */ void PrintDentry(void* parm, unsigned long addr) { struct dentry* dP = (struct dentry*) parm; if (dP == NULL) { fprintf(stderr, "NULL dentry\n"); return; } printf("dentry 0x%lX:\n", addr); if (DumpMemoryCast(addr, "dentry")) DumpMemory((char*)dP, sizeof(struct dentry), addr, DUMPMEM_I4); } #define FIELD_ADDR(_ptr, _addr, _field) \ (_addr + (unsigned long)((char *)&(_ptr)->_field - (char *)(_ptr))) /* Recursively show given dentry and all its descendants */ static void PrintDentryTreeRecur(struct dentry* dP, unsigned long addr, unsigned long parentAddr, int level) { char *indent = BLANKS(2*level); unsigned long h; unsigned long childAddr; unsigned long ipAddr; struct list_head *listP; struct inode *iP = NULL; int nMax = 50; ipAddr = (unsigned long)dP->d_inode; if (ipAddr) iP = (struct inode *)GetInode(ipAddr); #if LINUX_KERNEL_VERSION < 2060000 printf("%sdentry 0x%lX: d_inode %d i_count %d " "d_count %d h_next 0x%lX h_prev 0x%lX d_name \"%s\"\n", indent, addr, (iP ? iP->i_ino : 0), (iP ? atomic_read(&iP->i_count) : 0), dP->d_count, dP->d_hash.next, dP->d_hash.prev, dP->d_name.name); #else printf("%sdentry 0x%lX: d_inode %d i_count %d " "d_count %d h_next 0x%lX h_pprev 0x%lX d_name \"%s\"\n", indent, addr, (iP ? iP->i_ino : 0), (iP ? atomic_read(&iP->i_count) : 0), dP->d_count, dP->d_hash.next, dP->d_hash.pprev, dP->d_name.name); #endif if ((unsigned long)dP->d_parent != parentAddr) fprintf(stderr, "%sbad d_parent dentry 0x%lX !!!\n", indent, dP->d_parent); /* prevent infinite recursion */ if (level > 100) { fprintf(stderr, "%srecursion too deep !!!\n"); return; } h = FIELD_ADDR(dP, addr, d_subdirs); listP = dP->d_subdirs.next; while ((unsigned long)listP != h) { childAddr = (unsigned long)list_entry(listP, struct dentry, d_child); dP = (struct dentry*)GetDentry(childAddr); if (dP == NULL) { fprintf(stderr, "%s could not get dentry 0x%lX !!!\n", indent, childAddr); break; } PrintDentryTreeRecur(dP, childAddr, addr, level + 1); listP = dP->d_child.next; /* prevent infinite loop */ nMax--; if (nMax == 0) { fprintf(stderr, "%s too many children !!!\n", indent); break; } } } /* Show given dentry and all its descendants */ void PrintDentryTree(void* parm, unsigned long addr) { if (parm == 0) { fprintf(stderr, "NULL dentry\n"); return; } PrintDentryTreeRecur((struct dentry*)parm, addr, (unsigned long)(((struct dentry*)parm)->d_parent), 0); } void PrintFSStruct(void *parm, unsigned long addr) { if (parm == NULL) { fprintf(stderr, "NULL fs_struct\n"); return; } if (DumpMemoryCast(addr, "fs_struct")) DumpMemory((char*)parm, sizeof(struct fs_struct), addr, DUMPMEM_I4); } void PrintVFSMount(void *parm, unsigned long addr) { if (parm == NULL) { fprintf(stderr, "NULL vfsmount\n"); return; } if (DumpMemoryCast(addr, "vfsmount")) DumpMemory((char*)parm, sizeof(struct vfsmount), addr, DUMPMEM_I4); } void PrintVFSMountList(void *parm, unsigned long addr) { struct vfsmount *vfsP = (struct vfsmount *)parm; struct list_head *listP; char *devnameP; unsigned long h; unsigned long next; if (vfsP == NULL) { fprintf(stderr, "NULL vfsmount\n"); return; } devnameP = (char *)GenericGet((unsigned long)vfsP->mnt_devname, 20, 0); printf("vfsmount 0x%lX: mnt_count %5d mnt_devname %20s\n", addr, vfsP->mnt_count, devnameP); h = FIELD_ADDR(vfsP, addr, mnt_list); listP = vfsP->mnt_list.next; while ((unsigned long)listP != h) { next = (unsigned long)list_entry(listP, struct vfsmount, mnt_list); vfsP = (struct vfsmount *)GetVFSMount(next); if (vfsP == NULL) { fprintf(stderr, "Could not get vfsmount 0x%lX !!!\n", next); return; } devnameP = (char *)GenericGet((unsigned long)vfsP->mnt_devname, 20, 0); printf("vfsmount 0x%lX: mnt_count %5d mnt_devname %20s\n", next, vfsP->mnt_count, devnameP); listP = vfsP->mnt_list.next; } } /* Print an inode. Parameter may be NULL. */ void PrintInode(void* parm, unsigned long addr) { struct inode* iP = (struct inode*) parm; if (iP == NULL) { fprintf(stderr, "NULL inode\n"); return; } printf("inode 0x%lX:\n", addr); if (DumpMemoryCast(addr, "inode")) DumpMemory((char*)iP, sizeof(struct inode), addr, DUMPMEM_I4); } /* Print a super_block. Parameter may be NULL. */ void PrintSuperBlock(void* parm, unsigned long addr) { struct super_block* sP = (struct super_block*) parm; if (sP == NULL) { fprintf(stderr, "NULL super_block\n"); return; } printf("super_block 0x%lX:\n", addr); if (DumpMemoryCast(addr, "super_block")) DumpMemory((char*)sP, sizeof(struct super_block), addr, DUMPMEM_I4); } /* Print a page struct. Parameter may be NULL. */ void PrintPage(void* parm, unsigned long addr) { struct page* pageP = (struct page*) parm; if (pageP == NULL) { fprintf(stderr, "NULL page\n"); return; } printf("page 0x%lX (frame number 0x%lX):\n", addr, (addr-MemMapAddr)/sizeof(struct page)); if (DumpMemoryCast(addr, "page")) DumpMemory((char*)pageP, sizeof(struct page), addr, DUMPMEM_I4); } /* Print an address_space struct. Parameter may be NULL. */ void PrintAddressSpace(void* parm, unsigned long addr) { struct address_space* asP = (struct address_space*) parm; if (asP == NULL) { fprintf(stderr, "NULL address_space\n"); return; } printf("address_space 0x%lX:\n", addr); if (DumpMemoryCast(addr, "address_space")) DumpMemory((char*)asP, sizeof(struct address_space), addr, DUMPMEM_I4); } /* Print a vm_area_struct struct. Parameter may be NULL. */ void PrintVMAreaStruct(void* parm, unsigned long addr) { struct vm_area_struct* vmP = (struct vm_area_struct*) parm; if (vmP == NULL) { fprintf(stderr, "NULL vm_area_struct\n"); return; } printf("vm_area_struct 0x%lX:\n", addr); if (DumpMemoryCast(addr, "vm_area_struct")) DumpMemory((char*)vmP, sizeof(struct vm_area_struct), addr, DUMPMEM_I4); } /* Print an mm_struct struct. Parameter may be NULL. */ void PrintMMStruct(void* parm, unsigned long addr) { struct mm_struct* mmP = (struct mm_struct*) parm; if (mmP == NULL) { fprintf(stderr, "NULL mm_struct\n"); return; } printf("mm_struct 0x%lX:\n", addr); if (DumpMemoryCast(addr, "mm_struct")) DumpMemory((char*)mmP, sizeof(struct mm_struct), addr, DUMPMEM_I4); } /* Print an task_struct struct. Parameter may be NULL. */ void PrintTaskStruct(void* parm, unsigned long addr) { struct task_struct* taskP = (struct task_struct*) parm; if (taskP == NULL) { fprintf(stderr, "NULL task_struct\n"); return; } printf("task_struct 0x%lX:\n", addr); if (DumpMemoryCast(addr, "task_struct")) DumpMemory((char*)taskP, sizeof(struct task_struct), addr, DUMPMEM_I4); } #ifndef GPFS_ARCH_I386 void VirtToReal(unsigned long pgdAddr, unsigned long vaddr) { fprintf(stderr, "Not implemented."); } #else /* Display page table flag bits */ static void ShowFlagBits(unsigned long f) { if (f & _PAGE_PRESENT) printf(" present"); if (f & _PAGE_RW) printf(" RW"); if (f & _PAGE_USER) printf(" user"); if (f & _PAGE_PWT) printf(" PWT"); if (f & _PAGE_PCD) printf(" PCD"); if (f & _PAGE_ACCESSED) printf(" accessed"); if (f & _PAGE_DIRTY) printf(" dirty"); if (f & _PAGE_PSE) printf(" 4M"); if (f & _PAGE_GLOBAL) printf(" global"); printf("\n"); } /* Translate vaddr using pgd at addr */ void VirtToReal(unsigned long pgdAddr, unsigned long vaddr) { pgd_t* pgdP; unsigned long pgdIndex; pgd_t pgdEntry; unsigned long pgdVal; unsigned long pmdAddr; pmd_t* pmdP; pmd_t pmdEntry; unsigned long pmdVal; unsigned long pageNumber; unsigned long pteAddr; unsigned long pteIndex; pte_t* pteP; pte_t pteEntry; unsigned long pteVal; #if defined(CONFIG_X86_PAE) fprintf(stderr, "Could not read pmd\n"); return; #else pgdIndex = pgd_index(vaddr); pgdAddr = (unsigned long)(((pgd_t*)pgdAddr) + pgdIndex); pgdP = (pgd_t*)GenericGet(pgdAddr, sizeof(*pgdP), 0); if (pgdP == NULL) { fprintf(stderr, "Could not read pgd\n"); return; } pgdEntry = *pgdP; CondFree(pgdP); pgdVal = pgd_val(pgdEntry); printf("pgdAddr 0x%lX pgd entry 0x%lX", pgdAddr, pgdVal); ShowFlagBits(pgdVal); if (!(pgdVal & _PAGE_PRESENT)) { fprintf(stderr, "PGD not present\n"); return; } pmdAddr = (unsigned long) pmd_offset((void*)pgdAddr, vaddr); /* Above only works for two level page tables, because the code for 3-level tables actually dereferences pgdAddr, which we cannot do from this user-level program. */ pmdP = (pmd_t*)GenericGet(pmdAddr, sizeof(*pmdP), 0); if (pmdP == NULL) { fprintf(stderr, "Could not read pmd\n"); return; } pmdEntry = *pmdP; CondFree(pmdP); pmdVal = pmd_val(pmdEntry); printf("pmdAddr 0x%lX pmd entry 0x%lX", pmdAddr, pmdVal); ShowFlagBits(pmdVal); if (!(pmdVal & _PAGE_PRESENT)) { fprintf(stderr, "PMD not present\n"); return; } if (pmdVal & _PAGE_PSE) { pageNumber = (pgdVal>>PAGE_SHIFT) + ((vaddr & (PGDIR_SIZE-1))>>PAGE_SHIFT); printf("vaddr 0x%lX pageNumber 0x%lX page 0x%lX\n", vaddr, pageNumber, MemMapAddr + pageNumber*sizeof(struct page)); return; } pteAddr = (unsigned long) __va(pmdVal & PAGE_MASK); #if LINUX_KERNEL_VERSION >= 2060000 pteIndex = pte_index(vaddr); #else pteIndex = __pte_offset(vaddr); #endif pteAddr = (unsigned long)(((pte_t*)pteAddr) + pteIndex); pteP = (pte_t*)GenericGet(pteAddr, sizeof(pte_t), 0); pteEntry = *pteP; CondFree(pteP); pteVal = pte_val(pteEntry); printf("pteAddr 0x%lX pte entry 0x%lX", pteAddr, pteVal); ShowFlagBits(pteVal); if (!pte_present(pteEntry)) { fprintf(stderr, "PTE not present\n"); return; } pageNumber = pteVal >> PAGE_SHIFT; printf("vaddr 0x%lX pageNumber 0x%lX page 0x%lX\n", vaddr, pageNumber, MemMapAddr + pageNumber*sizeof(struct page)); #endif } #endif /* GPFS_ARCH_I386 */ void DoPs(void) { struct threadIter ti; tiInit(&ti); printf("task addr PID state name\n"); do { printf("0x%08lX %8d %0lX %s%s\n", ti.threadAddr, ti.threadP->pid, ti.threadP->state, (ti.threadAddr == ti.taskAddr) ? "" : " ", ti.threadP->comm); } while (tiNext(&ti)); } void PrintTraceback(struct task_struct* taskP) { #ifdef GPFS_ARCH_I386 unsigned long esp, esp2, stackWord, *p, offset, count; struct Symbol* sP; esp = taskP->thread.esp; printf("\nStack for process %d (%s):\n", taskP->pid, taskP->comm); while ((esp & (THREAD_SIZE-1))) { /* debug kernel may have odd esp offset */ for (esp2=esp, count=sizeof(taskP->thread.esp); count > 0;count--, esp2++) if (!(esp2 & (THREAD_SIZE-1))) break; if (count > 0) break; p = (unsigned long*)GenericGet(esp++, sizeof(esp), 0); if (p == NULL) { printf(" NULL stackWord pointer\n"); break; } stackWord = *p; if (stackWord >= LowKernelAddr && stackWord <= HighSymbolAddr) { sP = LookupSymbolByAddr(stackWord); assert(sP != NULL); if (sP->flags & FL_TEXT) { offset = stackWord - sP->addr; printf(" 0x%0lX %s + 0x%X\n", stackWord, sP->nameP, offset); } } /* else printf(" [%08lX]", stackWord); */ kFree(p); } printf("\n"); #elif defined(GPFS_ARCH_PPC64) struct bt_stack_frame { struct bt_stack_frame* next; long cr; void *ret_addr; }; struct bt_stack_frame* frameP = NULL; struct pt_regs *regs; unsigned long ip, *p, offset, frameAddr; struct Symbol* sP; int rc; frameAddr = taskP->thread.ksp; printf("\nStack for process %d (%s):\n", taskP->pid, taskP->comm); while ( frameAddr > PAGE_OFFSET ) { frameP = (struct bt_stack_frame*)GenericGet(frameAddr, sizeof(struct bt_stack_frame), 0); if (frameP == NULL) { printf(" NULL stack frame pointer\n"); break; } ip = (unsigned long)frameP->ret_addr; if (ip != 0) { sP = LookupSymbolByAddr(ip); if ( (sP->flags & FL_TEXT) ) { offset = ip - sP->addr; printf("%0p 0x%016lX %s + 0x%X\n", frameAddr, ip, sP->nameP, offset); } } frameAddr = (unsigned long)(frameP->next); kFree((unsigned long*)frameP); } #elif defined(GPFS_ARCH_X86_64) && LINUX_KERNEL_VERSION >= 2060000 unsigned long rsp, stackWord, *p, offset, count; struct Symbol* sP; rsp = taskP->thread.rsp; printf("\nStack for process %d (%s):\n", taskP->pid, taskP->comm); while ((rsp & (THREAD_SIZE-1))) { p = (unsigned long*)GenericGet(rsp++, sizeof(rsp), 0); if (p == NULL) { printf(" NULL stackWord pointer\n"); break; } stackWord = *p; if (stackWord >= LowKernelAddr && stackWord <= HighSymbolAddr) { sP = LookupSymbolByAddr(stackWord); assert(sP != NULL); if (sP->flags & FL_TEXT) { offset = stackWord - sP->addr; printf(" 0x%0lX %s + 0x%X\n", stackWord, sP->nameP, offset); } } /* else printf(" [%08lX]", stackWord); */ kFree(p); } printf("\n"); #endif } /* Print kernel traceback for a particular process. pid == -1 * means all processes */ void BacktracePid(unsigned long pid) { struct threadIter ti; tiInit(&ti); do { if (pid == -1 || ti.threadP->pid == pid) { PrintTraceback(ti.threadP); if (pid != -1) { tiDone(&ti); return; } } } while (tiNext(&ti)); if (pid != -1) fprintf(stderr, "PID %ld not found\n", pid); } void BacktraceAll(void) { BacktracePid(-1); } static struct elf_prstatus prstatus; static struct elf_prpsinfo prpsinfo; struct memelfnote { char *name; int type; unsigned int datasize; void *data; }; #define ROUNDUP(_addr, _align) ( (_addr + (_align - 1))/_align * _align) void ReadElfNote(struct memelfnote* memnote) { struct elf_note note; int len; readCore(¬e, sizeof(note)); memnote->type = note.n_type; len = ROUNDUP(note.n_namesz, 4); memnote->name = (char*)kMalloc(len); assert(memnote->name != NULL); readCore(memnote->name, len); memnote->name[note.n_namesz] = '\0'; len = ROUNDUP(note.n_descsz, 4); memnote->datasize = note.n_descsz; memnote->data = kMalloc(len); assert(memnote->data != NULL); memset(memnote->data, 0, len); readCore(memnote->data, len); } void ReadKernelCore(char* corefile) { int i; struct elfhdr hdr; struct elf_phdr phdr_note, phdr_load; struct memelfnote status_note, psinfo_note, taskstruct_note; struct vmStruct* aListP; struct vmStruct** prevPP; printf("Reading ELF core file %s...\n", corefile); isCore = 1; openCore(corefile); readCore(&hdr, sizeof(hdr)); assert(hdr.e_type == ET_CORE); assert(hdr.e_version == EV_CURRENT); assert(elf_check_arch(&hdr)); assert(hdr.e_ehsize == sizeof(struct elfhdr)); assert(hdr.e_phentsize == sizeof(struct elf_phdr)); readCore(&phdr_note, sizeof(phdr_note)); vmListHeadP = NULL; prevPP = &vmListHeadP; for (i = 0; i < hdr.e_phnum - 1; i++) { readCore(&phdr_load, sizeof(phdr_note)); if (phdr_load.p_type & PT_LOAD) { aListP = (struct vmStruct*) kMalloc(sizeof(struct vmStruct)); assert(aListP != NULL); aListP->startAddr = phdr_load.p_vaddr; aListP->areaLen = phdr_load.p_memsz; aListP->file_offset = phdr_load.p_offset; aListP->nextAreaP = NULL; *prevPP = aListP; prevPP = &aListP->nextAreaP; } } seekCore(phdr_note.p_offset); ReadElfNote(&status_note); assert(status_note.type == NT_PRSTATUS); cxiMemcpy(&prstatus, status_note.data, sizeof(prstatus)); ReadElfNote(&psinfo_note); assert(psinfo_note.type == NT_PRPSINFO); cxiMemcpy(&prpsinfo, psinfo_note.data, sizeof(prpsinfo)); ReadElfNote(&taskstruct_note); assert(taskstruct_note.type == NT_TASKSTRUCT); #ifdef GPFS_ARCH_I386 #define REG(_a) prstatus.pr_reg[_a] printf("Registers:\n"); printf("eax: %08lX ebx: %08lX ecx: %08lX edx: %08lX\n", REG(6), REG(0), REG(1), REG(2)); printf("esi: %08lX edi: %08lX ebp: %08lX esp: %08lX\n", REG(3), REG(4), REG(5), REG(15)); printf("eip: %08lX eflags: %08lX\n", REG(12), REG(14)); #undef REG #endif } #endif