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