[PATCH] fix KDB backtrace for ppc64 (reworked)
Ananth N Mavinakayanahalli
ananth at in.ibm.com
Thu May 6 16:34:09 EST 2004
On Wed, May 05, 2004 at 01:20:42PM -0500, linas at austin.ibm.com wrote:
>
> On Wed, May 05, 2004 at 07:16:47PM +0500, Ananth N Mavinakayanahalli wrote:
> > @@ -200,25 +196,49 @@ kdba_bt_stack_ppc(struct pt_regs *regs,
> > + if (!flag && (task_curr(p))) {
> > +
> > + lr = regs->link;
>
> Its not obvious that regs might not be a null pointer. Code
> higher up tries to make sure that regs is set to something,
> but its not clear that every branch is correctly handled.
>
Right.. Here is a reworked patch that handles NULL regs.
Anton,
Please consider this patch for inclusion to Ameslab.
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 22:06:39.401239784 -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,50 @@ 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++;
+ if ((!regs) || (regs->link < PAGE_OFFSET) ||
+ (regs->link == eip))
+ goto next_frame;
+
+ lr = regs->link;
+ 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 +257,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