Re: [PATCH] add -s option for struct command

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

 



Hello Dave,

After some many discussions, I rewrite the code to an extension module.
What I want is not only the member of structure page, but also other
structure's members. So for the speed of analysing a big number of data
and not obeying your attitude towards the change of struct command, I
made it an extension module.

And about the patch which changes gdb, I create a new method print_command_2 to do the work.

At 2012-4-19 20:50, Dave Anderson wrote:


----- Original Message -----
At 2012-4-18 21:21, Dave Anderson wrote:
In our original discussions, i thought that I had made it clear
that
the introduction of a new option paradigm with submembers could be
avoided by using, for example, "page._mapcounter" instead of having
to enter "page._mapcount.counter"?  This option makes the struct
command seemingly violate its own rules, and really confuses things.
For example, with your patch, a user would see things like this:

The most important reason why I insisted this option is the performance.
Both original struct and print command are very slow. When kernel
debugger wants to parse a bit amount of data, the performance of
original struct and print command is not ideal.


   crash>   page._mapcount.counter ffffea0000000508 -s
   -1
   crash>   page._mapcount.counter ffffea0000000508
   struct: invalid format: page._mapcount.counter
   crash>   page._mapcount ffffea0000000508
       _mapcount = {
         counter = -1
       }
   crash>   page._mapcount ffffea0000000508 -s
   struct: invalid data structure reference page._mapcount
   crash>

An idea of solving this confusion is changing the error information.
When users uses "-s" option and error happens, error information
suggests to use struct command without "-s" option if it is valid.
And vice versa, when error happens without specified "-s" option.

It's not so much the error message wording, it's the usage of a
completely different option-expression.  And you can still display
the -s information without the extra submember.


I had suggested that you look into the get_member_data() function
in to the gdb/symtab.c file to access the member offset and size
values.

Actually, the function need to be changed a lot to support what I want.
I need the information of submember, and I need the position and size of
bitfield. After investigation, function print_command_1 hides the data
that I want. I know it is not a good idea of modifying this function.
But what if a new function which has the similar mechanism with function
print_command_1?

Right, that's exactly what I suggested below:

I also don't like the idea of modifying the prototype of
the stalwart print_command_1() gdb function, and the creation
of a new gdb command.  Whenever there is a need to update the
embedded gdb version, patches like this can be problematic.
I would prefer that you create a new "GNU_XXXX" #define,
similar to GNU_GET_SYMBOL_TYPE, pass the request through
the gdb_command_funnel switch statement, and write a new
standalone function to accomplish what you have done in the
print_command_1() function.

Dave

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




--
--
Regards
Qiao Nuohan


/* pstruct.c - print structure's member
 *
 * Copyright (C) 2012 FUJITSU LIMITED
 * Author: 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 STRUCTURE_CACHE_MAX_SIZE    10

struct struct_cache {
	char name[100];
	char member[100];
	long type;
	long unsigned_type;
	long length;
	long offset;
	long bitpos;
	long bitsize;
};

int struct_cache_size = -1;
struct struct_cache struct_cache[STRUCTURE_CACHE_MAX_SIZE];

int _init(void);
int _fini(void);

void cmd_pstruct(void);     /* Declare the commands and their help data. */
char *help_pstruct[];

static struct struct_cache *get_struct_cache(char *, char *);
static void get_bitfield_data(ulong *, int, int);

static struct command_table_entry command_table[] = {
	{ "pstruct", cmd_pstruct, help_pstruct, 0 },  /* One or more commands, */
	{ NULL }                                      /* terminated by NULL, */
};

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;
}

char *help_pstruct[] = {
        "pstruct",                                     /* command name */
        "print structure member's data in one line",   /* short description */
        "struct_name.member[.member...,member...] [-d|-x] [-l offset]\n"
	"    [address|symbol]",              /* argument synopsis, or " " if none */
 
        "  This command displays the contents of a structure's members in one",
	"  line.\n",
	"  The arguments are as follows:\n",
	"  struct_name  name of a C-code structure used by the kernel.",
	"   .member...  name of a structure member; to display multiple members",
	"               of a structure, use a comma-separated list of members.",
	"    -l offset  if the address argument is a pointer to a structure",
	"               member that is contained by the target data structure,",
	"               typically a pointer to an embedded list_head, the offset",
	"               to the embedded member may be entered in either of the",
	"               following manners:",
	"                   1. in \"structure.member\" format.",
	"                   2. a number of bytes. ",
	"           -x  override default output format with hexadecimal format.",
	"           -d  override default output format with decimal format.",
	"  ",
        "\nEXAMPLE",
        "  Display the page's member private, _count.counter, inuse at address ",
	"  0xffffea00000308f0:\n",
        "    %s> pstruct page.private,_count.counter,inuse 0xffffea00000308f0",
        "    0       198896  59904",
	" ",
	"  Display the page's member mapping, index at address 0xffffea00000308f0",
	"  in hexadecimal format:\n",
        "    %s> pstruct page.mapping,index ffffea000004c778 -x",
        "    0xffff88004b6412b8      0x100167",
        NULL
};

/* 
 *  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_pstruct(void)
{
        int c, i;
	ulong addr;
	struct syment *sp;
	ulong list_head_offset;
	int argc_members;
	unsigned int radix;
	struct datatype_member datatype_member, *dm;
	char *structname, *members;
	char *separator;
	char *memberlist[MAXARGS];
	char outputbuf[BUFSIZE];
	long outputindex;
	ulong tmpvalue;
	struct struct_cache *struct_cache;

	argc_members = 0;
	dm = &datatype_member;
	list_head_offset = 0;
	structname = separator = members = NULL;
	outputindex = 0;

        while ((c = getopt(argcnt, args, "dxl:")) != EOF) {
                switch(c)
                {
		case 'd':
			if (radix == 16)
				error(FATAL, 
				    "-d and -x are mutually exclusive\n");
			radix = 10;
			break;

		case 'x':
			if (radix == 10)
				error(FATAL, 
				    "-d and -x are mutually exclusive\n");
			radix = 16;
			break;

		case 'l':
                        if (IS_A_NUMBER(optarg))
                                list_head_offset = stol(optarg,
                                        FAULT_ON_ERROR, NULL);
                        else if (arg_to_datatype(optarg,
                                dm, RETURN_ON_ERROR) > 1)
                                list_head_offset = dm->member_offset;
			else
				error(FATAL, "invalid -l option: %s\n", 
					optarg);
			break;

                default:
                        argerrs++;
                        break;
                }
        }

        if (argerrs || !args[optind] || !args[optind+1] || args[optind+2])
                cmd_usage(pc->curcmd, SYNOPSIS);

	if ((count_chars(args[optind], ',')+1) > MAXARGS)
		error(FATAL, "too many members in comma-separated list!\n");

	if ((LASTCHAR(args[optind]) == ',') || (LASTCHAR(args[optind]) == '.'))
		error(FATAL, "invalid format: %s\n", args[optind]);

	if (count_chars(args[optind], '.') < 1)
		error(FATAL, "no member format is invalid: %s\n", args[optind]);

	/*
	 * Handle struct.member[,member] argument format.
	 */
	structname = GETBUF(strlen(args[optind])+1);
	strcpy(structname, args[optind]);
	separator = strstr(structname, ".");

	members = GETBUF(strlen(args[optind])+1);
	strcpy(members, separator+1);
	replace_string(members, ",", ' ');
	argc_members = parse_line(members, memberlist);

	*separator = NULLCHAR;

	/*
 	 *  Handle address
 	 */
	if (clean_arg() && IS_A_NUMBER(args[optind+1]))
		addr = htol(args[optind+1], FAULT_ON_ERROR, NULL);
	else if ((sp = symbol_search(args[optind+1])))
		addr = sp->value;
	else {
		fprintf(fp, "symbol not found: %s\n", args[optind+1]);
		fprintf(fp, "possible alternatives:\n");
		if (!symbol_query(args[optind], "  ", NULL))
			fprintf(fp, "  (none found)\n");
		goto freebuf;
	}

	if (list_head_offset)
		addr -= list_head_offset;

	i = 0;
	outputindex = 0;
	
	do {
		tmpvalue = 0;
		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,
					"%lu\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);

freebuf:
	if (structname)
		FREEBUF(structname);
	if (members)
                FREEBUF(members);
}

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 && index <= 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;
}
>From 0a01acbe0f12496dd0ed3609f70ab6639afc9e59 Mon Sep 17 00:00:00 2001
From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx>
Date: Tue, 15 May 2012 04:54:26 +0800
Subject: [PATCH] add gdb command printm

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

diff --git a/gdb-7.3.1.patch b/gdb-7.3.1.patch
index 4e1c08b..791923a 100644
--- a/gdb-7.3.1.patch
+++ b/gdb-7.3.1.patch
@@ -1357,3 +1357,80 @@
  	      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
+@@ -1016,11 +1016,62 @@ print_command_1 (char *exp, int inspect, int voidprint)
+ }
+ 
+ static void
++print_command_2 (char *exp, int inspect, int voidprint)
++{
++  struct expression *expr;
++  struct cleanup *old_chain = 0;
++  char format = 0;
++  struct value *val;
++  struct format_data fmt;
++  int cleanup = 0;
++
++  if (exp && *exp == '/')
++    {
++      exp++;
++      fmt = decode_format (&exp, last_format, 0);
++      validate_format (fmt, "print");
++      last_format = format = fmt.format;
++    }
++  else
++    {
++      fmt.count = 1;
++      fmt.format = 0;
++      fmt.size = 0;
++      fmt.raw = 0;
++    }
++
++  if (exp && *exp)
++    {
++      expr = parse_expression (exp);
++      old_chain = make_cleanup (free_current_contents, &expr);
++      cleanup = 1;
++      val = evaluate_expression (expr);
++    }
++  else
++    val = access_value_history (0);
++
++    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));
++
++  if (cleanup)
++    do_cleanups (old_chain);
++}
++
++static void
+ print_command (char *exp, int from_tty)
+ {
+   print_command_1 (exp, 0, 1);
+ }
+ 
++static void
++printm_command (char *exp, int from_tty)
++{
++  print_command_2 (exp, 0, 1);
++}
++
+ /* Same as print, except in epoch, it gets its own window.  */
+ static void
+ inspect_command (char *exp, int from_tty)
+@@ -2847,6 +2898,11 @@ but no count or size letter (see \"x\" command)."));
+   set_cmd_completer (c, expression_completer);
+   add_com_alias ("p", "print", class_vars, 1);
+ 
++  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);
++
+   c = add_com ("inspect", class_vars, inspect_command, _("\
+ Same as \"print\" command, except that if you are running in the epoch\n\
+ environment, the value is printed in its own window."));
-- 
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