SIGSEGV: handle and pretty-print on amd64-linux
This commit is contained in:
parent
bbf52cee67
commit
9866b9bca9
@ -423,6 +423,8 @@ tc.amd64-linux.elf.gcc = amd64-linux-gcc-3.4.4 -fPIC -m64 -nostdinc -MMD -MT $@
|
|||||||
tc.amd64-linux.elf.gcc += -fno-exceptions -fno-asynchronous-unwind-tables
|
tc.amd64-linux.elf.gcc += -fno-exceptions -fno-asynchronous-unwind-tables
|
||||||
tc.amd64-linux.elf.gcc += -Wall -W -Wcast-align -Wcast-qual -Wstrict-prototypes -Wwrite-strings -Werror
|
tc.amd64-linux.elf.gcc += -Wall -W -Wcast-align -Wcast-qual -Wstrict-prototypes -Wwrite-strings -Werror
|
||||||
|
|
||||||
|
#amd64-linux.elf-entry.h amd64-linux.elf-fold.h: tc.amd64-linux.elf.gcc += -DTEST_SIGSEGV
|
||||||
|
|
||||||
amd64-linux.elf-entry.h: $(srcdir)/src/$$T.S
|
amd64-linux.elf-entry.h: $(srcdir)/src/$$T.S
|
||||||
@echo; echo TARGET=$@ PATH=$(PATH); echo
|
@echo; echo TARGET=$@ PATH=$(PATH); echo
|
||||||
$(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
|
$(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin
|
||||||
|
|||||||
@ -95,6 +95,45 @@ _start: .globl _start
|
|||||||
push %rcx // argc
|
push %rcx // argc
|
||||||
push %rdx // param for atexit()
|
push %rdx // param for atexit()
|
||||||
|
|
||||||
|
#if TEST_SIGSEGV
|
||||||
|
// install SIGSEGV handler for debugging
|
||||||
|
SIGSEGV= 11
|
||||||
|
SA_SIGINFO= 4 // /usr/include/bits/sigaction.h
|
||||||
|
SA_RESTORER= 0x04000000
|
||||||
|
__NR_rt_sigaction= 13 // /usr/include/asm/unistd_64.h
|
||||||
|
push %rdi // save reg
|
||||||
|
sub %edx,%edx // arg3= 0 ==> do not save old sigaction
|
||||||
|
push %rdx // .sa_mask: 64 bits (8 bytes) of flags for signals
|
||||||
|
lea __restore_rt(%rip),%rax; push %rax // .sa_restorer
|
||||||
|
push $SA_RESTORER | SA_SIGINFO // .sa_flags
|
||||||
|
lea sigsegv_sigaction(%rip),%rax; push %rax // .sa_sigaction
|
||||||
|
push %rsp; pop %rsi // arg2= &new struct sigaction
|
||||||
|
push $SIGSEGV; pop %rdi // arg1= signum
|
||||||
|
push $8; pop %r10 // sys4= sizeof(__sigset_t) ==> 64 bits
|
||||||
|
push $__NR_rt_sigaction; pop %rax; syscall
|
||||||
|
add $(3 + 1) * NBPW,%rsp // toss struct sigaction
|
||||||
|
pop %rdi // restore reg
|
||||||
|
|
||||||
|
#if 0 //{ TEST ONLY
|
||||||
|
movl $0x18181818,%r8d
|
||||||
|
movl $0x19191919,%r9d
|
||||||
|
movl $0x1a1a1a1a,%r10d
|
||||||
|
movl $0x1b1b1b1b,%r11d
|
||||||
|
movl $0x1c1c1c1c,%r12d
|
||||||
|
movl $0x1d1d1d1d,%r13d
|
||||||
|
movl $0x1e1e1e1e,%r14d
|
||||||
|
movl $0x1f1f1f1f,%r15d
|
||||||
|
movl $0xaaaaaaaa,%eax
|
||||||
|
movl $0xbbbbbbbb,%ebx
|
||||||
|
movl $0xcccccccc,%ecx
|
||||||
|
movl $0xdddddddd,%edx
|
||||||
|
movl $0x55555555,%ebp
|
||||||
|
movl $0x66666666,%esi
|
||||||
|
movl $0x77777777,%edi
|
||||||
|
movl (%rdx),%edx // force SIGSEGV
|
||||||
|
#endif //}
|
||||||
|
#endif // TEST_SIGSEGV
|
||||||
|
|
||||||
#define old_sp %rbp
|
#define old_sp %rbp
|
||||||
F_FRAME= 7*NBPW
|
F_FRAME= 7*NBPW
|
||||||
F_ENTR= 6*NBPW; F_PMASK= F_ENTR
|
F_ENTR= 6*NBPW; F_PMASK= F_ENTR
|
||||||
@ -295,6 +334,165 @@ eof_n2b:
|
|||||||
add $D_FOLD,%rax // beyond .data
|
add $D_FOLD,%rax // beyond .data
|
||||||
jmp *%rax // goto unfolded stub
|
jmp *%rax // goto unfolded stub
|
||||||
|
|
||||||
|
#if TEST_SIGSEGV
|
||||||
|
__NR_rt_sigreturn= 15
|
||||||
|
.balign 16
|
||||||
|
__restore_rt:
|
||||||
|
endbr64
|
||||||
|
mov $__NR_rt_sigreturn,%eax
|
||||||
|
syscall
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
sigsegv_sigaction:
|
||||||
|
endbr64
|
||||||
|
push %rdx // save &ucontext_t
|
||||||
|
|
||||||
|
// print /proc/self/maps of child (same as parent: the beauty of fork())
|
||||||
|
mov $end_announce_sigaction - announce_sigaction,%edx // arg3 len
|
||||||
|
lea announce_sigaction(%rip),%rsi // arg2 buf
|
||||||
|
push $2; pop %rdi // arg1 fd_stderr
|
||||||
|
push $__NR_write; pop %eax; syscall // ignore error on write()
|
||||||
|
|
||||||
|
xor %esi,%esi // arg2 O_RDONLY
|
||||||
|
lea proc_self_maps(%rip),%arg1
|
||||||
|
push $__NR_open; pop %rax; syscall
|
||||||
|
mov %rax,%r12 // fd_maps
|
||||||
|
BUFLEN= 4096
|
||||||
|
mov $BUFLEN,%ebx; sub %rbx,%rsp // allocate buffer
|
||||||
|
loop_maps:
|
||||||
|
mov %ebx,%edx // arg3 buflen
|
||||||
|
push %rsp; pop %rsi // arg2 buffer
|
||||||
|
mov %r12,%rdi // arg1 fd_maps
|
||||||
|
xor %eax,%eax; syscall // __NR_read
|
||||||
|
test %eax,%eax; jle done_maps // ignore error on read()
|
||||||
|
mov %eax,%edx // arg3 buflen
|
||||||
|
push %rsp; pop %rsi // arg2 buf
|
||||||
|
push $2; pop %rdi // arg1 fd_stderr
|
||||||
|
push $__NR_write; pop %rax; syscall // ignore error on write()
|
||||||
|
jmp loop_maps
|
||||||
|
done_maps:
|
||||||
|
mov %r12,%rdi //arg1 fd_maps
|
||||||
|
add %rbx,%rsp // discard buffer
|
||||||
|
push $__NR_close; pop %rax; syscall
|
||||||
|
// end printing of /proc/self/maps
|
||||||
|
|
||||||
|
pop %rdx // restore &ucontext_t
|
||||||
|
__NR_fork= 57
|
||||||
|
push $__NR_fork; pop %rax; call sys_check
|
||||||
|
test %eax,%eax; je child
|
||||||
|
parent:
|
||||||
|
jmp parent // spin; paused by gdb
|
||||||
|
|
||||||
|
proc_self_cmdline:
|
||||||
|
.asciz "/proc/self/cmdline"
|
||||||
|
announce_sigaction:
|
||||||
|
.asciz "\n\nSIGSEGV address space:\n"
|
||||||
|
end_announce_sigaction:
|
||||||
|
|
||||||
|
proc_self_maps:
|
||||||
|
.asciz "/proc/self/maps"
|
||||||
|
minus_q:
|
||||||
|
.asciz "-q"
|
||||||
|
path_gdb:
|
||||||
|
.asciz "/usr/bin/gdb"
|
||||||
|
commands_gdb:
|
||||||
|
.ascii "info inferiors\n"
|
||||||
|
|
||||||
|
.ascii "print \"r8, r9\"\n"
|
||||||
|
.ascii "x/2xg $rdx + 5*8\n"
|
||||||
|
.ascii "print \"r10, r11\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"r12, r13\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"r14, r15\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
|
||||||
|
.ascii "print \"rdi, rsi\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"rbp, rbx\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"rdx, rax\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"rcx, rsp\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
.ascii "print \"rip, efl\"\n"
|
||||||
|
.ascii "x/2xg\n"
|
||||||
|
|
||||||
|
.ascii "set $pc = *(long *)($rdx + 168)\n"
|
||||||
|
.ascii "print \"faulting instr\"\n"
|
||||||
|
.ascii "x/i $pc\n"
|
||||||
|
.ascii "print \"fault context\"\n"
|
||||||
|
.ascii "x/24i $pc - 0x20\n"
|
||||||
|
|
||||||
|
.ascii "kill\n"
|
||||||
|
.ascii "quit 1"
|
||||||
|
.byte 0
|
||||||
|
commands_gdb_end:
|
||||||
|
|
||||||
|
child:
|
||||||
|
PATH_MAX= 4096
|
||||||
|
sub $PATH_MAX,%rsp
|
||||||
|
lea proc_self_cmdline(%rip),%arg1
|
||||||
|
O_RDONLY= 0
|
||||||
|
push $O_RDONLY; pop %arg2
|
||||||
|
push $__NR_open; pop %rax; call sys_check
|
||||||
|
push %rax; pop %arg1 // fd
|
||||||
|
push %rsp; pop %arg2 // buffer
|
||||||
|
push $PATH_MAX; pop %arg3
|
||||||
|
__NR_read= 0
|
||||||
|
push $__NR_read; pop %rax; call sys_check
|
||||||
|
push $__NR_close; pop %eax; call sys_check
|
||||||
|
|
||||||
|
__NR_getppid= 110
|
||||||
|
push $__NR_getppid; pop %eax; syscall
|
||||||
|
push %rax; pop %rsi
|
||||||
|
xor %eax,%eax; push %rax; push %rax // decimal(pid) fits in 16 bytes
|
||||||
|
push %rsp; pop %rdi; call unsimal
|
||||||
|
// argv
|
||||||
|
push %rsp; pop %rsi // fence post: &pid.unsimal
|
||||||
|
push $0 // argv[4]
|
||||||
|
push %rsi // arg3 pid
|
||||||
|
add $16,%rsi; push %rsi // arg2 exename
|
||||||
|
lea minus_q(%rip),%rax; push %rax // arg1 "-q"
|
||||||
|
add $(path_gdb - minus_q),%rax; push %rax // arg[0] "/usr/bin/gdb"
|
||||||
|
|
||||||
|
#if 1 //{ pipe input to gdb
|
||||||
|
xor %edi,%edi; push $__NR_close; pop %rax; syscall
|
||||||
|
push %rax; push %rsp; pop %rdi // &fd_pipe[2]; 4 bytes each
|
||||||
|
__NR_pipe= 22
|
||||||
|
push $__NR_pipe; pop %rax; call sys_check
|
||||||
|
pop %rdi; shr $32,%rdi // arg1 write side of pipe
|
||||||
|
|
||||||
|
push $commands_gdb_end - commands_gdb; pop %arg3
|
||||||
|
lea commands_gdb(%rip),%arg2
|
||||||
|
__NR_write= 1
|
||||||
|
push $__NR_write; pop %rax; call sys_check
|
||||||
|
push $__NR_close; pop %rax; syscall
|
||||||
|
#endif //}
|
||||||
|
|
||||||
|
push $0; pop %arg3 // _environ BUG
|
||||||
|
push %rsp; pop %arg2 // argv
|
||||||
|
movq (%arg2),%arg1 // "/usr/bin/gdb"
|
||||||
|
__NR_execve= 59
|
||||||
|
push $__NR_execve; pop %rax; call sys_check
|
||||||
|
hlt
|
||||||
|
|
||||||
|
unsimal: // (dst, value)
|
||||||
|
push $10; pop %rcx // radix
|
||||||
|
mov %esi,%eax // value
|
||||||
|
call 0f
|
||||||
|
movb $0,(%rdi) // terminator
|
||||||
|
ret
|
||||||
|
0:
|
||||||
|
xor %edx,%edx; div %ecx; push %rdx // eax= quo(%edx:%eax / %ecx); edx= rem
|
||||||
|
// 'div' undefines all flags!
|
||||||
|
test %eax,%eax; je 1f; call 0b
|
||||||
|
1:
|
||||||
|
pop %rax; add $'0',%eax
|
||||||
|
stosb
|
||||||
|
ret
|
||||||
|
#endif // TEST_SIGSEGV
|
||||||
|
|
||||||
sys_check:
|
sys_check:
|
||||||
push %rax // save __NR_ for debug
|
push %rax // save __NR_ for debug
|
||||||
syscall
|
syscall
|
||||||
|
|||||||
@ -177,6 +177,17 @@ no_env_pse:
|
|||||||
mov %ebp,%ebx # fd
|
mov %ebp,%ebx # fd
|
||||||
movq %rax,3*NBPW(%rsp) # entry
|
movq %rax,3*NBPW(%rsp) # entry
|
||||||
|
|
||||||
|
#if TEST_SIGSEGV
|
||||||
|
// Uninstall SIGSEGV handler
|
||||||
|
SIGSEGV= 11
|
||||||
|
__NR_rt_sigaction= 13 // /usr/include/asm/unistd_64.h
|
||||||
|
push $8; pop %sys4 // sys_arg4 minimal byte count
|
||||||
|
xor %edx,%edx // no old
|
||||||
|
xor %esi,%esi // no new
|
||||||
|
push $SIGSEGV; pop %rdi
|
||||||
|
push $__NR_rt_sigaction; pop %eax; syscall
|
||||||
|
#endif // TEST_SIGSEGV
|
||||||
|
|
||||||
sz_Ehdr= 8*NBPW
|
sz_Ehdr= 8*NBPW
|
||||||
e_type= 16
|
e_type= 16
|
||||||
ET_EXEC= 2
|
ET_EXEC= 2
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user