[Crash-utility] whatis: display full parameter name when symbol is function

Dave Anderson anderson at redhat.com
Tue Mar 12 19:39:52 UTC 2013



----- Original Message -----
> Dave,
> 
> Here is the patch which add feature to whatis that would display full parameter name
> when it detect the symbol is a function.
> 
> And this patch already include previous fix for gdb_get_datatype,
> please help review it.
> 
> Thanks,
> Lei

When I attempt a "whatis <text-symbol>" on a module function prior to
loading its module.ko file, your patch changes the command's behavior.
For example, without your patch, it shows that the gdb request failed:

 crash> whatis call_transmit
 whatis: gdb request failed: whatis call_transmit
 crash>

So I load the module, and try again:

 crash> mod -s sunrpc
      MODULE       NAME                     SIZE  OBJECT FILE
 ffffffffa0153ea0  sunrpc                 255581  /lib/modules/3.7.9-104.fc17.x86_64/kernel/net/sunrpc/sunrpc.ko 
 crash> whatis call_transmit 
 void call_transmit(struct rpc_task *);
 crash> 

But with your patch, it fails quietly:

 crash> whatis call_transmit
 crash>

And while it works most of the time:

 crash> mod -s sunrpc
      MODULE       NAME                     SIZE  OBJECT FILE
 ffffffffa0153ea0  sunrpc                 255581  /lib/modules/3.7.9-104.fc17.x86_64/kernel/net/sunrpc/sunrpc.ko 
 crash> whatis call_transmit
 void call_transmit(struct rpc_task * task);
 crash> 

if I do some other whatis/mod commands prior to it, I occasionally can get
this to happen:

 crash> mod -s sunrpc
      MODULE       NAME                     SIZE  OBJECT FILE
 ffffffffa0153ea0  sunrpc                 255581  /lib/modules/3.7.9-104.fc17.x86_64/kernel/net/sunrpc/sunrpc.ko 
 crash> whatis call_transmit
    <segmentation violation in gdb>
 
 crash> 

The backtrace shows a SIGSEGV in your new gdb_function_nameargs() function:

 Program received signal SIGSEGV, Segmentation fault.
 gdb_function_nameargs (req=<optimized out>) at symtab.c:5263
 5263		while ((BLOCK_FUNCTION(b) == NULL || block_inlined_p(b))
 Missing separate debuginfos, use: debuginfo-install glibc-2.15-58.fc17.x86_64 ncurses-libs-5.9-4.20120204.fc17.x86_64 zlib-1.2.5-7.fc17.x86_64
 (gdb) bt
 #0  gdb_function_nameargs (req=<optimized out>) at symtab.c:5263
 #1  gdb_command_funnel (req=req at entry=0xdd1e20) at symtab.c:4957
 #2  0x00000000004d78c0 in gdb_interface (req=req at entry=0xdd1e20) at gdb_interface.c:397
 #3  0x000000000050860d in whatis_variable (sp=<optimized out>) at symbols.c:6767
 #4  0x0000000000508ab4 in cmd_whatis () at symbols.c:6199
 #5  0x0000000000460694 in exec_command () at main.c:775
 #6  0x0000000000521982 in exec_input_file () at cmdline.c:1407
 #7  0x00000000004603e6 in is_input_file () at main.c:871
 #8  exec_command () at main.c:782
 #9  0x00000000004608ba in main_loop () at main.c:723
 #10 0x000000000056ee49 in captured_command_loop (data=data at entry=0x0) at ./main.c:228
 #11 0x000000000056e28e in catch_errors (func=func at entry=0x56ee40 <captured_command_loop>, 
     func_args=func_args at entry=0x0, errstring=errstring at entry=0x882acb "", mask=mask at entry=6) at exceptions.c:531
 #12 0x000000000056fad6 in captured_main (data=data at entry=0x7fffffffe430) at ./main.c:958
 #13 0x000000000056e28e in catch_errors (func=func at entry=0x56ef20 <captured_main>, 
     func_args=func_args at entry=0x7fffffffe430, errstring=errstring at entry=0x882acb "", mask=mask at entry=6)
     at exceptions.c:531
 #14 0x000000000056fda4 in gdb_main (args=args at entry=0x7fffffffe430) at ./main.c:973
 #15 0x000000000056fdde in gdb_main_entry (argc=<optimized out>, argv=argv at entry=0x7fffffffe588) at ./main.c:993
 #16 0x00000000004d69d4 in gdb_main_loop (argc=<optimized out>, argc at entry=1, argv=argv at entry=0x7fffffffe588)
     at gdb_interface.c:76
 #17 0x000000000045eeff in main (argc=1, argv=0x7fffffffe588) at main.c:628
 (gdb)

But unfortunately, it's not necessarily reproducible, even with the same set 
of commands!

The backtrace above was from a live session, and now I can't seem to reproduce it.
But I'm guessing that block_for_pc_sect() returned a NULL "b" pointer.

Dave


> 
> From 8ea80a2ddbd0ea524a715a5e188118c39a0ce311 Mon Sep 17 00:00:00
> 2001
> From: Lei Wen <leiwen at marvell.com>
> Date: Mon, 11 Mar 2013 10:34:15 +0800
> Subject: [PATCH] whatis: display full parameter name when symbol is
> function
> 
> Signed-off-by: Lei Wen <leiwen at marvell.com>
> ---
>  defs.h          |    1 +
>  gdb-7.3.1.patch |   77
>  +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb_interface.c |    3 ++
>  symbols.c       |   50 +++++++++++++++++++++++++++++++++++-
>  4 files changed, 130 insertions(+), 1 deletions(-)
> 
> diff --git a/defs.h b/defs.h
> index 1f693c3..1b31d1f 100755
> --- a/defs.h
> +++ b/defs.h
> @@ -3685,6 +3685,7 @@ struct gnu_request {
>  #define GNU_GET_SYMBOL_TYPE      (15)
>  #define GNU_USER_PRINT_OPTION 	 (16)
>  #define GNU_SET_CRASH_BLOCK      (17)
> +#define GNU_FUNCTION_NAMEARGS    (18)
>  #define GNU_DEBUG_COMMAND       (100)
>  /*
>   *  GNU flags
> diff --git a/gdb-7.3.1.patch b/gdb-7.3.1.patch
> index a12d3d4..3b0f0d1 100644
> --- a/gdb-7.3.1.patch
> +++ b/gdb-7.3.1.patch
> @@ -1821,3 +1821,80 @@ diff -up gdb-7.3.1/gdb/psymtab.c.orig
> gdb-7.3.1/gdb/psymtab.c
>   	  break;
> 
>         if (cur_sec == NULL)
> +--- gdb-7.3.1/gdb/symtab.c.orig
> ++++ gdb-7.3.1/gdb/symtab.c
> +@@ -4848,6 +4848,7 @@ static void gdb_get_symbol_type(struct
> gnu_request *);
> + static void gdb_command_exists(struct gnu_request *);
> + static void gdb_debug_command(struct gnu_request *);
> + static void gdb_function_numargs(struct gnu_request *);
> ++static void gdb_function_nameargs(struct gnu_request *);
> + static void gdb_add_symbol_file(struct gnu_request *);
> + static void gdb_delete_symbol_file(struct gnu_request *);
> + static void gdb_patch_symbol_values(struct gnu_request *);
> +@@ -4952,6 +4953,10 @@ gdb_command_funnel(struct gnu_request *req)
> + 		gdb_set_crash_block(req);
> + 		break;
> +
> ++	case GNU_FUNCTION_NAMEARGS:
> ++		gdb_function_nameargs(req);
> ++		break;
> ++
> + 	default:
> + 		req->flags |= GNU_COMMAND_FAILED;
> + 		break;
> +@@ -5054,8 +5059,9 @@ gdb_get_datatype(struct gnu_request *req)
> + 		if (gdb_CRASHDEBUG(2))
> +         		console("expr->elts[0].opcode: OP_VAR_VALUE\n");
> + 		type = expr->elts[2].symbol->type;
> ++		req->typecode = TYPE_CODE(type);
> ++		req->length = TYPE_LENGTH(type);
> + 		if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
> +-			req->typecode = TYPE_CODE(type);
> + 			req->value = SYMBOL_VALUE(expr->elts[2].symbol);
> + 			req->tagname = TYPE_TAG_NAME(type);
> + 			if (!req->tagname) {
> +@@ -5243,6 +5249,44 @@ gdb_function_numargs(struct gnu_request *req)
> + 	req->value = (ulong)TYPE_NFIELDS(sym->type);
> + }
> +
> ++static void
> ++gdb_function_nameargs(struct gnu_request *req)
> ++{
> ++	struct block *b;
> ++	struct dict_iterator iter;
> ++	struct symbol *sym = NULL;
> ++	int len;
> ++	char *buf = req->buf;
> ++
> ++	b = block_for_pc_sect(req->pc, find_pc_mapped_section(req->pc));
> ++	/* Get the lexical block, which is not a inline function */
> ++	while ((BLOCK_FUNCTION(b) == NULL || block_inlined_p(b))
> ++			&& BLOCK_SUPERBLOCK(b) != NULL)
> ++		b = BLOCK_SUPERBLOCK(b);
> ++
> ++	ALL_BLOCK_SYMBOLS (b, iter, sym)
> ++	{
> ++		if (!SYMBOL_IS_ARGUMENT (sym))
> ++			continue;
> ++
> ++		if (*SYMBOL_LINKAGE_NAME (sym))
> ++		{
> ++			struct symbol *nsym;
> ++
> ++			nsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym),
> ++					b, VAR_DOMAIN, NULL);
> ++			gdb_assert (nsym != NULL);
> ++			if (SYMBOL_CLASS (nsym) != LOC_REGISTER
> ++					|| SYMBOL_IS_ARGUMENT (nsym))
> ++				sym = nsym;
> ++		}
> ++
> ++		len = strlen(SYMBOL_PRINT_NAME(sym));
> ++		sprintf(buf, "%s,", SYMBOL_PRINT_NAME(sym));
> ++		buf += len + 1;
> ++	}
> ++}
> ++
> + struct load_module *gdb_current_load_module = NULL;
> +
> + static void
> diff --git a/gdb_interface.c b/gdb_interface.c
> index afc197c..a460ea8 100755
> --- a/gdb_interface.c
> +++ b/gdb_interface.c
> @@ -590,6 +590,9 @@ gdb_command_string(int cmd, char *buf, int live)
>          case GNU_SET_CRASH_BLOCK:
>                  sprintf(buf, "GNU_SET_CRASH_BLOCK");
>  		break;
> +	case GNU_FUNCTION_NAMEARGS:
> +                sprintf(buf, "GNU_FUNCTION_NAMEARGS");
> +		break;
>  	case 0:
>  		buf[0] = NULLCHAR;
>  		break;
> diff --git a/symbols.c b/symbols.c
> index 4fb397c..b38a2a3 100755
> --- a/symbols.c
> +++ b/symbols.c
> @@ -6660,18 +6660,62 @@ whatis_datatype(char *st, ulong flags, FILE
> *ofp)
>  }
> 
>  /*
> + * add the function argument to the function type showing
> + * The arg name input is seperated by comma
> + */
> +static void
> +add_function_name(char *argnames, char *func)
> +{
> +	char *arg, *seperator, *tmp;
> +
> +	tmp = func;
> +	for (arg = strtok(argnames, ","); arg; ) {
> +		seperator = strstr(tmp, ",");
> +		if (!seperator)
> +			seperator= strrchr(func, ')');
> +
> +		shift_string_right(seperator, strlen(arg) + 1);
> +		BCOPY(arg, seperator + 1, strlen(arg));
> +		tmp = seperator + 2 + strlen(arg);
> +		arg = strtok(NULL, ",");
> +	}
> +}
> +
> +/*
>   *  Scan the symbol file for a variable declaration.
>   */
>  static void
>  whatis_variable(struct syment *sp)
>  {
> +	struct datatype_member datatype_member, *dm;
> +	struct gnu_request *req;
> +	int ret;
>  	char *p1;
>  	char buf[BUFSIZE];
> 
> +	dm = &datatype_member;
> +	strcpy(buf, sp->name);
> +	if (!arg_to_datatype(buf, dm, RETURN_ON_ERROR|DATATYPE_QUERY))
> +		return FALSE;
> +
>          open_tmpfile();
>          sprintf(buf, "whatis %s", sp->name);
> -        if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
> +
> +	req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
> +	req->buf = GETBUF(BUFSIZE);
> +
> +	ret = gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR);
> +	if (ret && dm->type == FUNCTION) {
> +		req->command = GNU_FUNCTION_NAMEARGS;
> +		req->flags |= GNU_RETURN_ON_ERROR;
> +		req->pc = symbol_value(sp->name);
> +
> +		gdb_interface(req);
> +	}
> +        if (!ret || req->flags & GNU_COMMAND_FAILED) {
>                  close_tmpfile();
> +		FREEBUF(req->buf);
> +		FREEBUF(req);
>                  error(FATAL, "gdb request failed: whatis %s\n",
>                  sp->name);
>          }
> 
> @@ -6693,6 +6737,7 @@ whatis_variable(struct syment *sp)
>  		if (index(buf, '(') == rindex(buf, '(')) {
>  			shift_string_right(p1, strlen(sp->name));
>  			BCOPY(sp->name, p1, strlen(sp->name));
> +			add_function_name(req->buf, p1 + strlen(sp->name));
>  		} else {
>  			p1 = strstr(buf, ")");
>  			shift_string_right(p1, strlen(sp->name));
> @@ -6705,6 +6750,9 @@ whatis_variable(struct syment *sp)
>                  fprintf(fp, "%s%s%s;\n", p1, LASTCHAR(p1) == '*' ?
>                  "":" ",
>  			sp->name);
>  	}
> +
> +	FREEBUF(req->buf);
> +	FREEBUF(req);
>  }
> 
>  /*
> --
> 1.7.5.4
> 




More information about the Crash-utility mailing list