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
15package symbol_inject
16
17import (
18	"debug/macho"
19	"fmt"
20	"io"
21	"sort"
22	"strings"
23)
24
25func machoSymbolsFromFile(r io.ReaderAt) (*File, error) {
26	machoFile, err := macho.NewFile(r)
27	if err != nil {
28		return nil, cantParseError{err}
29	}
30
31	return extractMachoSymbols(machoFile)
32}
33
34func extractMachoSymbols(machoFile *macho.File) (*File, error) {
35	symbols := machoFile.Symtab.Syms
36	sort.SliceStable(symbols, func(i, j int) bool {
37		if symbols[i].Sect != symbols[j].Sect {
38			return symbols[i].Sect < symbols[j].Sect
39		}
40		return symbols[i].Value < symbols[j].Value
41	})
42
43	file := &File{}
44
45	for _, section := range machoFile.Sections {
46		file.Sections = append(file.Sections, &Section{
47			Name:   section.Name,
48			Addr:   section.Addr,
49			Offset: uint64(section.Offset),
50			Size:   section.Size,
51		})
52	}
53
54	for _, symbol := range symbols {
55		if symbol.Sect > 0 {
56			section := file.Sections[symbol.Sect-1]
57			file.Symbols = append(file.Symbols, &Symbol{
58				// symbols in macho files seem to be prefixed with an underscore
59				Name: strings.TrimPrefix(symbol.Name, "_"),
60				// MachO symbol value is virtual address of the symbol, convert it to offset into the section.
61				Addr: symbol.Value - section.Addr,
62				// MachO symbols don't have size information.
63				Size:    0,
64				Section: section,
65			})
66		}
67	}
68
69	return file, nil
70}
71
72func dumpMachoSymbols(r io.ReaderAt) error {
73	machoFile, err := macho.NewFile(r)
74	if err != nil {
75		return cantParseError{err}
76	}
77
78	fmt.Println("&macho.File{")
79
80	fmt.Println("\tSections: []*macho.Section{")
81	for _, section := range machoFile.Sections {
82		fmt.Printf("\t\t&macho.Section{SectionHeader: %#v},\n", section.SectionHeader)
83	}
84	fmt.Println("\t},")
85
86	fmt.Println("\tSymtab: &macho.Symtab{")
87	fmt.Println("\t\tSyms: []macho.Symbol{")
88	for _, symbol := range machoFile.Symtab.Syms {
89		fmt.Printf("\t\t\t%#v,\n", symbol)
90	}
91	fmt.Println("\t\t},")
92	fmt.Println("\t},")
93
94	fmt.Println("}")
95
96	return nil
97}
98