16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# Copyright (c) 2014 The Chromium Authors. All rights reserved.
26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)# found in the LICENSE file.
46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import re
66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)import crash_utils
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciSYZYASAN_STACK_FRAME_PATTERN = re.compile(
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    r'(CF: )?(.*?)( \(FPO: .*\) )?( \(CONV: .*\) )?\[(.*) @ (\d+)\]')
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciFILE_PATH_AND_LINE_PATTERN = re.compile(r'(.*?):(\d+)(:\d+)?')
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class StackFrame(object):
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """Represents a frame in stacktrace.
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  Attributes:
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    index: An index of the stack frame.
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    component_path: The path of the component this frame represents.
216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    component_name: The name of the component this frame represents.
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    file_name: The name of the file that crashed.
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    function: The function that caused the crash.
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    file_path: The path of the crashed file.
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    crashed_line_range: The line of the file that caused the crash.
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """
276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def __init__(self, stack_frame_index, component_path, component_name,
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               file_name, function, file_path, crashed_line_range):
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.index = stack_frame_index
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.component_path = component_path
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.component_name = component_name
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.file_name = file_name
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.function = function
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.file_path = file_path
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.crashed_line_range = crashed_line_range
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class CallStack(object):
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """Represents a call stack within a stacktrace.
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  It is a list of StackFrame object, and the object keeps track of whether
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  the stack is crash stack, freed or previously-allocated.
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def __init__(self, stack_priority):
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.frame_list = []
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.priority = stack_priority
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def Add(self, stacktrace_line):
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.frame_list.append(stacktrace_line)
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def GetTopNFrames(self, n):
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return self.frame_list[:n]
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)class Stacktrace(object):
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """Represents Stacktrace object.
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  Contains a list of callstacks, because one stacktrace might have more than
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  one callstacks.
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  """
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def __init__(self, stacktrace, build_type, parsed_deps):
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.stack_list = None
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.ParseStacktrace(stacktrace, build_type, parsed_deps)
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def ParseStacktrace(self, stacktrace, build_type, parsed_deps):
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """Parses stacktrace and normalizes it.
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    If there are multiple callstacks within the stacktrace,
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    it will parse each of them separately, and store them in the stack_list
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    variable.
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Args:
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      stacktrace: A string containing stacktrace.
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      build_type: A string containing the build type of the crash.
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      parsed_deps: A parsed DEPS file to normalize path with.
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # If the passed in string is empty, the object does not represent anything.
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if not stacktrace:
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Reset the stack list.
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.stack_list = []
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    reached_new_callstack = False
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Note that we do not need exact stack frame index, we only need relative
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # position of a frame within a callstack. The reason for not extracting
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # index from a line is that some stack frames do not have index.
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    stack_frame_index = 0
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    current_stack = CallStack(-1)
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    for line in stacktrace:
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      line = line.strip()
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      (is_new_callstack, stack_priority) = self.__IsStartOfNewCallStack(
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          line, build_type)
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if is_new_callstack:
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # If this callstack is crash stack, update the boolean.
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if not reached_new_callstack:
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          reached_new_callstack = True
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          current_stack = CallStack(stack_priority)
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # If this is from freed or allocation, add the callstack we have
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # to the list of callstacks, and increment the stack priority.
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        else:
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          stack_frame_index = 0
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          if current_stack and current_stack.frame_list:
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            self.stack_list.append(current_stack)
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          current_stack = CallStack(stack_priority)
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # Generate stack frame object from the line.
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      parsed_stack_frame = self.__GenerateStackFrame(
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          stack_frame_index, line, build_type, parsed_deps)
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # If the line does not represent the stack frame, ignore this line.
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if not parsed_stack_frame:
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        continue
1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # Add the parsed stack frame object to the current stack.
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      current_stack.Add(parsed_stack_frame)
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      stack_frame_index += 1
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Add the current callstack only if there are frames in it.
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if current_stack and current_stack.frame_list:
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      self.stack_list.append(current_stack)
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def __IsStartOfNewCallStack(self, line, build_type):
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """Check if this line is the start of the new callstack.
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Since each builds have different format of stacktrace, the logic for
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    checking the line for all builds is handled in here.
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Args:
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      line: Line to check for.
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      build_type: The name of the build.
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Returns:
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      True if the line is the start of new callstack, False otherwise. If True,
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      it also returns the priority of the line.
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if 'syzyasan' in build_type:
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # In syzyasan build, new stack starts with 'crash stack:',
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # 'freed stack:', etc.
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      callstack_start_pattern = re.compile(r'^(.*) stack:$')
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      match = callstack_start_pattern.match(line)
1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # If the line matches the callstack start pattern.
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if match:
1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # Check the type of the new match.
1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        stack_type = match.group(1)
1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # Crash stack gets priority 0.
1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        if stack_type == 'Crash':
1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          return (True, 0)
1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        # Other callstacks all get priority 1.
1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        else:
1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          return (True, 1)
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    elif 'tsan' in build_type:
1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # Create patterns for each callstack type.
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      crash_callstack_start_pattern1 = re.compile(
1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^(Read|Write) of size \d+')
1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      crash_callstack_start_pattern2 = re.compile(
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          r'^[A-Z]+: ThreadSanitizer')
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      allocation_callstack_start_pattern = re.compile(
1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^Previous (write|read) of size \d+')
1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      location_callstack_start_pattern = re.compile(
1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^Location is heap block of size \d+')
1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # Crash stack gets priority 0.
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (crash_callstack_start_pattern1.match(line) or
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          crash_callstack_start_pattern2.match(line)):
1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 0)
1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # All other stacks get priority 1.
1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if allocation_callstack_start_pattern.match(line):
1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 1)
1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if location_callstack_start_pattern.match(line):
1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 1)
1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    else:
1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # In asan and other build types, crash stack can start
1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # in two different ways.
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      crash_callstack_start_pattern1 = re.compile(r'^==\d+== ?[A-Z]+:')
1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      crash_callstack_start_pattern2 = re.compile(
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^(READ|WRITE) of size \d+ at')
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      crash_callstack_start_pattern3 = re.compile(r'^backtrace:')
1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      freed_callstack_start_pattern = re.compile(
1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^freed by thread T\d+ (.* )?here:')
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      allocation_callstack_start_pattern = re.compile(
1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^previously allocated by thread T\d+ (.* )?here:')
1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      other_callstack_start_pattern = re.compile(
2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          r'^Thread T\d+ (.* )?created by')
2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # Crash stack gets priority 0.
2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if (crash_callstack_start_pattern1.match(line) or
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          crash_callstack_start_pattern2.match(line) or
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          crash_callstack_start_pattern3.match(line)):
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 0)
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      # All other callstack gets priority 1.
2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if freed_callstack_start_pattern.match(line):
2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 1)
2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if allocation_callstack_start_pattern.match(line):
2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 1)
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      if other_callstack_start_pattern.match(line):
2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        return (True, 1)
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # If the line does not match any pattern, return false and a dummy for
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # stack priority.
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return (False, -1)
2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __GenerateStackFrame(self, stack_frame_index, line, build_type,
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           parsed_deps):
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """Extracts information from a line in stacktrace.
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Args:
2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      stack_frame_index: A stack frame index of this line.
2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      line: A stacktrace string to extract data from.
2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      build_type: A string containing the build type
2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                    of this crash (e.g. linux_asan_chrome_mp).
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      parsed_deps: A parsed DEPS file to normalize path with.
2326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Returns:
2346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      A triple containing the name of the function, the path of the file and
2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      the crashed line number.
2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """
2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    line_parts = line.split()
2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    try:
2396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if 'syzyasan' in build_type:
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        stack_frame_match = SYZYASAN_STACK_FRAME_PATTERN.match(line)
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if not stack_frame_match:
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          return None
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        file_path = stack_frame_match.group(5)
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        crashed_line_range = [int(stack_frame_match.group(6))]
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        function = stack_frame_match.group(2)
2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      else:
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if not line_parts[0].startswith('#'):
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          return None
2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if 'tsan' in build_type:
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          file_path_and_line = line_parts[-2]
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          function = ' '.join(line_parts[1:-2])
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        else:
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          file_path_and_line = line_parts[-1]
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          function = ' '.join(line_parts[3:-1])
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # Get file path and line info from the line.
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        file_path_and_line_match = FILE_PATH_AND_LINE_PATTERN.match(
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            file_path_and_line)
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # Return None if the file path information is not available
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if not file_path_and_line_match:
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          return None
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        file_path = file_path_and_line_match.group(1)
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # Get the crashed line range. For example, file_path:line_number:range.
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        crashed_line_range_num = file_path_and_line_match.group(3)
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if crashed_line_range_num:
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          # Strip ':' prefix.
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          crashed_line_range_num = int(crashed_line_range_num[1:])
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        else:
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          crashed_line_range_num = 0
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        crashed_line_number = int(file_path_and_line_match.group(2))
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        # For example, 655:1 has crashed lines 655 and 656.
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        crashed_line_range = \
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            range(crashed_line_number,
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  crashed_line_number + crashed_line_range_num + 1)
2846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Return None if the line is malformed.
2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    except IndexError:
2876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return None
2886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    except ValueError:
2896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return None
2906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Normalize the file path so that it can be compared to repository path.
2926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    (component_path, component_name, file_path) = (
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        crash_utils.NormalizePath(file_path, parsed_deps))
2946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
2956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Return a new stack frame object with the parsed information.
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    file_name = file_path.split('/')[-1]
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # If we have the common stack frame index pattern, then use it
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # since it is more reliable.
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    index_match = re.match('\s*#(\d+)\s.*', line)
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if index_match:
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      stack_frame_index = int(index_match.group(1))
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return StackFrame(stack_frame_index, component_path, component_name,
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      file_name, function, file_path, crashed_line_range)
3066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def __getitem__(self, index):
3086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return self.stack_list[index]
3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  def GetCrashStack(self):
3116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """Returns the callstack with the highest priority.
3126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Crash stack has priority 0, and allocation/freed/other thread stacks
3146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    get priority 1.
3156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
3166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Returns:
3176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      The highest priority callstack in the stacktrace.
3186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    """
3196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    sorted_stacklist = sorted(self.stack_list,
3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                              key=lambda callstack: callstack.priority)
3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return sorted_stacklist[0]
322