-
Notifications
You must be signed in to change notification settings - Fork 4
Glibc test suite for a target without native GNU toolchain
- Table of Contents
- Introduction
- Setting things up
- Glibc test-suite execution with QEMU system emulation
- Glibc test-suite execution with QEMU user mode emulation
- Useful tips
Glibc test-suite was created in assumption that it will be run natively (i.e. on the same host where it was built) and even though now there's a way to run tests on remote target we still need to mimic "native" execution. For that we need:
-
Use the same user on both host and target. I.e. whichever user runs
cross-test-ssh.sh
on host must be specified for SSH connection in the wrapper. Otherwise some tests will fail, for example see posix/globtest. -
Host's file-system must be accessible from target. Moreover paths must match exactly on both devices (i.e.
/home/username/glibc-testsuite
in both cases must be available and contain exactly the same data) because tests are being built on the fly and immediately get executed via SSH. Thus we need to mount host's filesystem with glibc testsuite on target.We have at least 2 options here: NFS or SSHFS.
SSHFS may sporadically fail with
symbol lookup error: ./csu/test-as-const-tcb-offsets: undefined symbol: __libc_start_main, version GLIBC_2.32
. That said NFS is a recommended way.
Additionally since we're are talking about remote execution (host drives the whole process) we need to have SSH server on target so that host may login onto target and execute tests or special scripts.
Also note that some tests require much more memory than ~700 Mb we currently may use in DDR on HSDK. Fortunately this could be easily worked-around with use of SWAP on either micro SD-card or USB flash-drive.
We use Buildroot for building toolchain, Linux kernel and root file-system because it allows to build everything except Glibc tests itself in one run.
To change default settings use Buildroot's configuration utility such as menuconfig
, xconfig
, nconfig
or gconfig
.
The following options must be enabled:
-
BR2_INSTALL_LIBSTDCPP
- Some Glibc tests require C++ cross-compiler and in its absence won't be built and executed. -
BR2_PACKAGE_OPENSSH
- Host uses SSH connection for execution of tests on the target. -
BR2_PACKAGE_NTP
andBR2_PACKAGE_NTP_NTPDATE
- Used to setup correct date and time on target so that user passwords are not treated as expired. -
BR2_TOOLCHAIN_GLIBC_GCONV_LIBS_COPY
- Copiesgconv
libraries on target, that's required for some tests (see iconv/test-iconvconfig) -
BR2_PACKAGE_NFS_UTILS
- To be able to mount NFS. -
BR2_PACKAGE_SSHFS
- [Optional] If SSHFS will be used for mounting host's file-system corresponding utilities must be built and installed on target.
For QEMU please use snps_archs38_haps_defconfig
with options above and also:
-
BR2_LINUX_KERNEL_DEFCONFIG
- set tohaps_hs
(disable SMP). -
BR2_TARGET_ROOTFS_INITRAMFS
- build-in initial ramfs to kernel. -
BR2_SYSTEM_DHCP="eth0"
- Because we are going to run QEMU user network with DHCP enabled. -
BR2_PACKAGE_HAVEGED
- [Optional] Used to collect lower-quality entropy for linux kernel random generator which speeds up rng initialization and ssh daemon startup. It is also recommended to pre-generate sshd keys and provide it to buildroot via overlay.
If Linux kernel gets built by Buildroot it's possible to change kernel's configuration as usual but starting configuration utility by a special Buildroot's target this way:
make linux-menuconfig
The following options should be set:
-
CONFIG_NFS_FS
- Required to mount NFS share on target -
CONFIG_NAMESPACES
,CONFIG_UTS_NS
,CONFIG_IPC_NS
,CONFIG_USER_NS
,CONFIG_PID_NS
,CONFIG_NET_NS
- Required for tests which are executed in container -
CONFIG_CGROUPS
,CONFIG_MEMCG
- Recommended to be set withCONFIG_USER_NS
-
CONFIG_IPV6
- needed for some networking tests -
CONFIG_FUSE_FS
- [Optional] required if host's file-system will be mounted via SSHFS -
CONFIG_SWAP
- [Optional] required if SWAP partition will be used to extend available memory
Additional configuration for QEMU:
-
Apply following kernel patch to restrict instruction set.CONFIG_ARC_TUNE_MCPU="-mcpu=archs"
- Since commit it is possible to specify required mcpu with kernel configs in order to restrict instruction set
Even though that looks pretty strange but there's a need to rebuild Glibc from scratch after everything was already built by Buildroot. That's because Glibc's configuration scripts check availability of C++ compiler and if it is not found some tests later-on won't be built and run. And essentially at the time of initial Glibc compilation C++ compiler is not yet built even if it is "enabled" in Buildroot with mentioned above BR2_INSTALL_LIBSTDCPP
.
Anyways this is as simple as: make glibc-dirclean && make
-
Configure exports (in
/etc/exports
):sudo echo "/home/$USERNAME *(rw,all_squash,anonuid=`id -u`,anongid=`id -g`)" > /etc/exports
Note
all_squash
andanonuid
/anongid
are required for mapping target's user to you user on host.Otherwise use of
no_root_squash
is very dangerous as target's root will be treated as a root on your host and it:- Might be really harmful to your system
- Target will generate files on host's filesystem owned by host's
root
user so if glibc's testsuite is executed by normal user test results won't be accessible for it. And idea to run testsuite by localroot
is very dangerous so please don't do that!
For QEMU user network support it is also required to have
insecure
oiption set. QEMU user network is NATed so NFS should allow any source ports. -
Start NFS server
sudo systemctl start nfs
-
Open NFS and RPC-BIND ports in firewall
firewall-cmd --permanent --add-service=nfs firewall-cmd --permanent --add-service=rpc-bind firewall-cmd --reload
Now when everything is built on host and ready for execution we need to start built Linux kernel on target and do some preparatory steps:
If you want to use QEMU as a target for glibc testing use the following command:
qemu-system-arc -cpu archs -display none -kernel "${BUILDROOT_TOP}/output/image/vmlinux" \
-netdev "user,id=net0,hostfwd=tcp:127.0.0.1:${GUEST_SSH_PORT}-:22" \
-device virtio-net-device,netdev=net0 --global cpu.freq_hz=50000000 -nographic
Where:
-
BUILDROOT_TOP
- path to buildroot top directory. -
GUEST_SSH_PORT
- port to be used on host to connect to guest ssh. So QEMU guest can be reached viassh -p "$GUEST_SSH_PORT" 127.0.0.1
. -
--global cpu.freq_hz=50000000
- needed forhaps_hs
config to have properly worked clock.
If DHCP is configured on Buildroot configuration step host can be reached from guest via 10.0.2.2 (see QEMU user network).
For some tests bidirectional ethernet interface is essential. Following steps will allow to run QEMU with the virtual TAP layer with the host:
# Create and setup interface
sudo ip tuntap add tap1 mode tap
sudo ip addr add 10.42.0.1/24 dev tap1
sudo ip link set tap1 up
The tun
kernel module should be loaded.
Then you can run QEMU with the tap1 interface, created on previous step:
qemu-system-arc -cpu archs -M virt -display none -kernel ${BUILDROOT_TOP}/output/image/vmlinux \
-netdev tap,id=net0,ifname=tap1,script=no,downscript=no \
-device virtio-net-device,netdev=net0 \
--global cpu.freq_hz=50000000 -nographic
If DHCP is configured on Buildroot configuration you can run DHCP server for tap1 interface or set IP address for your target manually:
ifconfig eth0 10.42.0.100
ping 10.42.0.1
-
Make sure Ethernet interface is up and running:
udhcpc
-
Set correct date and time (for that we need to have working internet connection already):
ntpdate
-
Create
home
folder, otherwise on user creation its home folder won't appear:mkdir /home
-
Create a user. Note it's required to have on target the same user as on host so let's create one:
adduser username
-
Install public key on target Now to let host to connect to the target's SSH server without asking user for password (otherwise user will need to enter password for all 5000+ tests) it's required to install host user's public key. We'll do it with help of
ssh-copy-id
on host:ssh-copy-id -i ~/.ssh/id_rsa.pub 10.42.0.100
where
10.42.0.100
is target's IP-address. For QEMU use portGUEST_SSH_PORT
and IP127.0.0.1
.
Keep in mind that all paths must be the same on both host and target. The most obvious mounting point would be Glibc's source folder.
Note if Glibc was built as a part of Buildroot then it will be an output of realpath output/build/glibc-xxx
command:
mkdir -p /__full_path_to_glibc_source__
-
Via NFS (recommended)
mount -t nfs 10.42.0.1:/__full_path_to_glibc_source__ /__full_path_to_glibc_source__ -o nolock
-
Via SSHFS (if NFS-share is not available)
sshfs -o idmap=user,allow_other [email protected]:/__full_path_to_glibc_source__ /__full_path_to_glibc_source__
Note 10.42.0.1
here is host's IP-address. For QEMU user network it will be 10.0.2.2
.
As already mentioned the whole process is controlled from host. It's important to note that tests are being built right before execution.
Before execution of tests we need to cd
into build
folder of glibc
.
Note if Glibc was built as a part of Buildroot then we need to cd
into output/build/glibc-xxx/build/
.
Then start execution of entire test-suite:
make test-wrapper='/__full_path_to_glibc_source__/scripts/cross-test-ssh.sh 10.42.0.100' check ; \ # This target builds test env and runs main testpack
make test-wrapper='/__full_path_to_glibc_source__/scripts/cross-test-ssh.sh 10.42.0.100' xcheck # This target runs extra tests
To pass specific SSH port to cross-test-ssh.sh
use --ssh ${SSH_CMD}
. Where SSH_CMD
should not contain spaces because it causes some tests to fail. Wrapper can be used to bypass this behavior, for example for port 5522
:
$ cat ssh-p5522
#!/bin/sh
exec ssh -p 5522 "$@"
QEMU allows to run executable compiled for one CPU on another CPU. You can run program compiled for ARCv2 CPU by following command:
qemu-arc -R 3G -L $ARC_SYSROOT_PATH -cpu archs arc-program-name
where ARC_SYSROOT_PATH
is a path to the ARC target environment.
To use QEMU user mode emulation in purpose of glibc testing we will utilize the binfmt Linux kernel capability.
The arc-gnu-toolchain repository contains scripts/qemu-binfmt-conf.sh
script which register new binary types (arc64, arc32, arc) in binfmt_misc
file-system interface. Run script and check new binfmt records:
sudo sh ./scripts/qemu-binfmt-conf.sh --qemu-suffix -load
ls /proc/sys/fs/binfmt_misc
cat /proc/sys/fs/binfmt_misc/qemu-arc
enabled
interpreter /usr/local/bin/qemu-arc-load
flags:
offset 0
magic 7f454c460201010000000000000000000200fd00
mask fffffffffffefe00fffffffffffffffffeffffff
As a result, every time you run a program compiled for ARCv2 CPU on your host Linux the /usr/local/bin/qemu-arc-load interpreter will be called. Now we have to prepare the qemu-arc-load
wrapper to run QEMU user mode emulation. It will look like:
#!/bin/sh
qemu-arc -R 3G -L $ARC_SYSROOT_PATH -cpu archs $@
where ARC_SYSROOT_PATH
should point to the sysroot directory with ARC target components. Put the qemu-arc-load
wrapper to the /usr/local/bin
directory.
Before execution of tests, we need to cd
to glibc build folder, then it will be enough to print make check
to run tests. Unfortunately, some tests may get stuck, or unexpected test timeout can occur, so it will be a good idea to use the timeout
program as the test wrapper and set the TIMEOUTFACTOR
environment variable:
TIMEOUTFACTOR=10 make check test-wrapper='timeout -k 15m 15m'
Using QEMU user mode is another way to run glibc tests. It's less accurate and can cause more test failures than in system emulation mode. But this method is easy to use, and it is free from restrictions of full emulated ARC system.
Some proxy DNS servers might not resolve names to IPv6 addresses, see posix/tst-getaddrinfo4.
For that execute: echo "nameserver 8.8.8.8" > /etc/resolv.conf
Since some tests require more than 1Gb of memory on platforms with limited amount of RAM swap partition might be a viable option.
- Make sure
CONFIG_SWAP
is enabled in Linux kernel configuration - Create "Linux swap" partition on micro SD-card or USB flash-drive (for simplicity do it on host system)
- Insert SD-card or USB flash-drive with swap partition into HSDK and enable swap:
where
mkswap /dev/mmcblk0p3 swapon -a -e /dev/mmcblk0p3
/dev/mmcblk0p3
is swap partition. In that example MMC's 3-rd partition was used. If one wants to use USB for that use/dev/sda3
for its third partition.
Change the last line of the file scripts/cross-test-ssh.sh
to:
timeout --foreground 20m $ssh "$host" /bin/sh -c "$full_command"
These scripts should be executed in Glibc's build
folder.
- Get all currently available results:
find . -type f -name '*.test-result' -exec cat {} \; > results.txt
- Count all passed tests:
find . -type f -name '*.test-result' -exec cat {} \; | grep PASS | wc -l
- Count all failed tests:
find . -type f -name '*.test-result' -exec cat {} \; | grep FAIL | wc -l