github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/cmd/symbol_inject/elf.go (about)

     1  // Copyright 2018 Google Inc. All rights reserved.
     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  package main
    16  
    17  import (
    18  	"debug/elf"
    19  	"fmt"
    20  	"io"
    21  )
    22  
    23  type mockableElfFile interface {
    24  	Symbols() ([]elf.Symbol, error)
    25  	Sections() []elf.SectionHeader
    26  	Type() elf.Type
    27  }
    28  
    29  var _ mockableElfFile = elfFileWrapper{}
    30  
    31  type elfFileWrapper struct {
    32  	*elf.File
    33  }
    34  
    35  func (f elfFileWrapper) Sections() []elf.SectionHeader {
    36  	ret := make([]elf.SectionHeader, len(f.File.Sections))
    37  	for i, section := range f.File.Sections {
    38  		ret[i] = section.SectionHeader
    39  	}
    40  
    41  	return ret
    42  }
    43  
    44  func (f elfFileWrapper) Type() elf.Type {
    45  	return f.File.Type
    46  }
    47  
    48  type mockElfFile struct {
    49  	symbols  []elf.Symbol
    50  	sections []elf.SectionHeader
    51  	t        elf.Type
    52  }
    53  
    54  func (f mockElfFile) Sections() []elf.SectionHeader  { return f.sections }
    55  func (f mockElfFile) Symbols() ([]elf.Symbol, error) { return f.symbols, nil }
    56  func (f mockElfFile) Type() elf.Type                 { return f.t }
    57  
    58  func elfSymbolsFromFile(r io.ReaderAt) (*File, error) {
    59  	elfFile, err := elf.NewFile(r)
    60  	if err != nil {
    61  		return nil, cantParseError{err}
    62  	}
    63  	return extractElfSymbols(elfFileWrapper{elfFile})
    64  }
    65  
    66  func extractElfSymbols(elfFile mockableElfFile) (*File, error) {
    67  	symbols, err := elfFile.Symbols()
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	file := &File{}
    73  
    74  	for _, section := range elfFile.Sections() {
    75  		file.Sections = append(file.Sections, &Section{
    76  			Name:   section.Name,
    77  			Addr:   section.Addr,
    78  			Offset: section.Offset,
    79  			Size:   section.Size,
    80  		})
    81  	}
    82  
    83  	_ = elf.Section{}
    84  
    85  	for _, symbol := range symbols {
    86  		if elf.ST_TYPE(symbol.Info) != elf.STT_OBJECT {
    87  			continue
    88  		}
    89  		if symbol.Section == elf.SHN_UNDEF || symbol.Section >= elf.SHN_LORESERVE {
    90  			continue
    91  		}
    92  		if int(symbol.Section) >= len(file.Sections) {
    93  			return nil, fmt.Errorf("invalid section index %d", symbol.Section)
    94  		}
    95  
    96  		section := file.Sections[symbol.Section]
    97  
    98  		var addr uint64
    99  		switch elfFile.Type() {
   100  		case elf.ET_REL:
   101  			// "In relocatable files, st_value holds a section offset for a defined symbol.
   102  			// That is, st_value is an offset from the beginning of the section that st_shndx identifies."
   103  			addr = symbol.Value
   104  		case elf.ET_EXEC, elf.ET_DYN:
   105  			// "In executable and shared object files, st_value holds a virtual address. To make these
   106  			// files’ symbols more useful for the dynamic linker, the section offset (file interpretation)
   107  			// gives way to a virtual address (memory interpretation) for which the section number is
   108  			// irrelevant."
   109  			if symbol.Value < section.Addr {
   110  				return nil, fmt.Errorf("symbol starts before the start of its section")
   111  			}
   112  			addr = symbol.Value - section.Addr
   113  			if addr+symbol.Size > section.Size {
   114  				return nil, fmt.Errorf("symbol extends past the end of its section")
   115  			}
   116  		default:
   117  			return nil, fmt.Errorf("unsupported elf file type %d", elfFile.Type())
   118  		}
   119  
   120  		file.Symbols = append(file.Symbols, &Symbol{
   121  			Name:    symbol.Name,
   122  			Addr:    addr,
   123  			Size:    symbol.Size,
   124  			Section: section,
   125  		})
   126  	}
   127  
   128  	return file, nil
   129  }
   130  
   131  func dumpElfSymbols(r io.ReaderAt) error {
   132  	elfFile, err := elf.NewFile(r)
   133  	if err != nil {
   134  		return cantParseError{err}
   135  	}
   136  
   137  	symbols, err := elfFile.Symbols()
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	fmt.Println("mockElfFile{")
   143  	fmt.Printf("\tt: %#v,\n", elfFile.Type)
   144  
   145  	fmt.Println("\tsections: []elf.SectionHeader{")
   146  	for _, section := range elfFile.Sections {
   147  		fmt.Printf("\t\t%#v,\n", section.SectionHeader)
   148  	}
   149  	fmt.Println("\t},")
   150  
   151  	fmt.Println("\tsymbols: []elf.Symbol{")
   152  	for _, symbol := range symbols {
   153  		fmt.Printf("\t\t%#v,\n", symbol)
   154  	}
   155  	fmt.Println("\t},")
   156  
   157  	fmt.Println("}")
   158  
   159  	return nil
   160  }