This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: How to implement '@' GDB-like operator for libcc1


On Mon, 16 Mar 2015 04:22:35 +0100, Manuel LÃpez-IbÃÃez wrote:
> >
> > But GDB features a useful custom expression operator '@':
> >     https://sourceware.org/gdb/onlinedocs/gdb/Arrays.html
> >
> > I have problems implementing '@' into GCC, could you suggest at which place
> > should I call build_array_type_nelts()?  Or is it the right way at all?
> >
> > Testing it on a sample code - it should return 2:
> >     int a[]={1,2,3};int main(void){ return (*a@3)[1]; }
> 
> Sorry if I'm missing something, but this example does not make sense
> to me. You can directly use a[1], no need for the @-operator here.

You are right but I did not want to complicate the reproducer by an interface
to GDB.


> In my experience (and again, sorry if I'm missing other interesting
> usercases), the utility of @ is to be able to do things like:
> 
> print a@3
> print (*&(something complicated expression))@(some integer expression)

Yes although it is missing one dereference, that is it should be:
	print *a@3
	print (*(something complicated expression))@(some integer expression)
I agree it is a bit counter-intuitive but this is how existing GDB '@'
operator works.


> Thus, the question is what info GDB needs from GCC to be able to print
> the contents of the array.

Variable with an array type in DWARF.


> And it probably just needs the type of whatever is to the left of @ and the
> value of whatever is to the right of @, no?

There are two ways how to fix that.  As '@' makes sense only at the outermost
operator of an expression GDB could strip it and not to pass it to GCC at all.
But then there would be unhandled corner cases like parentheses:
	(gdb) print (*a@3)

So I tried to implement '@' as a proper GCC operator so that GCC creates full
array type in the DWARF.


Then there also is an option to hook GDB somewhere into the expression parser
of GCC.  GDB currently implements 'compile print' just by compiling a special
generated .c file into .o and running .o + parsing the .o's DWARF to find the
proper type, see below.


> Also note that given this code and breaking in main()
> 
> int a[]={1,2,3};int main(void){ return (a[1]); }
> 
> then:
> 
> (gdb) p a
> $1 = {1, 2, 3}
> (gdb) p a@3
> $2 = {{1, 2, 3}, {0, 0, 0}, {0, 0, 0}}
> 
> This is because:
> 
> (gdb) ptype a
> type = int [3]
> (gdb)  ptype a@3
> type = int [3][3]

There is missing one *:
	(gdb) p a
	$1 = {1, 2, 3}
	(gdb) p *a@3
	$2 = {1, 2, 3}
	(gdb) ptype a
	type = int [3]
	(gdb) ptype *a@3
	type = int [3]


> Thus, what happens currently when you do?
> (gdb) compile int a[]={1,2,3}
> (gdb) compile print a

(gdb) compile int a[]={1,2,3}
(gdb) compile print a
gdb command line:1:30: error: âaâ undeclared (first use in this function)

Because the compiled modules info is not persistent.  But with 'a' defined in
the inferior program one gets:
	(gdb) compile print a
	{1, 2, 3}

You may guess there is already a hack for this case, GDB compiles for
the 'compile print' command following stub:

void _gdb_expr (struct __gdb_regs *__regs, void * __gdb_out_param, int __gdb_expr_take_address) {
	__auto_type __gdb_expr_val = /***The expression:***/ a;
	typeof (/***The expression:***/ a) *__gdb_expr_ptr_type;
	if (__gdb_expr_take_address)
		memcpy (__gdb_out_param, &__gdb_expr_val, sizeof (*__gdb_expr_ptr_type));
	else
		memcpy (__gdb_out_param, __gdb_expr_val, sizeof (*__gdb_expr_ptr_type));
}

Depending on the DWARF types of __gdb_expr_val and __gdb_expr_ptr_type GDB will
pass the boolean flag '__gdb_expr_take_address' to handle arrays correctly, one
can see it for:

(gdb) l
1	int main(void) {
2	int i=0;         __auto_type i_val=i; typeof(i) *i_ptr_type;
3	int a[]={1,2,3}; __auto_type a_val=a; typeof(a) *a_ptr_type;
4	return 0; }
(gdb) ptype i_val
type = int
(gdb) ptype i_ptr_type
type = int *
	-> i_ptr_type == i_val * => __gdb_expr_take_address=true
(gdb) ptype a_val
type = int *
(gdb) ptype a_ptr_type
type = int (*)[3]
	-> i_ptr_type == (&*i_val)* && i_val is array => __gdb_expr_take_address=false
Implemented by:
	https://github.com/tromey/gdb/commit/6ec13bc75ebbaa3b5fab8ecda8518af56cc5e2e8

Before this auto-detection GDB would print only pointers, not arrays:
	(gdb) l
	1       int a[]={1,2,3,4,5};
	(gdb) print a
	$1 = {1, 2, 3, 4, 5}
	(gdb) compile print a
	(int *) 0x601040 <a>

The problem is that '__auto_type' does not preserve the array type,
'__auto_type' converts arrays to pointers.  When I tried to "fix" that in
attached auto_type.patch GCC would error on such assignment
	__auto_type a_val=a;
with:
	gdb command line:1:30: error: array initialized from non-constant array expression


Thanks,
Jan
gdb command line:1:30: error: array initialized from non-constant array expression

   including converting functions and arrays to pointers if CONVERT_P.
struct c_expr convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, bool convert_p, bool read_p)

Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 221058)
+++ gcc/c/c-parser.c	(working copy)
@@ -1770,7 +1770,7 @@ c_parser_declaration_or_fndef (c_parser
 		    error_at (here,
 			      "%<__auto_type%> used with a bit-field"
 			      " initializer");
-		  init = convert_lvalue_to_rvalue (init_loc, init, true, true);
+		  init = convert_lvalue_to_rvalue (init_loc, init, false, true);
 		  tree init_type = TREE_TYPE (init.value);
 		  /* As with typeof, remove all qualifiers from atomic types.  */
 		  if (init_type != error_mark_node && TYPE_ATOMIC (init_type))

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]