summaryrefslogtreecommitdiffstats
path: root/check-kabi
blob: f9d4dcb84861aafd4115e75a342f414cf7815580 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/python3
#
# check-kabi - Red Hat kABI reference checking tool
#
# We use this script to check against reference Module.kabi files.
#
# Author: Jon Masters <jcm@redhat.com>
# Copyright (C) 2007-2009 Red Hat, Inc.
#
# This software may be freely redistributed under the terms of the GNU
# General Public License (GPL).

# Changelog:
#
# 2018/06/01 - Update for python3 by Petr Oros.
# 2009/08/15 - Updated for use in RHEL6.
# 2007/06/13 - Initial rewrite in python by Jon Masters.

__author__ = "Jon Masters <jcm@redhat.com>"
__version__ = "2.0"
__date__ = "2009/08/15"
__copyright__ = "Copyright (C) 2007-2009 Red Hat, Inc"
__license__ = "GPL"

import getopt
import string
import sys

true = 1
false = 0


def load_symvers(symvers, filename):
    """Load a Module.symvers file."""

    symvers_file = open(filename, "r")

    while true:
        in_line = symvers_file.readline()
        if in_line == "":
            break
        if in_line == "\n":
            continue
        checksum, symbol, directory, type = in_line.split()

        symvers[symbol] = in_line[0:-1]


def load_kabi(kabi, filename):
    """Load a Module.kabi file."""

    kabi_file = open(filename, "r")

    while true:
        in_line = kabi_file.readline()
        if in_line == "":
            break
        if in_line == "\n":
            continue
        checksum, symbol, directory, type = in_line.split()

        kabi[symbol] = in_line[0:-1]


def check_kabi(symvers, kabi):
    """Check Module.kabi and Module.symvers files."""

    fail = 0
    warn = 0
    changed_symbols = []
    moved_symbols = []

    for symbol in kabi:
        abi_hash, abi_sym, abi_dir, abi_type = kabi[symbol].split()
        if symbol in symvers:
            sym_hash, sym_sym, sym_dir, sym_type = symvers[symbol].split()
            if abi_hash != sym_hash:
                fail = 1
                changed_symbols.append(symbol)

            if abi_dir != sym_dir:
                warn = 1
                moved_symbols.append(symbol)
        else:
            fail = 1
            changed_symbols.append(symbol)

    if fail:
        print("*** ERROR - ABI BREAKAGE WAS DETECTED ***")
        print("")
        print("The following symbols have been changed (this will cause an ABI breakage):")
        print("")
        for symbol in changed_symbols:
            print(symbol)
        print("")

    if warn:
        print("*** WARNING - ABI SYMBOLS MOVED ***")
        print("")
        print("The following symbols moved (typically caused by moving a symbol from being")
        print("provided by the kernel vmlinux out to a loadable module):")
        print("")
        for symbol in moved_symbols:
            print(symbol)
        print("")

    """Halt the build, if we got errors and/or warnings. In either case,
       double-checkig is required to avoid introducing / concealing
       KABI inconsistencies."""
    if fail or warn:
        sys.exit(1)
    sys.exit(0)


def usage():
    print("""
check-kabi: check Module.kabi and Module.symvers files.

    check-kabi [ -k Module.kabi ] [ -s Module.symvers ]

""")


if __name__ == "__main__":

    symvers_file = ""
    kabi_file = ""

    opts, args = getopt.getopt(sys.argv[1:], 'hk:s:')

    for o, v in opts:
        if o == "-s":
            symvers_file = v
        if o == "-h":
            usage()
            sys.exit(0)
        if o == "-k":
            kabi_file = v

    if (symvers_file == "") or (kabi_file == ""):
        usage()
        sys.exit(1)

    symvers = {}
    kabi = {}

    load_symvers(symvers, symvers_file)
    load_kabi(kabi, kabi_file)
    check_kabi(symvers, kabi)