--- crash-5.0.9/help.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/help.c	2010-11-11 16:46:40.000000000 -0500
@@ -1479,11 +1479,11 @@ char *help_bt[] = {
 "          START: schedule at c01190e0",
 "      [c1aa1f28] dput at c0157dbc",
 "      [c1aa1f4c] schedule_timeout at c0124cd4",
-"      [c1aa1f78] svc_recv at cb22c4d8",
+"      [c1aa1f78] svc_recv at cb22c4d8 [sunrpc]",
 "      [c1aa1f98] put_files_struct at c011eb21",
-"      [c1aa1fcc] nlmclnt_proc at cb237bef",
+"      [c1aa1fcc] nlmclnt_proc at cb237bef [lockd]",
 "      [c1aa1ff0] kernel_thread at c0105826",
-"      [c1aa1ff8] nlmclnt_proc at cb237a60",
+"      [c1aa1ff8] nlmclnt_proc at cb237a60 [lockd]",
 " ",
 "  Search the current stack for possible exception frames:\n",
 "    %s> bt -e",
@@ -1529,7 +1529,7 @@ char *help_bt[] = {
 "       EAX: 00000013  EBX: cb297000  ECX: 00000000  EDX: c5962000  EBP: c74dff28",
 "       DS:  0018      ESI: 00000000  ES:  0018      EDI: 00000000",
 "       CS:  0010      EIP: cb297076  ERR: ffffffff  EFLAGS: 00010282",
-"    #3 [c74dff1c] crash_init at cb297076",
+"    #3 [c74dff1c] crash_init at cb297076 [crash]",
 "    #4 [c74dff2c] sys_init_module at c011d233",
 "    #5 [c74dffc0] system_call at c0107154",
 "       EAX: 00000080  EBX: 08060528  ECX: 08076450  EDX: 0000000a",
@@ -4671,6 +4671,10 @@ char *help_sym[] = {
 "       -q string  searches for all symbols containing \"string\".",
 "          symbol  a kernel text or data symbol.",
 "           vaddr  a kernel virtual address.",
+" ",
+"  If the \"symbol\", \"vaddr\" or \"string\" argument resolves to a module",
+"  symbol, then the module name will be displayed in brackets following the",
+"  symbol value.",
 "\nEXAMPLES",
 "  Translate data symbol jiffies to its value, and vice-versa:\n",
 "    %s> sym jiffies",
@@ -4781,6 +4785,10 @@ char *help_sym[] = {
 "    c023027c (D) prof_shift",  
 "    c0230280 (D) jiffies ", 
 "    c02302a0 (D) task",
+"\n  Translate a symbol value to its name and module:\n",
+"    crash> sym f88878d1",
+"    f88878d1 (t) ext3_readdir [ext3]",  
+"    crash>",
 NULL               
 };
 
--- crash-5.0.9/kernel.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/kernel.c	2010-11-11 16:46:43.000000000 -0500
@@ -2083,6 +2083,7 @@ print_stack_text_syms(struct bt_info *bt
 	ulong next_sp, next_pc;
 	int i;
 	ulong *up;
+	struct load_module *lm;
 	char buf[BUFSIZE];
 
 	if (bt->flags & BT_TEXT_SYMBOLS) {
@@ -2107,8 +2108,8 @@ print_stack_text_syms(struct bt_info *bt
 		}
 		if (is_kernel_text(*up) && (bt->flags & 
 		    (BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT))) { 
-			if (bt->flags & (BT_ERROR_MASK|BT_TEXT_SYMBOLS))
-                               	fprintf(fp, "  %s[%s] %s at %lx\n",
+			if (bt->flags & (BT_ERROR_MASK|BT_TEXT_SYMBOLS)) {
+                               	fprintf(fp, "  %s[%s] %s at %lx",
 					bt->flags & BT_ERROR_MASK ?
 					"  " : "",
 					mkstring(buf, VADDR_PRLEN, 
@@ -2116,7 +2117,10 @@ print_stack_text_syms(struct bt_info *bt
                                		MKSTR(bt->stackbase + 
 					(i * sizeof(long)))),
 					closest_symbol(*up), *up);
-			else
+				if (module_symbol(*up, NULL, &lm, NULL, 0))
+					fprintf(fp, " [%s]", lm->mod_name);
+				fprintf(fp, "\n");
+			} else
                                	fprintf(fp, "%lx: %s\n",
                                        	bt->stackbase + 
 					(i * sizeof(long)),
@@ -2694,6 +2698,7 @@ module_init(void)
 		MEMBER_OFFSET_INIT(module_init_size, "module", "init_size");
 		MEMBER_OFFSET_INIT(module_init_text_size, "module", 
 			"init_text_size");
+		MEMBER_OFFSET_INIT(module_percpu, "module", "percpu");
 
 		/*
 		 *  Make sure to pick the kernel "modules" list_head symbol,
--- crash-5.0.9/alpha.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/alpha.c	2010-11-08 09:52:07.000000000 -0500
@@ -1,8 +1,8 @@
 /* alpha.c - core analysis suite
  *
  * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
- * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson
- * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2010 David Anderson
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2010 Red Hat, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -589,6 +589,8 @@ alpha_print_stack_entry(struct gnu_reque
 			ulong flags,
 			struct bt_info *bt)
 {
+	struct load_module *lm;
+
 	if (BT_REFERENCE_CHECK(bt)) {
                 switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
                 {
@@ -606,10 +608,13 @@ alpha_print_stack_entry(struct gnu_reque
 			break;
 		}
 	} else {
-		fprintf(fp, "%s#%d [%lx] %s at %lx\n",
+		fprintf(fp, "%s#%d [%lx] %s at %lx",
         		req->curframe < 10 ? " " : "", req->curframe, req->sp,
 			STREQ(name, "strace") ?  "strace (via entSys)" : name, 
 			callpc);
+		if (module_symbol(callpc, NULL, &lm, NULL, 0))
+			fprintf(fp, " [%s]", lm->mod_name);
+		fprintf(fp, "\n");
 	}
 
 	if (!(flags & BT_SPECULATE))
--- crash-5.0.9/ppc.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/ppc.c	2010-11-08 09:52:46.000000000 -0500
@@ -1,8 +1,8 @@
 /* ppc.c - core analysis suite
  *
  * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
- * Copyright (C) 2002, 2003, 2004, 2005 David Anderson
- * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2002, 2003, 2004, 2005, 2010 David Anderson
+ * Copyright (C) 2002, 2003, 2004, 2005, 2010 Red Hat, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -843,6 +843,8 @@ ppc_print_stack_entry(int frame, 
 		      char *name, 
 		      struct bt_info *bt)
 {
+	struct load_module *lm;
+
 	if (BT_REFERENCE_CHECK(bt)) {
                 switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
                 {
@@ -857,9 +859,12 @@ ppc_print_stack_entry(int frame, 
                         break;
                 }
 	} else {
-		fprintf(fp, "%s#%d [%lx] %s at %lx\n",
+		fprintf(fp, "%s#%d [%lx] %s at %lx",
         		frame < 10 ? " " : "", frame,
                 	req->sp, name, callpc);
+		if (module_symbol(callpc, NULL, &lm, NULL, 0))
+			fprintf(fp, " [%s]", lm->mod_name);
+                fprintf(fp, "\n");
 	}
 
 	if (bt->flags & BT_SAVE_LASTSP)
--- crash-5.0.9/s390.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/s390.c	2010-11-05 16:25:36.000000000 -0400
@@ -663,6 +663,7 @@ s390_back_trace_cmd(struct bt_info *bt)
 	backchain = ksp;
 	do {
 		unsigned long r14_stack_off;
+		struct load_module *lm;
 		int j;
 
 		/* Find stack: Either async, panic stack or task stack */
@@ -697,7 +698,10 @@ s390_back_trace_cmd(struct bt_info *bt)
 			skip_first_frame=0;
 		} else {
 			fprintf(fp," #%i [%08lx] ",i,backchain);
-			fprintf(fp,"%s at %x\n", closest_symbol(r14), r14);
+			fprintf(fp,"%s at %x", closest_symbol(r14), r14);
+			if (module_symbol(r14, NULL, &lm, NULL, 0))
+				fprintf(fp, " [%s]", lm->mod_name);
+			fprintf(fp, "\n");
 			if (bt->flags & BT_LINE_NUMBERS)
 				s390_dump_line_number(r14);
 			i++;
--- crash-5.0.9/s390x.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/s390x.c	2010-11-05 16:48:56.000000000 -0400
@@ -896,6 +896,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
 	backchain = ksp; 
 	do {
 		unsigned long r14_stack_off;
+		struct load_module *lm;
 		int j;
 
 		/* Find stack: Either async, panic stack or task stack */
@@ -930,7 +931,10 @@ s390x_back_trace_cmd(struct bt_info *bt)
 			skip_first_frame=0;
 		} else {
 			fprintf(fp," #%i [%08lx] ",i,backchain);
-			fprintf(fp,"%s at %lx\n", closest_symbol(r14), r14);
+			fprintf(fp,"%s at %lx", closest_symbol(r14), r14);
+			if (module_symbol(r14, NULL, &lm, NULL, 0))
+				fprintf(fp, " [%s]", lm->mod_name);
+			fprintf(fp, "\n");
 			if (bt->flags & BT_LINE_NUMBERS)
 				s390x_dump_line_number(r14);
 			i++;
--- crash-5.0.9/ppc64.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/ppc64.c	2010-11-05 16:36:08.000000000 -0400
@@ -1561,6 +1561,7 @@ ppc64_print_stack_entry(int frame, 
 		      ulong lr, 	
 		      struct bt_info *bt)
 {
+	struct load_module *lm;
 	char *lrname = NULL;
 	if (BT_REFERENCE_CHECK(bt)) {
 		switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
@@ -1579,6 +1580,8 @@ ppc64_print_stack_entry(int frame, 
 		fprintf(fp, "%s#%d [%lx] %s at %lx",
 			frame < 10 ? " " : "", frame,
 			req->sp, req->name, req->pc);
+		if (module_symbol(req->pc, NULL, &lm, NULL, 0))
+			fprintf(fp, " [%s]", lm->mod_name);
 	
 		if (req->ra) {
 			/*
--- crash-5.0.9/x86_64.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/x86_64.c	2010-11-05 16:53:47.000000000 -0400
@@ -2407,6 +2407,7 @@ x86_64_print_stack_entry(struct bt_info 
 	int i, result; 
 	long eframe_check;
 	char buf[BUFSIZE];
+	struct load_module *lm;
 
 	eframe_check = -1;
 	if (!(bt->flags & BT_SAVE_EFRAME_IP))
@@ -2423,9 +2424,12 @@ x86_64_print_stack_entry(struct bt_info 
 			rsp = bt->stkptr;
 		else
 			rsp = bt->stackbase + (stkindex * sizeof(long));
-                fprintf(ofp, "  [%s] %s at %lx\n",
+                fprintf(ofp, "  [%s] %s at %lx",
                 	mkstring(buf, VADDR_PRLEN, RJUST|LONG_HEX, MKSTR(rsp)),
                         name, text);
+		if (module_symbol(text, NULL, &lm, NULL, 0))
+			fprintf(ofp, " [%s]", lm->mod_name);
+		fprintf(ofp, "\n");
 		if (BT_REFERENCE_CHECK(bt))
 			x86_64_do_bt_reference_check(bt, text, name);
 		return BACKTRACE_ENTRY_DISPLAYED;
@@ -2501,6 +2505,8 @@ x86_64_print_stack_entry(struct bt_info 
 		    (spl = value_search(locking_func, &offset)))
 			fprintf(ofp, " (via %s)", spl->name);
 	}
+	if (module_symbol(text, NULL, &lm, NULL, 0))
+		fprintf(ofp, " [%s]", lm->mod_name);
 
 	if (bt->flags & BT_FRAMESIZE_DISABLE)
 		fprintf(ofp, " *");
--- crash-5.0.9/symbols.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/symbols.c	2010-11-11 17:33:10.000000000 -0500
@@ -71,7 +71,9 @@ static void Elf32_Sym_to_common(Elf32_Sy
 static void Elf64_Sym_to_common(Elf64_Sym *, struct elf_common *); 
 static void cmd_datatype_common(ulong);
 static int display_per_cpu_info(struct syment *);
-
+static struct load_module *get_module_percpu_sym_owner(struct syment *);
+static int is_percpu_symbol(struct syment *);
+static void dump_percpu_symbols(struct load_module *);
 
 #define KERNEL_SECTIONS  (void *)(1)
 #define MODULE_SECTIONS  (void *)(2) 
@@ -896,11 +898,14 @@ symname_hash_search(char *name)
 static void
 symbol_dump(ulong flags, char *module)
 {
-	int i;
+	int i, start, percpu_syms;
         struct syment *sp, *sp_end;
 	struct load_module *lm;
 	char *p1, *p2;;
 
+#define TBD  1
+#define DISPLAYED 2
+
 	if (flags & KERNEL_SYMS) {
         	for (sp = st->symtable; sp < st->symend; sp++) 
 			show_symbol(sp, 0, SHOW_RADIX());
@@ -917,17 +922,41 @@ symbol_dump(ulong flags, char *module)
 
 		sp = lm->mod_symtable;
 		sp_end = lm->mod_symend;
+		percpu_syms = 0;
+
+                for (start = FALSE; sp <= sp_end; sp++) {
+
+			if (IN_MODULE_PERCPU(sp->value, lm)) {
+				if (percpu_syms == DISPLAYED)
+					continue;
+				if (!start) {
+					percpu_syms = TBD;
+					continue;
+				}
+				dump_percpu_symbols(lm);
+				percpu_syms = DISPLAYED;
+			}
 
-                for ( ; sp <= sp_end; sp++) {
 			if (MODULE_PSEUDO_SYMBOL(sp)) {
 				if (MODULE_START(sp)) {
 					p1 = "MODULE START";
 					p2 = sp->name+strlen("_MODULE_START_");
+					start = TRUE;
 				} else {
 					p1 = "MODULE END";
 					p2 = sp->name+strlen("_MODULE_END_");
+					if (MODULE_PERCPU_SYMS_LOADED(lm) &&
+					    !percpu_syms) {
+						dump_percpu_symbols(lm);
+						percpu_syms = DISPLAYED;
+					}
 				}
 				fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2);
+
+				if (percpu_syms == TBD) {
+					dump_percpu_symbols(lm);
+					percpu_syms = DISPLAYED;
+				}
 			} else
 				show_symbol(sp, 0, SHOW_RADIX());
                 }
@@ -950,7 +979,23 @@ symbol_dump(ulong flags, char *module)
 					show_symbol(sp, 0, SHOW_RADIX());
 			}
 		}
+	}
+#undef TBD
+#undef DISPLAYED
+}
+
+static void
+dump_percpu_symbols(struct load_module *lm)
+{
+	struct syment *sp, *sp_end;
 
+	if (MODULE_PERCPU_SYMS_LOADED(lm)) {
+		sp = lm->mod_symtable;
+		sp_end = lm->mod_symend;
+		for ( ; sp <= sp_end; sp++) {
+			if (IN_MODULE_PERCPU(sp->value, lm))
+				show_symbol(sp, 0, SHOW_RADIX());
+		}
 	}
 }
 
@@ -1092,6 +1137,7 @@ store_module_symbols_v1(ulong total, int
 
 		st->ext_module_symtable[mcnt].value = mod;
 		st->ext_module_symtable[mcnt].type = 'm';
+		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 		sprintf(buf2, "%s%s", "_MODULE_START_", name);
 		namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace,
 			&st->ext_module_symtable[mcnt], buf2);
@@ -1153,6 +1199,7 @@ store_module_symbols_v1(ulong total, int
 				st->ext_module_symtable[mcnt].value = 
 					modsym->value;
 				st->ext_module_symtable[mcnt].type = '?'; 
+				st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 				strip_module_symbol_end(buf1);
                 		namespace_ctl(NAMESPACE_INSTALL, 
 				    &st->ext_module_namespace,
@@ -1194,6 +1241,7 @@ store_module_symbols_v1(ulong total, int
 
 		st->ext_module_symtable[mcnt].value = mod + size;
 		st->ext_module_symtable[mcnt].type = 'm';
+		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 		sprintf(buf2, "%s%s", "_MODULE_END_", name);
                 namespace_ctl(NAMESPACE_INSTALL, 
 			&st->ext_module_namespace,
@@ -1349,6 +1397,7 @@ store_module_symbols_v2(ulong total, int
 		lm->mod_ext_symcnt = mcnt;
 		lm->mod_init_module_ptr = ULONG(modbuf + 
 			OFFSET(module_module_init));
+		lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu));
 		if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
 			lm->mod_etext_guess = lm->mod_base +
 				UINT(modbuf + OFFSET(module_core_text_size));
@@ -1368,6 +1417,7 @@ store_module_symbols_v2(ulong total, int
 
 		st->ext_module_symtable[mcnt].value = lm->mod_base;
 		st->ext_module_symtable[mcnt].type = 'm';
+		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 		sprintf(buf2, "%s%s", "_MODULE_START_", mod_name);
 		namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace,
 			&st->ext_module_symtable[mcnt], buf2);
@@ -1377,6 +1427,7 @@ store_module_symbols_v2(ulong total, int
 		if (lm->mod_init_size > 0) {
 			st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr;
 			st->ext_module_symtable[mcnt].type = 'm';
+			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 			sprintf(buf3, "%s%s", "_MODULE_INIT_START_", mod_name);
 			namespace_ctl(NAMESPACE_INSTALL, 
 					&st->ext_module_namespace,
@@ -1450,6 +1501,7 @@ store_module_symbols_v2(ulong total, int
 				st->ext_module_symtable[mcnt].value = 
 					modsym->value;
 				st->ext_module_symtable[mcnt].type = '?'; 
+				st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 				strip_module_symbol_end(buf1);
                 		namespace_ctl(NAMESPACE_INSTALL, 
 				    &st->ext_module_namespace,
@@ -1523,6 +1575,7 @@ store_module_symbols_v2(ulong total, int
 				st->ext_module_symtable[mcnt].value = 
 					modsym->value;
 				st->ext_module_symtable[mcnt].type = '?'; 
+				st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 				strip_module_symbol_end(buf1);
                 		namespace_ctl(NAMESPACE_INSTALL, 
 				    &st->ext_module_namespace,
@@ -1557,6 +1610,7 @@ store_module_symbols_v2(ulong total, int
 
 		st->ext_module_symtable[mcnt].value = lm->mod_base + size;
 		st->ext_module_symtable[mcnt].type = 'm';
+		st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 		sprintf(buf2, "%s%s", "_MODULE_END_", mod_name);
                 namespace_ctl(NAMESPACE_INSTALL, 
 			&st->ext_module_namespace,
@@ -1566,6 +1620,7 @@ store_module_symbols_v2(ulong total, int
 		if (lm->mod_init_size > 0) {
 			st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr + lm->mod_init_size;
 			st->ext_module_symtable[mcnt].type = 'm';
+			st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL;
 			sprintf(buf4, "%s%s", "_MODULE_INIT_END_", mod_name);
 			namespace_ctl(NAMESPACE_INSTALL, 
 					&st->ext_module_namespace,
@@ -1624,6 +1679,10 @@ store_module_symbols_v2(ulong total, int
 
         if (symbol_query("__insmod_", NULL, NULL))
                 st->flags |= INSMOD_BUILTIN;
+
+	if (mcnt > total)
+		error(FATAL, "store_module_symbols_v2: total: %ld mcnt: %d\n", 
+			total, mcnt);
 }
 
 /*
@@ -1756,6 +1815,7 @@ store_module_kallsyms_v1(struct load_mod
 
                        	st->ext_module_symtable[mcnt_idx].value = symbol_addr;
                        	st->ext_module_symtable[mcnt_idx].type = type;
+                       	st->ext_module_symtable[mcnt_idx].flags |= MODULE_SYMBOL;
                         namespace_ctl(NAMESPACE_INSTALL,
                                 &st->ext_module_namespace,
                                 &st->ext_module_symtable[mcnt_idx++], nameptr);
@@ -1945,6 +2005,7 @@ store_module_kallsyms_v2(struct load_mod
 
                 st->ext_module_symtable[mcnt_idx].value = ec->st_value;
                 st->ext_module_symtable[mcnt_idx].type = ec->st_info;
+                st->ext_module_symtable[mcnt_idx].flags |= MODULE_SYMBOL;
                 namespace_ctl(NAMESPACE_INSTALL,
                 	&st->ext_module_namespace,
                         &st->ext_module_symtable[mcnt_idx++], nameptr);
@@ -2632,6 +2693,26 @@ dump_symbol_table(void)
 			lm->mod_init_text_size);
 		fprintf(fp, "   mod_init_module_ptr: %lx\n",
 			lm->mod_init_module_ptr);
+		if (lm->mod_percpu_size) {
+			fprintf(fp, "       mod_percpu_size: %lx\n", 
+				lm->mod_percpu_size);
+			fprintf(fp, "            mod_percpu: %lx - %lx\n", 
+				lm->mod_percpu, 
+				lm->mod_percpu + lm->mod_percpu_size);
+		} else {
+			if (lm->mod_percpu) {
+				fprintf(fp, 
+				    "       mod_percpu_size: (not loaded)\n");
+				fprintf(fp, 
+				    "            mod_percpu: %lx - (unknown)\n",
+					lm->mod_percpu);
+			} else {
+				fprintf(fp, 
+				    "       mod_percpu_size: (not used)\n");
+				fprintf(fp, 
+				    "            mod_percpu: (not used)\n");
+			}
+		}
 
 		fprintf(fp, "          mod_sections: %d\n", lm->mod_sections);
 		fprintf(fp, "      mod_section_data: %lx %s\n",
@@ -3140,6 +3221,7 @@ cmd_sym(void)
 			name = NULL;
 			multiples = 0;
 			sp = NULL;
+			show_flags &= ~SHOW_MODULE;
 
 			if (hexadecimal(args[optind], 0)) {
 				errflag = 0;
@@ -3150,6 +3232,9 @@ cmd_sym(void)
 						args[optind]);
 				} else if ((sp = value_search(value, &offset))){
 					name = sp->name;
+					if (module_symbol(sp->value, NULL, NULL,
+					    NULL, 0))
+						show_flags |= SHOW_MODULE;
 					if (prev && 
 					    (spp = prev_symbol(NULL, sp))) 
 						show_symbol(spp, 0, show_flags);
@@ -3173,6 +3258,9 @@ cmd_sym(void)
 				if ((sp = symbol_search(args[optind]))) {
 					multiples = symbol_name_count(sp->name);
 do_multiples:
+					if (module_symbol(sp->value, NULL, NULL,
+					    NULL, 0))
+						show_flags |= SHOW_MODULE;
 					name = sp->name;
 					if (prev && 
 					    (spp = prev_symbol(NULL, sp)))
@@ -3214,6 +3302,9 @@ show_symbol(struct syment *sp, ulong off
 	char buf[BUFSIZE];
 	char *p1;
 	ulong radix;
+	struct load_module *lm;
+
+	lm = NULL;
 
 	switch (show_flags & (SHOW_HEX_OFFS|SHOW_DEC_OFFS))
 	{
@@ -3227,7 +3318,6 @@ show_symbol(struct syment *sp, ulong off
 		break;
 	}
 
-
 	if (MODULE_START(sp)) {
 		p1 = sp->name + strlen("_MODULE_START_");
 		fprintf(fp, "%lx (%c) (%s module)", sp->value, sp->type, p1);
@@ -3236,24 +3326,27 @@ show_symbol(struct syment *sp, ulong off
 				offset);
 		fprintf(fp, "\n");
 		return;
-	}
+	} else if (show_flags & SHOW_MODULE)
+		module_symbol(sp->value, NULL, &lm, NULL, 0);
 
         if (offset)
                 fprintf(fp, (radix == 16) ?
-			"%lx (%c) %s+0x%lx  " : "%lx (%c) %s+%ld  ", 
+			"%lx (%c) %s+0x%lx" : "%lx (%c) %s+%ld", 
 			sp->value+offset, sp->type, sp->name, offset);
         else
-                fprintf(fp, "%lx (%c) %s  ", sp->value, sp->type, sp->name);
+                fprintf(fp, "%lx (%c) %s", sp->value, sp->type, sp->name);
+
+	if (lm)
+		fprintf(fp, " [%s]", lm->mod_name);
 
         if (is_kernel_text(sp->value+offset) && 
 	    (show_flags & SHOW_LINENUM))
-                fprintf(fp, "%s", 
+                fprintf(fp, " %s", 
 			get_line_number(sp->value+offset, buf, TRUE));
 
 	if (show_flags & SHOW_SECTION)
-                fprintf(fp, "[%s]", get_section(sp->value+offset, buf));
+                fprintf(fp, " [%s]", get_section(sp->value+offset, buf));
 		
-
 	fprintf(fp, "\n");
 }
 
@@ -3419,7 +3512,8 @@ symbol_query(char *s, char *print_pad, s
 				if (print_pad) {
 					if (strlen(print_pad))
 						fprintf(fp, "%s", print_pad);
-					show_symbol(sp, 0, SHOW_RADIX());
+					show_symbol(sp, 0, 
+						SHOW_RADIX()|SHOW_MODULE);
 				}
 				if (spp)
 					*spp = sp;
@@ -3446,7 +3540,8 @@ symbol_query(char *s, char *print_pad, s
 				if (print_pad) {
 					if (strlen(print_pad))
 						fprintf(fp, "%s", print_pad);
-					show_symbol(sp, 0, SHOW_RADIX());
+					show_symbol(sp, 0, 
+						SHOW_RADIX()|SHOW_MODULE);
 				}
 				if (spp)
 					*spp = sp;
@@ -3487,10 +3582,9 @@ symbol_search(char *s)
 		sp = lm->mod_symtable;
                 sp_end = lm->mod_symend;
 
-                for ( ; sp < sp_end; sp++) {
+                for ( ; sp <= sp_end; sp++) {
                 	if (!pseudos && MODULE_PSEUDO_SYMBOL(sp))
                         	continue;
-
                 	if (STREQ(s, sp->name))
                         	return(sp);
                 }
@@ -3726,7 +3820,9 @@ module_symbol(ulong value, 
 		} else if (IN_MODULE_INIT(value, lm)) {
 			base = lm->mod_init_module_ptr;
 			end = lm->mod_init_module_ptr + lm->mod_init_size;
-
+		} else if (IN_MODULE_PERCPU(value, lm)) {
+			base = lm->mod_percpu;
+			end = lm->mod_percpu + lm->mod_percpu_size;
 		} else
 			continue;
 
@@ -4432,16 +4528,12 @@ per_cpu_symbol_search(char *symbol)
 			return sp;
 		new = symbol + strlen("per_cpu__");
 		if ((sp = symbol_search(new))) {
-			if ((sp->type == 'V') ||
-			    ((sp->value >= st->__per_cpu_start) && 
-		    	    (sp->value < st->__per_cpu_end)))
+			if ((sp->type == 'V') || (is_percpu_symbol(sp)))
 				return sp;
 		}
 	} else {
 		if ((sp = symbol_search(symbol))) {
-			if ((sp->type == 'V') ||
-			    ((sp->value >= st->__per_cpu_start) && 
-		    	    (sp->value < st->__per_cpu_end)))
+			if ((sp->type == 'V') || (is_percpu_symbol(sp)))
 				return sp;
 		}
 
@@ -5638,7 +5730,10 @@ cmd_p(void)
 		leader = strlen(buf2);
 		if (module_symbol(sp->value, NULL, NULL, NULL, *gdb_output_radix))
 			do_load_module_filter = TRUE;
-	} else if (st->flags & LOAD_MODULE_SYMS)
+	} else if ((percpu_sp = per_cpu_symbol_search(args[optind])) &&
+		   display_per_cpu_info(percpu_sp))
+		return;
+	else if (st->flags & LOAD_MODULE_SYMS)
 		do_load_module_filter = TRUE;
 
 	if (leader || do_load_module_filter)
@@ -5698,8 +5793,7 @@ display_per_cpu_info(struct syment *sp)
 	char buf[BUFSIZE];
 
 	if (((kt->flags & (SMP|PER_CPU_OFF)) != (SMP|PER_CPU_OFF)) ||
-	    (sp->value < symbol_value("__per_cpu_start")) || 
-	    (sp->value >= symbol_value("__per_cpu_end")) ||
+	    (!is_percpu_symbol(sp)) ||
 	    !((sp->type == 'd') || (sp->type == 'D') || (sp->type == 'V')))
 		return FALSE;
 
@@ -5719,6 +5813,43 @@ display_per_cpu_info(struct syment *sp)
 	return TRUE;
 }
 
+static struct load_module *
+get_module_percpu_sym_owner(struct syment *sp)
+{
+	int i;
+	struct load_module *lm;
+
+	if (!IS_MODULE_SYMBOL(sp))
+		return NULL;
+
+	/*
+	 * Find out percpu symbol owner module.
+	 * If found out, sp is module's percpu symbol.
+	 */
+	for (i = 0; i < st->mods_installed; i++) {
+		lm = &st->load_modules[i];
+		if (!MODULE_PERCPU_SYMS_LOADED(lm))
+			continue;
+		if (IN_MODULE_PERCPU(sp->value, lm))
+			return lm;
+	}
+	return NULL;
+}
+
+static int 
+is_percpu_symbol(struct syment *sp)
+{
+	if (sp->value >= st->__per_cpu_start) {
+		if (sp->value < st->__per_cpu_end)
+			/* kernel percpu symbol */
+			return 1;
+		else if (get_module_percpu_sym_owner(sp))
+			/* module percpu symbol */
+			return 2;
+	}
+	return 0;
+}
+
 /*
  *  As a latch ditch effort before a command is thrown away by exec_command(),
  *  args[0] is checked to see whether it's the name of a variable, structure, 
@@ -6903,6 +7034,8 @@ dump_offset_table(char *spec, ulong make
 		OFFSET(module_symtab));
 	fprintf(fp, "                 module_strtab: %ld\n",
 		OFFSET(module_strtab));
+	fprintf(fp, "                 module_percpu: %ld\n",
+		OFFSET(module_percpu));
 
 	fprintf(fp, "             module_sect_attrs: %ld\n",
 		OFFSET(module_sect_attrs));
@@ -8346,6 +8479,14 @@ store_section_data(struct load_module *l
 	lm->mod_section_data[i].section = section;
 	lm->mod_section_data[i].priority = prio;
 	lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND;
+	/* 
+	 * The percpu section isn't included in kallsyms or module_core area.
+	 */
+	if (lm->mod_percpu &&
+	    (STREQ(name,".data.percpu") || STREQ(name, ".data..percpu"))) {
+		lm->mod_percpu_size = bfd_section_size(bfd, section);
+		lm->mod_section_data[i].flags |= SEC_FOUND;
+	}
 	lm->mod_section_data[i].size = bfd_section_size(bfd, section);
 	lm->mod_section_data[i].offset = 0;
 	if (strlen(name) < MAX_MOD_SEC_NAME)
@@ -8791,13 +8932,26 @@ add_symbol_file(struct load_module *lm)
 	{
 		secname = lm->mod_section_data[i].name;
 		if ((lm->mod_section_data[i].flags & SEC_FOUND) &&
-		    !STREQ(secname, ".text")) {
+		    (!STREQ(secname, ".text") &&
+		     !STREQ(secname, ".data.percpu") &&
+		     !STREQ(secname, ".data..percpu"))) {
 			sprintf(buf, " -s %s 0x%lx", secname, 
 				lm->mod_section_data[i].offset + lm->mod_base);
 			len += strlen(buf);
 		}
 	}
 
+	for (i = 0; i < lm->mod_sections; i++)
+	{
+		secname = lm->mod_section_data[i].name;
+		if ((lm->mod_section_data[i].flags & SEC_FOUND) &&
+		    (STREQ(secname, ".data.percpu") ||
+		     STREQ(secname, ".data..percpu"))) {
+			sprintf(buf, " -s %s 0x%lx", secname, lm->mod_percpu);
+			len += strlen(buf);
+		}
+	}
+
         req->command = GNU_ADD_SYMBOL_FILE;
 	req->addr = (ulong)lm;
 	req->buf = GETBUF(len+BUFSIZE);
@@ -8816,6 +8970,31 @@ add_symbol_file(struct load_module *lm)
 }
 
 #ifdef GDB_7_0
+static int 
+add_symbol_file_percpu(struct load_module *lm, struct gnu_request *req, int buflen)
+{
+	char pbuf[BUFSIZE];
+	int i, len;
+	char *secname;
+
+	len = strlen(req->buf);
+	for (i = 0; i < lm->mod_sections; i++) {
+		secname = lm->mod_section_data[i].name;
+		if ((lm->mod_section_data[i].flags & SEC_FOUND) &&
+		    (STREQ(secname, ".data.percpu") ||
+		     STREQ(secname, ".data..percpu"))) {
+			sprintf(pbuf, " -s %s 0x%lx", secname, lm->mod_percpu);
+			while ((len + strlen(pbuf)) >= buflen) {
+				RESIZEBUF(req->buf, buflen, buflen * 2);
+				buflen *= 2;
+			}
+			strcat(req->buf, pbuf);
+			len += strlen(pbuf);
+		}
+	}
+	return buflen;
+}
+
 /*
  *  Gather the module section data from the in-kernel data structures.
  */
@@ -9035,6 +9214,11 @@ add_symbol_file_kallsyms(struct load_mod
 		return FALSE;
 	}
 
+	/* 
+	 * Special case for per-cpu symbols 
+	 */
+	buflen = add_symbol_file_percpu(lm, req, buflen);
+
 	lm->mod_flags |= MOD_NOPATCH;
         req->command = GNU_ADD_SYMBOL_FILE;
 	req->addr = (ulong)lm;
@@ -9176,7 +9360,7 @@ store_load_module_symbols(bfd *bfd, int 
 
 	if (!lm->mod_load_symtable) {
 	        if ((lm->mod_load_symtable = (struct syment *)
-	             malloc(symalloc * sizeof(struct syment))) == NULL)
+	             calloc(symalloc, sizeof(struct syment))) == NULL)
 	                error(FATAL, "module syment space malloc: %s\n",
 	                        strerror(errno));
 
@@ -9314,7 +9498,12 @@ store_load_module_symbols(bfd *bfd, int 
 				else if ((spx = kallsyms_module_symbol(lm, &syminfo))) {
 					syminfo.value = spx->value;
 					found = TRUE;
-                                } else {
+				} else if (lm->mod_percpu &&
+					(STREQ(secname, ".data.percpu") ||
+					STREQ(secname, ".data..percpu"))) {
+					syminfo.value += lm->mod_percpu;
+					found = TRUE;
+				} else {
                                         syminfo.value += lm->mod_section_data[i].offset + lm->mod_base;
                                         found = TRUE;
                                 }
@@ -9329,6 +9518,7 @@ store_load_module_symbols(bfd *bfd, int 
                             syminfo.type)) {
                                 sp->value = syminfo.value;
                                 sp->type = syminfo.type;
+				sp->flags |= MODULE_SYMBOL;
                                 namespace_ctl(NAMESPACE_INSTALL,
                                         &lm->mod_load_namespace, sp, name);
 
@@ -9385,6 +9575,7 @@ store_load_module_symbols(bfd *bfd, int 
 
 			lm->mod_load_symend->value = spx->value;
 			lm->mod_load_symend->type = spx->type;
+			lm->mod_load_symend->flags |= MODULE_SYMBOL;
 			lm->mod_load_symend++;
 			lm->mod_load_symcnt++;
 		} 
@@ -9397,9 +9588,10 @@ store_load_module_symbols(bfd *bfd, int 
                 compare_syms);
 
 	lm->mod_load_symend--;
-	if (!MODULE_END(lm->mod_load_symend))
-		error(INFO, "%s: last symbol is not _MODULE_END_%s?\n",
-			lm->mod_name, lm->mod_name);
+	if (!MODULE_END(lm->mod_load_symend) &&
+	    !IN_MODULE_PERCPU(lm->mod_load_symend->value, lm))
+		error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n",
+			lm->mod_name, lm->mod_load_symend->name, lm->mod_name);
 
         lm->mod_symtable = lm->mod_load_symtable;
         lm->mod_symend = lm->mod_load_symend;
@@ -9408,7 +9600,6 @@ store_load_module_symbols(bfd *bfd, int 
 	lm->mod_flags |= MOD_LOAD_SYMS;
 
 	st->flags |= LOAD_MODULE_SYMS;
-
 }
 
 /*
@@ -9451,6 +9642,7 @@ delete_load_module(ulong base_addr)
 			lm->mod_text_start = lm->mod_data_start = 0; 
 			lm->mod_bss_start = lm->mod_rodata_start = 0;
 			lm->mod_sections = 0;
+			lm->mod_percpu_size = 0;
 			if (lm->mod_section_data)
 				free(lm->mod_section_data);
 			lm->mod_section_data = (struct mod_section_data *)0;
@@ -9485,6 +9677,7 @@ delete_load_module(ulong base_addr)
                         lm->mod_load_symcnt = lm->mod_symalloc = 0;
                         lm->mod_text_start = lm->mod_data_start = 0;
 			lm->mod_bss_start = lm->mod_rodata_start = 0;
+			lm->mod_percpu_size = 0;
 			lm->mod_sections = 0;
 			if (lm->mod_section_data)
 				free(lm->mod_section_data);
@@ -9926,7 +10119,6 @@ clear_text_value_cache(void)
  *  new one.
  */
 
-#define allocated pad1
 #define last_sp addr2
 
 int 
@@ -9962,10 +10154,10 @@ patch_kernel_symbol(struct gnu_request *
 
 	sp = (struct syment *)req->last_sp; 
 	sp += sp ? 1 : 0;
-	if (sp && (sp->cnt == 1) && !(sp->allocated) && 
+	if (sp && (sp->cnt == 1) && !(sp->flags & SYMBOL_NAME_USED) && 
 	    STREQ(sp->name, req->name)) {
                 *((ulong *)req->addr) = sp->value;
-                sp->allocated = TRUE;
+                sp->flags |= SYMBOL_NAME_USED;
                 req->last_sp = (ulong)sp;
 	} else {
 		switch (c = get_syment_array(req->name, sp_array, 1000))
@@ -9975,16 +10167,16 @@ patch_kernel_symbol(struct gnu_request *
 	
 		case 1: 
 			*((ulong *)req->addr) = sp_array[0]->value;
-			sp_array[0]->allocated = TRUE;
+			sp_array[0]->flags |= SYMBOL_NAME_USED;
 			req->last_sp = (ulong)sp_array[0];
 			break;
 	
 		default:
 			for (i = 0; i < c; i++) {
-				if (sp_array[i]->allocated)
+				if (sp_array[i]->flags & SYMBOL_NAME_USED)
 					continue;
 				*((ulong *)req->addr) = sp_array[i]->value;
-				sp_array[i]->allocated = TRUE;
+				sp_array[i]->flags |= SYMBOL_NAME_USED;
 				req->last_sp = (ulong)sp_array[i];
 				break;
 			}
@@ -9995,7 +10187,6 @@ patch_kernel_symbol(struct gnu_request *
 	return TRUE;
 }
 
-#undef allocated
 #undef last_sp
 
 /*
--- crash-5.0.9/lkcd_x86_trace.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/lkcd_x86_trace.c	2010-11-05 15:09:31.000000000 -0400
@@ -1716,6 +1716,7 @@ find_trace(
 				}
 			} else if (strstr(func_name, "call_do_IRQ") ||
 				strstr(func_name, "common_interrupt") ||
+				strstr(func_name, "reboot_interrupt") ||
 				strstr(func_name, "call_function_interrupt")) {
 				/* Interrupt frame */
 				sp = curframe->fp + 4;
@@ -2581,6 +2582,7 @@ print_stack_entry(struct bt_info *bt, in
 {
 	char buf[BUFSIZE];
 	struct syment *sp;
+	struct load_module *lm;
 
 	if (frmp && frmp->prev && STREQ(frmp->funcname, "error_code") &&
 	    (sp = x86_jmp_error_code((ulong)frmp->prev->pc)))
@@ -2595,10 +2597,13 @@ print_stack_entry(struct bt_info *bt, in
 	if ((sp = eframe_label(funcname, eip))) 
 		funcname = sp->name;
 
-	fprintf(ofp, "%s#%d [%8lx] %s%s at %lx\n",
+	fprintf(ofp, "%s#%d [%8lx] %s%s at %lx",
                 level < 10 ? " " : "", level, esp, 
 		funcname_display(funcname), 
 		strlen(buf) ? buf : "", eip);
+	if (module_symbol(eip, NULL, &lm, NULL, 0))
+		fprintf(ofp, " [%s]", lm->mod_name);
+	fprintf(ofp, "\n");
 
         if (bt->flags & BT_LINE_NUMBERS) {
                 get_line_number(eip, buf, FALSE);
--- crash-5.0.9/unwind.c	2010-11-12 15:34:12.000000000 -0500
+++ crash/unwind.c	2010-11-05 17:13:23.000000000 -0400
@@ -1696,6 +1696,7 @@ unwind_v3(struct bt_info *bt)
 	struct pt_regs *pt;
         int frame;
         char *name;
+	struct load_module *lm;
 	static int unw_in_progress = FALSE;
 
 	if (bt->debug)
@@ -1751,9 +1752,12 @@ restart:
                                 break;
                         }
                 } else {
-                        fprintf(fp, "%s#%d [BSP:%lx] %s at %lx\n",
+                        fprintf(fp, "%s#%d [BSP:%lx] %s at %lx",
                                 frame >= 10 ? "" : " ", frame,
                                 bsp, name, ip);
+			if (module_symbol(ip, NULL, &lm, NULL, 0))
+				fprintf(fp, " [%s]", lm->mod_name);
+			fprintf(fp, "\n");
 
 			if (bt->flags & BT_FULL)
                         	rse_function_params(bt, info, name);
--- crash-5.0.9/defs.h	2010-11-12 15:34:12.000000000 -0500
+++ crash/defs.h	2010-11-11 17:04:27.000000000 -0500
@@ -1532,6 +1532,7 @@ struct offset_table {                   
 	long unwind_idx_insn;
 	long signal_struct_nr_threads;
 	long module_init_size;
+	long module_percpu;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -1911,6 +1912,10 @@ struct alias_data {                 /* c
 #endif /* !GDB_COMMON */
 
 
+#define SYMBOL_NAME_USED (0x1)
+#define MODULE_SYMBOL    (0x2)
+#define IS_MODULE_SYMBOL(SYM)  ((SYM)->flags & MODULE_SYMBOL)
+
 struct syment {
         ulong value;
         char *name;
@@ -1918,10 +1923,10 @@ struct syment {
 	struct syment *name_hash_next;
 	char type;
 	unsigned char cnt;
-	unsigned char pad1;
+	unsigned char flags;
 	unsigned char pad2;
 };
-                
+
 #define NAMESPACE_INIT     (1)
 #define NAMESPACE_REUSE    (2)
 #define NAMESPACE_FREE     (3)
@@ -2063,6 +2068,8 @@ struct load_module {
 	ulong mod_init_size;
 	struct syment *mod_init_symtable;
 	struct syment *mod_init_symend;
+	ulong mod_percpu;
+	ulong mod_percpu_size;
 };
 
 #define IN_MODULE(A,L) \
@@ -2071,6 +2078,11 @@ struct load_module {
 #define IN_MODULE_INIT(A,L) \
  (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size)))
 
+#define IN_MODULE_PERCPU(A,L) \
+ (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size)))
+
+#define MODULE_PERCPU_SYMS_LOADED(L) ((L)->mod_percpu && (L)->mod_percpu_size)
+
 #ifndef GDB_COMMON
 
 #define KVADDR             (0x1)
@@ -3579,6 +3591,7 @@ void show_symbol(struct syment *, ulong,
 #define SHOW_HEX_OFFS (0x4)
 #define SHOW_DEC_OFFS (0x8)
 #define SHOW_RADIX() (*gdb_output_radix == 16 ? SHOW_HEX_OFFS : SHOW_DEC_OFFS)
+#define SHOW_MODULE  (0x10)
 int symbol_query(char *, char *, struct syment **);
 struct syment *next_symbol(char *, struct syment *);
 struct syment *prev_symbol(char *, struct syment *);
