Commit 51a6b19d authored by maruel@chromium.org's avatar maruel@chromium.org

Add touch-only detection for strace API implementation.

Update smoke test accordingly.

R=cmp@chromium.org
BUG=
TEST=


Review URL: https://chromiumcodereview.appspot.com/10748009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146159 0039d316-1c4b-4281-b951-d872f2087c98
parent 12126d37
...@@ -871,11 +871,14 @@ class ApiBase(object): ...@@ -871,11 +871,14 @@ class ApiBase(object):
render_to_string_and_fix_case(self.initial_cwd), render_to_string_and_fix_case(self.initial_cwd),
children) children)
def add_file(self, filepath): def add_file(self, filepath, touch_only):
if self.root().blacklist(unicode(filepath)): if self.root().blacklist(unicode(filepath)):
return return
logging.debug('add_file(%d, %s)' % (self.pid, filepath)) logging.debug('add_file(%d, %s, %s)' % (self.pid, filepath, touch_only))
self.files.add(filepath) if touch_only:
self.only_touched.add(filepath)
else:
self.files.add(filepath)
def __init__(self, blacklist): def __init__(self, blacklist):
self.blacklist = blacklist self.blacklist = blacklist
...@@ -1013,11 +1016,14 @@ class Strace(ApiBase): ...@@ -1013,11 +1016,14 @@ class Strace(ApiBase):
UNNAMED_FUNCTION = '????' UNNAMED_FUNCTION = '????'
# Arguments parsing. # Arguments parsing.
RE_ACCESS = re.compile(r'^\"(.+?)\", R_[A-Z]+$')
RE_CHDIR = re.compile(r'^\"(.+?)\"$') RE_CHDIR = re.compile(r'^\"(.+?)\"$')
RE_EXECVE = re.compile(r'^\"(.+?)\", \[(.+)\], \[\/\* \d+ vars? \*\/\]$') RE_EXECVE = re.compile(r'^\"(.+?)\", \[(.+)\], \[\/\* \d+ vars? \*\/\]$')
RE_OPEN2 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+)$') RE_OPEN2 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+)$')
RE_OPEN3 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+), (\d+)$') RE_OPEN3 = re.compile(r'^\"(.*?)\", ([A-Z\_\|]+), (\d+)$')
RE_READLINK = re.compile(r'^\"(.+?)\", \".+?\"(\.\.\.)?, \d+$')
RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$') RE_RENAME = re.compile(r'^\"(.+?)\", \"(.+?)\"$')
RE_STAT = re.compile(r'\"(.+?)\", \{.+?, \.\.\.\}')
class RelativePath(object): class RelativePath(object):
"""A late-bound relative path.""" """A late-bound relative path."""
...@@ -1143,6 +1149,12 @@ class Strace(ApiBase): ...@@ -1143,6 +1149,12 @@ class Strace(ApiBase):
line, line,
e) e)
def handle_access(self, args, result):
if result.startswith('-1'):
return
match = self.RE_ACCESS.match(args)
self._handle_file(match.group(1), True)
def handle_chdir(self, args, result): def handle_chdir(self, args, result):
"""Updates cwd.""" """Updates cwd."""
if not result.startswith('0'): if not result.startswith('0'):
...@@ -1183,7 +1195,7 @@ class Strace(ApiBase): ...@@ -1183,7 +1195,7 @@ class Strace(ApiBase):
'Failed to process execve(%s)' % args, 'Failed to process execve(%s)' % args,
None, None, None) None, None, None)
filepath = match.group(1) filepath = match.group(1)
self._handle_file(filepath) self._handle_file(filepath, False)
self.executable = self.RelativePath(self.get_cwd(), filepath) self.executable = self.RelativePath(self.get_cwd(), filepath)
self.command = process_quoted_arguments(match.group(2)) self.command = process_quoted_arguments(match.group(2))
...@@ -1195,20 +1207,47 @@ class Strace(ApiBase): ...@@ -1195,20 +1207,47 @@ class Strace(ApiBase):
def handle_fork(_args, _result): def handle_fork(_args, _result):
raise NotImplementedError('Unexpected/unimplemented trace fork()') raise NotImplementedError('Unexpected/unimplemented trace fork()')
def handle_getcwd(self, _args, _result):
pass
def handle_lstat(self, args, result):
if result.startswith('-1'):
return
match = self.RE_STAT.match(args)
self._handle_file(match.group(1), True)
def handle_open(self, args, result): def handle_open(self, args, result):
if result.startswith('-1'): if result.startswith('-1'):
return return
args = (self.RE_OPEN3.match(args) or self.RE_OPEN2.match(args)).groups() args = (self.RE_OPEN3.match(args) or self.RE_OPEN2.match(args)).groups()
if 'O_DIRECTORY' in args[1]: if 'O_DIRECTORY' in args[1]:
return return
self._handle_file(args[0]) self._handle_file(args[0], False)
def handle_readlink(self, args, result):
if result.startswith('-1'):
return
match = self.RE_READLINK.match(args)
if not match:
raise TracingFailure(
'Failed to parse: readlink(%s) = %s' % (args, result),
None,
None,
None)
self._handle_file(match.group(1), False)
def handle_rename(self, args, result): def handle_rename(self, args, result):
if result.startswith('-1'): if result.startswith('-1'):
return return
args = self.RE_RENAME.match(args).groups() args = self.RE_RENAME.match(args).groups()
self._handle_file(args[0]) self._handle_file(args[0], False)
self._handle_file(args[1]) self._handle_file(args[1], False)
def handle_stat(self, args, result):
if result.startswith('-1'):
return
match = self.RE_STAT.match(args)
self._handle_file(match.group(1), True)
@staticmethod @staticmethod
def handle_stat64(_args, _result): def handle_stat64(_args, _result):
...@@ -1218,9 +1257,10 @@ class Strace(ApiBase): ...@@ -1218,9 +1257,10 @@ class Strace(ApiBase):
def handle_vfork(_args, _result): def handle_vfork(_args, _result):
raise NotImplementedError('Unexpected/unimplemented trace vfork()') raise NotImplementedError('Unexpected/unimplemented trace vfork()')
def _handle_file(self, filepath): def _handle_file(self, filepath, touch_only):
filepath = self.RelativePath(self.get_cwd(), filepath) filepath = self.RelativePath(self.get_cwd(), filepath)
self.add_file(filepath) #assert not touch_only, unicode(filepath)
self.add_file(filepath, touch_only)
def __init__(self, blacklist, initial_cwd): def __init__(self, blacklist, initial_cwd):
super(Strace.Context, self).__init__(blacklist) super(Strace.Context, self).__init__(blacklist)
...@@ -1284,6 +1324,8 @@ class Strace(ApiBase): ...@@ -1284,6 +1324,8 @@ class Strace(ApiBase):
return [i[len(prefix):] for i in dir(cls.Process) if i.startswith(prefix)] return [i[len(prefix):] for i in dir(cls.Process) if i.startswith(prefix)]
class Tracer(ApiBase.Tracer): class Tracer(ApiBase.Tracer):
MAX_LEN = 256
def trace(self, cmd, cwd, tracename, output): def trace(self, cmd, cwd, tracename, output):
"""Runs strace on an executable.""" """Runs strace on an executable."""
logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output)) logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output))
...@@ -1300,11 +1342,12 @@ class Strace(ApiBase): ...@@ -1300,11 +1342,12 @@ class Strace(ApiBase):
if output: if output:
stdout = subprocess.PIPE stdout = subprocess.PIPE
stderr = subprocess.STDOUT stderr = subprocess.STDOUT
traces = ','.join(Strace.Context.traces()) # Ensure all file related APIs are hooked.
traces = ','.join(Strace.Context.traces() + ['file'])
trace_cmd = [ trace_cmd = [
'strace', 'strace',
'-ff', '-ff',
'-s', '256', '-s', '%d' % self.MAX_LEN,
'-e', 'trace=%s' % traces, '-e', 'trace=%s' % traces,
'-o', self._logname + '.' + tracename, '-o', self._logname + '.' + tracename,
] ]
...@@ -1583,7 +1626,7 @@ class Dtrace(ApiBase): ...@@ -1583,7 +1626,7 @@ class Dtrace(ApiBase):
# saw open_nocancel(".", 0, 0) = 0 lines. # saw open_nocancel(".", 0, 0) = 0 lines.
if os.path.isdir(filepath): if os.path.isdir(filepath):
return return
self.processes[pid].add_file(filepath) self.processes[pid].add_file(filepath, False)
def handle_ftruncate(self, pid, args): def handle_ftruncate(self, pid, args):
"""Just used as a signal to kill dtrace, ignoring.""" """Just used as a signal to kill dtrace, ignoring."""
...@@ -2304,7 +2347,7 @@ class LogmanTrace(ApiBase): ...@@ -2304,7 +2347,7 @@ class LogmanTrace(ApiBase):
return return
file_object = line[FILE_OBJECT] file_object = line[FILE_OBJECT]
if file_object in proc.file_objects: if file_object in proc.file_objects:
proc.add_file(proc.file_objects.pop(file_object)) proc.add_file(proc.file_objects.pop(file_object), False)
def handle_FileIo_Create(self, line): def handle_FileIo_Create(self, line):
"""Handles a file open. """Handles a file open.
......
...@@ -573,6 +573,10 @@ class TraceInputsImport(TraceInputsBase): ...@@ -573,6 +573,10 @@ class TraceInputsImport(TraceInputsBase):
], ],
'executable': self.real_executable, 'executable': self.real_executable,
'files': [ 'files': [
{
'path': os.path.join(u'data', 'trace_inputs', 'test_file.txt'),
'size': 0,
},
{ {
'path': os.path.join(u'data', 'trace_inputs', 'touch_only.py'), 'path': os.path.join(u'data', 'trace_inputs', 'touch_only.py'),
'size': self._size('data', 'trace_inputs', 'touch_only.py'), 'size': self._size('data', 'trace_inputs', 'touch_only.py'),
...@@ -581,6 +585,10 @@ class TraceInputsImport(TraceInputsBase): ...@@ -581,6 +585,10 @@ class TraceInputsImport(TraceInputsBase):
'initial_cwd': self.initial_cwd, 'initial_cwd': self.initial_cwd,
}, },
} }
if sys.platform != 'linux2':
# TODO(maruel): Remove once properly implemented.
expected['root']['files'].pop(0)
actual = results.flatten() actual = results.flatten()
self.assertTrue(actual['root'].pop('pid')) self.assertTrue(actual['root'].pop('pid'))
self.assertEquals(expected, actual) self.assertEquals(expected, actual)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment