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