Skip to contentSkip to conversation

arch: add BR2_READELF_ARCH_NAME hidden config option

PATCH Superseded Thomas Petazzoni 2 participants 3 messages Mar 12, 2017 C-sky architecture

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/2 arch: add BR2_READELF_ARCH_NAME hidden config option

This config option corresponds to the string returned by readelf for the "Machine" field of the ELF header. It will be used to check if the architecture of binaries built by Buildroot match the target architecture.

---
Changes since v2:
- Improve comment above BR2_READELF_ARCH_NAME to explain that it is the value of the "Machine:" field in readelf output, and point to the readelf source code for the list of possible values.

Changes since v1:
- None

---
 arch/Config.in            | 6 ++++++
 arch/Config.in.arc        | 3 +++
 arch/Config.in.arm        | 4 ++++
 arch/Config.in.bfin       | 3 +++
 arch/Config.in.csky       | 2 ++
 arch/Config.in.m68k       | 3 +++
 arch/Config.in.microblaze | 3 +++
 arch/Config.in.mips       | 3 +++
 arch/Config.in.nios2      | 3 +++
 arch/Config.in.or1k       | 3 +++
 arch/Config.in.powerpc    | 4 ++++
 arch/Config.in.sh         | 3 +++
 arch/Config.in.sparc      | 4 ++++
 arch/Config.in.x86        | 4 ++++
 arch/Config.in.xtensa     | 3 +++
 15 files changed, 51 insertions(+)
arch/Config.in +6 -0
index 65a33fb..50377a9 100644
@@ -292,6 +292,12 @@ config BR2_GCC_TARGET_MODE
 config BR2_BINFMT_SUPPORTS_SHARED
 	bool
 
+# Must match the name of the architecture from readelf point of view,
+# i.e the "Machine:" field of readelf output. See get_machine_name()
+# in binutils/readelf.c for the list of possible values.
+config BR2_READELF_ARCH_NAME
+	string
+
 # Set up target binary format
 choice
 	prompt "Target Binary Format"
arch/Config.in.arc +3 -0
index 7d341f3..dcdba68 100644
@@ -38,6 +38,9 @@ config BR2_GCC_TARGET_CPU
 	default "arc700" if BR2_arc770d
 	default "archs"	 if BR2_archs38
 
+config BR2_READELF_ARCH_NAME
+	default "ARCv2"
+
 choice
 	prompt "MMU Page Size"
 	default BR2_ARC_PAGE_SIZE_8K
arch/Config.in.arm +4 -0
index 2617976..f910364 100644
@@ -568,3 +568,7 @@ config BR2_GCC_TARGET_FLOAT_ABI
 config BR2_GCC_TARGET_MODE
 	default "arm"		if BR2_ARM_INSTRUCTIONS_ARM
 	default "thumb"		if BR2_ARM_INSTRUCTIONS_THUMB || BR2_ARM_INSTRUCTIONS_THUMB2
+
+config BR2_READELF_ARCH_NAME
+	default "ARM"		if BR2_arm || BR2_armeb
+	default "AArch64"	if BR2_aarch64 || BR2_aarch64_be
arch/Config.in.bfin +3 -0
index 9f7056a..90e4ab9 100644
@@ -105,3 +105,6 @@ config BR2_GCC_TARGET_CPU_REVISION
 	  value of the -mcpu option. For example, if the selected CPU is
 	  bf609, and then selected CPU revision is "0.0", then gcc will
 	  receive the -mcpu=bf609-0.0 option.
+
+config BR2_READELF_ARCH_NAME
+	default "Analog Devices Blackfin"
arch/Config.in.csky +2 -0
index 7029c60..e88e4e2 100644
@@ -44,3 +44,5 @@ config BR2_GCC_TARGET_CPU
 	default "ck810f"	if (BR2_ck810 &&  BR2_CSKY_FPU && !BR2_CSKY_DSP)
 	default "ck810ef"	if (BR2_ck810 &&  BR2_CSKY_FPU &&  BR2_CSKY_DSP)
 
+config BR2_READELF_ARCH_NAME
+	default "CSKY"
arch/Config.in.m68k +3 -0
index ced871f..c56031c 100644
@@ -35,3 +35,6 @@ endchoice
 config BR2_GCC_TARGET_CPU
 	default "68040"		if BR2_m68k_68040
 	default "5208"		if BR2_m68k_cf5208
+
+config BR2_READELF_ARCH_NAME
+	default "MC68000"
arch/Config.in.microblaze +3 -0
index 2d4c1fe..042712a 100644
@@ -6,6 +6,9 @@ config BR2_ENDIAN
 	default "LITTLE" if BR2_microblazeel
 	default "BIG"	 if BR2_microblazebe
 
+config BR2_READELF_ARCH_NAME
+	default "Xilinx MicroBlaze"
+
 config BR2_microblaze
 	bool
 	default y if BR2_microblazeel || BR2_microblazebe
arch/Config.in.mips +3 -0
index ce41e9e..22819d0 100644
@@ -161,3 +161,6 @@ config BR2_GCC_TARGET_ABI
 	default "32"		if BR2_MIPS_OABI32
 	default "n32"		if BR2_MIPS_NABI32
 	default "64"		if BR2_MIPS_NABI64
+
+config BR2_READELF_ARCH_NAME
+	default "MIPS R3000"
arch/Config.in.nios2 +3 -0
index ed63898..7466331 100644
@@ -3,3 +3,6 @@ config BR2_ARCH
 
 config BR2_ENDIAN
 	default "LITTLE"
+
+config BR2_READELF_ARCH_NAME
+	default "Altera Nios II"
arch/Config.in.or1k +3 -0
index dba64a6..b31ab3e 100644
@@ -3,3 +3,6 @@ config BR2_ARCH
 
 config BR2_ENDIAN
 	default "BIG"
+
+config BR2_READELF_ARCH_NAME
+	default "OpenRISC 1000"
arch/Config.in.powerpc +4 -0
index 09ac794..0968412 100644
@@ -212,3 +212,7 @@ config BR2_GCC_TARGET_ABI
 	default "no-spe"		if BR2_PPC_ABI_no-spe
 	default "ibmlongdouble"		if BR2_PPC_ABI_ibmlongdouble
 	default "ieeelongdouble"	if BR2_PPC_ABI_ieeelongdouble
+
+config BR2_READELF_ARCH_NAME
+	default "PowerPC"	if BR2_powerpc
+	default "PowerPC64"	if BR2_powerpc64 || BR2_powerpc64le
arch/Config.in.sh +3 -0
index 4705212..deb7244 100644
@@ -27,3 +27,6 @@ config BR2_ARCH
 config BR2_ENDIAN
 	default "LITTLE"	if BR2_sh4 || BR2_sh4a
 	default "BIG"		if BR2_sh2a || BR2_sh4eb || BR2_sh4aeb
+
+config BR2_READELF_ARCH_NAME
+	default "Renesas / SuperH SH"
arch/Config.in.sparc +4 -0
index 307540f..9b6a6aa 100644
@@ -28,3 +28,7 @@ config BR2_GCC_TARGET_CPU
 	default "leon3"		if BR2_sparc_leon3
 	default "v8"		if BR2_sparc_v8
 	default "ultrasparc"	if BR2_sparc_v9
+
+config BR2_READELF_ARCH_NAME
+	default "Sparc"		if BR2_sparc
+	default "Sparc v9"	if BR2_sparc64
arch/Config.in.x86 +4 -0
index efa9567..0d9e93b 100644
@@ -275,3 +275,7 @@ config BR2_GCC_TARGET_ARCH
 	default "c3"		if BR2_x86_c3
 	default "c3-2"		if BR2_x86_c32
 	default "geode"		if BR2_x86_geode
+
+config BR2_READELF_ARCH_NAME
+	default "Intel 80386"			if BR2_i386
+	default "Advanced Micro Devices X86-64" if BR2_x86_64
arch/Config.in.xtensa +3 -0
index fcb3dc9..88dbe18 100644
@@ -54,3 +54,6 @@ config BR2_ENDIAN
 
 config BR2_ARCH
 	default "xtensa"	if BR2_xtensa
+
+config BR2_READELF_ARCH_NAME
+	default "Tensilica Xtensa Processor"
Signature · 1 line
2.7.4
#1 lore raw

PATCH v3 2/2 Makefile: add check of binaries architecture

As shown recently by the firejail example, it is easy to miss that a package builds and installs binaries without actually cross-compiling
them: they are built for the host architecture instead of the target architecture.

This commit adds a small helper script, check-bin-arch, called as a GLOBAL_INSTRUMENTATION_HOOKS at the end of the target installation of each package, to verify that the files installed by this package have been built for the correct architecture.

Being called as a GLOBAL_INSTRUMENTATION_HOOKS allows the build to error out right after the installation of the faulty package, and therefore get autobuilder error detection properly assigned to this specific package.

Example output with the firejail package enabled, when building for an ARM target:

ERROR: ./usr/lib/firejail/libconnect.so (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/bin/firejail (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/lib/firejail/libtrace.so (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/lib/firejail/libtracelog.so (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/lib/firejail/ftee (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/lib/firejail/faudit (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/bin/firemon (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM
ERROR: ./usr/bin/firecfg (from firejail) architecture is Advanced Micro Devices X86-64, should be ARM package/pkg-generic.mk:306: recipe for target '/home/thomas/projets/buildroot/output/build/firejail-0.9.44.8/.stamp_target_installed' failed make[1]: *** [/home/thomas/projets/buildroot/output/build/firejail-0.9.44.8/.stamp_target_installed] Error 1

Many thanks to Yann E. Morin and Arnout Vandecappelle for their reviews and suggestions.

---
Changes since v2:
- Moved as a per-package check, so that we detect the faulty package earlier, and get correct autobuilder notifications.
- Use TARGET_DIR from the environment and use BR2_CONFIG to retrieve the value of BR2_READELF_ARCH_NAME.
- Skip firmware files in /lib/firmware and /usr/lib/firmware.
- Simply ignore files for which readelf returned an empty Machine field, as a way to quickly detect non-ELF files.

Changes since v1:
- Following Yann E. Morin's comment, restrict the check to bin, lib, sbin, usr/bin, usr/lib and usr/sbin, in order to avoid matching firmware files that could use the ELF format but be targeted for other architectures.

---
 package/pkg-generic.mk         |  8 ++++++++
 support/scripts/check-bin-arch | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)
 create mode 100755 support/scripts/check-bin-arch
package/pkg-generic.mk +8 -0
index e8a8021..71e3033 100644
@@ -87,6 +87,14 @@ define step_pkg_size
 endef
 GLOBAL_INSTRUMENTATION_HOOKS += step_pkg_size
 
+define check_bin_arch
+	$(if $(filter end-install-target,$(1)-$(2)),\
+		support/scripts/check-bin-arch $(3) \
+			$(BUILD_DIR)/packages-file-list.txt $(TARGET_CROSS))
+endef
+
+GLOBAL_INSTRUMENTATION_HOOKS += check_bin_arch
+
 # This hook checks that host packages that need libraries that we build
 # have a proper DT_RPATH or DT_RUNPATH tag
 define check_host_rpath
support/scripts/check-bin-arch new file +39 -0
new file mode 100755
index 0000000..4c94abe
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+PACKAGE=$1
+PACKAGE_FILE_LIST=$2
+TARGET_CROSS=$3
+
+exitcode=0
+
+READELF_ARCH_NAME=$(sed -r -e "/^BR2_READELF_ARCH_NAME=\"(.+)\"$/!d; s//\1/;" ${BR2_CONFIG})
+PKG_FILES=$(sed -r -e "/^${PACKAGE},(.+)$/!d; s//\1/;" ${PACKAGE_FILE_LIST})
+
+for f in ${PKG_FILES} ; do
+	# Skip firmware files, they could be ELF files for other
+	# architectures
+	if [[ "${f}" =~ ^\./(usr/)?lib/firmware/.* ]]; then
+		continue
+	fi
+
+	# Get architecture using readelf
+	arch=$(${TARGET_CROSS}readelf -h "${TARGET_DIR}/${f}" 2>&1 | \
+		       sed -r -e '/^  Machine: +(.+)/!d; s//\1/;')
+
+	# If no architecture found, assume it was not an ELF file
+	if test "${arch}" = "" ; then
+		continue
+	fi
+
+	# Architecture is correct
+	if test "${arch}" = "${READELF_ARCH_NAME}" ; then
+		continue
+	fi
+
+	printf 'ERROR: %s (from %s) architecture is %s, should be %s\n' \
+	       "${f}" "${PACKAGE}" "${arch}" "${READELF_ARCH_NAME}"
+
+	exitcode=1
+done
+
+exit ${exitcode}
Signature · 1 line
2.7.4
#2 lore raw

PATCH v3 2/2 Makefile: add check of binaries architecture

Thomas, All,

On 2017-03-12 22:55 +0100, Thomas Petazzoni spake thusly:

Quoted 9 lines

As shown recently by the firejail example, it is easy to miss that a package builds and installs binaries without actually cross-compiling
them: they are built for the host architecture instead of the target architecture.

This commit adds a small helper script, check-bin-arch, called as a GLOBAL_INSTRUMENTATION_HOOKS at the end of the target installation of each package, to verify that the files installed by this package have been built for the correct architecture.

[--SNIP--]

package/pkg-generic.mk define step_pkg_size · line 93

Quoted 12 lines
package/pkg-generic.mk +4 -0
index e8a8021..71e3033 100644
@@ -87,6 +87,14 @@ define step_pkg_size
 endef
 GLOBAL_INSTRUMENTATION_HOOKS += step_pkg_size
 
+define check_bin_arch
+	$(if $(filter end-install-target,$(1)-$(2)),\
+		support/scripts/check-bin-arch $(3) \
+			$(BUILD_DIR)/packages-file-list.txt $(TARGET_CROSS))

Also pass $(BR2_READELF_ARCH_NAME) directly from here, since we have it in the Makefile, which would allow you...

Quoted 13 lines
package/pkg-generic.mk +4 -0
+endef
+
+GLOBAL_INSTRUMENTATION_HOOKS += check_bin_arch
+
 # This hook checks that host packages that need libraries that we build
 # have a proper DT_RPATH or DT_RUNPATH tag
 define check_host_rpath
support/scripts/check-bin-arch new file +0 -0
new file mode 100755
index 0000000..4c94abe

support/scripts/check-bin-arch line 9

Quoted 9 lines
support/scripts/check-bin-arch new file +9 -0
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+PACKAGE=$1
+PACKAGE_FILE_LIST=$2
+TARGET_CROSS=$3
+
+exitcode=0
+
+READELF_ARCH_NAME=$(sed -r -e "/^BR2_READELF_ARCH_NAME=\"(.+)\"$/!d; s//\1/;" ${BR2_CONFIG})

... to get rid of this ugly code. ;-)

support/scripts/check-bin-arch line 20

Quoted 11 lines
support/scripts/check-bin-arch new file +11 -0
+PKG_FILES=$(sed -r -e "/^${PACKAGE},(.+)$/!d; s//\1/;" ${PACKAGE_FILE_LIST})
+
+for f in ${PKG_FILES} ; do
+	# Skip firmware files, they could be ELF files for other
+	# architectures
+	if [[ "${f}" =~ ^\./(usr/)?lib/firmware/.* ]]; then
+		continue
+	fi
+
+	# Get architecture using readelf
+	arch=$(${TARGET_CROSS}readelf -h "${TARGET_DIR}/${f}" 2>&1 | \

As already said, runn that with LC_ALL=C.

support/scripts/check-bin-arch line 33

Quoted 13 lines
support/scripts/check-bin-arch new file +13 -0
+		       sed -r -e '/^  Machine: +(.+)/!d; s//\1/;')
+
+	# If no architecture found, assume it was not an ELF file
+	if test "${arch}" = "" ; then
+		continue
+	fi
+
+	# Architecture is correct
+	if test "${arch}" = "${READELF_ARCH_NAME}" ; then
+		continue
+	fi
+
+	printf 'ERROR: %s (from %s) architecture is %s, should be %s\n' \

The grammar is not nice here. What about:

"ERROR: architecture for %s (from %s) is %s, should be %s\n"

Otherwise, looks good. :-)

Regards,
Yann E. MORIN.

Quoted 9 lines
support/scripts/check-bin-arch new file +6 -0
+	       "${f}" "${PACKAGE}" "${arch}" "${READELF_ARCH_NAME}"
+
+	exitcode=1
+done
+
+exit ${exitcode}
Signature · 1 line
2.7.4
Signature · 6 lines
.-----------------.--------------------.------------------.--------------------.
|  Yann E. MORIN  | Real-Time Embedded | /"\ ASCII RIBBON | Erics' conspiracy: |
| +33 662 376 056 | Software  Designer | \ / CAMPAIGN     |  ___               |
| +33 223 225 172 `------------.-------:  X  AGAINST      |  \e/  There is no  |
| http://ymorin.is-a-geek.org/ | _/*\_ | / \ HTML MAIL    |   v   conspiracy.  |
'------------------------------^-------^------------------^--------------------'