blob: 0a3ae690f0580ccc5080c46cdb4d2d5da28a9efe [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):
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700178 self.addr = addr
179 self.type_obj = type_obj
180
181 # Type name determined later since drivers needs to look at the
182 # API struct address
183 self.type_name = None
Andrew Boie8ce260d2020-04-24 16:24:46 -0700184 self.data = 0
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700185
186
187class KobjectType:
188 def __init__(self, offset, name, size, api=False):
189 self.name = name
190 self.size = size
191 self.offset = offset
192 self.api = api
193
194 def __repr__(self):
195 return "<kobject %s>" % self.name
196
197 @staticmethod
198 def has_kobject():
199 return True
200
201 def get_kobjects(self, addr):
202 return {addr: KobjectInstance(self, addr)}
203
204
205class ArrayType:
206 def __init__(self, offset, elements, member_type):
207 self.elements = elements
208 self.member_type = member_type
209 self.offset = offset
210
211 def __repr__(self):
212 return "<array of %d>" % self.member_type
213
214 def has_kobject(self):
215 if self.member_type not in type_env:
216 return False
217
218 return type_env[self.member_type].has_kobject()
219
220 def get_kobjects(self, addr):
221 mt = type_env[self.member_type]
222
223 # Stacks are arrays of _k_stack_element_t but we want to treat
224 # the whole array as one kernel object (a thread stack)
225 # Data value gets set to size of entire region
226 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
227 # An array of stacks appears as a multi-dimensional array.
228 # The last size is the size of each stack. We need to track
229 # each stack within the array, not as one huge stack object.
230 *dimensions, stacksize = self.elements
231 num_members = 1
232 for e in dimensions:
233 num_members = num_members * e
234
235 ret = {}
236 for i in range(num_members):
237 a = addr + (i * stacksize)
238 o = mt.get_kobjects(a)
239 o[a].data = stacksize
240 ret.update(o)
241 return ret
242
243 objs = {}
244
245 # Multidimensional array flattened out
246 num_members = 1
247 for e in self.elements:
248 num_members = num_members * e
249
250 for i in range(num_members):
251 objs.update(mt.get_kobjects(addr + (i * mt.size)))
252 return objs
253
254
255class AggregateTypeMember:
256 def __init__(self, offset, member_name, member_type, member_offset):
257 self.member_name = member_name
258 self.member_type = member_type
259 if isinstance(member_offset, list):
260 # DWARF v2, location encoded as set of operations
261 # only "DW_OP_plus_uconst" with ULEB128 argument supported
262 if member_offset[0] == 0x23:
263 self.member_offset = member_offset[1] & 0x7f
264 for i in range(1, len(member_offset)-1):
265 if member_offset[i] & 0x80:
266 self.member_offset += (
267 member_offset[i+1] & 0x7f) << i*7
268 else:
269 raise Exception("not yet supported location operation (%s:%d:%d)" %
270 (self.member_name, self.member_type, member_offset[0]))
271 else:
272 self.member_offset = member_offset
273
274 def __repr__(self):
275 return "<member %s, type %d, offset %d>" % (
276 self.member_name, self.member_type, self.member_offset)
277
278 def has_kobject(self):
279 if self.member_type not in type_env:
280 return False
281
282 return type_env[self.member_type].has_kobject()
283
284 def get_kobjects(self, addr):
285 mt = type_env[self.member_type]
286 return mt.get_kobjects(addr + self.member_offset)
287
288
289class ConstType:
290 def __init__(self, child_type):
291 self.child_type = child_type
292
293 def __repr__(self):
294 return "<const %d>" % self.child_type
295
296 def has_kobject(self):
297 if self.child_type not in type_env:
298 return False
299
300 return type_env[self.child_type].has_kobject()
301
302 def get_kobjects(self, addr):
303 return type_env[self.child_type].get_kobjects(addr)
304
305
306class AggregateType:
307 def __init__(self, offset, name, size):
308 self.name = name
309 self.size = size
310 self.offset = offset
311 self.members = []
312
313 def add_member(self, member):
314 self.members.append(member)
315
316 def __repr__(self):
317 return "<struct %s, with %s>" % (self.name, self.members)
318
319 def has_kobject(self):
320 result = False
321
322 bad_members = []
323
324 for member in self.members:
325 if member.has_kobject():
326 result = True
327 else:
328 bad_members.append(member)
329 # Don't need to consider this again, just remove it
330
331 for bad_member in bad_members:
332 self.members.remove(bad_member)
333
334 return result
335
336 def get_kobjects(self, addr):
337 objs = {}
338 for member in self.members:
339 objs.update(member.get_kobjects(addr))
340 return objs
341
342
343# --- helper functions for getting data from DIEs ---
344
345def die_get_spec(die):
346 if 'DW_AT_specification' not in die.attributes:
347 return None
348
349 spec_val = die.attributes["DW_AT_specification"].value
350
351 # offset of the DW_TAG_variable for the extern declaration
352 offset = spec_val + die.cu.cu_offset
353
354 return extern_env.get(offset)
355
356
357def die_get_name(die):
358 if 'DW_AT_name' not in die.attributes:
359 die = die_get_spec(die)
360 if not die:
361 return None
362
363 return die.attributes["DW_AT_name"].value.decode("utf-8")
364
365
366def die_get_type_offset(die):
367 if 'DW_AT_type' not in die.attributes:
368 die = die_get_spec(die)
369 if not die:
370 return None
371
372 return die.attributes["DW_AT_type"].value + die.cu.cu_offset
373
374
375def die_get_byte_size(die):
376 if 'DW_AT_byte_size' not in die.attributes:
377 return 0
378
379 return die.attributes["DW_AT_byte_size"].value
380
381
382def analyze_die_struct(die):
383 name = die_get_name(die) or "<anon>"
384 offset = die.offset
385 size = die_get_byte_size(die)
386
387 # Incomplete type
388 if not size:
389 return
390
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700391 if name in kobjects:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700392 type_env[offset] = KobjectType(offset, name, size)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700393 elif name in subsystems:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700394 type_env[offset] = KobjectType(offset, name, size, api=True)
Andrew Boie299ec8f2020-05-29 13:30:19 -0700395 elif name in net_sockets:
396 type_env[offset] = KobjectType(offset, "NET_SOCKET", size)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700397 else:
398 at = AggregateType(offset, name, size)
399 type_env[offset] = at
400
401 for child in die.iter_children():
402 if child.tag != "DW_TAG_member":
403 continue
404 data_member_location = child.attributes.get("DW_AT_data_member_location")
405 if not data_member_location:
406 continue
407
408 child_type = die_get_type_offset(child)
409 member_offset = data_member_location.value
410 cname = die_get_name(child) or "<anon>"
411 m = AggregateTypeMember(child.offset, cname, child_type,
412 member_offset)
413 at.add_member(m)
414
415 return
416
417
418def analyze_die_const(die):
419 type_offset = die_get_type_offset(die)
420 if not type_offset:
421 return
422
423 type_env[die.offset] = ConstType(type_offset)
424
425
426def analyze_die_array(die):
427 type_offset = die_get_type_offset(die)
428 elements = []
429
430 for child in die.iter_children():
431 if child.tag != "DW_TAG_subrange_type":
432 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700433
Wayne Ren938642c2020-07-21 16:52:09 +0800434 if "DW_AT_upper_bound" in child.attributes:
435 ub = child.attributes["DW_AT_upper_bound"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700436
Wayne Ren938642c2020-07-21 16:52:09 +0800437 if not ub.form.startswith("DW_FORM_data"):
438 continue
439
440 elements.append(ub.value + 1)
441 # in DWARF 4, e.g. ARC Metaware toolchain, DW_AT_count is used
442 # not DW_AT_upper_bound
443 elif "DW_AT_count" in child.attributes:
444 ub = child.attributes["DW_AT_count"]
445
446 if not ub.form.startswith("DW_FORM_data"):
447 continue
448
449 elements.append(ub.value)
450 else:
451 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700452
453 if not elements:
454 if type_offset in type_env.keys():
455 mt = type_env[type_offset]
456 if mt.has_kobject():
457 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
458 elements.append(1)
459 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
460 else:
461 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
462
463
464def analyze_typedef(die):
465 type_offset = die_get_type_offset(die)
466
467 if type_offset not in type_env.keys():
468 return
469
470 type_env[die.offset] = type_env[type_offset]
471
472
473def unpack_pointer(elf, data, offset):
474 endian_code = "<" if elf.little_endian else ">"
475 if elf.elfclass == 32:
476 size_code = "I"
477 size = 4
478 else:
479 size_code = "Q"
480 size = 8
481
482 return struct.unpack(endian_code + size_code,
483 data[offset:offset + size])[0]
484
485
486def addr_deref(elf, addr):
487 for section in elf.iter_sections():
488 start = section['sh_addr']
489 end = start + section['sh_size']
490
491 if start <= addr < end:
492 data = section.data()
493 offset = addr - start
494 return unpack_pointer(elf, data, offset)
495
496 return 0
497
498
499def device_get_api_addr(elf, addr):
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100500 # See include/device.h for a description of struct device
501 offset = 8 if elf.elfclass == 32 else 16
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700502 return addr_deref(elf, addr + offset)
503
504
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700505def find_kobjects(elf, syms):
Andrew Boie8ce260d2020-04-24 16:24:46 -0700506 global thread_counter
507 global sys_mutex_counter
508 global futex_counter
509 global stack_counter
510
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700511 if not elf.has_dwarf_info():
512 sys.exit("ELF file has no DWARF information")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700513
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700514 app_smem_start = syms["_app_smem_start"]
515 app_smem_end = syms["_app_smem_end"]
Andrew Boie8ce260d2020-04-24 16:24:46 -0700516 user_stack_start = syms["z_user_stacks_start"]
517 user_stack_end = syms["z_user_stacks_end"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700518
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700519 di = elf.get_dwarf_info()
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700520
Wentong Wu0bf51132020-05-21 16:49:28 +0800521 variables = []
522
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700523 # Step 1: collect all type information.
524 for CU in di.iter_CUs():
525 for die in CU.iter_DIEs():
526 # Unions are disregarded, kernel objects should never be union
527 # members since the memory is not dedicated to that object and
528 # could be something else
529 if die.tag == "DW_TAG_structure_type":
530 analyze_die_struct(die)
531 elif die.tag == "DW_TAG_const_type":
532 analyze_die_const(die)
533 elif die.tag == "DW_TAG_array_type":
534 analyze_die_array(die)
535 elif die.tag == "DW_TAG_typedef":
536 analyze_typedef(die)
537 elif die.tag == "DW_TAG_variable":
538 variables.append(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700539
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700540 # Step 2: filter type_env to only contain kernel objects, or structs
541 # and arrays of kernel objects
542 bad_offsets = []
543 for offset, type_object in type_env.items():
544 if not type_object.has_kobject():
545 bad_offsets.append(offset)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700546
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700547 for offset in bad_offsets:
548 del type_env[offset]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700549
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700550 # Step 3: Now that we know all the types we are looking for, examine
551 # all variables
552 all_objs = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700553
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700554 for die in variables:
555 name = die_get_name(die)
556 if not name:
557 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700558
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100559 if name.startswith("__init_sys_init"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700560 # Boot-time initialization function; not an actual device
561 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700562
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700563 type_offset = die_get_type_offset(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700564
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700565 # Is this a kernel object, or a structure containing kernel
566 # objects?
567 if type_offset not in type_env:
568 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700569
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700570 if "DW_AT_declaration" in die.attributes:
571 # Extern declaration, only used indirectly
572 extern_env[die.offset] = die
573 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700574
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700575 if "DW_AT_location" not in die.attributes:
576 debug_die(die,
577 "No location information for object '%s'; possibly stack allocated"
578 % name)
579 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700580
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700581 loc = die.attributes["DW_AT_location"]
582 if loc.form != "DW_FORM_exprloc" and \
583 loc.form != "DW_FORM_block1":
584 debug_die(die, "kernel object '%s' unexpected location format" %
585 name)
586 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700587
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700588 opcode = loc.value[0]
589 if opcode != DW_OP_addr:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700590
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700591 # Check if frame pointer offset DW_OP_fbreg
592 if opcode == DW_OP_fbreg:
593 debug_die(die, "kernel object '%s' found on stack" % name)
594 else:
595 debug_die(die,
596 "kernel object '%s' unexpected exprloc opcode %s" %
597 (name, hex(opcode)))
598 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700599
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700600 addr = (loc.value[1] | (loc.value[2] << 8) |
601 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700602
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700603 if addr == 0:
604 # Never linked; gc-sections deleted it
605 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700606
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700607 type_obj = type_env[type_offset]
608 objs = type_obj.get_kobjects(addr)
609 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700610
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700611 debug("symbol '%s' at %s contains %d object(s)"
612 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700613
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700614 # Step 4: objs is a dictionary mapping variable memory addresses to
615 # their associated type objects. Now that we have seen all variables
616 # and can properly look up API structs, convert this into a dictionary
617 # mapping variables to the C enumeration of what kernel object type it
618 # is.
619 ret = {}
620 for addr, ko in all_objs.items():
621 # API structs don't get into the gperf table
622 if ko.type_obj.api:
623 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700624
Andrew Boie455e1782020-05-29 13:22:20 -0700625 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700626 if not user_ram_allowed and app_smem_start <= addr < app_smem_end:
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800627 debug("object '%s' found in invalid location %s"
628 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700629 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700630
Andrew Boie8ce260d2020-04-24 16:24:46 -0700631 if (ko.type_obj.name == STACK_TYPE and
632 (addr < user_stack_start or addr >= user_stack_end)):
633 debug("skip kernel-only stack at %s" % hex(addr))
634 continue
635
636 # At this point we know the object will be included in the gperf table
637 if ko.type_obj.name == "k_thread":
638 # Assign an ID for this thread object, used to track its
639 # permissions to other kernel objects
640 ko.data = thread_counter
641 thread_counter = thread_counter + 1
642 elif ko.type_obj.name == "sys_mutex":
643 ko.data = "&kernel_mutexes[%d]" % sys_mutex_counter
644 sys_mutex_counter += 1
645 elif ko.type_obj.name == "k_futex":
646 ko.data = "&futex_data[%d]" % futex_counter
647 futex_counter += 1
648 elif ko.type_obj.name == STACK_TYPE:
649 stack_counter += 1
650
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700651 if ko.type_obj.name != "device":
652 # Not a device struct so we immediately know its type
653 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700654 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700655 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700656
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700657 # Device struct. Need to get the address of its API struct,
658 # if it has one.
659 apiaddr = device_get_api_addr(elf, addr)
660 if apiaddr not in all_objs:
661 if apiaddr == 0:
662 debug("device instance at 0x%x has no associated subsystem"
663 % addr)
664 else:
665 debug("device instance at 0x%x has unknown API 0x%x"
666 % (addr, apiaddr))
667 # API struct does not correspond to a known subsystem, skip it
668 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700669
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700670 apiobj = all_objs[apiaddr]
671 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
672 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700673
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700674 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700675
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700676 # 1. Before python 3.7 dict order is not guaranteed. With Python
677 # 3.5 it doesn't seem random with *integer* keys but can't
678 # rely on that.
679 # 2. OrderedDict means _insertion_ order, so not enough because
680 # built from other (random!) dicts: need to _sort_ first.
681 # 3. Sorting memory address looks good.
682 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700683
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700684def get_symbols(elf):
685 for section in elf.iter_sections():
686 if isinstance(section, SymbolTableSection):
687 return {sym.name: sym.entry.st_value
688 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700689
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700690 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700691
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700692
693# -- GPERF generation logic
694
Andrew Boie945af952017-08-22 13:15:23 -0700695header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700696%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700697%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700698%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700699%struct-type
700%{
701#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800702#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700703#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700704#include <string.h>
705%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700706struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700707"""
708
Andy Gross6042ae92018-01-22 14:26:49 -0600709# Different versions of gperf have different prototypes for the lookup
710# function, best to implement the wrapper here. The pointer value itself is
711# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500712# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700713footer = """%%
Peter Bigot2fcf7622020-05-14 05:06:08 -0500714struct z_object *z_object_gperf_find(const void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700715{
Patrik Flykt4344e272019-03-08 14:19:05 -0700716 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700717}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700718
Patrik Flykt4344e272019-03-08 14:19:05 -0700719void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700720{
721 int i;
722
723 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700724 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700725 func(&wordlist[i], context);
726 }
727 }
728}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800729
730#ifndef CONFIG_DYNAMIC_OBJECTS
Peter Bigot2fcf7622020-05-14 05:06:08 -0500731struct z_object *z_object_find(const void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700732 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800733
Patrik Flykt4344e272019-03-08 14:19:05 -0700734void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
735 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800736#endif
Andrew Boie945af952017-08-22 13:15:23 -0700737"""
738
739
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700740def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700741 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700742 if sys_mutex_counter != 0:
743 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
744 % sys_mutex_counter)
745 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400746 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700747 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700748 fp.write(", ")
749 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700750
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700751 if futex_counter != 0:
752 fp.write("static struct z_futex_data futex_data[%d] = {\n"
753 % futex_counter)
754 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800755 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700756 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800757 fp.write(", ")
758 fp.write("};\n")
759
Andrew Boie28be7932020-03-11 10:56:19 -0700760 metadata_names = {
761 "K_OBJ_THREAD" : "thread_id",
762 "K_OBJ_SYS_MUTEX" : "mutex",
763 "K_OBJ_FUTEX" : "futex_data"
764 }
765
766 if "CONFIG_GEN_PRIV_STACKS" in syms:
767 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700768 if stack_counter != 0:
Andrew Boie8ce260d2020-04-24 16:24:46 -0700769 # Same as K_KERNEL_STACK_ARRAY_DEFINE, but routed to a different
770 # memory section.
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500771 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie8ce260d2020-04-24 16:24:46 -0700772 " __aligned(Z_KERNEL_STACK_OBJ_ALIGN)"
773 " priv_stacks[%d][Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700774 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700775
776 fp.write("static struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700777 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700778 counter = 0
779 for _, ko in objs.items():
780 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
781 continue
782
783 # ko.data currently has the stack size. fetch the value to
784 # populate the appropriate entry in stack_data, and put
785 # a reference to the entry in stack_data into the data value
786 # instead
787 size = ko.data
788 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500789 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700790 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700791 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700792 fp.write(",")
793 fp.write("\n")
794 counter += 1
795 fp.write("};\n")
796 else:
797 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
798
Andrew Boief0835672019-03-27 15:44:52 -0700799 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700800 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700801 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
802 thread_idx_map = {}
803
804 for i in range(0, thread_max_bytes):
805 thread_idx_map[i] = 0xFF
806
Andrew Boiebca15da2017-10-15 14:17:48 -0700807 for obj_addr, ko in objs.items():
808 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700809 # pre-initialized objects fall within this memory range, they are
810 # either completely initialized at build time, or done automatically
811 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200812 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700813 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700814
Andrew Boief290ab52019-11-18 17:06:13 -0800815 if "CONFIG_64BIT" in syms:
816 format_code = "Q"
817 else:
818 format_code = "I"
819
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700820 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800821 endian = "<"
822 else:
823 endian = ">"
824
825 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700826 fp.write("\"")
827 for byte in byte_str:
828 val = "\\x%02x" % byte
829 fp.write(val)
830
Andrew Boie78757072019-07-23 13:29:30 -0700831 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200832 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700833 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200834 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700835 flags += " | K_OBJ_FLAG_DRIVER"
836
Andrew Boief2734ab2020-03-11 06:37:42 -0700837 if ko.type_name in metadata_names:
838 tname = metadata_names[ko.type_name]
839 else:
840 tname = "unused"
841
842 fp.write("\", {}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
843 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700844
Daniel Leunge58b6542018-08-08 11:23:16 -0700845 if obj_type == "K_OBJ_THREAD":
846 idx = math.floor(ko.data / 8)
847 bit = ko.data % 8
848 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
849
Andrew Boie945af952017-08-22 13:15:23 -0700850 fp.write(footer)
851
Daniel Leunge58b6542018-08-08 11:23:16 -0700852 # Generate the array of already mapped thread indexes
853 fp.write('\n')
Andrew Boie9b34ecd2020-01-08 17:37:11 -0800854 fp.write('Z_GENERIC_SECTION(.kobject_data.data) ')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500855 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700856
857 for i in range(0, thread_max_bytes):
858 fp.write(' 0x%x, ' % (thread_idx_map[i]))
859
860 fp.write('};\n')
861
Andrew Boie945af952017-08-22 13:15:23 -0700862
Leandro Pereirac2003672018-04-04 13:50:32 -0700863driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700864#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 -0700865"""
866
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500867
Leandro Pereirac2003672018-04-04 13:50:32 -0700868def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700869 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
870 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700871
Andrew Boie8345e5e2018-05-04 15:57:57 -0700872 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
873 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
874 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
875 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700876
877 for subsystem in subsystems:
878 subsystem = subsystem.replace("_driver_api", "")
879
880 fp.write(driver_macro_tpl % {
881 "driver_lower": subsystem.lower(),
882 "driver_upper": subsystem.upper(),
883 })
884
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700885 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700886
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700887
888def write_kobj_types_output(fp):
889 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700890 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700891 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700892 if kobj == "device":
893 continue
894
Andrew Boie09c22cc2018-06-27 10:25:45 -0700895 if dep:
896 fp.write("#ifdef %s\n" % dep)
897
Andrew Boief20efcf2018-05-23 10:57:39 -0700898 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700899
Andrew Boie09c22cc2018-06-27 10:25:45 -0700900 if dep:
901 fp.write("#endif\n")
902
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700903 fp.write("/* Driver subsystems */\n")
904 for subsystem in subsystems:
905 subsystem = subsystem.replace("_driver_api", "").upper()
906 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
907
908
909def write_kobj_otype_output(fp):
910 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700911 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700912 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700913 if kobj == "device":
914 continue
915
Andrew Boie09c22cc2018-06-27 10:25:45 -0700916 if dep:
917 fp.write("#ifdef %s\n" % dep)
918
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500919 fp.write('case %s: ret = "%s"; break;\n' %
920 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700921 if dep:
922 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700923
924 fp.write("/* Driver subsystems */\n")
925 for subsystem in subsystems:
926 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700927 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700928 subsystem.upper(),
929 subsystem
930 ))
931
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500932
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700933def write_kobj_size_output(fp):
934 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700935 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700936 dep, _, alloc = obj_info
937
938 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700939 continue
940
Andrew Boie09c22cc2018-06-27 10:25:45 -0700941 if dep:
942 fp.write("#ifdef %s\n" % dep)
943
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700944 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500945 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700946 if dep:
947 fp.write("#endif\n")
948
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700949
Corey Whartonccd15df2020-02-29 14:51:42 -0800950def parse_subsystems_list_file(path):
951 with open(path, "r") as fp:
952 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700953 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700954 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800955
Andrew Boie945af952017-08-22 13:15:23 -0700956def parse_args():
957 global args
958
Anas Nashif72565532017-12-12 08:19:25 -0500959 parser = argparse.ArgumentParser(
960 description=__doc__,
961 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700962
Leandro Pereirac2003672018-04-04 13:50:32 -0700963 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500964 help="Input zephyr ELF binary")
965 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700966 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500967 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700968 parser.add_argument(
969 "-V", "--validation-output", required=False,
970 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700971 parser.add_argument(
972 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700973 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700974 parser.add_argument(
975 "-S", "--kobj-otype-output", required=False,
976 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700977 parser.add_argument(
978 "-Z", "--kobj-size-output", required=False,
979 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -0800980 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
981 help='''Specifies a file with a JSON encoded list of subsystem names to append to
982 the driver subsystems list. Can be specified multiple times:
983 -i file1 -i file2 ...''')
984
Andrew Boie945af952017-08-22 13:15:23 -0700985 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500986 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700987 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100988 if "VERBOSE" in os.environ:
989 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700990
991
992def main():
993 parse_args()
994
Corey Whartonccd15df2020-02-29 14:51:42 -0800995 if args.include_subsystem_list is not None:
996 for list_file in args.include_subsystem_list:
997 parse_subsystems_list_file(list_file)
998
Leandro Pereirac2003672018-04-04 13:50:32 -0700999 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -08001000 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001001 elf = ELFFile(open(args.kernel, "rb"))
1002 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -07001003 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001004 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -08001005 if not objs:
1006 sys.stderr.write("WARNING: zero kobject found in %s\n"
1007 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -07001008
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001009 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +02001010 sys.exit("Too many thread objects ({})\n"
1011 "Increase CONFIG_MAX_THREAD_BYTES to {}"
1012 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -07001013
Leandro Pereirac2003672018-04-04 13:50:32 -07001014 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001015 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -07001016 syms["_static_kernel_objects_begin"],
1017 syms["_static_kernel_objects_end"])
1018
1019 if args.validation_output:
1020 with open(args.validation_output, "w") as fp:
1021 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001022
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001023 if args.kobj_types_output:
1024 with open(args.kobj_types_output, "w") as fp:
1025 write_kobj_types_output(fp)
1026
1027 if args.kobj_otype_output:
1028 with open(args.kobj_otype_output, "w") as fp:
1029 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001030
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001031 if args.kobj_size_output:
1032 with open(args.kobj_size_output, "w") as fp:
1033 write_kobj_size_output(fp)
1034
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001035
Andrew Boie945af952017-08-22 13:15:23 -07001036if __name__ == "__main__":
1037 main()