raspberrypi / picotool

BSD 3-Clause "New" or "Revised" License
555 stars 95 forks source link

picotool crashes when given an ELF built with embedded rust #39

Closed jonathanpallant closed 1 year ago

jonathanpallant commented 2 years ago
$ cargo build --example pico_blinky
   Compiling pico v0.1.0 (/home/jonathan/rp-hal/boards/pico)
    Finished dev [unoptimized + debuginfo] target(s) in 0.91s
$ ../picotool/build/picotool info ./target/thumbv6m-none-eabi/debug/examples/pico_blinky
ERROR: filename './target/thumbv6m-none-eabi/debug/examples/pico_blinky' does not have a recognized file type (extension)
$ cp ./target/thumbv6m-none-eabi/debug/examples/pico_blinky ./pico_blinky.elf
$ ../picotool/build/picotool info ./pico_blinky.elf
picotool: /home/jonathan/picotool/main.cpp:156: void range_map<T>::check_overlap(uint32_t) [with T = long unsigned int; uint32_t = unsigned int]: Assertion `p >= f->first' failed.
[1]    3871 abort      ../picotool/build/picotool info ./pico_blinky.elf
jonathanpallant commented 2 years ago
$ readelf --sections pico_blinky.elf
There are 24 section headers, starting at offset 0x323f38:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .vector_table     PROGBITS        10000100 000114 0000a8 00   A  0   0  4
  [ 2] .boot2            PROGBITS        10000000 0001bc 000100 00   A  0   0  1
  [ 3] .text             PROGBITS        100001a8 0002bc 00d4f4 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        1000d6a0 00d7b0 000f08 00  AM  0   0 16
  [ 5] .data             PROGBITS        20000000 00e6b8 000000 00   A  0   0  4
  [ 6] .gnu.sgstubs      PROGBITS        1000e5c0 00e6c0 000000 00   A  0   0 32
  [ 7] .bss              NOBITS          20000000 00e6c0 000004 00  WA  0   0  4
  [ 8] .uninit           NOBITS          20000004 00e6c0 000000 00  WA  0   0  4
  [ 9] .debug_abbrev     PROGBITS        00000000 00e6c0 00c97e 00      0   0  1
  [10] .debug_info       PROGBITS        00000000 01b03e 0d83ab 00      0   0  1
  [11] .debug_aranges    PROGBITS        00000000 0f33e9 00bae8 00      0   0  1
  [12] .debug_str        PROGBITS        00000000 0feed1 0e4805 01  MS  0   0  1
  [13] .debug_pubnames   PROGBITS        00000000 1e36d6 02ffd0 00      0   0  1
  [14] .debug_pubtypes   PROGBITS        00000000 2136a6 03c60d 00      0   0  1
  [15] .ARM.attributes   ARM_ATTRIBUTES  00000000 24fcb3 000032 00      0   0  1
  [16] .debug_frame      PROGBITS        00000000 24fce8 0215ec 00      0   0  4
  [17] .debug_line       PROGBITS        00000000 2712d4 07dc33 00      0   0  1
  [18] .debug_loc        PROGBITS        00000000 2eef07 000e33 00      0   0  1
  [19] .debug_ranges     PROGBITS        00000000 2efd3a 01e8b8 00      0   0  1
  [20] .comment          PROGBITS        00000000 30e5f2 00006d 01  MS  0   0  1
  [21] .symtab           SYMTAB          00000000 30e660 006570 10     23 1194  4
  [22] .shstrtab         STRTAB          00000000 314bd0 0000fd 00      0   0  1
  [23] .strtab           STRTAB          00000000 314ccd 00f268 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)
lurch commented 2 years ago

If it's asserting in check_overlap could you add some extra debug code to picotool to see which sections it thinks are overlapping? I know almost nothing about ELF myself, but I suspect @kilograham will be able to investigate this easier if you can provide a copy of your built pico_blinky.elf ? :slightly_smiling_face:

jonathanpallant commented 2 years ago

I think it's an ordering issue. You always check against the lowest item in the map.

jonathanpallant commented 2 years ago

pico_blinky.zip

jonathanpallant commented 2 years ago

I can confirm that sorting our sections fixes the crash. But you should probably tolerate sections that aren't in order (or at least give a better error than an assertion).

pico_blinky_fixed.zip

kilograham commented 2 years ago

yup this is a bug in the checking code, you can comment it out for now as a workaround - will fix it pretty soon

lurch commented 2 years ago

@jonathanpallant Do you want to test the latest develop version of picotool?

jannic commented 2 years ago

picotool 1.1.0 now does write ELF binaries built with embedded rust without crashing, but the resulting flash contents are broken.

This is caused by the ELF binaries containing non-contiguous ranges which end / begin in the same flash erase page. Eg.:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .vector_table     PROGBITS        10000100 010100 0000a8 00   A  0   0  4
  [ 2] .boot2            PROGBITS        10000000 020000 000100 00   A  0   0  1
  [ 3] .text             PROGBITS        100001a8 0201a8 00ec8c 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        1000ee40 02ee40 00185c 00  AM  0   0 16
  [ 5] .data             PROGBITS        20000000 03069c 000000 00   A  0   0  4
  [ 6] .gnu.sgstubs      PROGBITS        100106a0 0306a0 000000 00   A  0   0 32
  [ 7] .bss              NOBITS          20000000 040000 000004 00  WA  0   0  4
  [ 8] .uninit           NOBITS          20000004 040000 000000 00  WA  0   0  4

Adding some diagnostic output printing the range_map entries shows:

Found memory range 0x10000100->0x100001a8
Found memory range 0x10000000->0x10000100
Found memory range 0x100001a8->0x1000ee34
Found memory range 0x1000ee40->0x1001069c

Notice that there's a hole between 0x1000ee34 and 0x1000ee40.

When writing the last range, the code at https://github.com/raspberrypi/picotool/blob/master/main.cpp#L1854-L1860 will zero the whole erase block, causing the flash contents from 0x1000e000 to 0x1000ee34 to be overwritten with zeros.

This matches what I can see after dumping the resulting flash contents.

lurch commented 2 years ago

This is caused by the ELF binaries containing non-contiguous ranges

Possibly a similar problem to https://github.com/raspberrypi/pico-sdk/issues/762 ?

the code at ... will zero the whole erase block

Hmmm, perhaps picotool contains a similar bug to pico-bootrom ?

jannic commented 1 year ago

Just as a note: I wondered why the ELF files had those gaps between sections at all. Found this questions which might be related: https://stackoverflow.com/questions/66644603/gnu-ld-for-arm-produces-section-alignment-to-unwanted-bound TL;DR: It looks like some linker versions increase the alignment of some sections, which can cause such gaps.

kilograham commented 1 year ago

@jannic any chance you can attach an ELF/UF2 with holes

jannic commented 1 year ago

@jannic any chance you can attach an ELF/UF2 with holes

Sure: pico_blinky.zip (Zipped because github doesn't like raw elf files)

Flashing that file picotool load pico_blinky -t elf fails with 1.1.0 and works with #51. (The flash command itself seems to succeed, but the flash contents are wrong and the blinky example doesn't work.)

readelf -S of that binary:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .vector_table     PROGBITS        10000100 000134 0000a8 00   A  0   0  4
  [ 2] .boot2            PROGBITS        10000000 0001dc 000100 00   A  0   0  1
  [ 3] .text             PROGBITS        100001a8 0002dc 00d974 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        1000db20 00dc50 0012b0 00  AM  0   0 16
  [ 5] .data             PROGBITS        20000000 00ef00 000000 00   A  0   0  4
[...]
kilograham commented 1 year ago

merged into develop