Signal handling with qemu-user
Asked Answered
G

2

9

On my machine I have an aarch64 binary, that is statically compiled. I run it using qemu-aarch64-static with the -g 6566 flag. In another terminal I start up gdb-multiarch and connect as target remote localhost:6566.

I expect the binary to raise a signal for which I have a handler defined in the binary. I set a breakpoint at the handler from inside gdb-multiarch after connecting to remote. However, when the signal arises, the breakpoint is not hit on gdb-multiarch. Instead, on the terminal that runs the binary, I get a message along the lines of :-

[1]     + 8388 suspended (signal)  qemu-aarch64-static -g 6566 ./testbinary

Why does this happen? How can I set a breakpoint on the handler and debug it? I've tried SIGCHLD and SIGFPE.

Gingili answered 13/7, 2015 at 12:47 Comment(2)
What is the signal you want to catch after all? SIGCHLD and SIGFPE are raised under very different conditions, I don't see how you tried them both because there is no relation between them. Show the handlers code and how you set them up.Allot
I've tried them both for separate binaries. For SIGCHLD binary does a fork, parent does a wait. For SIGFPE, I perform an intentional division by 0. Handlers are added as signal(SIGCHLD, handler) or signal(SIGFPE, handler).Gingili
L
2

This works for me with a recent QEMU:

$ cat sig.c

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>

void handler(int sig) {
     printf("In signal handler, signal %d\n", sig);
     return;
}

int main(void) {
    printf("hello world\n");
    signal(SIGUSR1, handler);
    raise(SIGUSR1);
    printf("done\n");
    return 0;
}

$ aarch64-linux-gnu-gcc -g -Wall -o sig sig.c -static

$ qemu-aarch64 -g 6566 ./sig

and then in another window:

$ gdb-multiarch 
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
[etc]
(gdb) set arch aarch64
The target architecture is assumed to be aarch64
(gdb) file /tmp/sigs/sig
Reading symbols from /tmp/sigs/sig...done.
(gdb) target remote :6566
Remote debugging using :6566
0x0000000000400c98 in _start ()
(gdb) break handler
Breakpoint 1 at 0x400e44: file sig.c, line 6.
(gdb) c
Continuing.

Program received signal SIGUSR1, User defined signal 1.
0x0000000000405c68 in raise ()
(gdb) c
Continuing.

Breakpoint 1, handler (sig=10) at sig.c:6
6        printf("In signal handler, signal %d\n", sig);
(gdb)

As you can see, gdb gets control both immediately the process receives the signal and then again when we hit the breakpoint for the handler function.

Incidentally, (integer) dividing by zero is not a reliable way to provoke a signal. This is undefined behaviour in C, and the implementation is free to do the most convenient thing. On x86 this typically results in a SIGFPE. On ARM you will typically find that the result is zero and execution will continue without a signal. (This is a manifestation of the different behaviour of the underlying hardware instructions for division between the two architectures.)

Louie answered 26/7, 2015 at 19:37 Comment(0)
M
1

i was doing some R&D for your answer and find following answer

"Internally, bad memory accesses result in the Mach exception EXC_BAD_ACCESS being sent to the program. Normally, this is translated into a SIGBUS UNIX signal. However, gdb intercepts Mach exceptions directly, before the signal translation. The solution is to give gdb the command set dont-handle-bad-access 1 before running your program. Then the normal mechanism is used, and breakpoints inside your signal handler are honored."

The link is gdb: set a breakpoint for a SIGBUS handler It perhaps help you by considering that qemu does not change the functionality of base operations

Meow answered 23/7, 2015 at 16:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.