Background
I am running the qemu-arm user space emulator inside of a Docker container on Docker for Mac.
I am working on a code base that runs on cortex-m4 processors. I want to be able to cross-compile the code in the docker container to target the cortex-m4 processor and run that code on the qemu-arm user space emulator.
to test this, I have a simple C program (/tmp/program.c):
int main() {
return 0;
}
I use the debian:stable docker image as a base.
I compile the program with the GNU arm toolchain like so:
arm-none-eabi-gcc -mcpu=cortex-m4 --specs=nosys.specs /tmp/program.c
Then I attempt to run this with qemu-arm in the docker container:
qemu-arm -cpu cortex-m4 -strace ./a.out
But I get the following error:
--- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x0007fff0} ---
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault
From what I understand, SIGSEGV occurs in a few scenarios, the only one that makes sense here is that I am accessing memory that I don't have access to when I attempt to run the binary in the qemu-arm user space.
It would seem that the si_addr=0x0007fff0 is the address that I am accessing that I am not supposed to.
Since my program does very little, I am assuming this inaccessible address might be where qemu-arm is attempting to store the binary to run? But I don't see an option in qemu-arm to specify this.
Questions
So my questions are:
how can I verify what is attempting to access that inaccessible address?
if I am correct in my thinking (that this is where qemu-arm is attempting to store the binary to be run), is there a way to change that? I didn't see one in any of the command line options
More information
Docker version 20.10.6, build 370c289
Dockerfile to reproduce:
FROM debian:stable
RUN apt-get update
RUN apt-get install -y gcc-arm-none-eabi qemu-user gcc
RUN echo 'int main() {return 0;}' > /tmp/program.c
# running the program on the docker container exits successfully
RUN gcc /tmp/program.c
RUN ./a.out
# running the program in `qemu-arm` errors
RUN arm-none-eabi-gcc -mcpu=cortex-m4 --specs=nosys.specs /tmp/program.c
RUN qemu-arm -cpu cortex-m4 -strace ./a.out
qemu-arm is an emulator for Linux user-space binaries. The program you're compiling seems to be built with a bare-metal toolchain. It's not impossible to compile a bare-metal binary in such a way that it will run as a Linux user-space program as well, but you have to take specific steps to make it work that way.
You should probably think about whether what you really wanted was:
build a Linux binary targeting Cortex-M4, and run it on qemu-arm
build a bare-metal binary, and run it on qemu-system-arm
something else
For example, how are you expecting your program to produce output? Is the program going to want to talk directly to (emulated) hardware like a serial port, or to other devices? Does the program need to run interrupt handlers?
The best way to debug what's happening is to get QEMU to start its gdbstub, and connect an arm-aware gdb to it. Then you can single step through. (This will probably be a confusing introduction to your toolchain's C runtime startup code...)
Related
I'm trying to compile the Elmer FEM software on Raspberry Pi OS (AFIK formerly known as Raspbian). Following these instructions:
sudo apt install cmake gfortran libopenblas-dev libqt4-dev libqwt-dev
inside the build directory cmake .. -DWITH_OpenMP:BOOLEAN=TRUE -DWITH_MPI:BOOLEAN=FALSE -DWITH_ELMERGUI:BOOLEAN=TRUE
make -j3
sudo make install
I managed to compile the software with no errors (... load of warnings though!). Now heading towards /usr/local/bin and running ./ElmerGUI the software icon appears for a minute or two and then disappears with no prompt or errors, showing just a Killed message in the terminal:
Given that there is no error messages I have no clue what is going wrong leading to the abrupt termination of the software. I would appreciate if you could help me know what is the problem and how I can resolve it.
My environment:
Hardware: Raspberry Pi 3 Model B Rev 1.2
Operating system: Linux raspberrypi 5.4.51-v7+ ... armv7l GNU/Linux
P.S. Following this comment on Discord, I did grep -r "Killed" . in the project folder, which returned no results. I'm almost certain the Killed message is from the OS itself.
I wrote a short boot code and tried to run it with Qemu with:
qemu-system-arm.exe -M versatilepb -cpu cortex-a9 -kernel boot.bin
I expected the code to be loaded to address 0x8400000 but qemu returned me the error
Trying to execute code outside RAM or ROM at 0x84000000
This usually means one of the following happened:
(1) You told QEMU to execute a kernel for the wrong machine type, and it crashed on startup (eg trying to run a raspberry pi kernel on a versatilepb QEMU machine)
(2) You didn't give QEMU a kernel or BIOS filename at all, and QEMU executed a ROM full of no-op instructions until it fell off the end
(3) Your guest kernel has a bug and crashed by jumping off into nowhere
This is almost always one of the first two, so check your command line and that you are using the right type of kernel for this machine.
If you think option (3) is likely then you can try debugging your guest with the -d debug options; in particular -d guest_errors will cause the log to include a dump of the guest register state at this point.
Execution cannot continue; stopping here.
So I guess my code has not yet started running because it is not loaded into the right place
What am I wrong about?
Thanks
You say "I expected the code to be loaded to address 0x8400000" but QEMU's error message says "0x84000000" which is not the same number (it has an extra 0). This suggests that you have a typo in your linker script or whatever is creating your boot.bin file. (I am assuming that boot.bin is an ELF file, which QEMU loads at the addresses the ELF file specifies, because otherwise it will be loaded into RAM anyhow on the assumption that it's a Linux kernel image capable of self-relocation.)
I am trying to run a cross compiled file with qemu, but get "Permission denied" / "Operation not permitted" erros (even when running with sudo).
I am running Debian 8.7 i386 in a VirtualBox 5.0.22, cross compiling to ARM. The cross-compile setup is described in more detail here http://exploringbeaglebone.com/chapter7.
The cross-compiled file runs fine when copied over to a native ARM device.
#include <stdio.h>
int main()
{
printf("Hello ARM\n";
return 0
}
Build it:
# arm-linux-gnueabihf-gcc testARM.c -o testARM -Wall
# file testARM
# testARM: ELF 32-bit LSB executable, ARM, EABI5 version1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=...., not stripped
Trying to run directly gives
# ./testARM
# bash: ./testARM: Permission denied
Trying to run via qemu
# qemu-arm ./testARM
# ./testARM: Operation not permitted
Same with sudo
# sudo qemu-arm ./testARM
# ./testARM: Operation not permitted
Running it native on the platform it was cross-compiled for works
beaglebone:~$ ./testARM
Hello ARM
Of course, I also checked the file permissions ( rwxr-xr-x )
Googling showed me someone else with the same issue, but no solution.
My best guess is that running qemu from within VirtualBox is causing the issue, but there are multiple reports that it just works. Host CPU is an Intel Core i7.
What could be the issue? I would like to run automated tests as part of the build process, thats why a working setup with qemu would be nice.
As #TobySpeight supposed, this was just a filesystem mount flag issue. It is described on stackexchange here.
Using the exec flag for mounting resolved the issue: mount -o remount,exec filesystem
I have written a program in C for an embedded device on a Debian-based linux.
One of the devices got a segmentation fault after 8 days running, so it is not a very frequent bug that I can track fast with gdb.
A few years ago I know that I used gdb (with gdbserver, I guess) running the program detached from the shell so I could leave the device running and check every day if something bad had happened, but I don't remember how I did that!
I have tried with gdbserver, connecting to it with gdb, but it stops debugging when I close the connection.
Do you know how to achieve this?
You'll have to detach, not quit gdb like that.
Since you're only in for post-mortems, anyway, I'd however recommend something completely different:
Enable core dumping; as root, run
> sudo -s ##become root
$ echo "* soft core unlimited" >> /etc/security/limits.conf
$ su -l <user that is running the crashing program>
$ ulimit -c unlimited
$ program
##wait for crash
(that lifts any restriction, including the default 0B restriction, on the maximum core dump file size).
Then, after a crash, find the core.* coredump file, and open it with gdb. Voila, the state of the program when crashing is restored in gdb and you can do pretty much anything that you could do with a gdb attached at crash time.
I've installed Linux mint on usb as my hard drive got really slow. Now I want to compile and run C code. I successfully compiled it but as linux is in usb and I've to store program in one of my hard drive NTFS/FAT partitions so I'm getting bash permission denied error what should I do to run the code? I cannot store the program in usb(Linux partition)
Probably your problem is that the NFS/VFAT systems are mounted with the noexec flag or maybe the showexec flag. It instruct the kernel not to run any executable from these partitions (a security measure).
If it is showexec, then it is simply a matter of naming your executable with an .exe, .com or .bat extension (yes, even if it is a Linux executable, the vfat driver uses the extension to infer the executable permission bit).
If it is noexec, read on...
On older kernels you could bypass this with the /ld-*.so trick, but as man mount comments:
noexec: [...] (Until recently it was possible to run binaries anyway using a command like /lib/ld*.so /mnt/binary. This trick fails since Linux 2.4.25 / 2.6.0.)
If my guess is correct, you have several options:
A. Remove the flag from the partition, with this command as root:
mount -o remount,exec <mount-point>
B. Find out why your partitions have this flag, which program does it (gnome-disks or whatever) and change it.
C. Compile your program to another partition, if not in the USB partition, then for example in a tmpfs:
mkdir exe
sudo mount -t tmpfs exe exe
And then, when you compile your program:
gcc test.c -o exe/test
But beware! A tmpfs is volatile and will disappear when you umount it or shut down the machine. You can make a permanent partition-in-a-file:
truncate -s 512M exe.img
mkfs.ext4 exe.img
mkdir exe
Then, to mount the image each time you boot the machine:
sudo mount -o loop exe.img exe
Copy the file to /tmp, set the execute permission, and you should be good to go, until you reboot and then you'll have to repeat it.
cp /path/to/wherever/myprogram /tmp/myprogram
chmod +x /tmp/myprogram
/tmp/myprogram
I Had same program this is what worked, for a console HELLO WORLD test on Debian Linux.
Simply compiled with syntax:
gcc hello.c -o hello.exe
Compiled in an instant and ran program at command line
via:. ./hello.exe