blob: 8742cbd1a94933ba199bc6c70d2fb0d4d1a820c5 [file] [log] [blame]
Colin Cross5498f852018-01-03 23:39:54 -08001// 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
Dan Willemsen2249dc82018-10-15 00:35:59 -070015package symbol_inject
Colin Cross5498f852018-01-03 23:39:54 -080016
17import (
18 "debug/elf"
19 "fmt"
20 "io"
21)
22
Colin Cross8673b5b2018-03-01 11:20:25 -080023type mockableElfFile interface {
24 Symbols() ([]elf.Symbol, error)
25 Sections() []elf.SectionHeader
26 Type() elf.Type
27}
28
29var _ mockableElfFile = elfFileWrapper{}
30
31type elfFileWrapper struct {
32 *elf.File
33}
34
35func (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
44func (f elfFileWrapper) Type() elf.Type {
45 return f.File.Type
46}
47
48type mockElfFile struct {
49 symbols []elf.Symbol
50 sections []elf.SectionHeader
51 t elf.Type
52}
53
54func (f mockElfFile) Sections() []elf.SectionHeader { return f.sections }
55func (f mockElfFile) Symbols() ([]elf.Symbol, error) { return f.symbols, nil }
56func (f mockElfFile) Type() elf.Type { return f.t }
57
58func elfSymbolsFromFile(r io.ReaderAt) (*File, error) {
Colin Cross5498f852018-01-03 23:39:54 -080059 elfFile, err := elf.NewFile(r)
60 if err != nil {
Colin Cross8673b5b2018-03-01 11:20:25 -080061 return nil, cantParseError{err}
62 }
63 return extractElfSymbols(elfFileWrapper{elfFile})
64}
65
66func 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
131func dumpElfSymbols(r io.ReaderAt) error {
132 elfFile, err := elf.NewFile(r)
133 if err != nil {
134 return cantParseError{err}
Colin Cross5498f852018-01-03 23:39:54 -0800135 }
136
137 symbols, err := elfFile.Symbols()
138 if err != nil {
Colin Cross8673b5b2018-03-01 11:20:25 -0800139 return err
Colin Cross5498f852018-01-03 23:39:54 -0800140 }
141
Colin Cross8673b5b2018-03-01 11:20:25 -0800142 fmt.Println("mockElfFile{")
143 fmt.Printf("\tt: %#v,\n", elfFile.Type)
Colin Cross5498f852018-01-03 23:39:54 -0800144
Colin Cross8673b5b2018-03-01 11:20:25 -0800145 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},")
Colin Cross5498f852018-01-03 23:39:54 -0800150
Colin Cross8673b5b2018-03-01 11:20:25 -0800151 fmt.Println("\tsymbols: []elf.Symbol{")
152 for _, symbol := range symbols {
153 fmt.Printf("\t\t%#v,\n", symbol)
Colin Cross5498f852018-01-03 23:39:54 -0800154 }
Colin Cross8673b5b2018-03-01 11:20:25 -0800155 fmt.Println("\t},")
156
157 fmt.Println("}")
158
159 return nil
Colin Cross5498f852018-01-03 23:39:54 -0800160}