>From 25c19191bb42c690a17f1c2d2170ef3174c06705 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
Date: Fri, 30 Mar 2012 10:15:15 +0800
Subject: [PATCH] add ipcs command

---
 Makefile      |    7 +-
 defs.h        |   37 ++++
 global_data.c |    1 +
 help.c        |   69 +++++++
 ipcs.c        |  580 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 692 insertions(+), 2 deletions(-)
 create mode 100644 ipcs.c

diff --git a/Makefile b/Makefile
index 5d88a44..b682128 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
 	netdump.c diskdump.c makedumpfile.c xendump.c unwind.c unwind_decoder.c \
 	unwind_x86_32_64.c unwind_arm.c \
 	xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
-	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c
+	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c
 
 SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
 	${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
@@ -85,7 +85,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
 	lkcd_x86_trace.o unwind_v1.o unwind_v2.o unwind_v3.o \
 	unwind_x86_32_64.o unwind_arm.o \
 	xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
-	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o
+	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o
 
 MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
 
@@ -485,6 +485,9 @@ xen_hyper_global_data.o: ${GENERIC_HFILES} xen_hyper_global_data.c
 xen_hyper_dump_tables.o: ${GENERIC_HFILES} xen_hyper_dump_tables.c
 	cc -c ${CRASH_CFLAGS} xen_hyper_dump_tables.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
+ipcs.o: ${GENERIC_HFILES} ipcs.c
+	cc -c ${CRASH_CFLAGS} ipcs.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
 ${PROGRAM}: force
 	@make --no-print-directory all
 
diff --git a/defs.h b/defs.h
index a942dbb..e454911 100755
--- a/defs.h
+++ b/defs.h
@@ -1662,6 +1662,38 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long request_queue_rq;
 	long subsys_private_klist_devices;
 	long subsystem_kset;
+
+	long file_f_op;
+	long file_private_data;
+	long hstate_order;
+	long hugetlbfs_sb_info_hstate;
+	long idr_layer_ary;
+	long idr_layer_layer;
+	long idr_layers;
+	long idr_top;
+	long ipc_id_ary_p;
+	long ipc_ids_entries;
+	long ipc_ids_max_id;
+	long ipc_ids_ipcs_idr;
+	long ipc_ids_in_use;
+	long ipc_namespace_ids;
+	long ipc_namespace_shm_tot;
+	long kern_ipc_perm_deleted;
+	long kern_ipc_perm_key;
+	long kern_ipc_perm_mode;
+	long kern_ipc_perm_seq;
+	long kern_ipc_perm_uid;
+	long kern_ipc_perm_id;
+	long nsproxy_ipc_ns;
+	long shmem_inode_info_swapped;
+	long shmem_inode_info_vfs_inode;
+	long shm_file_data_file;
+	long shmid_kernel_shm_file;
+	long shmid_kernel_shm_nattch;
+	long shmid_kernel_shm_perm;
+	long shmid_kernel_shm_segsz;
+	long shmid_kernel_id;
+	long super_block_s_fs_info;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -1788,6 +1820,9 @@ struct size_table {         /* stash of commonly-used sizes */
 	long class_private;
 	long rq_in_flight;
 	long class_private_devices;
+	long hstate;
+	long ipc_ids;
+	long shmid_kernel;
 };
 
 struct array_table {
@@ -3539,6 +3574,7 @@ void cmd_dev(void);          /* dev.c */
 void cmd_gdb(void);          /* gdb_interface.c */
 void cmd_net(void);          /* net.c */
 void cmd_extend(void);       /* extensions.c */
+void cmd_ipcs(void);         /* ipcs.c */
 #if defined(S390) || defined(S390X)
 void cmd_s390dbf(void);
 #endif
@@ -4017,6 +4053,7 @@ extern char *help_vtop[];
 extern char *help_waitq[];
 extern char *help_whatis[];
 extern char *help_wr[];
+extern char *help_ipcs[];
 #if defined(S390) || defined(S390X)
 extern char *help_s390dbf[];
 #endif
diff --git a/global_data.c b/global_data.c
index 98a5a79..e697f8e 100755
--- a/global_data.c
+++ b/global_data.c
@@ -118,6 +118,7 @@ struct command_table_entry linux_command_table[] = {
 	{"waitq",   cmd_waitq,   help_waitq,   REFRESH_TASK_TABLE},
 	{"whatis",  cmd_whatis,  help_whatis,  0},
 	{"wr",      cmd_wr,      help_wr,      0},
+	{"ipcs",    cmd_ipcs,    help_ipcs,    REFRESH_TASK_TABLE},
 #if defined(S390) || defined(S390X)
         {"s390dbf", cmd_s390dbf, help_s390dbf, 0},
 #endif
diff --git a/help.c b/help.c
index f752283..2ba0389 100755
--- a/help.c
+++ b/help.c
@@ -5491,6 +5491,75 @@ char *help_waitq[] = {
 NULL
 };
 
+char *help_ipcs[] = {
+"ipcs",
+"provide information on ipc facilities(shared memory)",                        
+" [-u] [-i id]",
+"  This command provides information on the ipc facilities. SHM_KERNEL is the",
+"  address of the structure shmid_kernel. The unit of RSS and SWAP is the",
+"  number of pages, and the BYTES is allocated memory with the unit of byte.",
+"  The SHM_INODE represents the address of vfs_inode member of",
+"  shmem_inode_info objects. The command now only shows information on shared",
+"  memory.",
+" ",
+"       -u  shows summary information",
+"    -i id  it allows a specific resource id to be specified, and the",
+"           information on this id will be printed",
+"\nEXAMPLE",
+"  display all ipc facilities:\n",
+"    %s> ipcs",
+"    ------ Shared Memory Segments ------", 
+"    SHM_KERNEL       KEY        SHMID    RSS   SWAP  UID   PERMS BYTES   NATTCH  SHM_INODE       ",
+"    ffff8804683b0310 0x00000000 0        7     15    0     600   393216  2       ffff880470512d98",
+"    ffff880470987910 0x00000000 32769    6     16    0     600   393216  2       ffff880470512758",
+"    ffff880471621190 0x00000000 65538    46    0     0     600   393216  2       ffff880474202d98",
+"    ffff8804747f1a50 0x00000000 98307    12    12    0     600   393216  2       ffff880471264758",
+"    ffff8804704ad510 0x00000000 131076   96    0     0     600   393216  2       ffff880474094d98",
+"    ffff880872e42150 0x00000000 163845   44    0     0     600   393216  2       ffff880872e6f758",
+"    ffff88049cf33e10 0x00000000 196614   33    15    0     600   393216  2       ffff880872f0a438",
+"    ffff880872e428d0 0x00000000 229383   72    0     0     600   393216  2       ffff880872e6f118",
+"    ffff8804704ad5d0 0x00000000 262152   72    13    0     600   393216  2       ffff880470408758",
+"    ffff880872e42210 0x00000000 294921   10    12    0     600   393216  2       ffff880872df2438",
+"    ffff880872e42510 0x00000000 327690   96    0     0     600   393216  2       ffff880872ece118",
+"    ffff880872e42750 0x00000000 360459   96    0     0     600   393216  2       ffff880872ece438",
+"    ffff88086e2c0090 0x00000000 393228   96    0     0     600   393216  2       ffff880872045438",
+"    ffff880872e422d0 0x00000000 425997   11    11    0     600   393216  2       ffff880872e6c118",
+"    ffff880872e42090 0x00000000 458766   26    22    0     600   393216  2       ffff880872ea8d98",
+"    ffff88046803a090 0x00000000 491535   0     25    0     600   393216  2       ffff880474202a78",
+"    ffff88046803ad50 0x00000000 524304   0     45    0     600   393216  2       ffff880474202758",
+"    ffff8804716219d0 0x00000000 557073   9     87    0     600   393216  2       ffff8804707bc758",
+"    ffff88046803ab10 0x00000000 589842   89    7     0     600   393216  2       ffff880474202118",
+"    ffff880471621790 0x00000000 4423699  0     0     0     666   1024    0       ffff88046f49e438",
+"    ffff880470988390 0x00000000 720916   96    0     0     600   393216  2       ffff880470408d98",
+"    ffff8804747f1810 0x00000000 753685   24    0     0     600   393216  2       ffff88047467d758",
+"    ffff880470987610 0x00000000 4390934  282   0     0     600   1152000 2       ffff880471470438",
+"    ffff880471621850 0x00000001 4456471  0     0     0     666   1024    0       ffff88046f49e118",
+"    ffff880471621550 0x00000002 4489240  0     0     0     666   1024    0       ffff8804704be758",
+"    ffff880471621a90 0x00000003 4522009  0     0     0     666   1024    0       ffff88046f5f7758",
+"    ffff880471621b50 0x00000004 4554778  0     0     0     666   1024    0       ffff8804683f9758",
+" ",
+"  display summary:\n",
+"    %s> ipcs -u",
+"    ------ Shared Memroy Status --------",
+"    segments allocated 27",
+"    pages allocatd 2303",
+"    pages resident 1223",
+"    pages swapped  280",
+"    swap performance attemts   0",
+"    swap performance successes 0",
+" ",
+"  display a specified resource:\n",
+"    %s> ipcs -u -i 458766",
+"    SHMID: 458766",
+"    ------ Shared Memroy Status --------",
+"    segments allocated 27",
+"    pages allocatd 96",
+"    pages resident 26",
+"    pages swapped  22",
+"    swap performance attemts   0",
+"    swap performance successes 0",
+};
+
 
 /*
  *  Find out what the help request is looking for, accepting aliases as well,
diff --git a/ipcs.c b/ipcs.c
new file mode 100644
index 0000000..8048b72
--- /dev/null
+++ b/ipcs.c
@@ -0,0 +1,580 @@
+/* ipcs.c - core analysis suite 
+ *
+ * Copyright (C) 2012 FUJITSU LIMITED
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "defs.h"
+
+#define IPCS_INIT 0x1
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+
+/*
+ * struct declaration
+ */
+struct shm_info {
+	ulong shm_kernel;
+	int key;
+	int shmid;
+	ulong rss;
+	ulong swap;
+	unsigned int uid;
+	unsigned int perms;
+	ulong bytes;
+	ulong nattch;
+	ulong shm_inode;
+	int deleted;
+};
+
+struct total_shm_info {
+	int used_ids;
+	ulong shm_tot;
+	ulong shm_rss;
+	ulong shm_swp;
+	ulong swap_attempts;
+	ulong swap_successes;
+};
+
+/*
+ * function declaration
+ */
+static void dump_shared_memory(int, int);
+static void ipc_search_idr(ulong, int, int (*)(ulong, int));
+static void ipc_search_array(ulong, int, int (*)(ulong, int));
+static ulong idr_find(ulong, int);
+static int dump_single_shm(ulong, int);
+static int dump_specified_shm(ulong, int);
+static void get_shm_info(struct shm_info *, ulong);
+static void add_rss_swap(ulong, int, ulong *, ulong *);
+static int is_file_hugepages(ulong);
+static void display_summary(void);
+
+/*
+ * global data
+ */
+static int idr_bits;
+static ulong init_flags;
+static ulong hugetlbfs_f_op_addr;
+static ulong shm_f_op_addr;
+static ulong shm_f_op_huge_addr;
+static int use_shm_f_op;
+static struct total_shm_info total_shm_info;
+static unsigned int page_size;
+static unsigned int page_shift;
+
+static void ipcs_init(void)
+{
+	total_shm_info.shm_rss = 0;
+	total_shm_info.shm_swp = 0;
+	total_shm_info.swap_attempts = 0;
+	total_shm_info.swap_successes = 0;
+
+	if (init_flags & IPCS_INIT) {
+		return;
+	}
+
+	init_flags |= IPCS_INIT;
+
+	MEMBER_OFFSET_INIT(nsproxy_ipc_ns, "nsproxy", "ipc_ns");
+	MEMBER_OFFSET_INIT(ipc_namespace_ids, "ipc_namespace", "ids");
+	MEMBER_OFFSET_INIT(ipc_namespace_shm_tot, "ipc_namespace", "shm_tot");
+	MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries");
+	MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id");
+	MEMBER_OFFSET_INIT(ipc_ids_in_use, "ipc_ids", "in_use");
+	MEMBER_OFFSET_INIT(ipc_ids_ipcs_idr, "ipc_ids", "ipcs_idr");
+	MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p");
+	MEMBER_OFFSET_INIT(idr_top, "idr", "top");
+	MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer");
+	MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary");
+	MEMBER_OFFSET_INIT(shmid_kernel_shm_perm, "shmid_kernel", "shm_perm");
+	MEMBER_OFFSET_INIT(shmid_kernel_shm_segsz, "shmid_kernel", "shm_segsz");
+	MEMBER_OFFSET_INIT(shmid_kernel_shm_nattch, "shmid_kernel", "shm_nattch");
+	MEMBER_OFFSET_INIT(shmid_kernel_shm_file, "shmid_kernel", "shm_file");
+	MEMBER_OFFSET_INIT(shmid_kernel_id, "shmid_kernel", "id");
+	MEMBER_OFFSET_INIT(kern_ipc_perm_key, "kern_ipc_perm", "key");
+	MEMBER_OFFSET_INIT(kern_ipc_perm_id, "kern_ipc_perm", "id");
+	MEMBER_OFFSET_INIT(kern_ipc_perm_uid, "kern_ipc_perm", "uid");
+	MEMBER_OFFSET_INIT(kern_ipc_perm_mode, "kern_ipc_perm", "mode");
+	MEMBER_OFFSET_INIT(kern_ipc_perm_deleted, "kern_ipc_perm", "deleted");
+	MEMBER_OFFSET_INIT(file_f_op, "file", "f_op");
+	MEMBER_OFFSET_INIT(file_private_data, "file", "private_data");
+	MEMBER_OFFSET_INIT(shm_file_data_file, "shm_file_data", "file");
+	MEMBER_OFFSET_INIT(super_block_s_fs_info, "super_block", "s_fs_info");
+	MEMBER_OFFSET_INIT(hstate_order, "hstate", "order");
+	MEMBER_OFFSET_INIT(shmem_inode_info_vfs_inode, "shmem_inode_info", "vfs_inode");
+	MEMBER_OFFSET_INIT(shmem_inode_info_swapped, "shmem_inode_info", "swapped");
+
+	/*
+	 * struct size
+	 */
+	STRUCT_SIZE_INIT(ipc_ids, "ipc_ids");
+	STRUCT_SIZE_INIT(shmid_kernel, "shmid_kernel");
+	STRUCT_SIZE_INIT(hstate, "hstate");
+
+	hugetlbfs_f_op_addr = symbol_value("hugetlbfs_file_operations");
+	if (symbol_exists("is_file_shm_hugepages")) {
+		use_shm_f_op = TRUE;
+		shm_f_op_addr = symbol_value("shm_file_operations");
+		if (symbol_exists("shm_file_operations_huge")) {
+			shm_f_op_huge_addr =
+				symbol_value("shm_file_operations_huge");
+		} else {
+			shm_f_op_huge_addr = -1;
+		}
+	} else {
+		use_shm_f_op = FALSE;
+		shm_f_op_addr = -1;
+		shm_f_op_huge_addr = -1;
+	}
+
+	if (BITS32())
+		idr_bits = 5;
+	else if (BITS64())
+		idr_bits = 6;
+	else
+		error(FATAL, "machdep->bits is not 32 or 64");
+
+	page_size = memory_page_size();
+	page_shift = ffs(page_size) - 1;
+}
+
+void cmd_ipcs(void)
+{
+	int show_summary, specified_id;
+	int id;
+	int c;
+
+	id = 0;
+	show_summary = 0;
+	specified_id = 0;
+	while ((c = getopt(argcnt, args, "ui:")) != EOF) {
+		switch(c) {
+			case 'u':
+				show_summary = 1;
+				break;
+			case 'i':
+				id = dtoi(optarg, FAULT_ON_ERROR, NULL);
+				specified_id = 1;
+				break;
+			default:
+				cmd_usage(pc->curcmd, SYNOPSIS);;
+				return;
+		}
+	}
+
+	ipcs_init();
+
+	if (show_summary && !specified_id)
+		open_tmpfile();
+    
+	dump_shared_memory(specified_id, id);
+
+	if (show_summary && !specified_id) {
+		close_tmpfile();
+		display_summary();
+	}
+}
+
+static void dump_shared_memory(int specified_id, int id)
+{
+	ulong cur_task = CURRENT_TASK();
+	ulong nsproxy_p, ipc_ns_p;
+	ulong ipc_ids_p;
+	void (*ipc_search)(ulong, int, int (*)(ulong, int));
+	int (*dump_shm)(ulong, int);
+	char buf0[BUFSIZE];
+	char buf1[BUFSIZE];
+	char buf2[BUFSIZE];
+	char buf3[BUFSIZE];
+	char buf4[BUFSIZE];
+	char buf5[BUFSIZE];
+	char buf6[BUFSIZE];
+	char buf7[BUFSIZE];
+	char buf8[BUFSIZE];
+	char buf9[BUFSIZE];
+
+	if (!specified_id) {
+		fprintf(fp, "------ Shared Memory Segments ------\n");
+		fprintf(fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+			mkstring(buf0, VADDR_PRLEN, LJUST, "SHM_KERNEL"),
+			space(MINSPACE),
+			mkstring(buf1, 10, LJUST, "KEY"),
+			space(MINSPACE),
+			mkstring(buf2, 8, LJUST, "SHMID"),
+			space(MINSPACE),
+			mkstring(buf3, 5, LJUST, "RSS"),
+			space(MINSPACE),
+			mkstring(buf4, 5, LJUST, "SWAP"),
+			space(MINSPACE),
+			mkstring(buf5, 5, LJUST, "UID"),
+			space(MINSPACE),
+			mkstring(buf6, 5, LJUST, "PERMS"),
+			space(MINSPACE),
+			mkstring(buf7, 7, LJUST, "BYTES"),
+			space(MINSPACE),
+			mkstring(buf8, 7, LJUST, "NATTCH"),
+			space(MINSPACE),
+			mkstring(buf9, VADDR_PRLEN, LJUST, "SHM_INODE"));
+		dump_shm = dump_single_shm;
+	} else
+		dump_shm = dump_specified_shm;
+
+	if (VALID_MEMBER(ipc_ids_max_id)) {
+		ipc_search = ipc_search_array;
+	} else {
+		ipc_search = ipc_search_idr;
+	}
+
+	if (symbol_exists("shm_ids")) {
+		ipc_ids_p = symbol_value("shm_ids");
+		int shm_tot;
+		readmem(symbol_value("shm_tot"), KVADDR, &shm_tot, sizeof(int),
+			"shm_tot", FAULT_ON_ERROR);
+		total_shm_info.shm_tot = shm_tot;
+	} else {
+		readmem(cur_task + OFFSET(task_struct_nsproxy), KVADDR,
+			&nsproxy_p, sizeof(ulong), "task_struct.nsproxy",
+			FAULT_ON_ERROR);
+		readmem(nsproxy_p + OFFSET(nsproxy_ipc_ns), KVADDR, &ipc_ns_p,
+			sizeof(ulong), "nsproxy.ipc_ns", FAULT_ON_ERROR);
+		int shm_tot;
+		readmem(ipc_ns_p + OFFSET(ipc_namespace_shm_tot), KVADDR,
+			&shm_tot, sizeof(int),
+			"ipc_namespace.shm_tot", FAULT_ON_ERROR);
+		total_shm_info.shm_tot = shm_tot;
+
+		ipc_ids_p = ipc_ns_p + OFFSET(ipc_namespace_ids) + 2 * SIZE(ipc_ids);
+	}
+	ipc_search(ipc_ids_p, id, dump_shm);
+}
+
+/*
+ * if shared memory information is stored in an array, use this function.
+ */
+static void ipc_search_array(ulong ipc_ids_p, int id, int (*fn)(ulong, int))
+{
+	ulong entries_p;
+	int max_id, i;
+	ulong *array;
+
+	readmem(ipc_ids_p + OFFSET(ipc_ids_entries), KVADDR, &entries_p,
+		sizeof(ulong), "ipc_ids.entries", FAULT_ON_ERROR);
+	readmem(ipc_ids_p + OFFSET(ipc_ids_max_id), KVADDR, &max_id, sizeof(int),
+		"ipc_ids.max_id", FAULT_ON_ERROR);
+	ulong in_use;
+	readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &in_use,
+		sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
+	total_shm_info.used_ids = in_use;
+
+	array = (ulong *)GETBUF(sizeof(ulong *) * (max_id + 1));
+	readmem(entries_p + OFFSET(ipc_id_ary_p), KVADDR, array,
+		sizeof(ulong *) * (max_id + 1), "ipc_id_ary.p", FAULT_ON_ERROR);
+
+	for (i=0; i<=max_id; i++) {
+		if (array[i] == 0)
+			continue;
+		if (fn(array[i], id))
+			break;
+	}
+
+	FREEBUF(array);
+}
+
+/*
+ * if shared memory information is stored by using idr, use this function to
+ * get data.
+ */
+static void ipc_search_idr(ulong ipc_ids_p, int id, int (*fn)(ulong, int))
+{
+	int in_use;
+	ulong ipcs_idr_p;
+	ulong ipc;
+	int next_id, total;
+
+	readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &in_use, 
+		sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
+
+	total_shm_info.used_ids = in_use;
+	ipcs_idr_p = ipc_ids_p + OFFSET(ipc_ids_ipcs_idr);
+
+	for (total = 0, next_id = 0; total < in_use; next_id++) {
+		ipc = idr_find(ipcs_idr_p, next_id);
+		if (ipc == 0)
+			continue;
+		
+		total++;
+		if (fn(ipc, id))
+			break;
+	}
+}
+
+/*
+ * search every idr_layer
+ */
+static ulong idr_find(ulong idp, int id)
+{
+	ulong idr_layer_p;
+	int layer;
+	int n;
+	int index;
+
+	readmem(idp + OFFSET(idr_top), KVADDR, &idr_layer_p, sizeof(ulong),
+		"idr.top", FAULT_ON_ERROR);
+
+	if (!idr_layer_p)
+		return 0;
+
+	readmem(idr_layer_p + OFFSET(idr_layer_layer), KVADDR, &layer,
+		sizeof(int), "idr_layer.layer", FAULT_ON_ERROR);
+
+	n = (layer + 1) * idr_bits;
+	id &= MAX_ID_MASK;
+
+	if (id >= (1 << n))
+		return 0;
+
+	while (n > 0 && idr_layer_p) {
+		n -= idr_bits;
+		index = (id >> n) & ((1 << idr_bits) - 1);
+		readmem(idr_layer_p + OFFSET(idr_layer_ary) + sizeof(ulong) * index,
+			KVADDR, &idr_layer_p, sizeof(ulong), "idr_layer.ary",
+			FAULT_ON_ERROR);
+	}
+	
+	return idr_layer_p;
+}
+
+static int dump_single_shm(ulong shp, int id)
+{
+	struct shm_info shm_info;
+	char buf0[BUFSIZE];
+	char buf1[BUFSIZE];
+
+	get_shm_info(&shm_info, shp);
+	
+	if (shm_info.deleted)
+		return 0;
+
+	fprintf(fp, "%s%s0x%08x%s%-8d%s%-5ld%s%-5ld%s%-5d%s%-5o%s%-7ld%s%-7ld%s%s\n",
+		mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
+			LJUST|LONG_HEX,	(char *)shm_info.shm_kernel),
+		space(MINSPACE),
+		shm_info.key,
+		space(MINSPACE),
+		shm_info.shmid,
+		space(MINSPACE),
+		shm_info.rss,
+		space(MINSPACE),
+		shm_info.swap,
+		space(MINSPACE),
+		shm_info.uid,
+		space(MINSPACE),
+		shm_info.perms & 0777,
+		space(MINSPACE),
+		shm_info.bytes,
+		space(MINSPACE),
+		shm_info.nattch,
+		space(MINSPACE),
+		mkstring(buf1, VADDR_PRLEN <= 9 ? 9 : VADDR_PRLEN, LJUST|LONG_HEX,
+			(char *)shm_info.shm_inode));
+
+	return 0;
+}
+
+/*
+ * if the resource is specified, use this function to output information
+ */
+static int dump_specified_shm(ulong shp, int id)
+{
+	struct shm_info shm_info;
+
+	get_shm_info(&shm_info, shp);
+
+	if(shm_info.shmid == id) {
+		fprintf(fp, "SHMID: %d\n", shm_info.shmid);
+		fprintf(fp, "------ Shared Memroy Status --------\n");
+		fprintf(fp, "segments allocated %d\n", total_shm_info.used_ids);
+		fprintf(fp, "pages allocatd %ld\n",
+			(shm_info.bytes + page_size - 1) >> page_shift);
+		fprintf(fp, "pages resident %ld\n", shm_info.rss);
+		fprintf(fp, "pages swapped  %ld\n", shm_info.swap);
+		fprintf(fp, "swap performance attemts   %ld\n",
+			total_shm_info.swap_attempts);
+		fprintf(fp, "swap performance successes %ld",
+			total_shm_info.swap_successes);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void get_shm_info(struct shm_info *shm_info, ulong shp)
+{
+	char buf[BUFSIZE];
+	ulong filep, dentryp, inodep;
+
+	shm_info->shm_kernel = shp - OFFSET(shmid_kernel_shm_perm);
+
+	//cache shmid_kernel
+	readmem(shm_info->shm_kernel, KVADDR, buf, SIZE(shmid_kernel),
+		"shmid_kernel", FAULT_ON_ERROR);
+
+	shm_info->key = INT(buf + OFFSET(shmid_kernel_shm_perm) +
+			OFFSET(kern_ipc_perm_key));
+	if (VALID_MEMBER(shmid_kernel_id))
+		shm_info->shmid = INT(buf + OFFSET(shmid_kernel_id));
+	else
+		shm_info->shmid = INT(buf + OFFSET(shmid_kernel_shm_perm) +
+				OFFSET(kern_ipc_perm_id));
+
+	shm_info->uid = UINT(buf + OFFSET(shmid_kernel_shm_perm) +
+			OFFSET(kern_ipc_perm_uid));
+
+	if (BITS32())
+		shm_info->perms = USHORT(buf + OFFSET(shmid_kernel_shm_perm) +
+				OFFSET(kern_ipc_perm_mode));
+	else
+		shm_info->perms = UINT(buf + OFFSET(shmid_kernel_shm_perm) +
+				OFFSET(kern_ipc_perm_mode));
+
+	shm_info->bytes = ULONG(buf + OFFSET(shmid_kernel_shm_segsz));
+
+	shm_info->nattch = ULONG(buf + OFFSET(shmid_kernel_shm_nattch));
+
+	filep = ULONG(buf + OFFSET(shmid_kernel_shm_file));
+	readmem(filep + OFFSET(file_f_dentry), KVADDR, &dentryp, sizeof(ulong),
+		"file.f_dentry", FAULT_ON_ERROR);
+	readmem(dentryp + OFFSET(dentry_d_inode), KVADDR, &inodep, sizeof(ulong),
+		"dentry.d_inode", FAULT_ON_ERROR);
+	// shm_inode here is the vfs_inode of struct shmem_inode_info
+	shm_info->shm_inode = inodep;
+
+	shm_info->rss = 0;
+	shm_info->swap = 0;
+
+	add_rss_swap(inodep, is_file_hugepages(filep), &shm_info->rss,
+                 &shm_info->swap);
+
+	shm_info->deleted = UINT(buf + OFFSET(shmid_kernel_shm_perm) +
+				OFFSET(kern_ipc_perm_deleted));
+}
+
+/*
+ * get rss & swap related to every shared memory, and get the total number of rss
+ * & swap
+ */
+static void add_rss_swap(ulong inode_p, int hugepage, ulong *rss, ulong *swap)
+{
+	unsigned long mapping_p, nr_pages;
+
+	readmem(inode_p + OFFSET(inode_i_mapping), KVADDR, &mapping_p,
+		sizeof(ulong), "inode.i_mapping", FAULT_ON_ERROR);
+	readmem(mapping_p + OFFSET(address_space_nrpages), KVADDR, &nr_pages,
+		sizeof(ulong), "address_space.nrpages", FAULT_ON_ERROR);
+
+	if (hugepage) {
+		unsigned long pages_per_hugepage;
+		if (VALID_SIZE(hstate)) {
+			unsigned long i_sb_p, hsb_p, hstate_p;
+			unsigned int order;
+
+			readmem(inode_p + OFFSET(inode_i_sb), KVADDR, &i_sb_p,
+				sizeof(ulong), "inode.i_sb", FAULT_ON_ERROR);
+			readmem(i_sb_p + OFFSET(super_block_s_fs_info), KVADDR,
+				&hsb_p, sizeof(ulong), "super_block.s_fs_info",
+				FAULT_ON_ERROR);
+			readmem(hsb_p + OFFSET(hugetlbfs_sb_info_hstate), KVADDR,
+				&hstate_p, sizeof(ulong),
+				"hugetlbfs_sb_info.hstate", FAULT_ON_ERROR);
+			readmem(hstate_p + OFFSET(hstate_order), KVADDR, &order,
+				sizeof(uint), "hstate.order", FAULT_ON_ERROR);
+			pages_per_hugepage = 1 << order;
+		} else {
+			unsigned long hpage_shift;
+			/*
+			 * HPAGE_SHIFT is 21 after commit 83a5101b(kernel > 2.6.24)
+			 */
+			if (THIS_KERNEL_VERSION > LINUX(2, 6, 24)) {
+				hpage_shift = 21;
+			} else {
+				/*
+				 * HPAGE_SHIFT:
+				 *   x86(PAE): 21
+				 *   x86(no PAE): 22
+				 *   x86_64: 21
+				 */
+				if ((machine_type("X86") && !(machdep->flags & PAE)))
+					hpage_shift = 22;
+				else
+					hpage_shift = 21;
+			}
+			pages_per_hugepage = (1 << hpage_shift) / page_size;
+		}
+		*rss += pages_per_hugepage * nr_pages;
+		total_shm_info.shm_rss += *rss;
+	} else {
+		unsigned long swapped;
+
+		*rss += nr_pages;
+		total_shm_info.shm_rss += *rss;
+		readmem(inode_p - OFFSET(shmem_inode_info_vfs_inode) +
+			OFFSET(shmem_inode_info_swapped), KVADDR, &swapped,
+			sizeof(ulong), "shmem_inode_info.swapped", FAULT_ON_ERROR);
+		*swap += swapped;
+		total_shm_info.shm_swp += *swap;
+    }
+}
+
+static int is_file_hugepages(ulong file_p)
+{
+	unsigned long f_op, sfd_p;
+
+again:
+	readmem(file_p + OFFSET(file_f_op), KVADDR, &f_op, sizeof(ulong),
+		"file.f_op", FAULT_ON_ERROR);
+	if (f_op == hugetlbfs_f_op_addr)
+		return 1;
+
+	if (use_shm_f_op) {
+		if (shm_f_op_huge_addr != -1) {
+			if (f_op == shm_f_op_huge_addr)
+				return 1;
+		} else {
+			if (f_op == shm_f_op_addr) {
+				readmem(file_p + OFFSET(file_private_data), KVADDR,
+					&sfd_p, sizeof(ulong), "file.private_data",
+					FAULT_ON_ERROR);
+				readmem(sfd_p + OFFSET(shm_file_data_file), KVADDR,
+					&file_p, sizeof(ulong),
+					"shm_file_data.file", FAULT_ON_ERROR);
+				goto again;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void display_summary()
+{
+	fprintf(fp, "------ Shared Memroy Status --------\n");
+	fprintf(fp, "segments allocated %d\n", total_shm_info.used_ids);
+	fprintf(fp, "pages allocatd %ld\n", total_shm_info.shm_tot);
+	fprintf(fp, "pages resident %ld\n", total_shm_info.shm_rss);
+	fprintf(fp, "pages swapped  %ld\n", total_shm_info.shm_swp);
+	fprintf(fp, "swap performance attemts   %ld\n",
+			total_shm_info.swap_attempts);
+	fprintf(fp, "swap performance successes %ld",
+			total_shm_info.swap_successes);
+}
-- 
1.7.1

