-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathdump-message-log
More file actions
executable file
·159 lines (131 loc) · 6.21 KB
/
dump-message-log
File metadata and controls
executable file
·159 lines (131 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python3
"""
LLDB script to dump the contents of WebKit's IPC message log for testing.
Usage in LLDB:
(lldb) command script import Tools/Scripts/dump-message-log
(lldb) dump_message_log
The script dumps messages in reverse chronological order (most recent first),
starting from the last written position and stopping when it encounters either:
- An Invalid message name (indicating unwritten slots)
- A full traversal of the buffer (wrapping back to start)
"""
import lldb
import re
def dump_message_log(debugger, command, result, internal_dict):
"""Dumps the contents of IPC::gMessageLog in reverse chronological order"""
target = debugger.GetSelectedTarget()
if not target or not target.IsValid():
print("Error: No valid target selected", file=result)
return
process = target.GetProcess()
if not process or not process.IsValid():
print("Error: No valid process attached", file=result)
return
# Find the global message log
buffer_var = target.FindFirstGlobalVariable("IPC::gMessageLog")
if not buffer_var or not buffer_var.IsValid():
print("Error: Could not find IPC::gMessageLog", file=result)
print("Make sure the process is using a build with the message log compiled in.", file=result)
return
# Get capacity from the type name (e.g., MessageLog<256>)
buffer_type = buffer_var.GetType()
type_name = buffer_type.GetName()
match = re.search(r'MessageLog<(\d+)>', type_name)
if not match:
print(f"Error: Could not parse capacity from type name: {type_name}", file=result)
return
capacity = int(match.group(1))
# Get m_index (std::atomic<size_t>)
# Note: m_index is a private member, but LLDB can access it for debugging
m_index_var = buffer_var.GetChildMemberWithName("m_index")
if not m_index_var or not m_index_var.IsValid():
print("Error: Could not access m_index member", file=result)
return
# Extract the actual value from std::atomic
# Try different member names used by different standard library implementations
index_value = None
for atomic_member in ["_M_i", "__a_", "_Value", "Value", "__a"]:
atomic_storage = m_index_var.GetChildMemberWithName(atomic_member)
if atomic_storage and atomic_storage.IsValid():
index_value = atomic_storage.GetValueAsUnsigned()
break
if index_value is None:
# Fallback: try to get value directly
index_value = m_index_var.GetValueAsUnsigned()
if index_value == 0xFFFFFFFFFFFFFFFF: # Likely failed
print("Error: Could not read m_index value", file=result)
return
# Get m_buffer (std::array)
# Note: m_buffer is a private member, but LLDB can access it for debugging
m_buffer_var = buffer_var.GetChildMemberWithName("m_buffer")
if not m_buffer_var or not m_buffer_var.IsValid():
print("Error: Could not access m_buffer member", file=result)
return
# std::array may wrap the actual array in an __elems_ or similar member
# Try to access it, otherwise use m_buffer_var directly
elems_var = m_buffer_var.GetChildMemberWithName("__elems_")
if elems_var and elems_var.IsValid():
m_buffer_var = elems_var
# Try to find IPC::MessageName::Invalid
message_name_type = target.FindFirstType("IPC::MessageName")
message_name_invalid = None
if message_name_type and message_name_type.IsValid():
enum_members = message_name_type.GetEnumMembers()
for i in range(enum_members.GetSize()):
member = enum_members.GetTypeEnumMemberAtIndex(i)
if member.GetName() == "Invalid":
message_name_invalid = member.GetValueAsUnsigned()
break
# Print header
print("\n" + "=" * 80, file=result)
print(f"WebKit IPC Message Log Dump (Capacity: {capacity})", file=result)
print("=" * 80, file=result)
print("\nMessages (most recent first):\n", file=result)
# Calculate the last written index
# m_index points to the NEXT position to write, so last written is (m_index - 1) % capacity
if index_value == 0:
last_written = capacity - 1
else:
last_written = (index_value - 1) % capacity
current_index = last_written
messages_found = 0
for i in range(capacity):
# Get array element at current_index
element = m_buffer_var.GetChildAtIndex(current_index)
if not element or not element.IsValid():
print(f"Warning: Could not read buffer[{current_index}]", file=result)
break
message_value = element.GetValueAsUnsigned()
# Stop if we encounter Invalid
if message_name_invalid is not None and message_value == message_name_invalid:
print(f"\n[Stopped at Invalid message after {messages_found} messages (at buffer[{current_index}])]", file=result)
break
# Try to get the symbolic name
message_name_str = element.GetValue()
if message_name_str:
# Clean up the format (e.g., "IPCTester_EmptyMessage" instead of full enum path)
message_name_str = message_name_str.replace("IPC::MessageName::", "")
# Display "Invalid" instead of "Count" since they're semantically invalid messages
if message_name_str == "Count":
message_name_str = "Invalid"
else:
message_name_str = f"<value={message_value}>"
print(f"{messages_found}. {message_name_str}", file=result)
messages_found += 1
# Move to previous index (wrap around)
if current_index == 0:
current_index = capacity - 1
else:
current_index -= 1
print("\n" + "=" * 80 + "\n", file=result)
def __lldb_init_module(debugger, internal_dict):
"""Register the command when the script is loaded"""
debugger.HandleCommand(
'command script add -f dump_message_log.dump_message_log dump_message_log'
)
print('The "dump_message_log" command has been installed.')
if __name__ == "__main__":
print("This script is intended to be used within LLDB, not run directly.")
print("\nUsage in LLDB:")
print(" (lldb) command script import Tools/Scripts/dump-message-log")
print(" (lldb) dump_message_log")