blob: a1f18df14e7e7b8ebf84ed2a99c7a63df1aab0d3 [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)),
Anas Nashif989ebf62020-11-27 11:30:45 -0500108 ("k_futex", (None, True, False)),
109 ("k_condvar", (None, False, True))
Marc Herbertf78288b2019-03-05 14:31:44 -0800110])
111
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700112def kobject_to_enum(kobj):
113 if kobj.startswith("k_") or kobj.startswith("z_"):
114 name = kobj[2:]
115 else:
116 name = kobj
117
118 return "K_OBJ_%s" % name.upper()
119
Andrew Boie5bd891d2017-09-27 12:59:28 -0700120subsystems = [
Corey Wharton86bfc482020-03-04 13:32:01 -0800121 # Editing the list is deprecated, add the __subsystem sentinal to your driver
122 # api declaration instead. e.x.
123 #
124 # __subsystem struct my_driver_api {
125 # ....
126 #};
Andrew Boie6f928092019-04-23 13:06:59 -0700127]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700128
Andrew Boie299ec8f2020-05-29 13:30:19 -0700129# Names of all structs tagged with __net_socket, found by parse_syscalls.py
130net_sockets = [ ]
131
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700132def subsystem_to_enum(subsys):
133 return "K_OBJ_DRIVER_" + subsys[:-11].upper()
134
135# --- debug stuff ---
136
137scr = os.path.basename(sys.argv[0])
138
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700139def debug(text):
140 if not args.verbose:
141 return
142 sys.stdout.write(scr + ": " + text + "\n")
143
144def error(text):
145 sys.exit("%s ERROR: %s" % (scr, text))
146
147def debug_die(die, text):
148 lp_header = die.dwarfinfo.line_program_for_CU(die.cu).header
149 files = lp_header["file_entry"]
150 includes = lp_header["include_directory"]
151
152 fileinfo = files[die.attributes["DW_AT_decl_file"].value - 1]
153 filename = fileinfo.name.decode("utf-8")
154 filedir = includes[fileinfo.dir_index - 1].decode("utf-8")
155
156 path = os.path.join(filedir, filename)
157 lineno = die.attributes["DW_AT_decl_line"].value
158
159 debug(str(die))
160 debug("File '%s', line %d:" % (path, lineno))
161 debug(" %s" % text)
162
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700163# -- ELF processing
164
165DW_OP_addr = 0x3
166DW_OP_fbreg = 0x91
167STACK_TYPE = "z_thread_stack_element"
168thread_counter = 0
169sys_mutex_counter = 0
170futex_counter = 0
171stack_counter = 0
172
173# Global type environment. Populated by pass 1.
174type_env = {}
175extern_env = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700176
177class KobjectInstance:
178 def __init__(self, type_obj, addr):
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700179 self.addr = addr
180 self.type_obj = type_obj
181
182 # Type name determined later since drivers needs to look at the
183 # API struct address
184 self.type_name = None
Andrew Boie8ce260d2020-04-24 16:24:46 -0700185 self.data = 0
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700186
187
188class KobjectType:
189 def __init__(self, offset, name, size, api=False):
190 self.name = name
191 self.size = size
192 self.offset = offset
193 self.api = api
194
195 def __repr__(self):
196 return "<kobject %s>" % self.name
197
198 @staticmethod
199 def has_kobject():
200 return True
201
202 def get_kobjects(self, addr):
203 return {addr: KobjectInstance(self, addr)}
204
205
206class ArrayType:
207 def __init__(self, offset, elements, member_type):
208 self.elements = elements
209 self.member_type = member_type
210 self.offset = offset
211
212 def __repr__(self):
213 return "<array of %d>" % self.member_type
214
215 def has_kobject(self):
216 if self.member_type not in type_env:
217 return False
218
219 return type_env[self.member_type].has_kobject()
220
221 def get_kobjects(self, addr):
222 mt = type_env[self.member_type]
223
224 # Stacks are arrays of _k_stack_element_t but we want to treat
225 # the whole array as one kernel object (a thread stack)
226 # Data value gets set to size of entire region
227 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
228 # An array of stacks appears as a multi-dimensional array.
229 # The last size is the size of each stack. We need to track
230 # each stack within the array, not as one huge stack object.
231 *dimensions, stacksize = self.elements
232 num_members = 1
233 for e in dimensions:
234 num_members = num_members * e
235
236 ret = {}
237 for i in range(num_members):
238 a = addr + (i * stacksize)
239 o = mt.get_kobjects(a)
240 o[a].data = stacksize
241 ret.update(o)
242 return ret
243
244 objs = {}
245
246 # Multidimensional array flattened out
247 num_members = 1
248 for e in self.elements:
249 num_members = num_members * e
250
251 for i in range(num_members):
252 objs.update(mt.get_kobjects(addr + (i * mt.size)))
253 return objs
254
255
256class AggregateTypeMember:
257 def __init__(self, offset, member_name, member_type, member_offset):
258 self.member_name = member_name
259 self.member_type = member_type
260 if isinstance(member_offset, list):
261 # DWARF v2, location encoded as set of operations
262 # only "DW_OP_plus_uconst" with ULEB128 argument supported
263 if member_offset[0] == 0x23:
264 self.member_offset = member_offset[1] & 0x7f
265 for i in range(1, len(member_offset)-1):
266 if member_offset[i] & 0x80:
267 self.member_offset += (
268 member_offset[i+1] & 0x7f) << i*7
269 else:
270 raise Exception("not yet supported location operation (%s:%d:%d)" %
271 (self.member_name, self.member_type, member_offset[0]))
272 else:
273 self.member_offset = member_offset
274
275 def __repr__(self):
276 return "<member %s, type %d, offset %d>" % (
277 self.member_name, self.member_type, self.member_offset)
278
279 def has_kobject(self):
280 if self.member_type not in type_env:
281 return False
282
283 return type_env[self.member_type].has_kobject()
284
285 def get_kobjects(self, addr):
286 mt = type_env[self.member_type]
287 return mt.get_kobjects(addr + self.member_offset)
288
289
290class ConstType:
291 def __init__(self, child_type):
292 self.child_type = child_type
293
294 def __repr__(self):
295 return "<const %d>" % self.child_type
296
297 def has_kobject(self):
298 if self.child_type not in type_env:
299 return False
300
301 return type_env[self.child_type].has_kobject()
302
303 def get_kobjects(self, addr):
304 return type_env[self.child_type].get_kobjects(addr)
305
306
307class AggregateType:
308 def __init__(self, offset, name, size):
309 self.name = name
310 self.size = size
311 self.offset = offset
312 self.members = []
313
314 def add_member(self, member):
315 self.members.append(member)
316
317 def __repr__(self):
318 return "<struct %s, with %s>" % (self.name, self.members)
319
320 def has_kobject(self):
321 result = False
322
323 bad_members = []
324
325 for member in self.members:
326 if member.has_kobject():
327 result = True
328 else:
329 bad_members.append(member)
330 # Don't need to consider this again, just remove it
331
332 for bad_member in bad_members:
333 self.members.remove(bad_member)
334
335 return result
336
337 def get_kobjects(self, addr):
338 objs = {}
339 for member in self.members:
340 objs.update(member.get_kobjects(addr))
341 return objs
342
343
344# --- helper functions for getting data from DIEs ---
345
346def die_get_spec(die):
347 if 'DW_AT_specification' not in die.attributes:
348 return None
349
350 spec_val = die.attributes["DW_AT_specification"].value
351
352 # offset of the DW_TAG_variable for the extern declaration
353 offset = spec_val + die.cu.cu_offset
354
355 return extern_env.get(offset)
356
357
358def die_get_name(die):
359 if 'DW_AT_name' not in die.attributes:
360 die = die_get_spec(die)
361 if not die:
362 return None
363
364 return die.attributes["DW_AT_name"].value.decode("utf-8")
365
366
367def die_get_type_offset(die):
368 if 'DW_AT_type' not in die.attributes:
369 die = die_get_spec(die)
370 if not die:
371 return None
372
373 return die.attributes["DW_AT_type"].value + die.cu.cu_offset
374
375
376def die_get_byte_size(die):
377 if 'DW_AT_byte_size' not in die.attributes:
378 return 0
379
380 return die.attributes["DW_AT_byte_size"].value
381
382
383def analyze_die_struct(die):
384 name = die_get_name(die) or "<anon>"
385 offset = die.offset
386 size = die_get_byte_size(die)
387
388 # Incomplete type
389 if not size:
390 return
391
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700392 if name in kobjects:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700393 type_env[offset] = KobjectType(offset, name, size)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700394 elif name in subsystems:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700395 type_env[offset] = KobjectType(offset, name, size, api=True)
Andrew Boie299ec8f2020-05-29 13:30:19 -0700396 elif name in net_sockets:
397 type_env[offset] = KobjectType(offset, "NET_SOCKET", size)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700398 else:
399 at = AggregateType(offset, name, size)
400 type_env[offset] = at
401
402 for child in die.iter_children():
403 if child.tag != "DW_TAG_member":
404 continue
405 data_member_location = child.attributes.get("DW_AT_data_member_location")
406 if not data_member_location:
407 continue
408
409 child_type = die_get_type_offset(child)
410 member_offset = data_member_location.value
411 cname = die_get_name(child) or "<anon>"
412 m = AggregateTypeMember(child.offset, cname, child_type,
413 member_offset)
414 at.add_member(m)
415
416 return
417
418
419def analyze_die_const(die):
420 type_offset = die_get_type_offset(die)
421 if not type_offset:
422 return
423
424 type_env[die.offset] = ConstType(type_offset)
425
426
427def analyze_die_array(die):
428 type_offset = die_get_type_offset(die)
429 elements = []
430
431 for child in die.iter_children():
432 if child.tag != "DW_TAG_subrange_type":
433 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700434
Wayne Ren938642c2020-07-21 16:52:09 +0800435 if "DW_AT_upper_bound" in child.attributes:
436 ub = child.attributes["DW_AT_upper_bound"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700437
Wayne Ren938642c2020-07-21 16:52:09 +0800438 if not ub.form.startswith("DW_FORM_data"):
439 continue
440
441 elements.append(ub.value + 1)
442 # in DWARF 4, e.g. ARC Metaware toolchain, DW_AT_count is used
443 # not DW_AT_upper_bound
444 elif "DW_AT_count" in child.attributes:
445 ub = child.attributes["DW_AT_count"]
446
447 if not ub.form.startswith("DW_FORM_data"):
448 continue
449
450 elements.append(ub.value)
451 else:
452 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700453
454 if not elements:
455 if type_offset in type_env.keys():
456 mt = type_env[type_offset]
457 if mt.has_kobject():
458 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
459 elements.append(1)
460 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
461 else:
462 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
463
464
465def analyze_typedef(die):
466 type_offset = die_get_type_offset(die)
467
468 if type_offset not in type_env.keys():
469 return
470
471 type_env[die.offset] = type_env[type_offset]
472
473
474def unpack_pointer(elf, data, offset):
475 endian_code = "<" if elf.little_endian else ">"
476 if elf.elfclass == 32:
477 size_code = "I"
478 size = 4
479 else:
480 size_code = "Q"
481 size = 8
482
483 return struct.unpack(endian_code + size_code,
484 data[offset:offset + size])[0]
485
486
487def addr_deref(elf, addr):
488 for section in elf.iter_sections():
489 start = section['sh_addr']
490 end = start + section['sh_size']
491
492 if start <= addr < end:
493 data = section.data()
494 offset = addr - start
495 return unpack_pointer(elf, data, offset)
496
497 return 0
498
499
500def device_get_api_addr(elf, addr):
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100501 # See include/device.h for a description of struct device
502 offset = 8 if elf.elfclass == 32 else 16
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700503 return addr_deref(elf, addr + offset)
504
505
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700506def find_kobjects(elf, syms):
Andrew Boie8ce260d2020-04-24 16:24:46 -0700507 global thread_counter
508 global sys_mutex_counter
509 global futex_counter
510 global stack_counter
511
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700512 if not elf.has_dwarf_info():
513 sys.exit("ELF file has no DWARF information")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700514
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700515 app_smem_start = syms["_app_smem_start"]
516 app_smem_end = syms["_app_smem_end"]
Andrew Boie8ce260d2020-04-24 16:24:46 -0700517 user_stack_start = syms["z_user_stacks_start"]
518 user_stack_end = syms["z_user_stacks_end"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700519
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700520 di = elf.get_dwarf_info()
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700521
Wentong Wu0bf51132020-05-21 16:49:28 +0800522 variables = []
523
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700524 # Step 1: collect all type information.
525 for CU in di.iter_CUs():
526 for die in CU.iter_DIEs():
527 # Unions are disregarded, kernel objects should never be union
528 # members since the memory is not dedicated to that object and
529 # could be something else
530 if die.tag == "DW_TAG_structure_type":
531 analyze_die_struct(die)
532 elif die.tag == "DW_TAG_const_type":
533 analyze_die_const(die)
534 elif die.tag == "DW_TAG_array_type":
535 analyze_die_array(die)
536 elif die.tag == "DW_TAG_typedef":
537 analyze_typedef(die)
538 elif die.tag == "DW_TAG_variable":
539 variables.append(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700540
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700541 # Step 2: filter type_env to only contain kernel objects, or structs
542 # and arrays of kernel objects
543 bad_offsets = []
544 for offset, type_object in type_env.items():
545 if not type_object.has_kobject():
546 bad_offsets.append(offset)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700547
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700548 for offset in bad_offsets:
549 del type_env[offset]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700550
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700551 # Step 3: Now that we know all the types we are looking for, examine
552 # all variables
553 all_objs = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700554
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700555 for die in variables:
556 name = die_get_name(die)
557 if not name:
558 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700559
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100560 if name.startswith("__init_sys_init"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700561 # Boot-time initialization function; not an actual device
562 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700563
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700564 type_offset = die_get_type_offset(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700565
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700566 # Is this a kernel object, or a structure containing kernel
567 # objects?
568 if type_offset not in type_env:
569 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700570
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700571 if "DW_AT_declaration" in die.attributes:
572 # Extern declaration, only used indirectly
573 extern_env[die.offset] = die
574 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700575
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700576 if "DW_AT_location" not in die.attributes:
577 debug_die(die,
578 "No location information for object '%s'; possibly stack allocated"
579 % name)
580 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700581
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700582 loc = die.attributes["DW_AT_location"]
583 if loc.form != "DW_FORM_exprloc" and \
584 loc.form != "DW_FORM_block1":
585 debug_die(die, "kernel object '%s' unexpected location format" %
586 name)
587 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700588
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700589 opcode = loc.value[0]
590 if opcode != DW_OP_addr:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700591
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700592 # Check if frame pointer offset DW_OP_fbreg
593 if opcode == DW_OP_fbreg:
594 debug_die(die, "kernel object '%s' found on stack" % name)
595 else:
596 debug_die(die,
597 "kernel object '%s' unexpected exprloc opcode %s" %
598 (name, hex(opcode)))
599 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700600
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700601 addr = (loc.value[1] | (loc.value[2] << 8) |
602 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700603
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700604 if addr == 0:
605 # Never linked; gc-sections deleted it
606 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700607
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700608 type_obj = type_env[type_offset]
609 objs = type_obj.get_kobjects(addr)
610 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700611
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700612 debug("symbol '%s' at %s contains %d object(s)"
613 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700614
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700615 # Step 4: objs is a dictionary mapping variable memory addresses to
616 # their associated type objects. Now that we have seen all variables
617 # and can properly look up API structs, convert this into a dictionary
618 # mapping variables to the C enumeration of what kernel object type it
619 # is.
620 ret = {}
621 for addr, ko in all_objs.items():
622 # API structs don't get into the gperf table
623 if ko.type_obj.api:
624 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700625
Andrew Boie455e1782020-05-29 13:22:20 -0700626 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700627 if not user_ram_allowed and app_smem_start <= addr < app_smem_end:
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800628 debug("object '%s' found in invalid location %s"
629 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700630 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700631
Andrew Boie8ce260d2020-04-24 16:24:46 -0700632 if (ko.type_obj.name == STACK_TYPE and
633 (addr < user_stack_start or addr >= user_stack_end)):
634 debug("skip kernel-only stack at %s" % hex(addr))
635 continue
636
637 # At this point we know the object will be included in the gperf table
638 if ko.type_obj.name == "k_thread":
639 # Assign an ID for this thread object, used to track its
640 # permissions to other kernel objects
641 ko.data = thread_counter
642 thread_counter = thread_counter + 1
643 elif ko.type_obj.name == "sys_mutex":
644 ko.data = "&kernel_mutexes[%d]" % sys_mutex_counter
645 sys_mutex_counter += 1
646 elif ko.type_obj.name == "k_futex":
647 ko.data = "&futex_data[%d]" % futex_counter
648 futex_counter += 1
649 elif ko.type_obj.name == STACK_TYPE:
650 stack_counter += 1
651
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700652 if ko.type_obj.name != "device":
653 # Not a device struct so we immediately know its type
654 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700655 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700656 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700657
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700658 # Device struct. Need to get the address of its API struct,
659 # if it has one.
660 apiaddr = device_get_api_addr(elf, addr)
661 if apiaddr not in all_objs:
662 if apiaddr == 0:
663 debug("device instance at 0x%x has no associated subsystem"
664 % addr)
665 else:
666 debug("device instance at 0x%x has unknown API 0x%x"
667 % (addr, apiaddr))
668 # API struct does not correspond to a known subsystem, skip it
669 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700670
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700671 apiobj = all_objs[apiaddr]
672 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
673 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700674
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700675 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700676
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700677 # 1. Before python 3.7 dict order is not guaranteed. With Python
678 # 3.5 it doesn't seem random with *integer* keys but can't
679 # rely on that.
680 # 2. OrderedDict means _insertion_ order, so not enough because
681 # built from other (random!) dicts: need to _sort_ first.
682 # 3. Sorting memory address looks good.
683 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700684
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700685def get_symbols(elf):
686 for section in elf.iter_sections():
687 if isinstance(section, SymbolTableSection):
688 return {sym.name: sym.entry.st_value
689 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700690
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700691 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700692
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700693
694# -- GPERF generation logic
695
Andrew Boie945af952017-08-22 13:15:23 -0700696header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700697%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700698%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700699%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700700%struct-type
701%{
702#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800703#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700704#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700705#include <string.h>
706%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700707struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700708"""
709
Andy Gross6042ae92018-01-22 14:26:49 -0600710# Different versions of gperf have different prototypes for the lookup
711# function, best to implement the wrapper here. The pointer value itself is
712# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500713# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700714footer = """%%
Peter Bigot2fcf7622020-05-14 05:06:08 -0500715struct z_object *z_object_gperf_find(const void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700716{
Patrik Flykt4344e272019-03-08 14:19:05 -0700717 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700718}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700719
Patrik Flykt4344e272019-03-08 14:19:05 -0700720void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700721{
722 int i;
723
724 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700725 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700726 func(&wordlist[i], context);
727 }
728 }
729}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800730
731#ifndef CONFIG_DYNAMIC_OBJECTS
Peter Bigot2fcf7622020-05-14 05:06:08 -0500732struct z_object *z_object_find(const void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700733 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800734
Patrik Flykt4344e272019-03-08 14:19:05 -0700735void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
736 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800737#endif
Andrew Boie945af952017-08-22 13:15:23 -0700738"""
739
740
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700741def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700742 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700743 if sys_mutex_counter != 0:
744 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
745 % sys_mutex_counter)
746 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400747 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700748 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700749 fp.write(", ")
750 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700751
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700752 if futex_counter != 0:
753 fp.write("static struct z_futex_data futex_data[%d] = {\n"
754 % futex_counter)
755 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800756 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700757 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800758 fp.write(", ")
759 fp.write("};\n")
760
Andrew Boie28be7932020-03-11 10:56:19 -0700761 metadata_names = {
762 "K_OBJ_THREAD" : "thread_id",
763 "K_OBJ_SYS_MUTEX" : "mutex",
764 "K_OBJ_FUTEX" : "futex_data"
765 }
766
767 if "CONFIG_GEN_PRIV_STACKS" in syms:
768 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700769 if stack_counter != 0:
Andrew Boie8ce260d2020-04-24 16:24:46 -0700770 # Same as K_KERNEL_STACK_ARRAY_DEFINE, but routed to a different
771 # memory section.
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500772 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie8ce260d2020-04-24 16:24:46 -0700773 " __aligned(Z_KERNEL_STACK_OBJ_ALIGN)"
774 " priv_stacks[%d][Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700775 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700776
777 fp.write("static struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700778 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700779 counter = 0
780 for _, ko in objs.items():
781 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
782 continue
783
784 # ko.data currently has the stack size. fetch the value to
785 # populate the appropriate entry in stack_data, and put
786 # a reference to the entry in stack_data into the data value
787 # instead
788 size = ko.data
789 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500790 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700791 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700792 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700793 fp.write(",")
794 fp.write("\n")
795 counter += 1
796 fp.write("};\n")
797 else:
798 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
799
Andrew Boief0835672019-03-27 15:44:52 -0700800 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700801 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700802 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
803 thread_idx_map = {}
804
805 for i in range(0, thread_max_bytes):
806 thread_idx_map[i] = 0xFF
807
Andrew Boiebca15da2017-10-15 14:17:48 -0700808 for obj_addr, ko in objs.items():
809 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700810 # pre-initialized objects fall within this memory range, they are
811 # either completely initialized at build time, or done automatically
812 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200813 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700814 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700815
Andrew Boief290ab52019-11-18 17:06:13 -0800816 if "CONFIG_64BIT" in syms:
817 format_code = "Q"
818 else:
819 format_code = "I"
820
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700821 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800822 endian = "<"
823 else:
824 endian = ">"
825
826 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700827 fp.write("\"")
828 for byte in byte_str:
829 val = "\\x%02x" % byte
830 fp.write(val)
831
Andrew Boie78757072019-07-23 13:29:30 -0700832 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200833 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700834 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200835 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700836 flags += " | K_OBJ_FLAG_DRIVER"
837
Andrew Boief2734ab2020-03-11 06:37:42 -0700838 if ko.type_name in metadata_names:
839 tname = metadata_names[ko.type_name]
840 else:
841 tname = "unused"
842
843 fp.write("\", {}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
844 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700845
Daniel Leunge58b6542018-08-08 11:23:16 -0700846 if obj_type == "K_OBJ_THREAD":
847 idx = math.floor(ko.data / 8)
848 bit = ko.data % 8
849 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
850
Andrew Boie945af952017-08-22 13:15:23 -0700851 fp.write(footer)
852
Daniel Leunge58b6542018-08-08 11:23:16 -0700853 # Generate the array of already mapped thread indexes
854 fp.write('\n')
Andrew Boie9b34ecd2020-01-08 17:37:11 -0800855 fp.write('Z_GENERIC_SECTION(.kobject_data.data) ')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500856 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700857
858 for i in range(0, thread_max_bytes):
859 fp.write(' 0x%x, ' % (thread_idx_map[i]))
860
861 fp.write('};\n')
862
Andrew Boie945af952017-08-22 13:15:23 -0700863
Leandro Pereirac2003672018-04-04 13:50:32 -0700864driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700865#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 -0700866"""
867
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500868
Leandro Pereirac2003672018-04-04 13:50:32 -0700869def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700870 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
871 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700872
Andrew Boie8345e5e2018-05-04 15:57:57 -0700873 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
874 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
875 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
876 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700877
878 for subsystem in subsystems:
879 subsystem = subsystem.replace("_driver_api", "")
880
881 fp.write(driver_macro_tpl % {
882 "driver_lower": subsystem.lower(),
883 "driver_upper": subsystem.upper(),
884 })
885
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700886 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700887
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700888
889def write_kobj_types_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
Andrew Boief20efcf2018-05-23 10:57:39 -0700899 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700900
Andrew Boie09c22cc2018-06-27 10:25:45 -0700901 if dep:
902 fp.write("#endif\n")
903
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700904 fp.write("/* Driver subsystems */\n")
905 for subsystem in subsystems:
906 subsystem = subsystem.replace("_driver_api", "").upper()
907 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
908
909
910def write_kobj_otype_output(fp):
911 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700912 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700913 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700914 if kobj == "device":
915 continue
916
Andrew Boie09c22cc2018-06-27 10:25:45 -0700917 if dep:
918 fp.write("#ifdef %s\n" % dep)
919
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500920 fp.write('case %s: ret = "%s"; break;\n' %
921 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700922 if dep:
923 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700924
925 fp.write("/* Driver subsystems */\n")
926 for subsystem in subsystems:
927 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700928 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700929 subsystem.upper(),
930 subsystem
931 ))
932
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500933
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700934def write_kobj_size_output(fp):
935 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700936 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700937 dep, _, alloc = obj_info
938
939 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700940 continue
941
Andrew Boie09c22cc2018-06-27 10:25:45 -0700942 if dep:
943 fp.write("#ifdef %s\n" % dep)
944
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700945 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500946 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700947 if dep:
948 fp.write("#endif\n")
949
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700950
Corey Whartonccd15df2020-02-29 14:51:42 -0800951def parse_subsystems_list_file(path):
952 with open(path, "r") as fp:
953 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700954 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700955 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800956
Andrew Boie945af952017-08-22 13:15:23 -0700957def parse_args():
958 global args
959
Anas Nashif72565532017-12-12 08:19:25 -0500960 parser = argparse.ArgumentParser(
961 description=__doc__,
962 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700963
Leandro Pereirac2003672018-04-04 13:50:32 -0700964 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500965 help="Input zephyr ELF binary")
966 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700967 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500968 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700969 parser.add_argument(
970 "-V", "--validation-output", required=False,
971 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700972 parser.add_argument(
973 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700974 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700975 parser.add_argument(
976 "-S", "--kobj-otype-output", required=False,
977 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700978 parser.add_argument(
979 "-Z", "--kobj-size-output", required=False,
980 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -0800981 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
982 help='''Specifies a file with a JSON encoded list of subsystem names to append to
983 the driver subsystems list. Can be specified multiple times:
984 -i file1 -i file2 ...''')
985
Andrew Boie945af952017-08-22 13:15:23 -0700986 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500987 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700988 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100989 if "VERBOSE" in os.environ:
990 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700991
992
993def main():
994 parse_args()
995
Corey Whartonccd15df2020-02-29 14:51:42 -0800996 if args.include_subsystem_list is not None:
997 for list_file in args.include_subsystem_list:
998 parse_subsystems_list_file(list_file)
999
Leandro Pereirac2003672018-04-04 13:50:32 -07001000 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -08001001 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001002 elf = ELFFile(open(args.kernel, "rb"))
1003 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -07001004 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001005 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -08001006 if not objs:
1007 sys.stderr.write("WARNING: zero kobject found in %s\n"
1008 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -07001009
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001010 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +02001011 sys.exit("Too many thread objects ({})\n"
1012 "Increase CONFIG_MAX_THREAD_BYTES to {}"
1013 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -07001014
Leandro Pereirac2003672018-04-04 13:50:32 -07001015 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001016 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -07001017 syms["_static_kernel_objects_begin"],
1018 syms["_static_kernel_objects_end"])
1019
1020 if args.validation_output:
1021 with open(args.validation_output, "w") as fp:
1022 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001023
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001024 if args.kobj_types_output:
1025 with open(args.kobj_types_output, "w") as fp:
1026 write_kobj_types_output(fp)
1027
1028 if args.kobj_otype_output:
1029 with open(args.kobj_otype_output, "w") as fp:
1030 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001031
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001032 if args.kobj_size_output:
1033 with open(args.kobj_size_output, "w") as fp:
1034 write_kobj_size_output(fp)
1035
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001036
Andrew Boie945af952017-08-22 13:15:23 -07001037if __name__ == "__main__":
1038 main()