Catching SIGSEGV caused by jump to null pointer hangs qemu-arm-static
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Linaro QEMU |
New
|
Undecided
|
Unassigned |
Bug Description
Host system: Ubuntu 12.04 on x86_64
I'm maintaining a fork of UnitTest++ (https:/
Reproduction with standalone test-case:
# Verify test-case works on host...
$ wget -qO foo.c http://
$ gcc -Wall -pedantic-errors -std=gnu99 foo.c
$ ./a.out
Hello World
catchCrash(
catchCrash(
catchCrash(
catchCrash(jmpZero) returned 1
# Now setup armel chroot...
$ cd /var/qemu
$ apt-get install qemu-user-static
$ apt-get install debootstrap
$ qemu-debootstrap --arch armel wheezy armel http://
$ mount -t proc proc armel/proc
$ mount -t sysfs sysfs armel/sys
$ mount -o bind /dev armel/dev
$ LC_ALL=C chroot armel
# In the chroot...
$ wget -qO foo.c http://
$ gcc -Wall -pedantic-errors -std=gnu99 foo.c
$ ./a.out
Hello World
catchCrash(
catchCrash(
catchCrash(
<...hangs...>
What's interesting is that SIGSEGV resulting from simply dereferencing a null pointer work fine, but if you call a null function-pointer, it hangs.
You can see a prettified rendering of the code here:
http://
I also tried with a build of qemu-arm-static from what I believe is the latest source:
# Host-side...
$ cd /var/qemu
$ wget -qO- --no-check-
$ cd qemu-linaro-
$ ./configure --target-
$ make
$ cd ..
$ mv armel/usr/
$ cp qemu-linaro-
$ LC_ALL=C chroot armel
# In the chroot...
$ wget -qO foo.c http://
$ gcc -Wall -pedantic-errors -std=gnu99 foo.c
$ ./a.out
Hello World
catchCrash(
catchCrash(
catchCrash(
<...hangs...>
Any help or suggestions gratefully received.
Chris
This happens because linux-user mode doesn't emulate the guest MMU. In system emulation mode (where the test case runs OK) we identify accesses and jumps to 0 because they have no TLB entry and we end up with tlb_fill() calling raise_exception() and generating an emulated guest CPU exception (via a longjmp out to the top level). In linux-user mode we handle accesses to address 0 by catching the host SIGSEGV and identifying it as a fault in generated code which needs to be turned into a guest SIGSEGV. However if the guest jumps to address 0 then the SEGV ends up happening in QEMU proper:
#0 0x000055555560e4db in ldl_p (ptr=0x7ffefc9c a000) at /tmp/qemu- linaro- 1.4.0-2013. 03/include/ qemu/bswap. h:261 a000) at /tmp/qemu- linaro- 1.4.0-2013. 03/include/ qemu/bswap. h:294 aec0, addr=0, do_swap=false) at /tmp/qemu- linaro- 1.4.0-2013. 03/target- arm/cpu. h:748 aec0, s=0x7fffffffda90) at /tmp/qemu- linaro- 1.4.0-2013. 03/target- arm/translate. c:6580 e_code_ internal (env=0x55555783 aec0, tb=0x7ffff39d99e8, search_pc=0) linaro- 1.4.0-2013. 03/target- arm/translate. c:9890 e_code (env=0x55555783 aec0, tb=0x7ffff39d99e8) at /tmp/qemu- linaro- 1.4.0-2013. 03/target- arm/translate. c:10019 aec0, tb=0x7ffff39d99e8, gen_code_ size_ptr= 0x7fffffffdbd8) linaro- 1.4.0-2013. 03/translate- all.c:174 aec0, pc=0, cs_base=0, flags=128, cflags=0) at /tmp/qemu- linaro- 1.4.0-2013. 03/translate- all.c:968 aec0, pc=0, cs_base=0, flags=128) at /tmp/qemu- linaro- 1.4.0-2013. 03/cpu- exec.c: 125 aec0) at /tmp/qemu- linaro- 1.4.0-2013. 03/cpu- exec.c: 152 aec0) at /tmp/qemu- linaro- 1.4.0-2013. 03/cpu- exec.c: 567 aec0) at /tmp/qemu- linaro- 1.4.0-2013. 03/linux- user/main. c:707 e5e8, envp=0x7fffffff e600) at /tmp/qemu- linaro- 1.4.0-2013. 03/linux- user/main. c:3984
#1 0x000055555560e55f in ldl_le_p (ptr=0x7ffefc9c
#2 0x000055555560e64d in arm_ldl_code (env=0x55555783
#3 0x000055555563623b in disas_arm_insn (env=0x55555783
#4 0x000055555563e5cb in gen_intermediat
at /tmp/qemu-
#5 0x000055555563ea13 in gen_intermediat
#6 0x000055555564dca0 in cpu_arm_gen_code (env=0x55555783
at /tmp/qemu-
#7 0x000055555564f044 in tb_gen_code (env=0x55555783
#8 0x00005555555a0a3b in tb_find_slow (env=0x55555783
#9 0x00005555555a0bb2 in tb_find_fast (env=0x55555783
#10 0x00005555555a0fdf in cpu_arm_exec (env=0x55555783
#11 0x00005555555c7fcb in cpu_loop (env=0x55555783
#12 0x00005555555ca2f8 in main (argc=2, argv=0x7fffffff
and linux-user QEMU copes very badly with signals that are caused by bits of its own code (it turns them into signals directed at the guest, which usually means we just hang rather than aborting with a helpful error message).