Index: tools/ipc_messages_log.py |
diff --git a/tools/ipc_messages_log.py b/tools/ipc_messages_log.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..26284d1cd60827e679e24d62750277653abd75ec |
--- /dev/null |
+++ b/tools/ipc_messages_log.py |
@@ -0,0 +1,168 @@ |
+#!/usr/bin/python |
+# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+""""Processes a log file and resolves IPC message identifiers. |
+ |
+Resolves IPC messages of the form [unknown type NNNNNN] to named IPC messages. |
+ |
+e.g. logfile containing |
+ |
+I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S [unknown type 66372] |
+ |
+will be transformed to: |
+ |
+I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S ViewMsg_SetCSSColors |
+ |
+In order to find the message header files efficiently, it requires that |
+Chromium is checked out using git. |
+""" |
+ |
+import optparse |
+import os |
+import re |
+import subprocess |
+import sys |
+ |
+ |
+def _SourceDir(): |
+ """Get chromium's source directory.""" |
+ return os.path.join(sys.path[0], '..') |
+ |
+ |
+def _ReadLines(f): |
+ """Read from file f and generate right-stripped lines.""" |
+ for line in f: |
+ yield line.rstrip() |
+ |
+ |
+def _GetMsgStartTable(): |
+ """Read MsgStart enumeration from ipc/ipc_message_utils.h. |
+ |
+ Determines the message type identifiers by reading. |
+ header file ipc/ipc_message_utils.h and looking for |
+ enum IPCMessageStart. Assumes following code format in header file: |
+ enum IPCMessageStart { |
+ Type1MsgStart ..., |
+ Type2MsgStart, |
+ }; |
+ |
+ Returns: |
+ A dictionary mapping StartName to enumeration value. |
+ """ |
+ ipc_message_file = _SourceDir() + '/ipc/ipc_message_utils.h' |
+ ipc_message_lines = _ReadLines(open(ipc_message_file)) |
+ is_msg_start = False |
+ count = 0 |
+ msg_start_table = dict() |
+ for line in ipc_message_lines: |
+ if is_msg_start: |
+ if line.strip() == '};': |
+ break |
+ msgstart_index = line.find('MsgStart') |
+ msg_type = line[:msgstart_index] + 'MsgStart' |
+ msg_start_table[msg_type.strip()] = count |
+ count+=1 |
+ elif line.strip() == 'enum IPCMessageStart {': |
+ is_msg_start = True |
+ |
+ return msg_start_table |
+ |
+ |
+def _FindMessageHeaderFiles(): |
+ """Look through the source directory for *_messages.h.""" |
+ os.chdir(_SourceDir()) |
+ pipe = subprocess.Popen(['git', 'ls-files', '--', '*_messages.h'], |
+ stdout=subprocess.PIPE) |
+ return _ReadLines(pipe.stdout) |
+ |
+ |
+def _GetMsgId(msg_start, line_number, msg_start_table): |
+ """Construct the meessage id given the msg_start and the line number.""" |
+ hex_str = '%x%04x' % (msg_start_table[msg_start], line_number) |
+ return int(hex_str, 16) |
+ |
+ |
+def _ReadHeaderFile(f, msg_start_table, msg_map): |
+ """Read a header file and construct a map from message_id to message name.""" |
+ msg_def_re = re.compile( |
+ '^IPC_(?:SYNC_)?MESSAGE_[A-Z0-9_]+\(([A-Za-z0-9_]+).*') |
+ msg_start_re = re.compile( |
+ '^\s*#define\s+IPC_MESSAGE_START\s+([a-zA-Z0-9_]+MsgStart).*') |
+ msg_start = None |
+ msg_name = None |
+ line_number = 0 |
+ |
+ for line in f: |
+ line_number+=1 |
+ match = re.match(msg_start_re, line) |
+ if match: |
+ msg_start = match.group(1) |
+ # print "msg_start = " + msg_start |
+ match = re.match(msg_def_re, line) |
+ if match: |
+ msg_name = match.group(1) |
+ # print "msg_name = " + msg_name |
+ if msg_start and msg_name: |
+ msg_id = _GetMsgId(msg_start, line_number, msg_start_table) |
+ msg_map[msg_id] = msg_name |
+ return msg_map |
+ |
+ |
+def _ResolveMsg(msg_type, msg_map): |
+ """Fully resolve a message type to a name.""" |
+ if msg_type in msg_map: |
+ return msg_map[msg_type] |
+ else: |
+ return '[Unknown message %d (0x%x)]x' % (msg_type, msg_type) |
+ |
+ |
+def _ProcessLog(f, msg_map): |
+ """Read lines from f and resolve the IPC messages according to msg_map.""" |
+ unknown_msg_re = re.compile('\[unknown type (\d+)\]') |
+ for line in f: |
+ line = line.rstrip() |
+ match = re.search(unknown_msg_re, line) |
+ if match: |
+ line = re.sub(unknown_msg_re, |
+ _ResolveMsg(int(match.group(1)), msg_map), |
+ line) |
+ print line |
+ |
+ |
+def _GetMsgMap(): |
+ """Returns a dictionary mapping from message number to message name.""" |
+ msg_start_table = _GetMsgStartTable() |
+ msg_map = dict() |
+ for header_file in _FindMessageHeaderFiles(): |
+ _ReadHeaderFile(open(header_file), |
+ msg_start_table, |
+ msg_map) |
+ return msg_map |
+ |
+ |
+def main(): |
+ """Processes one or more log files with IPC logging messages. |
+ |
+ Replaces '[unknown type NNNNNN]' with resolved |
+ IPC messages. |
+ |
+ Reads from standard input if no log files specified on the |
+ command line. |
+ """ |
+ parser = optparse.OptionParser('usage: %prog [LOGFILE...]') |
+ (_, args) = parser.parse_args() |
+ |
+ msg_map = _GetMsgMap() |
+ log_files = args |
+ |
+ if log_files: |
+ for log_file in log_files: |
+ _ProcessLog(open(log_file), msg_map) |
+ else: |
+ _ProcessLog(sys.stdin, msg_map) |
+ |
+ |
+if __name__ == '__main__': |
+ main() |