picotool icon indicating copy to clipboard operation
picotool copied to clipboard

picotool crashes when given an ELF built with embedded rust

Open jonathanpallant opened this issue 4 years ago • 9 comments

$ 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 avatar Oct 05 '21 10:10 jonathanpallant

$ 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)

jonathanpallant avatar Oct 05 '21 10:10 jonathanpallant

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:

lurch avatar Oct 05 '21 10:10 lurch

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

jonathanpallant avatar Oct 05 '21 10:10 jonathanpallant

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

jonathanpallant avatar Oct 05 '21 10:10 jonathanpallant

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

kilograham avatar Oct 05 '21 16:10 kilograham

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

lurch avatar Oct 22 '21 12:10 lurch

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.

jannic avatar Jun 05 '22 12:06 jannic

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 ?

lurch avatar Jun 05 '22 12:06 lurch

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.

jannic avatar Nov 19 '22 10:11 jannic

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

kilograham avatar Feb 09 '23 00:02 kilograham

@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
[...]

jannic avatar Feb 09 '23 12:02 jannic

merged into develop

kilograham avatar Feb 10 '23 13:02 kilograham