If we can't find a symbol corresponding to the current IP, assume that
the previously-executed instruction is a call and attempt to find the
calling function using the return address on the stack. Otherwise we end
up associating the last stack frame with the current function call,
which is incorrect and causes the unwinder to skip printing of the
calling function. For example, if function A() calls B(), and B() calls
a NULL function pointer, the previous unwind logic would result in a
stack of "A() -> ??", skipping B().
Details
Diff Detail
- Lint
Lint Passed - Unit
No Test Coverage
Event Timeline
Can you also fix this on i386? Also, did you write a simple test for this? (A kernel module whose MOD_LOAD hook invokes a NULL function pointer would work)
Sure.
Also, did you write a simple test for this? (A kernel module whose MOD_LOAD hook invokes a NULL function pointer would work)
Yup - I changed a sysctl handler to call a NULL function pointer. With the change I get:
Fatal trap 12: page fault while in kernel mode
cpuid = 1; apic id = 01
fault virtual address = 0x0
fault code = supervisor read instruction, page not present
instruction pointer = 0x20:0x0
stack pointer = 0x28:0xfffffe00d9322780
frame pointer = 0x28:0xfffffe00d93227c0
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 582 (sysctl)
[ thread pid 582 tid 100060 ]
Stopped at 0
db> bt
Tracing pid 582 tid 100060 td 0xfffff800050c9000
??() at 0
sysctl_runningspace() at sysctl_runningspace+0x43/frame 0xfffffe00d93227c0
sysctl_root_handler_locked() at sysctl_root_handler_locked+0x94/frame 0xfffffe00d9322800
sysctl_root() at sysctl_root+0x188/frame 0xfffffe00d9322850
userland_sysctl() at userland_sysctl+0x192/frame 0xfffffe00d93228f0
sys___sysctl() at sys___sysctl+0x74/frame 0xfffffe00d93229a0
amd64_syscall() at amd64_syscall+0x282/frame 0xfffffe00d9322ab0
Xfast_syscall() at Xfast_syscall+0xfb/frame 0xfffffe00d9322ab0
- syscall (202, FreeBSD ELF64, sys___sysctl), rip = 0x80095086a, rsp = 0x7fffffffd9e8, rbp = 0x7fffffffda20 ---
Without the change I get
Fatal trap 12: page fault while in kernel mode
cpuid = 1; apic id = 01
fault virtual address = 0x0
fault code = supervisor read instruction, page not present
instruction pointer = 0x20:0x0
stack pointer = 0x28:0xfffffe00d9395780
frame pointer = 0x28:0xfffffe00d93957c0
code segment = base 0x0, limit 0xfffff, type 0x1b
= DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags = interrupt enabled, resume, IOPL = 0
current process = 584 (sysctl)
[ thread pid 584 tid 100083 ]
Stopped at 0:KDB: reentering
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe00d9394dc0
kdb_reenter() at kdb_reenter+0x33/frame 0xfffffe00d9394dd0
trap() at trap+0x54/frame 0xfffffe00d9394fe0
calltrap() at calltrap+0x8/frame 0xfffffe00d9394fe0
- trap 0xc, rip = 0xffffffff80690bc3, rsp = 0xfffffe00d93950a0, rbp = 0xfffffe00d9395140 ---
db_read_bytes() at db_read_bytes+0x53/frame 0xfffffe00d9395140
db_get_value() at db_get_value+0x33/frame 0xfffffe00d9395180
db_disasm() at db_disasm+0x29/frame 0xfffffe00d9395290
db_trap() at db_trap+0xbb/frame 0xfffffe00d9395320
kdb_trap() at kdb_trap+0x194/frame 0xfffffe00d93953b0
trap_fatal() at trap_fatal+0x315/frame 0xfffffe00d9395410
trap_pfault() at trap_pfault+0x23e/frame 0xfffffe00d93954b0
trap() at trap+0x4b8/frame 0xfffffe00d93956c0
calltrap() at calltrap+0x8/frame 0xfffffe00d93956c0
- trap 0xc, rip = 0, rsp = 0xfffffe00d9395780, rbp = 0xfffffe00d93957c0 ---
uart_sab82532_class() at 0/frame 0xfffffe00d93957c0
sysctl_root_handler_locked() at sysctl_root_handler_locked+0x94/frame 0xfffffe00d9395800
sysctl_root() at sysctl_root+0x188/frame 0xfffffe00d9395850
userland_sysctl() at userland_sysctl+0x192/frame 0xfffffe00d93958f0
sys___sysctl() at sys___sysctl+0x74/frame 0xfffffe00d93959a0
amd64_syscall() at amd64_syscall+0x282/frame 0xfffffe00d9395ab0
Xfast_syscall() at Xfast_syscall+0xfb/frame 0xfffffe00d9395ab0
- syscall (202, FreeBSD ELF64, sys___sysctl), rip = 0x80095086a, rsp = 0x7fffffffd9e8, rbp = 0x7fffffffda20 ---
- error reading from address 0 ***
KDB: reentering
KDB: stack backtrace:
...
db> bt
Tracing pid 584 tid 100083 td 0xfffff800057084c0
uart_sab82532_class() at 0/frame 0xfffffe00d93957c0
sysctl_root_handler_locked() at sysctl_root_handler_locked+0x94/frame 0xfffffe00d9395800
sysctl_root() at sysctl_root+0x188/frame 0xfffffe00d9395850
userland_sysctl() at userland_sysctl+0x192/frame 0xfffffe00d93958f0
sys___sysctl() at sys___sysctl+0x74/frame 0xfffffe00d93959a0
amd64_syscall() at amd64_syscall+0x282/frame 0xfffffe00d9395ab0
Xfast_syscall() at Xfast_syscall+0xfb/frame 0xfffffe00d9395ab0
- syscall (202, FreeBSD ELF64, sys___sysctl), rip = 0x80095086a, rsp = 0x7fffffffd9e8, rbp = 0x7fffffffda20 ---
- ddb: improve amd64's stack unwinding after an IP fault
- Use a more generic name for the stack pointer argument.
- Handle i386 as well.
sys/amd64/amd64/db_trace.c | ||
---|---|---|
205 | I would maybe go for three question marks, but that's entirely up to you. (i.e. not important) |
sys/amd64/amd64/db_trace.c | ||
---|---|---|
205 | I was just copying what gdb does. I'll change it to three before committing. |