Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(940)

Side by Side Diff: tools/isolate/trace_inputs.py

Issue 10448034: Improve tracing on OSX and Windows (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # coding=utf-8 2 # coding=utf-8
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Traces an executable and its child processes and extract the files accessed 7 """Traces an executable and its child processes and extract the files accessed
8 by them. 8 by them.
9 9
10 The implementation uses OS-specific API. The native Kernel logger and the ETL 10 The implementation uses OS-specific API. The native Kernel logger and the ETL
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 RE_SIGNAL = re.compile(r'^--- SIG[A-Z]+ .+ ---') 376 RE_SIGNAL = re.compile(r'^--- SIG[A-Z]+ .+ ---')
377 # A process didn't handle a signal. 377 # A process didn't handle a signal.
378 RE_KILLED = re.compile(r'^\+\+\+ killed by ([A-Z]+) \+\+\+$') 378 RE_KILLED = re.compile(r'^\+\+\+ killed by ([A-Z]+) \+\+\+$')
379 # A call was canceled. 379 # A call was canceled.
380 RE_UNAVAILABLE = re.compile(r'\)\s+= \? <unavailable>$') 380 RE_UNAVAILABLE = re.compile(r'\)\s+= \? <unavailable>$')
381 # Happens when strace fails to even get the function name. 381 # Happens when strace fails to even get the function name.
382 UNNAMED_FUNCTION = '????' 382 UNNAMED_FUNCTION = '????'
383 383
384 # Arguments parsing. 384 # Arguments parsing.
385 RE_CHDIR = re.compile(r'^\"(.+?)\"$') 385 RE_CHDIR = re.compile(r'^\"(.+?)\"$')
386 RE_EXECVE = re.compile(r'^\"(.+?)\", \[.+?\], \[.+?\]$') 386 RE_EXECVE = re.compile(r'^\"(.+?)\", \[(.+)\], \[\/\* \d\d vars \*\/\]$')
387 RE_OPEN2 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+)$') 387 RE_OPEN2 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+)$')
388 RE_OPEN3 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+), (\d+)$') 388 RE_OPEN3 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+), (\d+)$')
389 RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$') 389 RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$')
390 390
391 class RelativePath(object): 391 class RelativePath(object):
392 """A late-bound relative path.""" 392 """A late-bound relative path."""
393 def __init__(self, parent, value): 393 def __init__(self, parent, value):
394 self.parent = parent 394 self.parent = parent
395 self.value = value 395 self.value = value
396 396
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 """Transfers cwd.""" 496 """Transfers cwd."""
497 if result == '? ERESTARTNOINTR (To be restarted)': 497 if result == '? ERESTARTNOINTR (To be restarted)':
498 return 498 return
499 # Update the other process right away. 499 # Update the other process right away.
500 childpid = int(result) 500 childpid = int(result)
501 child = self.root().get_or_set_proc(childpid) 501 child = self.root().get_or_set_proc(childpid)
502 # Copy the cwd object. 502 # Copy the cwd object.
503 child.initial_cwd = self.get_cwd() 503 child.initial_cwd = self.get_cwd()
504 assert child.parentid is None 504 assert child.parentid is None
505 child.parentid = self.pid 505 child.parentid = self.pid
506 # It is necessary because the logs are processed out of order.
507 assert childpid not in self.children
506 self.children.append(childpid) 508 self.children.append(childpid)
507 509
508 def handle_close(self, _function, _args, _result): 510 def handle_close(self, _function, _args, _result):
509 pass 511 pass
510 512
511 def handle_execve(self, _function, args, result): 513 def handle_execve(self, _function, args, result):
512 self._handle_file(self.RE_EXECVE.match(args).group(1), result) 514 if result != '0':
515 return
516 m = self.RE_EXECVE.match(args)
517 self._handle_file(m.group(1), result)
513 518
514 def handle_exit_group(self, _function, _args, _result): 519 def handle_exit_group(self, _function, _args, _result):
515 """Removes cwd.""" 520 """Removes cwd."""
516 self.cwd = None 521 self.cwd = None
517 522
518 @staticmethod 523 @staticmethod
519 def handle_fork(_function, args, result): 524 def handle_fork(_function, args, result):
520 assert False, (args, result) 525 assert False, (args, result)
521 526
522 def handle_open(self, _function, args, result): 527 def handle_open(self, _function, args, result):
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 syscall::truncate:return, 763 syscall::truncate:return,
759 syscall::unlink:return, 764 syscall::unlink:return,
760 syscall::utimes:return, 765 syscall::utimes:return,
761 */ 766 */
762 """ 767 """
763 768
764 @classmethod 769 @classmethod
765 def code(cls, pid, cwd): 770 def code(cls, pid, cwd):
766 """Setups the D code to implement child process tracking. 771 """Setups the D code to implement child process tracking.
767 772
768 Injects a fake chdir() trace to simplify parsing. The reason is that the 773 Injects the pid and the initial cwd into the trace header for context.
769 child process is already running at that point so: 774 The reason is that the child process is already running at that point so:
770 - no proc_start() is logged for it. 775 - no proc_start() is logged for it.
771 - there is no way to figure out the absolute path of cwd in kernel on OSX 776 - there is no way to figure out the absolute path of cwd in kernel on OSX
772 777
773 Since the child process is already started, initialize current_processes to 778 Since the child process is already started, initialize current_processes to
774 1. 779 1.
775 """ 780 """
776 pid = str(pid) 781 pid = str(pid)
777 cwd = os.path.realpath(cwd).replace('\\', '\\\\').replace('%', '%%') 782 cwd = os.path.realpath(cwd).replace('\\', '\\\\').replace('%', '%%')
778 return ( 783 return (
779 'dtrace:::BEGIN {\n' 784 'dtrace:::BEGIN {\n'
780 ' current_processes = 1;\n' 785 ' current_processes = 1;\n'
781 ' logindex = 0;\n' 786 ' logindex = 0;\n'
782 ' trackedpid[') + pid + ('] = 1;\n' 787 ' trackedpid[' + pid + '] = 1;\n'
783 ' printf("%d %d:%d chdir(\\"' + cwd + '\\") = 0\\n",\n' 788 ' printf("%d %d:%d %s_%s(\\"' + cwd + '\\") = 0\\n",\n'
784 ' logindex, 1, ' + pid + ');\n' 789 ' logindex, ppid, ' + pid + ', probeprov, probename);\n'
785 ' logindex++;\n'
786 ' printf("%d %d:%d %s_%s() = 0\\n",\n'
787 ' logindex, ppid, pid, probeprov, probename);\n'
788 ' logindex++;\n' 790 ' logindex++;\n'
789 '}\n') + cls.D_CODE 791 '}\n') + cls.D_CODE
790 792
791 class Context(ApiBase.Context): 793 class Context(ApiBase.Context):
792 # This is the most common format. index pid function(args) = result 794 # This is the most common format. index pid function(args) = result
793 RE_HEADER = re.compile(r'^\d+ (\d+):(\d+) ([a-zA-Z_\-]+)\((.*?)\) = (.+)$') 795 RE_HEADER = re.compile(r'^\d+ (\d+):(\d+) ([a-zA-Z_\-]+)\((.*?)\) = (.+)$')
794 796
795 # Arguments parsing. 797 # Arguments parsing.
798 RE_DTRACE_BEGIN = re.compile(r'^\"(.+?)\"$')
796 RE_CHDIR = re.compile(r'^\"(.+?)\"$') 799 RE_CHDIR = re.compile(r'^\"(.+?)\"$')
797 RE_OPEN = re.compile(r'^\"(.+?)\", (\d+), (-?\d+)$') 800 RE_OPEN = re.compile(r'^\"(.+?)\", (\d+), (-?\d+)$')
798 RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$') 801 RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$')
799 802
800 O_DIRECTORY = 0x100000 803 O_DIRECTORY = 0x100000
801 804
802 class Process(ApiBase.Context.Process): 805 class Process(ApiBase.Context.Process):
803 pass 806 pass
804 807
808 def __init__(self, blacklist):
809 super(Dtrace.Context, self).__init__(blacklist)
810 # Process ID of the trace_child_process.py wrapper script instance.
811 self._tracer_pid = None
812 # First process to be started by self._tracer_pid.
813 self._initial_pid = None
814 self._initial_cwd = None
815
805 def on_line(self, line): 816 def on_line(self, line):
806 match = self.RE_HEADER.match(line) 817 match = self.RE_HEADER.match(line)
807 assert match, line 818 assert match, line
808 fn = getattr( 819 fn = getattr(
809 self, 820 self,
810 'handle_%s' % match.group(3).replace('-', '_'), 821 'handle_%s' % match.group(3).replace('-', '_'),
811 self._handle_ignored) 822 self._handle_ignored)
812 return fn( 823 return fn(
813 int(match.group(1)), 824 int(match.group(1)),
814 int(match.group(2)), 825 int(match.group(2)),
815 match.group(3), 826 match.group(3),
816 match.group(4), 827 match.group(4),
817 match.group(5)) 828 match.group(5))
818 829
819 def handle_dtrace_BEGIN(self, _ppid, _pid, _function, args, _result): 830 def handle_dtrace_BEGIN(self, _ppid, pid, _function, args, _result):
820 pass 831 assert not self._tracer_pid and not self._initial_pid
832 self._tracer_pid = pid
833 self._initial_cwd = self.RE_DTRACE_BEGIN.match(args).group(1)
821 834
822 def handle_proc_start(self, ppid, pid, _function, _args, result): 835 def handle_proc_start(self, ppid, pid, _function, _args, result):
823 """Transfers cwd.""" 836 """Transfers cwd.
837
838 The dtrace script already takes care of only tracing the processes that
839 are child of the traced processes so there is no need to verify the
840 process hierarchy.
841 """
824 assert result == '0' 842 assert result == '0'
825 cwd = self.processes[ppid].cwd
826 assert pid not in self.processes 843 assert pid not in self.processes
844 assert (ppid == self._tracer_pid) != bool(self._initial_pid)
845 if not self._initial_pid:
846 self._initial_pid = pid
847 ppid = None
848 cwd = self._initial_cwd
849 else:
850 parent = self.processes[ppid]
851 cwd = parent.cwd
827 proc = self.processes[pid] = self.Process(self, pid, cwd, ppid) 852 proc = self.processes[pid] = self.Process(self, pid, cwd, ppid)
828 proc.cwd = cwd 853 proc.cwd = cwd
854 logging.debug('New child: %s -> %d' % (ppid, pid))
829 855
830 def handle_proc_exit(self, _ppid, pid, _function, _args, _result): 856 def handle_proc_exit(self, _ppid, pid, _function, _args, _result):
831 """Removes cwd.""" 857 """Removes cwd."""
832 self.processes[pid].cwd = None 858 if pid != self._tracer_pid:
859 # self._tracer_pid is not traced itself.
860 self.processes[pid].cwd = None
833 861
834 def handle_chdir(self, ppid, pid, _function, args, result): 862 def handle_chdir(self, _ppid, pid, _function, args, result):
835 """Updates cwd.""" 863 """Updates cwd."""
864 assert self._tracer_pid
865 assert pid in self.processes
836 if result.startswith('0'): 866 if result.startswith('0'):
837 cwd = self.RE_CHDIR.match(args).group(1) 867 cwd = self.RE_CHDIR.match(args).group(1)
838 if not cwd.startswith('/'): 868 if not cwd.startswith('/'):
839 cwd2 = os.path.join(self.processes[pid].cwd, cwd) 869 cwd2 = os.path.join(self.processes[pid].cwd, cwd)
840 logging.debug('handle_chdir(%d, %s) -> %s' % (pid, cwd, cwd2)) 870 logging.debug('handle_chdir(%d, %s) -> %s' % (pid, cwd, cwd2))
841 else: 871 else:
842 logging.debug('handle_chdir(%d, %s)' % (pid, cwd)) 872 logging.debug('handle_chdir(%d, %s)' % (pid, cwd))
843 cwd2 = cwd 873 cwd2 = cwd
844 proc = self.processes.setdefault( 874 self.processes[pid].cwd = cwd2
845 pid, self.Process(self, pid, cwd2, ppid))
846 proc.cwd = cwd2
847 else: 875 else:
848 assert False, 'Unexecpected fail: %s' % result 876 assert False, 'Unexecpected fail: %s' % result
849 877
850 def handle_open_nocancel(self, ppid, pid, function, args, result): 878 def handle_open_nocancel(self, ppid, pid, function, args, result):
851 return self.handle_open(ppid, pid, function, args, result) 879 return self.handle_open(ppid, pid, function, args, result)
852 880
853 def handle_open(self, _ppid, pid, function, args, result): 881 def handle_open(self, _ppid, pid, function, args, result):
854 match = self.RE_OPEN.match(args) 882 match = self.RE_OPEN.match(args)
855 assert match, (pid, function, args, result) 883 assert match, (pid, function, args, result)
856 args = match.groups() 884 args = match.groups()
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
989 with open(logname, 'rb') as logfile: 1017 with open(logname, 'rb') as logfile:
990 lines = [f for f in logfile.readlines() if f.strip()] 1018 lines = [f for f in logfile.readlines() if f.strip()]
991 lines = sorted(lines, key=lambda l: int(l.split(' ', 1)[0])) 1019 lines = sorted(lines, key=lambda l: int(l.split(' ', 1)[0]))
992 with open(logname, 'wb') as logfile: 1020 with open(logname, 'wb') as logfile:
993 logfile.write(''.join(lines)) 1021 logfile.write(''.join(lines))
994 1022
995 1023
996 class LogmanTrace(ApiBase): 1024 class LogmanTrace(ApiBase):
997 """Uses the native Windows ETW based tracing functionality to trace a child 1025 """Uses the native Windows ETW based tracing functionality to trace a child
998 process. 1026 process.
1027
1028 Caveat: this implementations doesn't track cwd or initial_cwd.
999 """ 1029 """
1000 class Context(ApiBase.Context): 1030 class Context(ApiBase.Context):
1001 """Processes a ETW log line and keeps the list of existent and non 1031 """Processes a ETW log line and keeps the list of existent and non
1002 existent files accessed. 1032 existent files accessed.
1003 1033
1004 Ignores directories. 1034 Ignores directories.
1005 """ 1035 """
1006 # Only the useful headers common to all entries are listed there. Any column 1036 # Only the useful headers common to all entries are listed there. Any column
1007 # at 19 or higher is dependent on the specific event. 1037 # at 19 or higher is dependent on the specific event.
1008 EVENT_NAME = 0 1038 EVENT_NAME = 0
1009 TYPE = 1 1039 TYPE = 1
1010 PID = 9 1040 PID = 9
1011 TID = 10 1041 TID = 10
1012 PROCESSOR_ID = 11 1042 PROCESSOR_ID = 11
1013 TIMESTAMP = 16 1043 TIMESTAMP = 16
1014 1044
1015 class Process(ApiBase.Context.Process): 1045 class Process(ApiBase.Context.Process):
1016 pass 1046 def __init__(self, *args):
1047 super(LogmanTrace.Context.Process, self).__init__(*args)
1048 # Handle file objects that succeeded.
1049 self.file_objects = {}
1017 1050
1018 def __init__(self, blacklist): 1051 def __init__(self, blacklist):
1019 super(LogmanTrace.Context, self).__init__(blacklist) 1052 super(LogmanTrace.Context, self).__init__(blacklist)
1020 self._drive_map = DosDriveMap() 1053 self._drive_map = DosDriveMap()
1021 self._first_line = False
1022 # Threads mapping to the corresponding process id. 1054 # Threads mapping to the corresponding process id.
1023 self._threads_active = {} 1055 self._threads_active = {}
1056 # Process ID of the tracer, e.g. tracer_inputs.py
1057 self._tracer_pid = None
1058 # First process to be started by self._tracer_pid.
1059 self._initial_pid = None
1060 self._line_number = 0
1024 1061
1025 def on_csv_line(self, line): 1062 def on_csv_line(self, line):
1026 """Processes a CSV Event line.""" 1063 """Processes a CSV Event line."""
1027 # So much white space! 1064 # So much white space!
1028 line = [i.strip() for i in line] 1065 line = [i.strip() for i in line]
1029 if not self._first_line: 1066 self._line_number += 1
1067 if self._line_number == 1:
1030 assert line == [ 1068 assert line == [
1031 u'Event Name', 1069 u'Event Name',
1032 u'Type', 1070 u'Type',
1033 u'Event ID', 1071 u'Event ID',
1034 u'Version', 1072 u'Version',
1035 u'Channel', 1073 u'Channel',
1036 u'Level', # 5 1074 u'Level', # 5
1037 u'Opcode', 1075 u'Opcode',
1038 u'Task', 1076 u'Task',
1039 u'Keyword', 1077 u'Keyword',
1040 u'PID', 1078 u'PID',
1041 u'TID', # 10 1079 u'TID', # 10
1042 u'Processor Number', 1080 u'Processor Number',
1043 u'Instance ID', 1081 u'Instance ID',
1044 u'Parent Instance ID', 1082 u'Parent Instance ID',
1045 u'Activity ID', 1083 u'Activity ID',
1046 u'Related Activity ID', # 15 1084 u'Related Activity ID', # 15
1047 u'Clock-Time', 1085 u'Clock-Time',
1048 u'Kernel(ms)', # Both have a resolution of ~15ms which makes them 1086 u'Kernel(ms)', # Both have a resolution of ~15ms which makes them
1049 u'User(ms)', # pretty much useless. 1087 u'User(ms)', # pretty much useless.
1050 u'User Data', 1088 u'User Data',
1051 ] 1089 ]
1052 self._first_line = True
1053 return 1090 return
1054 1091
1055 # As you can see, the CSV is full of useful non-redundant information: 1092 # As you can see, the CSV is full of useful non-redundant information:
1056 # Event ID 1093 # Event ID
1057 assert line[2] == '0' 1094 assert line[2] == '0'
1058 # Version 1095 # Version
1059 assert line[3] in ('2', '3'), line[3] 1096 assert line[3] in ('2', '3'), line[3]
1060 # Channel 1097 # Channel
1061 assert line[4] == '0' 1098 assert line[4] == '0'
1062 # Level 1099 # Level
(...skipping 24 matching lines...) Expand all
1087 'handle_%s_%s' % (line[self.EVENT_NAME], line[self.TYPE]), 1124 'handle_%s_%s' % (line[self.EVENT_NAME], line[self.TYPE]),
1088 None) 1125 None)
1089 if not handler: 1126 if not handler:
1090 # Try to get an universal fallback 1127 # Try to get an universal fallback
1091 handler = getattr(self, 'handle_%s_Any' % line[self.EVENT_NAME], None) 1128 handler = getattr(self, 'handle_%s_Any' % line[self.EVENT_NAME], None)
1092 if handler: 1129 if handler:
1093 handler(line) 1130 handler(line)
1094 else: 1131 else:
1095 assert False, '%s_%s' % (line[self.EVENT_NAME], line[self.TYPE]) 1132 assert False, '%s_%s' % (line[self.EVENT_NAME], line[self.TYPE])
1096 1133
1134 def _thread_to_process(self, tid):
1135 """Finds the process from the thread id."""
1136 tid = int(tid, 16)
1137 return self.processes.get(self._threads_active.get(tid))
1138
1097 @staticmethod 1139 @staticmethod
1098 def handle_EventTrace_Header(line): 1140 def handle_EventTrace_Header(line):
1099 """Verifies no event was dropped, e.g. no buffer overrun occured.""" 1141 """Verifies no event was dropped, e.g. no buffer overrun occured."""
1100 #BUFFER_SIZE = 19 1142 #BUFFER_SIZE = 19
1101 #VERSION = 20 1143 #VERSION = 20
1102 #PROVIDER_VERSION = 21 1144 #PROVIDER_VERSION = 21
1103 #NUMBER_OF_PROCESSORS = 22 1145 #NUMBER_OF_PROCESSORS = 22
1104 #END_TIME = 23 1146 #END_TIME = 23
1105 #TIMER_RESOLUTION = 24 1147 #TIMER_RESOLUTION = 24
1106 #MAX_FILE_SIZE = 25 1148 #MAX_FILE_SIZE = 25
(...skipping 10 matching lines...) Expand all
1117 #START_TIME = 36 1159 #START_TIME = 36
1118 #RESERVED_FLAGS = 37 1160 #RESERVED_FLAGS = 37
1119 #BUFFERS_LOST = 38 1161 #BUFFERS_LOST = 38
1120 #SESSION_NAME_STRING = 39 1162 #SESSION_NAME_STRING = 39
1121 #LOG_FILE_NAME_STRING = 40 1163 #LOG_FILE_NAME_STRING = 40
1122 assert line[EVENTS_LOST] == '0' 1164 assert line[EVENTS_LOST] == '0'
1123 1165
1124 def handle_EventTrace_Any(self, line): 1166 def handle_EventTrace_Any(self, line):
1125 pass 1167 pass
1126 1168
1169 def handle_FileIo_Cleanup(self, line):
1170 """General wisdom: if a file is closed, it's because it was opened.
MAD 2012/05/30 15:39:00 :-)
M-A Ruel 2012/05/30 15:57:16 Note that it is a reference to line 1197, which do
1171
1172 Note that FileIo_Close is not used since if a file was opened properly but
1173 not closed before the process exits, only Cleanup will be logged.
1174 """
1175 #IRP = 19
1176 TTID = 20 # Thread ID, that's what we want.
1177 FILE_OBJECT = 21
1178 #FILE_KEY = 22
1179 proc = self._thread_to_process(line[TTID])
1180 if not proc:
1181 # Not a process we care about.
1182 return
1183 file_object = line[FILE_OBJECT]
1184 if file_object in proc.file_objects:
1185 proc.add_file(proc.file_objects.pop(file_object))
1186
1127 def handle_FileIo_Create(self, line): 1187 def handle_FileIo_Create(self, line):
1128 """Handles a file open. 1188 """Handles a file open.
1129 1189
1130 All FileIo events are described at 1190 All FileIo events are described at
1131 http://msdn.microsoft.com/library/windows/desktop/aa363884.aspx 1191 http://msdn.microsoft.com/library/windows/desktop/aa363884.aspx
1132 for some value of 'description'. 1192 for some value of 'description'.
1133 1193
1134 " (..) process and thread id values of the IO events (..) are not valid " 1194 " (..) process and thread id values of the IO events (..) are not valid "
1135 http://msdn.microsoft.com/magazine/ee358703.aspx 1195 http://msdn.microsoft.com/magazine/ee358703.aspx
1196
1197 The FileIo.Create event doesn't return if the CreateFile() call
1198 succeeded so keep track of the file_object and look if it is closed.
MAD 2012/05/30 15:39:00 add a coma "," after succeeded please... "look if
M-A Ruel 2012/05/30 15:57:16 Changed the wording a little.
1136 """ 1199 """
1137 #IRP = 19 1200 #IRP = 19
1138 TTID = 20 # Thread ID, that's what we want. 1201 TTID = 20 # Thread ID, that's what we want.
1139 #FILE_OBJECT = 21 1202 FILE_OBJECT = 21
1140 #CREATE_OPTIONS = 22 1203 #CREATE_OPTIONS = 22
1141 #FILE_ATTRIBUTES = 23 1204 #FILE_ATTRIBUTES = 23
1142 #SHARE_ACCESS = 24 1205 #SHARE_ACCESS = 24
1143 OPEN_PATH = 25 1206 OPEN_PATH = 25
1144 1207
1145 # Find the process from the thread id. 1208 proc = self._thread_to_process(line[TTID])
1146 tid = int(line[TTID], 16)
1147 proc = self.processes.get(self._threads_active.get(tid))
1148 if not proc: 1209 if not proc:
1149 # Not a process we care about. 1210 # Not a process we care about.
1150 return 1211 return
1151 1212
1152 match = re.match(r'^\"(.+)\"$', line[OPEN_PATH]) 1213 match = re.match(r'^\"(.+)\"$', line[OPEN_PATH])
1153 raw_path = match.group(1) 1214 raw_path = match.group(1)
1154 # Ignore directories and bare drive right away. 1215 # Ignore directories and bare drive right away.
1155 if raw_path.endswith(os.path.sep): 1216 if raw_path.endswith(os.path.sep):
1156 return 1217 return
1157 filename = self._drive_map.to_dos(raw_path) 1218 filename = self._drive_map.to_dos(raw_path)
1158 # Ignore bare drive right away. 1219 # Ignore bare drive right away. Some may still fall through with format
1159 if len(raw_path) == 2: 1220 # like '\\?\X:'
1221 if len(filename) == 2:
1160 return 1222 return
1161 proc.add_file(filename) 1223 file_object = line[FILE_OBJECT]
1224 # Override any stale file object
1225 proc.file_objects[file_object] = filename
1162 1226
1163 def handle_FileIo_Rename(self, line): 1227 def handle_FileIo_Rename(self, line):
1164 # TODO(maruel): Handle? 1228 # TODO(maruel): Handle?
1165 pass 1229 pass
1166 1230
1167 def handle_FileIo_Any(self, line): 1231 def handle_FileIo_Any(self, line):
1168 pass 1232 pass
1169 1233
1170 def handle_Process_Any(self, line): 1234 def handle_Process_Any(self, line):
1171 pass 1235 pass
(...skipping 11 matching lines...) Expand all
1183 #EXIT_STATUS = 23 1247 #EXIT_STATUS = 23
1184 #DIRECTORY_TABLE_BASE = 24 1248 #DIRECTORY_TABLE_BASE = 24
1185 #USER_SID = 25 1249 #USER_SID = 25
1186 IMAGE_FILE_NAME = 26 1250 IMAGE_FILE_NAME = 26
1187 #COMMAND_LINE = 27 1251 #COMMAND_LINE = 27
1188 1252
1189 ppid = int(line[PARENT_PID], 16) 1253 ppid = int(line[PARENT_PID], 16)
1190 if line[IMAGE_FILE_NAME] == '"logman.exe"': 1254 if line[IMAGE_FILE_NAME] == '"logman.exe"':
1191 # logman's parent is trace_input.py or whatever tool using it as a 1255 # logman's parent is trace_input.py or whatever tool using it as a
1192 # library. Trace any other children started by it. 1256 # library. Trace any other children started by it.
1193 assert ppid not in self.processes 1257 assert not self._tracer_pid
1194 self.processes[ppid] = self.Process(self, ppid, None, None) 1258 self._tracer_pid = ppid
1195 logging.info('Found logman\'s parent at %d' % ppid) 1259 logging.info('Found logman\'s parent at %d' % ppid)
1196 1260
1197 def handle_Process_End(self, line): 1261 def handle_Process_End(self, line):
1198 # Look if it is logman terminating, if so, grab the parent's process pid 1262 # Look if it is logman terminating, if so, grab the parent's process pid
1199 # and inject cwd. 1263 # and inject cwd.
1200 pid = line[self.PID] 1264 pid = line[self.PID]
1201 if pid in self.processes: 1265 if pid in self.processes:
1202 logging.info('Terminated: %d' % pid) 1266 logging.info('Terminated: %d' % pid)
1267 self.processes[pid].cwd = None
1203 1268
1204 def handle_Process_Start(self, line): 1269 def handle_Process_Start(self, line):
1205 """Handles a new child process started by PID.""" 1270 """Handles a new child process started by PID."""
1206 #UNIQUE_PROCESS_KEY = 19 1271 #UNIQUE_PROCESS_KEY = 19
1207 PROCESS_ID = 20 1272 PROCESS_ID = 20
1208 #PARENT_PID = 21 1273 #PARENT_PID = 21
1209 #SESSION_ID = 22 1274 #SESSION_ID = 22
1210 #EXIT_STATUS = 23 1275 #EXIT_STATUS = 23
1211 #DIRECTORY_TABLE_BASE = 24 1276 #DIRECTORY_TABLE_BASE = 24
1212 #USER_SID = 25 1277 #USER_SID = 25
1213 IMAGE_FILE_NAME = 26 1278 IMAGE_FILE_NAME = 26
1214 #COMMAND_LINE = 27 1279 #COMMAND_LINE = 27
1215 1280
1216 ppid = line[self.PID] 1281 ppid = line[self.PID]
1217 pid = int(line[PROCESS_ID], 16) 1282 pid = int(line[PROCESS_ID], 16)
1218 if ppid in self.processes: 1283 if ppid == self._tracer_pid:
1219 # Need to ignore processes we don't know about because the log is 1284 # Need to ignore processes we don't know about because the log is
1220 # system-wide. 1285 # system-wide.
1221 if line[IMAGE_FILE_NAME] == '"logman.exe"': 1286 if line[IMAGE_FILE_NAME] == '"logman.exe"':
1222 # Skip the shutdown call when "logman.exe stop" is executed. 1287 # Skip the shutdown call when "logman.exe stop" is executed.
1223 return 1288 return
1289 self._initial_pid = self._initial_pid or pid
1290 assert pid not in self.processes
1291 self.processes[pid] = self.Process(self, pid, None, None)
1292 logging.info(
1293 'New child: %d -> %d %s' % (ppid, pid, line[IMAGE_FILE_NAME]))
1294 elif ppid in self.processes:
1295 # Grand-children
1224 assert pid not in self.processes 1296 assert pid not in self.processes
1225 self.processes[pid] = self.Process(self, pid, None, ppid) 1297 self.processes[pid] = self.Process(self, pid, None, ppid)
1226 logging.info( 1298 logging.info(
1227 'New child: %d -> %d %s' % (ppid, pid, line[IMAGE_FILE_NAME])) 1299 'New child: %d -> %d %s' % (ppid, pid, line[IMAGE_FILE_NAME]))
1228 1300
1229 def handle_Thread_End(self, line): 1301 def handle_Thread_End(self, line):
1230 """Has the same parameters as Thread_Start.""" 1302 """Has the same parameters as Thread_Start."""
1231 tid = int(line[self.TID], 16) 1303 tid = int(line[self.TID], 16)
1232 self._threads_active.pop(tid, None) 1304 self._threads_active.pop(tid, None)
1233 1305
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 'TMP', 1353 'TMP',
1282 ) 1354 )
1283 for i in vars_to_ignore: 1355 for i in vars_to_ignore:
1284 if os.environ.get(i): 1356 if os.environ.get(i):
1285 self.IGNORED.add(os.environ[i]) 1357 self.IGNORED.add(os.environ[i])
1286 1358
1287 # Also add their short path name equivalents. 1359 # Also add their short path name equivalents.
1288 for i in list(self.IGNORED): 1360 for i in list(self.IGNORED):
1289 self.IGNORED.add(GetShortPathName(i.replace('/', os.path.sep))) 1361 self.IGNORED.add(GetShortPathName(i.replace('/', os.path.sep)))
1290 1362
1291 # Add this one last since it has no short path name equivalent. 1363 # Add these last since they have no short path name equivalent.
1292 self.IGNORED.add('\\SystemRoot') 1364 self.IGNORED.add('\\SystemRoot')
1365 # All the NTFS metadata is in the form x:\$EXTEND or stuff like that.
1366 for letter in (chr(l) for l in xrange(ord('C'), ord('Z')+1)):
1367 self.IGNORED.add('%s\\\$' % letter)
1368 # TODO(maruel): Remove the need to add these.
1369 self.IGNORED.add('\\\\?\\%s\\$' % letter)
1293 self.IGNORED = tuple(sorted(self.IGNORED)) 1370 self.IGNORED = tuple(sorted(self.IGNORED))
1294 1371
1295 @staticmethod 1372 @staticmethod
1296 def clean_trace(logname): 1373 def clean_trace(logname):
1297 if os.path.isfile(logname): 1374 if os.path.isfile(logname):
1298 os.remove(logname) 1375 os.remove(logname)
1299 if os.path.isfile(logname + '.etl'): 1376 if os.path.isfile(logname + '.etl'):
1300 os.remove(logname + '.etl') 1377 os.remove(logname + '.etl')
1301 1378
1302 @classmethod 1379 @classmethod
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
1801 os.path.abspath(options.log), 1878 os.path.abspath(options.log),
1802 args, 1879 args,
1803 options.root_dir, 1880 options.root_dir,
1804 options.cwd, 1881 options.cwd,
1805 options.product_dir, 1882 options.product_dir,
1806 options.force) 1883 options.force)
1807 1884
1808 1885
1809 if __name__ == '__main__': 1886 if __name__ == '__main__':
1810 sys.exit(main()) 1887 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698