2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """"Processes a log file and resolves IPC message identifiers.
8 Resolves IPC messages of the form [unknown type NNNNNN] to named IPC messages.
10 e.g. logfile containing
12 I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S [unknown type 66372]
14 will be transformed to:
16 I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S ViewMsg_SetCSSColors
18 In order to find the message header files efficiently, it requires that
19 Chromium is checked out using git.
30 """Get chromium's source directory."""
31 return os.path.join(sys.path[0], '..')
35 """Read from file f and generate right-stripped lines."""
40 def _GetMsgStartTable():
41 """Read MsgStart enumeration from ipc/ipc_message_utils.h.
43 Determines the message type identifiers by reading.
44 header file ipc/ipc_message_utils.h and looking for
45 enum IPCMessageStart. Assumes following code format in header file:
46 enum IPCMessageStart {
52 A dictionary mapping StartName to enumeration value.
54 ipc_message_file = _SourceDir() + '/ipc/ipc_message_utils.h'
55 ipc_message_lines = _ReadLines(open(ipc_message_file))
58 msg_start_table = dict()
59 for line in ipc_message_lines:
61 if line.strip() == '};':
63 msgstart_index = line.find('MsgStart')
64 msg_type = line[:msgstart_index] + 'MsgStart'
65 msg_start_table[msg_type.strip()] = count
67 elif line.strip() == 'enum IPCMessageStart {':
70 return msg_start_table
73 def _FindMessageHeaderFiles():
74 """Look through the source directory for *_messages.h."""
75 os.chdir(_SourceDir())
76 pipe = subprocess.Popen(['git', 'ls-files', '--', '*_messages.h'],
77 stdout=subprocess.PIPE)
78 return _ReadLines(pipe.stdout)
81 def _GetMsgId(msg_start, line_number, msg_start_table):
82 """Construct the meessage id given the msg_start and the line number."""
83 hex_str = '%x%04x' % (msg_start_table[msg_start], line_number)
84 return int(hex_str, 16)
87 def _ReadHeaderFile(f, msg_start_table, msg_map):
88 """Read a header file and construct a map from message_id to message name."""
89 msg_def_re = re.compile(
90 '^IPC_(?:SYNC_)?MESSAGE_[A-Z0-9_]+\(([A-Za-z0-9_]+).*')
91 msg_start_re = re.compile(
92 '^\s*#define\s+IPC_MESSAGE_START\s+([a-zA-Z0-9_]+MsgStart).*')
99 match = re.match(msg_start_re, line)
101 msg_start = match.group(1)
102 # print "msg_start = " + msg_start
103 match = re.match(msg_def_re, line)
105 msg_name = match.group(1)
106 # print "msg_name = " + msg_name
107 if msg_start and msg_name:
108 msg_id = _GetMsgId(msg_start, line_number, msg_start_table)
109 msg_map[msg_id] = msg_name
113 def _ResolveMsg(msg_type, msg_map):
114 """Fully resolve a message type to a name."""
115 if msg_type in msg_map:
116 return msg_map[msg_type]
118 return '[Unknown message %d (0x%x)]x' % (msg_type, msg_type)
121 def _ProcessLog(f, msg_map):
122 """Read lines from f and resolve the IPC messages according to msg_map."""
123 unknown_msg_re = re.compile('\[unknown type (\d+)\]')
126 match = re.search(unknown_msg_re, line)
128 line = re.sub(unknown_msg_re,
129 _ResolveMsg(int(match.group(1)), msg_map),
135 """Returns a dictionary mapping from message number to message name."""
136 msg_start_table = _GetMsgStartTable()
138 for header_file in _FindMessageHeaderFiles():
139 _ReadHeaderFile(open(header_file),
146 """Processes one or more log files with IPC logging messages.
148 Replaces '[unknown type NNNNNN]' with resolved
151 Reads from standard input if no log files specified on the
154 parser = optparse.OptionParser('usage: %prog [LOGFILE...]')
155 (_, args) = parser.parse_args()
157 msg_map = _GetMsgMap()
161 for log_file in log_files:
162 _ProcessLog(open(log_file), msg_map)
164 _ProcessLog(sys.stdin, msg_map)
167 if __name__ == '__main__':