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  }