Skip to content

Commit

Permalink
script: test framework to validate the reproducible builds
Browse files Browse the repository at this point in the history
A test framework to verify that builds are reproducible, i.e.
producing exactly the same binary. Validating the binary generated
from same directory, different directories and on different hosts
with same tool chain.

Signed-off-by: Ajay Kishore <[email protected]>
  • Loading branch information
ajaykish committed Nov 23, 2018
1 parent 644b31d commit 130c5aa
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 0 deletions.
89 changes: 89 additions & 0 deletions scripts/check_reproducible_builds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

# This script verify that builds are reproducible, i.e.
# producing exactly the same binary if built using the same code base.
# Using diffoscope tool which recursively transform various binary
# formats into more human-readable forms for comparison.
#
# Command to use test script:
# python check_reproducible_builds.py -i1 path_of_elf1 -i2 path_of_elf2

import os
import sys
import time
import re
import subprocess
import argparse
import colorama

def reproducible_builds(input_file1, input_file2):
res = res1 = res2 = res3 = 0
filename = os.path.join('/tmp', 'out.txt')

if os.path.exists("filename"):
os.remove("filename")

if os.path.exists(input_file1):
if os.path.exists(input_file2):
subprocess.call("diffoscope --text filename {0} {1}". format(input_file1, input_file2), shell=True)

if os.path.isfile('filename'):
with open('filename', 'r') as out_file:
for line in out_file:
if 'Start of section headers:' in line:
if res is 0:
res = int(re.search(r'\d+', line).group())
else:
res1 = int(re.search(r'\d+', line).group())
print(colorama.Fore.LIGHTRED_EX + 'Bytes in section header mismatch')
print(colorama.Fore.LIGHTRED_EX + 'Bytes in section header of elf file1 and file2 are {0} and {1} respectively'.format(res, res1) + colorama.Fore.RESET)
res = res1 = 0
break
out_file.seek(0, 0);
for line in out_file:
if 'Number of section headers:' in line:
if res is 0:
res = int(re.search(r'\d+', line).group())
else:
res1 = int(re.search(r'\d+', line).group())
print(colorama.Fore.LIGHTRED_EX + 'Number of section headers mismatch')
print(colorama.Fore.LIGHTRED_EX + 'Number of section headers of elf file1 and file2 are {0} and {1} respectively'.format(res, res1) + colorama.Fore.RESET)
res = res1 = 0
break

out_file.seek(0, 0);
for line in out_file:
if 'Symbol table \'.symtab\' contains' in line:
if res is 0:
res = int(re.search(r'\d+', line).group())
else:
res1 = int(re.search(r'\d+', line).group())
print(colorama.Fore.LIGHTRED_EX + 'Entries in symbol table mismatch')
print(colorama.Fore.LIGHTRED_EX + 'Entries in Symbol table of elf file1 and file2 are {0} and {1} respectively'.format(res, res1) + colorama.Fore.RESET)
break
else:
print "No difference found in the comparison of both input elf file"

if __name__=="__main__":
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter)

parser.add_argument(
"-i1",
"--input1",
required=True,
help="First ELF file to compare")
parser.add_argument(
"-i2",
"--input2",
required=True,
help="Second Input file to compare")

args = parser.parse_args()

ret = reproducible_builds(args.input1, args.input2)
sys.exit(ret)
1 change: 1 addition & 0 deletions scripts/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pyelftools==0.24
pyocd==0.12.0
pyserial
pykwalify
diffoscope
# "win32" is used for 64-bit Windows as well
windows-curses; sys_platform == "win32"
colorama
29 changes: 29 additions & 0 deletions tests/reproducible_builds/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
Title: Test framework to validate reproducible binary

Description:
This script verify that builds are reproducible, i.e. producing exactly
the same binary if built using the same source code repository.
Validating the binary generated in below scenario:
- build generated in the same directory
- build generated in different directories
- Enable “TIMER_RANDOM_GENERATOR" config and generate the build

Usage:
Execute sh ./check_reproducible_build.sh which will clone the latest Zephyr
source code repository and generate the binary in above mentioned scenario.
And further it will compare all the binaries using diffoscope tool.

Sample Output:
checking reproducible build from the same directory

checking reproducible build from the different directory
Bytes in section header mismatch
Bytes in section header of elf file1 and file2 are 585232 and 548764 respectively
Number of section headers mismatch
Number of section headers of elf file1 and file2 are 28 and 27 respectively
Entries in symbol table mismatch
Entries in Symbol table of elf file1 and file2 are 981 and 940 respectively

checking reproducible build with CONFIG_TIMER_RANDOM_GENERATOR
Bytes in section header mismatch
Bytes in section header of elf file1 and file2 are 548760 and 548764 respectively
108 changes: 108 additions & 0 deletions tests/reproducible_builds/check_reproducible_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env bash
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

if [ -d "/tmp/zephyr_src1" ]; then
rm -rf /tmp/zephyr_src1/
fi

mkdir /tmp/zephyr_src1
echo "Cloning latest code in zephyr_src1"
cd /tmp/zephyr_src1/
git clone https://github.com/zephyrproject-rtos/zephyr.git

cd /tmp/zephyr_src1/zephyr/
source /tmp/zephyr_src1/zephyr/zephyr-env.sh

cd samples/hello_world/
if [ -d "build" ]; then
rm -rf build
fi

mkdir build && cd build
cmake -GNinja -DBOARD=qemu_x86 ../
ninja

if [ ! -d "/tmp/zephyr_src1/temp" ]
then
mkdir /tmp/zephyr_src1/temp
fi

# copy zephyr.elf into a temp folder
cp /tmp/zephyr_src1/zephyr/samples/hello_world/build/zephyr/zephyr.elf \
/tmp/zephyr_src1/temp/


cd /tmp/zephyr_src1/zephyr/samples/hello_world/
if [ -d "build" ]; then
rm -rf build
fi

mkdir build && cd build
cmake -GNinja -DBOARD=qemu_x86 ../
ninja

if [ ! -d "/tmp/zephyr_src1/temp1" ]
then
mkdir /tmp/zephyr_src1/temp1/
fi

# copy zephyr.elf into a temp folder
cp /tmp/zephyr_src1/zephyr/samples/hello_world/build/zephyr/zephyr.elf \
/tmp/zephyr_src1/temp1/

# adding CONFIG_TIMER_RANDOM_GENERATOR into prj.conf
cd /tmp/zephyr_src1/zephyr/samples/hello_world/
echo 'CONFIG_TIMER_RANDOM_GENERATOR=y' > temp_prj.conf
cat prj.conf >> temp_prj.conf
mv temp_prj.conf prj.conf

if [ -d "build" ]; then
rm -rf build
fi
mkdir build && cd build
cmake -GNinja -DBOARD=qemu_x86 ..
ninja

cd /tmp/zephyr_src1/zephyr/tests/kernel/init/
if [ -d "build" ]; then
rm -rf build
fi
mkdir build && cd build
cmake -GNinja -DBOARD=qemu_x86 ..
ninja

if [ -f "/tmp/out.txt" ]; then
rm -rf out.txt
fi

echo "checking reproducible build from the same directory"
python /tmp/zephyr_src1/zephyr/scripts/check_reproducible_builds.py -i1 \
/tmp/zephyr_src1/temp/zephyr.elf -i2 /tmp/zephyr_src1/temp1/zephyr.elf

if [ -f "/tmp/out.txt" ]; then
rm -rf out.txt
fi

echo "checking reproducible build from the different directory"
python /tmp/zephyr_src1/zephyr/scripts/check_reproducible_builds.py -i1 \
/tmp/zephyr_src1/zephyr/tests/kernel/init/build/zephyr/zephyr.elf -i2 \
/tmp/zephyr_src1/temp1/zephyr.elf

if [ -f "/tmp/out.txt" ]; then
rm -rf out.txt
fi

echo "checking reproducible build with CONFIG_TIMER_RANDOM_GENERATOR"
python /tmp/zephyr_src1/zephyr/scripts/check_reproducible_builds.py -i1 \
/tmp/zephyr_src1/zephyr/samples/hello_world/build/zephyr/zephyr.elf -i2 \
/tmp/zephyr_src1/temp/zephyr.elf

#Delete latest cloned code
rm -rf /tmp/zephyr_src1/
#Delete the output file generated using diffoscope
if [ -f "/tmp/out.txt" ]; then
rm -rf out.txt
fi

0 comments on commit 130c5aa

Please sign in to comment.