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__':