github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/cover/backend/dwarf_test.go (about) 1 // Copyright 2024 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package backend 5 6 import ( 7 "testing" 8 ) 9 10 // kcov is known to be broken in GCC versions < 14. 11 // If the version cannot be parsed, assume it is broken. 12 func TestIsKcovBrokenInCompiler(t *testing.T) { 13 inputDataTrue := []string{ 14 "gcc (Debian 12.2.0-14) 12.2.0", 15 "gcc (Debian 13.2.0-5) 13.2.0", 16 "arm-unknown-linux-gnueabihf-g++ (GCC) 13.2.0", 17 "aarch64-unknown-linux-gnu-g++ (GCC) 11.1.0", 18 "g++ (Compiler-Explorer-Build-gcc-d3f1cf4e50356e44f745c5bc67ffd529cc4e2358-binutils-2.36.1) 12.0.0 20210426 (experimental)", // nolint:lll 19 "g++ (Compiler-Explorer-Build-gcc--binutils-2.40) 13.2.0", 20 "gcc (Compiler-Explorer-Build) 9.2.0", 21 "GCC something something", 22 } 23 inputDataFalse := []string{ 24 "Debian clang version 16.0.6 (16)", 25 "arm-unknown-linux-gnueabihf-g++ (GCC) 14.0.1 20240124 (experimental)", 26 "g++ (Compiler-Explorer-Build-gcc-2a9637b229f64775d82fb5917f83f71e8ad1911d-binutils-2.40) 14.0.1 20240125 (experimental)", // nolint:lll 27 } 28 for _, ver := range inputDataTrue { 29 if !isKcovBrokenInCompiler(ver) { 30 t.Fatalf("isKcovBrokenInCompiler(%q) unexpectedly returned false", ver) 31 } 32 } 33 for _, ver := range inputDataFalse { 34 if isKcovBrokenInCompiler(ver) { 35 t.Fatalf("isKcovBrokenInCompiler(%q) unexpectedly returned true", ver) 36 } 37 } 38 } 39 40 type CleanPathAndroidTest struct { 41 SrcDir string 42 Delimiters []string 43 // Each test case is a triple of {path, epath, ename}, where path is passed to cleanPathAndroid(), 44 // and (epath, ename) is its expected return value. 45 Files [][3]string 46 FnExists func(string) bool 47 } 48 49 func TestCleanPathAndroid(t *testing.T) { 50 tests := []CleanPathAndroidTest{ 51 // Test that paths with "/aosp/" and "/private/" in them are normalized. 52 { 53 SrcDir: "/src/kernel", 54 Delimiters: []string{"/aosp/", "/private/"}, 55 Files: [][3]string{ 56 {"/src/kernel/aosp/mm/mmap.c", "mm/mmap.c", "/src/kernel/aosp/mm/mmap.c"}, 57 {"/src/kernel/out/cache/feedface/aosp/mm/mmap.c", "mm/mmap.c", "/src/kernel/aosp/mm/mmap.c"}, 58 {"/src/kernel/out/cache/cafebabe/private/google_modules/module/mod.c", "google_modules/module/mod.c", 59 "/src/kernel/private/google_modules/module/mod.c"}, 60 {"/some/other/path/aosp/mm/mmap.c", "mm/mmap.c", "/src/kernel/aosp/mm/mmap.c"}, 61 }, 62 FnExists: func(string) bool { return true }, 63 }, 64 // Test that for empty delimiters empty results are returned. 65 { 66 SrcDir: "/src/kernel/", 67 Delimiters: []string{}, 68 Files: [][3]string{ 69 {"/src/kernel/mm/mmap.c", "", ""}, 70 }, 71 FnExists: func(string) bool { return true }, 72 }, 73 // Test that for path that does not contain a delimiter the result is constructed based on FnExists(). 74 { 75 SrcDir: "/src/kernel/", 76 Delimiters: []string{"/aosp/", "/private/"}, 77 Files: [][3]string{ 78 {"mm/mmap.c", "mm/mmap.c", "/src/kernel/aosp/mm/mmap.c"}, 79 }, 80 FnExists: func(s string) bool { return s == "/src/kernel/aosp/mm/mmap.c" }, 81 }, 82 // Test that for path that does not contain a delimiter the result is constructed based on FnExists(). 83 { 84 SrcDir: "/src/kernel/", 85 Delimiters: []string{"/aosp/", "/private/"}, 86 Files: [][3]string{ 87 {"mm/mmap.c", "mm/mmap.c", "/src/kernel/private/mm/mmap.c"}, 88 }, 89 FnExists: func(s string) bool { return s != "/src/kernel/aosp/mm/mmap.c" }, 90 }, 91 } 92 for _, test := range tests { 93 for _, files := range test.Files { 94 path, epath, ename := files[0], files[1], files[2] 95 rpath, rname := cleanPathAndroid(path, test.SrcDir, test.Delimiters, test.FnExists) 96 if (rpath != epath) || (rname != ename) { 97 t.Fatalf("cleanPathAndroid(`%s`, `%s`, %v, ...) unexpectedly returned (`%s`, `%s`) instead of (`%s`, `%s`)", 98 path, test.SrcDir, test.Delimiters, rpath, rname, epath, ename) 99 } 100 } 101 } 102 } 103 104 type NextCallTargetTest struct { 105 Arch *Arch 106 Text uint64 107 Data []byte 108 ExpTarget uint64 109 ExpPC uint64 110 } 111 112 func runNextCallTarget(t *testing.T, arg NextCallTargetTest) { 113 i := 0 114 target, pc := nextCallTarget(arg.Arch, arg.Text, arg.Data, &i) 115 if target != arg.ExpTarget || pc != arg.ExpPC { 116 t.Fatalf("nextCallTarget(`%v`, %x, %v) unexpectedly returned (%x, %x) instead of (%x, %x)", 117 arg.Arch, arg.Text, arg.Data, target, pc, arg.ExpTarget, arg.ExpPC) 118 } 119 } 120 121 func TestNextCallTargetARM64(t *testing.T) { 122 tests := []NextCallTargetTest{ 123 // ffff800080020010: 9414234f bl ffff800080528d4c <__sanitizer_cov_trace_pc> 124 { 125 Data: []byte{0x4f, 0x23, 0x14, 0x94}, 126 ExpTarget: 0xffff800080528d4c, 127 ExpPC: 0xffff800080020010, 128 }, 129 // ffff800080020088: 95fbe498 bl ffff800087f192e8 <__debug_smp_processor_id_veneer> 130 { 131 Data: []byte{0x98, 0xe4, 0xfb, 0x95}, 132 ExpTarget: 0xffff800087f192e8, 133 ExpPC: 0xffff800080020088, 134 }, 135 // ffff80008477626c: 96f6cab8 bl ffff800080528d4c <__sanitizer_cov_trace_pc> 136 { 137 Data: []byte{0xb8, 0xca, 0xf6, 0x96}, 138 ExpTarget: 0xffff800080528d4c, 139 ExpPC: 0xffff80008477626c, 140 }, 141 // ffff80008052aa18: 97fff8cd bl ffff800080528d4c <__sanitizer_cov_trace_pc> 142 { 143 Data: []byte{0xcd, 0xf8, 0xff, 0x97}, 144 ExpTarget: 0xffff800080528d4c, 145 ExpPC: 0xffff80008052aa18, 146 }, 147 } 148 for _, test := range tests { 149 arch := arches["arm64"] 150 test.Arch = &arch 151 test.Text = test.ExpPC 152 runNextCallTarget(t, test) 153 } 154 } 155 156 func TestNextCallTargetAMD64(t *testing.T) { 157 tests := []NextCallTargetTest{ 158 // ffffffff811744c6: e8 85 fb 7b 00 call ffffffff81934050 <__sanitizer_cov_trace_pc> 159 { 160 Data: []byte{0xe8, 0x85, 0xfb, 0x7b, 0x00}, 161 Text: 0xffffffff811744c6, 162 ExpTarget: 0xffffffff81934050, 163 ExpPC: 0xffffffff811744c6, 164 }, 165 // Same, but the search window starts two bytes earlier. 166 { 167 Data: []byte{0x90, 0x90, 0xe8, 0x85, 0xfb, 0x7b, 0x00}, 168 Text: 0xffffffff811744c4, 169 ExpTarget: 0xffffffff81934050, 170 ExpPC: 0xffffffff811744c6, 171 }, 172 } 173 for _, test := range tests { 174 arch := arches["amd64"] 175 test.Arch = &arch 176 runNextCallTarget(t, test) 177 } 178 }