firecracker

Форк
0
/
test_bindings.py 
165 строк · 5.2 Кб
1
# Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
# SPDX-License-Identifier: Apache-2.0
3

4
"""
5
Script used to check if bindgen-generated code creates structs that differ from previously created
6
onces.
7

8
The script uses `pahole` (man 1 pahole) to gather debug information from two firecracker binaries
9
(script's arguments). It parses pahole output and gathers struct information in a dictionary of the
10
form:
11

12
```
13
{
14
    "struct_name": {"size": size_in_bytes, "alignment": alignment_in_bytes},
15
    ...
16
}
17
```
18

19
It also, filters structure names using the "bindings" filter for keeping only bindgen related
20
structs.
21

22
*NOTE*: this assumes that all bindgen-related structs live under a crate or module name with
23
"bindings" in it. At the moment, this is true.
24

25
It then iterates through the structs of the firecracker binary built from the older version and
26
checks if there are mismatches with the struct info from the second binary (newer version)
27

28
### Usage
29

30
1. Create the two binaries
31

32
```
33
# First create the binary with existing bindings
34
$ git checkout main
35
$ ./tools/devtool build
36
$ cp ./build/cargo_target/x86_64-unknown-linux-musl/debug/firecracker firecracker_old
37

38
# Second create the binary with new bindings
39
$ git checkout new_bindings
40
$ ./tools/devtool build
41
$ cp ./build/cargo_target/x86_64-unknown-linux-musl/debug/firecracker firecracker_new
42

43
# Run the script
44
$ python3 ./tools/test_bindings.py firecracker_old firecracker_new
45
```
46
"""
47

48
import argparse
49
import logging
50
import re
51
import subprocess
52
import sys
53

54
logging.basicConfig(level=logging.DEBUG)
55
log = logging.getLogger(__name__)
56

57

58
def parse_pahole(pahole_output):
59
    """Gather bindings related structs from pahole output
60

61
    Parse pahole output and gather struct information filtering for the 'bindings' keyword.
62
    The information gathered is the struct size and its alignment.
63

64
    @param fname: File including pahole output
65
    @return: A dictionary where keys are struct names and values struct size and alignment
66
    """
67
    ret = {}
68

69
    # regular expression matches the name of the struct, its size and alignment
70
    structs = re.findall(
71
        rb"struct (.*?)\{.*?/\* size: (\d+).*?\*/.*?\n\} "
72
        rb"__attribute__\(\(__aligned__\((\d+)\)\)\)\;",
73
        pahole_output,
74
        flags=re.DOTALL,
75
    )
76

77
    for struct in structs:
78
        struct_name = str(struct[0])
79
        size = int(struct[1])
80
        alignment = int(struct[2])
81

82
        if "bindings" in struct_name:
83
            ret[struct_name] = {"size": size, "alignment": alignment}
84

85
    return ret
86

87

88
def pahole(binary: str) -> str:
89
    """Runs pahole on a binary and returns its output as a str
90

91
    If pahole fails this will raise a `CalledProcessError`
92

93
    @param binary: binary to run pahole on
94
    @return: On success, it will return the stdout of the pahole process
95
    """
96
    result = subprocess.run(
97
        ["pahole", binary], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
98
    )
99
    return result.stdout
100

101

102
def check_pahole_mismatches(old: str, new: str) -> bool:
103
    """Checks for pahole mismatches in pahole information between two binaries
104

105
    @param old: old Firecracker binary
106
    @param new: new Firecracker binary
107
    @return: false if no mismatches found, true otherwise
108
    """
109
    pahole_structs_1 = parse_pahole(pahole(old))
110
    pahole_structs_2 = parse_pahole(pahole(new))
111

112
    # We go through all the structs existing in the old firecracker binary and check for mismatches
113
    # in the new one.
114
    for name, prop_1 in pahole_structs_1.items():
115
        # Note that the reverse, i.e. a name existing in the new binary but not in the old binary,
116
        # is not a problem. That would mean we are making use of some new struct from
117
        # bindgen-generated code. That does not break ABI compatibility.
118
        if name not in pahole_structs_2:
119
            log.warning("struct '%s' does not exist in new binary", name)
120
            continue
121

122
        prop_2 = pahole_structs_2[name]
123
        # Size mismatches are hard errors
124
        if prop_1["size"] != prop_2["size"]:
125
            log.error("size of '%s' does not match in two binaries", name)
126
            log.error("old: %s", prop_1["size"])
127
            log.error("new: %s", prop_2["size"])
128
            return True
129

130
        # Alignment mismatches just cause warnings
131
        if prop_1["alignment"] != prop_2["alignment"]:
132
            log.warning("alignment of '%s' does not match in two binaries", name)
133
            log.warning("old: %s", prop_1["alignment"])
134
            log.warning("new: %s", prop_2["alignment"])
135
        else:
136
            log.info("struct '%s' matches", name)
137

138
    return False
139

140

141
if __name__ == "__main__":
142
    parser = argparse.ArgumentParser(
143
        description="Check bindings ABI compatibility for Firecracker"
144
    )
145
    parser.add_argument(
146
        "firecracker_old",
147
        type=str,
148
        metavar="old-firecracker-binary",
149
        help="Firecracker binary with old bindings",
150
    )
151
    parser.add_argument(
152
        "firecracker_new",
153
        type=str,
154
        metavar="new-firecracker-binary",
155
        help="Firecracker binary with new bindings",
156
    )
157
    args = parser.parse_args()
158

159
    if check_pahole_mismatches(args.firecracker_old, args.firecracker_new):
160
        log.error("Structure layout mismatch")
161
        sys.exit(1)
162
    else:
163
        log.info("Structure layout matches")
164

165
    sys.exit(0)
166

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.