This is the mail archive of the
gdb@sources.redhat.com
mailing list for the GDB project.
MT program receives SIGSEGV while debugging remotely
- From: Sergei Poselenov <sergei dot poselenov at auriga dot ru>
- To: gdb at sources dot redhat dot com
- Date: Fri, 19 Dec 2003 10:39:44 +0000
- Subject: MT program receives SIGSEGV while debugging remotely
Hi all,
I'm using gdb/gdbserver 6.0 (built on RH 8.0 (glibc 2.2.93-5))
for debugging my multithreaded application remotely on x86
target and run into this.
I double-checked the libraries used in program build and
located on target.
Finally I reproduced it on the RH 8 host running
fresh-built gdb/gdbserver. The behaviour is the same for
dynamically and statically linked program.
The testcase is pretty simple: main() creates 2 threads,
each doing nothing but printf(). After last pthread_create()
main() orders a SIGALRM with sigaction(), calls alarm(6)
and sleeps in sigsuspend() waiting for it.
I set the breakpoint in thread and it triggered OK.
Then I got SIGSEGV trying to 'next':
GNU gdb 6.0
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x40000b30 in ?? ()
(gdb) b foo
Breakpoint 1 at 0x80485f8: file /tmp/cvarmut.c, line 35.
(gdb) c
Continuing.
[New Thread 8192]
[New Thread 8194]
[Switching to Thread 8194]
Breakpoint 1, foo (str=0x804886c "+") at /tmp/cvarmut.c:35
35 printf("%s", str);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x080485f9 in foo (str=0x804886c "+") at /tmp/cvarmut.c:35
35 printf("%s", str);
(gdb)
Debugging natively goes OK, as well as the program runnig itself.
Probably this is fixed already but unfortunately I've found no
mentions about such a bug since gdb 6.0 was released.
Thanks in advance for any help...
(I'm attaching the test progarm for convenience.)
-Sergei
// INCLUDE FILES
#include <stdio.h> // Standard I/O defines for printf, etc.
#include <stdlib.h> // Defines EXIT_SUCCESS and EXIT_FAILURE
#include <pthread.h> // Headers for thread creation and access
#include <unistd.h> // Misc. POSIX defines, like sleep()
#include <signal.h> // Signal handling datatypes and routines
// Defines
#define TIME_LIMIT 6 /* Timer time limit */
// Global Variable Declarations
static pthread_t tid1, tid2; // Variable to hold ids of threads
static pthread_attr_t t_attr; // Attribute creation structure
static pthread_mutex_t mut; // Variable to hold reference to mutex
static pthread_mutexattr_t mut_attr; // Mutex attribute creation struct
static pthread_cond_t cv_a, cv_b; // Variable to hold condition vars
static pthread_condattr_t cv_attr; // Cond var attr creation struct
static int cv_count = 0; // Variable to keep track of execution cycles
int got_alarm = 0;
// Alarm handler for SIGALRM. This prints out the final
// results and terminates the program and its respective threads.
void sig_alarm_handler(int sig, void *x)
{
fprintf(stderr, "Benchmark results: %d cycles per second\n",
cv_count / TIME_LIMIT);
got_alarm = 1;
}
void foo(char *str)
{
printf("%s", str);
}
void *thread1(void *seq)
{
int i;
for (;; cv_count++) { // Run till stopped from the outside.
i = 100000;
foo("+");
while (i--)
;
}
return 0;
}
// Code for thread 2. Slightly different from that of
// thread 1 in that it sets the data structure values
// a differently.
void *thread2(void *seq)
{
int i;
for (;; cv_count++) { // Run until stopped by signal
i = 100000;
foo("-");
while(i--)
;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
// main entry point to demo_cvarmut
int main() {
struct sigaction act; // Used to hold signal mask and flags
sigset_t set; // Signal Receipt method mask
// Create thread attribute structure.
if (pthread_attr_init(&t_attr) == -1) {
perror("pthread_attr_init");
exit(EXIT_FAILURE);
}
// Create thread 1.
if (pthread_create(&tid1, &t_attr, thread1, 0) == -1) {
perror("pthread_create(1)");
exit(EXIT_FAILURE);
}
// Create thread 2.
if (pthread_create(&tid2, &t_attr, thread2, 0) == -1) {
perror("pthread_create(2)");
exit(EXIT_FAILURE);
}
// cast suppresses warning for g++
act.sa_handler = (void(*))sig_alarm_handler; // Handler for timer sig.
sigemptyset(&act.sa_mask); // Default signal receipt method.
act.sa_flags = 0; // Clear signal mask.
// Set the SIGALRM signal to execute sig_alarm_handler upon receipt of SIGALRM.
if (sigaction(SIGALRM, &act, (struct sigaction *) NULL)) {
perror("sigaction");
exit(EXIT_FAILURE);
}
alarm(TIME_LIMIT); // Set SIGALRM to trigger in TIME_LIMIT secs.
// Clear POSIX-compliant signal mask. All signals can
// interrupt. Note that this is slightly more complicated
// than our standard pause() call, but it illustrates the
// use of the POSIX signal mask which is actually 64
// bits long. (32 for signals and 32 for events).
sigemptyset(&set);
// Loop, waiting for signals to arrive. Program termination
// is accomplished through SIGALRM signal or through
// default action of terminating signals like SIGINT...
printf("Threads created, now loop waiting for signals\n");
for (;;) {
sigsuspend(&set);
if (got_alarm == 1){
return 0;
}
}
return 0;
}