From 717ea8ba5523d333de9e9f23ea2733f6466ccd53 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
Date: Fri, 5 Nov 2010 15:07:12 +0900
Subject: [PATCH 2/4] module's percpu basic procedure.

- Initialize new member at module_init()
- Make static SEC_FOUND to .data..percpu and .data.percpu sections
  at store_section_data()
  These can not read from /dev/mem or core file.
  (not include in kallsyms nor module_core.)
- Install syms into st->mod_load_namespace at store_load_module_symbols()
  module's percpu section include bfd of module object.
  The syment.value is sum of bfd value and module.percpu.

[v3]
- Set percpu section size at store_section_data()
  I think bfd_section_size(module percpu section) can get the same value
  as kernel's percpu_modalloc(sh_size).

- Register percpu section into gdb interface.
  Without registration, p &(module percpu symbol) is not work well.

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 kernel.c  |    1 +
 symbols.c |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/kernel.c b/kernel.c
index 9ba0dc4..3439c5a 100755
--- a/kernel.c
+++ b/kernel.c
@@ -2694,6 +2694,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,
diff --git a/symbols.c b/symbols.c
index ec9c893..5b59fb2 100755
--- a/symbols.c
+++ b/symbols.c
@@ -1349,6 +1349,7 @@ store_module_symbols_v2(ulong total, int mods_installed)
 		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));
@@ -8346,6 +8347,12 @@ store_section_data(struct load_module *lm, bfd *bfd, asection *section)
 	lm->mod_section_data[i].section = section;
 	lm->mod_section_data[i].priority = prio;
 	lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND;
+	/* percpu section isn't included in kallsyms nor 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 +8798,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 +8836,32 @@ add_symbol_file(struct load_module *lm)
 }
 
 #ifdef GDB_7_0
+static long add_symbol_file_percpu(struct load_module *lm, char *buf,
+				   long buflen)
+{
+	char pbuf[BUFSIZE];
+	int i;
+	char *secname;
+	long len;
+
+	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(pbuf, " -s %s 0x%lx", secname, lm->mod_percpu);
+			while ((len + strlen(pbuf)) >= buflen) {
+				RESIZEBUF(buf, buflen, buflen * 2);
+				buflen *= 2;
+			}
+			strcat(buf, pbuf);
+			len += strlen(pbuf);
+		}
+	}
+	return buflen;
+}
+
 /*
  *  Gather the module section data from the in-kernel data structures.
  */
@@ -9035,6 +9081,9 @@ add_symbol_file_kallsyms(struct load_module *lm, struct gnu_request *req)
 		return FALSE;
 	}
 
+	/* too ugly but gdb registration request must be one-shot. */
+	buflen = add_symbol_file_percpu(lm, req->buf, buflen);
+
 	lm->mod_flags |= MOD_NOPATCH;
         req->command = GNU_ADD_SYMBOL_FILE;
 	req->addr = (ulong)lm;
@@ -9314,7 +9363,12 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms,
 				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;
                                 }
-- 
1.7.3.2.161.g3089c

