Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (c) 2017-2018 Linaro |
| 4 | # |
| 5 | # SPDX-License-Identifier: Apache-2.0 |
| 6 | |
| 7 | import sys |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 8 | import os |
| 9 | import struct |
| 10 | from distutils.version import LooseVersion |
| 11 | |
Marc Herbert | f78288b | 2019-03-05 14:31:44 -0800 | [diff] [blame] | 12 | from collections import OrderedDict |
| 13 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 14 | import elftools |
| 15 | from elftools.elf.elffile import ELFFile |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 16 | from elftools.elf.sections import SymbolTableSection |
| 17 | |
| 18 | if LooseVersion(elftools.__version__) < LooseVersion('0.24'): |
| 19 | sys.stderr.write("pyelftools is out of date, need version 0.24 or later\n") |
| 20 | sys.exit(1) |
| 21 | |
| 22 | |
| 23 | def subsystem_to_enum(subsys): |
| 24 | return "K_OBJ_DRIVER_" + subsys[:-11].upper() |
| 25 | |
| 26 | |
Andrew Boie | f20efcf | 2018-05-23 10:57:39 -0700 | [diff] [blame] | 27 | def kobject_to_enum(kobj): |
| 28 | if kobj.startswith("k_") or kobj.startswith("_k_"): |
| 29 | name = kobj[2:] |
| 30 | else: |
| 31 | name = kobj |
| 32 | |
| 33 | return "K_OBJ_%s" % name.upper() |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 34 | |
| 35 | |
| 36 | DW_OP_addr = 0x3 |
| 37 | DW_OP_fbreg = 0x91 |
| 38 | STACK_TYPE = "_k_thread_stack_element" |
| 39 | thread_counter = 0 |
Andrew Boie | f083567 | 2019-03-27 15:44:52 -0700 | [diff] [blame] | 40 | sys_mutex_counter = 0 |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 41 | |
| 42 | # Global type environment. Populated by pass 1. |
| 43 | type_env = {} |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 44 | extern_env = {} |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 45 | kobjects = {} |
| 46 | subsystems = {} |
| 47 | |
| 48 | # --- debug stuff --- |
| 49 | |
| 50 | scr = os.path.basename(sys.argv[0]) |
| 51 | |
| 52 | # --- type classes ---- |
| 53 | |
| 54 | |
| 55 | class KobjectInstance: |
| 56 | def __init__(self, type_obj, addr): |
| 57 | global thread_counter |
Andrew Boie | f083567 | 2019-03-27 15:44:52 -0700 | [diff] [blame] | 58 | global sys_mutex_counter |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 59 | |
| 60 | self.addr = addr |
| 61 | self.type_obj = type_obj |
| 62 | |
| 63 | # Type name determined later since drivers needs to look at the |
| 64 | # API struct address |
| 65 | self.type_name = None |
| 66 | |
| 67 | if self.type_obj.name == "k_thread": |
| 68 | # Assign an ID for this thread object, used to track its |
| 69 | # permissions to other kernel objects |
| 70 | self.data = thread_counter |
| 71 | thread_counter = thread_counter + 1 |
Andrew Boie | f083567 | 2019-03-27 15:44:52 -0700 | [diff] [blame] | 72 | elif self.type_obj.name == "sys_mutex": |
| 73 | self.data = "(u32_t)(&kernel_mutexes[%d])" % sys_mutex_counter |
| 74 | sys_mutex_counter += 1 |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 75 | else: |
| 76 | self.data = 0 |
| 77 | |
| 78 | |
| 79 | class KobjectType: |
| 80 | def __init__(self, offset, name, size, api=False): |
| 81 | self.name = name |
| 82 | self.size = size |
| 83 | self.offset = offset |
| 84 | self.api = api |
| 85 | |
| 86 | def __repr__(self): |
| 87 | return "<kobject %s>" % self.name |
| 88 | |
| 89 | def has_kobject(self): |
| 90 | return True |
| 91 | |
| 92 | def get_kobjects(self, addr): |
| 93 | return {addr: KobjectInstance(self, addr)} |
| 94 | |
| 95 | |
| 96 | class ArrayType: |
| 97 | def __init__(self, offset, elements, member_type): |
| 98 | self.elements = elements |
| 99 | self.member_type = member_type |
| 100 | self.offset = offset |
| 101 | |
| 102 | def __repr__(self): |
Ulf Magnusson | 7ffd628 | 2019-03-20 21:56:09 +0100 | [diff] [blame] | 103 | return "<array of %d>" % self.member_type |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 104 | |
| 105 | def has_kobject(self): |
| 106 | if self.member_type not in type_env: |
| 107 | return False |
| 108 | |
| 109 | return type_env[self.member_type].has_kobject() |
| 110 | |
| 111 | def get_kobjects(self, addr): |
| 112 | mt = type_env[self.member_type] |
| 113 | |
| 114 | # Stacks are arrays of _k_stack_element_t but we want to treat |
| 115 | # the whole array as one kernel object (a thread stack) |
| 116 | # Data value gets set to size of entire region |
| 117 | if isinstance(mt, KobjectType) and mt.name == STACK_TYPE: |
| 118 | # An array of stacks appears as a multi-dimensional array. |
| 119 | # The last size is the size of each stack. We need to track |
| 120 | # each stack within the array, not as one huge stack object. |
| 121 | *dimensions, stacksize = self.elements |
| 122 | num_members = 1 |
| 123 | for e in dimensions: |
| 124 | num_members = num_members * e |
| 125 | |
| 126 | ret = {} |
| 127 | for i in range(num_members): |
| 128 | a = addr + (i * stacksize) |
| 129 | o = mt.get_kobjects(a) |
| 130 | o[a].data = stacksize |
| 131 | ret.update(o) |
| 132 | return ret |
| 133 | |
| 134 | objs = {} |
| 135 | |
| 136 | # Multidimensional array flattened out |
| 137 | num_members = 1 |
| 138 | for e in self.elements: |
| 139 | num_members = num_members * e |
| 140 | |
| 141 | for i in range(num_members): |
| 142 | objs.update(mt.get_kobjects(addr + (i * mt.size))) |
| 143 | return objs |
| 144 | |
| 145 | |
| 146 | class AggregateTypeMember: |
| 147 | def __init__(self, offset, member_name, member_type, member_offset): |
| 148 | self.member_name = member_name |
| 149 | self.member_type = member_type |
Andrew Boie | e144a68 | 2018-05-21 15:51:31 -0700 | [diff] [blame] | 150 | if isinstance(member_offset, list): |
ruuddw | 8364b22 | 2018-05-25 15:53:27 +0200 | [diff] [blame] | 151 | # DWARF v2, location encoded as set of operations |
| 152 | # only "DW_OP_plus_uconst" with ULEB128 argument supported |
Anas Nashif | 6af68b3 | 2018-09-16 14:52:34 -0500 | [diff] [blame] | 153 | if member_offset[0] == 0x23: |
ruuddw | 8364b22 | 2018-05-25 15:53:27 +0200 | [diff] [blame] | 154 | self.member_offset = member_offset[1] & 0x7f |
| 155 | for i in range(1, len(member_offset)-1): |
Ulf Magnusson | ba312fe | 2019-03-20 19:30:29 +0100 | [diff] [blame] | 156 | if member_offset[i] & 0x80: |
Anas Nashif | 6af68b3 | 2018-09-16 14:52:34 -0500 | [diff] [blame] | 157 | self.member_offset += ( |
| 158 | member_offset[i+1] & 0x7f) << i*7 |
ruuddw | 8364b22 | 2018-05-25 15:53:27 +0200 | [diff] [blame] | 159 | else: |
Andrew Boie | cf91f8c | 2019-03-27 13:40:51 -0700 | [diff] [blame] | 160 | raise Exception("not yet supported location operation (%s:%d:%d)" % |
| 161 | (self.member_name, self.member_type, member_offset[0])) |
Andrew Boie | e144a68 | 2018-05-21 15:51:31 -0700 | [diff] [blame] | 162 | else: |
| 163 | self.member_offset = member_offset |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 164 | |
| 165 | def __repr__(self): |
| 166 | return "<member %s, type %d, offset %d>" % ( |
| 167 | self.member_name, self.member_type, self.member_offset) |
| 168 | |
| 169 | def has_kobject(self): |
| 170 | if self.member_type not in type_env: |
| 171 | return False |
| 172 | |
| 173 | return type_env[self.member_type].has_kobject() |
| 174 | |
| 175 | def get_kobjects(self, addr): |
| 176 | mt = type_env[self.member_type] |
| 177 | return mt.get_kobjects(addr + self.member_offset) |
| 178 | |
| 179 | |
| 180 | class ConstType: |
| 181 | def __init__(self, child_type): |
| 182 | self.child_type = child_type |
| 183 | |
| 184 | def __repr__(self): |
| 185 | return "<const %d>" % self.child_type |
| 186 | |
| 187 | def has_kobject(self): |
| 188 | if self.child_type not in type_env: |
| 189 | return False |
| 190 | |
| 191 | return type_env[self.child_type].has_kobject() |
| 192 | |
| 193 | def get_kobjects(self, addr): |
| 194 | return type_env[self.child_type].get_kobjects(addr) |
| 195 | |
| 196 | |
| 197 | class AggregateType: |
| 198 | def __init__(self, offset, name, size): |
| 199 | self.name = name |
| 200 | self.size = size |
| 201 | self.offset = offset |
| 202 | self.members = [] |
| 203 | |
| 204 | def add_member(self, member): |
| 205 | self.members.append(member) |
| 206 | |
| 207 | def __repr__(self): |
| 208 | return "<struct %s, with %s>" % (self.name, self.members) |
| 209 | |
| 210 | def has_kobject(self): |
| 211 | result = False |
| 212 | |
| 213 | bad_members = [] |
| 214 | |
| 215 | for member in self.members: |
| 216 | if member.has_kobject(): |
| 217 | result = True |
| 218 | else: |
| 219 | bad_members.append(member) |
| 220 | # Don't need to consider this again, just remove it |
| 221 | |
| 222 | for bad_member in bad_members: |
| 223 | self.members.remove(bad_member) |
| 224 | |
| 225 | return result |
| 226 | |
| 227 | def get_kobjects(self, addr): |
| 228 | objs = {} |
| 229 | for member in self.members: |
| 230 | objs.update(member.get_kobjects(addr)) |
| 231 | return objs |
| 232 | |
| 233 | |
| 234 | # --- helper functions for getting data from DIEs --- |
| 235 | |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 236 | def die_get_spec(die): |
| 237 | if 'DW_AT_specification' not in die.attributes: |
| 238 | return None |
| 239 | |
| 240 | spec_val = die.attributes["DW_AT_specification"].value |
| 241 | |
| 242 | # offset of the DW_TAG_variable for the extern declaration |
| 243 | offset = spec_val + die.cu.cu_offset |
| 244 | |
| 245 | return extern_env.get(offset) |
| 246 | |
| 247 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 248 | def die_get_name(die): |
| 249 | if 'DW_AT_name' not in die.attributes: |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 250 | die = die_get_spec(die) |
| 251 | if not die: |
| 252 | return None |
| 253 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 254 | return die.attributes["DW_AT_name"].value.decode("utf-8") |
| 255 | |
| 256 | |
| 257 | def die_get_type_offset(die): |
| 258 | if 'DW_AT_type' not in die.attributes: |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 259 | die = die_get_spec(die) |
| 260 | if not die: |
| 261 | return None |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 262 | |
| 263 | return die.attributes["DW_AT_type"].value + die.cu.cu_offset |
| 264 | |
| 265 | |
| 266 | def die_get_byte_size(die): |
| 267 | if 'DW_AT_byte_size' not in die.attributes: |
| 268 | return 0 |
| 269 | |
| 270 | return die.attributes["DW_AT_byte_size"].value |
| 271 | |
| 272 | |
| 273 | def analyze_die_struct(die): |
| 274 | name = die_get_name(die) or "<anon>" |
| 275 | offset = die.offset |
| 276 | size = die_get_byte_size(die) |
| 277 | |
| 278 | # Incomplete type |
| 279 | if not size: |
| 280 | return |
| 281 | |
| 282 | if name in kobjects: |
| 283 | type_env[offset] = KobjectType(offset, name, size) |
| 284 | elif name in subsystems: |
| 285 | type_env[offset] = KobjectType(offset, name, size, api=True) |
| 286 | else: |
| 287 | at = AggregateType(offset, name, size) |
| 288 | type_env[offset] = at |
| 289 | |
| 290 | for child in die.iter_children(): |
| 291 | if child.tag != "DW_TAG_member": |
| 292 | continue |
| 293 | child_type = die_get_type_offset(child) |
| 294 | member_offset = \ |
| 295 | child.attributes["DW_AT_data_member_location"].value |
| 296 | cname = die_get_name(child) or "<anon>" |
| 297 | m = AggregateTypeMember(child.offset, cname, child_type, |
| 298 | member_offset) |
| 299 | at.add_member(m) |
| 300 | |
| 301 | return |
| 302 | |
| 303 | |
| 304 | def analyze_die_const(die): |
| 305 | type_offset = die_get_type_offset(die) |
| 306 | if not type_offset: |
| 307 | return |
| 308 | |
| 309 | type_env[die.offset] = ConstType(type_offset) |
| 310 | |
| 311 | |
| 312 | def analyze_die_array(die): |
| 313 | type_offset = die_get_type_offset(die) |
| 314 | elements = [] |
| 315 | |
| 316 | for child in die.iter_children(): |
| 317 | if child.tag != "DW_TAG_subrange_type": |
| 318 | continue |
| 319 | if "DW_AT_upper_bound" not in child.attributes: |
| 320 | continue |
| 321 | |
| 322 | ub = child.attributes["DW_AT_upper_bound"] |
| 323 | if not ub.form.startswith("DW_FORM_data"): |
| 324 | continue |
| 325 | |
| 326 | elements.append(ub.value + 1) |
| 327 | |
| 328 | if not elements: |
| 329 | return |
| 330 | |
| 331 | type_env[die.offset] = ArrayType(die.offset, elements, type_offset) |
| 332 | |
| 333 | |
| 334 | def addr_deref(elf, addr): |
| 335 | for section in elf.iter_sections(): |
| 336 | start = section['sh_addr'] |
| 337 | end = start + section['sh_size'] |
| 338 | |
| 339 | if addr >= start and addr < end: |
| 340 | data = section.data() |
| 341 | offset = addr - start |
| 342 | return struct.unpack("<I" if elf.little_endian else ">I", |
| 343 | data[offset:offset + 4])[0] |
| 344 | |
| 345 | return 0 |
| 346 | |
| 347 | |
| 348 | def device_get_api_addr(elf, addr): |
| 349 | return addr_deref(elf, addr + 4) |
| 350 | |
| 351 | |
| 352 | def get_filename_lineno(die): |
| 353 | lp_header = die.dwarfinfo.line_program_for_CU(die.cu).header |
| 354 | files = lp_header["file_entry"] |
| 355 | includes = lp_header["include_directory"] |
| 356 | |
| 357 | fileinfo = files[die.attributes["DW_AT_decl_file"].value - 1] |
| 358 | filename = fileinfo.name.decode("utf-8") |
| 359 | filedir = includes[fileinfo.dir_index - 1].decode("utf-8") |
| 360 | |
| 361 | path = os.path.join(filedir, filename) |
| 362 | lineno = die.attributes["DW_AT_decl_line"].value |
| 363 | return (path, lineno) |
| 364 | |
| 365 | |
| 366 | class ElfHelper: |
| 367 | |
| 368 | def __init__(self, filename, verbose, kobjs, subs): |
| 369 | self.verbose = verbose |
| 370 | self.fp = open(filename, "rb") |
| 371 | self.elf = ELFFile(self.fp) |
| 372 | self.little_endian = self.elf.little_endian |
| 373 | global kobjects |
| 374 | global subsystems |
| 375 | kobjects = kobjs |
| 376 | subsystems = subs |
| 377 | |
| 378 | def find_kobjects(self, syms): |
| 379 | if not self.elf.has_dwarf_info(): |
| 380 | sys.stderr.write("ELF file has no DWARF information\n") |
| 381 | sys.exit(1) |
| 382 | |
| 383 | kram_start = syms["__kernel_ram_start"] |
| 384 | kram_end = syms["__kernel_ram_end"] |
| 385 | krom_start = syms["_image_rom_start"] |
| 386 | krom_end = syms["_image_rom_end"] |
| 387 | |
| 388 | di = self.elf.get_dwarf_info() |
| 389 | |
| 390 | variables = [] |
| 391 | |
| 392 | # Step 1: collect all type information. |
| 393 | for CU in di.iter_CUs(): |
Ulf Magnusson | 12ba9df | 2019-03-19 19:28:24 +0100 | [diff] [blame] | 394 | for die in CU.iter_DIEs(): |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 395 | # Unions are disregarded, kernel objects should never be union |
| 396 | # members since the memory is not dedicated to that object and |
| 397 | # could be something else |
| 398 | if die.tag == "DW_TAG_structure_type": |
| 399 | analyze_die_struct(die) |
| 400 | elif die.tag == "DW_TAG_const_type": |
| 401 | analyze_die_const(die) |
| 402 | elif die.tag == "DW_TAG_array_type": |
| 403 | analyze_die_array(die) |
| 404 | elif die.tag == "DW_TAG_variable": |
| 405 | variables.append(die) |
| 406 | |
| 407 | # Step 2: filter type_env to only contain kernel objects, or structs |
| 408 | # and arrays of kernel objects |
| 409 | bad_offsets = [] |
| 410 | for offset, type_object in type_env.items(): |
| 411 | if not type_object.has_kobject(): |
| 412 | bad_offsets.append(offset) |
| 413 | |
| 414 | for offset in bad_offsets: |
| 415 | del type_env[offset] |
| 416 | |
| 417 | # Step 3: Now that we know all the types we are looking for, examine |
| 418 | # all variables |
| 419 | all_objs = {} |
| 420 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 421 | for die in variables: |
| 422 | name = die_get_name(die) |
| 423 | if not name: |
| 424 | continue |
| 425 | |
Andrew Boie | e48bc56 | 2018-12-03 10:13:39 -0800 | [diff] [blame] | 426 | if name.startswith("__device_sys_init"): |
| 427 | # Boot-time initialization function; not an actual device |
| 428 | continue |
| 429 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 430 | type_offset = die_get_type_offset(die) |
| 431 | |
| 432 | # Is this a kernel object, or a structure containing kernel |
| 433 | # objects? |
| 434 | if type_offset not in type_env: |
| 435 | continue |
| 436 | |
| 437 | if "DW_AT_declaration" in die.attributes: |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 438 | # Extern declaration, only used indirectly |
| 439 | extern_env[die.offset] = die |
| 440 | continue |
| 441 | |
| 442 | if "DW_AT_location" not in die.attributes: |
| 443 | self.debug_die( |
| 444 | die, |
| 445 | "No location information for object '%s'; possibly" |
| 446 | " stack allocated" % name) |
| 447 | continue |
| 448 | |
| 449 | loc = die.attributes["DW_AT_location"] |
| 450 | if loc.form != "DW_FORM_exprloc" and \ |
| 451 | loc.form != "DW_FORM_block1": |
| 452 | self.debug_die( |
| 453 | die, |
| 454 | "kernel object '%s' unexpected location format" % |
| 455 | name) |
| 456 | continue |
| 457 | |
| 458 | opcode = loc.value[0] |
| 459 | if opcode != DW_OP_addr: |
| 460 | |
| 461 | # Check if frame pointer offset DW_OP_fbreg |
| 462 | if opcode == DW_OP_fbreg: |
| 463 | self.debug_die(die, "kernel object '%s' found on stack" % |
Anas Nashif | 6af68b3 | 2018-09-16 14:52:34 -0500 | [diff] [blame] | 464 | name) |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 465 | else: |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 466 | self.debug_die( |
| 467 | die, |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 468 | "kernel object '%s' unexpected exprloc opcode %s" % |
| 469 | (name, hex(opcode))) |
| 470 | continue |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 471 | |
Andrew Boie | 577d5dd | 2018-05-16 15:52:37 -0700 | [diff] [blame] | 472 | addr = (loc.value[1] | (loc.value[2] << 8) | |
| 473 | (loc.value[3] << 16) | (loc.value[4] << 24)) |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 474 | |
| 475 | if addr == 0: |
| 476 | # Never linked; gc-sections deleted it |
| 477 | continue |
| 478 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 479 | type_obj = type_env[type_offset] |
| 480 | objs = type_obj.get_kobjects(addr) |
| 481 | all_objs.update(objs) |
| 482 | |
Anas Nashif | 6af68b3 | 2018-09-16 14:52:34 -0500 | [diff] [blame] | 483 | self.debug("symbol '%s' at %s contains %d object(s)" |
| 484 | % (name, hex(addr), len(objs))) |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 485 | |
| 486 | # Step 4: objs is a dictionary mapping variable memory addresses to |
| 487 | # their associated type objects. Now that we have seen all variables |
| 488 | # and can properly look up API structs, convert this into a dictionary |
| 489 | # mapping variables to the C enumeration of what kernel object type it |
| 490 | # is. |
| 491 | ret = {} |
| 492 | for addr, ko in all_objs.items(): |
| 493 | # API structs don't get into the gperf table |
| 494 | if ko.type_obj.api: |
| 495 | continue |
| 496 | |
Andrew Boie | c235e16 | 2019-03-27 14:27:24 -0700 | [diff] [blame] | 497 | _, user_ram_allowed = kobjects[ko.type_obj.name] |
| 498 | if (not user_ram_allowed and |
| 499 | (addr < kram_start or addr >= kram_end) and |
| 500 | (addr < krom_start or addr >= krom_end)): |
| 501 | |
| 502 | self.debug_die(die, |
| 503 | "object '%s' found in invalid location %s" |
| 504 | % (name, hex(addr))) |
| 505 | continue |
| 506 | |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 507 | if ko.type_obj.name != "device": |
| 508 | # Not a device struct so we immediately know its type |
| 509 | ko.type_name = kobject_to_enum(ko.type_obj.name) |
| 510 | ret[addr] = ko |
| 511 | continue |
| 512 | |
| 513 | # Device struct. Need to get the address of its API struct, |
| 514 | # if it has one. |
| 515 | apiaddr = device_get_api_addr(self.elf, addr) |
| 516 | if apiaddr not in all_objs: |
Andrew Boie | c7b7363 | 2018-12-03 08:37:27 -0800 | [diff] [blame] | 517 | if apiaddr == 0: |
| 518 | self.debug("device instance at 0x%x has no associated subsystem" |
Ulf Magnusson | d831415 | 2019-03-22 00:14:40 +0100 | [diff] [blame] | 519 | % addr) |
Andrew Boie | c7b7363 | 2018-12-03 08:37:27 -0800 | [diff] [blame] | 520 | else: |
| 521 | self.debug("device instance at 0x%x has unknown API 0x%x" |
Ulf Magnusson | d831415 | 2019-03-22 00:14:40 +0100 | [diff] [blame] | 522 | % (addr, apiaddr)) |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 523 | # API struct does not correspond to a known subsystem, skip it |
| 524 | continue |
| 525 | |
| 526 | apiobj = all_objs[apiaddr] |
| 527 | ko.type_name = subsystem_to_enum(apiobj.type_obj.name) |
| 528 | ret[addr] = ko |
| 529 | |
| 530 | self.debug("found %d kernel object instances total" % len(ret)) |
Marc Herbert | f78288b | 2019-03-05 14:31:44 -0800 | [diff] [blame] | 531 | |
| 532 | # 1. Before python 3.7 dict order is not guaranteed. With Python |
| 533 | # 3.5 it doesn't seem random with *integer* keys but can't |
| 534 | # rely on that. |
| 535 | # 2. OrderedDict means _insertion_ order, so not enough because |
| 536 | # built from other (random!) dicts: need to _sort_ first. |
| 537 | # 3. Sorting memory address looks good. |
| 538 | return OrderedDict(sorted(ret.items())) |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 539 | |
| 540 | def get_symbols(self): |
| 541 | for section in self.elf.iter_sections(): |
| 542 | if isinstance(section, SymbolTableSection): |
Ulf Magnusson | 425998b | 2019-03-20 20:24:21 +0100 | [diff] [blame] | 543 | return {sym.name: sym.entry.st_value |
| 544 | for sym in section.iter_symbols()} |
Andy Gross | 826389a | 2018-01-22 14:09:48 -0600 | [diff] [blame] | 545 | |
| 546 | raise LookupError("Could not find symbol table") |
| 547 | |
| 548 | def debug(self, text): |
| 549 | if not self.verbose: |
| 550 | return |
| 551 | sys.stdout.write(scr + ": " + text + "\n") |
| 552 | |
| 553 | def error(self, text): |
| 554 | sys.stderr.write("%s ERROR: %s\n" % (scr, text)) |
| 555 | sys.exit(1) |
| 556 | |
| 557 | def debug_die(self, die, text): |
| 558 | fn, ln = get_filename_lineno(die) |
| 559 | |
| 560 | self.debug(str(die)) |
| 561 | self.debug("File '%s', line %d:" % (fn, ln)) |
| 562 | self.debug(" %s" % text) |
| 563 | |
| 564 | def get_thread_counter(self): |
| 565 | return thread_counter |
Andrew Boie | f083567 | 2019-03-27 15:44:52 -0700 | [diff] [blame] | 566 | |
| 567 | def get_sys_mutex_counter(self): |
| 568 | return sys_mutex_counter |