1#!/usr/bin/env python3 2# Copyright 2018 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Tests for extract_unwind_tables.py 7 8This test suite contains various tests for extracting CFI tables from breakpad 9symbol files. 10""" 11 12import io 13import optparse 14import os 15import struct 16import sys 17import tempfile 18import unittest 19 20import extract_unwind_tables 21 22sys.path.append(os.path.join(os.path.dirname(__file__), "gyp")) 23from util import build_utils 24 25 26class TestExtractUnwindTables(unittest.TestCase): 27 def testExtractCfi(self): 28 test_data_lines = """ 29MODULE Linux arm CDE12FE1DF2B37A9C6560B4CBEE056420 lib_chrome.so 30INFO CODE_ID E12FE1CD2BDFA937C6560B4CBEE05642 31FILE 0 ../../base/allocator/allocator_check.cc 32FILE 1 ../../base/allocator/allocator_extension.cc 33FILE 2 ../../base/allocator/allocator_shim.cc 34FUNC 1adcb60 54 0 i2d_name_canon 351adcb60 1a 509 17054 363b94c70 2 69 40 37PUBLIC e17001 0 assist_ranker::(anonymous namespace)::FakePredict::Initialize() 38PUBLIC e17005 0 (anonymous namespace)::FileDeleter(base::File) 39STACK CFI INIT e17000 4 .cfa: sp 0 + .ra: lr 40STACK CFI INIT 0 4 .cfa: sp 0 + .ra: lr 41STACK CFI 2 .cfa: sp 4 + 42STACK CFI 4 .cfa: sp 12 + .ra: .cfa -8 + ^ r7: .cfa -12 + ^ 43STACK CFI 6 .cfa: sp 16 + 44STACK CFI INIT e1a96e 20 .cfa: sp 0 + .ra: lr 45STACK CFI e1a970 .cfa: sp 4 + 46STACK CFI e1a972 .cfa: sp 12 + .ra: .cfa -8 + ^ r7: .cfa -12 + ^ 47STACK CFI e1a974 .cfa: sp 16 + 48STACK CFI INIT e1a1e4 b0 .cfa: sp 0 + .ra: lr 49STACK CFI e1a1e6 .cfa: sp 16 + .ra: .cfa -4 + ^ r4: .cfa -16 + ^ r5: .cfa -12 + 50STACK CFI e1a1e8 .cfa: sp 80 + 51STACK CFI INIT 0 4 .cfa: sp 0 + .ra: lr 52STACK CFI INIT 3b92e24 3c .cfa: sp 0 + .ra: lr 53STACK CFI 3b92e4c .cfa: sp 16 + .ra: .cfa -12 + ^ 54STACK CFI INIT e17004 0 .cfa: sp 0 + .ra: lr 55STACK CFI e17004 2 .cfa: sp 0 + .ra: lr 56STACK CFI INIT 3b92e70 38 .cfa: sp 0 + .ra: lr 57STACK CFI 3b92e74 .cfa: sp 8 + .ra: .cfa -4 + ^ r4: .cfa -8 + ^ 58STACK CFI 3b92e90 .cfa: sp 0 + .ra: .ra r4: r4 59STACK CFI INIT 3b93114 6c .cfa: sp 0 + .ra: lr 60STACK CFI 3b93118 .cfa: r7 16 + .ra: .cfa -4 + ^ 61STACK CFI INIT 3b92114 6c .cfa: sp 0 + .ra: lr 62STACK CFI 3b92118 .cfa: r7 16 + .ra: .cfa -20 + ^ 63STACK CFI INIT 3b93214 fffff .cfa: sp 0 + .ra: lr 64STACK CFI 3b93218 .cfa: r7 16 + .ra: .cfa -4 + ^ 65""".splitlines() 66 cfi_data = extract_unwind_tables._GetAllCfiRows( 67 [l.encode('utf8') for l in test_data_lines]) 68 out_file = io.BytesIO() 69 extract_unwind_tables._WriteCfiData(cfi_data, out_file) 70 71 expected_cfi_data = { 72 0xe1a1e4: [0x2, 0x11, 0x4, 0x50], 73 0xe1a296: [], 74 0xe1a96e: [0x2, 0x4, 0x4, 0xe, 0x6, 0x10], 75 0xe1a990: [], 76 0x3b92e24: [0x28, 0x13], 77 0x3b92e62: [], 78 } 79 expected_function_count = len(expected_cfi_data) 80 81 actual_output = [] 82 out_file.seek(0) 83 while True: 84 read = out_file.read(2) 85 if not read: 86 break 87 actual_output.append(struct.unpack('H', read)[0]) 88 89 # First value is size of unw_index table. 90 unw_index_size = actual_output[1] << 16 | actual_output[0] 91 # |unw_index_size| should match entry count. 92 self.assertEqual(expected_function_count, unw_index_size) 93 # |actual_output| is in blocks of 2 bytes. Skip first 4 bytes representing 94 # size. 95 unw_index_start = 2 96 unw_index_addr_end = unw_index_start + expected_function_count * 2 97 unw_index_end = unw_index_addr_end + expected_function_count 98 unw_index_addr_col = actual_output[unw_index_start:unw_index_addr_end] 99 unw_index_index_col = actual_output[unw_index_addr_end:unw_index_end] 100 101 unw_data_start = unw_index_end 102 unw_data = actual_output[unw_data_start:] 103 104 for func_iter in range(0, expected_function_count): 105 func_addr = (unw_index_addr_col[func_iter * 2 + 1] << 16 106 | unw_index_addr_col[func_iter * 2]) 107 index = unw_index_index_col[func_iter] 108 # If index is CANT_UNWIND then invalid function. 109 if index == 0xFFFF: 110 self.assertEqual(expected_cfi_data[func_addr], []) 111 continue 112 113 func_start = index + 1 114 func_end = func_start + unw_data[index] * 2 115 self.assertEqual(len(expected_cfi_data[func_addr]), func_end - func_start) 116 func_cfi = unw_data[func_start:func_end] 117 self.assertEqual(expected_cfi_data[func_addr], func_cfi) 118 119 120if __name__ == '__main__': 121 unittest.main() 122