/
mach-o.go
124 lines (113 loc) · 3.59 KB
/
mach-o.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package backend
import (
"debug/macho"
"fmt"
"path/filepath"
"sort"
"strings"
"github.com/google/syzkaller/pkg/host"
"github.com/google/syzkaller/sys/targets"
)
func makeMachO(target *targets.Target, objDir, srcDir, buildDir string,
moduleObj []string, hostModules []host.KernelModule) (*Impl, error) {
return makeDWARF(&dwarfParams{
target: target,
objDir: objDir,
srcDir: srcDir,
buildDir: buildDir,
moduleObj: moduleObj,
hostModules: hostModules,
readSymbols: machoReadSymbols,
readTextData: machoReadTextData,
readModuleCoverPoints: machoReadModuleCoverPoints,
readTextRanges: machoReadTextRanges,
})
}
func machoReadSymbols(module *Module, info *symbolInfo) ([]*Symbol, error) {
file, err := macho.Open(module.Path)
if err != nil {
return nil, err
}
text := file.Section("__text")
if text == nil {
return nil, fmt.Errorf("no __text section in the object file")
}
if file.Symtab == nil {
return nil, fmt.Errorf("failed to read Mach-O symbols")
}
info.textAddr = text.Addr
// We don't get symbol lengths or symbol ends in Mach-O symbols. So we
// guesstimate them by taking the next symbols beginning -1. That only
// works after we have sorted them.
sort.Slice(file.Symtab.Syms, func(i, j int) bool {
return file.Symtab.Syms[i].Value < file.Symtab.Syms[j].Value
})
var symbols []*Symbol
for i, symb := range file.Symtab.Syms {
// Mach-Os doesn't contain the Symbol size like in ELF
symbEnd := text.Addr + text.Size
if i < len(file.Symtab.Syms)-1 {
symbEnd = file.Symtab.Syms[i+1].Value
}
text := symb.Value >= text.Addr && symbEnd <= text.Addr+text.Size
if text {
symbStart := symb.Value + module.Addr
symbols = append(symbols, &Symbol{
Module: module,
ObjectUnit: ObjectUnit{
Name: symb.Name,
},
Start: symbStart,
End: symbEnd,
})
}
if strings.HasPrefix(symb.Name, "___sanitizer_cov_trace_") {
if symb.Name == "___sanitizer_cov_trace_pc_guard" {
info.tracePCIdx[i] = true
if text {
info.tracePC[symb.Value] = true
}
} else {
info.traceCmpIdx[i] = true
if text {
info.traceCmp[symb.Value] = true
}
}
}
}
return symbols, nil
}
func machoReadTextRanges(module *Module) ([]pcRange, []*CompileUnit, error) {
dir, kernel := filepath.Split(module.Path)
dSYMPath := filepath.Join(dir, fmt.Sprintf(
"%[1]s.dSYM/Contents/Resources/DWARF/%[1]s", kernel))
dSYM, err := macho.Open(dSYMPath)
if err != nil {
return nil, nil, err
}
debugInfo, err := dSYM.DWARF()
if err != nil {
return nil, nil, fmt.Errorf("failed to parse DWARF: %w", err)
}
return readTextRanges(debugInfo, module, nil)
}
func machoReadTextData(module *Module) ([]byte, error) {
file, err := macho.Open(module.Path)
if err != nil {
return nil, err
}
text := file.Section("__text")
if text == nil {
return nil, fmt.Errorf("no __text section in the object file")
}
return text.Data()
}
func machoReadModuleCoverPoints(target *targets.Target, module *Module, info *symbolInfo) ([2][]uint64, error) {
// TODO: Linux/ELF supports module symbols. We should probably also do that
// for XNU/Mach-O. To maximize code re-use we already have a lot of the
// plumbing for module support. I think we mainly miss an equivalent to
// discoverModules and this function at the moment.
return [2][]uint64{}, fmt.Errorf("machoReadModuleCoverPoints not implemented")
}