1# coding=utf-8 2# 3# %CopyrightBegin% 4# 5# Copyright Ericsson AB 2013-2021. All Rights Reserved. 6# 7# Licensed under the Apache License, Version 2.0 (the "License"); 8# you may not use this file except in compliance with the License. 9# You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, software 14# distributed under the License is distributed on an "AS IS" BASIS, 15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16# See the License for the specific language governing permissions and 17# limitations under the License. 18# 19# %CopyrightEnd% 20# 21# 22# This script was orinally written by Anthony Ramine (aka nox) in 2013. 23# A lot of things have changed since then, but the same base remains. 24# 25 26import re 27import lldb 28import shlex 29 30unquoted_atom_re = re.compile(u'^[a-zß-öø-ÿ][a-zA-Zß-öø-ÿ0-9@]*$') 31code_pointers = {} 32 33def __lldb_init_module(debugger, internal_dict): 34 debugger.HandleCommand('type format add -f hex Eterm') 35 debugger.HandleCommand('type format add -f hex BeamInstr') 36 debugger.HandleCommand('type summary add -F etp.eterm_summary Eterm') 37 debugger.HandleCommand('command script add -f etp.processes_cmd etp-processes') 38 debugger.HandleCommand('command script add -f etp.process_info_cmd etp-process-info') 39 debugger.HandleCommand('command script add -f etp.stacktrace_cmd etp-stacktrace') 40 debugger.HandleCommand('command script add -f etp.stackdump_cmd etp-stackdump') 41 debugger.HandleCommand('command script add -f etp.eterm_cmd etp') 42 43#################################### 44## Print all processes in the system 45#################################### 46def processes_cmd(debugger, command, result, internal_dict): 47 target = debugger.GetSelectedTarget() 48 init(target) 49 proc = erts_proc(target) 50 proc_r_o = proc.GetChildMemberWithName('r').GetChildMemberWithName('o') 51 proc_max_ix = proc_r_o.GetChildMemberWithName('max') 52 proc_tab = proc_r_o.GetChildMemberWithName('tab').Cast(ProcessPtrPtr(target)) 53 proc_cnt = atomic_value(proc.GetChildMemberWithName('vola').GetChildMemberWithName('tile').GetChildMemberWithName('count')) 54 invalid_proc = global_var('erts_invalid_process', target).address_of 55 for proc_ix in range(0, proc_max_ix.unsigned): 56 proc = offset(proc_ix, proc_tab).deref 57 if proc.unsigned != 0 and proc.unsigned != invalid_proc.unsigned: 58 print('---') 59 print(' Pix: %d' % proc_ix) 60 process_info(proc) 61 proc_cnt -= 1 62 if proc_cnt == 0: 63 break 64 65############################################ 66## Print process-info about a single process 67############################################ 68def process_info_cmd(debugger, command, result, internal_dict): 69 target = debugger.GetSelectedTarget() 70 init(target) 71 proc = target.process.selected_thread.GetSelectedFrame().EvaluateExpression(command).Cast(ProcessPtr(target)) 72 process_info(proc) 73 74def process_info(proc): 75 print(' Pid: %s' % eterm(proc.GetChildMemberWithName('common').GetChildMemberWithName('id'))) 76 print(' State: %s' % process_state(proc)) 77 print(' Flags: %s' % process_flags(proc)) 78 print_process_reg_name(proc) 79 current = proc.GetChildMemberWithName('current') 80 if current.unsigned != 0 and atomic_value(proc.GetChildMemberWithName('state')) & 0x800 == 0: 81 print(' Current function: %s' % mfa(current)) 82 else: 83 print(' Current function: %s' % 'unknown') 84 i = proc.GetChildMemberWithName('i') 85 if i.unsigned != 0: 86 print(' I: %s' % eterm(i)) 87 else: 88 print(' I: %s' % 'unknown') 89 print(' Pointer: %#x' % proc.unsigned) 90 91def print_process_reg_name(proc): 92 state = proc.GetChildMemberWithName('state').unsigned 93 if (state & 0x800) == 0: 94 # Not exiting. 95 reg = proc.GetChildMemberWithName('common').GetChildMemberWithName('u').GetChildMemberWithName('alive').GetChildMemberWithName('reg') 96 if reg.unsigned != 0: 97 print(' Registered name: %s' % eterm(reg.GetChildMemberWithName('name'))) 98 99def process_state(proc): 100 state = proc.GetChildMemberWithName('state').unsigned 101 res = '' 102 if state & 0x80000000: 103 res += "GARBAGE<0x80000000> | " 104 if state & 0x40000000: 105 res += "dirty-running-sys | " 106 if state & 0x20000000: 107 res += "dirty-running | " 108 if state & 0x10000000: 109 res += "dirty-active-sys | " 110 if state & 0x8000000: 111 res += "dirty-io-proc | " 112 if state & 0x4000000: 113 res += "dirty-cpu-proc | " 114 if state & 0x2000000: 115 res += "sig-q | " 116 if state & 0x1000000: 117 res += "off-heap-msgq | " 118 if state & 0x800000: 119 res += "delayed-sys | " 120 if state & 0x400000: 121 res += "proxy | " 122 proxy_process = True 123 else: 124 proxy_process = False 125 if state & 0x200000: 126 res += "running-sys | " 127 if state & 0x100000: 128 res += "active-sys | " 129 if state & 0x80000: 130 res += "sig-in-q | " 131 if state & 0x40000: 132 res += "sys-tasks | " 133 if state & 0x20000: 134 res += "garbage-collecting | " 135 if state & 0x10000: 136 res += "suspended | " 137 if state & 0x8000: 138 res += "running | " 139 if state & 0x4000: 140 res += "in-run-queue | " 141 if state & 0x2000: 142 res += "active | " 143 if state & 0x1000: 144 res += "unused | " 145 if state & 0x800: 146 res += "exiting | " 147 if state & 0x400: 148 res += "free | " 149 if state & 0x200: 150 res += "in-prq-low | " 151 if state & 0x100: 152 res += "in-prq-normal | " 153 if state & 0x80: 154 res += "in-prq-high | " 155 if state & 0x40: 156 res += "in-prq-max | " 157 if state & 0x30 == 0x0: 158 res += "prq-prio-max | " 159 elif state & 0x30 == 0x10: 160 res += "prq-prio-high | " 161 elif state & 0x30 == 0x20: 162 res += "prq-prio-normal | " 163 else: 164 res += "prq-prio-low | " 165 if state & 0xc == 0x0: 166 res += "usr-prio-max | " 167 elif state & 0xc == 0x4: 168 res += "usr-prio-high | " 169 elif state & 0xc == 0x8: 170 res += "usr-prio-normal | " 171 else: 172 res += "usr-prio-low | " 173 if state & 0x3 == 0x0: 174 res += "act-prio-max" 175 elif state & 0x3 == 0x1: 176 res += "act-prio-high" 177 elif state & 0x3 == 0x2: 178 res += "act-prio-normal" 179 else: 180 res += "act-prio-low" 181 return res 182 183def process_flags(proc): 184 flags = proc.GetChildMemberWithName('flags').unsigned 185 res = '' 186 if flags & ~((1 << 24)-1): 187 res += "GARBAGE<%#x> " % (flags & ~((1 << 24)-1)) 188 if flags & (1 << 22): 189 res += "trap-exit " 190 if flags & (1 << 21): 191 res += "hibernated " 192 if flags & (1 << 20): 193 res += "dirty-minor-gc " 194 if flags & (1 << 19): 195 res += "dirty-major-gc " 196 if flags & (1 << 18): 197 res += "dirty-gc-hibernate " 198 if flags & (1 << 17): 199 res += "dirty-cla " 200 if flags & (1 << 16): 201 res += "delayed-del-proc " 202 if flags & (1 << 15): 203 res += "have-blocked-nmsb " 204 if flags & (1 << 14): 205 res += "shdlr-onln-wait-q " 206 if flags & (1 << 13): 207 res += "delay-gc " 208 if flags & (1 << 12): 209 res += "abandoned-heap-use " 210 if flags & (1 << 11): 211 res += "disable-gc " 212 if flags & (1 << 10): 213 res += "force-gc " 214 if flags & (1 << 9): 215 res += "ets-super-user " 216 if flags & (1 << 8): 217 res += "have-blocked-msb " 218 if flags & (1 << 7): 219 res += "using-ddll " 220 if flags & (1 << 6): 221 res += "distribution " 222 if flags & (1 << 5): 223 res += "using-db " 224 if flags & (1 << 4): 225 res += "need-fullsweep " 226 if flags & (1 << 3): 227 res += "heap-grow " 228 if flags & (1 << 2): 229 res += "timo " 230 if flags & (1 << 1): 231 res += "inslpqueue " 232 if flags & (1 << 0): 233 res += "hibernate-sched " 234 return res 235 236############################################ 237## Print the stacktrace of a single process 238############################################ 239def stacktrace_cmd(debugger, command, result, internal_dict): 240 target = debugger.GetSelectedTarget() 241 init(target) 242 proc = target.process.selected_thread.GetSelectedFrame().EvaluateExpression(command).Cast(ProcessPtr(target)) 243 stackdump(proc, False) 244 245############################################ 246## Print the stackdump of a single process 247############################################ 248def stackdump_cmd(debugger, command, result, internal_dict): 249 target = debugger.GetSelectedTarget() 250 init(target) 251 proc = target.process.selected_thread.GetSelectedFrame().EvaluateExpression(command).Cast(ProcessPtr(target)) 252 stackdump(proc, True) 253 254def stackdump(proc, dump): 255 stop = proc.GetChildMemberWithName('stop') 256 send = proc.GetChildMemberWithName('hend') 257 cnt = 0 258 if atomic_value(proc.GetChildMemberWithName('state')) & 0x8000: 259 print('%%%%%% WARNING: The process is currently running, so c_p->stop will not be correct') 260 print(F'%% Stacktrace ({send.unsigned - stop.unsigned})'); 261 i = proc.GetChildMemberWithName('i') 262 if i.unsigned != 0: 263 print(F'I: {eterm(i)}') 264 while stop.unsigned < send.unsigned: 265 if stop.deref.unsigned & 0x3 == 0x0 or dump: 266 print(F'{cnt}: {eterm(stop.deref)}') 267 cnt += 1 268 stop = offset(1, stop) 269 270############################################ 271## Print an eterm 272############################################ 273def eterm_cmd(debugger, command, result, internal_dict): 274 args = shlex.split(command) 275 target = debugger.GetSelectedTarget() 276 init(target) 277 term = target.process.selected_thread.GetSelectedFrame().EvaluateExpression(args[0]).Cast(EtermPtr(target)) 278 if len(args) >= 2: 279 print(eterm(term, int(args[1]))) 280 else: 281 print(eterm(term)) 282 283############################################ 284## Print the summary of an Eterm 285############################################ 286def eterm_summary(valobj, internal_dict): 287 if valobj.TypeIsPointerType(): 288 return '' 289 return F'{valobj.unsigned:#x} {eterm(valobj, 5)}' 290 291def eterm(valobj, depth = float('inf')): 292 val = valobj.unsigned 293 valobj = strip_literal_tag(valobj) 294 tag = val & 0x3 295 if tag == 0x1: 296 return cons(valobj, depth) 297 elif tag == 0x2: 298 return boxed(valobj, depth) 299 elif tag == 0x3: 300 return imm(valobj) 301 elif val == 0x0: 302 return '<the non-value>' 303 elif val == 0x4: 304 return '<the non-value debug>' 305 else: 306 return cp(valobj) 307 308def cons(valobj, depth = float('inf')): 309 items = [] 310 cdr = strip_literal_tag(valobj) 311 improper = False 312 truncated = False 313 depth *= 20 314 315 ptr = cdr.CreateValueFromData( 316 "unconsed", 317 lldb.SBData.CreateDataFromInt(cdr.unsigned - 1), 318 EtermPtr(cdr.target)) 319 if ptr.deref.error.fail: 320 return "#ConsError<%x>" % cdr.unsigned; 321 322 while True: 323 cdr = strip_literal_tag(cdr) 324 ptr = cdr.CreateValueFromData( 325 "unconsed", 326 lldb.SBData.CreateDataFromInt(cdr.unsigned - 1), 327 EtermPtr(cdr.target)) 328 items.append((ptr.deref, depth // 20)); # Append depth, car 329 if ptr.deref.unsigned & 0xF == 0xF: 330 depth -= 1 331 else: 332 depth -= 20 333 cdr = offset(1,ptr).deref 334 if is_nil(cdr): 335 break 336 if cdr.unsigned & 0x1 == 0: 337 improper = True 338 break 339 if depth <= 1: 340 truncated = True 341 break 342 343 if improper: 344 return '#ImproperList' 345 346 ## Try to print as ascii first 347 chars = '' 348 isprintable = True 349 for car, car_depth in items: 350 if car.unsigned & 0xF == 0xF: 351 if car.unsigned >> 4 == 10: 352 chars += '\\n' 353 elif car.unsigned >> 4 == 9: 354 chars += '\\t' 355 else: 356 chars += f'{car.unsigned >> 4:c}' 357 else: 358 isprintable = False 359 break 360 isprintable = isprintable and chars.isprintable() 361 if isprintable: 362 if not truncated: 363 return F'"{chars}"' 364 else: 365 return F'"{chars}..."' 366 367 ## If not printable, we print the objects 368 objs = [] 369 chars = '[' 370 for car, car_depth in items: 371 objs.append(eterm(car, car_depth)) 372 if not truncated: 373 return '[' + ','.join(objs) + ']' 374 else: 375 return '[' + ','.join(objs) + '|...]' 376 377def boxed(valobj, depth = float('inf')): 378 ptr = valobj.CreateValueFromData( 379 "unboxed", 380 lldb.SBData.CreateDataFromInt(valobj.unsigned - 2), 381 EtermPtr(valobj.target)) 382 boxed_hdr = ptr.deref 383 if boxed_hdr.error.fail: 384 return "#BoxedError<%x>" % valobj.unsigned; 385 boxed_hdr = boxed_hdr.unsigned 386 if boxed_hdr & 0x3f == 0x00: 387 arity = (boxed_hdr >> 6) 388 terms = [] 389 for x in range(1, arity+1): 390 if depth <= 1: 391 terms.append('...') 392 break 393 depth -= 1 394 terms.append(eterm(offset(x, ptr).deref, depth)) 395 res = ','.join(terms) 396 return F"{{{res}}}" 397 if boxed_hdr & 0x3c == 0x3c: 398 if boxed_hdr & 0xc0 == 0x0: 399 return "#FlatMap" 400 else: 401 return "#HashMap" 402 boxed_type = (boxed_hdr >> 2) & 0xF 403 if boxed_type == 0xC: 404 return '#ExternalPid' 405 if boxed_type == 0xD: 406 return '#ExternalPort' 407 if boxed_type == 0x2 or boxed_type == 0x3: 408 return '#Bignum' 409 if boxed_type == 0x6: 410 return '#Float' 411 if boxed_type == 0x4: 412 return '#Ref' 413 if boxed_type == 0xE: 414 return '#ExternalRef' 415 if boxed_type == 0x5: 416 return '#Fun' 417 if boxed_type == 0x8: 418 return '#RefcBin' 419 if boxed_type == 0x9: 420 return '#HeapBin' 421 if boxed_type == 0xA: 422 return '#SubBin' 423 return F'#Boxed<{valobj.unsigned}>' 424 425def imm(valobj): 426 val = valobj.unsigned 427 if (val & 0x3) != 3: 428 return '#NotImmediate<%#x>' % val 429 tag = val & 0xF 430 if tag == 0x3: 431 return pid(valobj) 432 elif tag == 0x7: 433 return port(valobj) 434 elif tag == 0xF: 435 return str(val >> 4) 436 elif tag == 0xB: 437 # Immediate2 438 tag2 = val & 0x3F 439 if tag2 == 0x0B: 440 return atom(valobj) 441 elif tag2 == 0x1B: 442 return F'#Catch<{val>>6:#x}>' 443 elif is_nil(valobj): 444 return '[]' 445 return '#UnknownImmediate<%#x>' % val 446 447# Continuation pointers 448 449def cp(valobj): 450 mfaptr = erts_lookup_function_info(valobj) 451 if mfaptr == None: 452 pointer = code_pointers.get(valobj.unsigned) 453 if pointer != None: 454 return '#Cp<%s>' % pointer 455 else: 456 return '#Cp<%#x>' % valobj.unsigned 457 else: 458 return '#Cp<%s>' % mfa(mfaptr) 459 460# Pids and ports 461 462def pid(valobj): 463 val = valobj.unsigned 464 if (val & 0xF) == 0x3: 465 target = valobj.target 466 if etp_arch_bits(target) == 64: 467 if etp_big_endian(target): 468 data = (val >> 35) & 0x0FFFFFFF 469 else: 470 data = (val >> 4) & 0x0FFFFFFF 471 else: 472 data = pixdata2data(valobj) 473 return '<0.%u.%u>' % (data & 0x7FFF, (data >> 15) & 0x1FFF) 474 else: 475 return '#NotPid<%#x>' % val 476 477def port(valobj): 478 val = valobj.unsigned 479 if (val & 0xF) == 0x7: 480 target = valobj.target 481 if etp_arch_bits(target) == 64 and not etp_halfword(target): 482 if etp_big_endian(target): 483 data = (val >> 36) & 0x0FFFFFFF 484 else: 485 data = (val >> 4) & 0x0FFFFFFF 486 else: 487 data = pixdata2data(valobj) 488 return '#Port<0.%u>' % data 489 else: 490 return '#NotPort<%#x>' % val 491 492# Strings and atoms 493 494def atom(valobj): 495 val = valobj.unsigned 496 if (val & 0x3F) == 0x0B: 497 name = atom_name(atom_tab(valobj)) 498 if unquoted_atom_re.match(name): 499 return str(name) 500 else: 501 return quoted_name(name, "'") 502 else: 503 return '#NotAtom<%#x>' % val 504 505def atom_name(entry): 506 name = entry.GetChildMemberWithName('name') 507 length = entry.GetChildMemberWithName('len').unsigned 508 data = name.GetPointeeData(0, length).uint8s 509 return ''.join(map(chr, data)) 510 511def quoted_name(name, quote): 512 return quote + ''.join(map(lambda c: quoted_char(c, quote), name)) + quote 513 514def quoted_char(c, quote): 515 point = ord(c) 516 if c == quote: 517 return '\\' + quote 518 elif point == 0x08: 519 return '\\b' 520 elif point == 0x09: 521 return '\\t' 522 elif point == 0x0A: 523 return '\\n' 524 elif point == 0x0B: 525 return '\\v' 526 elif point == 0x0C: 527 return '\\f' 528 elif point == 0x0D: 529 return '\\e' 530 elif point >= 0x20 and point <= 0x7E or point >= 0xA0: 531 return c 532 elif (point > 0xFF): 533 return '#NotChar<%#x>' % c 534 else: 535 return '\\%03o' % point 536 537# Constants 538 539MI_FUNCTIONS = 13 540MI_NUM_FUNCTIONS = 0 541 542def is_nil(value): 543 ## We handle both -5 and 0x3b as NIL values so that this script 544 ## works with more versions 545 return value.signed == -5 or value.unsigned == 0x3b 546 547# Types 548 549def Atom(target): 550 return target.FindFirstType('Atom') 551 552def Char(target): 553 return target.FindFirstType('char') 554def CharPtr(target): 555 return Char(target).GetPointerType() 556 557def Eterm(target): 558 return target.FindFirstType('Eterm') 559def EtermPtr(target): 560 return Eterm(target).GetPointerType() 561def EtermPtrPtr(target): 562 return EtermPtr(target).GetPointerType() 563 564def Range(target): 565 return target.FindFirstType('Range') 566 567def BeamInstr(target): 568 return target.FindFirstType('BeamInstr') 569def BeamInstrPtr(target): 570 return BeamInstr(target).GetPointerType() 571 572def ErtsCodeInfo(target): 573 return target.FindFirstType('ErtsCodeInfo') 574def ErtsCodeInfoPtr(target): 575 return ErtsCodeInfo(target).GetPointerType() 576 577def Process(target): 578 return target.FindFirstType('Process') 579def ProcessPtr(target): 580 return Process(target).GetPointerType() 581def ProcessPtrPtr(target): 582 return ProcessPtr(target).GetPointerType() 583 584# Globals 585 586def erts_atom_table(target): 587 return global_var('erts_atom_table', target) 588 589def erts_proc(target): 590 return global_var('erts_proc', target) 591 592def etp_arch_bits(target): 593 return global_var('etp_arch_bits', target).unsigned 594 595def etp_big_endian(target): 596 return global_var('etp_endianness', target).unsigned > 0 597 598def etp_halfword(target): 599 return False 600 601def the_active_code_index(target): 602 return global_var('the_active_code_index', target) 603 604# Functions 605 606def atom_tab(valobj): 607 idx = valobj.unsigned 608 target = valobj.target 609 seg = erts_atom_table(target).GetChildMemberWithName('seg_table') 610 slot = offset(idx >> 16, seg).deref 611 entry = offset(idx >> 6 & 0x3FF, slot).deref 612 return entry.Cast(Atom(target).GetPointerType()) 613 614def erts_lookup_function_info(valobj): 615 r = find_range(valobj) 616 if r is None: 617 return None 618 pc = valobj.unsigned 619 target = valobj.target 620 start = r.GetChildMemberWithName('start').Cast(EtermPtr(target)) 621 curr = offset(MI_FUNCTIONS, start).Cast(ErtsCodeInfoPtr(target).GetPointerType()) 622 prev = curr 623 cnt = offset(MI_NUM_FUNCTIONS, start).deref.unsigned 624 for x in range(0, cnt): 625 prev = curr 626 curr = offset(1, curr) 627 if pc < curr.deref.unsigned: 628 return prev.deref.GetChildMemberWithName('mfa') 629 return None 630 631def find_range(valobj): 632 pc = valobj.unsigned 633 target = valobj.target 634 active = the_active_code_index(target).unsigned 635 ranges = offset(active, global_var('r', target)) 636 n = ranges.GetChildMemberWithName('n').unsigned 637 low = ranges.GetChildMemberWithName('modules') 638 high = offset(n, low) 639 range_type = Range(target) 640 range_pointer_type = range_type.GetPointerType() 641 mid = ranges.GetChildMemberWithName('mid').Cast(range_pointer_type) 642 while low.unsigned < high.unsigned: 643 start = mid.GetChildMemberWithName('start').unsigned 644 end = atomic_value(mid.GetChildMemberWithName('end')) 645 if pc < start: 646 high = mid 647 elif pc > end: 648 low = offset(1, mid).Cast(range_pointer_type) 649 else: 650 return mid 651 length = (high.unsigned - low.unsigned) // range_type.size 652 mid = offset(length // 2, low) 653 return None 654 655def mfa(mfa): 656 return '%s:%s/%d' % (eterm(mfa.GetChildMemberWithName('module')), 657 eterm(mfa.GetChildMemberWithName('function')), 658 mfa.GetChildMemberWithName('arity').unsigned) 659 660def pixdata2data(valobj): 661 pixdata = valobj.unsigned 662 proc = erts_proc(target) 663 ro = proc.GetChildMemberWithName('r').GetChildMemberWithName('o') 664 pix_mask = ro.GetChildMemberWithName('pix_mask').unsigned 665 pix_cl_mask = ro.GetChildMemberWithName('pix_cl_mask').unsigned 666 pix_cl_shift = ro.GetChildMemberWithName('pix_cl_shift').unsigned 667 pix_cli_mask = ro.GetChildMemberWithName('pix_cli_mask').unsigned 668 pix_cli_shift = ro.GetChildMemberWithName('pix_cli_shift').unsigned 669 data = pixdata & ~pix_mask 670 data |= (pixdata >> pix_cl_shift) & pix_cl_mask 671 data |= (pixdata & pix_cli_mask) << pix_cli_shift 672 return data 673 674def strip_literal_tag(valobj): 675 if valobj.size == 4: 676 # This is a 32-bit executable. There are no literal tags. 677 return valobj 678 679 # Strip literal tags from list and boxed terms. 680 primary_tag = valobj.unsigned & 0x03 681 if (primary_tag == 1 or primary_tag == 2) and valobj.unsigned & 0x04: 682 valobj = valobj.CreateValueFromData( 683 valobj.name, 684 lldb.SBData.CreateDataFromInt(valobj.unsigned - 0x04), 685 Eterm(valobj.target)) 686 return valobj 687 688def init(target): 689 names = ['beam_apply', 'beam_normal_exit', 'beam_exit', 'beam_save_calls', 690 'beam_bif_export_trap', 'beam_export_trampoline', 'beam_continue_exit', 691 'beam_return_to_trace', 'beam_return_trace', 'beam_exception_trace', 692 'beam_return_time_trace'] 693 for name in names: 694 code_pointers[global_var(name, target).unsigned] = name 695 696# LLDB utils 697 698def global_var(name, target): 699 return target.FindGlobalVariables(name, 1)[0] 700 701def offset(i, valobj): 702 # print("offset(" + str(i) + ", " + str(valobj.unsigned) + ")") 703 val = valobj.GetChildAtIndex(i, lldb.eNoDynamicValues, True) 704 if valobj.TypeIsPointerType(): 705 return val.address_of.Cast(valobj.GetType()) 706 else: 707 return val 708 709def atomic_value(valobj): 710 value = valobj.GetChildMemberWithName('counter') 711 if value.IsValid(): 712 return value.unsigned 713 else: 714 return valobj.GetChildMemberWithName('value').unsigned 715