github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/elf/elf_test.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package elf 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "fmt" 23 "io" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "testing" 28 29 . "gopkg.in/check.v1" 30 31 "github.com/cilium/cilium/pkg/testutils" 32 ) 33 34 // Hook up gocheck into the "go test" runner. 35 type ELFTestSuite struct{} 36 37 var ( 38 _ = Suite(&ELFTestSuite{}) 39 40 elfObjCopy = "elf-demo-copy.o" 41 baseObjPath = filepath.Join(testutils.CiliumRootDir, "test", "bpf", "elf-demo.o") 42 ) 43 44 func Test(t *testing.T) { 45 TestingT(t) 46 } 47 48 func hash(path string) ([]byte, error) { 49 f, err := os.Open(path) 50 if err != nil { 51 return nil, err 52 } 53 defer f.Close() 54 55 hash := sha256.New() 56 if _, err := io.Copy(hash, f); err != nil { 57 return nil, err 58 } 59 60 return hash.Sum(nil), nil 61 } 62 63 var errDifferentFiles = fmt.Errorf("file hashes differ") 64 65 func compareFiles(path1, path2 string) error { 66 h1, err := hash(path1) 67 if err != nil { 68 return err 69 } 70 h2, err := hash(path2) 71 if err != nil { 72 return err 73 } 74 75 if !bytes.Equal(h1, h2) { 76 return errDifferentFiles 77 } 78 return nil 79 } 80 81 func (s *ELFTestSuite) TestWrite(c *C) { 82 tmpDir, err := ioutil.TempDir("", "cilium_") 83 c.Assert(err, IsNil) 84 defer os.RemoveAll(tmpDir) 85 86 elf, err := Open(baseObjPath) 87 c.Assert(err, IsNil) 88 defer elf.Close() 89 90 validOptions := IsNil 91 notValidOptions := Not(validOptions) 92 type testOption struct { 93 description string 94 key string 95 kind symbolKind 96 intValue uint32 97 strValue string 98 elfValid Checker 99 elfChangeErr error 100 } 101 testOptions := []testOption{ 102 { 103 description: "test direct copy", 104 elfValid: validOptions, 105 }, 106 { 107 description: "test constant substitution 1", 108 key: "FOO", 109 kind: symbolUint32, 110 intValue: 42, 111 elfValid: validOptions, 112 elfChangeErr: errDifferentFiles, 113 }, 114 { 115 description: "test constant substitution 2", 116 key: "BAR", 117 kind: symbolUint32, 118 intValue: 42, 119 elfValid: validOptions, 120 elfChangeErr: errDifferentFiles, 121 }, 122 { 123 description: "test map name substitution name", 124 key: "test_cilium_calls_4278124286", 125 kind: symbolString, 126 strValue: "test_cilium_calls_0000000042", 127 elfValid: validOptions, 128 elfChangeErr: errDifferentFiles, 129 }, 130 { 131 description: "test invalid map name substitution", 132 key: "test_cilium_calls_4278124286", 133 kind: symbolString, 134 strValue: "test_cilium_calls_00", 135 elfValid: notValidOptions, 136 }, 137 } 138 139 for i := 1; i <= 4; i++ { 140 testOptions = append(testOptions, testOption{ 141 description: fmt.Sprintf("test ipv6 substitution %d", i), 142 key: fmt.Sprintf("GLOBAL_IPV6_%d", i), 143 kind: symbolUint32, 144 intValue: 42, 145 elfValid: validOptions, 146 elfChangeErr: errDifferentFiles, 147 }) 148 } 149 150 for i := 1; i <= 2; i++ { 151 testOptions = append(testOptions, testOption{ 152 description: fmt.Sprintf("test mac substitution %d", i), 153 key: fmt.Sprintf("LOCAL_MAC_%d", i), 154 kind: symbolUint32, 155 intValue: 42, 156 elfValid: validOptions, 157 elfChangeErr: errDifferentFiles, 158 }) 159 } 160 161 for i, test := range testOptions { 162 c.Logf("%s", test.description) 163 164 // Create the copy of the ELF with an optional substitution 165 intOptions := make(map[string]uint32) 166 strOptions := make(map[string]string) 167 switch test.kind { 168 case symbolUint32: 169 intOptions[test.key] = test.intValue 170 case symbolString: 171 strOptions[test.key] = test.strValue 172 } 173 objectCopy := filepath.Join(tmpDir, fmt.Sprintf("%d_%s", i, elfObjCopy)) 174 err = elf.Write(objectCopy, intOptions, strOptions) 175 c.Assert(err, test.elfValid) 176 if test.elfValid == notValidOptions { 177 continue 178 } 179 err = compareFiles(baseObjPath, objectCopy) 180 c.Assert(err, Equals, test.elfChangeErr) 181 182 // Test that the written ELF matches expectations 183 modifiedElf, err := Open(objectCopy) 184 c.Assert(err, IsNil) 185 defer modifiedElf.Close() 186 187 switch test.kind { 188 case symbolUint32: 189 value, err := modifiedElf.readOption(test.key) 190 c.Assert(err, IsNil) 191 c.Assert(value, Equals, test.intValue) 192 case symbolString: 193 err := modifiedElf.findString(test.strValue) 194 c.Assert(err, IsNil) 195 default: 196 _, err = modifiedElf.readOption("unknown") 197 c.Assert(err, NotNil) 198 } 199 modifiedElf.Close() 200 } 201 } 202 203 // BenchmarkWriteELF benchmarks writing a very simple elf demo program. 204 func BenchmarkWriteELF(b *testing.B) { 205 tmpDir, err := ioutil.TempDir("", "cilium_") 206 if err != nil { 207 b.Fatal(err) 208 } 209 defer os.RemoveAll(tmpDir) 210 211 elf, err := Open(baseObjPath) 212 if err != nil { 213 b.Fatal(err) 214 } 215 defer elf.Close() 216 217 b.ResetTimer() 218 for i := 0; i < b.N; i++ { 219 intOptions := make(map[string]uint32) 220 strOptions := make(map[string]string) 221 222 objectCopy := filepath.Join(tmpDir, fmt.Sprintf("%d_%s", i, elfObjCopy)) 223 if err = elf.Write(objectCopy, intOptions, strOptions); err != nil { 224 b.Fatal(err) 225 } 226 } 227 }