Hello Dave,
The patch has been changed into an extension module. And the option and
its related output is changed as well. Please check.
--
--
Regards
Qiao Nuohan
/* ipcs.c - provide information on ipc facilities
*
* Copyright (C) 2012 FUJITSU LIMITED
* Auther: Qiao Nuohan <qiaonuohan@xxxxxxxxxxxxxx>
*
* 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" /* From the crash source top-level directory */
#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
#define IPCS_MEMBER_OFFSET_INIT(X, Y, Z) (ipcs_offset_table.X = MEMBER_OFFSET(Y, Z))
#define IPCS_ANON_MEMBER_OFFSET_INIT(X, Y, Z) (ipcs_offset_table.X = ANON_MEMBER_OFFSET(Y, Z))
#define IPCS_STRUCT_SIZE_INIT(X, Y) (ipcs_size_table.X = STRUCT_SIZE(Y))
#define IPCS_OFFSET(X) (OFFSET_verify(ipcs_offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define IPCS_SIZE(X) (SIZE_verify(ipcs_size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define IPCS_INVALID_MEMBER(X) (ipcs_offset_table.X == INVALID_OFFSET)
#define IPCS_INVALID_SIZE(X) (ipcs_size_table.X == -1)
#define IPCS_VALID_SIZE(X) (ipcs_size_table.X >= 0)
#define IPCS_VALID_STRUCT(X) (ipcs_size_table.X >= 0)
#define IPCS_VALID_MEMBER(X) (ipcs_offset_table.X >= 0)
/*
* struct declaration
*/
struct ipcs_offset_table {
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_uid;
long kern_ipc_perm_id;
long kern_ipc_perm_seq;
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 ipcs_size_table {
long hstate;
long ipc_ids;
long shmid_kernel;
long sem_array;
long msg_queue;
};
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 {
ulong sem_array;
int key;
int semid;
unsigned int uid;
unsigned int perms;
ulong nsems;
int deleted;
};
struct msg_info {
ulong msg_queue;
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;
int seq_multiplier;
};
/*
* function declaration
*/
int _init(void);
int _fini(void);
void cmd_ipcs(void); /* Declare the commands and their help data. */
char *help_ipcs[];
static void ipcs_init(void);
static void dump_shared_memory(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, int));
static void ipc_search_array(ulong, int, int, int (*)(ulong, int, int));
static ulong idr_find(ulong, int);
static int dump_single_shm(ulong, int, int);
static int dump_specified_shm(ulong, int, int);
static int dump_single_sem(ulong, int, int);
static int dump_specified_sem(ulong, int, int);
static int dump_single_msg(ulong, int, int);
static int dump_specified_msg(ulong, int, int);
static void get_shm_info(struct shm_info *, ulong, int);
static void get_sem_info(struct sem_info *, ulong, int);
static void get_msg_info(struct msg_info *, ulong, int);
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);
static struct command_table_entry command_table[] = {
{ "ipcs", cmd_ipcs, help_ipcs, 0 }, /* One or more commands, */
{ NULL } /* terminated by NULL, */
};
/*
* global data
*/
static struct ipcs_offset_table ipcs_offset_table = { 0 };
static struct ipcs_size_table ipcs_size_table = { 0 };
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 };
int
_init(void) /* Register the command set. */
{
register_extension(command_table);
return 1;
}
/*
* The _fini() function is called if the shared object is unloaded.
* If desired, perform any cleanups here.
*/
int
_fini(void)
{
return 1;
}
static void
ipcs_init(void)
{
if (ipcs_table.init_flags & IPCS_INIT) {
return;
}
ipcs_table.init_flags |= IPCS_INIT;
IPCS_MEMBER_OFFSET_INIT(file_f_op, "file", "f_op");
IPCS_MEMBER_OFFSET_INIT(file_private_data, "file", "private_data");
IPCS_MEMBER_OFFSET_INIT(hstate_order, "hstate", "order");
IPCS_MEMBER_OFFSET_INIT(hugetlbfs_sb_info_hstate, "hugetlbfs_sb_info",
"hstate");
IPCS_MEMBER_OFFSET_INIT(idr_layers, "idr", "layers");
IPCS_MEMBER_OFFSET_INIT(idr_layer_layer, "idr_layer", "layer");
IPCS_MEMBER_OFFSET_INIT(idr_layer_ary, "idr_layer", "ary");
IPCS_MEMBER_OFFSET_INIT(idr_top, "idr", "top");
IPCS_MEMBER_OFFSET_INIT(ipc_id_ary_p, "ipc_id_ary", "p");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_entries, "ipc_ids", "entries");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_max_id, "ipc_ids", "max_id");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_in_use, "ipc_ids", "in_use");
IPCS_MEMBER_OFFSET_INIT(ipc_ids_ipcs_idr, "ipc_ids", "ipcs_idr");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_ids, "ipc_namespace", "ids");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_shm_tot, "ipc_namespace",
"shm_tot");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_used_sems, "ipc_namespace",
"used_sems");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_msg_hdrs, "ipc_namespace",
"msg_hdrs");
IPCS_MEMBER_OFFSET_INIT(ipc_namespace_msg_bytes, "ipc_namespace",
"msg_bytes");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_key, "kern_ipc_perm", "key");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_id, "kern_ipc_perm", "id");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_uid, "kern_ipc_perm", "uid");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_mode, "kern_ipc_perm", "mode");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_deleted, "kern_ipc_perm",
"deleted");
IPCS_MEMBER_OFFSET_INIT(kern_ipc_perm_seq, "kern_ipc_perm", "seq");
IPCS_MEMBER_OFFSET_INIT(nsproxy_ipc_ns, "nsproxy", "ipc_ns");
IPCS_MEMBER_OFFSET_INIT(shmem_inode_info_vfs_inode, "shmem_inode_info",
"vfs_inode");
IPCS_MEMBER_OFFSET_INIT(shmem_inode_info_swapped, "shmem_inode_info",
"swapped");
if (IPCS_INVALID_MEMBER(shmem_inode_info_swapped))
IPCS_ANON_MEMBER_OFFSET_INIT(shmem_inode_info_swapped,
"shmem_inode_info", "swapped");
IPCS_MEMBER_OFFSET_INIT(shm_file_data_file, "shm_file_data", "file");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_perm, "shmid_kernel",
"shm_perm");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_segsz, "shmid_kernel",
"shm_segsz");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_nattch, "shmid_kernel",
"shm_nattch");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_shm_file, "shmid_kernel",
"shm_file");
IPCS_MEMBER_OFFSET_INIT(shmid_kernel_id, "shmid_kernel", "id");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_perm, "sem_array", "sem_perm");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_id, "sem_array", "sem_id");
IPCS_MEMBER_OFFSET_INIT(sem_array_sem_nsems, "sem_array", "sem_nsems");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_perm, "msg_queue", "q_perm");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_id, "msg_queue", "q_id");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_cbytes, "msg_queue", "q_cbytes");
IPCS_MEMBER_OFFSET_INIT(msg_queue_q_qnum, "msg_queue", "q_qnum");
IPCS_MEMBER_OFFSET_INIT(super_block_s_fs_info, "super_block",
"s_fs_info");
/*
* struct size
*/
IPCS_STRUCT_SIZE_INIT(ipc_ids, "ipc_ids");
IPCS_STRUCT_SIZE_INIT(shmid_kernel, "shmid_kernel");
IPCS_STRUCT_SIZE_INIT(sem_array, "sem_array");
IPCS_STRUCT_SIZE_INIT(msg_queue, "msg_queue");
IPCS_STRUCT_SIZE_INIT(hstate, "hstate");
if (symbol_exists("hugetlbfs_file_operations"))
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");
ipcs_table.seq_multiplier = 32768;
}
/*
* Arguments are passed to the command functions in the global args[argcnt]
* array. See getopt(3) for info on dash arguments. Check out defs.h and
* other crash commands for usage of the myriad of utility routines available
* to accomplish what your task.
*/
void
cmd_ipcs(void)
{
int show_summary, specified;
int specified_id;
int c;
int shm, sem, msg;
specified_id = 0;
show_summary = 0;
specified = 0;
shm = 0;
sem = 0;
msg = 0;
while ((c = getopt(argcnt, args, "ui:smq")) != EOF) {
switch(c) {
case 'u':
show_summary = 1;
break;
case 'i':
specified_id =
dtoi(optarg, FAULT_ON_ERROR, NULL);
specified = 1;
break;
case 's':
sem = 1;
break;
case 'm':
shm = 1;
break;
case 'q':
msg = 1;
break;
default:
cmd_usage(pc->curcmd, SYNOPSIS);;
return;
}
}
if (specified && (shm + sem + msg) != 1) {
error(INFO,
"specified one of -s -m -q together with -i option\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
if (THIS_KERNEL_VERSION < LINUX(2,6,0))
command_not_supported();
ipcs_init();
if (!shm && !sem && !msg)
shm = sem = msg = 1;
if (show_summary && !specified)
open_tmpfile();
if (shm)
dump_shared_memory(specified, specified_id);
if (sem)
dump_semaphore_arrays(specified, specified_id);
if (msg)
dump_message_queues(specified, specified_id);
if (show_summary && !specified) {
close_tmpfile();
if (shm)
display_shm_summary();
if (sem)
display_sem_summary();
if (msg)
display_msg_summary();
}
}
char *help_ipcs[] = {
"ipcs", /* command name */
"provide information on ipc facilities", /* short description */
"[[-u] [-smq]] | [-i id [-smq]]", /* argument synopsis, or " " if none */
" 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 ------",
" SHM_KERNEL KEY SHMID UID PERMS BYTES NATTCH STATUS",
" ffff88046925d5d0 0x00000000 786432 0 600 393216 2 dest ",
" ffff880868747c10 0x00000000 819201 0 600 393216 2 dest ",
" ffff880859e63cd0 0x00000000 851970 0 600 393216 2 dest ",
" ffff880859e63790 0x00000000 884739 0 600 393216 2 dest ",
" ffff880859e63610 0x00000000 917508 0 600 393216 2 dest ",
" ffff88085902fed0 0x00000000 950277 0 600 393216 2 dest ",
" ffff880868041990 0x00000000 983046 0 600 393216 2 dest ",
" ffff880859e633d0 0x00000000 1015815 0 600 393216 2 dest ",
" ffff8808687479d0 0x00000000 1048584 0 600 393216 2 dest ",
" ffff880868041510 0x00000000 1081353 0 600 393216 2 dest ",
" ffff880859e63550 0x00000000 1114122 0 600 393216 2 dest ",
" ffff880859e63850 0x00000000 1146891 0 600 393216 2 dest ",
" ffff880859ecaf10 0x00000000 1179660 0 600 393216 2 dest ",
" ffff880868041d50 0x00000000 1212429 0 600 393216 2 dest ",
" ffff880408727450 0x00000000 3637262 0 600 1920000 2 dest ",
" ffff88085902f810 0x00000000 1409039 0 600 393216 2 dest ",
" ffff88085f4720d0 0x00000000 1441808 0 600 393216 2 dest ",
" ffff880868041450 0x00000000 1474577 0 600 393216 2 dest ",
" ffff880859eca850 0x00000000 3014674 0 600 393216 2 dest ",
" ffff880859eca9d0 0x00000000 3440659 0 600 393216 2 dest ",
" ffff880859ecac10 0x00000000 3473428 0 600 393216 2 dest ",
" ffff880864adea90 0x00000000 3506197 0 600 393216 2 dest ",
" ",
" ------ Semaphore Arrays --------",
" SEM_ARRAY KEY SEMID UID PERMS NSEMS ",
" ffff88046a337f10 0x00000000 0 0 600 1 ",
" ffff880869d8ed90 0x00000000 32769 0 600 1 ",
" ",
" ------ Message Queues --------",
" MSG_QUEUE KEY MSQID UID PERMS USED-BYTES MESSAGES ",
" ffff88085902f5d0 0x00000000 0 0 666 0 0 ",
" ffff88085902f150 0x00000001 32769 0 666 0 0 ",
" ffff88085902f750 0x00000002 65538 0 666 0 0 ",
" ffff88085902fd50 0x00000003 98307 0 666 0 0 ",
" ffff88085902f690 0x00000004 131076 0 666 0 0 ",
" ffff88086811b990 0x00000005 163845 0 666 0 0 ",
" ffff880864ab4310 0x00000006 196614 0 666 0 0 ",
" ffff880864ab4190 0x00000007 229383 0 666 0 0 ",
" ffff880864ab4250 0x00000008 262152 0 666 0 0 ",
" ffff880864ab40d0 0x00000009 294921 0 666 0 0 ",
" ",
" display summary:\n",
" %s> ipcs -u",
" ------ Shared Memroy Status --------",
" segments allocated 22",
" pages allocatd 2485",
" pages resident 4872",
" pages swapped 0",
" swap performance attemts 0",
" swap performance successes 0",
" ",
" ------ Semaphore Status --------",
" used arrays = 2",
" allocated semaphores = 2",
" ",
" ------ Messages Status --------",
" allocated queues = 10",
" used headers = 0",
" used space = 0 bytes",
" ",
" display a specified resource:\n",
" %s> ipcs -u -i 458766",
" SHMID: 1048584",
" ------ Shared Memroy Status --------",
" segments allocated 22",
" pages allocatd 96",
" pages resident 72",
" pages swapped 0",
" swap performance attemts 0",
" swap performance successes 0",
" vfs_inode 0xffff880868092a98",
NULL
};
static void
dump_shared_memory(int specified, int specified_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));
int (*dump_shm)(ulong, int, 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];
if (!specified) {
fprintf(fp, "------ Shared Memory Segments ------\n");
fprintf(fp, "%s %s %s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
LJUST, "SHM_KERNEL"),
mkstring(buf1, 10, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "SHMID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 10, LJUST, "BYTES"),
mkstring(buf6, 6, LJUST, "NATTCH"),
mkstring(buf7, 6, LJUST, "STATUS"));
dump_shm = dump_single_shm;
} else
dump_shm = dump_specified_shm;
if (IPCS_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);
if (!readmem(nsproxy_p + IPCS_OFFSET(nsproxy_ipc_ns), KVADDR,
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
RETURN_ON_ERROR|QUIET))
error(FATAL,
"cannot determine ipc_namespace location!\n");
int shm_tot;
readmem(ipc_ns_p + IPCS_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 + IPCS_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 + IPCS_OFFSET(ipc_namespace_ids) +
2 * IPCS_SIZE(ipc_ids);
}
int in_use;
readmem(ipc_ids_p + IPCS_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, specified_id, dump_shm);
fprintf(fp, "\n");
}
static void
dump_semaphore_arrays(int specified, int specified_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));
int (*dump_sem)(ulong, int, int);
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
if(!specified) {
fprintf(fp, "------ Semaphore Arrays --------\n");
fprintf(fp, "%s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
LJUST, "SEM_ARRAY"),
mkstring(buf1, 10, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "SEMID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 10, LJUST, "NSEMS"));
dump_sem = dump_single_sem;;
} else
dump_sem = dump_specified_sem;
if (IPCS_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 + IPCS_OFFSET(nsproxy_ipc_ns), KVADDR,
&ipc_ns_p, sizeof(ulong), "nsproxy.ipc_ns",
FAULT_ON_ERROR);
int semaem;
readmem(ipc_ns_p + IPCS_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 + IPCS_OFFSET(ipc_namespace_ids),
KVADDR, &ipc_ids_p, sizeof(ulong),
"ipc_namespace.ids[2]", FAULT_ON_ERROR);
else
ipc_ids_p = ipc_ns_p + IPCS_OFFSET(ipc_namespace_ids);
}
int semusz;
readmem(ipc_ids_p + IPCS_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, specified_id, dump_sem);
fprintf(fp, "\n");
}
static void
dump_message_queues(int specified, int specified_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));
int (*dump_msg)(ulong, int, int);
char buf0[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
char buf5[BUFSIZE];
char buf6[BUFSIZE];
if(!specified) {
fprintf(fp, "------ Message Queues --------\n");
fprintf(fp, "%s %s %s %s %s %s %s\n",
mkstring(buf0, VADDR_PRLEN<=10?10:VADDR_PRLEN,
LJUST, "MSG_QUEUE"),
mkstring(buf1, 10, LJUST, "KEY"),
mkstring(buf2, 10, LJUST, "MSQID"),
mkstring(buf3, 5, LJUST, "UID"),
mkstring(buf4, 5, LJUST, "PERMS"),
mkstring(buf5, 12, LJUST, "USED-BYTES"),
mkstring(buf6, 12, LJUST, "MESSAGES"));
dump_msg = dump_single_msg;
} else
dump_msg = dump_specified_msg;
if (IPCS_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 + IPCS_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 + IPCS_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 + IPCS_OFFSET(ipc_namespace_ids) +
IPCS_SIZE(ipc_ids);
}
int msgmap;
int msgtql;
if (IPCS_VALID_MEMBER(ipc_namespace_msg_hdrs)) {
readmem(ipc_ns_p + IPCS_OFFSET(ipc_namespace_msg_hdrs), KVADDR,
&msgmap, sizeof(int), "ipc_namespace.msg_hdrs",
FAULT_ON_ERROR);
readmem(ipc_ns_p + IPCS_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 + IPCS_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, specified_id, dump_msg);
fprintf(fp, "\n");
}
/*
* if shared memory information is stored in an array, use this function.
*/
static void
ipc_search_array(ulong ipc_ids_p, int specified, int specified_id, int (*fn)(ulong, int, int))
{
ulong entries_p;
int max_id, i;
ulong *array;
int found = 0;
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_entries), KVADDR, &entries_p,
sizeof(ulong), "ipc_ids.entries", FAULT_ON_ERROR);
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_max_id), KVADDR, &max_id,
sizeof(int), "ipc_ids.max_id", FAULT_ON_ERROR);
if (!specified && max_id < 0) {
fprintf(fp, "(none allocated)");
return;
}
array = (ulong *)GETBUF(sizeof(ulong *) * (max_id + 1));
if (IPCS_VALID_MEMBER(ipc_id_ary_p))
readmem(entries_p + IPCS_OFFSET(ipc_id_ary_p), KVADDR, array,
sizeof(ulong *) * (max_id + 1), "ipc_id_ary.p",
FAULT_ON_ERROR);
else
readmem(entries_p, KVADDR, array, sizeof(ulong *)*(max_id+1),
"ipc_id array", FAULT_ON_ERROR);
for (i=0; i<=max_id; i++) {
if (array[i] == 0)
continue;
if (fn(array[i], specified_id, i)) {
found = 1;
break;
}
}
if (specified && !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, int specified_id, int (*fn)(ulong, int, int))
{
int in_use;
ulong ipcs_idr_p;
ulong ipc;
int next_id, total;
int found = 0;
readmem(ipc_ids_p + IPCS_OFFSET(ipc_ids_in_use), KVADDR, &in_use,
sizeof(int), "ipc_ids.in_use", FAULT_ON_ERROR);
ipcs_idr_p = ipc_ids_p + IPCS_OFFSET(ipc_ids_ipcs_idr);
if (!specified && !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, specified_id, next_id)) {
found = 1;
break;
}
}
if (specified && !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 + IPCS_OFFSET(idr_top), KVADDR, &idr_layer_p,
sizeof(ulong), "idr.top", FAULT_ON_ERROR);
if (!idr_layer_p)
return 0;
if (IPCS_VALID_MEMBER(idr_layer_layer)) {
readmem(idr_layer_p + IPCS_OFFSET(idr_layer_layer), KVADDR,
&layer, sizeof(int), "idr_layer.layer",
FAULT_ON_ERROR);
n = (layer + 1) * ipcs_table.idr_bits;
} else {
readmem(idp + IPCS_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 + IPCS_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 specified_id, int id)
{
struct shm_info shm_info;
char buf0[BUFSIZE];
get_shm_info(&shm_info, shp, id);
if (shm_info.deleted)
return 0;
fprintf(fp, "%s 0x%08x %-10d %-5d %-5o %-10ld %-6ld %-s %-s\n",
mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)shm_info.shm_kernel),
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;
}
/*
* if the resource is specified, use this function to output information
*/
static int
dump_specified_shm(ulong shp, int specified_id, int id)
{
struct shm_info shm_info;
get_shm_info(&shm_info, shp, id);
if(shm_info.shmid == specified_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);
fprintf(fp, "vfs_inode 0x%lx", shm_info.shm_inode);
return 1;
}
return 0;
}
static int
dump_single_sem(ulong shp, int specified_id, int id)
{
struct sem_info sem_info;
char buf0[BUFSIZE];
get_sem_info(&sem_info, shp, id);
if (sem_info.deleted)
return 0;
fprintf(fp, "%s 0x%08x %-10d %-5d %-5o %-10ld\n",
mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)sem_info.sem_array),
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 specified_id, int id)
{
struct sem_info sem_info;
get_sem_info(&sem_info, shp, id);
if (sem_info.semid == specified_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 specified_id, int id)
{
struct msg_info msg_info;
char buf0[BUFSIZE];
get_msg_info(&msg_info, shp, id);
if (msg_info.deleted)
return 0;
fprintf(fp, "%s 0x%08x %-10d %-5d %-5o %-12ld %-12ld\n",
mkstring(buf0, VADDR_PRLEN <= 10 ? 10 : VADDR_PRLEN,
LJUST|LONG_HEX, (char *)msg_info.msg_queue),
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 specified_id, int id)
{
struct msg_info msg_info;
get_msg_info(&msg_info, shp, id);
if (msg_info.msgid == specified_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, int id)
{
char buf[BUFSIZE];
ulong filep, dentryp, inodep;
shm_info->shm_kernel = shp - IPCS_OFFSET(shmid_kernel_shm_perm);
//cache shmid_kernel
readmem(shm_info->shm_kernel, KVADDR, buf, IPCS_SIZE(shmid_kernel),
"shmid_kernel", FAULT_ON_ERROR);
shm_info->key = INT(buf + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(shmid_kernel_id))
shm_info->shmid = INT(buf + IPCS_OFFSET(shmid_kernel_id));
else
shm_info->shmid = INT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
shm_info->uid = UINT(buf + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
shm_info->perms = USHORT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
shm_info->perms = UINT(buf +
IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
shm_info->bytes = ULONG(buf + IPCS_OFFSET(shmid_kernel_shm_segsz));
shm_info->nattch = ULONG(buf + IPCS_OFFSET(shmid_kernel_shm_nattch));
filep = ULONG(buf + IPCS_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 + IPCS_OFFSET(shmid_kernel_shm_perm) +
IPCS_OFFSET(kern_ipc_perm_deleted));
}
static void
get_sem_info(struct sem_info *sem_info, ulong shp, int id)
{
char buf[BUFSIZE];
sem_info->sem_array = shp - IPCS_OFFSET(sem_array_sem_perm);
//cache sem_array
readmem(sem_info->sem_array, KVADDR, buf, IPCS_SIZE(sem_array),
"sem_array", FAULT_ON_ERROR);
sem_info->key = INT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(sem_array_sem_id))
sem_info->semid = INT(buf + IPCS_OFFSET(sem_array_sem_id));
else if (IPCS_VALID_MEMBER(kern_ipc_perm_id))
sem_info->semid = INT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
else {
ulong seq;
seq = ULONG(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_seq));
sem_info->semid = ipcs_table.seq_multiplier * seq + id;
}
sem_info->uid = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
sem_info->perms = USHORT(buf +
IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
sem_info->perms = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
sem_info->nsems = ULONG(buf + IPCS_OFFSET(sem_array_sem_nsems));
sem_info->deleted = UINT(buf + IPCS_OFFSET(sem_array_sem_perm) +
IPCS_OFFSET(kern_ipc_perm_deleted));
}
static void
get_msg_info(struct msg_info *msg_info, ulong shp, int id)
{
char buf[BUFSIZE];
msg_info->msg_queue = shp - IPCS_OFFSET(msg_queue_q_perm);
//cache msg_queue;
readmem(msg_info->msg_queue, KVADDR, buf, IPCS_SIZE(msg_queue),
"msg_queue", FAULT_ON_ERROR);
msg_info->key = INT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_key));
if (IPCS_VALID_MEMBER(msg_queue_q_id))
msg_info->msgid = INT(buf + IPCS_OFFSET(msg_queue_q_id));
else if (IPCS_VALID_MEMBER(kern_ipc_perm_id))
msg_info->msgid = INT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_id));
else {
ulong seq;
seq = ULONG(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_seq));
msg_info->msgid = ipcs_table.seq_multiplier * seq + id;
}
msg_info->uid = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_uid));
if (BITS32())
msg_info->perms = USHORT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
else
msg_info->perms = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_OFFSET(kern_ipc_perm_mode));
msg_info->bytes = ULONG(buf + IPCS_OFFSET(msg_queue_q_cbytes));
msg_info->messages = ULONG(buf + IPCS_OFFSET(msg_queue_q_qnum));
msg_info->deleted = UINT(buf + IPCS_OFFSET(msg_queue_q_perm) +
IPCS_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 (IPCS_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 + IPCS_OFFSET(super_block_s_fs_info),
KVADDR, &hsb_p, sizeof(ulong),
"super_block.s_fs_info", FAULT_ON_ERROR);
readmem(hsb_p + IPCS_OFFSET(hugetlbfs_sb_info_hstate),
KVADDR, &hstate_p, sizeof(ulong),
"hugetlbfs_sb_info.hstate", FAULT_ON_ERROR);
readmem(hstate_p + IPCS_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 - IPCS_OFFSET(shmem_inode_info_vfs_inode) +
IPCS_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 + IPCS_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 +
IPCS_OFFSET(file_private_data),
KVADDR, &sfd_p, sizeof(ulong),
"file.private_data", FAULT_ON_ERROR);
readmem(sfd_p +
IPCS_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");
}
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility