blob: 7ddd5b02f3b365a25bb08ab08162b3868048c346 [file]
# Copyright 2016 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.
import logging
import os
import re
from analysis.constants import CHROMIUM_REPO_URL
from analysis.constants import CHROMIUM_ROOT_PATH
GENERATED_CODE_FILE_PATH_PATTERN = re.compile(r'.*out/[^/]+/gen/')
THIRD_PARTY_FILE_PATH_MARKER = 'third_party'
JAVA_CHROMIUM_FUNCTION_MARKER = 'org.chromium.chrome.browser'
JAVA_CHROMIUM_CODE_REPOSITORY_PATH = 'src/chrome/android/java/src'
def GetFullPathForJavaFrame(function):
"""Uses java function package name to normalize and generate full file path.
Args:
function: Java function, for example, 'org.chromium.CrAct.onDestroy'.
Returns:
A string of normalized full path, for example, org/chromium/CrAct.java
"""
file_path = '%s.java' % '/'.join(function.split('.')[:-1])
if JAVA_CHROMIUM_FUNCTION_MARKER in function:
file_path = '%s/%s' % (JAVA_CHROMIUM_CODE_REPOSITORY_PATH, file_path)
return file_path
def GetCrashedLineRange(line_range_str):
"""Gets crashed line range.
Args:
line_range_str (str): Has the format of 'line_number:range' if crash line
range provided, else 'line_number'.
Returns:
A list of line numbers (int) where crash happened. For example, 655:1 has
crashed lines 655 and 656.
"""
if ':' not in line_range_str:
return [int(line_range_str)]
line_number, range_length = map(int, line_range_str.split(':'))
return range(line_number, line_number + range_length + 1)
def RemovePrefix(string, prefix):
"""Removes prefix from a string."""
return string[len(prefix):] if string.startswith(prefix) else string
def GetDepPathAndNormalizedFilePath(path, deps, is_java=False,
root_path=None,
root_repo_url=None):
"""Determines the dep of a file path and normalizes the path.
Args:
path (str): Represents a path.
deps (dict): Map dependency path to its corresponding Dependency.
is_java (boolean): If the path is a java stack path.
Returns:
A tuple - (dep_path, normalized_path, repo_url)
dep_path (str): Dependency path of this path. (e.g 'src', 'src/v8'
...etc), '' is no match found.
normalized_path (str): Normalized relative file path starting from dep_path.
repo_url (str): Repository url corresponding to dep_path.
"""
# Default the root repo to chromium if None provided.
root_path = root_path or CHROMIUM_ROOT_PATH
root_repo_url = root_repo_url or CHROMIUM_REPO_URL
# According to crbug.com/810426, a breakage from something in build,
# that caused paths relative to out/*asan directory. So strip the ../../ in
# the front of file path.
path = RemovePrefix(path, '../../')
# First normalize the path by retrieving the normalized path.
normalized_path = os.path.normpath(path).replace('\\', '/')
if GENERATED_CODE_FILE_PATH_PATTERN.match(normalized_path):
logging.info('Generated code path %s', normalized_path)
return '', normalized_path, None
# Iterate through all dep paths in the parsed DEPS in an order.
for dep_path in sorted(deps.keys(), key=lambda path: -path.count('/')):
# trim the 'src' in the beginning of the dep_path to match, because there
# are many cases, especially in linux platform, the file paths are like,
# 'third_party/WebKit/Source/...', or 'v8/...'.
trimmed_dep_path = dep_path
if (trimmed_dep_path.startswith(root_path + '/') and
trimmed_dep_path != root_path):
trimmed_dep_path = trimmed_dep_path[len(root_path + '/'):]
# We need to consider when the lowercased dep path is in the path,
# because syzyasan builds and win canary crashes return lowercased file
# path.
trimmed_dep_path_lower = trimmed_dep_path.lower()
dep_path_lower = dep_path.lower()
current_dep_path = ''
if (normalized_path.startswith(trimmed_dep_path + '/') or
normalized_path.startswith(trimmed_dep_path_lower + '/')):
# Case when the retrieved path is in lowercase.
if normalized_path.startswith(trimmed_dep_path + '/'):
current_dep_path = trimmed_dep_path
else:
current_dep_path = trimmed_dep_path_lower
# For some special cases, for example, a file like
# 'https://chromium.googlesource.com/chromium/src/+/master/'
# 'third_party/tcmalloc/chromium/src/common.cc', this path shouldn't be
# matched with 'src' in between, it should be matched to the trimmed 'src'
# in the beginning.
if (not normalized_path.startswith(THIRD_PARTY_FILE_PATH_MARKER) and
(dep_path + '/' in normalized_path or
dep_path_lower + '/' in normalized_path)):
if dep_path + '/' in normalized_path:
current_dep_path = dep_path
else:
current_dep_path = dep_path_lower
# Normalize the path by stripping everything off the dep's relative
# path.
if current_dep_path:
normalized_path = normalized_path.split(current_dep_path + '/', 1)[1]
return dep_path, normalized_path, deps[dep_path].repo_url
# If path is a java stack path, don't default dep_path to src.
if is_java:
return '', normalized_path, None
# For some crashes, the file path looks like this:
# third_party/WebKit/Source/a.cc, the src in the beginning is trimmed, so
# default the dep path to 'src' if no match found.
return root_path, normalized_path, root_repo_url