[PING][PATCH] Add support for the __flash qualifier on AVR

Pierre Langlois pierre.langlois@embecosm.com
Tue Jul 15 10:36:00 GMT 2014


Ping.

On 08/07/14 11:54, Pierre Langlois wrote:
> The __flash qualifier is part of the named address spaces for AVR [1]. It allows
> putting read-only data in the flash memory, normally reserved for code.
>
> When used together with a pointer, the DW_AT_address_class attribute is set to 1
> and allows GDB to detect that when it will be dereferenced, the data will be
> loaded from the flash memory (with the LPM instruction).
>
> We can now properly debug the following code:
>
> ~~~
> const __flash char data_in_flash = 0xab;
>
> int
> main (void)
> {
>    const __flash char *pointer_to_flash = &data_in_flash;
> }
> ~~~
>
> ~~~
> (gdb) print pointer_to_flash
> $1 = 0x1e8 <data_in_flash> "\253"
> (gdb) print/x *pointer_to_flash
> $2 = 0xab
> (gdb) x/x pointer_to_flash
> 0x1e8 <data_in_flash>: 0xXXXXXXab
> ~~~
>
> Whereas previously, GDB would revert to the default address space which is RAM
> and mapped in higher memory:
>
> ~~~
> (gdb) print pointer_to_flash
> $1 = 0x8001e8 ""
> ~~~
>
> Thanks,
>
> Pierre
>
> [1] https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html
>
> 2014-07-08  Pierre Langlois  <pierre.langlois@embecosm.com>
>
> gdb/
> 	* avr-tdep.c (AVR_TYPE_ADDRESS_CLASS_FLASH): New macro.
> 	(AVR_TYPE_INSTANCE_FLAG_ADDRESS_CLASS_FLASH): Likewise.
> 	(avr_address_to_pointer): Check for AVR_TYPE_ADDRESS_CLASS_FLASH.
> 	(avr_pointer_to_address): Likewise.
> 	(avr_address_class_type_flags): New function.
> 	(avr_address_class_type_flags_to_name): Likewise.
> 	(avr_address_class_name_to_type_flags): Likewise.
> 	(avr_gdbarch_init): Set address_class_type_flags,
> 	address_class_type_flags_to_name and
> 	address_class_name_to_type_flags.
>
> gdb/testsuite/
> 	* gdb.arch/avr-flash-qualifer.c: New.
> 	* gdb.arch/avr-flash-qualifer.exp: New.
> ---
>   gdb/avr-tdep.c                                 | 77 ++++++++++++++++++++++++--
>   gdb/testsuite/gdb.arch/avr-flash-qualifier.c   | 32 +++++++++++
>   gdb/testsuite/gdb.arch/avr-flash-qualifier.exp | 52 +++++++++++++++++
>   3 files changed, 156 insertions(+), 5 deletions(-)
>   create mode 100644 gdb/testsuite/gdb.arch/avr-flash-qualifier.c
>   create mode 100644 gdb/testsuite/gdb.arch/avr-flash-qualifier.exp
>
> diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
> index 9b0bfaf..eb99748 100644
> --- a/gdb/avr-tdep.c
> +++ b/gdb/avr-tdep.c
> @@ -71,6 +71,16 @@
>
>   /* Constants: prefixed with AVR_ to avoid name space clashes */
>
> +/* Address space flags */
> +
> +/* We are assigning the TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1 to the flash address
> +   space.  */
> +
> +#define AVR_TYPE_ADDRESS_CLASS_FLASH TYPE_ADDRESS_CLASS_1
> +#define AVR_TYPE_INSTANCE_FLAG_ADDRESS_CLASS_FLASH  \
> +  TYPE_INSTANCE_FLAG_ADDRESS_CLASS_1
> +
> +
>   enum
>   {
>     AVR_REG_W = 24,
> @@ -295,10 +305,19 @@ avr_address_to_pointer (struct gdbarch *gdbarch,
>   {
>     enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>
> +  /* Is it a data address in flash?  */
> +  if (AVR_TYPE_ADDRESS_CLASS_FLASH (type))
> +    {
> +      /* A data address in flash is always byte addressed.  */
> +      store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order,
> +			      avr_convert_iaddr_to_raw (addr));
> +    }
>     /* Is it a code address?  */
> -  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
> -      || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
> +  else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
> +	   || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
>       {
> +      /* A code address, either a function pointer or the program counter, is
> +	 word (16 bits) addressed.  */
>         store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order,
>   			      avr_convert_iaddr_to_raw (addr >> 1));
>       }
> @@ -318,10 +337,13 @@ avr_pointer_to_address (struct gdbarch *gdbarch,
>     CORE_ADDR addr
>       = extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
>
> +  /* Is it a data address in flash?  */
> +  if (AVR_TYPE_ADDRESS_CLASS_FLASH (type))
> +    return avr_make_iaddr (addr);
>     /* Is it a code address?  */
> -  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
> -      || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
> -      || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type)))
> +  else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
> +	   || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
> +	   || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type)))
>       return avr_make_iaddr (addr << 1);
>     else
>       return avr_make_saddr (addr);
> @@ -1342,6 +1364,45 @@ avr_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
>     return -1;
>   }
>
> +/* Map DW_AT_address_class attributes to a type_instance_flag_value.  Note that
> +   this attribute is only valid with pointer types and therefore the flag is set
> +   to the pointer type and not its target type.  */
> +
> +static int
> +avr_address_class_type_flags (int byte_size, int dwarf2_addr_class)
> +{
> +  // __flash qualifier
> +  if (dwarf2_addr_class == 1 && byte_size == 2)
> +    return AVR_TYPE_INSTANCE_FLAG_ADDRESS_CLASS_FLASH;
> +  return 0;
> +}
> +
> +/* Convert a type_instance_flag_value to an address space qualifier and
> +   vice-versa.  */
> +
> +static const char*
> +avr_address_class_type_flags_to_name (struct gdbarch *gdbarch, int type_flags)
> +{
> +  if (type_flags & AVR_TYPE_INSTANCE_FLAG_ADDRESS_CLASS_FLASH)
> +    return "flash";
> +  else
> +    return NULL;
> +}
> +
> +static int
> +avr_address_class_name_to_type_flags (struct gdbarch *gdbarch,
> +                                      const char* name,
> +                                      int *type_flags_ptr)
> +{
> +  if (strcmp (name, "flash") == 0)
> +    {
> +      *type_flags_ptr = AVR_TYPE_INSTANCE_FLAG_ADDRESS_CLASS_FLASH;
> +      return 1;
> +    }
> +  else
> +    return 0;
> +}
> +
>   /* Initialize the gdbarch structure for the AVR's.  */
>
>   static struct gdbarch *
> @@ -1452,6 +1513,12 @@ avr_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     set_gdbarch_unwind_pc (gdbarch, avr_unwind_pc);
>     set_gdbarch_unwind_sp (gdbarch, avr_unwind_sp);
>
> +  set_gdbarch_address_class_type_flags (gdbarch, avr_address_class_type_flags);
> +  set_gdbarch_address_class_name_to_type_flags
> +    (gdbarch, avr_address_class_name_to_type_flags);
> +  set_gdbarch_address_class_type_flags_to_name
> +    (gdbarch, avr_address_class_type_flags_to_name);
> +
>     return gdbarch;
>   }
>
> diff --git a/gdb/testsuite/gdb.arch/avr-flash-qualifier.c b/gdb/testsuite/gdb.arch/avr-flash-qualifier.c
> new file mode 100644
> index 0000000..4e5b451
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/avr-flash-qualifier.c
> @@ -0,0 +1,32 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2014 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 <http://www.gnu.org/licenses/>.  */
> +
> +const __flash char data_in_flash = 0xab;
> +
> +static void
> +pass_to_function (const __flash char *p)
> +{
> +}
> +
> +int
> +main (void)
> +{
> +  const __flash char *pointer_to_flash = &data_in_flash;
> +  /* break here.  */
> +  pass_to_function (&data_in_flash);
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/avr-flash-qualifier.exp b/gdb/testsuite/gdb.arch/avr-flash-qualifier.exp
> new file mode 100644
> index 0000000..e9ccb4f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/avr-flash-qualifier.exp
> @@ -0,0 +1,52 @@
> +# Copyright 2014 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 <http://www.gnu.org/licenses/>.
> +#
> +# This file is part of the gdb testsuite.
> +#
> +# Contributed by Pierre Langlois  <pierre.langlois@embecosm.com>
> +# Tests for the AVR __flash named address space qualifier.
> +
> +if {![istarget "avr*"]} {
> +  verbose "Skipping ${gdb_test_file_name}."
> +  return
> +}
> +
> +# The __flash qualifier was added in GCC 4.7.
> +if {[test_compiler_info {gcc-[0-4]-[0-6]}]} {
> +  verbose "Skipping ${gdb_test_file_name}."
> +  return
> +}
> +
> +standard_testfile
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}]} {
> +  return -1
> +}
> +
> +if ![runto [gdb_get_line_number "break here."]] {
> +  untested "could not run to \"break here.\""
> +  return -1
> +}
> +
> +gdb_test "print pointer_to_flash" \
> +  " = $hex <data_in_flash> .*"
> +
> +gdb_breakpoint "pass_to_function"
> +gdb_continue_to_breakpoint "pass_to_function"
> +
> +gdb_test "print p" \
> +  " = $hex <data_in_flash> .*"
> +
> +gdb_test "backtrace 1" \
> +  "\#0  pass_to_function \\(p=$hex <data_in_flash> .*\\).*"
>



More information about the Gdb-patches mailing list