-
Notifications
You must be signed in to change notification settings - Fork 0
/
macho.go
130 lines (118 loc) · 3.05 KB
/
macho.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
125
126
127
128
129
130
package macho
import (
"debug/macho"
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"os"
"strings"
)
type MachoUUIDS map[string]string
type MachoFile struct {
name string
uuids MachoUUIDS
}
func NewMacho(name string) (*MachoFile, error) {
machoFile := &MachoFile{
name: name,
uuids: MachoUUIDS{},
}
err := machoFile.load()
if err != nil {
return nil, err
}
return machoFile, nil
}
func NewMachoFromReader(r io.ReaderAt) (*MachoFile, error) {
machoFile := &MachoFile{
name: "",
uuids: MachoUUIDS{},
}
err := machoFile.loadFromReader(r)
if err != nil {
return nil, err
}
return machoFile, nil
}
func (m *MachoFile) loadFromReader(r io.ReaderAt) error {
machoFile, err := macho.NewFile(r)
if err != nil {
fatFile, _ := macho.NewFatFile(r)
defer fatFile.Close()
for _, arch := range fatFile.Arches {
archName, _ := m.getArchName(arch.Cpu, arch.SubCpu)
m.parse_data(arch.Loads, arch.ByteOrder, archName)
}
} else {
defer machoFile.Close()
archName, _ := m.getArchName(machoFile.Cpu, machoFile.SubCpu)
m.parse_data(machoFile.Loads, machoFile.ByteOrder, archName)
}
return nil
}
//加载符号表文件
func (m *MachoFile) load() error {
r, err := os.Open(m.name)
if err != nil {
return err
}
machoFile, err := macho.NewFile(r)
if err != nil {
fatFile, _ := macho.NewFatFile(r)
defer fatFile.Close()
for _, arch := range fatFile.Arches {
archName, _ := m.getArchName(arch.Cpu, arch.SubCpu)
m.parse_data(arch.Loads, arch.ByteOrder, archName)
}
} else {
defer machoFile.Close()
archName, _ := m.getArchName(machoFile.Cpu, machoFile.SubCpu)
m.parse_data(machoFile.Loads, machoFile.ByteOrder, archName)
}
return nil
}
//补充官方库没解析的 command 信息
//暂时只补充了 LC_UUID command
func (m *MachoFile) parse_data(loads []macho.Load, byteOrder binary.ByteOrder, archName string) {
for _, l := range loads {
_, ok := l.(*macho.Segment)
if !ok { //补充未解的部分
dat := l.Raw()
cmd, _ := macho.LoadCmd(byteOrder.Uint32(dat[0:4])), byteOrder.Uint32(dat[4:8])
if cmd == LC_UUID {
m.uuids[strings.ToLower(archName)] = m.lc_uuid(dat)
}
}
}
}
//获取符号表的 uuid 字典
func (m *MachoFile) GetUUIDS() MachoUUIDS {
return m.uuids
}
//根据 cpu 类型,获取符号表的 uuid
func (m *MachoFile) GetUUIDByName(arch string) (string, error) {
uuid, ok := m.uuids[arch]
if ok {
return uuid, nil
} else {
return "", nil
}
}
func (m *MachoFile) getArchName(Cpu macho.Cpu, SubCpu uint32) (string, error) {
subCpuTypeName := getCpuSubTypeName(Cpu, SubCpu)
archName := strings.Replace(subCpuTypeName, "CPU_SUBTYPE_", "", 1)
archName = strings.Replace(archName, "_", "", 1)
if archName == "ARMALL12" {
archName = CPU_TYPE_NAMES[Cpu]
}
return archName, nil
}
//解析uuid的数据
func (m *MachoFile) lc_uuid(data []byte) string {
uuidRaw := data[8:]
uuidHex := make([]byte, hex.EncodedLen(len(uuidRaw)))
hex.Encode(uuidHex, uuidRaw)
uuid := fmt.Sprintf("%s-%s-%s-%s-%s", uuidHex[0:8], uuidHex[8:12], uuidHex[12:16], uuidHex[16:20], uuidHex[20:])
return strings.ToUpper(uuid)
}