|
| 1 | +""" Helper commands to make development of llnode easier. No API stability |
| 2 | +guarantees for these commands (at least for now). |
| 3 | +
|
| 4 | +To use it, run: |
| 5 | +
|
| 6 | + (llnode) command script import ./tools/helpers.py |
| 7 | +
|
| 8 | +Or start llnode with: |
| 9 | +
|
| 10 | + $ llnode -o 'command script import ./tools/helpers.py' |
| 11 | +""" |
| 12 | +import struct |
| 13 | + |
| 14 | +import lldb |
| 15 | + |
| 16 | + |
| 17 | +def int_from_bytearray(uint, size, target): |
| 18 | + byte_order = target.GetByteOrder() |
| 19 | + |
| 20 | + fmt = "" |
| 21 | + |
| 22 | + # https://docs.python.org/3.2/library/struct.html#byte-order-size-and-alignment |
| 23 | + # < is little endian, > is big endian |
| 24 | + if byte_order == lldb.eByteOrderLittle: |
| 25 | + fmt += "<" |
| 26 | + elif byte_order == lldb.eByteOrderBig: |
| 27 | + fmt += ">" |
| 28 | + else: |
| 29 | + raise ValueError("Unexpected byte order %d" % byte_order) |
| 30 | + |
| 31 | + # https://docs.python.org/3.2/library/struct.html#format-characters |
| 32 | + if size == 1: |
| 33 | + fmt += "B" |
| 34 | + elif size == 2: |
| 35 | + fmt += "H" |
| 36 | + elif size == 4: |
| 37 | + fmt += "I" |
| 38 | + elif size == 8: |
| 39 | + fmt += "Q" |
| 40 | + else: |
| 41 | + raise ValueError("Unexpected size %d" % size) |
| 42 | + return struct.unpack(fmt, uint)[0] |
| 43 | + |
| 44 | + |
| 45 | +def brute(debugger, command, result, internal_dict): |
| 46 | + """ v8-brute <addr> |
| 47 | + This command will try to run `v8 inspect` on 20 object-aligned addresses |
| 48 | + following <addr>. Useful to find all objects on the stack, or all objects |
| 49 | + after a given object field, etc. |
| 50 | + """ |
| 51 | + process = debugger.GetSelectedTarget().GetProcess() |
| 52 | + if not command: |
| 53 | + return |
| 54 | + |
| 55 | + for i in range(20): |
| 56 | + addr = int(command, 16) + (8 * i) |
| 57 | + error = lldb.SBError() |
| 58 | + obj = process.ReadUnsignedFromMemory(addr, 8, error) |
| 59 | + if error.Fail(): |
| 60 | + print("failed for 0x%x" % addr) |
| 61 | + continue |
| 62 | + print("v8 inspect 0x%lx" % obj) |
| 63 | + debugger.HandleCommand("v8 inspect 0x%lx" % obj) |
| 64 | + |
| 65 | + |
| 66 | +def get_constants(debugger, command, result, internal_dict): |
| 67 | + """ v8-get-constants [pattern] |
| 68 | + This command will return all constants prefixed by v8dbg and nodedbg, with |
| 69 | + respective values for each constant. Useful when looking at missing types, |
| 70 | + offsets, etc. Optional pattern parameter will filter symbol names before |
| 71 | + showing them (for example, running `v8-get-constants v8dbg_type_` will |
| 72 | + return all type constants). |
| 73 | + """ |
| 74 | + target = debugger.GetSelectedTarget() |
| 75 | + |
| 76 | + for module in target.module_iter(): |
| 77 | + for symbol in module: |
| 78 | + name = symbol.GetName() |
| 79 | + if name is None: |
| 80 | + continue |
| 81 | + if name.startswith("v8dbg_") or name.startswith("nodedbg_"): |
| 82 | + if command and command not in name: |
| 83 | + continue |
| 84 | + start = symbol.GetStartAddress() |
| 85 | + size = symbol.GetEndAddress().GetOffset() - start.GetOffset() |
| 86 | + |
| 87 | + error = lldb.SBError() |
| 88 | + uint = bytes(target.ReadMemory(start, size, error)) |
| 89 | + if error.Success(): |
| 90 | + uint = int_from_bytearray(uint, size, target) |
| 91 | + print("%s: %d" % (name, uint)) |
| 92 | + else: |
| 93 | + print('error: ', error.GetCString()) |
| 94 | + |
| 95 | +lldb.debugger.HandleCommand('command script add -f helpers.brute v8-brute-inspect') |
| 96 | +lldb.debugger.HandleCommand('command script add -f helpers.get_constants v8-get-constants') |
0 commit comments