Hi,
Before going for vacation I had changed Hatari call stack handling
to deal with kernel stack manipulations (changing rts to a jump)
by brute force. Call stack output has now also symbol offset info.
I used these to look at the random LINE issue with udevadm on
Debian installer initrd. Backtrace of that looks weird though:
---------------------------------------------------
...
[ 54.880000] random: crng init done
[ 61.660000] *** LINE 1111 *** FORMAT=0
[ 61.670000] Current process id is 50
1. CPU breakpoint condition(s) matched 1 times.
pc = die_if_kernel :trace :noinit :file stack-show.ini
Reading debugger commands from 'stack-show.ini'...
> profile stack
- 1. 0x00511a: trap_c -0x56 (return = 0x287c)
- 2. 0x002876: schedule -0x2c7b8e (return = 0x3ba5e)
=> trap() instruction calling trap_c()
- 3. 0x03ba58: schedule -0x28e9ac (return = 0x3ba5e)
=> worker_thread() instruction calling schedule()
- 4. 0x03ba58: system_call +0x3913c (return = 0xc00e5082)
=> worker_thread() instruction calling schedule()
- 5. 0xc00e507e: system_call (return = 0xc00418da)
=> do_fcntl()?
- 6. 0xc00418d6: system_call (return = 0xc00418da)
=> middle of current_is_async() RTS instruction -> non-translated
user-space address from TT-RAM?
- 7. 0xc00418d6: system_call (return = 0xc00418da)
...
- 250. 0xc00418d6: system_call (return = 0xc00dbf8a)
- 251. 0xc00dbf86: system_call (return = 0xc00dcd26)
- 252. 0xc00dcd22: system_call (return = 0xc00418da)
[ 61.680000] BAD KERNEL TRAP: 00000000
[ 61.700000] Modules linked in:
[ 61.710000] PC: [<00002a2c>] user_inthandler+0x4/0x20
[ 61.720000] SR: 2c08 SP: bdb94e1a a2: 0006e000
[ 61.730000] d0: c0274000 d1: 000083ac d2: 00000af9 d3: c021b81c
[ 61.740000] d4: c0206000 d5: c001ed40 a0: c0206000 a1: c021d2c8
[ 61.750000] Process udevadm (pid: 50, task=d01ed1a6)
[ 61.760000] Frame format=0
[ 61.770000] Stack from 05a4fff8:
[ 61.770000] 0208c000 b6460110
[ 61.780000] Call Trace:
[ 61.790000] Code: 0000 2b24 508f 60ff ffff ff64 42a7 4878 <ffff> 2f00
48e7 7ce0 200f 0280 ffff e000 2440 2452 e9ef 010a 0032 0440 0038 2f0f
[ 61.810000] Disabling lock debugging due to kernel taint
---------------------------------------------------
I get large number of system_call() calls in call stack only
when tracking exception calls in addition to subroutine calls
(this happens also when there are no oopses & bad traps).
This means that there are some system_call() traps, where matching
RTE instructions are missing.
Looking at the assembly for system_call(), after the system call
has finished, system_call() can end in RTE, but in some cases it
will (eventually) call schedule() instead.
And apparently during last schedule() operation in above call stack,
user_inthandler() gets called at 0x4 offset where there's no valid
opcode (as that address is between instructions):
---------------------------------------------------
> d user_inthandler
user_inthandler:
$00002a28 : 42a7 clr.l -(sp)
$00002a2a : 4878 ffff pea $ffffffff.w
$00002a2e : 2f00 move.l d0,-(sp)
...
> m $2a2c
00002A2C: ff ff 2f 00 ...
---------------------------------------------------
I assume the invalid "ffff" "opcode" to cause the "line 1111" trap.
Because of the PS_S status register state, kernel trap handler says
it's a bad trap, see [1].
Questions:
* Any idea what could cause wrong offset to user_inthandler()?
* Does schedule(), or rest of system_call(), clean exception stack?
* What kind of size limits there are on different stack sizes?
* Are there e.g. any symbols pointing to stack base addresses
and stack size limits which I could use in conditional breakpoints?
- Eero
[1] Looking at kernel code, above call stack comes from:
-> trap_c()
-> void bad_super_trap()
-> die_if_kernel()
Corresponding kernel code is:
---------------------------------------------------
ENTRY(trap)
SAVE_ALL_INT
GET_CURRENT(%d0)
movel %sp,%sp@- | stack frame pointer argument
jbsr trap_c
...
asmlinkage void trap_c(struct frame *fp)
{
int sig, si_code;
void __user *addr;
int vector = (fp->ptregs.vector >> 2) & 0xff;
if (fp->ptregs.sr & PS_S) {
if (vector == VEC_TRACE) {
/* traced a trapping instruction on a 68020/30,
* real exception will be executed afterwards.
*/
return;
}
#ifdef CONFIG_MMU
if (fixup_exception(&fp->ptregs))
return;
#endif
bad_super_trap(fp);
return;
}
...
void bad_super_trap (struct frame *fp)
{
int vector = (fp->ptregs.vector >> 2) & 0xff;
console_verbose();
if (vector < ARRAY_SIZE(vec_names))
pr_err("*** %s *** FORMAT=%X\n",
vec_names[vector],
fp->ptregs.format);
else
pr_err("*** Exception %d *** FORMAT=%X\n",
vector, fp->ptregs.format);
if (vector == VEC_ADDRERR && CPU_IS_020_OR_030) {
...
}
pr_err("Current process id is %d\n", task_pid_nr(current));
die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
}
...
void die_if_kernel (char *str, struct pt_regs *fp, int nr)
{
if (!(fp->sr & PS_S))
return;
console_verbose();
pr_crit("%s: %08x\n", str, nr);
show_registers(fp);
add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
do_exit(SIGSEGV);
}
...
int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
struct pt_regs *tregs;
/* Are we prepared to handle this kernel fault? */
fixup = search_exception_tables(regs->pc);
if (!fixup)
return 0;
...
const struct exception_table_entry *search_exception_tables(unsigned
long addr)
{
const struct exception_table_entry *e;
e = search_extable(__start___ex_table,
__stop___ex_table - __start___ex_table, addr);
if (!e)
e = search_module_extables(addr);
return e;
}
...
const struct exception_table_entry *search_module_extables(unsigned long
addr)
{
const struct exception_table_entry *e = NULL;
struct module *mod;
preempt_disable();
mod = __module_address(addr);
if (!mod)
goto out;
if (!mod->num_exentries)
goto out;
e = search_extable(mod->extable,
mod->num_exentries,
addr);
out:
preempt_enable();
/*
* Now, if we found one, we are running inside it now, hence
* we cannot unload the module, hence no refcnt needed.
*/
return e;
}
...
const struct exception_table_entry *
search_extable(const struct exception_table_entry *base,
const size_t num,
unsigned long value)
{
return bsearch(&value, base, num,
sizeof(struct exception_table_entry),
cmp_ex_search);
}
...
#define EXCEPTION_TABLE(align) \
. = ALIGN(align); \
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \
__start___ex_table = .; \
KEEP(*(__ex_table)) \
__stop___ex_table = .; \
}
...
SECTIONS
{
. = 0x1000;
_text = .; /* Text and read-only data */
.text : {
HEAD_TEXT
TEXT_TEXT
IRQENTRY_TEXT
SOFTIRQENTRY_TEXT
SCHED_TEXT
CPUIDLE_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
} :text = 0x4e75
_etext = .; /* End of text section */
EXCEPTION_TABLE(16)
_sdata = .; /* Start of data section */
RODATA