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 }