LLDB 3.7 swallows real-time signals

Hi,

I have a simple program that uses real-time signals on Linux Ubuntu 14.04:

$ cat rt.cpp
#include
#include <sys/mman.h>
#include <signal.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>

void handler(int sig, siginfo_t* info, void* context)
{
std::cout << "signal " << sig << " received with value " << info->si_value.sival_in << “\n”;
}
int main()
{
int signo = SIGRTMIN + 1;
if (SIGRTMAX > SIGRTMIN)
{
struct sigaction action;
action.sa_sigaction = handler;
action.sa_flags = SA_SIGINFO;
sigaction(signo, &action, NULL);
for (int i = 0; i < 3; ++i)
{
sigval value;
value.sival_int = i + 10;
sigqueue(getpid(), signo, value);
}
}
else
{
std::cerr << “real-time signals not supported”;
}
}

This program works correctly standalone. GDB is capable of intercepting this signal and continue. LLDB-3.6 that I installed using apt-get does not intercept the signal but the program still receives it. But LLDB 3.7 that I built from sources from http://llvm.org/svn/llvm-project/lldb/trunk simply swallows the signals. I think GDB behavior is the best option, but I could live with 3.6 behavior.

Is this a known problem? Is there a workaround or fix I can apply locally?

Thanks,
Eugene

$ cat rt.cpp
#include
#include <sys/mman.h>
#include <signal.h>
#include <assert.h>
#include <sys/types.h>
#include <unistd.h>

void handler(int sig, siginfo_t* info, void* context)
{
std::cout << "signal " << sig << " received with value " << info->si_value.sival_in << “\n”;
}

int main()
{
int signo = SIGRTMIN + 1;
if (SIGRTMAX > SIGRTMIN)
{
struct sigaction action;
action.sa_sigaction = handler;
action.sa_flags = SA_SIGINFO;
sigaction(signo, &action, NULL);
for (int i = 0; i < 3; ++i)
{
sigval value;
value.sival_int = i + 10;
sigqueue(getpid(), signo, value);
}
}
else
{
std::cerr << “real-time signals are not supported”;
}
}

$ ./rt
signal 35 received with value 10
signal 35 received with value 11
signal 35 received with value 12

$ ~/llvm/bin/lldb ./rt
(lldb) target create “./rt”
Current executable set to ‘./rt’ (x86_64).
(lldb) pr lau
Process 18697 launched: ‘./rt’ (x86_64)
Process 18697 exited with status = 0 (0x00000000)
(lldb) q

$ lldb-3.6 ./rt
(lldb) target create “./rt”
Current executable set to ‘./rt’ (x86_64).
(lldb) pr lau
Process 18674 launching
Process 18674 launched: ‘./rt’ (x86_64)
signal 35 received with value 10
signal 35 received with value 11
signal 35 received with value 12
Process 18674 exited with status = 0 (0x00000000)
(lldb) q

$ gdb --quiet ./rt
Reading symbols from ./rt…done.
(gdb) r
Starting program: /home/eugene/Z/tmp/rt
Program received signal SIG35, Real-time event 35.
0x00007ffff722cfc4 in __sigqueue (pid=18662, sig=35, val=…) at …/sysdeps/unix/sysv/linux/sigqueue.c:46
46 …/sysdeps/unix/sysv/linux/sigqueue.c: No such file or directory.
(gdb) c
Continuing.
signal 35 received with value 10
Program received signal SIG35, Real-time event 35.
0x00007ffff722cfc4 in __sigqueue (pid=18662, sig=35, val=…) at …/sysdeps/unix/sysv/linux/sigqueue.c:46
46 in …/sysdeps/unix/sysv/linux/sigqueue.c
(gdb) c
Continuing.
signal 35 received with value 11
Program received signal SIG35, Real-time event 35.
0x00007ffff722cfc4 in __sigqueue (pid=18662, sig=35, val=…) at …/sysdeps/unix/sysv/linux/sigqueue.c:46
46 in …/sysdeps/unix/sysv/linux/sigqueue.c
(gdb) c
Continuing.
signal 35 received with value 12
[Inferior 1 (process 18662) exited normally]
(gdb) q

Hello,

I debugged signal processing a bit, and I think that the right solution would be just to add these signals to the list of known signals. I.e. in LinuxSignals.cpp:

void
LinuxSignals::Reset()
{
m_signals.clear();
AddSignal (1, “SIGHUP”, “HUP”, false, true , true , “hangup”);
AddSignal (2, “SIGINT”, “INT”, true , true , true , “interrupt”);
AddSignal (3, “SIGQUIT”, “QUIT”, false, true , true , “quit”);
AddSignal (4, “SIGILL”, “ILL”, false, true , true , “illegal instruction”);
AddSignal (5, “SIGTRAP”, “TRAP”, true , true , true , “trace trap (not reset when caught)”);
AddSignal (6, “SIGABRT”, “ABRT”, false, true , true , “abort()”);
AddSignal (6, “SIGIOT”, “IOT”, false, true , true , “IOT trap”);
AddSignal (7, “SIGBUS”, “BUS”, false, true , true , “bus error”);
AddSignal (8, “SIGFPE”, “FPE”, false, true , true , “floating point exception”);
AddSignal (9, “SIGKILL”, “KILL”, false, true , true , “kill”);
AddSignal (10, “SIGUSR1”, “USR1”, false, true , true , “user defined signal 1”);
AddSignal (11, “SIGSEGV”, “SEGV”, false, true , true , “segmentation violation”);
AddSignal (12, “SIGUSR2”, “USR2”, false, true , true , “user defined signal 2”);
AddSignal (13, “SIGPIPE”, “PIPE”, false, true , true , “write to pipe with reading end closed”);
AddSignal (14, “SIGALRM”, “ALRM”, false, false, false, “alarm”);
AddSignal (15, “SIGTERM”, “TERM”, false, true , true , “termination requested”);
AddSignal (16, “SIGSTKFLT”, “STKFLT”, false, true , true , “stack fault”);
AddSignal (16, “SIGCLD”, “CLD”, false, false, true , “same as SIGCHLD”);
AddSignal (17, “SIGCHLD”, “CHLD”, false, false, true , “child status has changed”);
AddSignal (18, “SIGCONT”, “CONT”, false, true , true , “process continue”);
AddSignal (19, “SIGSTOP”, “STOP”, true , true , true , “process stop”);
AddSignal (20, “SIGTSTP”, “TSTP”, false, true , true , “tty stop”);
AddSignal (21, “SIGTTIN”, “TTIN”, false, true , true , “background tty read”);
AddSignal (22, “SIGTTOU”, “TTOU”, false, true , true , “background tty write”);
AddSignal (23, “SIGURG”, “URG”, false, true , true , “urgent data on socket”);
AddSignal (24, “SIGXCPU”, “XCPU”, false, true , true , “CPU resource exceeded”);
AddSignal (25, “SIGXFSZ”, “XFSZ”, false, true , true , “file size limit exceeded”);
AddSignal (26, “SIGVTALRM”, “VTALRM”, false, true , true , “virtual time alarm”);
AddSignal (27, “SIGPROF”, “PROF”, false, false, false, “profiling time alarm”);
AddSignal (28, “SIGWINCH”, “WINCH”, false, true , true , “window size changes”);
AddSignal (29, “SIGPOLL”, “POLL”, false, true , true , “pollable event”);
AddSignal (29, “SIGIO”, “IO”, false, true , true , “input/output ready”);
AddSignal (30, “SIGPWR”, “PWR”, false, true , true , “power failure”);
AddSignal (31, “SIGSYS”, “SYS”, false, true , true , “invalid system call”);

// Add real-time signals
for (int rtsig = SIGRTMIN + 1; rtsig < SIGRTMAX; ++rtsig)
{
char signame[16];
char sigdescr[64];
::snprintf(signame, sizeof(signame), “SIG%d”, rtsig);
::snprintf(sigdescr, sizeof(sigdescr), “Real-time event %d”, rtsig);
AddSignal (rtsig, signame, signame, false, true, true, sigdescr);
}
}

Thanks,
Eugene

Hello Eugene,

thanks for diagnosing this issue. I will commit something similar to
LLDB shortly.

cheers,
pl

Thank you!

I have another concern about this file: why do we use numerical constants like 1,2,3,… here instead of symbolic SIGHUP,SIGINT,SIGQUIT,…?
Linux signal(7) man page gives 3 different values for some signals on different platforms. For example, SIGUSR1 could be 30, 10, or 16.

Standard signals
Linux supports the standard signals listed below. Several signal numbers are architecture-dependent, as
indicated in the “Value” column. (Where three values are given, the first one is usually valid for alpha
and sparc, the middle one for x86, arm, and most other architectures, and the last one for mips. (Values
for parisc are not shown; see the Linux kernel source for signal numbering on that architecture.) A -
denotes that a signal is absent on the corresponding architecture.)
First the signals described in the original POSIX.1-1990 standard.
Signal Value Action Comment
──────────────────────────────────────────────────────────────────────
SIGHUP 1 Term Hangup detected on controlling terminal
or death of controlling process
SIGINT 2 Term Interrupt from keyboard
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGABRT 6 Core Abort signal from abort(3)
SIGFPE 8 Core Floating point exception
SIGKILL 9 Term Kill signal
SIGSEGV 11 Core Invalid memory reference
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers
SIGALRM 14 Term Timer signal from alarm(2)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated

Eugene

Hi all,

Now that I think about it, being able to continue the process after it hits a SIGSEGV is very important for Android because the ART runtime (and dalvik?) use SIGSEGV to detect and generate NullPointerExceptions in Java.

Ideally, on Android, if we see a SIGSEGV at a PC that belongs to jit code we should probably just transparently continue the process.

Vince

Hello Eugene,

the reason for using raw numbers is that lldb is a cross platform
debugger, and you want to be able to do remote debugging where the
remote system has a different os/architecture. For this to work you
cannot rely on any constants from the host system when you are
compiling the client component. Therefore, we hardcoded the signal
numbers for x86(_64) in LinuxSignals, which until very recently was
the only supported linux architecture. However, you are right that
signal numbers differ across different architectures, so I guess we
will need to do a switch (or equivalent) here. I will create an issue
to track this.

Vince, that sounds like a reasonable thing to do. I will create an
issue for this as well.

cheers,
pl