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  }