1 /* od-avrelf.c -- dump information about an AVR elf object file.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
3 Written by Senthil Kumar Selvaraj, Atmel.
5 This file is part of GNU Binutils.
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)
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.
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. */
26 #include "safe-ctype.h"
32 #include "elf/external.h"
33 #include "elf/internal.h"
34 #include "elf32-avr.h"
36 /* Index of the options in the options[] array. */
37 #define OPT_MEMUSAGE 0
39 #define OPT_AVRDEVICEINFO 2
41 /* List of actions. */
42 static struct objdump_private_option options
[] =
46 { "avr-deviceinfo", 0},
53 elf32_avr_help (FILE *stream
)
57 mem-usage Display memory usage\n\
58 avr-prop Display contents of .avr.prop section\n\
59 avr-deviceinfo Display contents of .note.gnu.avr.deviceinfo section\n\
63 typedef struct tagDeviceInfo
69 uint32_t eeprom_start
;
75 /* Return TRUE if ABFD is handled. */
78 elf32_avr_filter (bfd
*abfd
)
80 return bfd_get_flavour (abfd
) == bfd_target_elf_flavour
;
84 elf32_avr_get_note_section_contents (bfd
*abfd
, bfd_size_type
*size
)
89 section
= bfd_get_section_by_name (abfd
, ".note.gnu.avr.deviceinfo");
93 if (!bfd_malloc_and_get_section (abfd
, section
, &contents
))
99 *size
= bfd_section_size (section
);
100 return (char *) contents
;
104 elf32_avr_get_note_desc (bfd
*abfd
, char *contents
, bfd_size_type size
,
105 bfd_size_type
*descsz
)
107 Elf_External_Note
*xnp
= (Elf_External_Note
*) contents
;
108 Elf_Internal_Note in
;
110 if (offsetof (Elf_External_Note
, name
) > size
)
113 in
.type
= bfd_get_32 (abfd
, xnp
->type
);
114 in
.namesz
= bfd_get_32 (abfd
, xnp
->namesz
);
115 in
.namedata
= xnp
->name
;
116 if (in
.namesz
> contents
- in
.namedata
+ size
)
119 if (in
.namesz
!= 4 || strcmp (in
.namedata
, "AVR") != 0)
122 in
.descsz
= bfd_get_32 (abfd
, xnp
->descsz
);
123 in
.descdata
= in
.namedata
+ align_power (in
.namesz
, 2);
124 if (in
.descsz
< 6 * sizeof (uint32_t)
125 || in
.descdata
>= contents
+ size
126 || in
.descsz
> contents
- in
.descdata
+ size
)
129 /* If the note has a string table, ensure it is 0 terminated. */
130 if (in
.descsz
> 8 * sizeof (uint32_t))
131 in
.descdata
[in
.descsz
- 1] = 0;
138 elf32_avr_get_device_info (bfd
*abfd
, char *description
,
139 bfd_size_type desc_size
, deviceinfo
*device
)
141 if (description
== NULL
)
144 const bfd_size_type memory_sizes
= 6;
146 memcpy (device
, description
, memory_sizes
* sizeof (uint32_t));
147 desc_size
-= memory_sizes
* sizeof (uint32_t);
151 uint32_t *stroffset_table
= (uint32_t *) description
+ memory_sizes
;
152 bfd_size_type stroffset_table_size
= bfd_get_32 (abfd
, stroffset_table
);
154 /* If the only content is the size itself, there's nothing in the table */
155 if (stroffset_table_size
< 8)
157 if (desc_size
<= stroffset_table_size
)
159 desc_size
-= stroffset_table_size
;
161 /* First entry is the device name index. */
162 uint32_t device_name_index
= bfd_get_32 (abfd
, stroffset_table
+ 1);
163 if (device_name_index
>= desc_size
)
166 char *str_table
= (char *) stroffset_table
+ stroffset_table_size
;
167 device
->name
= str_table
+ device_name_index
;
170 /* Get the size of section *SECNAME, truncated to a reasonable value in
171 order to catch PR 27285 and dysfunctional binaries. */
174 elf32_avr_get_truncated_size (bfd
*abfd
, const char *secname
)
176 /* Max size of around 1 MiB is more than any reasonable AVR will
177 ever be able to swallow. And it's small enough so that we won't
178 get overflows / UB as demonstrated in PR 27285. */
179 const bfd_size_type max_size
= 1000000;
180 bfd_size_type size
= 0;
183 section
= bfd_get_section_by_name (abfd
, secname
);
187 size
= bfd_section_size (section
);
188 if (size
> INT32_MAX
)
190 fprintf (stderr
, _("Warning: section %s has a negative size of"
191 " %ld bytes, saturating to 0 bytes\n"),
192 secname
, (long) (int32_t) size
);
195 else if (size
> max_size
)
197 fprintf (stderr
, _("Warning: section %s has an impossible size of"
198 " %lu bytes, truncating to %lu bytes\n"),
199 secname
, (unsigned long) size
, (unsigned long) max_size
);
208 elf32_avr_get_memory_usage (bfd
*abfd
,
209 bfd_size_type
*text_usage
,
210 bfd_size_type
*data_usage
,
211 bfd_size_type
*eeprom_usage
)
213 bfd_size_type avr_textsize
= elf32_avr_get_truncated_size (abfd
, ".text");
214 bfd_size_type avr_datasize
= elf32_avr_get_truncated_size (abfd
, ".data");;
215 bfd_size_type avr_bsssize
= elf32_avr_get_truncated_size (abfd
, ".bss");
216 bfd_size_type noinitsize
= elf32_avr_get_truncated_size (abfd
, ".noinit");
217 bfd_size_type rodatasize
= elf32_avr_get_truncated_size (abfd
, ".rodata");
218 bfd_size_type eepromsize
= elf32_avr_get_truncated_size (abfd
, ".eeprom");
219 bfd_size_type bootloadersize
= elf32_avr_get_truncated_size (abfd
,
222 *text_usage
= avr_textsize
+ avr_datasize
+ rodatasize
+ bootloadersize
;
223 *data_usage
= avr_datasize
+ avr_bsssize
+ noinitsize
;
224 *eeprom_usage
= eepromsize
;
228 elf32_avr_dump_mem_usage (bfd
*abfd
)
230 char *description
= NULL
;
231 bfd_size_type sec_size
, desc_size
;
233 deviceinfo device
= { 0, 0, 0, 0, 0, 0, NULL
};
234 device
.name
= "Unknown";
236 bfd_size_type data_usage
= 0;
237 bfd_size_type text_usage
= 0;
238 bfd_size_type eeprom_usage
= 0;
240 char *contents
= elf32_avr_get_note_section_contents (abfd
, &sec_size
);
242 if (contents
!= NULL
)
244 description
= elf32_avr_get_note_desc (abfd
, contents
, sec_size
,
246 elf32_avr_get_device_info (abfd
, description
, desc_size
, &device
);
249 elf32_avr_get_memory_usage (abfd
, &text_usage
, &data_usage
,
252 printf ("AVR Memory Usage\n"
254 "Device: %s\n\n", device
.name
);
257 printf ("Program:%8" PRIu64
" bytes", (uint64_t) text_usage
);
258 if (device
.flash_size
> 0)
259 printf (" (%2.1f%% Full)", (double) text_usage
/ device
.flash_size
* 100);
261 printf ("\n(.text + .data + .rodata + .bootloader)\n\n");
264 printf ("Data: %8" PRIu64
" bytes", (uint64_t) data_usage
);
265 if (device
.ram_size
> 0)
266 printf (" (%2.1f%% Full)", (double) data_usage
/ device
.ram_size
* 100);
268 printf ("\n(.data + .bss + .noinit)\n\n");
271 if (eeprom_usage
> 0)
273 printf ("EEPROM: %8" PRIu64
" bytes", (uint64_t) eeprom_usage
);
274 if (device
.eeprom_size
> 0)
275 printf (" (%2.1f%% Full)",
276 (double) eeprom_usage
/ device
.eeprom_size
* 100);
278 printf ("\n(.eeprom)\n\n");
281 if (contents
!= NULL
)
287 elf32_avr_dump_avr_prop (bfd
*abfd
)
289 struct avr_property_record_list
*r_list
;
292 r_list
= avr_elf32_load_property_records (abfd
);
296 printf ("\nContents of `%s' section:\n\n", r_list
->section
->name
);
298 printf (" Version: %d\n", r_list
->version
);
299 printf (" Flags: %#x\n\n", r_list
->flags
);
301 for (i
= 0; i
< r_list
->record_count
; ++i
)
303 printf (" %d %s @ %s + %#08" PRIx64
" (%#08" PRIx64
")\n",
305 avr_elf32_property_record_name (&r_list
->records
[i
]),
306 r_list
->records
[i
].section
->name
,
307 (uint64_t) r_list
->records
[i
].offset
,
308 ((uint64_t) bfd_section_vma (r_list
->records
[i
].section
)
309 + r_list
->records
[i
].offset
));
310 switch (r_list
->records
[i
].type
)
313 /* Nothing else to print. */
315 case RECORD_ORG_AND_FILL
:
316 printf (" Fill: %#08lx\n",
317 r_list
->records
[i
].data
.org
.fill
);
320 printf (" Align: %#08lx\n",
321 r_list
->records
[i
].data
.align
.bytes
);
323 case RECORD_ALIGN_AND_FILL
:
324 printf (" Align: %#08lx, Fill: %#08lx\n",
325 r_list
->records
[i
].data
.align
.bytes
,
326 r_list
->records
[i
].data
.align
.fill
);
335 elf32_avr_dump_avr_deviceinfo (bfd
*abfd
)
337 char *description
= NULL
;
338 bfd_size_type sec_size
, desc_size
;
340 deviceinfo dinfo
= { 0, 0, 0, 0, 0, 0, NULL
};
341 dinfo
.name
= "Unknown";
343 char *contents
= elf32_avr_get_note_section_contents (abfd
, &sec_size
);
345 if (contents
== NULL
)
348 description
= elf32_avr_get_note_desc (abfd
, contents
, sec_size
, &desc_size
);
349 elf32_avr_get_device_info (abfd
, description
, desc_size
, &dinfo
);
351 printf ("AVR Device Info\n"
353 "Device: %s\n\n", dinfo
.name
);
355 printf ("Memory Start Size Start Size\n");
357 printf ("Flash %9" PRIu32
" %9" PRIu32
" %#9" PRIx32
" %#9" PRIx32
"\n",
358 dinfo
.flash_start
, dinfo
.flash_size
,
359 dinfo
.flash_start
, dinfo
.flash_size
);
361 /* FIXME: There are devices like ATtiny11 without RAM, and where the
362 avr/io*.h header has defines like
363 #define RAMSTART 0x60
364 // Last memory addresses
366 which results in a negative RAM size. The correct display would be to
367 show a size of 0, however we also want to show what's actually in the
368 note section as precise as possible. Hence, display the decimal size
370 printf ("RAM %9" PRIu32
" %9" PRId32
" %#9" PRIx32
" %#9" PRIx32
"\n",
371 dinfo
.ram_start
, dinfo
.ram_size
,
372 dinfo
.ram_start
, dinfo
.ram_size
);
374 printf ("EEPROM %9" PRIu32
" %9" PRIu32
" %#9" PRIx32
" %#9" PRIx32
"\n",
375 dinfo
.eeprom_start
, dinfo
.eeprom_size
,
376 dinfo
.eeprom_start
, dinfo
.eeprom_size
);
382 elf32_avr_dump (bfd
*abfd
)
384 if (options
[OPT_MEMUSAGE
].selected
)
385 elf32_avr_dump_mem_usage (abfd
);
386 if (options
[OPT_AVRPROP
].selected
)
387 elf32_avr_dump_avr_prop (abfd
);
388 if (options
[OPT_AVRDEVICEINFO
].selected
)
389 elf32_avr_dump_avr_deviceinfo (abfd
);
392 const struct objdump_private_desc objdump_private_desc_elf32_avr
=