ipc_messages_log.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/env python
  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.
  5. """"Processes a log file and resolves IPC message identifiers.
  6. Resolves IPC messages of the form [unknown type NNNNNN] to named IPC messages.
  7. e.g. logfile containing
  8. I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S [unknown type 66372]
  9. will be transformed to:
  10. I/stderr ( 3915): ipc 3915.3.1370207904 2147483647 S ViewMsg_SetCSSColors
  11. In order to find the message header files efficiently, it requires that
  12. Chromium is checked out using git.
  13. """
  14. from __future__ import print_function
  15. import optparse
  16. import os
  17. import re
  18. import subprocess
  19. import sys
  20. def _SourceDir():
  21. """Get chromium's source directory."""
  22. return os.path.join(sys.path[0], '..')
  23. def _ReadLines(f):
  24. """Read from file f and generate right-stripped lines."""
  25. for line in f:
  26. yield line.rstrip()
  27. def _GetMsgStartTable():
  28. """Read MsgStart enumeration from ipc/ipc_message_utils.h.
  29. Determines the message type identifiers by reading.
  30. header file ipc/ipc_message_utils.h and looking for
  31. enum IPCMessageStart. Assumes following code format in header file:
  32. enum IPCMessageStart {
  33. Type1MsgStart ...,
  34. Type2MsgStart,
  35. };
  36. Returns:
  37. A dictionary mapping StartName to enumeration value.
  38. """
  39. ipc_message_file = _SourceDir() + '/ipc/ipc_message_utils.h'
  40. ipc_message_lines = _ReadLines(open(ipc_message_file))
  41. is_msg_start = False
  42. count = 0
  43. msg_start_table = dict()
  44. for line in ipc_message_lines:
  45. if is_msg_start:
  46. if line.strip() == '};':
  47. break
  48. msgstart_index = line.find('MsgStart')
  49. msg_type = line[:msgstart_index] + 'MsgStart'
  50. msg_start_table[msg_type.strip()] = count
  51. count+=1
  52. elif line.strip() == 'enum IPCMessageStart {':
  53. is_msg_start = True
  54. return msg_start_table
  55. def _FindMessageHeaderFiles():
  56. """Look through the source directory for *_messages.h."""
  57. os.chdir(_SourceDir())
  58. pipe = subprocess.Popen(['git', 'ls-files', '--', '*_messages.h'],
  59. stdout=subprocess.PIPE)
  60. return _ReadLines(pipe.stdout)
  61. def _GetMsgId(msg_start, line_number, msg_start_table):
  62. """Construct the meessage id given the msg_start and the line number."""
  63. hex_str = '%x%04x' % (msg_start_table[msg_start], line_number)
  64. return int(hex_str, 16)
  65. def _ReadHeaderFile(f, msg_start_table, msg_map):
  66. """Read a header file and construct a map from message_id to message name."""
  67. msg_def_re = re.compile(
  68. '^IPC_(?:SYNC_)?MESSAGE_[A-Z0-9_]+\(([A-Za-z0-9_]+).*')
  69. msg_start_re = re.compile(
  70. '^\s*#define\s+IPC_MESSAGE_START\s+([a-zA-Z0-9_]+MsgStart).*')
  71. msg_start = None
  72. msg_name = None
  73. line_number = 0
  74. for line in f:
  75. line_number+=1
  76. match = re.match(msg_start_re, line)
  77. if match:
  78. msg_start = match.group(1)
  79. # print("msg_start = " + msg_start)
  80. match = re.match(msg_def_re, line)
  81. if match:
  82. msg_name = match.group(1)
  83. # print("msg_name = " + msg_name)
  84. if msg_start and msg_name:
  85. msg_id = _GetMsgId(msg_start, line_number, msg_start_table)
  86. msg_map[msg_id] = msg_name
  87. return msg_map
  88. def _ResolveMsg(msg_type, msg_map):
  89. """Fully resolve a message type to a name."""
  90. if msg_type in msg_map:
  91. return msg_map[msg_type]
  92. else:
  93. return '[Unknown message %d (0x%x)]x' % (msg_type, msg_type)
  94. def _ProcessLog(f, msg_map):
  95. """Read lines from f and resolve the IPC messages according to msg_map."""
  96. unknown_msg_re = re.compile('\[unknown type (\d+)\]')
  97. for line in f:
  98. line = line.rstrip()
  99. match = re.search(unknown_msg_re, line)
  100. if match:
  101. line = re.sub(unknown_msg_re,
  102. _ResolveMsg(int(match.group(1)), msg_map),
  103. line)
  104. print(line)
  105. def _GetMsgMap():
  106. """Returns a dictionary mapping from message number to message name."""
  107. msg_start_table = _GetMsgStartTable()
  108. msg_map = dict()
  109. for header_file in _FindMessageHeaderFiles():
  110. _ReadHeaderFile(open(header_file),
  111. msg_start_table,
  112. msg_map)
  113. return msg_map
  114. def main():
  115. """Processes one or more log files with IPC logging messages.
  116. Replaces '[unknown type NNNNNN]' with resolved
  117. IPC messages.
  118. Reads from standard input if no log files specified on the
  119. command line.
  120. """
  121. parser = optparse.OptionParser('usage: %prog [LOGFILE...]')
  122. (_, args) = parser.parse_args()
  123. msg_map = _GetMsgMap()
  124. log_files = args
  125. if log_files:
  126. for log_file in log_files:
  127. _ProcessLog(open(log_file), msg_map)
  128. else:
  129. _ProcessLog(sys.stdin, msg_map)
  130. if __name__ == '__main__':
  131. main()