11 types['char'] = {"size": 1, "alignment": 1}
12 types['uint8_t'] = {"size": 1, "alignment": 1}
13 types['uint16_t'] = {"size": 2, "alignment": 2}
14 types['uint32_t'] = {"size": 4, "alignment": 4}
15 types['uint64_t'] = {"size": 8, "alignment": 8}
19 idRe = "[a-zA-Z_][a-zA-Z_0-9]*"
20 tokenRe = "#?" + idRe + "|[0-9]+|."
31 if line.startswith("/*"):
35 commentEnd = line.find("*/")
40 line = line[commentEnd + 2:]
42 match = re.match(tokenRe, line)
43 token = match.group(0)
44 line = line[len(token):]
45 if token.startswith('#'):
47 elif token in macros and not inDirective:
48 line = macros[token] + line
57 line = inputFile.readline()
59 while line.endswith("\\\n"):
60 line = line[:-2] + inputFile.readline()
64 fatal("unexpected end of input")
69 sys.stderr.write("%s:%d: error at \"%s\": %s\n" % (fileName, lineNumber, token, msg))
75 sys.stderr.write("%s:%d: warning: %s\n" % (fileName, lineNumber, msg))
83 return re.match(idRe + "$", s) != None
87 fatal("identifier expected")
90 if not re.match('[0-9]+$', token):
91 fatal("integer expected")
102 fatal("%s expected" % t)
104 def parseTaggedName():
105 assert token in ('struct', 'union')
109 name = "%s %s" % (name, token)
114 if token in ('struct', 'union'):
115 name = parseTaggedName()
120 fatal("type name expected")
125 fatal("unknown type \"%s\"" % name)
128 isStruct = token == 'struct'
129 structName = parseTaggedName()
134 alignment = 4 # ARM has minimum 32-bit alignment
136 while not match('}'):
137 typeName = parseTypeName()
138 typeSize = types[typeName]['size']
139 typeAlignment = types[typeName]['alignment']
156 nBytes = typeSize * count
158 if ofs % typeAlignment:
159 shortage = typeAlignment - (ofs % typeAlignment)
160 warn("%s member %s is %d bytes short of %d-byte alignment"
161 % (structName, memberName, shortage, typeAlignment))
169 if typeAlignment > alignment:
170 alignment = typeAlignment
174 shortage = alignment - (size % alignment)
175 if (structName == "struct ofp_packet_in" and
177 memberName == 'data' and
179 # This is intentional
182 warn("%s needs %d bytes of tail padding" % (structName, shortage))
184 types[structName] = {"size": size, "alignment": alignment}
187 if len(sys.argv) < 2:
188 sys.stderr.write("at least one non-option argument required; "
189 "use --help for help")
192 if '--help' in sys.argv:
194 slash = argv0.rfind('/')
196 argv0 = argv0[slash + 1:]
198 %(argv0)s, for checking struct and struct member alignment
199 usage: %(argv0)s HEADER [HEADER]...
201 This program reads the header files specified on the command line and
202 verifies that all struct members are aligned on natural boundaries
203 without any need for the compiler to add additional padding. It also
204 verifies that each struct's size is a multiple of 32 bits (because
205 some ABIs for ARM require all structs to be a multiple of 32 bits), or
206 64 bits if the struct has any 64-bit members, again without the
207 compiler adding additional padding. Finally, it checks struct size
208 assertions using OFP_ASSERT.
210 Header files are read in the order specified. #include directives are
211 not processed, so specify them in dependency order.
213 This program is specialized for reading include/openflow/openflow.h
214 and include/openflow/nicira-ext.h. It will not work on arbitrary
215 header files without extensions.''' % {"argv0": argv0}
219 for fileName in sys.argv[1:]:
222 inputFile = open(fileName)
225 if token in ("#ifdef", "#ifndef", "#include",
226 "#endif", "#elif", "#else"):
228 elif token == "#define":
231 if line.startswith('('):
239 macros[name] = definition
240 elif token == "enum":
243 elif token in ('struct', 'union'):
245 elif match('OFP_ASSERT') or match('BOOST_STATIC_ASSERT'):
249 typeName = parseTypeName()
257 if types[typeName]['size'] != size:
258 warn("%s is %d bytes long but declared as %d" % (
259 typeName, types[typeName]['size'], size))
266 if __name__ == '__main__':