Semi-hosting on ARM with Rust
embed.rs
embed.rs
PS: the article is not quite correct about when to use which trap instruction. Cortex-M profile CPUs should use BKPT; all other 32-bit code should use SVC (with an immediate value varying depending on whether the instruction is Thumb or ARM). 64-bit code uses a HLT insn. If you care at that level of detail you'll be looking at the documentation for the ABI anyway though...
This also works for getting rich unit testing frameworks to work, too. Not only do they expect the standard streams to be available, you can also store a bunch of data-parameterized test cases for the unit under test in a file.
Funny, the very reason I use a debugger is that it provides a faster turnaround than modifying the code, compiling, flashing, and hoping I printed the right thing...
This doesn't mean I use printf debugging often, just that it makes sense in some cases and I use it then :)
break file.c:200
commands
silent
printf "x is %d\n",x
cont
end
(NB: silent prevents gdb from announcing that it's stopping at the breakpoint, reducing the output noise.)Now with gdb running the program, every time we hit that line we can get this output. With logging (set logging file <filename>, set logging on) you can get the output from the run's execution stored to a file.
Conditionals are also possible, so we only print out the results of every 10th iteration through a loop, for instance.
br file.c:200 if (i % 10) == 9
commands
silent
printf "Iteration: %d, X: %x\n",i,x
end
(NB: Not at a computer with gdb, apologies if I miswrote something in the examples.)One of the true game changers in my current office's work. We're doing a lot of stuff (new-ish here) in embedded linux (versus self-hosted executables). It's a pain in the ass to load different versions of the software (by the way the rest of the system works, we can't load it on-the-fly because we will miss various timeouts that we can't control and the whole system will go into a failed state; can't load and save it because the OS is stored in nonvolatile memory that we can't directly alter without going into u-boot). For debugging this, we have the system load, and, before gdb executes, download just a specifically named file over the network containing these gdb commands for whatever we want to obtain. So you want to know if function foo ever gets called with a parameter of 4? Put that into the command file and reboot, run the tests and see the output in the serial console, download the log before rebooting again.
EDIT: We also have a system where we were running on embedded linux, but due to constraints simply couldn't get gdb involved. printf-style, implemented by way of a logging function where we could specify logging levels, was the effective solution for us.
I'm not a very good programmer...
In this environment, a stream of debug output (printfs in the basic case) is unmatchable. Also, as you build them up throughout your project they become a great diagnostic tool allowing you to trace program behaviour and diagnose bugs just by looking at the output.
If hope is involved, you could have almost certainly saved the same time by thinking more carefully.
Unfortunately, font rendering is still a bit of a crapshoot, it differs from OS to OS and even varies wildly between Linux distros (which may or may not use potentially non-free freetype functionality).
In the end, I hope it's manageable. We're open to redesign offers though =).
Windows 10, Firefox 49.0.1
FWIW, I think it's a pretty common problem with many web fonts on certain platforms (windows?). I see it all the time.
Also, thanks for the post!
Hopefully, it's readable for by everyone now.
bkpt_n = int(raw, 16 if raw.startswith('0x') else 10)
Tip: you can accomplish something similar with 'int(raw, 0)'.I think volatile also means don't change the order with respect to other volatile operations.