blob: f513ec157f1e556b3ac54a0b8dd8c5d7ae9ef643 [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)),
110 ("k_event", ("CONFIG_EVENTS", False, True))
Marc Herbertf78288b2019-03-05 14:31:44 -0800111])
112
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700113def kobject_to_enum(kobj):
114 if kobj.startswith("k_") or kobj.startswith("z_"):
115 name = kobj[2:]
116 else:
117 name = kobj
118
119 return "K_OBJ_%s" % name.upper()
120
Andrew Boie5bd891d2017-09-27 12:59:28 -0700121subsystems = [
Corey Wharton86bfc482020-03-04 13:32:01 -0800122 # Editing the list is deprecated, add the __subsystem sentinal to your driver
123 # api declaration instead. e.x.
124 #
125 # __subsystem struct my_driver_api {
126 # ....
127 #};
Andrew Boie6f928092019-04-23 13:06:59 -0700128]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700129
Andrew Boie299ec8f2020-05-29 13:30:19 -0700130# Names of all structs tagged with __net_socket, found by parse_syscalls.py
131net_sockets = [ ]
132
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700133def subsystem_to_enum(subsys):
134 return "K_OBJ_DRIVER_" + subsys[:-11].upper()
135
136# --- debug stuff ---
137
138scr = os.path.basename(sys.argv[0])
139
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700140def debug(text):
141 if not args.verbose:
142 return
143 sys.stdout.write(scr + ": " + text + "\n")
144
145def error(text):
146 sys.exit("%s ERROR: %s" % (scr, text))
147
148def debug_die(die, text):
149 lp_header = die.dwarfinfo.line_program_for_CU(die.cu).header
150 files = lp_header["file_entry"]
151 includes = lp_header["include_directory"]
152
153 fileinfo = files[die.attributes["DW_AT_decl_file"].value - 1]
154 filename = fileinfo.name.decode("utf-8")
155 filedir = includes[fileinfo.dir_index - 1].decode("utf-8")
156
157 path = os.path.join(filedir, filename)
158 lineno = die.attributes["DW_AT_decl_line"].value
159
160 debug(str(die))
161 debug("File '%s', line %d:" % (path, lineno))
162 debug(" %s" % text)
163
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700164# -- ELF processing
165
166DW_OP_addr = 0x3
167DW_OP_fbreg = 0x91
168STACK_TYPE = "z_thread_stack_element"
169thread_counter = 0
170sys_mutex_counter = 0
171futex_counter = 0
172stack_counter = 0
173
174# Global type environment. Populated by pass 1.
175type_env = {}
176extern_env = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700177
178class KobjectInstance:
179 def __init__(self, type_obj, addr):
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700180 self.addr = addr
181 self.type_obj = type_obj
182
183 # Type name determined later since drivers needs to look at the
184 # API struct address
185 self.type_name = None
Andrew Boie8ce260d2020-04-24 16:24:46 -0700186 self.data = 0
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700187
188
189class KobjectType:
190 def __init__(self, offset, name, size, api=False):
191 self.name = name
192 self.size = size
193 self.offset = offset
194 self.api = api
195
196 def __repr__(self):
197 return "<kobject %s>" % self.name
198
199 @staticmethod
200 def has_kobject():
201 return True
202
203 def get_kobjects(self, addr):
204 return {addr: KobjectInstance(self, addr)}
205
206
207class ArrayType:
208 def __init__(self, offset, elements, member_type):
209 self.elements = elements
210 self.member_type = member_type
211 self.offset = offset
212
213 def __repr__(self):
214 return "<array of %d>" % self.member_type
215
216 def has_kobject(self):
217 if self.member_type not in type_env:
218 return False
219
220 return type_env[self.member_type].has_kobject()
221
222 def get_kobjects(self, addr):
223 mt = type_env[self.member_type]
224
225 # Stacks are arrays of _k_stack_element_t but we want to treat
226 # the whole array as one kernel object (a thread stack)
227 # Data value gets set to size of entire region
228 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
229 # An array of stacks appears as a multi-dimensional array.
230 # The last size is the size of each stack. We need to track
231 # each stack within the array, not as one huge stack object.
232 *dimensions, stacksize = self.elements
233 num_members = 1
234 for e in dimensions:
235 num_members = num_members * e
236
237 ret = {}
238 for i in range(num_members):
239 a = addr + (i * stacksize)
240 o = mt.get_kobjects(a)
241 o[a].data = stacksize
242 ret.update(o)
243 return ret
244
245 objs = {}
246
247 # Multidimensional array flattened out
248 num_members = 1
249 for e in self.elements:
250 num_members = num_members * e
251
252 for i in range(num_members):
253 objs.update(mt.get_kobjects(addr + (i * mt.size)))
254 return objs
255
256
257class AggregateTypeMember:
258 def __init__(self, offset, member_name, member_type, member_offset):
259 self.member_name = member_name
260 self.member_type = member_type
261 if isinstance(member_offset, list):
262 # DWARF v2, location encoded as set of operations
263 # only "DW_OP_plus_uconst" with ULEB128 argument supported
264 if member_offset[0] == 0x23:
265 self.member_offset = member_offset[1] & 0x7f
266 for i in range(1, len(member_offset)-1):
267 if member_offset[i] & 0x80:
268 self.member_offset += (
269 member_offset[i+1] & 0x7f) << i*7
270 else:
271 raise Exception("not yet supported location operation (%s:%d:%d)" %
272 (self.member_name, self.member_type, member_offset[0]))
273 else:
274 self.member_offset = member_offset
275
276 def __repr__(self):
277 return "<member %s, type %d, offset %d>" % (
278 self.member_name, self.member_type, self.member_offset)
279
280 def has_kobject(self):
281 if self.member_type not in type_env:
282 return False
283
284 return type_env[self.member_type].has_kobject()
285
286 def get_kobjects(self, addr):
287 mt = type_env[self.member_type]
288 return mt.get_kobjects(addr + self.member_offset)
289
290
291class ConstType:
292 def __init__(self, child_type):
293 self.child_type = child_type
294
295 def __repr__(self):
296 return "<const %d>" % self.child_type
297
298 def has_kobject(self):
299 if self.child_type not in type_env:
300 return False
301
302 return type_env[self.child_type].has_kobject()
303
304 def get_kobjects(self, addr):
305 return type_env[self.child_type].get_kobjects(addr)
306
307
308class AggregateType:
309 def __init__(self, offset, name, size):
310 self.name = name
311 self.size = size
312 self.offset = offset
313 self.members = []
314
315 def add_member(self, member):
316 self.members.append(member)
317
318 def __repr__(self):
319 return "<struct %s, with %s>" % (self.name, self.members)
320
321 def has_kobject(self):
322 result = False
323
324 bad_members = []
325
326 for member in self.members:
327 if member.has_kobject():
328 result = True
329 else:
330 bad_members.append(member)
331 # Don't need to consider this again, just remove it
332
333 for bad_member in bad_members:
334 self.members.remove(bad_member)
335
336 return result
337
338 def get_kobjects(self, addr):
339 objs = {}
340 for member in self.members:
341 objs.update(member.get_kobjects(addr))
342 return objs
343
344
345# --- helper functions for getting data from DIEs ---
346
347def die_get_spec(die):
348 if 'DW_AT_specification' not in die.attributes:
349 return None
350
351 spec_val = die.attributes["DW_AT_specification"].value
352
353 # offset of the DW_TAG_variable for the extern declaration
354 offset = spec_val + die.cu.cu_offset
355
356 return extern_env.get(offset)
357
358
359def die_get_name(die):
360 if 'DW_AT_name' not in die.attributes:
361 die = die_get_spec(die)
362 if not die:
363 return None
364
365 return die.attributes["DW_AT_name"].value.decode("utf-8")
366
367
368def die_get_type_offset(die):
369 if 'DW_AT_type' not in die.attributes:
370 die = die_get_spec(die)
371 if not die:
372 return None
373
374 return die.attributes["DW_AT_type"].value + die.cu.cu_offset
375
376
377def die_get_byte_size(die):
378 if 'DW_AT_byte_size' not in die.attributes:
379 return 0
380
381 return die.attributes["DW_AT_byte_size"].value
382
383
384def analyze_die_struct(die):
385 name = die_get_name(die) or "<anon>"
386 offset = die.offset
387 size = die_get_byte_size(die)
388
389 # Incomplete type
390 if not size:
391 return
392
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700393 if name in kobjects:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700394 type_env[offset] = KobjectType(offset, name, size)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700395 elif name in subsystems:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700396 type_env[offset] = KobjectType(offset, name, size, api=True)
Andrew Boie299ec8f2020-05-29 13:30:19 -0700397 elif name in net_sockets:
398 type_env[offset] = KobjectType(offset, "NET_SOCKET", size)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700399 else:
400 at = AggregateType(offset, name, size)
401 type_env[offset] = at
402
403 for child in die.iter_children():
404 if child.tag != "DW_TAG_member":
405 continue
406 data_member_location = child.attributes.get("DW_AT_data_member_location")
407 if not data_member_location:
408 continue
409
410 child_type = die_get_type_offset(child)
411 member_offset = data_member_location.value
412 cname = die_get_name(child) or "<anon>"
413 m = AggregateTypeMember(child.offset, cname, child_type,
414 member_offset)
415 at.add_member(m)
416
417 return
418
419
420def analyze_die_const(die):
421 type_offset = die_get_type_offset(die)
422 if not type_offset:
423 return
424
425 type_env[die.offset] = ConstType(type_offset)
426
427
428def analyze_die_array(die):
429 type_offset = die_get_type_offset(die)
430 elements = []
431
432 for child in die.iter_children():
433 if child.tag != "DW_TAG_subrange_type":
434 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700435
Wayne Ren938642c2020-07-21 16:52:09 +0800436 if "DW_AT_upper_bound" in child.attributes:
437 ub = child.attributes["DW_AT_upper_bound"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700438
Wayne Ren938642c2020-07-21 16:52:09 +0800439 if not ub.form.startswith("DW_FORM_data"):
440 continue
441
442 elements.append(ub.value + 1)
443 # in DWARF 4, e.g. ARC Metaware toolchain, DW_AT_count is used
444 # not DW_AT_upper_bound
445 elif "DW_AT_count" in child.attributes:
446 ub = child.attributes["DW_AT_count"]
447
448 if not ub.form.startswith("DW_FORM_data"):
449 continue
450
451 elements.append(ub.value)
452 else:
453 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700454
455 if not elements:
Peter Mitsisfc12f692021-10-07 15:12:43 -0400456 if type_offset in type_env:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700457 mt = type_env[type_offset]
458 if mt.has_kobject():
459 if isinstance(mt, KobjectType) and mt.name == STACK_TYPE:
460 elements.append(1)
461 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
462 else:
463 type_env[die.offset] = ArrayType(die.offset, elements, type_offset)
464
465
466def analyze_typedef(die):
467 type_offset = die_get_type_offset(die)
468
469 if type_offset not in type_env.keys():
470 return
471
472 type_env[die.offset] = type_env[type_offset]
473
474
475def unpack_pointer(elf, data, offset):
476 endian_code = "<" if elf.little_endian else ">"
477 if elf.elfclass == 32:
478 size_code = "I"
479 size = 4
480 else:
481 size_code = "Q"
482 size = 8
483
484 return struct.unpack(endian_code + size_code,
485 data[offset:offset + size])[0]
486
487
488def addr_deref(elf, addr):
489 for section in elf.iter_sections():
490 start = section['sh_addr']
491 end = start + section['sh_size']
492
493 if start <= addr < end:
494 data = section.data()
495 offset = addr - start
496 return unpack_pointer(elf, data, offset)
497
498 return 0
499
500
501def device_get_api_addr(elf, addr):
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100502 # See include/device.h for a description of struct device
503 offset = 8 if elf.elfclass == 32 else 16
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700504 return addr_deref(elf, addr + offset)
505
506
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700507def find_kobjects(elf, syms):
Andrew Boie8ce260d2020-04-24 16:24:46 -0700508 global thread_counter
509 global sys_mutex_counter
510 global futex_counter
511 global stack_counter
512
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700513 if not elf.has_dwarf_info():
514 sys.exit("ELF file has no DWARF information")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700515
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700516 app_smem_start = syms["_app_smem_start"]
517 app_smem_end = syms["_app_smem_end"]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700518
519 if "CONFIG_LINKER_USE_PINNED_SECTION" in syms and "_app_smem_pinned_start" in syms:
520 app_smem_pinned_start = syms["_app_smem_pinned_start"]
521 app_smem_pinned_end = syms["_app_smem_pinned_end"]
522 else:
523 app_smem_pinned_start = app_smem_start
524 app_smem_pinned_end = app_smem_end
525
Andrew Boie8ce260d2020-04-24 16:24:46 -0700526 user_stack_start = syms["z_user_stacks_start"]
527 user_stack_end = syms["z_user_stacks_end"]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700528
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700529 di = elf.get_dwarf_info()
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700530
Wentong Wu0bf51132020-05-21 16:49:28 +0800531 variables = []
532
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700533 # Step 1: collect all type information.
534 for CU in di.iter_CUs():
535 for die in CU.iter_DIEs():
536 # Unions are disregarded, kernel objects should never be union
537 # members since the memory is not dedicated to that object and
538 # could be something else
539 if die.tag == "DW_TAG_structure_type":
540 analyze_die_struct(die)
541 elif die.tag == "DW_TAG_const_type":
542 analyze_die_const(die)
543 elif die.tag == "DW_TAG_array_type":
544 analyze_die_array(die)
545 elif die.tag == "DW_TAG_typedef":
546 analyze_typedef(die)
547 elif die.tag == "DW_TAG_variable":
548 variables.append(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700549
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700550 # Step 2: filter type_env to only contain kernel objects, or structs
551 # and arrays of kernel objects
552 bad_offsets = []
553 for offset, type_object in type_env.items():
554 if not type_object.has_kobject():
555 bad_offsets.append(offset)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700556
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700557 for offset in bad_offsets:
558 del type_env[offset]
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700559
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700560 # Step 3: Now that we know all the types we are looking for, examine
561 # all variables
562 all_objs = {}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700563
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700564 for die in variables:
565 name = die_get_name(die)
566 if not name:
567 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700568
Tomasz Bursztyka1eedd5e2020-03-13 12:59:58 +0100569 if name.startswith("__init_sys_init"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700570 # Boot-time initialization function; not an actual device
571 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700572
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700573 type_offset = die_get_type_offset(die)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700574
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700575 # Is this a kernel object, or a structure containing kernel
576 # objects?
577 if type_offset not in type_env:
578 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700579
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700580 if "DW_AT_declaration" in die.attributes:
581 # Extern declaration, only used indirectly
582 extern_env[die.offset] = die
583 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700584
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700585 if "DW_AT_location" not in die.attributes:
586 debug_die(die,
587 "No location information for object '%s'; possibly stack allocated"
588 % name)
589 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700590
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700591 loc = die.attributes["DW_AT_location"]
Peter Mitsisfc12f692021-10-07 15:12:43 -0400592 if loc.form not in ("DW_FORM_exprloc", "DW_FORM_block1"):
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700593 debug_die(die, "kernel object '%s' unexpected location format" %
594 name)
595 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700596
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700597 opcode = loc.value[0]
598 if opcode != DW_OP_addr:
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700599
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700600 # Check if frame pointer offset DW_OP_fbreg
601 if opcode == DW_OP_fbreg:
602 debug_die(die, "kernel object '%s' found on stack" % name)
603 else:
604 debug_die(die,
605 "kernel object '%s' unexpected exprloc opcode %s" %
606 (name, hex(opcode)))
607 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700608
Carlo Caioned804ee32021-03-23 09:44:42 +0100609 if "CONFIG_64BIT" in syms:
610 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
611 (loc.value[3] << 16) | (loc.value[4] << 24) |
612 (loc.value[5] << 32) | (loc.value[6] << 40) |
613 (loc.value[7] << 48) | (loc.value[8] << 56))
614 else:
615 addr = ((loc.value[1] << 0 ) | (loc.value[2] << 8) |
616 (loc.value[3] << 16) | (loc.value[4] << 24))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700617
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700618 if addr == 0:
619 # Never linked; gc-sections deleted it
620 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700621
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700622 type_obj = type_env[type_offset]
623 objs = type_obj.get_kobjects(addr)
624 all_objs.update(objs)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700625
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700626 debug("symbol '%s' at %s contains %d object(s)"
627 % (name, hex(addr), len(objs)))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700628
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700629 # Step 4: objs is a dictionary mapping variable memory addresses to
630 # their associated type objects. Now that we have seen all variables
631 # and can properly look up API structs, convert this into a dictionary
632 # mapping variables to the C enumeration of what kernel object type it
633 # is.
634 ret = {}
635 for addr, ko in all_objs.items():
636 # API structs don't get into the gperf table
637 if ko.type_obj.api:
638 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700639
Andrew Boie455e1782020-05-29 13:22:20 -0700640 _, user_ram_allowed, _ = kobjects[ko.type_obj.name]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700641 if (not user_ram_allowed and
642 ((app_smem_start <= addr < app_smem_end)
643 or (app_smem_pinned_start <= addr < app_smem_pinned_end))):
Wentong Wu6c9d4a52020-05-21 17:13:12 +0800644 debug("object '%s' found in invalid location %s"
645 % (ko.type_obj.name, hex(addr)))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700646 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700647
Andrew Boie8ce260d2020-04-24 16:24:46 -0700648 if (ko.type_obj.name == STACK_TYPE and
649 (addr < user_stack_start or addr >= user_stack_end)):
650 debug("skip kernel-only stack at %s" % hex(addr))
651 continue
652
653 # At this point we know the object will be included in the gperf table
654 if ko.type_obj.name == "k_thread":
655 # Assign an ID for this thread object, used to track its
656 # permissions to other kernel objects
657 ko.data = thread_counter
658 thread_counter = thread_counter + 1
659 elif ko.type_obj.name == "sys_mutex":
660 ko.data = "&kernel_mutexes[%d]" % sys_mutex_counter
661 sys_mutex_counter += 1
662 elif ko.type_obj.name == "k_futex":
663 ko.data = "&futex_data[%d]" % futex_counter
664 futex_counter += 1
665 elif ko.type_obj.name == STACK_TYPE:
666 stack_counter += 1
667
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700668 if ko.type_obj.name != "device":
669 # Not a device struct so we immediately know its type
670 ko.type_name = kobject_to_enum(ko.type_obj.name)
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700671 ret[addr] = ko
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700672 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700673
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700674 # Device struct. Need to get the address of its API struct,
675 # if it has one.
676 apiaddr = device_get_api_addr(elf, addr)
677 if apiaddr not in all_objs:
678 if apiaddr == 0:
679 debug("device instance at 0x%x has no associated subsystem"
680 % addr)
681 else:
682 debug("device instance at 0x%x has unknown API 0x%x"
683 % (addr, apiaddr))
684 # API struct does not correspond to a known subsystem, skip it
685 continue
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700686
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700687 apiobj = all_objs[apiaddr]
688 ko.type_name = subsystem_to_enum(apiobj.type_obj.name)
689 ret[addr] = ko
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700690
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700691 debug("found %d kernel object instances total" % len(ret))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700692
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700693 # 1. Before python 3.7 dict order is not guaranteed. With Python
694 # 3.5 it doesn't seem random with *integer* keys but can't
695 # rely on that.
696 # 2. OrderedDict means _insertion_ order, so not enough because
697 # built from other (random!) dicts: need to _sort_ first.
698 # 3. Sorting memory address looks good.
699 return OrderedDict(sorted(ret.items()))
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700700
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700701def get_symbols(elf):
702 for section in elf.iter_sections():
703 if isinstance(section, SymbolTableSection):
704 return {sym.name: sym.entry.st_value
705 for sym in section.iter_symbols()}
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700706
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700707 raise LookupError("Could not find symbol table")
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700708
Andrew Boiefc2f7c32020-03-11 14:17:56 -0700709
710# -- GPERF generation logic
711
Andrew Boie945af952017-08-22 13:15:23 -0700712header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700713%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700714%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700715%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700716%struct-type
717%{
718#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800719#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700720#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700721#include <string.h>
722%}
Andrew Boie2dc2ecf2020-03-11 07:13:07 -0700723struct z_object;
Andrew Boie945af952017-08-22 13:15:23 -0700724"""
725
Andy Gross6042ae92018-01-22 14:26:49 -0600726# Different versions of gperf have different prototypes for the lookup
727# function, best to implement the wrapper here. The pointer value itself is
728# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500729# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700730footer = """%%
Peter Bigot2fcf7622020-05-14 05:06:08 -0500731struct z_object *z_object_gperf_find(const void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700732{
Patrik Flykt4344e272019-03-08 14:19:05 -0700733 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700734}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700735
Patrik Flykt4344e272019-03-08 14:19:05 -0700736void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700737{
738 int i;
739
740 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700741 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700742 func(&wordlist[i], context);
743 }
744 }
745}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800746
747#ifndef CONFIG_DYNAMIC_OBJECTS
Peter Bigot2fcf7622020-05-14 05:06:08 -0500748struct z_object *z_object_find(const void *obj)
Patrik Flykt4344e272019-03-08 14:19:05 -0700749 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800750
Patrik Flykt4344e272019-03-08 14:19:05 -0700751void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
752 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800753#endif
Andrew Boie945af952017-08-22 13:15:23 -0700754"""
755
756
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700757def write_gperf_table(fp, syms, objs, little_endian, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700758 fp.write(header)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700759 if sys_mutex_counter != 0:
760 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n"
761 % sys_mutex_counter)
762 for i in range(sys_mutex_counter):
Anas Nashif45a1d8a2020-04-24 11:29:17 -0400763 fp.write("Z_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700764 if i != sys_mutex_counter - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700765 fp.write(", ")
766 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700767
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700768 if futex_counter != 0:
769 fp.write("static struct z_futex_data futex_data[%d] = {\n"
770 % futex_counter)
771 for i in range(futex_counter):
Wentong Wu5611e922019-06-20 23:51:27 +0800772 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700773 if i != futex_counter - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800774 fp.write(", ")
775 fp.write("};\n")
776
Andrew Boie28be7932020-03-11 10:56:19 -0700777 metadata_names = {
778 "K_OBJ_THREAD" : "thread_id",
779 "K_OBJ_SYS_MUTEX" : "mutex",
780 "K_OBJ_FUTEX" : "futex_data"
781 }
782
783 if "CONFIG_GEN_PRIV_STACKS" in syms:
784 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_data"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700785 if stack_counter != 0:
Andrew Boie8ce260d2020-04-24 16:24:46 -0700786 # Same as K_KERNEL_STACK_ARRAY_DEFINE, but routed to a different
787 # memory section.
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500788 fp.write("static uint8_t Z_GENERIC_SECTION(.priv_stacks.noinit) "
Andrew Boie8ce260d2020-04-24 16:24:46 -0700789 " __aligned(Z_KERNEL_STACK_OBJ_ALIGN)"
790 " priv_stacks[%d][Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)];\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700791 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700792
Daniel Leungc3711b32021-03-20 12:02:59 -0700793 fp.write("static const struct z_stack_data stack_data[%d] = {\n"
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700794 % stack_counter)
Andrew Boie28be7932020-03-11 10:56:19 -0700795 counter = 0
796 for _, ko in objs.items():
797 if ko.type_name != "K_OBJ_THREAD_STACK_ELEMENT":
798 continue
799
800 # ko.data currently has the stack size. fetch the value to
801 # populate the appropriate entry in stack_data, and put
802 # a reference to the entry in stack_data into the data value
803 # instead
804 size = ko.data
805 ko.data = "&stack_data[%d]" % counter
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500806 fp.write("\t{ %d, (uint8_t *)(&priv_stacks[%d]) }"
Andrew Boie28be7932020-03-11 10:56:19 -0700807 % (size, counter))
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700808 if counter != (stack_counter - 1):
Andrew Boie28be7932020-03-11 10:56:19 -0700809 fp.write(",")
810 fp.write("\n")
811 counter += 1
812 fp.write("};\n")
813 else:
814 metadata_names["K_OBJ_THREAD_STACK_ELEMENT"] = "stack_size"
815
Andrew Boief0835672019-03-27 15:44:52 -0700816 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700817 # Setup variables for mapping thread indexes
Daniel Leunge58b6542018-08-08 11:23:16 -0700818 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
819 thread_idx_map = {}
820
821 for i in range(0, thread_max_bytes):
822 thread_idx_map[i] = 0xFF
823
Andrew Boiebca15da2017-10-15 14:17:48 -0700824 for obj_addr, ko in objs.items():
825 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700826 # pre-initialized objects fall within this memory range, they are
827 # either completely initialized at build time, or done automatically
828 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200829 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700830 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700831
Andrew Boief290ab52019-11-18 17:06:13 -0800832 if "CONFIG_64BIT" in syms:
833 format_code = "Q"
834 else:
835 format_code = "I"
836
Andrew Boieb42fe9c2020-03-12 12:44:36 -0700837 if little_endian:
Andrew Boief290ab52019-11-18 17:06:13 -0800838 endian = "<"
839 else:
840 endian = ">"
841
842 byte_str = struct.pack(endian + format_code, obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700843 fp.write("\"")
844 for byte in byte_str:
845 val = "\\x%02x" % byte
846 fp.write(val)
847
Andrew Boie78757072019-07-23 13:29:30 -0700848 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200849 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700850 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200851 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700852 flags += " | K_OBJ_FLAG_DRIVER"
853
Andrew Boief2734ab2020-03-11 06:37:42 -0700854 if ko.type_name in metadata_names:
855 tname = metadata_names[ko.type_name]
856 else:
857 tname = "unused"
858
859 fp.write("\", {}, %s, %s, { .%s = %s }\n" % (obj_type, flags,
860 tname, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700861
Daniel Leunge58b6542018-08-08 11:23:16 -0700862 if obj_type == "K_OBJ_THREAD":
863 idx = math.floor(ko.data / 8)
864 bit = ko.data % 8
865 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
866
Andrew Boie945af952017-08-22 13:15:23 -0700867 fp.write(footer)
868
Daniel Leunge58b6542018-08-08 11:23:16 -0700869 # Generate the array of already mapped thread indexes
870 fp.write('\n')
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500871 fp.write('uint8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
Daniel Leunge58b6542018-08-08 11:23:16 -0700872
873 for i in range(0, thread_max_bytes):
874 fp.write(' 0x%x, ' % (thread_idx_map[i]))
875
876 fp.write('};\n')
877
Andrew Boie945af952017-08-22 13:15:23 -0700878
Leandro Pereirac2003672018-04-04 13:50:32 -0700879driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700880#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 -0700881"""
882
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500883
Leandro Pereirac2003672018-04-04 13:50:32 -0700884def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700885 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
886 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700887
Andrew Boie8345e5e2018-05-04 15:57:57 -0700888 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
889 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
890 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
891 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700892
893 for subsystem in subsystems:
894 subsystem = subsystem.replace("_driver_api", "")
895
896 fp.write(driver_macro_tpl % {
897 "driver_lower": subsystem.lower(),
898 "driver_upper": subsystem.upper(),
899 })
900
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700901 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700902
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700903
904def write_kobj_types_output(fp):
905 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700906 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700907 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700908 if kobj == "device":
909 continue
910
Andrew Boie09c22cc2018-06-27 10:25:45 -0700911 if dep:
912 fp.write("#ifdef %s\n" % dep)
913
Andrew Boief20efcf2018-05-23 10:57:39 -0700914 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700915
Andrew Boie09c22cc2018-06-27 10:25:45 -0700916 if dep:
917 fp.write("#endif\n")
918
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700919 fp.write("/* Driver subsystems */\n")
920 for subsystem in subsystems:
921 subsystem = subsystem.replace("_driver_api", "").upper()
922 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
923
924
925def write_kobj_otype_output(fp):
926 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700927 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700928 dep, _, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700929 if kobj == "device":
930 continue
931
Andrew Boie09c22cc2018-06-27 10:25:45 -0700932 if dep:
933 fp.write("#ifdef %s\n" % dep)
934
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500935 fp.write('case %s: ret = "%s"; break;\n' %
936 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700937 if dep:
938 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700939
940 fp.write("/* Driver subsystems */\n")
941 for subsystem in subsystems:
942 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700943 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700944 subsystem.upper(),
945 subsystem
946 ))
947
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500948
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700949def write_kobj_size_output(fp):
950 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700951 for kobj, obj_info in kobjects.items():
Andrew Boie455e1782020-05-29 13:22:20 -0700952 dep, _, alloc = obj_info
953
954 if not alloc:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700955 continue
956
Andrew Boie09c22cc2018-06-27 10:25:45 -0700957 if dep:
958 fp.write("#ifdef %s\n" % dep)
959
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700960 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500961 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700962 if dep:
963 fp.write("#endif\n")
964
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700965
Corey Whartonccd15df2020-02-29 14:51:42 -0800966def parse_subsystems_list_file(path):
967 with open(path, "r") as fp:
968 subsys_list = json.load(fp)
Andrew Boie59601192020-05-29 13:24:51 -0700969 subsystems.extend(subsys_list["__subsystem"])
Andrew Boie299ec8f2020-05-29 13:30:19 -0700970 net_sockets.extend(subsys_list["__net_socket"])
Corey Whartonccd15df2020-02-29 14:51:42 -0800971
Andrew Boie945af952017-08-22 13:15:23 -0700972def parse_args():
973 global args
974
Anas Nashif72565532017-12-12 08:19:25 -0500975 parser = argparse.ArgumentParser(
976 description=__doc__,
977 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700978
Leandro Pereirac2003672018-04-04 13:50:32 -0700979 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500980 help="Input zephyr ELF binary")
981 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700982 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500983 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700984 parser.add_argument(
985 "-V", "--validation-output", required=False,
986 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700987 parser.add_argument(
988 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700989 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700990 parser.add_argument(
991 "-S", "--kobj-otype-output", required=False,
992 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700993 parser.add_argument(
994 "-Z", "--kobj-size-output", required=False,
995 help="Output case statements for obj_size_get()")
Corey Whartonccd15df2020-02-29 14:51:42 -0800996 parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
997 help='''Specifies a file with a JSON encoded list of subsystem names to append to
998 the driver subsystems list. Can be specified multiple times:
999 -i file1 -i file2 ...''')
1000
Andrew Boie945af952017-08-22 13:15:23 -07001001 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -05001002 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -07001003 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +01001004 if "VERBOSE" in os.environ:
1005 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -07001006
1007
1008def main():
1009 parse_args()
1010
Corey Whartonccd15df2020-02-29 14:51:42 -08001011 if args.include_subsystem_list is not None:
1012 for list_file in args.include_subsystem_list:
1013 parse_subsystems_list_file(list_file)
1014
Leandro Pereirac2003672018-04-04 13:50:32 -07001015 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -08001016 assert args.kernel, "--kernel ELF required for --gperf-output"
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001017 elf = ELFFile(open(args.kernel, "rb"))
1018 syms = get_symbols(elf)
Leandro Pereirac2003672018-04-04 13:50:32 -07001019 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001020 objs = find_kobjects(elf, syms)
Marc Herbertf78288b2019-03-05 14:31:44 -08001021 if not objs:
1022 sys.stderr.write("WARNING: zero kobject found in %s\n"
1023 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -07001024
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001025 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +02001026 sys.exit("Too many thread objects ({})\n"
1027 "Increase CONFIG_MAX_THREAD_BYTES to {}"
1028 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -07001029
Leandro Pereirac2003672018-04-04 13:50:32 -07001030 with open(args.gperf_output, "w") as fp:
Andrew Boieb42fe9c2020-03-12 12:44:36 -07001031 write_gperf_table(fp, syms, objs, elf.little_endian,
Leandro Pereirac2003672018-04-04 13:50:32 -07001032 syms["_static_kernel_objects_begin"],
1033 syms["_static_kernel_objects_end"])
1034
1035 if args.validation_output:
1036 with open(args.validation_output, "w") as fp:
1037 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -05001038
Leandro Pereira39dc7d02018-04-05 13:59:33 -07001039 if args.kobj_types_output:
1040 with open(args.kobj_types_output, "w") as fp:
1041 write_kobj_types_output(fp)
1042
1043 if args.kobj_otype_output:
1044 with open(args.kobj_otype_output, "w") as fp:
1045 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -07001046
Andrew Boie47fa8eb2018-05-16 10:11:17 -07001047 if args.kobj_size_output:
1048 with open(args.kobj_size_output, "w") as fp:
1049 write_kobj_size_output(fp)
1050
Anas Nashif7a08b2b2018-09-16 14:54:44 -05001051
Andrew Boie945af952017-08-22 13:15:23 -07001052if __name__ == "__main__":
1053 main()