blob: b93258164803799b11d878bf908c4c13c3268e55 [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
Corey Whartonccd15df2020-02-29 14:51:42 -080059import json
Andrew Boiefc2f7c32020-03-11 14:17:56 -070060from distutils.version import LooseVersion
61
62import elftools
63from elftools.elf.elffile import ELFFile
64from elftools.elf.sections import SymbolTableSection
65
66if LooseVersion(elftools.__version__) < LooseVersion('0.24'):
67 sys.exit("pyelftools is out of date, need version 0.24 or later")
Andrew Boie945af952017-08-22 13:15:23 -070068
Marc Herbertf78288b2019-03-05 14:31:44 -080069from collections import OrderedDict
70
Andrew Boie09c22cc2018-06-27 10:25:45 -070071# Keys in this dictionary are structs which should be recognized as kernel
Andrew Boiec235e162019-03-27 14:27:24 -070072# objects. Values are a tuple:
73#
74# - The first item is None, or the name of a Kconfig that
75# indicates the presence of this object's definition in case it is not
76# available in all configurations.
77#
78# - The second item is a boolean indicating whether it is permissible for
79# the object to be located in user-accessible memory.
Andrew Boie455e1782020-05-29 13:22:20 -070080#
81# - The third items is a boolean indicating whether this item can be
Andrew Boiebe919d32020-05-29 17:49:02 -070082# dynamically allocated with k_object_alloc(). Keep this in sync with
83# the switch statement in z_impl_k_object_alloc().
Andrew Boie299ec8f2020-05-29 13:30:19 -070084#
85# Key names in all caps do not correspond to a specific data type but instead
86# indicate that objects of its type are of a family of compatible data
87# structures
Andrew Boie09c22cc2018-06-27 10:25:45 -070088
Marc Herbertf78288b2019-03-05 14:31:44 -080089# Regular dictionaries are ordered only with Python 3.6 and
90# above. Good summary and pointers to official documents at:
91# https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6
Ulf Magnusson0d39a102019-09-06 11:13:19 +020092kobjects = OrderedDict([
Andrew Boie455e1782020-05-29 13:22:20 -070093 ("k_mem_slab", (None, False, True)),
94 ("k_msgq", (None, False, True)),
95 ("k_mutex", (None, False, True)),
96 ("k_pipe", (None, False, True)),
97 ("k_queue", (None, False, True)),
98 ("k_poll_signal", (None, False, True)),
99 ("k_sem", (None, False, True)),
100 ("k_stack", (None, False, True)),
101 ("k_thread", (None, False, True)), # But see #
102 ("k_timer", (None, False, True)),
103 ("z_thread_stack_element", (None, False, False)),
104 ("device", (None, False, False)),
Andrew Boie299ec8f2020-05-29 13:30:19 -0700105 ("NET_SOCKET", (None, False, False)),
Jukka Rissanenbfa08cd2020-06-17 15:18:22 +0300106 ("net_if", (None, False, False)),
Andrew Boie455e1782020-05-29 13:22:20 -0700107 ("sys_mutex", (None, True, False)),
108 ("k_futex", (None, True, False))
Marc Herbertf78288b2019-03-05 14:31:44 -0800109])
110
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700111def kobject_to_enum(kobj):
112 if kobj.startswith("k_") or kobj.startswith("z_"):
113 name = kobj[2:]
114 else:
115 name = kobj
116
117 return "K_OBJ_%s" % name.upper()
118
Andrew Boie5bd891d2017-09-27 12:59:28 -0700119subsystems = [
Corey Wharton86bfc482020-03-04 13:32:01 -0800120 # Editing the list is deprecated, add the __subsystem sentinal to your driver
121 # api declaration instead. e.x.
122 #
123 # __subsystem struct my_driver_api {
124 # ....
125 #};
Andrew Boie6f928092019-04-23 13:06:59 -0700126]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700127
Andrew Boie299ec8f2020-05-29 13:30:19 -0700128# Names of all structs tagged with __net_socket, found by parse_syscalls.py
129net_sockets = [ ]
130
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700131def subsystem_to_enum(subsys):
132 return "K_OBJ_DRIVER_" + subsys[:-11].upper()
133
134# --- debug stuff ---
135
136scr = os.path.basename(sys.argv[0])
137
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700138def debug(text):
139 if not args.verbose:
140 return
141 sys.stdout.write(scr + ": " + text + "\n")
142
143def error(text):
144 sys.exit("%s ERROR: %s" % (scr, text))
145
146def debug_die(die, text):
147 lp_header = die.dwarfinfo.line_program_for_CU(die.cu).header
148 files = lp_header["file_entry"]
149 includes = lp_header["include_directory"]
150
151 fileinfo = files[die.attributes["DW_AT_decl_file"].value - 1]
152 filename = fileinfo.name.decode("utf-8")
153 filedir = includes[fileinfo.dir_index - 1].decode("utf-8")
154
155 path = os.path.join(filedir, filename)
156 lineno = die.attributes["DW_AT_decl_line"].value
157
158 debug(str(die))
159 debug("File '%s', line %d:" % (path, lineno))
160 debug(" %s" % text)
161
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700162# -- ELF processing
163
164DW_OP_addr = 0x3
165DW_OP_fbreg = 0x91
166STACK_TYPE = "z_thread_stack_element"
167thread_counter = 0
168sys_mutex_counter = 0
169futex_counter = 0
170stack_counter = 0
171
172# Global type environment. Populated by pass 1.
173type_env = {}
174extern_env = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700175
176class KobjectInstance:
177 def __init__(self, type_obj, addr):
178 global thread_counter
179 global sys_mutex_counter
180 global futex_counter
181 global stack_counter
182
183 self.addr = addr
184 self.type_obj = type_obj
185
186 # Type name determined later since drivers needs to look at the
187 # API struct address
188 self.type_name = None
189
190 if self.type_obj.name == "k_thread":
191 # Assign an ID for this thread object, used to track its
192 # permissions to other kernel objects
193 self.data = thread_counter
194 thread_counter = thread_counter + 1
195 elif self.type_obj.name == "sys_mutex":
196 self.data = "&kernel_mutexes[%d]" % sys_mutex_counter
197 sys_mutex_counter += 1
198 elif self.type_obj.name == "k_futex":
199 self.data = "&futex_data[%d]" % futex_counter
200 futex_counter += 1
201 elif self.type_obj.name == STACK_TYPE:
202 stack_counter += 1
203 else:
204 self.data = 0
205
206
207class KobjectType:
208 def __init__(self, offset, name, size, api=False):
209 self.name = name
210 self.size = size
211 self.offset = offset
212 self.api = api
213
214 def __repr__(self):
215 return "<kobject %s>" % self.name
216
217 @staticmethod
218 def has_kobject():
219 return True
220
221 def get_kobjects(self, addr):
222 return {addr: KobjectInstance(self, addr)}
223
224
225class ArrayType:
226 def __init__(self, offset, elements, member_type):
227 self.elements = elements
228 self.member_type = member_type
229 self.offset = offset
230
231 def __repr__(self):
232 return "<array of %d>" % self.member_type
233
234 def has_kobject(self):
235 if self.member_type not in type_env:
236 return False
237
238 return type_env[self.member_type].has_kobject()
239
240 def get_kobjects(self, addr):
241 mt = type_env[self.member_type]
242
243 # Stacks are arrays of _k_stack_element_t but we want to treat
244 # the whole array as one kernel object (a thread stack)
245 # Data value gets set to size of entire region
246 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
247 # An array of stacks appears as a multi-dimensional array.
248 # The last size is the size of each stack. We need to track
249 # each stack within the array, not as one huge stack object.
250 *dimensions, stacksize = self.elements
251 num_members = 1
252 for e in dimensions:
253 num_members = num_members * e
254
255 ret = {}
256 for i in range(num_members):
257 a = addr + (i * stacksize)
258 o = mt.get_kobjects(a)
259 o[a].data = stacksize
260 ret.update(o)
261 return ret
262
263 objs = {}
264
265 # Multidimensional array flattened out
266 num_members = 1
267 for e in self.elements:
268 num_members = num_members * e
269
270 for i in range(num_members):
271 objs.update(mt.get_kobjects(addr + (i * mt.size)))
272 return objs
273
274
275class AggregateTypeMember:
276 def __init__(self, offset, member_name, member_type, member_offset):
277 self.member_name = member_name
278 self.member_type = member_type
279 if isinstance(member_offset, list):
280 # DWARF v2, location encoded as set of operations
281 # only "DW_OP_plus_uconst" with ULEB128 argument supported
282 if member_offset[0] == 0x23:
283 self.member_offset = member_offset[1] & 0x7f
284 for i in range(1, len(member_offset)-1):
285 if member_offset[i] & 0x80:
286 self.member_offset += (
287 member_offset[i+1] & 0x7f) << i*7
288 else:
289 raise Exception("not yet supported location operation (%s:%d:%d)" %
290 (self.member_name, self.member_type, member_offset[0]))
291 else:
292 self.member_offset = member_offset
293
294 def __repr__(self):
295 return "<member %s, type %d, offset %d>" % (
296 self.member_name, self.member_type, self.member_offset)
297
298 def has_kobject(self):
299 if self.member_type not in type_env:
300 return False
301
302 return type_env[self.member_type].has_kobject()
303
304 def get_kobjects(self, addr):
305 mt = type_env[self.member_type]
306 return mt.get_kobjects(addr + self.member_offset)
307
308
309class ConstType:
310 def __init__(self, child_type):
311 self.child_type = child_type
312
313 def __repr__(self):
314 return "<const %d>" % self.child_type
315
316 def has_kobject(self):
317 if self.child_type not in type_env:
318 return False
319
320 return type_env[self.child_type].has_kobject()
321
322 def get_kobjects(self, addr):
323 return type_env[self.child_type].get_kobjects(addr)
324
325
326class AggregateType:
327 def __init__(self, offset, name, size):
328 self.name = name
329 self.size = size
330 self.offset = offset
331 self.members = []
332
333 def add_member(self, member):
334 self.members.append(member)
335
336 def __repr__(self):
337 return "<struct %s, with %s>" % (self.name, self.members)
338
339 def has_kobject(self):
340 result = False
341
342 bad_members = []
343
344 for member in self.members:
345 if member.has_kobject():
346 result = True
347 else:
348 bad_members.append(member)
349 # Don't need to consider this again, just remove it
350
351 for bad_member in bad_members:
352 self.members.remove(bad_member)
353
354 return result
355
356 def get_kobjects(self, addr):
357 objs = {}
358 for member in self.members:
359 objs.update(member.get_kobjects(addr))
360 return objs
361
362
363# --- helper functions for getting data from DIEs ---
364
365def die_get_spec(die):
366 if 'DW_AT_specification' not in die.attributes:
367 return None
368
369 spec_val = die.attributes["DW_AT_specification"].value
370
371 # offset of the DW_TAG_variable for the extern declaration
372 offset = spec_val + die.cu.cu_offset
373
374 return extern_env.get(offset)
375
376
377def die_get_name(die):
378 if 'DW_AT_name' not in die.attributes:
379 die = die_get_spec(die)
380 if not die:
381 return None
382
383 return die.attributes["DW_AT_name"].value.decode("utf-8")
384
385
386def die_get_type_offset(die):
387 if 'DW_AT_type' not in die.attributes:
388 die = die_get_spec(die)
389 if not die:
390 return None
391
392 return die.attributes["DW_AT_type"].value + die.cu.cu_offset
393
394
395def die_get_byte_size(die):
396 if 'DW_AT_byte_size' not in die.attributes:
397 return 0
398
399 return die.attributes["DW_AT_byte_size"].value
400
401
402def analyze_die_struct(die):
403 name = die_get_name(die) or "<anon>"
404 offset = die.offset
405 size = die_get_byte_size(die)
406
407 # Incomplete type
408 if not size:
409 return
410
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700411 if name in kobjects:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700412 type_env[offset] = KobjectType(offset, name, size)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700413 elif name in subsystems:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700414 type_env[offset] = KobjectType(offset, name, size, api=True)
Andrew Boie299ec8f2020-05-29 13:30:19 -0700415 elif name in net_sockets:
416 type_env[offset] = KobjectType(offset, "NET_SOCKET", size)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700417 else:
418 at = AggregateType(offset, name, size)
419 type_env[offset] = at
420
421 for child in die.iter_children():
422 if child.tag != "DW_TAG_member":
423 continue
424 data_member_location = child.attributes.get("DW_AT_data_member_location")
425 if not data_member_location:
426 continue
427
428 child_type = die_get_type_offset(child)
429 member_offset = data_member_location.value
430 cname = die_get_name(child) or "<anon>"
431 m = AggregateTypeMember(child.offset, cname, child_type,
432 member_offset)
433 at.add_member(m)
434
435 return
436
437
438def analyze_die_const(die):
439 type_offset = die_get_type_offset(die)
440 if not type_offset:
441 return
442
443 type_env[die.offset] = ConstType(type_offset)
444
445
446def analyze_die_array(die):
447 type_offset = die_get_type_offset(die)
448 elements = []
449
450 for child in die.iter_children():
451 if child.tag != "DW_TAG_subrange_type":
452 continue
453 if "DW_AT_upper_bound" not in child.attributes:
454 continue
455
456 ub = child.attributes["DW_AT_upper_bound"]
457 if not ub.form.startswith("DW_FORM_data"):
458 continue
459
460 elements.append(ub.value + 1)
461
462 if not elements:
463 if type_offset in type_env.keys():
464 mt = type_env[type_offset]
465 if mt.has_kobject():
466 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
467 elements.append(1)
468 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
469 else:
470 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
471
472
473def analyze_typedef(die):
474 type_offset = die_get_type_offset(die)
475
476 if type_offset not in type_env.keys():
477 return
478
479 type_env[die.offset] = type_env[type_offset]
480
481
482def unpack_pointer(elf, data, offset):
483 endian_code = "<" if elf.little_endian else ">"
484 if elf.elfclass == 32:
485 size_code = "I"
486 size = 4
487 else:
488 size_code = "Q"
489 size = 8
490
491 return struct.unpack(endian_code + size_code,
492 data[offset:offset + size])[0]
493
494
495def addr_deref(elf, addr):
496 for section in elf.iter_sections():
497 start = section['sh_addr']
498 end = start + section['sh_size']
499
500 if start <= addr < end:
501 data = section.data()
502 offset = addr - start
503 return unpack_pointer(elf, data, offset)
504
505 return 0
506
507
508def device_get_api_addr(elf, addr):
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100509 # See include/device.h for a description of struct device
510 offset = 8 if elf.elfclass == 32 else 16
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700511 return addr_deref(elf, addr + offset)
512
513
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700514def find_kobjects(elf, syms):
515 if not elf.has_dwarf_info():
516 sys.exit("ELF file has no DWARF information")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700517
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700518 app_smem_start = syms["_app_smem_start"]
519 app_smem_end = syms["_app_smem_end"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700520
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700521 di = elf.get_dwarf_info()
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700522
Wentong Wu0bf51132020-05-21 16:49:28 +0800523 variables = []
524
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700525 # Step 1: collect all type information.
526 for CU in di.iter_CUs():
527 for die in CU.iter_DIEs():
528 # Unions are disregarded, kernel objects should never be union
529 # members since the memory is not dedicated to that object and
530 # could be something else
531 if die.tag == "DW_TAG_structure_type":
532 analyze_die_struct(die)
533 elif die.tag == "DW_TAG_const_type":
534 analyze_die_const(die)
535 elif die.tag == "DW_TAG_array_type":
536 analyze_die_array(die)
537 elif die.tag == "DW_TAG_typedef":
538 analyze_typedef(die)
539 elif die.tag == "DW_TAG_variable":
540 variables.append(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700541
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700542 # Step 2: filter type_env to only contain kernel objects, or structs
543 # and arrays of kernel objects
544 bad_offsets = []
545 for offset, type_object in type_env.items():
546 if not type_object.has_kobject():
547 bad_offsets.append(offset)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700548
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700549 for offset in bad_offsets:
550 del type_env[offset]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700551
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700552 # Step 3: Now that we know all the types we are looking for, examine
553 # all variables
554 all_objs = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700555
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700556 for die in variables:
557 name = die_get_name(die)
558 if not name:
559 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700560
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100561 if name.startswith("__init_sys_init"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700562 # Boot-time initialization function; not an actual device
563 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700564
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700565 type_offset = die_get_type_offset(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700566
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700567 # Is this a kernel object, or a structure containing kernel
568 # objects?
569 if type_offset not in type_env:
570 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700571
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700572 if "DW_AT_declaration" in die.attributes:
573 # Extern declaration, only used indirectly
574 extern_env[die.offset] = die
575 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700576
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700577 if "DW_AT_location" not in die.attributes:
578 debug_die(die,
579 "No location information for object '%s'; possibly stack allocated"
580 % name)
581 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700582
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700583 loc = die.attributes["DW_AT_location"]
584 if loc.form != "DW_FORM_exprloc" and \
585 loc.form != "DW_FORM_block1":
586 debug_die(die, "kernel object '%s' unexpected location format" %
587 name)
588 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700589
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700590 opcode = loc.value[0]
591 if opcode != DW_OP_addr:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700592
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700593 # Check if frame pointer offset DW_OP_fbreg
594 if opcode == DW_OP_fbreg:
595 debug_die(die, "kernel object '%s' found on stack" % name)
596 else:
597 debug_die(die,
598 "kernel object '%s' unexpected exprloc opcode %s" %
599 (name, hex(opcode)))
600 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700601
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700602 addr = (loc.value[1] | (loc.value[2] << 8) |
603 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700604
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700605 if addr == 0:
606 # Never linked; gc-sections deleted it
607 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700608
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700609 type_obj = type_env[type_offset]
610 objs = type_obj.get_kobjects(addr)
611 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700612
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700613 debug("symbol '%s' at %s contains %d object(s)"
614 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700615
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700616 # Step 4: objs is a dictionary mapping variable memory addresses to
617 # their associated type objects. Now that we have seen all variables
618 # and can properly look up API structs, convert this into a dictionary
619 # mapping variables to the C enumeration of what kernel object type it
620 # is.
621 ret = {}
622 for addr, ko in all_objs.items():
623 # API structs don't get into the gperf table
624 if ko.type_obj.api:
625 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700626
Andrew Boie455e1782020-05-29 13:22:20 -0700627 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700628 if not user_ram_allowed and app_smem_start <= addr < app_smem_end:
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800629 debug("object '%s' found in invalid location %s"
630 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700631 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700632
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700633 if ko.type_obj.name != "device":
634 # Not a device struct so we immediately know its type
635 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700636 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700637 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700638
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700639 # Device struct. Need to get the address of its API struct,
640 # if it has one.
641 apiaddr = device_get_api_addr(elf, addr)
642 if apiaddr not in all_objs:
643 if apiaddr == 0:
644 debug("device instance at 0x%x has no associated subsystem"
645 % addr)
646 else:
647 debug("device instance at 0x%x has unknown API 0x%x"
648 % (addr, apiaddr))
649 # API struct does not correspond to a known subsystem, skip it
650 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700651
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700652 apiobj = all_objs[apiaddr]
653 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
654 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700655
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700656 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700657
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700658 # 1. Before python 3.7 dict order is not guaranteed. With Python
659 # 3.5 it doesn't seem random with *integer* keys but can't
660 # rely on that.
661 # 2. OrderedDict means _insertion_ order, so not enough because
662 # built from other (random!) dicts: need to _sort_ first.
663 # 3. Sorting memory address looks good.
664 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700665
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700666def get_symbols(elf):
667 for section in elf.iter_sections():
668 if isinstance(section, SymbolTableSection):
669 return {sym.name: sym.entry.st_value
670 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700671
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700672 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700673
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700674
675# -- GPERF generation logic
676
Andrew Boie945af952017-08-22 13:15:23 -0700677header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700678%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700679%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700680%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700681%struct-type
682%{
683#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800684#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700685#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700686#include <string.h>
687%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700688struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700689"""
690
Andy Gross6042ae92018-01-22 14:26:49 -0600691# Different versions of gperf have different prototypes for the lookup
692# function, best to implement the wrapper here. The pointer value itself is
693# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500694# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700695footer = """%%
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700696struct z_object *z_object_gperf_find(void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700697{
Patrik Flykt4344e272019-03-08 14:19:05 -0700698 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700699}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700700
Patrik Flykt4344e272019-03-08 14:19:05 -0700701void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700702{
703 int i;
704
705 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700706 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700707 func(&wordlist[i], context);
708 }
709 }
710}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800711
712#ifndef CONFIG_DYNAMIC_OBJECTS
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700713struct z_object *z_object_find(void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700714 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800715
Patrik Flykt4344e272019-03-08 14:19:05 -0700716void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
717 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800718#endif
Andrew Boie945af952017-08-22 13:15:23 -0700719"""
720
721
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700722def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700723 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700724 if sys_mutex_counter != 0:
725 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
726 % sys_mutex_counter)
727 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400728 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700729 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700730 fp.write(", ")
731 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700732
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700733 if futex_counter != 0:
734 fp.write("static struct z_futex_data futex_data[%d] = {\n"
735 % futex_counter)
736 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800737 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700738 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800739 fp.write(", ")
740 fp.write("};\n")
741
Andrew Boie28be7932020-03-11 10:56:19 -0700742 metadata_names = {
743 "K_OBJ_THREAD" : "thread_id",
744 "K_OBJ_SYS_MUTEX" : "mutex",
745 "K_OBJ_FUTEX" : "futex_data"
746 }
747
748 if "CONFIG_GEN_PRIV_STACKS" in syms:
749 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700750 if stack_counter != 0:
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500751 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie28be7932020-03-11 10:56:19 -0700752 " __aligned(Z_PRIVILEGE_STACK_ALIGN)"
753 " priv_stacks[%d][CONFIG_PRIVILEGED_STACK_SIZE];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700754 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700755
756 fp.write("static struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700757 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700758 counter = 0
759 for _, ko in objs.items():
760 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
761 continue
762
763 # ko.data currently has the stack size. fetch the value to
764 # populate the appropriate entry in stack_data, and put
765 # a reference to the entry in stack_data into the data value
766 # instead
767 size = ko.data
768 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500769 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700770 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700771 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700772 fp.write(",")
773 fp.write("\n")
774 counter += 1
775 fp.write("};\n")
776 else:
777 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
778
Andrew Boief0835672019-03-27 15:44:52 -0700779 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700780 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700781 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
782 thread_idx_map = {}
783
784 for i in range(0, thread_max_bytes):
785 thread_idx_map[i] = 0xFF
786
Andrew Boiebca15da2017-10-15 14:17:48 -0700787 for obj_addr, ko in objs.items():
788 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700789 # pre-initialized objects fall within this memory range, they are
790 # either completely initialized at build time, or done automatically
791 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200792 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700793 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700794
Andrew Boief290ab52019-11-18 17:06:13 -0800795 if "CONFIG_64BIT" in syms:
796 format_code = "Q"
797 else:
798 format_code = "I"
799
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700800 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800801 endian = "<"
802 else:
803 endian = ">"
804
805 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700806 fp.write("\"")
807 for byte in byte_str:
808 val = "\\x%02x" % byte
809 fp.write(val)
810
Andrew Boie78757072019-07-23 13:29:30 -0700811 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200812 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700813 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200814 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700815 flags += " | K_OBJ_FLAG_DRIVER"
816
Andrew Boief2734ab2020-03-11 06:37:42 -0700817 if ko.type_name in metadata_names:
818 tname = metadata_names[ko.type_name]
819 else:
820 tname = "unused"
821
822 fp.write("\", {}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
823 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700824
Daniel Leunge58b6542018-08-08 11:23:16 -0700825 if obj_type == "K_OBJ_THREAD":
826 idx = math.floor(ko.data / 8)
827 bit = ko.data % 8
828 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
829
Andrew Boie945af952017-08-22 13:15:23 -0700830 fp.write(footer)
831
Daniel Leunge58b6542018-08-08 11:23:16 -0700832 # Generate the array of already mapped thread indexes
833 fp.write('\n')
Andrew Boie9b34ecd2020-01-08 17:37:11 -0800834 fp.write('Z_GENERIC_SECTION(.kobject_data.data) ')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500835 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700836
837 for i in range(0, thread_max_bytes):
838 fp.write(' 0x%x, ' % (thread_idx_map[i]))
839
840 fp.write('};\n')
841
Andrew Boie945af952017-08-22 13:15:23 -0700842
Leandro Pereirac2003672018-04-04 13:50:32 -0700843driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700844#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 -0700845"""
846
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500847
Leandro Pereirac2003672018-04-04 13:50:32 -0700848def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700849 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
850 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700851
Andrew Boie8345e5e2018-05-04 15:57:57 -0700852 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
853 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
854 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
855 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700856
857 for subsystem in subsystems:
858 subsystem = subsystem.replace("_driver_api", "")
859
860 fp.write(driver_macro_tpl % {
861 "driver_lower": subsystem.lower(),
862 "driver_upper": subsystem.upper(),
863 })
864
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700865 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700866
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700867
868def write_kobj_types_output(fp):
869 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700870 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700871 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700872 if kobj == "device":
873 continue
874
Andrew Boie09c22cc2018-06-27 10:25:45 -0700875 if dep:
876 fp.write("#ifdef %s\n" % dep)
877
Andrew Boief20efcf2018-05-23 10:57:39 -0700878 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700879
Andrew Boie09c22cc2018-06-27 10:25:45 -0700880 if dep:
881 fp.write("#endif\n")
882
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700883 fp.write("/* Driver subsystems */\n")
884 for subsystem in subsystems:
885 subsystem = subsystem.replace("_driver_api", "").upper()
886 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
887
888
889def write_kobj_otype_output(fp):
890 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700891 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700892 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700893 if kobj == "device":
894 continue
895
Andrew Boie09c22cc2018-06-27 10:25:45 -0700896 if dep:
897 fp.write("#ifdef %s\n" % dep)
898
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500899 fp.write('case %s: ret = "%s"; break;\n' %
900 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700901 if dep:
902 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700903
904 fp.write("/* Driver subsystems */\n")
905 for subsystem in subsystems:
906 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700907 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700908 subsystem.upper(),
909 subsystem
910 ))
911
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500912
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700913def write_kobj_size_output(fp):
914 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700915 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700916 dep, _, alloc = obj_info
917
918 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700919 continue
920
Andrew Boie09c22cc2018-06-27 10:25:45 -0700921 if dep:
922 fp.write("#ifdef %s\n" % dep)
923
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700924 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500925 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700926 if dep:
927 fp.write("#endif\n")
928
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700929
Corey Whartonccd15df2020-02-29 14:51:42 -0800930def parse_subsystems_list_file(path):
931 with open(path, "r") as fp:
932 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700933 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700934 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800935
Andrew Boie945af952017-08-22 13:15:23 -0700936def parse_args():
937 global args
938
Anas Nashif72565532017-12-12 08:19:25 -0500939 parser = argparse.ArgumentParser(
940 description=__doc__,
941 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700942
Leandro Pereirac2003672018-04-04 13:50:32 -0700943 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500944 help="Input zephyr ELF binary")
945 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700946 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500947 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700948 parser.add_argument(
949 "-V", "--validation-output", required=False,
950 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700951 parser.add_argument(
952 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700953 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700954 parser.add_argument(
955 "-S", "--kobj-otype-output", required=False,
956 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700957 parser.add_argument(
958 "-Z", "--kobj-size-output", required=False,
959 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -0800960 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
961 help='''Specifies a file with a JSON encoded list of subsystem names to append to
962 the driver subsystems list. Can be specified multiple times:
963 -i file1 -i file2 ...''')
964
Andrew Boie945af952017-08-22 13:15:23 -0700965 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500966 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700967 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100968 if "VERBOSE" in os.environ:
969 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700970
971
972def main():
973 parse_args()
974
Corey Whartonccd15df2020-02-29 14:51:42 -0800975 if args.include_subsystem_list is not None:
976 for list_file in args.include_subsystem_list:
977 parse_subsystems_list_file(list_file)
978
Leandro Pereirac2003672018-04-04 13:50:32 -0700979 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -0800980 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700981 elf = ELFFile(open(args.kernel, "rb"))
982 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -0700983 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700984 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -0800985 if not objs:
986 sys.stderr.write("WARNING: zero kobject found in %s\n"
987 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -0700988
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500989 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +0200990 sys.exit("Too many thread objects ({})\n"
991 "Increase CONFIG_MAX_THREAD_BYTES to {}"
992 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -0700993
Leandro Pereirac2003672018-04-04 13:50:32 -0700994 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700995 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -0700996 syms["_static_kernel_objects_begin"],
997 syms["_static_kernel_objects_end"])
998
999 if args.validation_output:
1000 with open(args.validation_output, "w") as fp:
1001 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001002
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001003 if args.kobj_types_output:
1004 with open(args.kobj_types_output, "w") as fp:
1005 write_kobj_types_output(fp)
1006
1007 if args.kobj_otype_output:
1008 with open(args.kobj_otype_output, "w") as fp:
1009 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001010
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001011 if args.kobj_size_output:
1012 with open(args.kobj_size_output, "w") as fp:
1013 write_kobj_size_output(fp)
1014
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001015
Andrew Boie945af952017-08-22 13:15:23 -07001016if __name__ == "__main__":
1017 main()