blob: 93f2ed80e80f3f795c17f5e135668bec406adcb9 [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
Carlo Caioned804ee32021-03-23 09:44:42 +0100601 if "CONFIG_64BIT" in syms:
602 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
603 (loc.value[3] << 16) | (loc.value[4] << 24) |
604 (loc.value[5] << 32) | (loc.value[6] << 40) |
605 (loc.value[7] << 48) | (loc.value[8] << 56))
606 else:
607 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
608 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700609
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700610 if addr == 0:
611 # Never linked; gc-sections deleted it
612 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700613
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700614 type_obj = type_env[type_offset]
615 objs = type_obj.get_kobjects(addr)
616 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700617
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700618 debug("symbol '%s' at %s contains %d object(s)"
619 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700620
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700621 # Step 4: objs is a dictionary mapping variable memory addresses to
622 # their associated type objects. Now that we have seen all variables
623 # and can properly look up API structs, convert this into a dictionary
624 # mapping variables to the C enumeration of what kernel object type it
625 # is.
626 ret = {}
627 for addr, ko in all_objs.items():
628 # API structs don't get into the gperf table
629 if ko.type_obj.api:
630 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700631
Andrew Boie455e1782020-05-29 13:22:20 -0700632 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700633 if not user_ram_allowed and app_smem_start <= addr < app_smem_end:
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800634 debug("object '%s' found in invalid location %s"
635 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700636 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700637
Andrew Boie8ce260d2020-04-24 16:24:46 -0700638 if (ko.type_obj.name == STACK_TYPE and
639 (addr < user_stack_start or addr >= user_stack_end)):
640 debug("skip kernel-only stack at %s" % hex(addr))
641 continue
642
643 # At this point we know the object will be included in the gperf table
644 if ko.type_obj.name == "k_thread":
645 # Assign an ID for this thread object, used to track its
646 # permissions to other kernel objects
647 ko.data = thread_counter
648 thread_counter = thread_counter + 1
649 elif ko.type_obj.name == "sys_mutex":
650 ko.data = "&kernel_mutexes[%d]" % sys_mutex_counter
651 sys_mutex_counter += 1
652 elif ko.type_obj.name == "k_futex":
653 ko.data = "&futex_data[%d]" % futex_counter
654 futex_counter += 1
655 elif ko.type_obj.name == STACK_TYPE:
656 stack_counter += 1
657
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700658 if ko.type_obj.name != "device":
659 # Not a device struct so we immediately know its type
660 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700661 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700662 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700663
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700664 # Device struct. Need to get the address of its API struct,
665 # if it has one.
666 apiaddr = device_get_api_addr(elf, addr)
667 if apiaddr not in all_objs:
668 if apiaddr == 0:
669 debug("device instance at 0x%x has no associated subsystem"
670 % addr)
671 else:
672 debug("device instance at 0x%x has unknown API 0x%x"
673 % (addr, apiaddr))
674 # API struct does not correspond to a known subsystem, skip it
675 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700676
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700677 apiobj = all_objs[apiaddr]
678 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
679 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700680
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700681 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700682
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700683 # 1. Before python 3.7 dict order is not guaranteed. With Python
684 # 3.5 it doesn't seem random with *integer* keys but can't
685 # rely on that.
686 # 2. OrderedDict means _insertion_ order, so not enough because
687 # built from other (random!) dicts: need to _sort_ first.
688 # 3. Sorting memory address looks good.
689 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700690
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700691def get_symbols(elf):
692 for section in elf.iter_sections():
693 if isinstance(section, SymbolTableSection):
694 return {sym.name: sym.entry.st_value
695 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700696
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700697 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700698
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700699
700# -- GPERF generation logic
701
Andrew Boie945af952017-08-22 13:15:23 -0700702header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700703%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700704%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700705%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700706%struct-type
707%{
708#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800709#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700710#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700711#include <string.h>
712%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700713struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700714"""
715
Andy Gross6042ae92018-01-22 14:26:49 -0600716# Different versions of gperf have different prototypes for the lookup
717# function, best to implement the wrapper here. The pointer value itself is
718# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500719# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700720footer = """%%
Peter Bigot2fcf7622020-05-14 05:06:08 -0500721struct z_object *z_object_gperf_find(const void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700722{
Patrik Flykt4344e272019-03-08 14:19:05 -0700723 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700724}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700725
Patrik Flykt4344e272019-03-08 14:19:05 -0700726void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700727{
728 int i;
729
730 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700731 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700732 func(&wordlist[i], context);
733 }
734 }
735}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800736
737#ifndef CONFIG_DYNAMIC_OBJECTS
Peter Bigot2fcf7622020-05-14 05:06:08 -0500738struct z_object *z_object_find(const void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700739 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800740
Patrik Flykt4344e272019-03-08 14:19:05 -0700741void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
742 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800743#endif
Andrew Boie945af952017-08-22 13:15:23 -0700744"""
745
746
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700747def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700748 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700749 if sys_mutex_counter != 0:
750 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
751 % sys_mutex_counter)
752 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400753 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700754 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700755 fp.write(", ")
756 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700757
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700758 if futex_counter != 0:
759 fp.write("static struct z_futex_data futex_data[%d] = {\n"
760 % futex_counter)
761 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800762 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700763 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800764 fp.write(", ")
765 fp.write("};\n")
766
Andrew Boie28be7932020-03-11 10:56:19 -0700767 metadata_names = {
768 "K_OBJ_THREAD" : "thread_id",
769 "K_OBJ_SYS_MUTEX" : "mutex",
770 "K_OBJ_FUTEX" : "futex_data"
771 }
772
773 if "CONFIG_GEN_PRIV_STACKS" in syms:
774 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700775 if stack_counter != 0:
Andrew Boie8ce260d2020-04-24 16:24:46 -0700776 # Same as K_KERNEL_STACK_ARRAY_DEFINE, but routed to a different
777 # memory section.
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500778 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie8ce260d2020-04-24 16:24:46 -0700779 " __aligned(Z_KERNEL_STACK_OBJ_ALIGN)"
780 " priv_stacks[%d][Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700781 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700782
Daniel Leungc3711b32021-03-20 12:02:59 -0700783 fp.write("static const struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700784 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700785 counter = 0
786 for _, ko in objs.items():
787 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
788 continue
789
790 # ko.data currently has the stack size. fetch the value to
791 # populate the appropriate entry in stack_data, and put
792 # a reference to the entry in stack_data into the data value
793 # instead
794 size = ko.data
795 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500796 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700797 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700798 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700799 fp.write(",")
800 fp.write("\n")
801 counter += 1
802 fp.write("};\n")
803 else:
804 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
805
Andrew Boief0835672019-03-27 15:44:52 -0700806 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700807 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700808 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
809 thread_idx_map = {}
810
811 for i in range(0, thread_max_bytes):
812 thread_idx_map[i] = 0xFF
813
Andrew Boiebca15da2017-10-15 14:17:48 -0700814 for obj_addr, ko in objs.items():
815 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700816 # pre-initialized objects fall within this memory range, they are
817 # either completely initialized at build time, or done automatically
818 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200819 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700820 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700821
Andrew Boief290ab52019-11-18 17:06:13 -0800822 if "CONFIG_64BIT" in syms:
823 format_code = "Q"
824 else:
825 format_code = "I"
826
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700827 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800828 endian = "<"
829 else:
830 endian = ">"
831
832 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700833 fp.write("\"")
834 for byte in byte_str:
835 val = "\\x%02x" % byte
836 fp.write(val)
837
Andrew Boie78757072019-07-23 13:29:30 -0700838 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200839 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700840 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200841 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700842 flags += " | K_OBJ_FLAG_DRIVER"
843
Andrew Boief2734ab2020-03-11 06:37:42 -0700844 if ko.type_name in metadata_names:
845 tname = metadata_names[ko.type_name]
846 else:
847 tname = "unused"
848
849 fp.write("\", {}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
850 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700851
Daniel Leunge58b6542018-08-08 11:23:16 -0700852 if obj_type == "K_OBJ_THREAD":
853 idx = math.floor(ko.data / 8)
854 bit = ko.data % 8
855 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
856
Andrew Boie945af952017-08-22 13:15:23 -0700857 fp.write(footer)
858
Daniel Leunge58b6542018-08-08 11:23:16 -0700859 # Generate the array of already mapped thread indexes
860 fp.write('\n')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500861 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700862
863 for i in range(0, thread_max_bytes):
864 fp.write(' 0x%x, ' % (thread_idx_map[i]))
865
866 fp.write('};\n')
867
Andrew Boie945af952017-08-22 13:15:23 -0700868
Leandro Pereirac2003672018-04-04 13:50:32 -0700869driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700870#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 -0700871"""
872
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500873
Leandro Pereirac2003672018-04-04 13:50:32 -0700874def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700875 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
876 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700877
Andrew Boie8345e5e2018-05-04 15:57:57 -0700878 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
879 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
880 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
881 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700882
883 for subsystem in subsystems:
884 subsystem = subsystem.replace("_driver_api", "")
885
886 fp.write(driver_macro_tpl % {
887 "driver_lower": subsystem.lower(),
888 "driver_upper": subsystem.upper(),
889 })
890
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700891 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700892
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700893
894def write_kobj_types_output(fp):
895 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700896 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700897 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700898 if kobj == "device":
899 continue
900
Andrew Boie09c22cc2018-06-27 10:25:45 -0700901 if dep:
902 fp.write("#ifdef %s\n" % dep)
903
Andrew Boief20efcf2018-05-23 10:57:39 -0700904 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700905
Andrew Boie09c22cc2018-06-27 10:25:45 -0700906 if dep:
907 fp.write("#endif\n")
908
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700909 fp.write("/* Driver subsystems */\n")
910 for subsystem in subsystems:
911 subsystem = subsystem.replace("_driver_api", "").upper()
912 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
913
914
915def write_kobj_otype_output(fp):
916 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700917 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700918 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700919 if kobj == "device":
920 continue
921
Andrew Boie09c22cc2018-06-27 10:25:45 -0700922 if dep:
923 fp.write("#ifdef %s\n" % dep)
924
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500925 fp.write('case %s: ret = "%s"; break;\n' %
926 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700927 if dep:
928 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700929
930 fp.write("/* Driver subsystems */\n")
931 for subsystem in subsystems:
932 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700933 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700934 subsystem.upper(),
935 subsystem
936 ))
937
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500938
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700939def write_kobj_size_output(fp):
940 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700941 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700942 dep, _, alloc = obj_info
943
944 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700945 continue
946
Andrew Boie09c22cc2018-06-27 10:25:45 -0700947 if dep:
948 fp.write("#ifdef %s\n" % dep)
949
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700950 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500951 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700952 if dep:
953 fp.write("#endif\n")
954
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700955
Corey Whartonccd15df2020-02-29 14:51:42 -0800956def parse_subsystems_list_file(path):
957 with open(path, "r") as fp:
958 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700959 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700960 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800961
Andrew Boie945af952017-08-22 13:15:23 -0700962def parse_args():
963 global args
964
Anas Nashif72565532017-12-12 08:19:25 -0500965 parser = argparse.ArgumentParser(
966 description=__doc__,
967 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700968
Leandro Pereirac2003672018-04-04 13:50:32 -0700969 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500970 help="Input zephyr ELF binary")
971 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700972 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500973 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700974 parser.add_argument(
975 "-V", "--validation-output", required=False,
976 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700977 parser.add_argument(
978 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700979 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700980 parser.add_argument(
981 "-S", "--kobj-otype-output", required=False,
982 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700983 parser.add_argument(
984 "-Z", "--kobj-size-output", required=False,
985 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -0800986 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
987 help='''Specifies a file with a JSON encoded list of subsystem names to append to
988 the driver subsystems list. Can be specified multiple times:
989 -i file1 -i file2 ...''')
990
Andrew Boie945af952017-08-22 13:15:23 -0700991 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500992 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700993 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100994 if "VERBOSE" in os.environ:
995 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700996
997
998def main():
999 parse_args()
1000
Corey Whartonccd15df2020-02-29 14:51:42 -08001001 if args.include_subsystem_list is not None:
1002 for list_file in args.include_subsystem_list:
1003 parse_subsystems_list_file(list_file)
1004
Leandro Pereirac2003672018-04-04 13:50:32 -07001005 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -08001006 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001007 elf = ELFFile(open(args.kernel, "rb"))
1008 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -07001009 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001010 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -08001011 if not objs:
1012 sys.stderr.write("WARNING: zero kobject found in %s\n"
1013 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -07001014
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001015 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +02001016 sys.exit("Too many thread objects ({})\n"
1017 "Increase CONFIG_MAX_THREAD_BYTES to {}"
1018 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -07001019
Leandro Pereirac2003672018-04-04 13:50:32 -07001020 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001021 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -07001022 syms["_static_kernel_objects_begin"],
1023 syms["_static_kernel_objects_end"])
1024
1025 if args.validation_output:
1026 with open(args.validation_output, "w") as fp:
1027 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001028
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001029 if args.kobj_types_output:
1030 with open(args.kobj_types_output, "w") as fp:
1031 write_kobj_types_output(fp)
1032
1033 if args.kobj_otype_output:
1034 with open(args.kobj_otype_output, "w") as fp:
1035 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001036
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001037 if args.kobj_size_output:
1038 with open(args.kobj_size_output, "w") as fp:
1039 write_kobj_size_output(fp)
1040
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001041
Andrew Boie945af952017-08-22 13:15:23 -07001042if __name__ == "__main__":
1043 main()