--- crash-4.0-3.6/defs.h	2006-10-05 21:43:10.000000000 +0200
+++ crash-4.0-3.6-patch/defs.h	2006-10-09 10:42:17.000000000 +0200
@@ -838,6 +838,12 @@
 	int args;
 };
 
+#define HASH_TGID 64
+struct tgid_node {
+	struct tgid_node *next;
+	ulong tgid;
+};
+
 struct reference {       
         char *str;       
         ulong cmdflags;  
--- crash-4.0-3.6/task.c	2006-10-05 21:43:10.000000000 +0200
+++ crash-4.0-3.6-patch/task.c	2006-10-09 14:47:11.000000000 +0200
@@ -17,6 +17,10 @@
 
 #include "defs.h"
 
+#define TASK_LEVEL 1
+#define TASK_GROUP_LEVEL 2
+#define TASK_INDENT2 4
+
 static ulong get_panic_context(void);
 static int sort_by_pid(const void *, const void *);
 static void show_ps(ulong, struct psinfo *);
@@ -35,6 +39,7 @@
 static void show_task_times(struct task_context *, ulong);
 static void show_task_args(struct task_context *);
 static void show_tgid_list(ulong);
+static void show_tgid_sig_list(ulong);
 static int compare_start_time(const void *, const void *);
 static int start_time_timespec(void);
 static ulonglong convert_start_time(ulonglong, ulonglong);
@@ -51,7 +56,7 @@
 static void dump_prio_array(int, ulong, char *);
 static void task_struct_member(struct task_context *,ulong,struct reference *);
 static void signal_reference(struct task_context *, ulong, struct reference *);
-static void dump_signal_data(struct task_context *);
+static void dump_signal_data(struct task_context *, int);
 static int sigrt_minmax(int *, int *);
 static void signame_list(void);
 static void sigqueue_list(ulong);
@@ -60,6 +65,10 @@
 static void translate_sigset(ulonglong);
 static ulonglong sigaction_mask(ulong);
 static int task_has_cpu(ulong, char *);
+static struct tgid_node ** alloc_hash_tgid(void);
+static struct tgid_node * put_tgid(struct tgid_node **, ulong); 
+static void free_hash_tgid(struct tgid_node **);
+static void list_hash_tgid(struct tgid_node **);
 static int is_foreach_keyword(char *, int *);
 static char *task_pointer_string(struct task_context *, ulong, char *);
 static int panic_context_adjusted(struct task_context *tc);
@@ -2954,7 +2963,6 @@
 
 	fprintf(fp, "\n");
 }
-
 /*
  * Return the first task found that belongs to a pid. 
  */
@@ -4258,7 +4266,114 @@
 
 	foreach(fd);
 }
+/*
+ * Allocate a table of HASH_TGID hash lists.
+*/
+static  struct tgid_node **
+alloc_hash_tgid(void) 
+{
+	struct tgid_node **p;
+	p= (struct tgid_node**)calloc(sizeof(struct tgid_node*) , HASH_TGID);
+	if (!p)
+		error(FATAL,"cannot malloc hash_tgid\n");
+	/*
+	p= (struct tgid_node**)GETBUF(sizeof(struct tgid_node*) * HASH_TGID);
+	*/
+	return p;
+}
+/*
+ * If the tgid is already in a hash list (it has been used), NULL is returned ;
+ * otherwise, the new node address is returned.
+ */
+static struct tgid_node *
+put_tgid(struct tgid_node **hash_tgid, ulong tgid) 
+{
+	struct tgid_node *prev_node, *curr_node, *new_node;
+	ulong cell = (tgid % HASH_TGID);
+	if (CRASHDEBUG(1))
+		fprintf(fp, "cell %lu: ", cell);
+	for (prev_node=curr_node=*(hash_tgid + cell); 
+			curr_node; prev_node=curr_node, curr_node=curr_node->next) {
+		if(curr_node) {
+			if (CRASHDEBUG(1))
+				fprintf(fp,"%lu ", curr_node->tgid);
+			if (tgid > curr_node->tgid)
+				continue;
+			if (tgid == curr_node->tgid) {
+				fprintf(fp, "E\n");
+				return NULL;
+			}
+			break;
+		}
+		if (curr_node==prev_node && !curr_node->next) /* Just one node. */
+			break;
+	}
+	new_node = (struct tgid_node*)malloc(sizeof(struct tgid_node));
+	if (!new_node)
+		error(FATAL, "cannot malloc tgid_node\n");
+	/*
+	new_node = (struct tgid_node*)GETBUF(sizeof(struct tgid_node));
+	*/
+	if (CRASHDEBUG(1)) {
+		fprintf(fp,"%lu ", tgid); 
+		fprintf(fp,"N\n");
+	}
+	new_node->tgid = tgid;
+	new_node->next = NULL;
+	if (!prev_node || curr_node==prev_node) { /* First node or before first node. */
+		*(hash_tgid + cell)=new_node;
+		if(prev_node)
+			new_node->next = prev_node->next;
+	} else if (curr_node) { /* Midle node. */
+		prev_node->next = new_node;
+		new_node->next = curr_node->next;
+	} else  /* Last node. */
+		prev_node->next = new_node;
+	return new_node;
+}
+static void 
+free_hash_tgid(struct tgid_node **hash_tgid) 
+{
+	struct tgid_node **p, **p_end, *tn, *tn2;
+	p_end = hash_tgid+HASH_TGID;
+	for (p=hash_tgid; p < p_end; p++) {
+		if (CRASHDEBUG(1))
+			fprintf(fp,"cell %p: ",p);
+		tn=*p;
+		while(tn){
+			if (CRASHDEBUG(1))
+				fprintf(fp,"%lu ",tn->tgid);
+			tn2=tn->next;
+			free((void*)tn);
+			/*
+			FREEBUF((char*)tn);
+			*/
+			tn=tn2;
+		}
+		if (CRASHDEBUG(1))
+			fprintf(fp, "\n\n");
+	}
+	free((void *)hash_tgid);
+	/*
+	FREEBUF((char *)hash_tgid);		
+	*/
+}
 
+static void 
+list_hash_tgid(struct tgid_node **hash_tgid) 
+{
+	struct tgid_node **p, **p_end, *tn;
+	p_end = hash_tgid+HASH_TGID;
+	for (p=hash_tgid; p < p_end; p++) {
+		tn=*p;
+		fprintf(fp,"cell %p: ",tn);
+		while(tn){
+			fprintf(fp,"(%p %lu) ",tn->next,tn->tgid);
+			tn=tn->next;
+		}
+		fprintf(fp,"\n\n");
+	}
+}
 /*
  *  Do the work for cmd_foreach().
  */
@@ -4273,6 +4388,8 @@
 	ulong cmdflags; 
 	struct reference reference, *ref;
 	struct bt_info bt_info, *bt;
+	struct tgid_node **hash_tgid=NULL;
+	ulong tgid;
 
 	/* 
 	 *  Filter out any command/option issues.
@@ -4393,6 +4510,8 @@
 				error(FATAL, 
 			    	 "sig: -l and -s options are not applicable\n");
 			}
+			if (fd->flags & FOREACH_g_FLAG)
+				hash_tgid=alloc_hash_tgid();
                         break;
 
 		case FOREACH_TEST:
@@ -4453,7 +4572,7 @@
 		if (fd->reference) {
 			BZERO(ref, sizeof(struct reference));
 			ref->str = fd->reference;
-		} else
+		} else if (hash_tgid==NULL)
 			print_task_header(fp, tc, subsequent++);
 
 		for (k = 0; k < fd->keys; k++) {
@@ -4527,8 +4646,14 @@
 
                         case FOREACH_SIG:
 				pc->curcmd = "sig";
+                                if (fd->flags & FOREACH_g_FLAG) { 
+                                        tgid = task_tgid(tc->task); 
+					if (put_tgid(hash_tgid,tgid))
+						show_tgid_sig_list(tc->task);
+                                } else { 
                                 do_sig(tc->task, FOREACH_SIG,
                                         fd->reference ? ref : NULL);
+                                }
                                 break;
 
 			case FOREACH_SET:
@@ -4578,7 +4703,6 @@
 			pc->curcmd = "foreach";
 		} 
 	}
-
 	/*
 	 *  Post-process any commands requiring it.
 	 */
@@ -4592,6 +4716,14 @@
 				nlm_files_dump();
 			}
 			break;
+		case FOREACH_SIG:
+			if (CRASHDEBUG(1))
+				list_hash_tgid(hash_tgid);
+			if (fd->flags & FOREACH_g_FLAG) {
+				pc->curcmd = "sig";
+				free_hash_tgid(hash_tgid);
+			}
+			break;
 		}
 	}
 
@@ -5936,13 +6068,14 @@
 	struct task_context *tc;
 	ulong *tasklist;
 	char *siglist;
+	int task_group=FALSE;
 
 	tasklist = (ulong *)GETBUF((MAXARGS+NR_CPUS)*sizeof(ulong));
 	ref = (struct reference *)GETBUF(sizeof(struct reference));
 	siglist = GETBUF(BUFSIZE);
 	ref->str = siglist;
 
-        while ((c = getopt(argcnt, args, "lR:s:")) != EOF) {
+        while ((c = getopt(argcnt, args, "lR:s:g")) != EOF) {
                 switch(c)
 		{
 		case 's':
@@ -5959,7 +6092,10 @@
 		case 'l':
 			signame_list();
 			return;
-
+		case 'g':
+			pc->curcmd_flags |= TASK_SPECIFIED;
+			task_group=TRUE;
+			break;
 		default:
 			argerrs++;
 			break;
@@ -6006,10 +6142,64 @@
 		tasklist[tcnt++] = CURRENT_TASK();
 
 	for (c = 0; c < tcnt; c++) {
+		if(task_group)
+			show_tgid_sig_list(tasklist[c]);
+		else {
 		do_sig(tasklist[c], 0, strlen(ref->str) ? ref : NULL);
 		fprintf(fp, "\n");
 	}
+	}
+
+}
+static void
+show_tgid_sig_list(ulong task)
+{
+        int i;
+        int cnt;
+        struct task_context *tc;
+	ulong tgid;
+
+        tc = task_to_context(task);
+	tgid = task_tgid(task);
+
+	if (tc->pid != tgid) {
+		if (pc->curcmd_flags & TASK_SPECIFIED) {
+			if (!(tc = tgid_to_context(tgid))) 
+				return;
+			task = tc->task;
+		} else 
+			return;
+	}
+
+	if ((tc->pid == 0) && (pc->curcmd_flags & IDLE_TASK_SHOWN))
+		return;
+
+       	print_task_header(fp, tc, 0);
+	dump_signal_data(tc,TASK_GROUP_LEVEL);
+	fprintf(fp, "\n");
+	INDENT(2);
+	print_task_header(fp, tc, 0);
+	dump_signal_data(tc,TASK_LEVEL|TASK_INDENT2);
+
+	tc = FIRST_CONTEXT();
+        for (i = cnt = 0; i < RUNNING_TASKS(); i++, tc++) {
+		if (tc->task == task)
+			continue;
+
+		if (task_tgid(tc->task)	== tgid) {
+			fprintf(fp, "\n");
+                        INDENT(2);
+                        print_task_header(fp, tc, 0);
+			dump_signal_data(tc,TASK_LEVEL|TASK_INDENT2);
+                        cnt++;
+			if (tc->pid == 0)
+				pc->curcmd_flags |= IDLE_TASK_SHOWN;
+                }
+        }
 
+        if (!cnt)
+                fprintf(fp, "  (no threads)\n");
+	fprintf(fp, "\n");
 }
 
 /*
@@ -6027,7 +6217,7 @@
         else {
                 if (!(flags & FOREACH_TASK))
                         print_task_header(fp, tc, 0);
-                dump_signal_data(tc);
+                dump_signal_data(tc,TASK_LEVEL|TASK_GROUP_LEVEL);
         }
 }
 
@@ -6047,7 +6237,7 @@
  *  Dump all signal-handling data for a task.
  */
 static void
-dump_signal_data(struct task_context *tc)
+dump_signal_data(struct task_context *tc, int task_flags)
 {
 	int i, sigrtmax, others, use_sighand;
 	int translate, sigpending;
@@ -6074,16 +6264,6 @@
 	sigset = task_signal(tc->task, 0);
 	if (!tt->last_task_read)
 		return;
-	blocked = task_blocked(tc->task);
-
-	if (VALID_MEMBER(task_struct_sigpending))
-		sigpending = INT(tt->task_struct + 
-			OFFSET(task_struct_sigpending));
-	else if (VALID_MEMBER(thread_info_flags)) {
-		fill_thread_info(tc->thread_info);
-		ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags));
-		sigpending = ti_flags & (1<<TIF_SIGPENDING);
-	}
 	
 
 	if (VALID_MEMBER(task_struct_sig))
@@ -6093,8 +6273,6 @@
 		signal_struct = ULONG(tt->task_struct + 
 			OFFSET(task_struct_signal));
 
-	fprintf(fp, "SIGNAL_STRUCT: %lx  ", signal_struct);
-
 	size = MAX(SIZE(signal_struct), VALID_SIZE(signal_queue) ?  
 		SIZE(signal_queue) : SIZE(sigqueue));
 	if (VALID_SIZE(sighand_struct))
@@ -6104,9 +6282,19 @@
 	readmem(signal_struct, KVADDR, signal_buf,
 		SIZE(signal_struct), "signal_struct buffer",
 		FAULT_ON_ERROR);
+
+	/*
+	 *  Signal dispositions (task group level).
+	 */
+	if(task_flags & TASK_GROUP_LEVEL) {
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
+		fprintf(fp, "SIGNAL_STRUCT: %lx  ", signal_struct);
 	fprintf(fp, "COUNT: %d\n",
 		INT(signal_buf + OFFSET(signal_struct_count)));
 
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	fprintf(fp, " SIG %s %s %s %s\n",
 		mkstring(buf1, VADDR_PRLEN == 8 ? 9 : VADDR_PRLEN, 
 			CENTER, "SIGACTION"),
@@ -6127,6 +6315,8 @@
 	sigrtmax = sigrt_minmax(NULL, NULL);
 
         for (i = 1; i <= sigrtmax; i++) {
+			if (task_flags & TASK_INDENT2)
+				INDENT(2);
                 fprintf(fp, "%s[%d] ", i < 10 ? " " : "", i);
 
 		if (use_sighand) {
@@ -6213,11 +6403,43 @@
 
                 fprintf(fp, "\n");
         }
+	}
+	
+	if(task_flags & TASK_LEVEL) {
+		/*
+	 	* Pending signals (task level).
+		*/
+		if (VALID_MEMBER(task_struct_sigpending))
+			sigpending = INT(tt->task_struct + 
+				OFFSET(task_struct_sigpending));
+		else if (VALID_MEMBER(thread_info_flags)) {
+			fill_thread_info(tc->thread_info);
+			ti_flags = UINT(tt->thread_info + OFFSET(thread_info_flags));
+			sigpending = ti_flags & (1<<TIF_SIGPENDING);
+		}
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	fprintf(fp, "SIGPENDING: %s\n", sigpending ? "yes" : "no");
+
+		/*
+	 	*  Blocked signals (task level).
+	 	*/
+
+		blocked = task_blocked(tc->task);
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	fprintf(fp, "   BLOCKED: %016llx\n", blocked);
 		
+		/*
+	 	*  Pending queue (task level).
+	 	*/
+	
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	if (VALID_MEMBER(signal_struct_shared_pending) )
 		fprintf(fp, "PRIVATE_PENDING\n");
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	fprintf(fp, "    SIGNAL: %016llx\n", sigset);
 
 	if (VALID_MEMBER(task_struct_sigqueue)) 
@@ -6232,13 +6454,20 @@
 	if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue))
 		sigqueue = 0;
 
+		if (task_flags & TASK_INDENT2)
+			INDENT(2);
 	if (sigqueue) {
                 fprintf(fp, "  SIGQUEUE:  SIG  %s\n",
                         mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO"));
 		 sigqueue_list(sigqueue);
 	} else
                 fprintf(fp, "  SIGQUEUE: (empty)\n");
+	}
 
+	/*
+	 *  Pending queue (task group level).
+	 */
+	if (task_flags & TASK_GROUP_LEVEL) {
 	if (VALID_MEMBER(signal_struct_shared_pending) ) {
 		ulong shared_pending, signal;
 		fprintf(fp, "SHARED_PENDING\n");
@@ -6247,6 +6476,8 @@
 		readmem(signal, KVADDR, signal_buf,SIZE(sigpending_signal),
 			"signal", FAULT_ON_ERROR);
 		sigset = task_signal(0, (ulong*)signal_buf);
+			if (task_flags & TASK_INDENT2)
+				INDENT(2);
 		fprintf(fp, "    SIGNAL: %016llx\n", sigset);
                 sigqueue = (shared_pending + 
 			OFFSET_OPTION(sigpending_head, sigpending_list) + 
@@ -6257,6 +6488,8 @@
 
 		if (VALID_MEMBER(sigqueue_list) && empty_list(sigqueue))
 			sigqueue = 0;
+			if (task_flags & TASK_INDENT2)
+				INDENT(2);
 		if (sigqueue) {
                		fprintf(fp, "  SIGQUEUE:  SIG  %s\n",
                        		mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SIGINFO"));
@@ -6264,6 +6497,7 @@
 		} else
                		fprintf(fp, "  SIGQUEUE: (empty)\n");
 	}
+	}
 	FREEBUF(signal_buf);
 }
 
--- crash-4.0-3.6/help.c	2006-10-05 21:43:10.000000000 +0200
+++ crash-4.0-3.6-patch/help.c	2006-10-08 20:21:49.000000000 +0200
@@ -521,7 +521,7 @@
 "          files  run the \"files\" command  (optional flag: -R)",
 "            net  run the \"net\" command  (optional flags: -s -S -R)",
 "            set  run the \"set\" command",
-"            sig  run the \"sig\" command",
+"            sig  run the \"sig\" command (optional flag: -g)",
 "           vtop  run the \"vtop\" command  (optional flags: -c -u -k)\n",
 "     flag  Pass this optional flag to the command selected.",
 " argument  Pass this argument to the command selected.",
@@ -2845,7 +2845,7 @@
 char *help_sig[] = {
 "sig",
 "task signal handling",
-"[[-l] | [-s sigset]] | [pid | taskp] ...",
+"[[-l] | [-s sigset]] | [-g] [pid | taskp] ...",
 "  This command displays signal-handling data of one or more tasks.  Multiple",
 "  task or PID numbers may be entered; if no arguments are entered, the signal",
 "  handling data of the current context will be displayed.  The default display",
@@ -2868,6 +2868,7 @@
 " ",        
 "        pid  a process PID.",
 "      taskp  a hexadecimal task_struct pointer.",
+"         -g  displays signal informations for all tasks of task's task group",
 "         -l  displays the defined signal numbers and names.",
 "  -s sigset  translates a 64-bit hexadecimal value representing a sigset_t",
 "             into a list of signal names associated with the bits set.",
@@ -2915,6 +2916,50 @@
 "                 64  f51b9d18",
 "                 64  f51b9500",
 "    ",
+"  Dump the signal-handling data for all tasks of task's task group PID 2578:\n",
+"    %s> sig -g 2578",
+"    PID: 2387   TASK: f617d020  CPU: 0   COMMAND: \"slapd\"",
+"    SIGNAL_STRUCT: f7dede00  COUNT: 6",
+"    SIG SIGACTION  HANDLER       MASK       FLAGS",
+"    [1]  c1f60c04   a258a7 0000000000000000 10000000 (SA_RESTART)",
+"    [2]  c1f60c18   a258a7 0000000000000000 10000000 (SA_RESTART)",
+"    [3]  c1f60c2c  SIG_DFL 0000000000000000 0",
+"    [4]  c1f60c40  SIG_DFL 0000000000000000 0",
+"    [5]  c1f60c54   a258a7 0000000000000000 10000000 (SA_RESTART)",
+"    [6]  c1f60c68  SIG_DFL 0000000000000000 0",
+"    [7]  c1f60c7c  SIG_DFL 0000000000000000 0",
+"    [8]  c1f60c90  SIG_DFL 0000000000000000 0",
+"    [9]  c1f60ca4  SIG_DFL 0000000000000000 0",
+"   [10]  c1f60cb8   a25911 0000000000000000 10000000 (SA_RESTART)",
+"   ...",
+"   [64]  c1f610f0  SIG_DFL 0000000000000000 0",
+"   SHARED_PENDING",
+"       SIGNAL: 0000000000000000",
+"     SIGQUEUE: (empty)",
+"     ",
+"     PID: 2387   TASK: f617d020  CPU: 0   COMMAND: \"slapd\"",
+"     SIGPENDING: no",
+"        BLOCKED: 0000000000000000",
+"     PRIVATE_PENDING",
+"         SIGNAL: 0000000000000000",
+"       SIGQUEUE: (empty)",
+"    ",
+"     PID: 2392   TASK: f6175aa0  CPU: 0   COMMAND: \"slapd\"",
+"     SIGPENDING: no",
+"        BLOCKED: 0000000000000000",
+"     PRIVATE_PENDING",
+"         SIGNAL: 0000000000000000",
+"       SIGQUEUE: (empty)",
+"    ",
+"     PID: 2523   TASK: f7cd4aa0  CPU: 1   COMMAND: \"slapd\"",
+"     SIGPENDING: no",
+"        BLOCKED: 0000000000000000",
+"     PRIVATE_PENDING",
+"         SIGNAL: 0000000000000000",
+"       SIGQUEUE: (empty)",
+"    ",
+"     ...",
+"    ",
 "  Translate the sigset_t mask value, cut-and-pasted from the signal handling",
 "  data from signals 1 and 10 above:",
 " ",
