From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21626 invoked by alias); 4 Jan 2008 15:14:23 -0000 Received: (qmail 21616 invoked by uid 22791); 4 Jan 2008 15:14:22 -0000 X-Spam-Check-By: sourceware.org Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 04 Jan 2008 15:13:52 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 6F28B2A967A for ; Fri, 4 Jan 2008 10:13:50 -0500 (EST) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id drftG68OQG6u for ; Fri, 4 Jan 2008 10:13:50 -0500 (EST) Received: from joel.gnat.com (localhost.localdomain [127.0.0.1]) by rock.gnat.com (Postfix) with ESMTP id 0AE6E2A9679 for ; Fri, 4 Jan 2008 10:13:48 -0500 (EST) Received: by joel.gnat.com (Postfix, from userid 1000) id A6ECFE7ACB; Fri, 4 Jan 2008 07:13:40 -0800 (PST) Date: Fri, 04 Jan 2008 15:14:00 -0000 From: Joel Brobecker To: gdb-patches@sourceware.org Subject: [commit/Ada] Add handling of "ptype TYPE_NAME.FIELD0.[...].FIELDN" expressions Message-ID: <20080104151340.GC3758@adacore.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="DrWhICOqskFTAXiy" Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-01/txt/msg00055.txt.bz2 --DrWhICOqskFTAXiy Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1032 Hello, The subject says it all. Before the patch, you could do: (gdb) ptype type_name But if you wanted to get the type of one field inside that type, you would hit a limitation: (gdb) ptype circle.pos Invalid attempt to select from type: "circle.pos". The attached patch enhances the debugger to able to do the above. 2008-01-04 Joel Brobecker * ada-exp.y (chop_separator): New function. (write_selectors): Rewrite to re-use chop_separator. (ada_nget_field_index, get_symbol_field_type): New functions. (write_var_or_type): Add support for "ptype TYPENAME.FIELD" expressions. As usual when I can, I wrote a testcase: 2008-01-04 Joel Brobecker * gdb.ada/ptype_field/pck.ads, gdb.ada/ptype_field/pck.adb, gdb.ada/ptype_field/foo.adb: New files. * gdb.ada/ptype_field.exp: New testcase. All tested on x86-linux. Note that I used the multi_line function again! Very useful :) Checked in. -- Joel --DrWhICOqskFTAXiy Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ptype.diff" Content-length: 4628 Index: ada-exp.y =================================================================== --- ada-exp.y (revision 69) +++ ada-exp.y (revision 70) @@ -1112,6 +1112,22 @@ chop_selector (char *name, int end) return -1; } +/* If NAME is a string beginning with a separator (either '__', or + '.'), chop this separator and return the result; else, return + NAME. */ + +static char * +chop_separator (char *name) +{ + if (*name == '.') + return name + 1; + + if (name[0] == '_' && name[1] == '_') + return name + 2; + + return name; +} + /* Given that SELS is a string of the form ()*, where is '__' or '.', write the indicated sequence of STRUCTOP_STRUCT expression operators. */ @@ -1121,10 +1137,8 @@ write_selectors (char *sels) while (*sels != '\0') { struct stoken field_name; - char *p; - while (*sels == '_' || *sels == '.') - sels += 1; - p = sels; + char *p = chop_separator (sels); + sels = p; while (*sels != '\0' && *sels != '.' && (sels[0] != '_' || sels[1] != '_')) sels += 1; @@ -1154,6 +1168,70 @@ write_ambiguous_var (struct block *block write_exp_elt_opcode (OP_VAR_VALUE); } +/* A convenient wrapper around ada_get_field_index that takes + a non NUL-terminated FIELD_NAME0 and a FIELD_NAME_LEN instead + of a NUL-terminated field name. */ + +static int +ada_nget_field_index (const struct type *type, const char *field_name0, + int field_name_len, int maybe_missing) +{ + char *field_name = alloca ((field_name_len + 1) * sizeof (char)); + + strncpy (field_name, field_name0, field_name_len); + field_name[field_name_len] = '\0'; + return ada_get_field_index (type, field_name, maybe_missing); +} + +/* If encoded_field_name is the name of a field inside symbol SYM, + then return the type of that field. Otherwise, return NULL. + + This function is actually recursive, so if ENCODED_FIELD_NAME + doesn't match one of the fields of our symbol, then try to see + if ENCODED_FIELD_NAME could not be a succession of field names + (in other words, the user entered an expression of the form + TYPE_NAME.FIELD1.FIELD2.FIELD3), in which case we evaluate + each field name sequentially to obtain the desired field type. + In case of failure, we return NULL. */ + +static struct type * +get_symbol_field_type (struct symbol *sym, char *encoded_field_name) +{ + char *field_name = encoded_field_name; + char *subfield_name; + struct type *type = SYMBOL_TYPE (sym); + int fieldno; + + if (type == NULL || field_name == NULL) + return NULL; + + while (field_name[0] != '\0') + { + field_name = chop_separator (field_name); + + fieldno = ada_get_field_index (type, field_name, 1); + if (fieldno >= 0) + return TYPE_FIELD_TYPE (type, fieldno); + + subfield_name = field_name; + while (*subfield_name != '\0' && *subfield_name != '.' + && (subfield_name[0] != '_' || subfield_name[1] != '_')) + subfield_name += 1; + + if (subfield_name[0] == '\0') + return NULL; + + fieldno = ada_nget_field_index (type, field_name, + subfield_name - field_name, 1); + if (fieldno < 0) + return NULL; + + type = TYPE_FIELD_TYPE (type, fieldno); + field_name = subfield_name; + } + + return NULL; +} /* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or expression_block_context if NULL). If it denotes a type, return @@ -1252,14 +1330,21 @@ write_var_or_type (struct block *block, if (type_sym != NULL) { - struct type *type = SYMBOL_TYPE (type_sym); - - if (TYPE_CODE (type) == TYPE_CODE_VOID) - error (_("`%s' matches only void type name(s)"), name0.ptr); - else if (tail_index == name_len) - return type; + struct type *field_type; + + if (tail_index == name_len) + return SYMBOL_TYPE (type_sym); + + /* We have some extraneous characters after the type name. + If this is an expression "TYPE_NAME.FIELD0.[...].FIELDN", + then try to get the type of FIELDN. */ + field_type + = get_symbol_field_type (type_sym, encoded_name + tail_index); + if (field_type != NULL) + return field_type; else - error (_("Invalid attempt to select from type: \"%s\"."), name0.ptr); + error (_("Invalid attempt to select from type: \"%s\"."), + name0.ptr); } else if (tail_index == name_len && nsyms == 0) { --DrWhICOqskFTAXiy Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ptype-tc.diff" Content-length: 5831 Index: gdb.ada/ptype_field.exp =================================================================== --- gdb.ada/ptype_field.exp (revision 0) +++ gdb.ada/ptype_field.exp (revision 71) @@ -0,0 +1,70 @@ +# Copyright 2008 Free Software Foundation, Inc. +# +# 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 3 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if $tracelevel then { + strace $tracelevel +} + +load_lib "ada.exp" + +set testdir "ptype_field" +set testfile "${testdir}/foo" +set srcfile ${srcdir}/${subdir}/${testfile}.adb +set binfile ${objdir}/${subdir}/${testfile} + +file mkdir ${objdir}/${subdir}/${testdir} +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug additional_flags=-gnat05 ]] != "" } { + return -1 +} + +# A convenience function that joins all the arguments together, +# with a regexp that matches zero-or-more end of lines in between +# each argument. This function is ideal to write the expected output +# of a GDB command that generates more than a couple of lines, as +# this allows us to write each line as a separate string, which is +# easier to read by a human being. + +proc multi_line { args } { + return [join $args "\[\r\n\]*"] +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb] +runto "foo.adb:$bp_location" + +gdb_test "ptype circle" \ + [multi_line "type = record" \ + " pos: pck\\.position;" \ + " radius: integer;" \ + "end record" ] \ + "ptype circle" + +gdb_test "ptype circle.pos" \ + [multi_line "type = record" \ + " x: integer;" \ + " y: integer;" \ + "end record" ] \ + "ptype circle.pos" + +gdb_test "ptype circle.pos.x" \ + "type = <\[0-9\]+-byte integer>" \ + "ptype circle.pos.x" + + + Index: gdb.ada/ptype_field/pck.adb =================================================================== --- gdb.ada/ptype_field/pck.adb (revision 0) +++ gdb.ada/ptype_field/pck.adb (revision 71) @@ -0,0 +1,23 @@ +-- Copyright 2008 Free Software Foundation, Inc. +-- +-- 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 3 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +package body Pck is + + procedure Do_Nothing (C : in out Circle) is + begin + null; + end Do_Nothing; + +end Pck; Index: gdb.ada/ptype_field/pck.ads =================================================================== --- gdb.ada/ptype_field/pck.ads (revision 0) +++ gdb.ada/ptype_field/pck.ads (revision 71) @@ -0,0 +1,30 @@ +-- Copyright 2008 Free Software Foundation, Inc. +-- +-- 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 3 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +package Pck is + + type Position is record + X : Integer; + Y : Integer; + end record; + + type Circle is record + Pos : Position; + Radius : Integer; + end record; + + procedure Do_Nothing (C : in out Circle); + +end Pck; Index: gdb.ada/ptype_field/foo.adb =================================================================== --- gdb.ada/ptype_field/foo.adb (revision 0) +++ gdb.ada/ptype_field/foo.adb (revision 71) @@ -0,0 +1,22 @@ +-- Copyright 2008 Free Software Foundation, Inc. +-- +-- 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 3 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. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +with Pck; use Pck; + +procedure Foo is + My_Circle : Circle := (Pos => (1, 2), Radius => 3); +begin + Do_Nothing (My_Circle); -- STOP +end Foo; --DrWhICOqskFTAXiy--