blob: 596102627c71e838d890cfeaaf1a22a885b4242e [file] [log] [blame]
Andrew Boie945af952017-08-22 13:15:23 -07001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
Andrew Boiec78c5e62019-03-11 14:45:43 -07006"""
7Script to generate gperf tables of kernel object metadata
8
9User mode threads making system calls reference kernel objects by memory
10address, as the kernel/driver APIs in Zephyr are the same for both user
11and supervisor contexts. It is necessary for the kernel to be able to
12validate accesses to kernel objects to make the following assertions:
13
14 - That the memory address points to a kernel object
15
16 - The kernel object is of the expected type for the API being invoked
17
18 - The kernel object is of the expected initialization state
19
20 - The calling thread has sufficient permissions on the object
21
David B. Kinder17299f02019-05-31 15:39:39 -070022For more details see the :ref:`kernelobjects` section in the documentation.
Marc Herbert4a10eea2019-04-16 15:39:45 -070023
Andrew Boiec78c5e62019-03-11 14:45:43 -070024The zephyr build generates an intermediate ELF binary, zephyr_prebuilt.elf,
25which this script scans looking for kernel objects by examining the DWARF
26debug information to look for instances of data structures that are considered
27kernel objects. For device drivers, the API struct pointer populated at build
28time is also examined to disambiguate between various device driver instances
29since they are all 'struct device'.
30
Marc Herbert4a10eea2019-04-16 15:39:45 -070031This script can generate five different output files:
Andrew Boiec78c5e62019-03-11 14:45:43 -070032
33 - A gperf script to generate the hash table mapping kernel object memory
34 addresses to kernel object metadata, used to track permissions,
35 object type, initialization state, and any object-specific data.
36
37 - A header file containing generated macros for validating driver instances
38 inside the system call handlers for the driver subsystem APIs.
39
Marc Herbert4a10eea2019-04-16 15:39:45 -070040 - A code fragment included by kernel.h with one enum constant for
41 each kernel object type and each driver instance.
Andrew Boiec78c5e62019-03-11 14:45:43 -070042
Marc Herbert4a10eea2019-04-16 15:39:45 -070043 - The inner cases of a switch/case C statement, included by
44 kernel/userspace.c, mapping the kernel object types and driver
45 instances to their human-readable representation in the
Andrew Boiec78c5e62019-03-11 14:45:43 -070046 otype_to_str() function.
47
Marc Herbert4a10eea2019-04-16 15:39:45 -070048 - The inner cases of a switch/case C statement, included by
49 kernel/userspace.c, mapping kernel object types to their sizes.
50 This is used for allocating instances of them at runtime
51 (CONFIG_DYNAMIC_OBJECTS) in the obj_size_get() function.
Andrew Boiec78c5e62019-03-11 14:45:43 -070052"""
Andrew Boie945af952017-08-22 13:15:23 -070053
54import sys
55import argparse
Daniel Leunge58b6542018-08-08 11:23:16 -070056import math
Andrew Boie945af952017-08-22 13:15:23 -070057import os
58import struct
Andrew Boief20efcf2018-05-23 10:57:39 -070059from elf_helper import ElfHelper, kobject_to_enum
Andrew Boie945af952017-08-22 13:15:23 -070060
Marc Herbertf78288b2019-03-05 14:31:44 -080061from collections import OrderedDict
62
Andrew Boie09c22cc2018-06-27 10:25:45 -070063# Keys in this dictionary are structs which should be recognized as kernel
Andrew Boiec235e162019-03-27 14:27:24 -070064# objects. Values are a tuple:
65#
66# - The first item is None, or the name of a Kconfig that
67# indicates the presence of this object's definition in case it is not
68# available in all configurations.
69#
70# - The second item is a boolean indicating whether it is permissible for
71# the object to be located in user-accessible memory.
Andrew Boie09c22cc2018-06-27 10:25:45 -070072
Marc Herbertf78288b2019-03-05 14:31:44 -080073# Regular dictionaries are ordered only with Python 3.6 and
74# above. Good summary and pointers to official documents at:
75# https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6
Ulf Magnusson0d39a102019-09-06 11:13:19 +020076kobjects = OrderedDict([
Andrew Boiec235e162019-03-27 14:27:24 -070077 ("k_mem_slab", (None, False)),
78 ("k_msgq", (None, False)),
79 ("k_mutex", (None, False)),
80 ("k_pipe", (None, False)),
81 ("k_queue", (None, False)),
82 ("k_poll_signal", (None, False)),
83 ("k_sem", (None, False)),
84 ("k_stack", (None, False)),
85 ("k_thread", (None, False)),
86 ("k_timer", (None, False)),
87 ("_k_thread_stack_element", (None, False)),
Andrew Boiec235e162019-03-27 14:27:24 -070088 ("device", (None, False)),
Wentong Wu5611e922019-06-20 23:51:27 +080089 ("sys_mutex", (None, True)),
90 ("k_futex", (None, True))
Marc Herbertf78288b2019-03-05 14:31:44 -080091])
92
93
Andrew Boie5bd891d2017-09-27 12:59:28 -070094
95subsystems = [
Anas Nashif72565532017-12-12 08:19:25 -050096 "adc_driver_api",
97 "aio_cmp_driver_api",
98 "counter_driver_api",
99 "crypto_driver_api",
Andrew Boiece6c8f32018-02-09 13:58:37 -0800100 "dma_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500101 "flash_driver_api",
102 "gpio_driver_api",
103 "i2c_driver_api",
104 "i2s_driver_api",
105 "ipm_driver_api",
Manivannan Sadhasivam26babfc2018-05-03 23:46:58 +0530106 "led_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500107 "pinmux_driver_api",
108 "pwm_driver_api",
109 "entropy_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500110 "sensor_driver_api",
111 "spi_driver_api",
112 "uart_driver_api",
Alexander Wachter8757e782019-02-07 17:57:43 +0100113 "can_driver_api",
Jukka Rissanenc9aaab72019-05-27 16:01:49 +0800114 "ptp_clock_driver_api",
Henrik Brix Andersena2a7b772019-10-20 21:22:03 +0200115 "eeprom_driver_api",
Andrew Boie13b8b412019-12-16 12:15:45 -0800116 "wdt_driver_api",
Andrew Boie5bd891d2017-09-27 12:59:28 -0700117
Andrew Boie6f928092019-04-23 13:06:59 -0700118 # Fake 'sample driver' subsystem, used by tests/samples
119 "sample_driver_api"
120]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700121
Andrew Boie945af952017-08-22 13:15:23 -0700122header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700123%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700124%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700125%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700126%struct-type
127%{
128#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800129#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700130#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700131#include <string.h>
132%}
133struct _k_object;
Andrew Boie945af952017-08-22 13:15:23 -0700134"""
135
Andy Gross6042ae92018-01-22 14:26:49 -0600136# Different versions of gperf have different prototypes for the lookup
137# function, best to implement the wrapper here. The pointer value itself is
138# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500139# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700140footer = """%%
Patrik Flykt4344e272019-03-08 14:19:05 -0700141struct _k_object *z_object_gperf_find(void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700142{
Patrik Flykt4344e272019-03-08 14:19:05 -0700143 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700144}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700145
Patrik Flykt4344e272019-03-08 14:19:05 -0700146void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700147{
148 int i;
149
150 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700151 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700152 func(&wordlist[i], context);
153 }
154 }
155}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800156
157#ifndef CONFIG_DYNAMIC_OBJECTS
Patrik Flykt4344e272019-03-08 14:19:05 -0700158struct _k_object *z_object_find(void *obj)
159 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800160
Patrik Flykt4344e272019-03-08 14:19:05 -0700161void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
162 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800163#endif
Andrew Boie945af952017-08-22 13:15:23 -0700164"""
165
166
Andy Gross6042ae92018-01-22 14:26:49 -0600167def write_gperf_table(fp, eh, objs, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700168 fp.write(header)
Andrew Boief0835672019-03-27 15:44:52 -0700169 num_mutexes = eh.get_sys_mutex_counter()
Ulf Magnusson9d343562019-05-07 12:06:35 +0200170 if num_mutexes != 0:
Andrew Boief0835672019-03-27 15:44:52 -0700171 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n" % num_mutexes)
172 for i in range(num_mutexes):
173 fp.write("_K_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Ulf Magnusson9d343562019-05-07 12:06:35 +0200174 if i != num_mutexes - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700175 fp.write(", ")
176 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700177
Wentong Wu5611e922019-06-20 23:51:27 +0800178 num_futex = eh.get_futex_counter()
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200179 if num_futex != 0:
Wentong Wu5611e922019-06-20 23:51:27 +0800180 fp.write("static struct z_futex_data futex_data[%d] = {\n" % num_futex)
181 for i in range(num_futex):
182 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200183 if i != num_futex - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800184 fp.write(", ")
185 fp.write("};\n")
186
Andrew Boief0835672019-03-27 15:44:52 -0700187 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700188 # Setup variables for mapping thread indexes
189 syms = eh.get_symbols()
190 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
191 thread_idx_map = {}
192
193 for i in range(0, thread_max_bytes):
194 thread_idx_map[i] = 0xFF
195
Andrew Boiebca15da2017-10-15 14:17:48 -0700196 for obj_addr, ko in objs.items():
197 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700198 # pre-initialized objects fall within this memory range, they are
199 # either completely initialized at build time, or done automatically
200 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200201 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700202 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700203
Andrew Boief290ab52019-11-18 17:06:13 -0800204 if "CONFIG_64BIT" in syms:
205 format_code = "Q"
206 else:
207 format_code = "I"
208
209 if eh.little_endian:
210 endian = "<"
211 else:
212 endian = ">"
213
214 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700215 fp.write("\"")
216 for byte in byte_str:
217 val = "\\x%02x" % byte
218 fp.write(val)
219
Andrew Boie78757072019-07-23 13:29:30 -0700220 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200221 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700222 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200223 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700224 flags += " | K_OBJ_FLAG_DRIVER"
225
226 fp.write("\", {}, %s, %s, %s\n" % (obj_type, flags, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700227
Daniel Leunge58b6542018-08-08 11:23:16 -0700228 if obj_type == "K_OBJ_THREAD":
229 idx = math.floor(ko.data / 8)
230 bit = ko.data % 8
231 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
232
Andrew Boie945af952017-08-22 13:15:23 -0700233 fp.write(footer)
234
Daniel Leunge58b6542018-08-08 11:23:16 -0700235 # Generate the array of already mapped thread indexes
236 fp.write('\n')
Andrew Boie9b34ecd2020-01-08 17:37:11 -0800237 fp.write('Z_GENERIC_SECTION(.kobject_data.data) ')
Daniel Leunge58b6542018-08-08 11:23:16 -0700238 fp.write('u8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
239
240 for i in range(0, thread_max_bytes):
241 fp.write(' 0x%x, ' % (thread_idx_map[i]))
242
243 fp.write('};\n')
244
Andrew Boie945af952017-08-22 13:15:23 -0700245
Leandro Pereirac2003672018-04-04 13:50:32 -0700246driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700247#define Z_SYSCALL_DRIVER_%(driver_upper)s(ptr, op) Z_SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s)
Leandro Pereirac2003672018-04-04 13:50:32 -0700248"""
249
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500250
Leandro Pereirac2003672018-04-04 13:50:32 -0700251def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700252 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
253 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700254
Andrew Boie8345e5e2018-05-04 15:57:57 -0700255 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
256 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
257 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
258 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700259
260 for subsystem in subsystems:
261 subsystem = subsystem.replace("_driver_api", "")
262
263 fp.write(driver_macro_tpl % {
264 "driver_lower": subsystem.lower(),
265 "driver_upper": subsystem.upper(),
266 })
267
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700268 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700269
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700270
271def write_kobj_types_output(fp):
272 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700273 for kobj, obj_info in kobjects.items():
274 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700275 if kobj == "device":
276 continue
277
Andrew Boie09c22cc2018-06-27 10:25:45 -0700278 if dep:
279 fp.write("#ifdef %s\n" % dep)
280
Andrew Boief20efcf2018-05-23 10:57:39 -0700281 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700282
Andrew Boie09c22cc2018-06-27 10:25:45 -0700283 if dep:
284 fp.write("#endif\n")
285
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700286 fp.write("/* Driver subsystems */\n")
287 for subsystem in subsystems:
288 subsystem = subsystem.replace("_driver_api", "").upper()
289 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
290
291
292def write_kobj_otype_output(fp):
293 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700294 for kobj, obj_info in kobjects.items():
295 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700296 if kobj == "device":
297 continue
298
Andrew Boie09c22cc2018-06-27 10:25:45 -0700299 if dep:
300 fp.write("#ifdef %s\n" % dep)
301
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500302 fp.write('case %s: ret = "%s"; break;\n' %
303 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700304 if dep:
305 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700306
307 fp.write("/* Driver subsystems */\n")
308 for subsystem in subsystems:
309 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700310 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700311 subsystem.upper(),
312 subsystem
313 ))
314
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500315
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700316def write_kobj_size_output(fp):
317 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700318 for kobj, obj_info in kobjects.items():
319 dep, _ = obj_info
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700320 # device handled by default case. Stacks are not currently handled,
321 # if they eventually are it will be a special case.
Ulf Magnusson3feb8f92019-09-03 14:25:26 +0200322 if kobj in {"device", "_k_thread_stack_element"}:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700323 continue
324
Andrew Boie09c22cc2018-06-27 10:25:45 -0700325 if dep:
326 fp.write("#ifdef %s\n" % dep)
327
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700328 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500329 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700330 if dep:
331 fp.write("#endif\n")
332
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700333
Andrew Boie945af952017-08-22 13:15:23 -0700334def parse_args():
335 global args
336
Anas Nashif72565532017-12-12 08:19:25 -0500337 parser = argparse.ArgumentParser(
338 description=__doc__,
339 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700340
Leandro Pereirac2003672018-04-04 13:50:32 -0700341 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500342 help="Input zephyr ELF binary")
343 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700344 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500345 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700346 parser.add_argument(
347 "-V", "--validation-output", required=False,
348 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700349 parser.add_argument(
350 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700351 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700352 parser.add_argument(
353 "-S", "--kobj-otype-output", required=False,
354 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700355 parser.add_argument(
356 "-Z", "--kobj-size-output", required=False,
357 help="Output case statements for obj_size_get()")
Andrew Boie945af952017-08-22 13:15:23 -0700358 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500359 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700360 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100361 if "VERBOSE" in os.environ:
362 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700363
364
365def main():
366 parse_args()
367
Leandro Pereirac2003672018-04-04 13:50:32 -0700368 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -0800369 assert args.kernel, "--kernel ELF required for --gperf-output"
Leandro Pereirac2003672018-04-04 13:50:32 -0700370 eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
371 syms = eh.get_symbols()
372 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
373 objs = eh.find_kobjects(syms)
Marc Herbertf78288b2019-03-05 14:31:44 -0800374 if not objs:
375 sys.stderr.write("WARNING: zero kobject found in %s\n"
376 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -0700377
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500378 thread_counter = eh.get_thread_counter()
379 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +0200380 sys.exit("Too many thread objects ({})\n"
381 "Increase CONFIG_MAX_THREAD_BYTES to {}"
382 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -0700383
Leandro Pereirac2003672018-04-04 13:50:32 -0700384 with open(args.gperf_output, "w") as fp:
385 write_gperf_table(fp, eh, objs,
386 syms["_static_kernel_objects_begin"],
387 syms["_static_kernel_objects_end"])
388
389 if args.validation_output:
390 with open(args.validation_output, "w") as fp:
391 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -0500392
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700393 if args.kobj_types_output:
394 with open(args.kobj_types_output, "w") as fp:
395 write_kobj_types_output(fp)
396
397 if args.kobj_otype_output:
398 with open(args.kobj_otype_output, "w") as fp:
399 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -0700400
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700401 if args.kobj_size_output:
402 with open(args.kobj_size_output, "w") as fp:
403 write_kobj_size_output(fp)
404
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500405
Andrew Boie945af952017-08-22 13:15:23 -0700406if __name__ == "__main__":
407 main()