rust-embedded / wg

Coordination repository of the embedded devices Working Group
1.9k stars 99 forks source link

One step setup #43

Closed japaric closed 3 months ago

japaric commented 6 years ago

Embedded development involves cross compilation and remote debugging; the Rust toolchain doesn't provide all the tools so you have to install external ones like: a cross linker (e.g. arm-none-eabi-ld), a cross debugger (e.g. arm-none-eabi-gdb), some tool to communicate with the remote target (e.g. OpenOCD), etc.

It would be great if the user didn't have to figure out where to get all those tools and install them manually.

There are a few upcoming changes that might affect this situation.

lld is a multi-arch linker and it can be used to link ARM Cortex-M binaries so once this is in place user won't need to install arm-none-eabi-ld.

I don't think lld supports any of the other embedded targets (MSP430, AVR or RISCV) though

lldb is a multi-arch debugger. I personally could never get it to work with OpenOCD; I never found an equivalent to the monitor and load commands which are used to flash the binary into the remote target. lldb can debug ARM Cortex-M programs just fine; I have used it debug a emulated ARM Cortex-M microcontroller (QEMU).

Maybe someone had more luck with it and can share their experience?


One way to address this setup problem could be to provide a installer (script) like https://rustup.rs/ does but for each target architecture.

cc @jcsoo

whitequark commented 6 years ago

I never found an equivalent to the monitor and load commands which are used to flash the binary into the remote target.

The monitor command is process plugin packet monitor in lldb, and I'm afraid it's rather user unfriendly:

(lldb) process plugin packet monitor help
  packet: qRcmd,68656c70
response: O54686520666f6c6c6f77696e67206d6f6e69746f7220636f6d6d616e64732061726520737570706f727465643a0a

The flash functionality of the gdb stub is not supported.

IMO, it's a good idea to extend lldb to handle these use cases instead of giving up on it.

jcsoo commented 6 years ago

I haven't had a chance to try LLD / LLDB yet - for now, do you have to build LLVM from scratch to install them? What version should we be using to be close to what Rust is using? Or can we get them by doing a full Rust build?

Bobbin-CLI (https://github.com/bobbin-rs/bobbin-cli/) currently knows about many debuggers and flash loaders, and the documentation currently has pointers to download sites as well as some documentation about how to build and install them: https://github.com/bobbin-rs/bobbin-cli/blob/master/FIRMWARE.md

There's also a "bobbin check" command that scans for all tools that it knows about and displays version information:

mbp15:~ jcsoo$ bobbin check
    Bobbin 0.8.0
      Rust 1.25.0-nightly (27a046e93 2018-02-18)
     Cargo 0.26.0-nightly (1d6dfea44 2018-01-26)
     Xargo 0.3.10
       GCC 5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496]
   OpenOCD 0.10.0+dev-g7c2dc13 (2017-02-12-10:20)
     JLink V6.19e (Compiled Sep  1 2017 18:27:51)
     Bossa 1.7.0
    Teensy 2.1
  dfu-util 0.9

This could conceivably be extended to check for outdated versions and to add direct documentation links. Bobbin-CLI also has a database of USB Vendor / Product IDs that could be used to auto-detect devices with missing tools and point users to documentation and download links.

I've considered adding rustup style functionality but I don't think it's practical because of the third-party nature of these tools. I think the effort is better spent in building rust-native tools and/or building support directly into Bobbin-CLI. For instance, Teensy is a simple USB HID protocol, dfu-util is a reasonably straightforward USB protocol, and Bossa uses a serial protocol.

Bobbin-CLI also supports dumping files onto USB MSD volumes, which covers many ST-Link and DAPLink debuggers, and it might not be too difficult to teach it enough of the GDB remote protocol to handle flashing to anything that exposes a GDB server (JLink, and Black Magic Probe). In the long run there is https://github.com/mbedmicro/FlashAlgo which is collecting flash algorithms for a wide variety of targets.

So, it could conceivably have native flash loading support for a fairly broad range of boards and debuggers, limiting the OpenOCD dependency to people that need remote debugging or need to support devices that aren't covered.

dvc94ch commented 6 years ago

So is there interest in making an openocd crate so that it can be installed via cargo? I think this would be a requirement for useful cargo flash and cargo debug commands.

whitequark commented 6 years ago

Repackaging completely unrelated C applications in cargo seems wrong. The gcc crate doesn't package gcc...

hannobraun commented 6 years ago

@jcsoo

I think the effort is better spent in building rust-native tools and/or building support directly into Bobbin-CLI. For instance, Teensy is a simple USB HID protocol, dfu-util is a reasonably straightforward USB protocol, and Bossa uses a serial protocol.

A few years ago, I built a simple tool to replace Bossa for my own use, to upload to the SAM3X8E. Here: https://github.com/hannobraun/embedded/tree/master/uploader

I don't know how much is missing to make it useful, but I recall successfully using it to upload my program at the time. Maybe it can serve as a starting point or reference for your own efforts.

dvc94ch commented 6 years ago

@whitequark gcc isn't essential to the toolchain, and would require a dozen different crates for each architecture. Relying on distro package managers can be an option for Linux/established computer architectures. If we want a seamless experience for non-linux and archs like riscv, what do you suggest as an alternative? Rewriting openocd in rust is probably not a realistic goal till September

whitequark commented 6 years ago

@dvc94ch If you want a seamless experience? Rely on system package managers for Linux and OS X, and provide prebuilt Windows installers.

Even if you did package openocd as a crate, it depends on, at least, MinGW, MSYS and libusb1 to build on Windows, and these dependencies ensure that it's not going to be installable as simple as cargo install openocd. That's forgetting about any adapters more complex than FTDI ones...

thejpster commented 6 years ago

I think OpenOCD is a well solved problem and I don't think we need to do much there. What's more useful, I think, is helping people understand the differences between the normal C development process for any given platform and the 'normal' Rust development process. People could effectively then apply those differences to almost any C example/tutorial they find for any random board we've never even heard of.

I think what I'm saying is everything after the ELF is a platform problem not a language problem and I think we should stick to language problems.

jcsoo commented 6 years ago

When Rust has LLD and LLDB integration, does anyone know whether Rust will build, ship, and install the standalone binaries also? And what about other utilities? objcopy will be needed to convert to hex format for many flash loaders, and I use objdump + size very often.

I would hate to do all this work and still need the user to install the full GCC or LLVM toolchain just to get access to those utilities.

Could they be packaged in a separate rustup rust-tools component?

thejpster commented 6 years ago

objdump + size

They're from GNU Binutils, which is distinct to GCC and LLVM. I agree Rust versions would be easier to ship, but I'm OK with depending upon binutils as-is.

whitequark commented 6 years ago

They're from GNU Binutils, which is distinct to GCC and LLVM.

There are llvm-objdump and llvm-size since sometime late in 3.x cycle.

I'm OK with depending upon binutils as-is.

binutils are a really gross dependency to carry around. First, you get an entire second machine layer with its own independent bugs and deficiencies. There's no guarantee that the disassembler in binutils will know about all the same relocations as LLVM. (I've hit this.) Second, they're a pain in the ass to build on Windows as they require msys or cygwin.

japaric commented 6 years ago

When Rust has LLD and LLDB integration, does anyone know whether Rust will build, ship, and install the standalone binaries also?

That's what rust-lang/rust#48125 does. A LLD binary will be shipped with the Rust toolchain; it will be somewhere in $(rustc --print sysroot). There's some magic that will append the path to LLD to the PATH env variable when rustc invokes the linker so the user won't have to do anything to their environment.

I don't know what's the LLDB plan with respect to PATH.

japaric commented 6 years ago

There's a Rust tool that's basically a objdump re-implementation. Unfortunately I don't recall its name but, iirc, it's based on the Keystone Capstone (dis)assembler.

EDIT: Err, not Keystone; Capstone I think

japaric commented 6 years ago

There's a Rust tool that's basically a objdump re-implementation.

It's called cargo-sym but it doesn't seem like they are working on it anymore (no activity in the last 11 months).

whitequark commented 6 years ago

I really don't think we should use anything besides llvm-objdump if we want to support lesser-used architectures. That's just duplicating work and introducing more opportunity for obscure errors.

Ask me about that time I found out that OR1K assemblers in LLVM and binutils didn't match up, and then that LLVM and ld.bfd didn't agree on whether some DWARF relocation is absolute or relative...

japaric commented 6 years ago

I tested llvm-objdump locally and it worked fine; I had to pass -triple=thumbv7m-none-eabi to it to get the correct diassembly though. I also didn't see any demangling option but piping the output through c++filt did the trick. llvm-size worked without problems.

Given that lld is being added to the Rust toolchain I think we could push (submit an RFC) for shipping both llvm-size and llvm-objdump with the toolchain. That would eliminate the need for installing arm-none-eabi-binutils when targetting ARM Cortex-M and would do the same for the other targets once they get LLD support.

Once llvm-objdump and llvm-size are in place we could publish some thin wrappers as Cargo subcommands (e.g. cargo-objdump) that take care of passing -triple, demangling the output, specifying the full path to the binary, etc.

jcsoo commented 6 years ago

Can we get llvm-objcopy included also? It's needed for generating .bin or .hex files from the ELF output. All of the flash loaders (Bossa, Teensy, dfu-util) as well as ST-Link and DAPLink on-board drag-and-drop require one of those two formats.

whitequark commented 6 years ago

While you're at it, also include:

thejpster commented 6 years ago

llvm-objdump and llvm-size since sometime late in 3.x cycle.

Oh, cool!

binutils are a really gross dependency to carry around

I totally agree that if there are LLVM equivalents then that's a much better approach, and an easier way to get all our architectures supported properly.

thin wrappers ... cargo-objdump

Oh man, that would really improve my workflow.

japaric commented 6 years ago

Based on the discussion so far I have created two work items:

Help wanted!

dvc94ch commented 6 years ago

@therealprof had some success with lldb and stlink. [0]

monitor and load can probably be implemented as python scripts. If someone gets it working with openocd I can probably port lldb to riscv. According to [1] it doesn't seem too involved to get a basic working debugger running and could probably be implemented in a week or two. (gdb keeps segfaulting on me, so I'd be interested in trying a different debugger)

[0] https://www.eggers-club.de/blog/2017/07/01/embedded-debugging-with-lldb-sure/ [1] https://llvm.org/devmtg/2016-03/Tutorials/LLDB-tutorial.pdf

therealprof commented 6 years ago

@dvc94ch The "problem" with lldb is its funny interpretation of the "standard" gdbserver protocol. It'll pretty much only work reliably with it's own counter implementation lldb-server but none of the other available tools (e.g. OpenOCD or Blackmagic Probe) with the only notable exception being st-util from the STLink suite which works to a very basic extend.

I toyed around with lldb for a bit but the major problem I found was that lldb stuffs some important gdb commands into a NUL-terminated string instead of looking at and keeping their real size which means that you cannot put arbitrary binary data in them thus preventing a lot of stuff from working. Changing that seems to be a major effort, especially since lldb uses a rather antiquated development process with a more not so really open community.

dvc94ch commented 6 years ago

lldb uses a rather antiquated development process with a more not so really open community

@therealprof mmh, are not the same people working on it that work on llvm? I got a small patch upstreamed, didn't seem that annoying. I guess it depends on who is actually in charge of the code you want to change? anyway that's a shame...

therealprof commented 6 years ago

Ooh, actually there seems to be movement on the gdbserver protocol support front since I last checked http://lists.llvm.org/pipermail/lldb-dev/2018-January/013078.html .

@dvc94ch There's some overlap. But lldb is mostly handled by Apple and Google people.

therealprof commented 6 years ago

Nice, things are starting to move. Google contributes vFlash command support to lldb just a few days back, however it has been reverted due to virtual/physical address confusion. Otherwise I'd had done a quick check of whether the OpenOCD situation has improved.

pftbest commented 6 years ago

@dvc94ch You mentioned msp430 in your comment, did you mean riscv?

dvc94ch commented 6 years ago

Yes, I copy pasted it from the link I mentioned.

pftbest commented 6 years ago

@dvc94ch Interesting, I'll need to check out this msp430 lldb port.

japaric commented 6 years ago

Update: LLD is now being shipped with the Rust toolchain. You'll need Xargo v0.3.11 to be able to use it though.

Unfortunately, it doesn't seem to be ready for prime (at least when dealing with ARM Cortex-M). See the issues I encountered in https://github.com/japaric/cortex-m-rt/issues/53#issuecomment-371972935.

Ericson2314 commented 6 years ago

So there's a little known feature of binutils that you can configure it with --enable-targets=all and then it is also mutli-target! Or rather, every tool is except for GNU Assembler, but we don't use that anything. Perhaps we should also distribute this, at least as a stop-gap until lld has platform parity?

therealprof commented 6 years ago

@Ericson2314 That feature is close to useless:

# gsize blinky
gsize: blinky: File format is ambiguous
gsize: Matching formats: elf32-littlearm elf32-littlearm-symbian elf32-littlearm-vxworks
# gobjdump -Cd blinky
gobjdump: blinky: File format is ambiguous
gobjdump: Matching formats: elf32-littlearm elf32-littlearm-symbian elf32-littlearm-vxworks

Of course one could make it work by hardcoding all possible targets into understood triplets ...

# gsize --target=arm-none-eabi blinky
   text    data     bss     dec     hex filename
    394       0       4     398     18e blinky
Ericson2314 commented 6 years ago

@therealprof passing flags is a lot less cumbersome than building new tools! Besides, I'm not even sure coming clean about the ambiguity is the wrong approach if the alternative is some some flawed heuristic. ld or lld in build scripts should be passed flags anyways.

therealprof commented 6 years ago

I don't remember the llvm tools being even as close as picky as the gcc/binutils stuff and at least for ARM it just works:

# llvm-size i2c_haldriver_printmagserial
   text    data     bss     dec     hex filename
   3928   17392      20   21340    535c i2c_haldriver_printmagserial

But I'm certainly the last to complain if you can make the GNU binutils work...

Ericson2314 commented 6 years ago

@therealprof don't get me wrong, the LLVM ones are definitely better. (Certainly in your example above, the exact littlearm variant doesn't matter for calculating the size.) I was just trying to point out how progress can be made on distributing complete multi-target tools before lld is "finished".

Also, my hope is --enable-targets=all is little used enough there might be some low hanging fruit the binutils people would fix given both more usage (carrrot) and lld competition (stick).

japaric commented 6 years ago

Relevant: Custom workflows in Cargo. Also, boats will propose a RFC for Cargo templates.

andre-richter commented 6 years ago

One way to mitigate the personal hassle of compiling, installing and maintaining toolchains is letting other people do the unwanted work for you :)

For example, there is the dockcross project , which provides lots of cross-toolchains in docker containers. The way they design their containers, you just need to prepend the container runscript for every toolchain command, and everything else is more or less transparent to the user.

For example, I use their aarch64 container in these bare metal rust tutorials, e.g. https://github.com/andre-richter/rust-raspi3-tutorial/tree/master/05_uart0/ Inside makefile, you can see the usage. A user that has docker already installed need do nothing, the latest version of the image will automatically be pulled from dockerhub.

whitequark commented 6 years ago

Those don't work on Windows do they?

andre-richter commented 6 years ago

In theory they should. Will Most likely be a bit slow whitequark notifications@github.com schrieb am Fr. 6. Apr. 2018 um 16:34:

Those don't work on Windows do they?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/rust-lang-nursery/embedded-wg/issues/43#issuecomment-379272375, or mute the thread https://github.com/notifications/unsubscribe-auth/AD8E1SYBHMt3NWs54AK2SLiQBZKJfnzlks5tl30IgaJpZM4SNx4P .

japaric commented 6 years ago

Update on LLD: PR japaric/cortex-m-rt#64 adds LLD support to cortex-m-rt. With that version you can build ARM Cortex-M programs without having to install arm-none-eabi-ld. Seems to work so far but will continue testing locally.

thejpster commented 6 years ago

I use Docker for Windows on Windows 10 all day long. It spins up a Hyper-V VM running a very minimal Linux OS (just enough to run a Docker container) at boot-up and the rest is transparent.

whitequark commented 6 years ago

How about macOS?

thejpster commented 6 years ago

It exists, but I haven't used it. Very similar idea I imagine.

https://docs.docker.com/docker-for-mac/

Edit to add:

Docker for Mac requires OS X El Capitan 10.11 or newer macOS release running on a 2010 or newer Mac, with Intel’s hardware support for MMU virtualization - https://docs.docker.com/docker-for-mac/install/#download-docker-for-mac

therealprof commented 6 years ago

@whitequark What do you mean? Docker or run native?

whitequark commented 6 years ago

Do these prebuilt toolchains for macOS exist?

therealprof commented 6 years ago

@whitequark Yes, there're pre-built toolchains. Anything specific you're looking for?

andre-richter commented 6 years ago

The toolchain Containers dont distinguish between host. On Linux they use the native kernel, on Mac and Windows it's like jpster said via VM whitequark notifications@github.com schrieb am Fr. 6. Apr. 2018 um 20:24:

Do these prebuilt toolchains for macOS exist?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/rust-lang-nursery/embedded-wg/issues/43#issuecomment-379336944, or mute the thread https://github.com/notifications/unsubscribe-auth/AD8E1X3_MOBGhJQaQv7s5P7EcxPa07OPks5tl7L1gaJpZM4SNx4P .

therealprof commented 6 years ago

@andre-richter Docker on Mac used to do Virtualbox VMs but now it runs stuff directly in a Hypervisor.

therealprof commented 6 years ago

I haven't actually used docker for anything Rust so far. So far all bits ran just fine natively.

andre-richter commented 6 years ago

Yes but this is still a VM. It's not hosted by virtualbox anymore but macos native framework. Daniel Egger notifications@github.com schrieb am Fr. 6. Apr. 2018 um 20:28:

@andre-richter https://github.com/andre-richter Docker on Mac used to do Virtualbox VMs but now it runs stuff directly in a Hypervisor.

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/rust-lang-nursery/embedded-wg/issues/43#issuecomment-379337860, or mute the thread https://github.com/notifications/unsubscribe-auth/AD8E1XmYArp0P_EvpFs8lvlPD4DPgoJoks5tl7PDgaJpZM4SNx4P .

japaric commented 6 years ago

Update: cortex-m-rt v0.4.0 has been released and it supports linking with LLD