xref: /netbsd-src/external/gpl3/binutils.old/dist/binutils/od-elf32_avr.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1 /* od-avrelf.c -- dump information about an AVR elf object file.
2    Copyright (C) 2011-2022 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
elf32_avr_help(FILE * stream)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
elf32_avr_filter(bfd * abfd)75 elf32_avr_filter (bfd *abfd)
76 {
77   return bfd_get_flavour (abfd) == bfd_target_elf_flavour;
78 }
79 
80 static char *
elf32_avr_get_note_section_contents(bfd * abfd,bfd_size_type * size)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 *
elf32_avr_get_note_desc(bfd * abfd,char * contents,bfd_size_type size,bfd_size_type * descsz)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
elf32_avr_get_device_info(bfd * abfd,char * description,bfd_size_type desc_size,deviceinfo * device)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
elf32_avr_get_memory_usage(bfd * abfd,bfd_size_type * text_usage,bfd_size_type * data_usage,bfd_size_type * eeprom_usage)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
elf32_avr_dump_mem_usage(bfd * abfd)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
elf32_avr_dump_avr_prop(bfd * abfd)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
elf32_avr_dump(bfd * abfd)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   };
365