github.com/kubearmor/cilium@v1.6.12/pkg/alignchecker/elf.go (about)

     1  // Copyright (c) 2009 The Go Authors. All rights reserved.
     2  //
     3  // Redistribution and use in source and binary forms, with or without
     4  // modification, are permitted provided that the following conditions are
     5  // met:
     6  //
     7  //    * Redistributions of source code must retain the above copyright
     8  // notice, this list of conditions and the following disclaimer.
     9  //    * Redistributions in binary form must reproduce the above
    10  // copyright notice, this list of conditions and the following disclaimer
    11  // in the documentation and/or other materials provided with the
    12  // distribution.
    13  //    * Neither the name of Google Inc. nor the names of its
    14  // contributors may be used to endorse or promote products derived from
    15  // this software without specific prior written permission.
    16  //
    17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    28  
    29  package alignchecker
    30  
    31  import (
    32  	"bytes"
    33  	"compress/zlib"
    34  	"debug/dwarf"
    35  	"debug/elf"
    36  	"encoding/binary"
    37  	"fmt"
    38  	"io"
    39  	"strings"
    40  )
    41  
    42  // Adopted from elf.File.DWARF
    43  // https://github.com/golang/go/blob/master/src/debug/elf/file.go (go1.11.2).
    44  //
    45  // The former method function tries to apply relocations when extracting DWARF
    46  // debug sections. Unfortunately, the relocations are not implemented for EM_BPF,
    47  // so the method fails.
    48  //
    49  // For struct alignment checks, no relocations are needed, so we comment out
    50  // the relocation bits.
    51  //
    52  // NOTE: DO NOT USE THE FUNCTION FOR ANYTHING ELSE!
    53  func getDWARFFromELF(f *elf.File) (*dwarf.Data, error) {
    54  	dwarfSuffix := func(s *elf.Section) string {
    55  		switch {
    56  		case strings.HasPrefix(s.Name, ".debug_"):
    57  			return s.Name[7:]
    58  		case strings.HasPrefix(s.Name, ".zdebug_"):
    59  			return s.Name[8:]
    60  		default:
    61  			return ""
    62  		}
    63  
    64  	}
    65  	// sectionData gets the data for s, checks its size, and
    66  	// applies any applicable relations.
    67  	sectionData := func(i int, s *elf.Section) ([]byte, error) {
    68  		b, err := s.Data()
    69  		if err != nil && uint64(len(b)) < s.Size {
    70  			return nil, err
    71  		}
    72  
    73  		if len(b) >= 12 && string(b[:4]) == "ZLIB" {
    74  			dlen := binary.BigEndian.Uint64(b[4:12])
    75  			dbuf := make([]byte, dlen)
    76  			r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
    77  			if err != nil {
    78  				return nil, err
    79  			}
    80  			if _, err := io.ReadFull(r, dbuf); err != nil {
    81  				return nil, err
    82  			}
    83  			if err := r.Close(); err != nil {
    84  				return nil, err
    85  			}
    86  			b = dbuf
    87  		}
    88  
    89  		for _, r := range f.Sections {
    90  			if r.Type != elf.SHT_RELA && r.Type != elf.SHT_REL {
    91  				continue
    92  			}
    93  			if int(r.Info) != i {
    94  				continue
    95  			}
    96  			//rd, err := r.Data()
    97  			_, err := r.Data()
    98  			if err != nil {
    99  				return nil, err
   100  			}
   101  			// err = f.applyRelocations(b, rd)
   102  			// if err != nil {
   103  			// 	return nil, err
   104  			// }
   105  		}
   106  		return b, nil
   107  	}
   108  
   109  	// There are many other DWARF sections, but these
   110  	// are the ones the debug/dwarf package uses.
   111  	// Don't bother loading others.
   112  	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
   113  	for i, s := range f.Sections {
   114  		suffix := dwarfSuffix(s)
   115  		if suffix == "" {
   116  			continue
   117  		}
   118  		if _, ok := dat[suffix]; !ok {
   119  			continue
   120  		}
   121  		b, err := sectionData(i, s)
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		dat[suffix] = b
   126  	}
   127  
   128  	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	// Look for DWARF4 .debug_types sections.
   134  	for i, s := range f.Sections {
   135  		suffix := dwarfSuffix(s)
   136  		if suffix != "types" {
   137  			continue
   138  		}
   139  
   140  		b, err := sectionData(i, s)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  
   145  		err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  	}
   150  
   151  	return d, nil
   152  }