(root)/
binutils-2.41/
binutils/
od-elf32_avr.c
       1  /* od-avrelf.c -- dump information about an AVR elf object file.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3     Written by Senthil Kumar Selvaraj, Atmel.
       4  
       5     This file is part of GNU Binutils.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3, or (at your option)
      10     any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, write to the Free Software
      19     Foundation, 51 Franklin Street - Fifth Floor, Boston,
      20     MA 02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include <stddef.h>
      24  #include <time.h>
      25  #include <stdint.h>
      26  #include "safe-ctype.h"
      27  #include "bfd.h"
      28  #include "objdump.h"
      29  #include "bucomm.h"
      30  #include "bfdlink.h"
      31  #include "bfd.h"
      32  #include "elf/external.h"
      33  #include "elf/internal.h"
      34  #include "elf32-avr.h"
      35  
      36  /* Index of the options in the options[] array.  */
      37  #define OPT_MEMUSAGE 0
      38  #define OPT_AVRPROP 1
      39  
      40  /* List of actions.  */
      41  static struct objdump_private_option options[] =
      42    {
      43      { "mem-usage", 0 },
      44      { "avr-prop",  0},
      45      { NULL, 0 }
      46    };
      47  
      48  /* Display help.  */
      49  
      50  static void
      51  elf32_avr_help (FILE *stream)
      52  {
      53    fprintf (stream, _("\
      54  For AVR ELF files:\n\
      55    mem-usage   Display memory usage\n\
      56    avr-prop    Display contents of .avr.prop section\n\
      57  "));
      58  }
      59  
      60  typedef struct tagDeviceInfo
      61  {
      62      uint32_t flash_start;
      63      uint32_t flash_size;
      64      uint32_t ram_start;
      65      uint32_t ram_size;
      66      uint32_t eeprom_start;
      67      uint32_t eeprom_size;
      68      char * name;
      69  } deviceinfo;
      70  
      71  
      72  /* Return TRUE if ABFD is handled.  */
      73  
      74  static int
      75  elf32_avr_filter (bfd *abfd)
      76  {
      77    return bfd_get_flavour (abfd) == bfd_target_elf_flavour;
      78  }
      79  
      80  static char *
      81  elf32_avr_get_note_section_contents (bfd *abfd, bfd_size_type *size)
      82  {
      83    asection *section;
      84    bfd_byte *contents;
      85  
      86    section = bfd_get_section_by_name (abfd, ".note.gnu.avr.deviceinfo");
      87    if (section == NULL)
      88      return NULL;
      89  
      90    if (!bfd_malloc_and_get_section (abfd, section, &contents))
      91      {
      92        free (contents);
      93        contents = NULL;
      94      }
      95  
      96    *size = bfd_section_size (section);
      97    return (char *) contents;
      98  }
      99  
     100  static char *
     101  elf32_avr_get_note_desc (bfd *abfd, char *contents, bfd_size_type size,
     102  			 bfd_size_type *descsz)
     103  {
     104    Elf_External_Note *xnp = (Elf_External_Note *) contents;
     105    Elf_Internal_Note in;
     106  
     107    if (offsetof (Elf_External_Note, name) > size)
     108      return NULL;
     109  
     110    in.type = bfd_get_32 (abfd, xnp->type);
     111    in.namesz = bfd_get_32 (abfd, xnp->namesz);
     112    in.namedata = xnp->name;
     113    if (in.namesz > contents - in.namedata + size)
     114      return NULL;
     115  
     116    if (in.namesz != 4 || strcmp (in.namedata, "AVR") != 0)
     117      return NULL;
     118  
     119    in.descsz = bfd_get_32 (abfd, xnp->descsz);
     120    in.descdata = in.namedata + align_power (in.namesz, 2);
     121    if (in.descsz < 6 * sizeof (uint32_t)
     122        || in.descdata >= contents + size
     123        || in.descsz > contents - in.descdata + size)
     124      return NULL;
     125  
     126    /* If the note has a string table, ensure it is 0 terminated.  */
     127    if (in.descsz > 8 * sizeof (uint32_t))
     128      in.descdata[in.descsz - 1] = 0;
     129  
     130    *descsz = in.descsz;
     131    return in.descdata;
     132  }
     133  
     134  static void
     135  elf32_avr_get_device_info (bfd *abfd, char *description,
     136  			   bfd_size_type desc_size, deviceinfo *device)
     137  {
     138    if (description == NULL)
     139      return;
     140  
     141    const bfd_size_type memory_sizes = 6;
     142  
     143    memcpy (device, description, memory_sizes * sizeof (uint32_t));
     144    desc_size -= memory_sizes * sizeof (uint32_t);
     145    if (desc_size < 8)
     146      return;
     147  
     148    uint32_t *stroffset_table = (uint32_t *) description + memory_sizes;
     149    bfd_size_type stroffset_table_size = bfd_get_32 (abfd, stroffset_table);
     150  
     151    /* If the only content is the size itself, there's nothing in the table */
     152    if (stroffset_table_size < 8)
     153      return;
     154    if (desc_size <= stroffset_table_size)
     155      return;
     156    desc_size -= stroffset_table_size;
     157  
     158    /* First entry is the device name index. */
     159    uint32_t device_name_index = bfd_get_32 (abfd, stroffset_table + 1);
     160    if (device_name_index >= desc_size)
     161      return;
     162  
     163    char *str_table = (char *) stroffset_table + stroffset_table_size;
     164    device->name = str_table + device_name_index;
     165  }
     166  
     167  static void
     168  elf32_avr_get_memory_usage (bfd *abfd,
     169  			    bfd_size_type *text_usage,
     170  			    bfd_size_type *data_usage,
     171  			    bfd_size_type *eeprom_usage)
     172  {
     173  
     174    bfd_size_type avr_datasize = 0;
     175    bfd_size_type avr_textsize = 0;
     176    bfd_size_type avr_bsssize = 0;
     177    bfd_size_type bootloadersize = 0;
     178    bfd_size_type noinitsize = 0;
     179    bfd_size_type eepromsize = 0;
     180    bfd_size_type res;
     181    asection *section;
     182  
     183    if ((section = bfd_get_section_by_name (abfd, ".data")) != NULL)
     184      avr_datasize = bfd_section_size (section);
     185    if ((section = bfd_get_section_by_name (abfd, ".text")) != NULL)
     186      avr_textsize = bfd_section_size (section);
     187    if ((section = bfd_get_section_by_name (abfd, ".bss")) != NULL)
     188      avr_bsssize = bfd_section_size (section);
     189    if ((section = bfd_get_section_by_name (abfd, ".bootloader")) != NULL)
     190      bootloadersize = bfd_section_size (section);
     191    if ((section = bfd_get_section_by_name (abfd, ".noinit")) != NULL)
     192      noinitsize = bfd_section_size (section);
     193    if ((section = bfd_get_section_by_name (abfd, ".eeprom")) != NULL)
     194      eepromsize = bfd_section_size (section);
     195  
     196    /* PR 27285: Check for overflow.  */
     197    res = avr_textsize + avr_datasize;
     198    if (res < avr_textsize || res < avr_datasize)
     199      {
     200        fprintf (stderr, _("Warning: textsize (%#lx) + datasize (%#lx) overflows size type\n"),
     201  	       (long) avr_textsize, (long) avr_datasize);
     202        res = (bfd_size_type) -1;
     203      }
     204    else
     205      {
     206        bfd_size_type res2;
     207        res2 = res + bootloadersize;
     208        if (res2 < bootloadersize || res2 < res)
     209  	{
     210  	  fprintf (stderr, _("Warning: textsize (%#lx) + datasize (%#lx) + bootloadersize (%#lx) overflows size type\n"),
     211  		   (long) avr_textsize, (long) avr_datasize, (long) bootloadersize);
     212  	  res2 = (bfd_size_type) -1;
     213  	}
     214        res = res2;
     215      }
     216    *text_usage = res;
     217  
     218    res = avr_datasize + avr_bsssize;
     219    if (res < avr_datasize || res < avr_bsssize)
     220      {
     221        fprintf (stderr, _("Warning: datatsize (%#lx) + bssssize (%#lx) overflows size type\n"),
     222  	       (long) avr_datasize, (long) avr_bsssize);
     223        res = (bfd_size_type) -1;
     224      }
     225    else
     226      {
     227        bfd_size_type res2;
     228  
     229        res2 = res + noinitsize;
     230        if (res2 < res || res2 < noinitsize)
     231  	{
     232  	  fprintf (stderr, _("Warning: datasize (%#lx) + bsssize (%#lx) + noinitsize (%#lx) overflows size type\n"),
     233  		   (long) avr_datasize, (long) avr_bsssize, (long) noinitsize);
     234  	  res2 = (bfd_size_type) -1;
     235  	}
     236        res = res2;
     237      }
     238    *data_usage = res;
     239  
     240    *eeprom_usage = eepromsize;
     241  }
     242  
     243  static void
     244  elf32_avr_dump_mem_usage (bfd *abfd)
     245  {
     246    char *description = NULL;
     247    bfd_size_type sec_size, desc_size;
     248  
     249    deviceinfo device = { 0, 0, 0, 0, 0, 0, NULL };
     250    device.name = "Unknown";
     251  
     252    bfd_size_type data_usage = 0;
     253    bfd_size_type text_usage = 0;
     254    bfd_size_type eeprom_usage = 0;
     255  
     256    char *contents = elf32_avr_get_note_section_contents (abfd, &sec_size);
     257  
     258    if (contents != NULL)
     259      {
     260        description = elf32_avr_get_note_desc (abfd, contents, sec_size,
     261  					     &desc_size);
     262        elf32_avr_get_device_info (abfd, description, desc_size, &device);
     263      }
     264  
     265    elf32_avr_get_memory_usage (abfd, &text_usage, &data_usage,
     266  			      &eeprom_usage);
     267  
     268    printf ("AVR Memory Usage\n"
     269            "----------------\n"
     270            "Device: %s\n\n", device.name);
     271  
     272    /* Text size */
     273    printf ("Program:%8lu bytes", text_usage);
     274    if (device.flash_size > 0)
     275      printf (" (%2.1f%% Full)", ((float) text_usage / device.flash_size) * 100);
     276  
     277    printf ("\n(.text + .data + .bootloader)\n\n");
     278  
     279    /* Data size */
     280    printf ("Data:   %8lu bytes", data_usage);
     281    if (device.ram_size > 0)
     282      printf (" (%2.1f%% Full)", ((float) data_usage / device.ram_size) * 100);
     283  
     284    printf ("\n(.data + .bss + .noinit)\n\n");
     285  
     286    /* EEPROM size */
     287    if (eeprom_usage > 0)
     288      {
     289        printf ("EEPROM: %8lu bytes", eeprom_usage);
     290        if (device.eeprom_size > 0)
     291          printf (" (%2.1f%% Full)", ((float) eeprom_usage / device.eeprom_size) * 100);
     292  
     293        printf ("\n(.eeprom)\n\n");
     294      }
     295  
     296    if (contents != NULL)
     297      free (contents);
     298  
     299  }
     300  
     301  static void
     302  elf32_avr_dump_avr_prop (bfd *abfd)
     303  {
     304    struct avr_property_record_list *r_list;
     305    unsigned int i;
     306  
     307    r_list = avr_elf32_load_property_records (abfd);
     308    if (r_list == NULL)
     309      return;
     310  
     311    printf ("\nContents of `%s' section:\n\n", r_list->section->name);
     312  
     313    printf ("  Version: %d\n", r_list->version);
     314    printf ("  Flags:   %#x\n\n", r_list->flags);
     315  
     316    for (i = 0; i < r_list->record_count; ++i)
     317      {
     318        printf ("   %d %s @ %s + %#08lx (%#08lx)\n",
     319  	      i,
     320  	      avr_elf32_property_record_name (&r_list->records [i]),
     321  	      r_list->records [i].section->name,
     322  	      r_list->records [i].offset,
     323  	      (bfd_section_vma (r_list->records [i].section)
     324  	       + r_list->records [i].offset));
     325        switch (r_list->records [i].type)
     326          {
     327          case RECORD_ORG:
     328            /* Nothing else to print.  */
     329            break;
     330          case RECORD_ORG_AND_FILL:
     331            printf ("     Fill: %#08lx\n",
     332                    r_list->records [i].data.org.fill);
     333            break;
     334          case RECORD_ALIGN:
     335            printf ("     Align: %#08lx\n",
     336                    r_list->records [i].data.align.bytes);
     337            break;
     338          case RECORD_ALIGN_AND_FILL:
     339            printf ("     Align: %#08lx, Fill: %#08lx\n",
     340                    r_list->records [i].data.align.bytes,
     341                    r_list->records [i].data.align.fill);
     342            break;
     343          }
     344      }
     345  
     346    free (r_list);
     347  }
     348  
     349  static void
     350  elf32_avr_dump (bfd *abfd)
     351  {
     352    if (options[OPT_MEMUSAGE].selected)
     353      elf32_avr_dump_mem_usage (abfd);
     354    if (options[OPT_AVRPROP].selected)
     355      elf32_avr_dump_avr_prop (abfd);
     356  }
     357  
     358  const struct objdump_private_desc objdump_private_desc_elf32_avr =
     359    {
     360      elf32_avr_help,
     361      elf32_avr_filter,
     362      elf32_avr_dump,
     363      options
     364    };