>From f855845cc12328747a9623ae58972f6582a09179 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@cn.fujitsu.com>
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

