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