blob: 12253f6af38ae39ad0eb2ac0e0835f97ccc48a75 [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
15package main
16
17import (
18 "debug/elf"
19 "fmt"
20 "io"
21)
22
23func findElfSymbol(r io.ReaderAt, symbol string) (uint64, uint64, error) {
24 elfFile, err := elf.NewFile(r)
25 if err != nil {
26 return maxUint64, maxUint64, cantParseError{err}
27 }
28
29 symbols, err := elfFile.Symbols()
30 if err != nil {
31 return maxUint64, maxUint64, err
32 }
33
34 for _, s := range symbols {
35 if elf.ST_TYPE(s.Info) != elf.STT_OBJECT {
36 continue
37 }
38 if s.Name == symbol {
39 offset, err := calculateElfSymbolOffset(elfFile, s)
40 if err != nil {
41 return maxUint64, maxUint64, err
42 }
43 return offset, s.Size, nil
44 }
45 }
46
47 return maxUint64, maxUint64, fmt.Errorf("symbol not found")
48}
49
50func calculateElfSymbolOffset(file *elf.File, symbol elf.Symbol) (uint64, error) {
51 if symbol.Section == elf.SHN_UNDEF || int(symbol.Section) >= len(file.Sections) {
52 return maxUint64, fmt.Errorf("invalid section index %d", symbol.Section)
53 }
54 section := file.Sections[symbol.Section]
55 switch file.Type {
56 case elf.ET_REL:
57 // "In relocatable files, st_value holds a section offset for a defined symbol.
58 // That is, st_value is an offset from the beginning of the section that st_shndx identifies."
Colin Cross52226ad2018-02-15 15:54:14 -080059 return section.Offset + symbol.Value, nil
Colin Cross5498f852018-01-03 23:39:54 -080060 case elf.ET_EXEC, elf.ET_DYN:
61 // "In executable and shared object files, st_value holds a virtual address. To make these
62 // files’ symbols more useful for the dynamic linker, the section offset (file interpretation)
63 // gives way to a virtual address (memory interpretation) for which the section number is
64 // irrelevant."
65 if symbol.Value < section.Addr {
66 return maxUint64, fmt.Errorf("symbol starts before the start of its section")
67 }
68 section_offset := symbol.Value - section.Addr
69 if section_offset+symbol.Size > section.Size {
70 return maxUint64, fmt.Errorf("symbol extends past the end of its section")
71 }
72 return section.Offset + section_offset, nil
73 default:
74 return maxUint64, fmt.Errorf("unsupported elf file type %d", file.Type)
75 }
76}