xref: /aosp_15_r20/build/soong/symbol_inject/macho.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage symbol_inject
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"debug/macho"
19*333d2b36SAndroid Build Coastguard Worker	"encoding/binary"
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"io"
22*333d2b36SAndroid Build Coastguard Worker	"os"
23*333d2b36SAndroid Build Coastguard Worker	"os/exec"
24*333d2b36SAndroid Build Coastguard Worker	"path/filepath"
25*333d2b36SAndroid Build Coastguard Worker	"sort"
26*333d2b36SAndroid Build Coastguard Worker	"strings"
27*333d2b36SAndroid Build Coastguard Worker)
28*333d2b36SAndroid Build Coastguard Worker
29*333d2b36SAndroid Build Coastguard Workerfunc machoSymbolsFromFile(r io.ReaderAt) (*File, error) {
30*333d2b36SAndroid Build Coastguard Worker	machoFile, err := macho.NewFile(r)
31*333d2b36SAndroid Build Coastguard Worker	if err != nil {
32*333d2b36SAndroid Build Coastguard Worker		return nil, cantParseError{err}
33*333d2b36SAndroid Build Coastguard Worker	}
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Worker	return extractMachoSymbols(machoFile)
36*333d2b36SAndroid Build Coastguard Worker}
37*333d2b36SAndroid Build Coastguard Worker
38*333d2b36SAndroid Build Coastguard Workerfunc extractMachoSymbols(machoFile *macho.File) (*File, error) {
39*333d2b36SAndroid Build Coastguard Worker	symbols := machoFile.Symtab.Syms
40*333d2b36SAndroid Build Coastguard Worker	sort.SliceStable(symbols, func(i, j int) bool {
41*333d2b36SAndroid Build Coastguard Worker		if symbols[i].Sect != symbols[j].Sect {
42*333d2b36SAndroid Build Coastguard Worker			return symbols[i].Sect < symbols[j].Sect
43*333d2b36SAndroid Build Coastguard Worker		}
44*333d2b36SAndroid Build Coastguard Worker		return symbols[i].Value < symbols[j].Value
45*333d2b36SAndroid Build Coastguard Worker	})
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker	file := &File{IsMachoFile: true}
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard Worker	for _, section := range machoFile.Sections {
50*333d2b36SAndroid Build Coastguard Worker		file.Sections = append(file.Sections, &Section{
51*333d2b36SAndroid Build Coastguard Worker			Name:   section.Name,
52*333d2b36SAndroid Build Coastguard Worker			Addr:   section.Addr,
53*333d2b36SAndroid Build Coastguard Worker			Offset: uint64(section.Offset),
54*333d2b36SAndroid Build Coastguard Worker			Size:   section.Size,
55*333d2b36SAndroid Build Coastguard Worker		})
56*333d2b36SAndroid Build Coastguard Worker	}
57*333d2b36SAndroid Build Coastguard Worker
58*333d2b36SAndroid Build Coastguard Worker	for _, symbol := range symbols {
59*333d2b36SAndroid Build Coastguard Worker		if symbol.Sect > 0 {
60*333d2b36SAndroid Build Coastguard Worker			section := file.Sections[symbol.Sect-1]
61*333d2b36SAndroid Build Coastguard Worker			file.Symbols = append(file.Symbols, &Symbol{
62*333d2b36SAndroid Build Coastguard Worker				// symbols in macho files seem to be prefixed with an underscore
63*333d2b36SAndroid Build Coastguard Worker				Name: strings.TrimPrefix(symbol.Name, "_"),
64*333d2b36SAndroid Build Coastguard Worker				// MachO symbol value is virtual address of the symbol, convert it to offset into the section.
65*333d2b36SAndroid Build Coastguard Worker				Addr: symbol.Value - section.Addr,
66*333d2b36SAndroid Build Coastguard Worker				// MachO symbols don't have size information.
67*333d2b36SAndroid Build Coastguard Worker				Size:    0,
68*333d2b36SAndroid Build Coastguard Worker				Section: section,
69*333d2b36SAndroid Build Coastguard Worker			})
70*333d2b36SAndroid Build Coastguard Worker		}
71*333d2b36SAndroid Build Coastguard Worker	}
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Worker	return file, nil
74*333d2b36SAndroid Build Coastguard Worker}
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Workerfunc dumpMachoSymbols(r io.ReaderAt) error {
77*333d2b36SAndroid Build Coastguard Worker	machoFile, err := macho.NewFile(r)
78*333d2b36SAndroid Build Coastguard Worker	if err != nil {
79*333d2b36SAndroid Build Coastguard Worker		return cantParseError{err}
80*333d2b36SAndroid Build Coastguard Worker	}
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	fmt.Println("&macho.File{")
83*333d2b36SAndroid Build Coastguard Worker
84*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\tSections: []*macho.Section{")
85*333d2b36SAndroid Build Coastguard Worker	for _, section := range machoFile.Sections {
86*333d2b36SAndroid Build Coastguard Worker		fmt.Printf("\t\t&macho.Section{SectionHeader: %#v},\n", section.SectionHeader)
87*333d2b36SAndroid Build Coastguard Worker	}
88*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\t},")
89*333d2b36SAndroid Build Coastguard Worker
90*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\tSymtab: &macho.Symtab{")
91*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\t\tSyms: []macho.Symbol{")
92*333d2b36SAndroid Build Coastguard Worker	for _, symbol := range machoFile.Symtab.Syms {
93*333d2b36SAndroid Build Coastguard Worker		fmt.Printf("\t\t\t%#v,\n", symbol)
94*333d2b36SAndroid Build Coastguard Worker	}
95*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\t\t},")
96*333d2b36SAndroid Build Coastguard Worker	fmt.Println("\t},")
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Worker	fmt.Println("}")
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard Worker	return nil
101*333d2b36SAndroid Build Coastguard Worker}
102*333d2b36SAndroid Build Coastguard Worker
103*333d2b36SAndroid Build Coastguard Workerfunc CodeSignMachoFile(path string) error {
104*333d2b36SAndroid Build Coastguard Worker	filename := filepath.Base(path)
105*333d2b36SAndroid Build Coastguard Worker	cmd := exec.Command("/usr/bin/codesign", "--force", "-s", "-", "-i", filename, path)
106*333d2b36SAndroid Build Coastguard Worker	if err := cmd.Run(); err != nil {
107*333d2b36SAndroid Build Coastguard Worker		return err
108*333d2b36SAndroid Build Coastguard Worker	}
109*333d2b36SAndroid Build Coastguard Worker	return modifyCodeSignFlags(path)
110*333d2b36SAndroid Build Coastguard Worker}
111*333d2b36SAndroid Build Coastguard Worker
112*333d2b36SAndroid Build Coastguard Workerconst LC_CODE_SIGNATURE = 0x1d
113*333d2b36SAndroid Build Coastguard Workerconst CSSLOT_CODEDIRECTORY = 0
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Worker// To make codesign not invalidated by stripping, modify codesign flags to 0x20002
116*333d2b36SAndroid Build Coastguard Worker// (adhoc | linkerSigned).
117*333d2b36SAndroid Build Coastguard Workerfunc modifyCodeSignFlags(path string) error {
118*333d2b36SAndroid Build Coastguard Worker	f, err := os.OpenFile(path, os.O_RDWR, 0)
119*333d2b36SAndroid Build Coastguard Worker	if err != nil {
120*333d2b36SAndroid Build Coastguard Worker		return err
121*333d2b36SAndroid Build Coastguard Worker	}
122*333d2b36SAndroid Build Coastguard Worker	defer f.Close()
123*333d2b36SAndroid Build Coastguard Worker
124*333d2b36SAndroid Build Coastguard Worker	// Step 1: find code signature section.
125*333d2b36SAndroid Build Coastguard Worker	machoFile, err := macho.NewFile(f)
126*333d2b36SAndroid Build Coastguard Worker	if err != nil {
127*333d2b36SAndroid Build Coastguard Worker		return err
128*333d2b36SAndroid Build Coastguard Worker	}
129*333d2b36SAndroid Build Coastguard Worker	var codeSignSectionOffset uint32 = 0
130*333d2b36SAndroid Build Coastguard Worker	var codeSignSectionSize uint32 = 0
131*333d2b36SAndroid Build Coastguard Worker	for _, l := range machoFile.Loads {
132*333d2b36SAndroid Build Coastguard Worker		data := l.Raw()
133*333d2b36SAndroid Build Coastguard Worker		cmd := machoFile.ByteOrder.Uint32(data)
134*333d2b36SAndroid Build Coastguard Worker		if cmd == LC_CODE_SIGNATURE {
135*333d2b36SAndroid Build Coastguard Worker			codeSignSectionOffset = machoFile.ByteOrder.Uint32(data[8:])
136*333d2b36SAndroid Build Coastguard Worker			codeSignSectionSize = machoFile.ByteOrder.Uint32(data[12:])
137*333d2b36SAndroid Build Coastguard Worker		}
138*333d2b36SAndroid Build Coastguard Worker	}
139*333d2b36SAndroid Build Coastguard Worker	if codeSignSectionOffset == 0 {
140*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("code signature section not found")
141*333d2b36SAndroid Build Coastguard Worker	}
142*333d2b36SAndroid Build Coastguard Worker
143*333d2b36SAndroid Build Coastguard Worker	data := make([]byte, codeSignSectionSize)
144*333d2b36SAndroid Build Coastguard Worker	_, err = f.ReadAt(data, int64(codeSignSectionOffset))
145*333d2b36SAndroid Build Coastguard Worker	if err != nil {
146*333d2b36SAndroid Build Coastguard Worker		return err
147*333d2b36SAndroid Build Coastguard Worker	}
148*333d2b36SAndroid Build Coastguard Worker
149*333d2b36SAndroid Build Coastguard Worker	// Step 2: get flags offset.
150*333d2b36SAndroid Build Coastguard Worker	blobCount := binary.BigEndian.Uint32(data[8:])
151*333d2b36SAndroid Build Coastguard Worker	off := 12
152*333d2b36SAndroid Build Coastguard Worker	var codeDirectoryOff uint32 = 0
153*333d2b36SAndroid Build Coastguard Worker	for blobCount > 0 {
154*333d2b36SAndroid Build Coastguard Worker		blobType := binary.BigEndian.Uint32(data[off:])
155*333d2b36SAndroid Build Coastguard Worker		if blobType == CSSLOT_CODEDIRECTORY {
156*333d2b36SAndroid Build Coastguard Worker			codeDirectoryOff = binary.BigEndian.Uint32(data[off+4:])
157*333d2b36SAndroid Build Coastguard Worker			break
158*333d2b36SAndroid Build Coastguard Worker		}
159*333d2b36SAndroid Build Coastguard Worker		blobCount--
160*333d2b36SAndroid Build Coastguard Worker		off += 8
161*333d2b36SAndroid Build Coastguard Worker	}
162*333d2b36SAndroid Build Coastguard Worker	if codeDirectoryOff == 0 {
163*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("no code directory in code signature section")
164*333d2b36SAndroid Build Coastguard Worker	}
165*333d2b36SAndroid Build Coastguard Worker	flagsOff := codeSignSectionOffset + codeDirectoryOff + 12
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Worker	// Step 3: modify flags.
168*333d2b36SAndroid Build Coastguard Worker	flagsData := make([]byte, 4)
169*333d2b36SAndroid Build Coastguard Worker	_, err = f.ReadAt(flagsData, int64(flagsOff))
170*333d2b36SAndroid Build Coastguard Worker	if err != nil {
171*333d2b36SAndroid Build Coastguard Worker		return err
172*333d2b36SAndroid Build Coastguard Worker	}
173*333d2b36SAndroid Build Coastguard Worker	oldFlags := binary.BigEndian.Uint32(flagsData)
174*333d2b36SAndroid Build Coastguard Worker	if oldFlags != 0x2 {
175*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("unexpected flags in code signature section: 0x%x", oldFlags)
176*333d2b36SAndroid Build Coastguard Worker	}
177*333d2b36SAndroid Build Coastguard Worker	binary.BigEndian.PutUint32(flagsData, 0x20002)
178*333d2b36SAndroid Build Coastguard Worker	_, err = f.WriteAt(flagsData, int64(flagsOff))
179*333d2b36SAndroid Build Coastguard Worker	return err
180*333d2b36SAndroid Build Coastguard Worker}
181