Skip to content

Commit 1948512

Browse files
committed
tools: add script with commands to facilitate dev
Some tasks are very common when working on llnode, especially when upgrading a V8 version. This new script is intended to make developers life easier by simplifying tasks which usually require printfs on llnode code or manually inspecting the memory of a process. Hopefully we'll add more commands in the future. PR-URL: #339
1 parent 1839dc3 commit 1948512

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

tools/helpers.py

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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

Comments
 (0)