blob: 0e272019199dbe9402dbeb8b2bd5eb9f8529892f [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
Julien Massot36f116b2021-11-19 16:30:43 +010060from packaging import version
Andrew Boiefc2f7c32020-03-11 14:17:56 -070061
62import elftools
63from elftools.elf.elffile import ELFFile
64from elftools.elf.sections import SymbolTableSection
65
Julien Massot36f116b2021-11-19 16:30:43 +010066if version.parse(elftools.__version__) < version.parse('0.24'):
Andrew Boiefc2f7c32020-03-11 14:17:56 -070067 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)),
Peter Mitsisae394bf2021-09-20 14:14:32 -0400109 ("k_condvar", (None, False, True)),
Yuval Peress86cadf92022-04-05 11:42:31 -0600110 ("k_event", ("CONFIG_EVENTS", False, True)),
111 ("ztest_suite_node", ("CONFIG_ZTEST", True, False)),
112 ("ztest_suite_stats", ("CONFIG_ZTEST", True, False)),
113 ("ztest_unit_test", ("CONFIG_ZTEST_NEW_API", True, False)),
114 ("ztest_test_rule", ("CONFIG_ZTEST_NEW_API", True, False))
Marc Herbertf78288b2019-03-05 14:31:44 -0800115])
116
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700117def kobject_to_enum(kobj):
118 if kobj.startswith("k_") or kobj.startswith("z_"):
119 name = kobj[2:]
120 else:
121 name = kobj
122
123 return "K_OBJ_%s" % name.upper()
124
Andrew Boie5bd891d2017-09-27 12:59:28 -0700125subsystems = [
Nazar Kazakovf483b1b2022-03-16 21:07:43 +0000126 # Editing the list is deprecated, add the __subsystem sentinel to your driver
Corey Wharton86bfc482020-03-04 13:32:01 -0800127 # api declaration instead. e.x.
128 #
129 # __subsystem struct my_driver_api {
130 # ....
131 #};
Andrew Boie6f928092019-04-23 13:06:59 -0700132]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700133
Andrew Boie299ec8f2020-05-29 13:30:19 -0700134# Names of all structs tagged with __net_socket, found by parse_syscalls.py
135net_sockets = [ ]
136
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700137def subsystem_to_enum(subsys):
138 return "K_OBJ_DRIVER_" + subsys[:-11].upper()
139
140# --- debug stuff ---
141
142scr = os.path.basename(sys.argv[0])
143
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700144def debug(text):
145 if not args.verbose:
146 return
147 sys.stdout.write(scr + ": " + text + "\n")
148
149def error(text):
150 sys.exit("%s ERROR: %s" % (scr, text))
151
152def debug_die(die, text):
153 lp_header = die.dwarfinfo.line_program_for_CU(die.cu).header
154 files = lp_header["file_entry"]
155 includes = lp_header["include_directory"]
156
157 fileinfo = files[die.attributes["DW_AT_decl_file"].value - 1]
158 filename = fileinfo.name.decode("utf-8")
159 filedir = includes[fileinfo.dir_index - 1].decode("utf-8")
160
161 path = os.path.join(filedir, filename)
162 lineno = die.attributes["DW_AT_decl_line"].value
163
164 debug(str(die))
165 debug("File '%s', line %d:" % (path, lineno))
166 debug(" %s" % text)
167
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700168# -- ELF processing
169
170DW_OP_addr = 0x3
171DW_OP_fbreg = 0x91
172STACK_TYPE = "z_thread_stack_element"
173thread_counter = 0
174sys_mutex_counter = 0
175futex_counter = 0
176stack_counter = 0
177
178# Global type environment. Populated by pass 1.
179type_env = {}
180extern_env = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700181
182class KobjectInstance:
183 def __init__(self, type_obj, addr):
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700184 self.addr = addr
185 self.type_obj = type_obj
186
187 # Type name determined later since drivers needs to look at the
188 # API struct address
189 self.type_name = None
Andrew Boie8ce260d2020-04-24 16:24:46 -0700190 self.data = 0
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700191
192
193class KobjectType:
194 def __init__(self, offset, name, size, api=False):
195 self.name = name
196 self.size = size
197 self.offset = offset
198 self.api = api
199
200 def __repr__(self):
201 return "<kobject %s>" % self.name
202
203 @staticmethod
204 def has_kobject():
205 return True
206
207 def get_kobjects(self, addr):
208 return {addr: KobjectInstance(self, addr)}
209
210
211class ArrayType:
212 def __init__(self, offset, elements, member_type):
213 self.elements = elements
214 self.member_type = member_type
215 self.offset = offset
216
217 def __repr__(self):
218 return "<array of %d>" % self.member_type
219
220 def has_kobject(self):
221 if self.member_type not in type_env:
222 return False
223
224 return type_env[self.member_type].has_kobject()
225
226 def get_kobjects(self, addr):
227 mt = type_env[self.member_type]
228
229 # Stacks are arrays of _k_stack_element_t but we want to treat
230 # the whole array as one kernel object (a thread stack)
231 # Data value gets set to size of entire region
232 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
233 # An array of stacks appears as a multi-dimensional array.
234 # The last size is the size of each stack. We need to track
235 # each stack within the array, not as one huge stack object.
236 *dimensions, stacksize = self.elements
237 num_members = 1
238 for e in dimensions:
239 num_members = num_members * e
240
241 ret = {}
242 for i in range(num_members):
243 a = addr + (i * stacksize)
244 o = mt.get_kobjects(a)
245 o[a].data = stacksize
246 ret.update(o)
247 return ret
248
249 objs = {}
250
251 # Multidimensional array flattened out
252 num_members = 1
253 for e in self.elements:
254 num_members = num_members * e
255
256 for i in range(num_members):
257 objs.update(mt.get_kobjects(addr + (i * mt.size)))
258 return objs
259
260
261class AggregateTypeMember:
262 def __init__(self, offset, member_name, member_type, member_offset):
263 self.member_name = member_name
264 self.member_type = member_type
265 if isinstance(member_offset, list):
266 # DWARF v2, location encoded as set of operations
267 # only "DW_OP_plus_uconst" with ULEB128 argument supported
268 if member_offset[0] == 0x23:
269 self.member_offset = member_offset[1] & 0x7f
270 for i in range(1, len(member_offset)-1):
271 if member_offset[i] & 0x80:
272 self.member_offset += (
273 member_offset[i+1] & 0x7f) << i*7
274 else:
275 raise Exception("not yet supported location operation (%s:%d:%d)" %
276 (self.member_name, self.member_type, member_offset[0]))
277 else:
278 self.member_offset = member_offset
279
280 def __repr__(self):
281 return "<member %s, type %d, offset %d>" % (
282 self.member_name, self.member_type, self.member_offset)
283
284 def has_kobject(self):
285 if self.member_type not in type_env:
286 return False
287
288 return type_env[self.member_type].has_kobject()
289
290 def get_kobjects(self, addr):
291 mt = type_env[self.member_type]
292 return mt.get_kobjects(addr + self.member_offset)
293
294
295class ConstType:
296 def __init__(self, child_type):
297 self.child_type = child_type
298
299 def __repr__(self):
300 return "<const %d>" % self.child_type
301
302 def has_kobject(self):
303 if self.child_type not in type_env:
304 return False
305
306 return type_env[self.child_type].has_kobject()
307
308 def get_kobjects(self, addr):
309 return type_env[self.child_type].get_kobjects(addr)
310
311
312class AggregateType:
313 def __init__(self, offset, name, size):
314 self.name = name
315 self.size = size
316 self.offset = offset
317 self.members = []
318
319 def add_member(self, member):
320 self.members.append(member)
321
322 def __repr__(self):
323 return "<struct %s, with %s>" % (self.name, self.members)
324
325 def has_kobject(self):
326 result = False
327
328 bad_members = []
329
330 for member in self.members:
331 if member.has_kobject():
332 result = True
333 else:
334 bad_members.append(member)
335 # Don't need to consider this again, just remove it
336
337 for bad_member in bad_members:
338 self.members.remove(bad_member)
339
340 return result
341
342 def get_kobjects(self, addr):
343 objs = {}
344 for member in self.members:
345 objs.update(member.get_kobjects(addr))
346 return objs
347
348
349# --- helper functions for getting data from DIEs ---
350
351def die_get_spec(die):
352 if 'DW_AT_specification' not in die.attributes:
353 return None
354
355 spec_val = die.attributes["DW_AT_specification"].value
356
357 # offset of the DW_TAG_variable for the extern declaration
358 offset = spec_val + die.cu.cu_offset
359
360 return extern_env.get(offset)
361
362
363def die_get_name(die):
364 if 'DW_AT_name' not in die.attributes:
365 die = die_get_spec(die)
366 if not die:
367 return None
368
369 return die.attributes["DW_AT_name"].value.decode("utf-8")
370
371
372def die_get_type_offset(die):
373 if 'DW_AT_type' not in die.attributes:
374 die = die_get_spec(die)
375 if not die:
376 return None
377
378 return die.attributes["DW_AT_type"].value + die.cu.cu_offset
379
380
381def die_get_byte_size(die):
382 if 'DW_AT_byte_size' not in die.attributes:
383 return 0
384
385 return die.attributes["DW_AT_byte_size"].value
386
387
388def analyze_die_struct(die):
389 name = die_get_name(die) or "<anon>"
390 offset = die.offset
391 size = die_get_byte_size(die)
392
393 # Incomplete type
394 if not size:
395 return
396
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700397 if name in kobjects:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700398 type_env[offset] = KobjectType(offset, name, size)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700399 elif name in subsystems:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700400 type_env[offset] = KobjectType(offset, name, size, api=True)
Andrew Boie299ec8f2020-05-29 13:30:19 -0700401 elif name in net_sockets:
402 type_env[offset] = KobjectType(offset, "NET_SOCKET", size)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700403 else:
404 at = AggregateType(offset, name, size)
405 type_env[offset] = at
406
407 for child in die.iter_children():
408 if child.tag != "DW_TAG_member":
409 continue
410 data_member_location = child.attributes.get("DW_AT_data_member_location")
411 if not data_member_location:
412 continue
413
414 child_type = die_get_type_offset(child)
415 member_offset = data_member_location.value
416 cname = die_get_name(child) or "<anon>"
417 m = AggregateTypeMember(child.offset, cname, child_type,
418 member_offset)
419 at.add_member(m)
420
421 return
422
423
424def analyze_die_const(die):
425 type_offset = die_get_type_offset(die)
426 if not type_offset:
427 return
428
429 type_env[die.offset] = ConstType(type_offset)
430
431
432def analyze_die_array(die):
433 type_offset = die_get_type_offset(die)
434 elements = []
435
436 for child in die.iter_children():
437 if child.tag != "DW_TAG_subrange_type":
438 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700439
Wayne Ren938642c2020-07-21 16:52:09 +0800440 if "DW_AT_upper_bound" in child.attributes:
441 ub = child.attributes["DW_AT_upper_bound"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700442
Wayne Ren938642c2020-07-21 16:52:09 +0800443 if not ub.form.startswith("DW_FORM_data"):
444 continue
445
446 elements.append(ub.value + 1)
447 # in DWARF 4, e.g. ARC Metaware toolchain, DW_AT_count is used
448 # not DW_AT_upper_bound
449 elif "DW_AT_count" in child.attributes:
450 ub = child.attributes["DW_AT_count"]
451
452 if not ub.form.startswith("DW_FORM_data"):
453 continue
454
455 elements.append(ub.value)
456 else:
457 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700458
459 if not elements:
Peter Mitsisfc12f692021-10-07 15:12:43 -0400460 if type_offset in type_env:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700461 mt = type_env[type_offset]
462 if mt.has_kobject():
463 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
464 elements.append(1)
465 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
466 else:
467 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
468
469
470def analyze_typedef(die):
471 type_offset = die_get_type_offset(die)
472
Daniel Leunga5b33f82022-03-15 11:22:20 -0700473 if type_offset not in type_env:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700474 return
475
476 type_env[die.offset] = type_env[type_offset]
477
478
479def unpack_pointer(elf, data, offset):
480 endian_code = "<" if elf.little_endian else ">"
481 if elf.elfclass == 32:
482 size_code = "I"
483 size = 4
484 else:
485 size_code = "Q"
486 size = 8
487
488 return struct.unpack(endian_code + size_code,
489 data[offset:offset + size])[0]
490
491
492def addr_deref(elf, addr):
493 for section in elf.iter_sections():
494 start = section['sh_addr']
495 end = start + section['sh_size']
496
497 if start <= addr < end:
498 data = section.data()
499 offset = addr - start
500 return unpack_pointer(elf, data, offset)
501
502 return 0
503
504
505def device_get_api_addr(elf, addr):
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100506 # See include/device.h for a description of struct device
507 offset = 8 if elf.elfclass == 32 else 16
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700508 return addr_deref(elf, addr + offset)
509
510
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700511def find_kobjects(elf, syms):
Andrew Boie8ce260d2020-04-24 16:24:46 -0700512 global thread_counter
513 global sys_mutex_counter
514 global futex_counter
515 global stack_counter
516
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700517 if not elf.has_dwarf_info():
518 sys.exit("ELF file has no DWARF information")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700519
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700520 app_smem_start = syms["_app_smem_start"]
521 app_smem_end = syms["_app_smem_end"]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700522
523 if "CONFIG_LINKER_USE_PINNED_SECTION" in syms and "_app_smem_pinned_start" in syms:
524 app_smem_pinned_start = syms["_app_smem_pinned_start"]
525 app_smem_pinned_end = syms["_app_smem_pinned_end"]
526 else:
527 app_smem_pinned_start = app_smem_start
528 app_smem_pinned_end = app_smem_end
529
Andrew Boie8ce260d2020-04-24 16:24:46 -0700530 user_stack_start = syms["z_user_stacks_start"]
531 user_stack_end = syms["z_user_stacks_end"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700532
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700533 di = elf.get_dwarf_info()
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700534
Wentong Wu0bf51132020-05-21 16:49:28 +0800535 variables = []
536
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700537 # Step 1: collect all type information.
538 for CU in di.iter_CUs():
539 for die in CU.iter_DIEs():
540 # Unions are disregarded, kernel objects should never be union
541 # members since the memory is not dedicated to that object and
542 # could be something else
543 if die.tag == "DW_TAG_structure_type":
544 analyze_die_struct(die)
545 elif die.tag == "DW_TAG_const_type":
546 analyze_die_const(die)
547 elif die.tag == "DW_TAG_array_type":
548 analyze_die_array(die)
549 elif die.tag == "DW_TAG_typedef":
550 analyze_typedef(die)
551 elif die.tag == "DW_TAG_variable":
552 variables.append(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700553
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700554 # Step 2: filter type_env to only contain kernel objects, or structs
555 # and arrays of kernel objects
556 bad_offsets = []
557 for offset, type_object in type_env.items():
558 if not type_object.has_kobject():
559 bad_offsets.append(offset)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700560
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700561 for offset in bad_offsets:
562 del type_env[offset]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700563
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700564 # Step 3: Now that we know all the types we are looking for, examine
565 # all variables
566 all_objs = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700567
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700568 for die in variables:
569 name = die_get_name(die)
570 if not name:
571 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700572
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100573 if name.startswith("__init_sys_init"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700574 # Boot-time initialization function; not an actual device
575 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700576
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700577 type_offset = die_get_type_offset(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700578
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700579 # Is this a kernel object, or a structure containing kernel
580 # objects?
581 if type_offset not in type_env:
582 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700583
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700584 if "DW_AT_declaration" in die.attributes:
585 # Extern declaration, only used indirectly
586 extern_env[die.offset] = die
587 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700588
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700589 if "DW_AT_location" not in die.attributes:
590 debug_die(die,
591 "No location information for object '%s'; possibly stack allocated"
592 % name)
593 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700594
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700595 loc = die.attributes["DW_AT_location"]
Peter Mitsisfc12f692021-10-07 15:12:43 -0400596 if loc.form not in ("DW_FORM_exprloc", "DW_FORM_block1"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700597 debug_die(die, "kernel object '%s' unexpected location format" %
598 name)
599 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700600
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700601 opcode = loc.value[0]
602 if opcode != DW_OP_addr:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700603
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700604 # Check if frame pointer offset DW_OP_fbreg
605 if opcode == DW_OP_fbreg:
606 debug_die(die, "kernel object '%s' found on stack" % name)
607 else:
608 debug_die(die,
609 "kernel object '%s' unexpected exprloc opcode %s" %
610 (name, hex(opcode)))
611 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700612
Carlo Caioned804ee32021-03-23 09:44:42 +0100613 if "CONFIG_64BIT" in syms:
614 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
615 (loc.value[3] << 16) | (loc.value[4] << 24) |
616 (loc.value[5] << 32) | (loc.value[6] << 40) |
617 (loc.value[7] << 48) | (loc.value[8] << 56))
618 else:
619 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
620 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700621
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700622 if addr == 0:
623 # Never linked; gc-sections deleted it
624 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700625
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700626 type_obj = type_env[type_offset]
627 objs = type_obj.get_kobjects(addr)
628 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700629
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700630 debug("symbol '%s' at %s contains %d object(s)"
631 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700632
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700633 # Step 4: objs is a dictionary mapping variable memory addresses to
634 # their associated type objects. Now that we have seen all variables
635 # and can properly look up API structs, convert this into a dictionary
636 # mapping variables to the C enumeration of what kernel object type it
637 # is.
638 ret = {}
639 for addr, ko in all_objs.items():
640 # API structs don't get into the gperf table
641 if ko.type_obj.api:
642 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700643
Andrew Boie455e1782020-05-29 13:22:20 -0700644 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700645 if (not user_ram_allowed and
646 ((app_smem_start <= addr < app_smem_end)
647 or (app_smem_pinned_start <= addr < app_smem_pinned_end))):
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800648 debug("object '%s' found in invalid location %s"
649 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700650 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700651
Andrew Boie8ce260d2020-04-24 16:24:46 -0700652 if (ko.type_obj.name == STACK_TYPE and
653 (addr < user_stack_start or addr >= user_stack_end)):
654 debug("skip kernel-only stack at %s" % hex(addr))
655 continue
656
657 # At this point we know the object will be included in the gperf table
658 if ko.type_obj.name == "k_thread":
659 # Assign an ID for this thread object, used to track its
660 # permissions to other kernel objects
661 ko.data = thread_counter
662 thread_counter = thread_counter + 1
663 elif ko.type_obj.name == "sys_mutex":
664 ko.data = "&kernel_mutexes[%d]" % sys_mutex_counter
665 sys_mutex_counter += 1
666 elif ko.type_obj.name == "k_futex":
667 ko.data = "&futex_data[%d]" % futex_counter
668 futex_counter += 1
669 elif ko.type_obj.name == STACK_TYPE:
670 stack_counter += 1
671
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700672 if ko.type_obj.name != "device":
673 # Not a device struct so we immediately know its type
674 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700675 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700676 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700677
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700678 # Device struct. Need to get the address of its API struct,
679 # if it has one.
680 apiaddr = device_get_api_addr(elf, addr)
681 if apiaddr not in all_objs:
682 if apiaddr == 0:
683 debug("device instance at 0x%x has no associated subsystem"
684 % addr)
685 else:
686 debug("device instance at 0x%x has unknown API 0x%x"
687 % (addr, apiaddr))
688 # API struct does not correspond to a known subsystem, skip it
689 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700690
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700691 apiobj = all_objs[apiaddr]
692 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
693 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700694
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700695 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700696
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700697 # 1. Before python 3.7 dict order is not guaranteed. With Python
698 # 3.5 it doesn't seem random with *integer* keys but can't
699 # rely on that.
700 # 2. OrderedDict means _insertion_ order, so not enough because
701 # built from other (random!) dicts: need to _sort_ first.
702 # 3. Sorting memory address looks good.
703 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700704
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700705def get_symbols(elf):
706 for section in elf.iter_sections():
707 if isinstance(section, SymbolTableSection):
708 return {sym.name: sym.entry.st_value
709 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700710
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700711 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700712
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700713
714# -- GPERF generation logic
715
Andrew Boie945af952017-08-22 13:15:23 -0700716header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700717%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700718%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700719%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700720%struct-type
721%{
Fabio Baltieri93f20d72022-05-25 16:35:50 +0100722#include <zephyr/kernel.h>
723#include <zephyr/toolchain.h>
724#include <zephyr/syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700725#include <string.h>
726%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700727struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700728"""
729
Andy Gross6042ae92018-01-22 14:26:49 -0600730# Different versions of gperf have different prototypes for the lookup
731# function, best to implement the wrapper here. The pointer value itself is
732# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500733# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700734footer = """%%
Peter Bigot2fcf7622020-05-14 05:06:08 -0500735struct z_object *z_object_gperf_find(const void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700736{
Patrik Flykt4344e272019-03-08 14:19:05 -0700737 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700738}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700739
Patrik Flykt4344e272019-03-08 14:19:05 -0700740void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700741{
742 int i;
743
744 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700745 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700746 func(&wordlist[i], context);
747 }
748 }
749}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800750
751#ifndef CONFIG_DYNAMIC_OBJECTS
Peter Bigot2fcf7622020-05-14 05:06:08 -0500752struct z_object *z_object_find(const void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700753 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800754
Patrik Flykt4344e272019-03-08 14:19:05 -0700755void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
756 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800757#endif
Andrew Boie945af952017-08-22 13:15:23 -0700758"""
759
760
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700761def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700762 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700763 if sys_mutex_counter != 0:
764 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
765 % sys_mutex_counter)
766 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400767 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700768 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700769 fp.write(", ")
770 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700771
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700772 if futex_counter != 0:
773 fp.write("static struct z_futex_data futex_data[%d] = {\n"
774 % futex_counter)
775 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800776 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700777 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800778 fp.write(", ")
779 fp.write("};\n")
780
Andrew Boie28be7932020-03-11 10:56:19 -0700781 metadata_names = {
782 "K_OBJ_THREAD" : "thread_id",
783 "K_OBJ_SYS_MUTEX" : "mutex",
784 "K_OBJ_FUTEX" : "futex_data"
785 }
786
787 if "CONFIG_GEN_PRIV_STACKS" in syms:
788 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700789 if stack_counter != 0:
Andrew Boie8ce260d2020-04-24 16:24:46 -0700790 # Same as K_KERNEL_STACK_ARRAY_DEFINE, but routed to a different
791 # memory section.
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500792 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie8ce260d2020-04-24 16:24:46 -0700793 " __aligned(Z_KERNEL_STACK_OBJ_ALIGN)"
794 " priv_stacks[%d][Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700795 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700796
Daniel Leungc3711b32021-03-20 12:02:59 -0700797 fp.write("static const struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700798 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700799 counter = 0
800 for _, ko in objs.items():
801 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
802 continue
803
804 # ko.data currently has the stack size. fetch the value to
805 # populate the appropriate entry in stack_data, and put
806 # a reference to the entry in stack_data into the data value
807 # instead
808 size = ko.data
809 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500810 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700811 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700812 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700813 fp.write(",")
814 fp.write("\n")
815 counter += 1
816 fp.write("};\n")
817 else:
818 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
819
Andrew Boief0835672019-03-27 15:44:52 -0700820 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700821 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700822 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
823 thread_idx_map = {}
824
825 for i in range(0, thread_max_bytes):
826 thread_idx_map[i] = 0xFF
827
Andrew Boiebca15da2017-10-15 14:17:48 -0700828 for obj_addr, ko in objs.items():
829 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700830 # pre-initialized objects fall within this memory range, they are
831 # either completely initialized at build time, or done automatically
832 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200833 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700834 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700835
Andrew Boief290ab52019-11-18 17:06:13 -0800836 if "CONFIG_64BIT" in syms:
837 format_code = "Q"
838 else:
839 format_code = "I"
840
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700841 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800842 endian = "<"
843 else:
844 endian = ">"
845
846 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700847 fp.write("\"")
848 for byte in byte_str:
849 val = "\\x%02x" % byte
850 fp.write(val)
851
Andrew Boie78757072019-07-23 13:29:30 -0700852 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200853 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700854 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200855 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700856 flags += " | K_OBJ_FLAG_DRIVER"
857
Andrew Boief2734ab2020-03-11 06:37:42 -0700858 if ko.type_name in metadata_names:
859 tname = metadata_names[ko.type_name]
860 else:
861 tname = "unused"
862
Abramo Bagnara795500b2021-11-16 08:12:13 +0100863 fp.write("\", {0}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
Andrew Boief2734ab2020-03-11 06:37:42 -0700864 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700865
Daniel Leunge58b6542018-08-08 11:23:16 -0700866 if obj_type == "K_OBJ_THREAD":
867 idx = math.floor(ko.data / 8)
868 bit = ko.data % 8
869 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
870
Andrew Boie945af952017-08-22 13:15:23 -0700871 fp.write(footer)
872
Daniel Leunge58b6542018-08-08 11:23:16 -0700873 # Generate the array of already mapped thread indexes
874 fp.write('\n')
Daniel Leung7f8dba92022-03-09 11:39:35 -0800875 fp.write('Z_GENERIC_DOT_SECTION(data)\n')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500876 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700877
878 for i in range(0, thread_max_bytes):
879 fp.write(' 0x%x, ' % (thread_idx_map[i]))
880
881 fp.write('};\n')
882
Andrew Boie945af952017-08-22 13:15:23 -0700883
Leandro Pereirac2003672018-04-04 13:50:32 -0700884driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700885#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 -0700886"""
887
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500888
Leandro Pereirac2003672018-04-04 13:50:32 -0700889def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700890 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
891 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700892
Andrew Boie8345e5e2018-05-04 15:57:57 -0700893 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
894 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
895 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
896 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700897
898 for subsystem in subsystems:
899 subsystem = subsystem.replace("_driver_api", "")
900
901 fp.write(driver_macro_tpl % {
902 "driver_lower": subsystem.lower(),
903 "driver_upper": subsystem.upper(),
904 })
905
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700906 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700907
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700908
909def write_kobj_types_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
Andrew Boief20efcf2018-05-23 10:57:39 -0700919 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700920
Andrew Boie09c22cc2018-06-27 10:25:45 -0700921 if dep:
922 fp.write("#endif\n")
923
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700924 fp.write("/* Driver subsystems */\n")
925 for subsystem in subsystems:
926 subsystem = subsystem.replace("_driver_api", "").upper()
927 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
928
929
930def write_kobj_otype_output(fp):
931 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700932 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700933 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700934 if kobj == "device":
935 continue
936
Andrew Boie09c22cc2018-06-27 10:25:45 -0700937 if dep:
938 fp.write("#ifdef %s\n" % dep)
939
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500940 fp.write('case %s: ret = "%s"; break;\n' %
941 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700942 if dep:
943 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700944
945 fp.write("/* Driver subsystems */\n")
946 for subsystem in subsystems:
947 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700948 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700949 subsystem.upper(),
950 subsystem
951 ))
952
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500953
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700954def write_kobj_size_output(fp):
955 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700956 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700957 dep, _, alloc = obj_info
958
959 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700960 continue
961
Andrew Boie09c22cc2018-06-27 10:25:45 -0700962 if dep:
963 fp.write("#ifdef %s\n" % dep)
964
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700965 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500966 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700967 if dep:
968 fp.write("#endif\n")
969
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700970
Corey Whartonccd15df2020-02-29 14:51:42 -0800971def parse_subsystems_list_file(path):
972 with open(path, "r") as fp:
973 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700974 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700975 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800976
Andrew Boie945af952017-08-22 13:15:23 -0700977def parse_args():
978 global args
979
Anas Nashif72565532017-12-12 08:19:25 -0500980 parser = argparse.ArgumentParser(
981 description=__doc__,
982 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700983
Leandro Pereirac2003672018-04-04 13:50:32 -0700984 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500985 help="Input zephyr ELF binary")
986 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700987 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500988 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700989 parser.add_argument(
990 "-V", "--validation-output", required=False,
991 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700992 parser.add_argument(
993 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700994 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700995 parser.add_argument(
996 "-S", "--kobj-otype-output", required=False,
997 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700998 parser.add_argument(
999 "-Z", "--kobj-size-output", required=False,
1000 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -08001001 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
1002 help='''Specifies a file with a JSON encoded list of subsystem names to append to
1003 the driver subsystems list. Can be specified multiple times:
1004 -i file1 -i file2 ...''')
1005
Andrew Boie945af952017-08-22 13:15:23 -07001006 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -05001007 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -07001008 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +01001009 if "VERBOSE" in os.environ:
1010 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -07001011
1012
1013def main():
1014 parse_args()
1015
Corey Whartonccd15df2020-02-29 14:51:42 -08001016 if args.include_subsystem_list is not None:
1017 for list_file in args.include_subsystem_list:
1018 parse_subsystems_list_file(list_file)
1019
Leandro Pereirac2003672018-04-04 13:50:32 -07001020 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -08001021 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001022 elf = ELFFile(open(args.kernel, "rb"))
1023 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -07001024 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001025 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -08001026 if not objs:
1027 sys.stderr.write("WARNING: zero kobject found in %s\n"
1028 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -07001029
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001030 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +02001031 sys.exit("Too many thread objects ({})\n"
1032 "Increase CONFIG_MAX_THREAD_BYTES to {}"
1033 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -07001034
Leandro Pereirac2003672018-04-04 13:50:32 -07001035 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001036 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -07001037 syms["_static_kernel_objects_begin"],
1038 syms["_static_kernel_objects_end"])
1039
1040 if args.validation_output:
1041 with open(args.validation_output, "w") as fp:
1042 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001043
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001044 if args.kobj_types_output:
1045 with open(args.kobj_types_output, "w") as fp:
1046 write_kobj_types_output(fp)
1047
1048 if args.kobj_otype_output:
1049 with open(args.kobj_otype_output, "w") as fp:
1050 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001051
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001052 if args.kobj_size_output:
1053 with open(args.kobj_size_output, "w") as fp:
1054 write_kobj_size_output(fp)
1055
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001056
Andrew Boie945af952017-08-22 13:15:23 -07001057if __name__ == "__main__":
1058 main()