[PATCH] fix KDB backtrace for ppc64
Ananth N Mavinakayanahalli
ananth at in.ibm.com
Thu May 6 00:16:47 EST 2004
Hi Anton,
Here is a patch that fixes backtracing in KDB for ppc64. We were not
handling the link register and were missing an intermediate call
during bt.
The patch also contains updates to bring KDB in Ameslab to the latest
SGI released level.
Please apply!
Thanks,
Ananth
--
Ananth Narayan
Linux Technology Center,
IBM Software Lab, INDIA
diff -Naurp temp/ameslab/arch/ppc64/kdb/kdba_bt.c ameslab/arch/ppc64/kdb/kdba_bt.c
--- temp/ameslab/arch/ppc64/kdb/kdba_bt.c 2004-04-22 21:52:09.000000000 -0700
+++ ameslab/arch/ppc64/kdb/kdba_bt.c 2004-05-05 02:51:12.321319240 -0700
@@ -101,17 +101,15 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
struct task_struct *p, int regs_esp)
{
- kdb_machreg_t esp,eip,ebp,old_esp;
-/* kdb_symtab_t symtab, *sym; */
- kdbtbtable_t tbtab;
+ kdb_machreg_t esp, eip, ebp, old_esp;
/* declare these as raw ptrs so we don't get func descriptors */
extern void *ret_from_except, *ret_from_syscall_1;
-/* int do_bottom_half_ret=0; */
const char *name;
- char namebuf[128];
- unsigned long symsize,symoffset;
+ unsigned long symsize, symoffset;
char *symmodname;
+ int flag = 0;
+ char namebuf[128];
/*
* The caller may have supplied an address at which the
@@ -155,7 +153,8 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
kdb_printf(" SP(esp) PC(eip) Function(args)\n");
- /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs).
+ /* (Ref: 64-bit PowerPC ELF ABI Supplement:
+ Ian Lance Taylor, Zembu Labs).
A PPC stack frame looks like this:
High Address
@@ -180,18 +179,15 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
*/
while (1) {
kdb_printf("0x%016lx 0x%016lx ", esp, eip);
- /* kdbnearsym(eip, &symtab); */
- kdba_find_tb_table(eip, &tbtab);
-
- /* sym = symtab.sym_name ? &symtab : &tbtab.symtab; */
- /* use fake symtab if necessary */
name = NULL;
if (esp >= PAGE_OFFSET) {
- /*if ((sym) )*/
- /* if this fails, eip is outside of kernel space, dont trust it. */
+ /*
+ * if this fails, eip is outside of kernel space,
+ * dont trust it.
+ */
if (eip > PAGE_OFFSET) {
- name = kallsyms_lookup(eip, &symsize, &symoffset, &symmodname,
- namebuf);
+ name = kallsyms_lookup(eip, &symsize,
+ &symoffset, &symmodname, namebuf);
}
if (name) {
kdb_printf("%s", name);
@@ -200,25 +196,49 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
}
}
- /* if this fails, eip is outside of kernel space, dont trust data. */
+ /*
+ * if this fails, eip is outside of kernel space,
+ * dont trust data.
+ */
if (eip > PAGE_OFFSET) {
if (eip - symoffset > 0) {
kdb_printf(" +0x%lx", /*eip -*/ symoffset);
}
}
kdb_printf("\n");
+ if (!flag && (task_curr(p))) {
+ kdb_machreg_t lr;
+ unsigned long start = 0, end = 0;
+
+ flag++;
+ lr = regs->link;
+ if ((lr < PAGE_OFFSET) || (lr == eip))
+ goto next_frame;
+
+ start = eip - symoffset;
+ end = eip - symoffset + symsize;
+ if (lr >= start && lr < end)
+ goto next_frame;
+
+ name = NULL;
+ name = kallsyms_lookup(lr, &symsize,
+ &symoffset, &symmodname, namebuf);
+ if (name)
+ kdb_printf("0x%016lx 0x%016lx (lr) %s +0x%lx\n",
+ esp, lr, name, symoffset);
+ }
- /* ret_from_except=0xa5e0 ret_from_syscall_1=a378 do_bottom_half_ret=a5e0 */
+next_frame:
if (esp < PAGE_OFFSET) { /* below kernelspace.. */
kdb_printf("<Stack contents outside of kernel space. %.16lx>\n", esp );
break;
} else {
if (eip == (kdb_machreg_t)ret_from_except ||
- eip == (kdb_machreg_t)ret_from_syscall_1 /* ||
- eip == (kdb_machreg_t)do_bottom_half_ret */) {
+ eip == (kdb_machreg_t)ret_from_syscall_1) {
/* pull exception regs from the stack */
struct pt_regs eregs;
- kdba_getmem(esp+STACK_FRAME_OVERHEAD, &eregs, sizeof(eregs));
+ kdba_getmem(esp+STACK_FRAME_OVERHEAD,
+ &eregs, sizeof(eregs));
kdb_printf(" [exception: %lx:%s regs 0x%lx] "
"nip:[0x%lx] gpr[1]:[0x%lx]\n",
eregs.trap,getvecname(eregs.trap),
@@ -236,7 +256,10 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
break;
}
}
- /* we want to follow exception registers, not into user stack. ... */
+ /*
+ * we want to follow exception registers,
+ * not into user stack. ...
+ */
esp = eregs.gpr[1];
eip = eregs.nip;
} else {
diff -Naurp temp/ameslab/kdb/ChangeLog ameslab/kdb/ChangeLog
--- temp/ameslab/kdb/ChangeLog 2004-05-04 02:07:51.000000000 -0700
+++ ameslab/kdb/ChangeLog 2004-05-05 02:51:18.168228408 -0700
@@ -1,3 +1,8 @@
+2004-04-30 Keith Owens <kaos at sgi.com>
+
+ * Rewrite inode_pages command for new radix code in struct page.
+ * kdb v4.3-2.6.6-rc1-common-1.
+
2004-04-11 Keith Owens <kaos at sgi.com>
* Unlock sn_sal_lock before entering kdb from sn_serial.
diff -Naurp temp/ameslab/kdb/gen-kdb_cmds.c ameslab/kdb/gen-kdb_cmds.c
--- temp/ameslab/kdb/gen-kdb_cmds.c 2004-04-22 21:54:41.000000000 -0700
+++ ameslab/kdb/gen-kdb_cmds.c 1969-12-31 16:00:00.000000000 -0800
@@ -1,4 +0,0 @@
-#include <linux/init.h>
-char __initdata *kdb_cmds[] = {
- 0
-};
diff -Naurp temp/ameslab/kdb/modules/kdbm_pg.c ameslab/kdb/modules/kdbm_pg.c
--- temp/ameslab/kdb/modules/kdbm_pg.c 2004-05-04 02:07:51.000000000 -0700
+++ ameslab/kdb/modules/kdbm_pg.c 2004-05-05 03:07:16.033237072 -0700
@@ -151,42 +151,25 @@ kdbm_page(int argc, const char **argv, c
long offset=0;
int nextarg;
int diag;
- int lookup_page = 0;
- if (argc == 2) {
- if (strcmp(argv[1], "-s") != 0) {
- return KDB_ARGCOUNT;
- }
- lookup_page = 1;
- } else if (argc != 1) {
+ if (argc != 1)
return KDB_ARGCOUNT;
- }
- nextarg = argc;
+ nextarg = 1;
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
if (diag)
return diag;
- /* Assume argument is a page number, not address */
if (addr < PAGE_OFFSET)
addr = (unsigned long) &mem_map[addr];
- /* Get the struct page * that corresponds to this addr */
- if (lookup_page)
- {
- addr = (unsigned long) virt_to_page(addr);
- }
-
if ((diag = kdb_getarea(page, addr)))
return(diag);
kdb_printf("struct page at 0x%lx\n", addr);
-/* kdb_printf(" next 0x%p prev 0x%p addr space 0x%p index %lu (offset 0x%x)\n",
- page.list.next, page.list.prev, page.mapping, page.index,
- (int)(page.index << PAGE_CACHE_SHIFT)); */
- kdb_printf(" addr space 0x%p index %lu (offset 0x%x)\n",
+ kdb_printf(" addr space 0x%p index %lu (offset 0x%llx)\n",
page.mapping, page.index,
- (int)(page.index << PAGE_CACHE_SHIFT));
+ (unsigned long long)page.index << PAGE_CACHE_SHIFT);
kdb_printf(" count %d flags %s\n",
page.count.counter, page_flags(page.flags));
kdb_printf(" virtual 0x%p\n", page_address((struct page *)addr));
@@ -276,7 +259,7 @@ kdbm_rqueue(int argc, const char **argv,
return 0;
}
-/* routine not used currently.. sync with upstream later
+
static void
do_buffer(unsigned long addr)
{
@@ -285,13 +268,54 @@ do_buffer(unsigned long addr)
if (kdb_getarea(bh, addr))
return;
- kdb_printf("bh 0x%lx bno %8llu [%s]\n", addr,
+ kdb_printf(" bh 0x%lx bno %8llu [%s]", addr,
(unsigned long long)bh.b_blocknr,
map_flags(bh.b_state, bh_state_vals));
}
-*/
-/* inode_struct changed in 2.6.6-rc series.. sync with upstream later
+static void
+kdbm_show_page(struct page *page, int first)
+{
+ if (first)
+ kdb_printf("page_struct index cnt zone nid flags\n");
+ kdb_printf("%p%s %6lu %5d %3ld %3ld 0x%lx",
+ page_address(page), sizeof(void *) == 4 ? " " : "",
+ page->index, atomic_read(&(page->count)),
+ page_zonenum(page), page_to_nid(page),
+ page->flags & (~0UL >> ZONES_SHIFT));
+#define kdb_page_flags(page, type) if (Page ## type(page)) kdb_printf(" " #type);
+ kdb_page_flags(page, Locked);
+ kdb_page_flags(page, Error);
+ kdb_page_flags(page, Referenced);
+ kdb_page_flags(page, Uptodate);
+ kdb_page_flags(page, Dirty);
+ kdb_page_flags(page, LRU);
+ kdb_page_flags(page, Active);
+ kdb_page_flags(page, Slab);
+ kdb_page_flags(page, HighMem);
+ kdb_page_flags(page, Checked);
+ if (page->flags & (1UL << PG_arch_1))
+ kdb_printf(" arch_1");
+ kdb_page_flags(page, Reserved);
+ kdb_page_flags(page, Private);
+ kdb_page_flags(page, Writeback);
+ kdb_page_flags(page, Nosave);
+ if (page->flags & (1UL << PG_maplock))
+ kdb_printf(" maplock");
+ kdb_page_flags(page, Direct);
+ kdb_page_flags(page, MappedToDisk);
+ kdb_page_flags(page, Reclaim);
+ kdb_page_flags(page, Compound);
+ kdb_page_flags(page, Anon);
+ kdb_page_flags(page, SwapCache);
+ if (page_has_buffers(page))
+ do_buffer((unsigned long) page_buffers(page));
+ else if (page->private)
+ kdb_printf(" private=0x%lx", page->private);
+ kdb_printf("\n");
+#undef kdb_page_flags
+}
+
static int
kdbm_inode_pages(int argc, const char **argv, const char **envp,
struct pt_regs *regs)
@@ -302,12 +326,9 @@ kdbm_inode_pages(int argc, const char **
long offset=0;
int nextarg;
int diag;
- int which=0;
-
- struct list_head *head, *curr;
-
- if (argc < 1)
- return KDB_ARGCOUNT;
+ pgoff_t next = 0;
+ struct page *page;
+ int first;
nextarg = 1;
diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
@@ -321,6 +342,7 @@ kdbm_inode_pages(int argc, const char **
if (diag)
goto out;
kdb_printf("Looking for page index 0x%lx ... \n", addr1);
+ next = addr1;
}
if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) {
@@ -340,58 +362,23 @@ kdbm_inode_pages(int argc, const char **
if ((diag = kdb_getarea(*ap, (unsigned long) inode->i_mapping)))
goto out;
- again:
- if (which == 0){
- which=1;
- head = &inode->i_mapping->clean_pages;
- kdb_printf("CLEAN page_struct index cnt flags\n");
- } else if (which == 1) {
- which=2;
- head = &inode->i_mapping->dirty_pages;
- kdb_printf("DIRTY page_struct index cnt flags\n");
- } else if (which == 2) {
- which=3;
- head = &inode->i_mapping->locked_pages;
- kdb_printf("LOCKED page_struct index cnt flags\n");
- } else {
- goto out;
+ /* Run the pages in the radix tree, printing the state of each page */
+ first = 1;
+ while (radix_tree_gang_lookup(&ap->page_tree, (void **)&page, next, 1)) {
+ kdbm_show_page(page, first);
+ if (addr1)
+ break;
+ first = 0;
+ next = page->index + 1;
}
-
- curr = head->next;
- while (curr != head) {
- struct page page;
- struct list_head curr_struct;
-
- addr = (unsigned long) list_entry(curr, struct page, list);
- if ((diag = kdb_getarea(page, addr)))
- goto out;
-
- if (!addr1 || page.index == addr1 ||
- (addr1 == -1 && (page.flags & ( 1 << PG_locked))))
- {
- kdb_printf(" 0x%lx %6lu %5d 0x%lx ",
- addr, page.index, page.count.counter,
- page.flags);
- if (page_has_buffers(&page))
- do_buffer((unsigned long) page_buffers(&page));
- else
- kdb_printf("bh [NULL]\n");
- }
-
- if ((diag = kdb_getarea(curr_struct, (unsigned long) curr)))
- goto out;
-
- curr = curr_struct.next;
- }
- goto again;
- out:
+
+out:
if (inode)
kfree(inode);
if (ap)
kfree(ap);
return diag;
}
-*/
static int
kdbm_inode(int argc, const char **argv, const char **envp,
@@ -567,13 +554,12 @@ kdbm_memmap(int argc, const char **argv,
static int __init kdbm_pg_init(void)
{
#ifndef CONFIG_DISCONTIGMEM
- kdb_register("page", kdbm_page, "[-s] <vaddr>", "Display page [or page of addr]", 0);
+ kdb_register("page", kdbm_page, "<vaddr>", "Display page", 0);
#endif
kdb_register("inode", kdbm_inode, "<vaddr>", "Display inode", 0);
kdb_register("sb", kdbm_sb, "<vaddr>", "Display super_block", 0);
kdb_register("bh", kdbm_buffers, "<buffer head address>", "Display buffer", 0);
-/* inode struct changed in 2.6.6-rc series.. sync with upstream later
- kdb_register("inode_pages", kdbm_inode_pages, "<inode *>", "Display pages in an inode", 0); */
+ kdb_register("inode_pages", kdbm_inode_pages, "<inode *>", "Display pages in an inode", 0);
kdb_register("req", kdbm_request, "<vaddr>", "dump request struct", 0);
kdb_register("rqueue", kdbm_rqueue, "<vaddr>", "dump request queue", 0);
#if defined(CONFIG_X86) | defined(CONFIG_PPC64)
** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/
More information about the Linuxppc64-dev
mailing list