...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/time/asset.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/time

     1  // Copyright 2021 Chaos Mesh Authors.
     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  
    16  package time
    17  
    18  import (
    19  	"bytes"
    20  	"debug/elf"
    21  	"embed"
    22  	"encoding/binary"
    23  
    24  	"github.com/pkg/errors"
    25  )
    26  
    27  //go:embed fakeclock/*.o
    28  var fakeclock embed.FS
    29  
    30  const textSection = ".text"
    31  const relocationSection = ".rela.text"
    32  
    33  // LoadFakeImageFromEmbedFs builds FakeImage from the embed filesystem. It parses the ELF file and extract the variables from the relocation section, reserves the space for them at the end of content, then calculates and saves offsets as "manually relocation"
    34  func LoadFakeImageFromEmbedFs(filename string, symbolName string) (*FakeImage, error) {
    35  	path := "fakeclock/" + filename
    36  	object, err := fakeclock.ReadFile(path)
    37  	if err != nil {
    38  		return nil, errors.Wrapf(err, "read file from embedded fs %s", path)
    39  	}
    40  
    41  	elfFile, err := elf.NewFile(bytes.NewReader(object))
    42  	if err != nil {
    43  		return nil, errors.Wrapf(err, "parse elf file %s", path)
    44  	}
    45  
    46  	syms, err := elfFile.Symbols()
    47  	if err != nil {
    48  		return nil, errors.Wrapf(err, "get symbols %s", path)
    49  	}
    50  
    51  	fakeImage := FakeImage{
    52  		symbolName: symbolName,
    53  		offset:     make(map[string]int),
    54  	}
    55  	for _, r := range elfFile.Sections {
    56  
    57  		if r.Type == elf.SHT_PROGBITS && r.Name == textSection {
    58  			fakeImage.content, err = r.Data()
    59  			if err != nil {
    60  				return nil, errors.Wrapf(err, "read text section data %s", path)
    61  			}
    62  			break
    63  		}
    64  	}
    65  
    66  	for _, r := range elfFile.Sections {
    67  		if r.Type == elf.SHT_RELA && r.Name == relocationSection {
    68  			rela_section, err := r.Data()
    69  			if err != nil {
    70  				return nil, errors.Wrapf(err, "read rela section data %s", path)
    71  			}
    72  			rela_section_reader := bytes.NewReader(rela_section)
    73  
    74  			var rela elf.Rela64
    75  			for rela_section_reader.Len() > 0 {
    76  				err := binary.Read(rela_section_reader, elfFile.ByteOrder, &rela)
    77  				if err != nil {
    78  					return nil, errors.Wrapf(err, "read rela section rela64 entry %s", path)
    79  				}
    80  
    81  				symNo := rela.Info >> 32
    82  				if symNo == 0 || symNo > uint64(len(syms)) {
    83  					continue
    84  				}
    85  
    86  				// The relocation of a X86 image is like:
    87  				// Relocation section '.rela.text' at offset 0x288 contains 3 entries:
    88  				// Offset          Info           Type           Sym. Value    Sym. Name + Addend
    89  				// 000000000016  000900000002 R_X86_64_PC32     0000000000000000 CLOCK_IDS_MASK - 4
    90  				// 00000000001f  000a00000002 R_X86_64_PC32     0000000000000008 TV_NSEC_DELTA - 4
    91  				// 00000000002a  000b00000002 R_X86_64_PC32     0000000000000010 TV_SEC_DELTA - 4
    92  				//
    93  				// For example, we need to write the offset of `CLOCK_IDS_MASK` - 4 in 0x16 of the section
    94  				// If we want to put the `CLOCK_IDS_MASK` at the end of the section, it will be
    95  				// len(fakeImage.content) - 4 - 0x16
    96  
    97  				sym := &syms[symNo-1]
    98  				fakeImage.offset[sym.Name] = len(fakeImage.content)
    99  				targetOffset := uint32(len(fakeImage.content)) - uint32(rela.Off) + uint32(rela.Addend)
   100  				elfFile.ByteOrder.PutUint32(fakeImage.content[rela.Off:rela.Off+4], targetOffset)
   101  
   102  				// TODO: support other length besides uint64 (which is 8 bytes)
   103  				fakeImage.content = append(fakeImage.content, make([]byte, 8)...)
   104  			}
   105  
   106  			break
   107  		}
   108  	}
   109  	return &fakeImage, nil
   110  }
   111