[PATCH] add -s option for struct command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Dave,

The patch attached with this mail is to add "-s" option for struct command. The output is like below.

crash> page.private,_mapcount.counter,lru.next -s ffffea0000000850
0       -1      0xffffea0000000878
crash> page.private,_mapcount.counter,lru.next -s ffffea0000000850 -h
0x0     0xffffffff      0xffffea0000000878

There are three features provided by the patches.

1. the data can be output in one line, easier to be parsed

2. it is extremly faster than original struct command and print command. When using command like "struct xxx.yyy -s < address_list", if there are lots of addresses in the file, address_list, the original struct command will spend several minutes and even several hours. But the patch will reduce the time to several seconds.

3. submember can also be output, like "_mapcount.counter" int the above example

P.S.
The first patch is used to modified gdb. It add a command called "printm", which can output the relative information of a struct's member.

--
--
Regards
Qiao Nuohan


>From b281d5456964a05331a70b34b1764d10bec63d3d Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Mon, 16 Apr 2012 16:05:11 +0800
Subject: [PATCH 1/2] add printm command for gdb

---
 gdb-7.3.1.patch |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/gdb-7.3.1.patch b/gdb-7.3.1.patch
index 4e1c08b..0252260 100644
--- a/gdb-7.3.1.patch
+++ b/gdb-7.3.1.patch
@@ -1357,3 +1357,74 @@
  	      if (!field_is_static (&TYPE_FIELD (type, i))
  		  && TYPE_FIELD_PACKED (type, i))
  		{
+--- gdb-7.3.1/gdb/printcmd.c.orig
++++ gdb-7.3.1/gdb/printcmd.c
+@@ -941,7 +941,7 @@ validate_format (struct format_data fmt, char *cmdname)
+    first argument ("/x myvar" for example, to print myvar in hex).  */
+ 
+ static void
+-print_command_1 (char *exp, int inspect, int voidprint)
++print_command_1 (char *exp, int inspect, int voidprint, int memberprint)
+ {
+   struct expression *expr;
+   struct cleanup *old_chain = 0;
+@@ -975,7 +975,15 @@ print_command_1 (char *exp, int inspect, int voidprint)
+   else
+     val = access_value_history (0);
+ 
+-  if (voidprint || (val && value_type (val) &&
++  if (memberprint)
++    {
++      printf_filtered ("%d %d %d %d %d %d\n",
++        TYPE_CODE (check_typedef(value_type (val))),
++        TYPE_UNSIGNED (check_typedef(value_type (val))),
++        TYPE_LENGTH (check_typedef(value_type(val))),
++        value_offset (val), value_bitpos (val), value_bitsize(val));
++    }
++  else if (voidprint || (val && value_type (val) &&
+ 		    TYPE_CODE (value_type (val)) != TYPE_CODE_VOID))
+     {
+       struct value_print_options opts;
+@@ -1018,7 +1026,13 @@ print_command_1 (char *exp, int inspect, int voidprint)
+ static void
+ print_command (char *exp, int from_tty)
+ {
+-  print_command_1 (exp, 0, 1);
++  print_command_1 (exp, 0, 1, 0);
++}
++
++static void
++printm_command (char *exp, int from_tty)
++{
++  print_command_1 (exp, 0, 1, 1);
+ }
+ 
+ /* Same as print, except in epoch, it gets its own window.  */
+@@ -1027,14 +1041,14 @@ inspect_command (char *exp, int from_tty)
+ {
+   extern int epoch_interface;
+ 
+-  print_command_1 (exp, epoch_interface, 1);
++  print_command_1 (exp, epoch_interface, 1, 0);
+ }
+ 
+ /* Same as print, except it doesn't print void results.  */
+ static void
+ call_command (char *exp, int from_tty)
+ {
+-  print_command_1 (exp, 0, 0);
++  print_command_1 (exp, 0, 0, 0);
+ }
+ 
+ void
+@@ -2844,6 +2858,11 @@ resides in memory.\n\
+ \n\
+ EXP may be preceded with /FMT, where FMT is a format letter\n\
+ but no count or size letter (see \"x\" command)."));
++
++  c = add_com ("printm", class_vars, printm_command, _("\
++Similar to \"print\" command, but it used to print the type, size, offset,\n\
++bitpos and bitsize of the expression EXP."));
++
+   set_cmd_completer (c, expression_completer);
+   add_com_alias ("p", "print", class_vars, 1);
-- 
1.7.1

>From f855845cc12328747a9623ae58972f6582a09179 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Tue, 17 Apr 2012 15:06:29 +0800
Subject: [PATCH 2/2] add -s option for struct command

---
 Makefile      |    2 +-
 defs.h        |   16 +++++
 global_data.c |    3 +
 symbols.c     |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 187 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 37378c2..9f7b5ad 100644
--- a/Makefile
+++ b/Makefile
@@ -215,7 +215,7 @@ GDB_FLAGS=-DGDB_7_3_1
 # usefulness is also dependent upon the processor's compiler -- your mileage
 # may vary.
 #
-#WARNING_OPTIONS=-Wall -O2 -Wstrict-prototypes -Wmissing-prototypes -fstack-protector
+WARNING_OPTIONS=-Wall -O2 -Wstrict-prototypes -Wmissing-prototypes -fstack-protector
 #WARNING_ERROR=-Werror
 
 # TARGET_CFLAGS will be configured automatically by configure
diff --git a/defs.h b/defs.h
index 4089779..586213e 100755
--- a/defs.h
+++ b/defs.h
@@ -324,9 +324,22 @@ struct number_option {
 #define MEMORY_DRIVER_DEVICE        "/dev/crash"
 #define MEMORY_DRIVER_DEVICE_MODE   (S_IFCHR|S_IRUSR)
 
+#define STRUCTURE_CACHE_MAX_SIZE    10
+
 /*
  *  structure definitions
  */
+struct struct_cache {
+	char name[100];
+	char member[100];
+	long type;
+	long unsigned_type;
+	long length;
+	long offset;
+	long bitpos;
+	long bitsize;
+};
+
 struct program_context {
 	char *program_name;             /* this program's name */
 	char *program_path;             /* unadulterated argv[0] */
@@ -3583,6 +3596,9 @@ struct task_mem_usage {
 /*
  *  Global data (global_data.c) 
  */
+extern struct struct_cache struct_cache[];
+extern int struct_cache_size;
+extern int struct_cache_max_size;
 extern FILE *fp; 
 extern struct program_context program_context, *pc;
 extern struct task_table task_table, *tt;
diff --git a/global_data.c b/global_data.c
index 98a5a79..a3f00e2 100755
--- a/global_data.c
+++ b/global_data.c
@@ -32,6 +32,9 @@ FILE *fp;
  *  Given that it's consulted so often, "pc" is globally available to
  *  quickly access the structure contents.
  */
+int struct_cache_size = -1;
+struct struct_cache struct_cache[STRUCTURE_CACHE_MAX_SIZE];
+
 struct program_context program_context = { 0 };
 struct program_context *pc = &program_context;
 
diff --git a/symbols.c b/symbols.c
index 69a54f6..d839c58 100755
--- a/symbols.c
+++ b/symbols.c
@@ -85,7 +85,8 @@ static int dereference_pointer(ulong, struct datatype_member *, ulong);
 #define PARSE_FOR_DECLARATION (2)
 static void parse_for_member(struct datatype_member *, ulong);
 static int show_member_offset(FILE *, struct datatype_member *, char *);
-
+static struct struct_cache *get_struct_cache(char *, char *);
+static void get_bitfield_data(ulong *, int, int);
 
 /*
  *  structure/union printing stuff
@@ -5611,6 +5612,7 @@ cmd_datatype_common(ulong flags)
 	long len;
 	ulong list_head_offset;
 	int count, pflag;
+	int sflag;
 	int argc_members;
 	int optind_save;
 	unsigned int radix, restore_radix;
@@ -5618,6 +5620,8 @@ cmd_datatype_common(ulong flags)
         char *separator;
         char *structname, *members;
         char *memberlist[MAXARGS];
+	char outputbuf[BUFSIZE];
+	long outputindex = 0;
 
         dm = &datatype_member;
 	count = 0xdeadbeef;
@@ -5628,8 +5632,9 @@ cmd_datatype_common(ulong flags)
 	radix = restore_radix = 0;
 	separator = members = NULL;
 	pflag = 0;
+	sflag = 0;
 
-        while ((c = getopt(argcnt, args, "pxdhfuc:rvol:")) != EOF) {
+        while ((c = getopt(argcnt, args, "pxdhfuc:rvol:s")) != EOF) {
                 switch (c)
 		{
 		case 'p':
@@ -5690,6 +5695,10 @@ cmd_datatype_common(ulong flags)
 			pc->curcmd_flags |= MEMTYPE_UVADDR;
 			break;
 
+		case 's':
+			sflag++;
+			break;
+
 		default:
 			argerrs++;
 			break;
@@ -5702,11 +5711,14 @@ cmd_datatype_common(ulong flags)
         if ((count_chars(args[optind], ',')+1) > MAXARGS)
                 error(FATAL, "too many members in comma-separated list!\n");
 
-	if ((count_chars(args[optind], '.') > 1) ||
+	if ((!sflag && count_chars(args[optind], '.') > 1) ||
 	    (LASTCHAR(args[optind]) == ',') ||
 	    (LASTCHAR(args[optind]) == '.'))
 		error(FATAL, "invalid format: %s\n", args[optind]);
 
+	if (sflag && count_chars(args[optind], '.') < 1)
+		error(FATAL, "-s option is invalid with no member format!\n");
+
 	optind_save = optind;
 
         /*
@@ -5761,6 +5773,19 @@ cmd_datatype_common(ulong flags)
 	if (pflag && !aflag)
 		error(FATAL, "-p option requires address argument\n");
 
+	if (sflag) {
+		if (!aflag)
+			error(FATAL, "-s option requires address argument\n");
+		if (rawdata)
+			error(FATAL, "-s option is invalid with -r option\n");
+		if (pflag)
+			error(FATAL, "-s option is invalid with -p option\n");
+		if (flags & SHOW_OFFSET)
+			error(FATAL, "-s option is invalid with -o option\n");
+		if (count != 1)
+			error(FATAL, "-s option is invalid with count speicied\n");
+	}
+
 	if (list_head_offset)
 		addr -= list_head_offset;
 
@@ -5779,8 +5804,9 @@ cmd_datatype_common(ulong flags)
         } else
                 structname = args[optind];
 
-	if ((arg_to_datatype(structname, dm,
-		DATATYPE_QUERY|ANON_MEMBER_QUERY|RETURN_ON_ERROR) < 1))
+	if (sflag)
+		*separator = '\0';
+	else if ((arg_to_datatype(structname, dm, DATATYPE_QUERY|RETURN_ON_ERROR) < 1))
 		error(FATAL, "invalid data structure reference: %s\n", structname);
 
         if ((argc_members > 1) && !aflag) {
@@ -5803,10 +5829,72 @@ cmd_datatype_common(ulong flags)
 		addr = 0;  /* unused, but parsed by gdb */
 
        	for (c = 0; c < abs(count); c++, addr += len, pc->curcmd_private += len) {
+		if (sflag) {
+			i = 0;
+			outputindex = 0;
+			ulong tmpvalue = 0;
+			struct struct_cache *struct_cache;
+			do {
+				struct_cache = get_struct_cache(structname,
+						memberlist[i]);
+				switch (struct_cache->type)
+				{
+				case TYPE_CODE_PTR:
+					readmem(addr+struct_cache->offset,
+						KVADDR, &tmpvalue,
+						struct_cache->length,
+						"tmpvalue", FAULT_ON_ERROR);
+					outputindex += sprintf(outputbuf +
+						outputindex, "0x%lx\t",
+						tmpvalue);
+					break;
+
+				case TYPE_CODE_INT:
+					readmem(addr+struct_cache->offset,
+						KVADDR, &tmpvalue, 
+						struct_cache->length,
+						"tmpvalue", FAULT_ON_ERROR);
+					get_bitfield_data(&tmpvalue,
+						struct_cache->bitpos,
+						struct_cache->bitsize);
+					if (radix == 16 || (radix == 0 &&
+						*gdb_output_radix == 16))
+						outputindex +=
+							sprintf(outputbuf +
+							outputindex, "0x%lx\t",
+							tmpvalue);
+					else if (struct_cache->unsigned_type ||
+						struct_cache->length ==
+							sizeof(ulonglong))
+						outputindex +=
+							sprintf(outputbuf +
+							outputindex, "%ld\t",
+							tmpvalue);
+					else
+						outputindex +=
+							sprintf(outputbuf +
+							outputindex, "%d\t",
+							(int)tmpvalue);
+					break;
+
+				default:
+					error(FATAL, "invalid data structure reference %s.%s\n",
+						struct_cache->name,
+						struct_cache->member);
+					break;
+				}
+			
+			} while (++i < argc_members);
+			fprintf(fp, "%s\n", outputbuf);
+			continue;
+		}
+
 		if (c) 
 			fprintf(fp,"\n");
 
 		i = 0;
+
+
         	do {
                 	if (argc_members) {
                         	*separator = '.';
@@ -7006,6 +7094,80 @@ do_empty_offset:
 
 }
 
+static struct struct_cache *
+get_struct_cache(char *structname, char *member)
+{
+	int index = 0;
+	struct datatype_member datatype_member, *dm;
+	dm = &datatype_member;
+	char buf[BUFSIZE];
+	char *printmlist[MAXARGS];
+
+	while (index <= (struct_cache_size | STRUCTURE_CACHE_MAX_SIZE)) {
+		if (!strcmp(struct_cache[index].name, structname) &&
+			!strcmp(struct_cache[index].member, member))
+			return &struct_cache[index];
+
+		index++;
+	}
+
+	struct_cache_size++;
+	index = struct_cache_size | STRUCTURE_CACHE_MAX_SIZE;
+
+	open_tmpfile();
+
+	sprintf(buf, "printm ((struct %s *)0x0).%s", structname, member);
+
+	if (!gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) {
+		rewind(fp);
+		sprintf(buf, "printm ((union %s *)0x0).%s", structname, member);
+		if (!gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR))
+			error(FATAL,
+				"invalid data structure reference %s.%s\n",
+				structname, member);
+	}
+
+	rewind(fp);
+	if (fgets(buf, BUFSIZE, fp))
+	{
+		parse_line(buf, printmlist);
+	}
+
+	sprintf(struct_cache[index].name, "%s", structname);
+	sprintf(struct_cache[index].member, "%s", member);
+	struct_cache[index].type = dtol(printmlist[0], RETURN_ON_ERROR, NULL);
+	struct_cache[index].unsigned_type = dtol(printmlist[1],
+			RETURN_ON_ERROR, NULL);
+	struct_cache[index].length = dtol(printmlist[2], RETURN_ON_ERROR,
+			NULL);
+	struct_cache[index].offset = dtol(printmlist[3], RETURN_ON_ERROR,
+			NULL);
+	struct_cache[index].bitpos = dtol(printmlist[4], RETURN_ON_ERROR,
+			NULL);
+	struct_cache[index].bitsize = dtol(printmlist[5], RETURN_ON_ERROR,
+			NULL);
+
+	close_tmpfile();
+
+	return &struct_cache[index];
+}
+
+static void
+get_bitfield_data(ulong *value, int pos, int size)
+{
+	if (pos == 0 && size == 0)
+		return;
+
+	ulong tmpvalue = *value;
+	ulong mask;
+	
+	tmpvalue = tmpvalue >> pos;
+	mask = (1UL << size) - 1;
+	tmpvalue &= mask;
+
+	*value = tmpvalue;
+}
+
 /*
  *   Get and store the size of a "known" array.  This function is only called
  *   once per requested array; after the first time, ARRAY_LENGTH() should be
-- 
1.7.1

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux