debugging frequent kernel panics on 8.2-RELEASE
Andriy Gapon
avg at FreeBSD.org
Fri Aug 19 16:28:08 UTC 2011
on 19/08/2011 15:14 John Baldwin said the following:
> Yes, it is a bug in kgdb that it only walks allproc and not zombproc. Try this:
The patch worked perfectly well for me, thank you!
> Index: kthr.c
> ===================================================================
> --- kthr.c (revision 224879)
> +++ kthr.c (working copy)
> @@ -73,11 +73,52 @@ kgdb_thr_first(void)
> return (first);
> }
>
> +static void
> +kgdb_thr_add_procs(uintptr_t paddr)
> +{
> + struct proc p;
> + struct thread td;
> + struct kthr *kt;
> + CORE_ADDR addr;
> +
> + while (paddr != 0) {
> + if (kvm_read(kvm, paddr, &p, sizeof(p)) != sizeof(p)) {
> + warnx("kvm_read: %s", kvm_geterr(kvm));
> + break;
> + }
> + addr = (uintptr_t)TAILQ_FIRST(&p.p_threads);
> + while (addr != 0) {
> + if (kvm_read(kvm, addr, &td, sizeof(td)) !=
> + sizeof(td)) {
> + warnx("kvm_read: %s", kvm_geterr(kvm));
> + break;
> + }
> + kt = malloc(sizeof(*kt));
> + kt->next = first;
> + kt->kaddr = addr;
> + if (td.td_tid == dumptid)
> + kt->pcb = dumppcb;
> + else if (td.td_state == TDS_RUNNING && stoppcbs != 0 &&
> + CPU_ISSET(td.td_oncpu, &stopped_cpus))
> + kt->pcb = (uintptr_t)stoppcbs +
> + sizeof(struct pcb) * td.td_oncpu;
> + else
> + kt->pcb = (uintptr_t)td.td_pcb;
> + kt->kstack = td.td_kstack;
> + kt->tid = td.td_tid;
> + kt->pid = p.p_pid;
> + kt->paddr = paddr;
> + kt->cpu = td.td_oncpu;
> + first = kt;
> + addr = (uintptr_t)TAILQ_NEXT(&td, td_plist);
> + }
> + paddr = (uintptr_t)LIST_NEXT(&p, p_list);
> + }
> +}
> +
> struct kthr *
> kgdb_thr_init(void)
> {
> - struct proc p;
> - struct thread td;
> long cpusetsize;
> struct kthr *kt;
> CORE_ADDR addr;
> @@ -113,37 +154,11 @@ kgdb_thr_init(void)
>
> stoppcbs = kgdb_lookup("stoppcbs");
>
> - while (paddr != 0) {
> - if (kvm_read(kvm, paddr, &p, sizeof(p)) != sizeof(p)) {
> - warnx("kvm_read: %s", kvm_geterr(kvm));
> - break;
> - }
> - addr = (uintptr_t)TAILQ_FIRST(&p.p_threads);
> - while (addr != 0) {
> - if (kvm_read(kvm, addr, &td, sizeof(td)) !=
> - sizeof(td)) {
> - warnx("kvm_read: %s", kvm_geterr(kvm));
> - break;
> - }
> - kt = malloc(sizeof(*kt));
> - kt->next = first;
> - kt->kaddr = addr;
> - if (td.td_tid == dumptid)
> - kt->pcb = dumppcb;
> - else if (td.td_state == TDS_RUNNING && stoppcbs != 0 &&
> - CPU_ISSET(td.td_oncpu, &stopped_cpus))
> - kt->pcb = (uintptr_t) stoppcbs + sizeof(struct pcb) * td.td_oncpu;
> - else
> - kt->pcb = (uintptr_t)td.td_pcb;
> - kt->kstack = td.td_kstack;
> - kt->tid = td.td_tid;
> - kt->pid = p.p_pid;
> - kt->paddr = paddr;
> - kt->cpu = td.td_oncpu;
> - first = kt;
> - addr = (uintptr_t)TAILQ_NEXT(&td, td_plist);
> - }
> - paddr = (uintptr_t)LIST_NEXT(&p, p_list);
> + kgdb_thr_add_procs(paddr);
> + addr = kgdb_lookup("zombproc");
> + if (addr != 0) {
> + kvm_read(kvm, addr, &paddr, sizeof(paddr));
> + kgdb_thr_add_procs(paddr);
> }
> curkthr = kgdb_thr_lookup_tid(dumptid);
> if (curkthr == NULL)
>
>> is there an easy way to examine its stack in this case?
>
> Hmm, you can use something like this from my kgdb macros.
Oh, I completely forgot about them.
I hope I will remember where to search for the tricks next time I need them :-)
Thank you again!
> For amd64:
>
> # Do a backtrace given %rip and %rbp as args
> define bt
> set $_rip = $arg0
> set $_rbp = $arg1
> set $i = 0
> while ($_rbp != 0 || $_rip != 0)
> printf "%2d: pc ", $i
> if ($_rip != 0)
> x/1i $_rip
> else
> printf "\n"
> end
> if ($_rbp == 0)
> set $_rip = 0
> else
> set $fr = (struct amd64_frame *)$_rbp
> set $_rbp = $fr->f_frame
> set $_rip = $fr->f_retaddr
> set $i = $i + 1
> end
> end
> end
>
> document bt
> Given values for %rip and %rbp, perform a manual backtrace.
> end
>
> define btf
> bt $arg0.tf_rip $arg0.tf_rbp
> end
>
> document btf
> Do a manual backtrace from a specified trapframe.
> end
>
> For i386:
>
> # Do a backtrace given %eip and %ebp as args
> define bt
> set $_eip = $arg0
> set $_ebp = $arg1
> set $i = 0
> while ($_ebp != 0 || $_eip != 0)
> printf "%2d: pc ", $i
> if ($_eip != 0)
> x/1i $_eip
> else
> printf "\n"
> end
> if ($_ebp == 0)
> set $_eip = 0
> else
> set $fr = (struct i386_frame *)$_ebp
> set $_ebp = $fr->f_frame
> set $_eip = $fr->f_retaddr
> set $i = $i + 1
> end
> end
> end
>
> document bt
> Given values for %eip and %ebp, perform a manual backtrace.
> end
>
> define btf
> bt $arg0.tf_eip $arg0.tf_ebp
> end
>
> document btf
> Do a manual backtrace from a specified trapframe.
> end
>
--
Andriy Gapon
More information about the freebsd-stable
mailing list