>From 0265da31c97814dfd9c5efa66c0b83b35a06af24 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
Date: Fri, 6 Apr 2012 18:01:04 +0800
Subject: [PATCH] add ipcs command

---
 Makefile      |    7 +-
 defs.h        |   49 +++
 global_data.c |    1 +
 help.c        |   85 +++++
 ipcs.c        | 1051 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 symbols.c     |   93 +++++
 6 files changed, 1284 insertions(+), 2 deletions(-)
 create mode 100644 ipcs.c

diff --git a/Makefile b/Makefile
index 37378c2..b63a940 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 4089779..4fb6f0d 100755
--- a/defs.h
+++ b/defs.h
@@ -1682,6 +1682,48 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long mount_mnt;
 	long task_struct_exit_state;
 	long timekeeper_xtime;
+
+	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 ipc_namespace_used_sems;
+	long ipc_namespace_msg_hdrs;
+	long ipc_namespace_msg_bytes;
+	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 sem_array_sem_perm;
+	long sem_array_sem_id;
+	long sem_array_sem_nsems;
+	long msg_queue_q_perm;
+	long msg_queue_q_id;
+	long msg_queue_q_cbytes;
+	long msg_queue_q_qnum;
+	long super_block_s_fs_info;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -1809,6 +1851,11 @@ struct size_table {         /* stash of commonly-used sizes */
 	long rq_in_flight;
 	long class_private_devices;
 	long mount;
+	long hstate;
+	long ipc_ids;
+	long shmid_kernel;
+	long sem_array;
+	long msg_queue;
 };
 
 struct array_table {
@@ -3660,6 +3707,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
@@ -4140,6 +4188,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 e97c6b4..b8217e1 100755
--- a/help.c
+++ b/help.c
@@ -5566,6 +5566,91 @@ char *help_waitq[] = {
 NULL
 };
 
+char *help_ipcs[] = {
+"ipcs",
+"provide information on ipc facilities(shared memory)",                        
+" [[-u] [-smqM]] | [-i id [-smq]]",
+"  This command provides information on the ipc facilities. Without specified",
+"  one of -s -m -q, the command will show all of three facilities.",
+" ",
+"       -u  shows summary information",
+"       -s  shows semaphore arrays",
+"       -m  shows shared memory segments",
+"       -M  shows shared memory segments' other information"
+"       -q  shows message queue",
+"    -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 ------",
+"    KEY        SHMID      UID        PERMS      BYTES      NATTCH     STATUS       ",
+"    0x00000000 0          0          600        393216     2          dest         ",
+"    0x00000000 32769      0          600        393216     2          dest         ",
+"    0x00000000 65538      0          600        393216     2          dest         ",
+"    0x00000000 98307      0          600        393216     2          dest         ",
+"    0x00000000 131076     0          600        393216     2          dest         ",
+"    0x00000000 163845     0          600        393216     2          dest         ",
+"    0x00000000 196614     0          600        393216     2          dest         ",
+"    0x00000000 229383     0          600        393216     2          dest         ",
+"    0x00000000 262152     0          600        393216     2          dest         ",
+"    0x00000000 294921     0          600        393216     2          dest         ",
+"    0x00000000 327690     0          600        393216     2          dest         ",
+"    0x00000000 360459     0          600        393216     2          dest         ",
+"    0x00000000 393228     0          600        393216     2          dest         ",
+"    0x00000000 425997     0          600        393216     2          dest         ",
+"    0x00000000 458766     0          600        393216     2          dest         ",
+"    0x00000000 491535     0          600        393216     2          dest         ",
+"    0x00000000 524304     0          600        393216     2          dest         ",
+"    0x00000000 557073     0          600        393216     2          dest         ",
+"    0x00000000 589842     0          600        393216     2          dest         ",
+"    0x00000000 4423699    0          666        1024       0                       ",
+"    0x00000000 720916     0          600        393216     2          dest         ",
+"    0x00000000 753685     0          600        393216     2          dest         ",
+"    0x00000000 10747926   0          600        1152000    2          dest         ",
+"    0x00000001 4456471    0          666        1024       0                       ",
+"    0x00000002 4489240    0          666        1024       0                       ",
+"    0x00000003 4522009    0          666        1024       0                       ",
+"    0x00000004 4554778    0          666        1024       0                       ",
+"    ------ Semaphore Arrays --------",
+"    KEY        SEMID      UID        PERMS      NSEMS     ",
+"    0x00000000 0          0          600        1         ",
+"    0x00000000 32769      0          600        1         ",
+"    ------ Message Queues --------",
+"    KEY        MSQID      UID        PERMS      USED-BYTES   MESSAGES    ",
+"    (none allocated)",
+" ",
+"  display summary:\n",
+"    %s> ipcs -u",
+"    ------ Shared Memroy Status --------",
+"    segments allocated 27",
+"    pages allocatd 2303",
+"    pages resident 3612",
+"    pages swapped  969",
+"    swap performance attemts   0",
+"    swap performance successes 0",
+" ",
+"    ------ Semaphore Status --------",
+"    used arrays = 2",
+"    allocated semaphores = 2",
+" ",
+"    ------ Messages Status --------",
+"    allocated queues = 0",
+"    used headers = 0",
+"    used space = 0 bytes",
+" ",
+"  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..d0b6be2
--- /dev/null
+++ b/ipcs.c
@@ -0,0 +1,1051 @@
+/* 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)
+
+#define SHM_DEST   01000
+#define SHM_LOCKED 02000
+
+/*
+ * 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 sem_info {
+	int key;
+	int semid;
+	unsigned int uid;
+	unsigned int perms;
+	ulong nsems;
+	int deleted;
+};
+
+struct msg_info {
+	int key;
+	int msgid;
+	unsigned int uid;
+	unsigned int perms;
+	ulong bytes;
+	ulong messages;
+	int deleted;
+};
+
+struct total_shm_info {
+	int used_ids;
+	ulong shm_tot;
+	ulong shm_rss;
+	ulong shm_swp;
+	ulong swap_attempts;
+	ulong swap_successes;
+};
+
+struct total_sem_info {
+	int semusz;
+	int semaem;
+};
+
+struct total_msg_info {
+	int msgpool;
+	int msgmap;
+	int msgtql;
+};
+
+struct ipcs_table {
+	int idr_bits;
+	ulong init_flags;
+	ulong hugetlbfs_f_op_addr;
+	ulong shm_f_op_addr;
+	ulong shm_f_op_huge_addr;
+	int use_shm_f_op;
+};
+
+/*
+ * function declaration
+ */
+static void dump_shared_memory(int, int, int);
+static void dump_semaphore_arrays(int, int);
+static void dump_message_queues(int, int);
+static void ipc_search_idr(ulong, int, int, int (*)(ulong, int));
+static void ipc_search_array(ulong, int, int, int (*)(ulong, int));
+static ulong idr_find(ulong, int);
+static int dump_single_shm(ulong, int);
+static int dump_single_shm_verbose(ulong, int);
+static int dump_specified_shm(ulong, int);
+static int dump_single_sem(ulong, int);
+static int dump_specified_sem(ulong, int);
+static int dump_single_msg(ulong, int);
+static int dump_specified_msg(ulong, int);
+static void get_shm_info(struct shm_info *, ulong);
+static void get_sem_info(struct sem_info *, ulong);
+static void get_msg_info(struct msg_info *, ulong);
+static void add_rss_swap(ulong, int, ulong *, ulong *);
+static int is_file_hugepages(ulong);
+static void display_shm_summary(void);
+static void display_sem_summary(void);
+static void display_msg_summary(void);
+
+/*
+ * global data
+ */
+static struct total_shm_info total_shm_info = { 0 };
+static struct total_sem_info total_sem_info = { 0 };
+static struct total_msg_info total_msg_info = { 0 };
+static struct ipcs_table ipcs_table = { 0 };
+
+static void
+ipcs_init(void)
+{
+	if (ipcs_table.init_flags & IPCS_INIT) {
+		return;
+	}
+
+	ipcs_table.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_namespace_used_sems, "ipc_namespace", "used_sems");
+	MEMBER_OFFSET_INIT(ipc_namespace_msg_hdrs, "ipc_namespace", "msg_hdrs");
+	MEMBER_OFFSET_INIT(ipc_namespace_msg_bytes, "ipc_namespace", "msg_bytes");
+	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_layers, "idr", "layers");
+	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(sem_array_sem_perm, "sem_array", "sem_perm");
+	MEMBER_OFFSET_INIT(sem_array_sem_id, "sem_array", "sem_id");
+	MEMBER_OFFSET_INIT(sem_array_sem_nsems, "sem_array", "sem_nsems");
+	MEMBER_OFFSET_INIT(msg_queue_q_perm, "msg_queue", "q_perm");
+	MEMBER_OFFSET_INIT(msg_queue_q_cbytes, "msg_queue", "q_cbytes");
+	MEMBER_OFFSET_INIT(msg_queue_q_qnum, "msg_queue", "q_qnum");
+	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(sem_array, "sem_array");
+	STRUCT_SIZE_INIT(msg_queue, "msg_queue");
+	STRUCT_SIZE_INIT(hstate, "hstate");
+
+	ipcs_table.hugetlbfs_f_op_addr =
+		symbol_value("hugetlbfs_file_operations");
+	if (symbol_exists("is_file_shm_hugepages")) {
+		ipcs_table.use_shm_f_op = TRUE;
+		ipcs_table.shm_f_op_addr =
+			symbol_value("shm_file_operations");
+		if (symbol_exists("shm_file_operations_huge")) {
+			ipcs_table.shm_f_op_huge_addr =
+				symbol_value("shm_file_operations_huge");
+		} else {
+			ipcs_table.shm_f_op_huge_addr = -1;
+		}
+	} else {
+		ipcs_table.use_shm_f_op = FALSE;
+		ipcs_table.shm_f_op_addr = -1;
+		ipcs_table.shm_f_op_huge_addr = -1;
+	}
+
+	if (BITS32())
+		ipcs_table.idr_bits = 5;
+	else if (BITS64())
+		ipcs_table.idr_bits = 6;
+	else
+		error(FATAL, "machdep->bits is not 32 or 64");
+}
+
+void
+cmd_ipcs(void)
+{
+	int show_summary, specified_id;
+	int id;
+	int c;
+	int shm, sem, msg;
+	int shm_v;
+
+	id = 0;
+	show_summary = 0;
+	specified_id = 0;
+	shm = 0;
+	sem = 0;
+	msg = 0;
+	shm_v = 0;
+	
+	while ((c = getopt(argcnt, args, "ui:smqM")) != EOF) {
+		switch(c) {
+			case 'u':
+				show_summary = 1;
+				break;
+			case 'i':
+				id = dtoi(optarg, FAULT_ON_ERROR, NULL);
+				specified_id = 1;
+				break;
+			case 's':
+				sem = 1;
+				break;
+			case 'm':
+				shm = 1;
+				break;
+			case 'q':
+				msg = 1;
+				break;
+			case 'M':
+				shm = 1;
+				shm_v = 1;
+				break;
+			default:
+				cmd_usage(pc->curcmd, SYNOPSIS);;
+				return;
+		}
+	}
+
+	if (specified_id && (shm + sem + msg) != 1) {
+		error(INFO, "specified one of -s -m -q together with -i option\n");
+		cmd_usage(pc->curcmd, SYNOPSIS);
+	}
+
+	ipcs_init();
+
+	if (!shm && !sem && !msg)
+		shm = sem = msg = 1;
+
+	if (show_summary && !specified_id)
+		open_tmpfile();
+
+	if (shm)
+		dump_shared_memory(specified_id, id, shm_v);
+	if (sem)
+		dump_semaphore_arrays(specified_id, id);
+	if (msg)
+		dump_message_queues(specified_id, id);
+
+	if (show_summary && !specified_id) {
+		close_tmpfile();
+		if (shm)
+			display_shm_summary();
+		if (sem)
+			display_sem_summary();
+		if (msg)
+			display_msg_summary();
+	}
+}
+
+static void
+dump_shared_memory(int specified_id, int id, int shm_v)
+{
+	ulong cur_task = CURRENT_TASK();
+	ulong nsproxy_p, ipc_ns_p;
+	ulong ipc_ids_p;
+	void (*ipc_search)(ulong, int, 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];
+
+	if (!specified_id) {
+		fprintf(fp, "------ Shared Memory Segments ------\n");
+
+		if (shm_v) {
+			fprintf(fp, "%s %s %s %s %s\n",
+				mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
+					LJUST, "SHM_KERNEL"),
+				mkstring(buf1, 10, LJUST, "SHMID"),
+				mkstring(buf2, 10, LJUST, "RSS"),
+				mkstring(buf3, 10, LJUST, "SWAP"),
+				mkstring(buf4, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
+					LJUST, "SHM_INODE"));
+			dump_shm = dump_single_shm_verbose;
+		}
+		else {
+			fprintf(fp, "%s %s %s %s %s %s %s\n",
+				mkstring(buf0, 10, LJUST, "KEY"),
+				mkstring(buf1, 10, LJUST, "SHMID"),
+				mkstring(buf2, 10, LJUST, "UID"),
+				mkstring(buf3, 10, LJUST, "PERMS"),
+				mkstring(buf4, 10, LJUST, "BYTES"),
+				mkstring(buf5, 10, LJUST, "NATTCH"),
+				mkstring(buf6, 12, LJUST, "STATUS"));
+			dump_shm = dump_single_shm;
+		}
+	} else
+		dump_shm = dump_specified_shm;
+
+	if (VALID_MEMBER(kern_ipc_perm_id)) {
+		ipc_search = ipc_search_idr;
+	} else {
+		ipc_search = ipc_search_array;
+	}
+
+	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;
+
+		if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
+			readmem(ipc_ns_p + OFFSET(ipc_namespace_ids) +
+				sizeof(ulong) * 2, KVADDR, &ipc_ids_p,
+				sizeof(ulong), "ipc_namespace.ids[2]",
+				FAULT_ON_ERROR);
+		else
+			ipc_ids_p = ipc_ns_p + OFFSET(ipc_namespace_ids) +
+				2 * SIZE(ipc_ids);
+	}
+
+	int 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;
+
+	ipc_search(ipc_ids_p, specified_id, id, dump_shm);
+}
+
+static void
+dump_semaphore_arrays(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, int (*)(ulong, int));
+	int (*dump_sem)(ulong, int);
+	char buf0[BUFSIZE];
+	char buf1[BUFSIZE];
+	char buf2[BUFSIZE];
+	char buf3[BUFSIZE];
+	char buf4[BUFSIZE];
+
+	if(!specified_id) {
+		fprintf(fp, "------ Semaphore Arrays --------\n");
+		fprintf(fp, "%s %s %s %s %s\n",
+			mkstring(buf0, 10, LJUST, "KEY"),
+			mkstring(buf1, 10, LJUST, "SEMID"),
+			mkstring(buf2, 10, LJUST, "UID"),
+			mkstring(buf3, 10, LJUST, "PERMS"),
+			mkstring(buf4, 10, LJUST, "NSEMS"));
+		dump_sem = dump_single_sem;;
+	} else
+		dump_sem = dump_specified_sem;
+	
+	if (VALID_MEMBER(kern_ipc_perm_id)) {
+		ipc_search = ipc_search_idr;
+	} else {
+		ipc_search = ipc_search_array;
+	}
+
+	if (symbol_exists("sem_ids")) {
+		ipc_ids_p = symbol_value("sem_ids");
+		int semaem;
+		readmem(symbol_value("used_sems"), KVADDR, &semaem, sizeof(int),
+			"used_sems", FAULT_ON_ERROR);
+		total_sem_info.semaem = semaem;
+	} 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 semaem;
+		readmem(ipc_ns_p + OFFSET(ipc_namespace_used_sems), KVADDR,
+			&semaem, sizeof(int), "ipc_namespace.used_sems",
+			FAULT_ON_ERROR);
+		total_sem_info.semaem = semaem;
+
+		if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
+			readmem(ipc_ns_p + OFFSET(ipc_namespace_ids), KVADDR,
+				&ipc_ids_p, sizeof(ulong),
+				"ipc_namespace.ids[2]",	FAULT_ON_ERROR);
+		else
+			ipc_ids_p = ipc_ns_p + OFFSET(ipc_namespace_ids);
+	}
+
+	int semusz;
+	readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &semusz,
+			sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
+	total_sem_info.semusz = semusz;
+
+	ipc_search(ipc_ids_p, specified_id, id, dump_sem);
+}
+
+static void
+dump_message_queues(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, int (*)(ulong, int));
+	int (*dump_msg)(ulong, int);
+	char buf0[BUFSIZE];
+	char buf1[BUFSIZE];
+	char buf2[BUFSIZE];
+	char buf3[BUFSIZE];
+	char buf4[BUFSIZE];
+	char buf5[BUFSIZE];
+
+	if(!specified_id) {
+		fprintf(fp, "------ Message Queues --------\n");
+		fprintf(fp, "%s %s %s %s %s %s\n",
+			mkstring(buf0, 10, LJUST, "KEY"),
+			mkstring(buf1, 10, LJUST, "MSQID"),
+			mkstring(buf2, 10, LJUST, "UID"),
+			mkstring(buf3, 10, LJUST, "PERMS"),
+			mkstring(buf4, 12, LJUST, "USED-BYTES"),
+			mkstring(buf5, 12, LJUST, "MESSAGES"));
+		dump_msg = dump_single_msg;
+	} else
+		dump_msg = dump_specified_msg;
+	
+	if (VALID_MEMBER(kern_ipc_perm_id)) {
+		ipc_search = ipc_search_idr;
+	} else {
+		ipc_search = ipc_search_array;
+	}
+
+	if (symbol_exists("msg_ids")) {
+		ipc_ids_p = symbol_value("msg_ids");
+	} 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);
+
+		if (MEMBER_SIZE("ipc_namespace","ids") == sizeof(ulong) * 3)
+			readmem(ipc_ns_p + OFFSET(ipc_namespace_ids) +
+				sizeof(ulong), KVADDR, &ipc_ids_p,
+				sizeof(ulong), "ipc_namespace.ids[2]",
+				FAULT_ON_ERROR);
+		else
+			ipc_ids_p = ipc_ns_p + OFFSET(ipc_namespace_ids) +
+				SIZE(ipc_ids);
+	}
+
+	int msgmap;
+	int msgtql;
+
+	if (VALID_MEMBER(ipc_namespace_msg_hdrs)) {
+		readmem(ipc_ns_p + OFFSET(ipc_namespace_msg_hdrs), KVADDR,
+			&msgmap, sizeof(int), "ipc_namespace.msg_hdrs",
+			FAULT_ON_ERROR);
+		readmem(ipc_ns_p + OFFSET(ipc_namespace_msg_bytes), KVADDR,
+			&msgtql, sizeof(int), "ipc_namespace.msg_bytes",
+			FAULT_ON_ERROR);
+	} else {
+		readmem(symbol_value("msg_hdrs"), KVADDR, &msgmap, sizeof(int),
+			"msg_hdrs", FAULT_ON_ERROR);
+		readmem(symbol_value("msg_bytes"), KVADDR, &msgtql, sizeof(int),
+			"msg_bytes", FAULT_ON_ERROR);
+	}
+
+	total_msg_info.msgmap = msgmap;
+	total_msg_info.msgtql = msgtql;
+
+	int msgpool;
+	readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &msgpool,
+		sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
+	total_msg_info.msgpool = msgpool;
+
+	ipc_search(ipc_ids_p, specified_id, id, dump_msg);
+}
+
+/*
+ * if shared memory information is stored in an array, use this function.
+ */
+static void
+ipc_search_array(ulong ipc_ids_p, int specified_id, int id, int (*fn)(ulong, int))
+{
+	ulong entries_p;
+	int max_id, i;
+	ulong *array;
+	int found = 0;
+
+	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);
+
+	if (!specified_id && max_id < 0) {
+		fprintf(fp, "(none allocated)");
+		return;
+	}
+
+	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)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (specified_id && !found)
+		fprintf(fp, "(none found)\n");
+
+	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 specified_id, int id, int (*fn)(ulong, int))
+{
+	int in_use;
+	ulong ipcs_idr_p;
+	ulong ipc;
+	int next_id, total;
+	int found = 0;
+
+	readmem(ipc_ids_p + OFFSET(ipc_ids_in_use), KVADDR, &in_use, 
+		sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
+
+	ipcs_idr_p = ipc_ids_p + OFFSET(ipc_ids_ipcs_idr);
+
+	if (!specified_id && !in_use)
+		fprintf(fp, "(none allocated)\n");
+
+	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)) {
+			found = 1;
+			break;
+		}
+	}
+	
+	if (specified_id && !found)
+		fprintf(fp, "(none found)\n");
+}
+
+/*
+ * search every idr_layer
+ */
+static ulong
+idr_find(ulong idp, int id)
+{
+	ulong idr_layer_p;
+	int layer;
+	int idr_layers;
+	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;
+
+	if (VALID_MEMBER(idr_layer_layer)) {
+		readmem(idr_layer_p + OFFSET(idr_layer_layer), KVADDR, &layer,
+			sizeof(int), "idr_layer.layer", FAULT_ON_ERROR);
+		n = (layer + 1) * ipcs_table.idr_bits;
+	} else {
+		readmem(idp + OFFSET(idr_layers), KVADDR, &idr_layers,
+			sizeof(int), "idr.layers", FAULT_ON_ERROR);
+		n = idr_layers * ipcs_table.idr_bits;
+	}
+	id &= MAX_ID_MASK;
+
+	if (id >= (1 << n))
+		return 0;
+
+	while (n > 0 && idr_layer_p) {
+		n -= ipcs_table.idr_bits;
+		index = (id >> n) & ((1 << ipcs_table.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;
+
+	get_shm_info(&shm_info, shp);
+	
+	if (shm_info.deleted)
+		return 0;
+
+	fprintf(fp, "0x%08x %-10d %-10d %-10o %-10ld %-10ld %-6s %-6s\n",
+		shm_info.key,
+		shm_info.shmid,
+		shm_info.uid,
+		shm_info.perms & 0777,
+		shm_info.bytes,
+		shm_info.nattch,
+		shm_info.perms & SHM_DEST ? "dest" : " ",
+		shm_info.perms & SHM_LOCKED ? "locked" : " ");
+
+	return 0;
+}
+
+static int
+dump_single_shm_verbose(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 %-10d %-10ld %-10ld %s\n",
+		mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
+			LJUST|LONG_HEX,	(char *)shm_info.shm_kernel),
+		shm_info.shmid,
+		shm_info.rss,
+		shm_info.swap,
+		mkstring(buf1, VADDR_PRLEN <= 10 ? 10 : 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 + PAGESIZE() - 1) >> PAGESHIFT());
+		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\n",
+			total_shm_info.swap_successes);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+dump_single_sem(ulong shp, int id)
+{
+	struct sem_info sem_info;
+
+	get_sem_info(&sem_info, shp);
+
+	if (sem_info.deleted)
+		return 0;
+
+	fprintf(fp, "0x%08x %-10d %-10d %-10o %-10ld\n",
+		sem_info.key,
+		sem_info.semid,
+		sem_info.uid,
+		sem_info.perms & 0777,
+		sem_info.nsems);
+
+	return 0;
+}
+
+static int
+dump_specified_sem(ulong shp, int id)
+{
+	struct sem_info sem_info;
+
+	get_sem_info(&sem_info, shp);
+
+	if (sem_info.semid == id) {
+		fprintf(fp, "SEMID: %d\n", sem_info.semid);
+		fprintf(fp ,"------ Semaphore Status --------\n");
+		fprintf(fp, "used arrays          %d\n", total_sem_info.semusz);
+		fprintf(fp, "allocated semaphores %ld\n", sem_info.nsems);
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+dump_single_msg(ulong shp, int id)
+{
+	struct msg_info msg_info;
+
+	get_msg_info(&msg_info, shp);
+
+	if (msg_info.deleted)
+		return 0;
+
+	fprintf(fp, "0x%08x %-10d %-10d %-10o %-12ld %-12ld\n",
+		msg_info.key,
+		msg_info.msgid,
+		msg_info.uid,
+		msg_info.perms & 0777,
+		msg_info.bytes,
+		msg_info.messages);
+
+	return 0;
+}
+
+static int
+dump_specified_msg(ulong shp, int id)
+{
+	struct msg_info msg_info;
+
+	get_msg_info(&msg_info, shp);
+
+	if (msg_info.msgid == id) {
+		fprintf(fp, "MSGID: %d\n", msg_info.msgid);
+		fprintf(fp ,"------ Message Status --------\n");
+		fprintf(fp, "allocated queues %d\n", total_msg_info.msgpool);
+		fprintf(fp, "used headers     %ld\n", msg_info.messages);
+		fprintf(fp, "used space       %ld\n", msg_info.bytes);
+		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));
+}
+
+static void
+get_sem_info(struct sem_info *sem_info, ulong shp)
+{
+	ulong sem_array_p;
+	char buf[BUFSIZE];
+	
+	sem_array_p = shp - OFFSET(sem_array_sem_perm);
+
+	//cache sem_array
+	readmem(sem_array_p, KVADDR, buf, SIZE(sem_array), "sem_array",
+		FAULT_ON_ERROR);
+
+	sem_info->key = INT(buf + OFFSET(sem_array_sem_perm) +
+			OFFSET(kern_ipc_perm_key));
+
+	if (VALID_MEMBER(sem_array_sem_id))
+		sem_info->semid = INT(buf + OFFSET(sem_array_sem_id));
+	else
+		sem_info->semid = INT(buf + OFFSET(sem_array_sem_perm) +
+				OFFSET(kern_ipc_perm_id));
+
+	sem_info->uid = UINT(buf + OFFSET(sem_array_sem_perm) +
+			OFFSET(kern_ipc_perm_uid));
+
+	if (BITS32())
+		sem_info->perms = USHORT(buf + OFFSET(sem_array_sem_perm) +
+				OFFSET(kern_ipc_perm_mode));
+	else
+		sem_info->perms = UINT(buf + OFFSET(sem_array_sem_perm) +
+				OFFSET(kern_ipc_perm_mode));
+
+	sem_info->nsems = ULONG(buf + OFFSET(sem_array_sem_nsems));
+
+	sem_info->deleted = UINT(buf + OFFSET(sem_array_sem_perm) +
+				OFFSET(kern_ipc_perm_deleted));
+}
+
+static void
+get_msg_info(struct msg_info *msg_info, ulong shp)
+{
+	ulong msg_queue_p;
+	char buf[BUFSIZE];
+
+	msg_queue_p = shp - OFFSET(msg_queue_q_perm);
+
+	//cache msg_queue;
+	readmem(msg_queue_p, KVADDR, buf, SIZE(msg_queue), "msg_queue",
+		FAULT_ON_ERROR);
+
+	msg_info->key = INT(buf + OFFSET(msg_queue_q_perm) +
+			OFFSET(kern_ipc_perm_key));
+
+	if (VALID_MEMBER(msg_queue_q_id))
+		msg_info->msgid = INT(buf + OFFSET(msg_queue_q_id));
+	else
+		msg_info->msgid = INT(buf + OFFSET(msg_queue_q_perm) +
+				OFFSET(kern_ipc_perm_id));
+
+	msg_info->uid = UINT(buf + OFFSET(msg_queue_q_perm) +
+			OFFSET(kern_ipc_perm_uid));
+
+	if (BITS32())
+		msg_info->perms = USHORT(buf + OFFSET(msg_queue_q_perm) +
+				OFFSET(kern_ipc_perm_mode));
+	else
+		msg_info->perms = UINT(buf + OFFSET(msg_queue_q_perm) +
+				OFFSET(kern_ipc_perm_mode));
+
+	msg_info->bytes = ULONG(buf + OFFSET(msg_queue_q_cbytes));
+
+	msg_info->messages = ULONG(buf + OFFSET(msg_queue_q_qnum));
+	
+	msg_info->deleted = UINT(buf + OFFSET(msg_queue_q_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) / PAGESIZE();
+		}
+		*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 == ipcs_table.hugetlbfs_f_op_addr)
+		return 1;
+
+	if (ipcs_table.use_shm_f_op) {
+		if (ipcs_table.shm_f_op_huge_addr != -1) {
+			if (f_op == ipcs_table.shm_f_op_huge_addr)
+				return 1;
+		} else {
+			if (f_op == ipcs_table.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_shm_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\n",
+			total_shm_info.swap_successes);
+	fprintf(fp ,"\n");
+}
+
+static void
+display_sem_summary()
+{
+	fprintf(fp, "------ Semaphore Status --------\n");
+	fprintf(fp, "used arrays = %d\n", total_sem_info.semusz);
+	fprintf(fp, "allocated semaphores = %d\n", total_sem_info.semaem);
+	fprintf(fp, "\n");
+}
+
+static void
+display_msg_summary()
+{
+	fprintf(fp, "------ Messages Status --------\n");
+	fprintf(fp, "allocated queues = %d\n", total_msg_info.msgpool);
+	fprintf(fp, "used headers = %d\n", total_msg_info.msgmap);
+	fprintf(fp, "used space = %d bytes", total_msg_info.msgtql);
+	fprintf(fp, "\n");
+}
diff --git a/symbols.c b/symbols.c
index 69a54f6..0dac66b 100755
--- a/symbols.c
+++ b/symbols.c
@@ -8684,6 +8684,89 @@ dump_offset_table(char *spec, ulong makestruct)
 	fprintf(fp, "                subsystem_kset: %ld\n",
 		OFFSET(subsystem_kset));
 
+	fprintf(fp, "                     file_f_op: %ld\n",
+		OFFSET(file_f_op));
+	fprintf(fp, "             file_private_data: %ld\n",
+		OFFSET(file_private_data));
+	fprintf(fp, "                  hstate_order: %ld\n",
+		OFFSET(hstate_order));
+	fprintf(fp, "      hugetlbfs_sb_info_hstate: %ld\n",
+		OFFSET(hugetlbfs_sb_info_hstate));
+	fprintf(fp, "                 idr_layer_ary: %ld\n",
+		OFFSET(idr_layer_ary));
+	fprintf(fp, "               idr_layer_layer: %ld\n",
+		OFFSET(idr_layer_layer));
+	fprintf(fp, "                    idr_layers: %ld\n",
+		OFFSET(idr_layers));
+	fprintf(fp, "                       idr_top: %ld\n",
+		OFFSET(idr_top));
+	fprintf(fp, "                  ipc_id_ary_p: %ld\n",
+		OFFSET(ipc_id_ary_p));
+	fprintf(fp, "               ipc_ids_entries: %ld\n",
+		OFFSET(ipc_ids_entries));
+	fprintf(fp, "                ipc_ids_max_id: %ld\n",
+		OFFSET(ipc_ids_max_id));
+	fprintf(fp, "              ipc_ids_ipcs_idr: %ld\n",
+		OFFSET(ipc_ids_ipcs_idr));
+	fprintf(fp, "                ipc_ids_in_use: %ld\n",
+		OFFSET(ipc_ids_in_use));
+	fprintf(fp, "             ipc_namespace_ids: %ld\n",
+		OFFSET(ipc_namespace_ids));
+	fprintf(fp, "         ipc_namespace_shm_tot: %ld\n",
+		OFFSET(ipc_namespace_shm_tot));
+	fprintf(fp, "       ipc_namespace_used_sems: %ld\n",
+		OFFSET(ipc_namespace_used_sems));
+	fprintf(fp, "        ipc_namespace_msg_hdrs: %ld\n",
+		OFFSET(ipc_namespace_msg_hdrs));
+	fprintf(fp, "       ipc_namespace_msg_bytes: %ld\n",
+		OFFSET(ipc_namespace_msg_bytes));
+	fprintf(fp, "         kern_ipc_perm_deleted: %ld\n",
+		OFFSET(kern_ipc_perm_deleted));
+	fprintf(fp, "             kern_ipc_perm_key: %ld\n",
+		OFFSET(kern_ipc_perm_key));
+	fprintf(fp, "            kern_ipc_perm_mode: %ld\n",
+		OFFSET(kern_ipc_perm_mode));
+	fprintf(fp, "             kern_ipc_perm_seq: %ld\n",
+		OFFSET(kern_ipc_perm_seq));
+	fprintf(fp, "             kern_ipc_perm_uid: %ld\n",
+		OFFSET(kern_ipc_perm_uid));
+	fprintf(fp, "              kern_ipc_perm_id: %ld\n",
+		OFFSET(kern_ipc_perm_id));
+	fprintf(fp, "                nsproxy_ipc_ns: %ld\n",
+		OFFSET(nsproxy_ipc_ns));
+	fprintf(fp, "      shmem_inode_info_swapped: %ld\n",
+		OFFSET(shmem_inode_info_swapped));
+	fprintf(fp, "    shmem_inode_info_vfs_inode: %ld\n",
+		OFFSET(shmem_inode_info_vfs_inode));
+	fprintf(fp, "            shm_file_data_file: %ld\n",
+		OFFSET(shm_file_data_file));
+	fprintf(fp, "         shmid_kernel_shm_file: %ld\n",
+		OFFSET(shmid_kernel_shm_file));
+	fprintf(fp, "       shmid_kernel_shm_nattch: %ld\n",
+		OFFSET(shmid_kernel_shm_nattch));
+	fprintf(fp, "         shmid_kernel_shm_perm: %ld\n",
+		OFFSET(shmid_kernel_shm_perm));
+	fprintf(fp, "        shmid_kernel_shm_segsz: %ld\n",
+		OFFSET(shmid_kernel_shm_segsz));
+	fprintf(fp, "               shmid_kernel_id: %ld\n",
+		OFFSET(shmid_kernel_id));
+	fprintf(fp, "            sem_array_sem_perm: %ld\n",
+		OFFSET(sem_array_sem_perm));
+	fprintf(fp, "              sem_array_sem_id: %ld\n",
+		OFFSET(sem_array_sem_id));
+	fprintf(fp, "           sem_array_sem_nsems: %ld\n",
+		OFFSET(sem_array_sem_nsems));
+	fprintf(fp, "              msg_queue_q_perm: %ld\n",
+		OFFSET(msg_queue_q_perm));
+	fprintf(fp, "                msg_queue_q_id: %ld\n",
+		OFFSET(msg_queue_q_id));
+	fprintf(fp, "            msg_queue_q_cbytes: %ld\n",
+		OFFSET(msg_queue_q_cbytes));
+	fprintf(fp, "              msg_queue_q_qnum: %ld\n",
+		OFFSET(msg_queue_q_qnum));
+	fprintf(fp, "         super_block_s_fs_info: %ld\n",
+		OFFSET(super_block_s_fs_info));
+
 	fprintf(fp, "\n                    size_table:\n");
 	fprintf(fp, "                          page: %ld\n", SIZE(page));
 	fprintf(fp, "                    page_flags: %ld\n", SIZE(page_flags));
@@ -8884,6 +8967,16 @@ dump_offset_table(char *spec, ulong makestruct)
 		SIZE(rq_in_flight));
 	fprintf(fp, "         class_private_devices: %ld\n",
 		SIZE(class_private_devices));
+	fprintf(fp, "                        hstate: %ld\n",
+		SIZE(hstate));
+	fprintf(fp, "                       ipc_ids: %ld\n",
+		SIZE(ipc_ids));
+	fprintf(fp, "                  shmid_kernel: %ld\n",
+		SIZE(shmid_kernel));
+	fprintf(fp, "                     sem_array: %ld\n",
+		SIZE(sem_array));
+	fprintf(fp, "                     msg_queue: %ld\n",
+		SIZE(msg_queue));
 
         fprintf(fp, "\n                   array_table:\n");
 	/*
-- 
1.7.1

