xref: /aosp_15_r20/build/soong/symbol_inject/symbol_inject.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	"bytes"
19*333d2b36SAndroid Build Coastguard Worker	"encoding/binary"
20*333d2b36SAndroid Build Coastguard Worker	"fmt"
21*333d2b36SAndroid Build Coastguard Worker	"io"
22*333d2b36SAndroid Build Coastguard Worker	"math"
23*333d2b36SAndroid Build Coastguard Worker)
24*333d2b36SAndroid Build Coastguard Worker
25*333d2b36SAndroid Build Coastguard Workervar maxUint64 uint64 = math.MaxUint64
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workertype cantParseError struct {
28*333d2b36SAndroid Build Coastguard Worker	error
29*333d2b36SAndroid Build Coastguard Worker}
30*333d2b36SAndroid Build Coastguard Worker
31*333d2b36SAndroid Build Coastguard Workerfunc OpenFile(r io.ReaderAt) (*File, error) {
32*333d2b36SAndroid Build Coastguard Worker	file, err := elfSymbolsFromFile(r)
33*333d2b36SAndroid Build Coastguard Worker	if elfError, ok := err.(cantParseError); ok {
34*333d2b36SAndroid Build Coastguard Worker		// Try as a mach-o file
35*333d2b36SAndroid Build Coastguard Worker		file, err = machoSymbolsFromFile(r)
36*333d2b36SAndroid Build Coastguard Worker		if _, ok := err.(cantParseError); ok {
37*333d2b36SAndroid Build Coastguard Worker			// Try as a windows PE file
38*333d2b36SAndroid Build Coastguard Worker			file, err = peSymbolsFromFile(r)
39*333d2b36SAndroid Build Coastguard Worker			if _, ok := err.(cantParseError); ok {
40*333d2b36SAndroid Build Coastguard Worker				// Can't parse as elf, macho, or PE, return the elf error
41*333d2b36SAndroid Build Coastguard Worker				return nil, elfError
42*333d2b36SAndroid Build Coastguard Worker			}
43*333d2b36SAndroid Build Coastguard Worker		}
44*333d2b36SAndroid Build Coastguard Worker	}
45*333d2b36SAndroid Build Coastguard Worker	if err != nil {
46*333d2b36SAndroid Build Coastguard Worker		return nil, err
47*333d2b36SAndroid Build Coastguard Worker	}
48*333d2b36SAndroid Build Coastguard Worker
49*333d2b36SAndroid Build Coastguard Worker	file.r = r
50*333d2b36SAndroid Build Coastguard Worker
51*333d2b36SAndroid Build Coastguard Worker	return file, err
52*333d2b36SAndroid Build Coastguard Worker}
53*333d2b36SAndroid Build Coastguard Worker
54*333d2b36SAndroid Build Coastguard Workerfunc InjectStringSymbol(file *File, w io.Writer, symbol, value, from string) error {
55*333d2b36SAndroid Build Coastguard Worker	offset, size, err := findSymbol(file, symbol)
56*333d2b36SAndroid Build Coastguard Worker	if err != nil {
57*333d2b36SAndroid Build Coastguard Worker		return err
58*333d2b36SAndroid Build Coastguard Worker	}
59*333d2b36SAndroid Build Coastguard Worker
60*333d2b36SAndroid Build Coastguard Worker	if uint64(len(value))+1 > size {
61*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("value length %d overflows symbol size %d", len(value), size)
62*333d2b36SAndroid Build Coastguard Worker	}
63*333d2b36SAndroid Build Coastguard Worker
64*333d2b36SAndroid Build Coastguard Worker	if from != "" {
65*333d2b36SAndroid Build Coastguard Worker		// Read the exsting symbol contents and verify they match the expected value
66*333d2b36SAndroid Build Coastguard Worker		expected := make([]byte, size)
67*333d2b36SAndroid Build Coastguard Worker		existing := make([]byte, size)
68*333d2b36SAndroid Build Coastguard Worker		copy(expected, from)
69*333d2b36SAndroid Build Coastguard Worker		_, err := file.r.ReadAt(existing, int64(offset))
70*333d2b36SAndroid Build Coastguard Worker		if err != nil {
71*333d2b36SAndroid Build Coastguard Worker			return err
72*333d2b36SAndroid Build Coastguard Worker		}
73*333d2b36SAndroid Build Coastguard Worker		if bytes.Compare(existing, expected) != 0 {
74*333d2b36SAndroid Build Coastguard Worker			return fmt.Errorf("existing symbol contents %q did not match expected value %q",
75*333d2b36SAndroid Build Coastguard Worker				string(existing), string(expected))
76*333d2b36SAndroid Build Coastguard Worker		}
77*333d2b36SAndroid Build Coastguard Worker	}
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Worker	buf := make([]byte, size)
80*333d2b36SAndroid Build Coastguard Worker	copy(buf, value)
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	return copyAndInject(file.r, w, offset, buf)
83*333d2b36SAndroid Build Coastguard Worker}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Workerfunc InjectUint64Symbol(file *File, w io.Writer, symbol string, value uint64) error {
86*333d2b36SAndroid Build Coastguard Worker	offset, size, err := findSymbol(file, symbol)
87*333d2b36SAndroid Build Coastguard Worker	if err != nil {
88*333d2b36SAndroid Build Coastguard Worker		return err
89*333d2b36SAndroid Build Coastguard Worker	}
90*333d2b36SAndroid Build Coastguard Worker
91*333d2b36SAndroid Build Coastguard Worker	if size != 8 {
92*333d2b36SAndroid Build Coastguard Worker		return fmt.Errorf("symbol %q is not a uint64, it is %d bytes long", symbol, size)
93*333d2b36SAndroid Build Coastguard Worker	}
94*333d2b36SAndroid Build Coastguard Worker
95*333d2b36SAndroid Build Coastguard Worker	buf := make([]byte, 8)
96*333d2b36SAndroid Build Coastguard Worker	binary.LittleEndian.PutUint64(buf, value)
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Worker	return copyAndInject(file.r, w, offset, buf)
99*333d2b36SAndroid Build Coastguard Worker}
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Workerfunc copyAndInject(r io.ReaderAt, w io.Writer, offset uint64, buf []byte) (err error) {
102*333d2b36SAndroid Build Coastguard Worker	// Copy the first bytes up to the symbol offset
103*333d2b36SAndroid Build Coastguard Worker	_, err = io.Copy(w, io.NewSectionReader(r, 0, int64(offset)))
104*333d2b36SAndroid Build Coastguard Worker
105*333d2b36SAndroid Build Coastguard Worker	// Write the injected value in the output file
106*333d2b36SAndroid Build Coastguard Worker	if err == nil {
107*333d2b36SAndroid Build Coastguard Worker		_, err = w.Write(buf)
108*333d2b36SAndroid Build Coastguard Worker	}
109*333d2b36SAndroid Build Coastguard Worker
110*333d2b36SAndroid Build Coastguard Worker	// Write the remainder of the file
111*333d2b36SAndroid Build Coastguard Worker	pos := int64(offset) + int64(len(buf))
112*333d2b36SAndroid Build Coastguard Worker	if err == nil {
113*333d2b36SAndroid Build Coastguard Worker		_, err = io.Copy(w, io.NewSectionReader(r, pos, 1<<63-1-pos))
114*333d2b36SAndroid Build Coastguard Worker	}
115*333d2b36SAndroid Build Coastguard Worker
116*333d2b36SAndroid Build Coastguard Worker	if err == io.EOF {
117*333d2b36SAndroid Build Coastguard Worker		err = io.ErrUnexpectedEOF
118*333d2b36SAndroid Build Coastguard Worker	}
119*333d2b36SAndroid Build Coastguard Worker
120*333d2b36SAndroid Build Coastguard Worker	return err
121*333d2b36SAndroid Build Coastguard Worker}
122*333d2b36SAndroid Build Coastguard Worker
123*333d2b36SAndroid Build Coastguard Workerfunc findSymbol(file *File, symbolName string) (uint64, uint64, error) {
124*333d2b36SAndroid Build Coastguard Worker	for i, symbol := range file.Symbols {
125*333d2b36SAndroid Build Coastguard Worker		if symbol.Name == symbolName {
126*333d2b36SAndroid Build Coastguard Worker			// Find the next symbol (n the same section with a higher address
127*333d2b36SAndroid Build Coastguard Worker			var n int
128*333d2b36SAndroid Build Coastguard Worker			for n = i; n < len(file.Symbols); n++ {
129*333d2b36SAndroid Build Coastguard Worker				if file.Symbols[n].Section != symbol.Section {
130*333d2b36SAndroid Build Coastguard Worker					n = len(file.Symbols)
131*333d2b36SAndroid Build Coastguard Worker					break
132*333d2b36SAndroid Build Coastguard Worker				}
133*333d2b36SAndroid Build Coastguard Worker				if file.Symbols[n].Addr > symbol.Addr {
134*333d2b36SAndroid Build Coastguard Worker					break
135*333d2b36SAndroid Build Coastguard Worker				}
136*333d2b36SAndroid Build Coastguard Worker			}
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker			size := symbol.Size
139*333d2b36SAndroid Build Coastguard Worker			if size == 0 {
140*333d2b36SAndroid Build Coastguard Worker				var end uint64
141*333d2b36SAndroid Build Coastguard Worker				if n < len(file.Symbols) {
142*333d2b36SAndroid Build Coastguard Worker					end = file.Symbols[n].Addr
143*333d2b36SAndroid Build Coastguard Worker				} else {
144*333d2b36SAndroid Build Coastguard Worker					end = symbol.Section.Size
145*333d2b36SAndroid Build Coastguard Worker				}
146*333d2b36SAndroid Build Coastguard Worker
147*333d2b36SAndroid Build Coastguard Worker				if end <= symbol.Addr || end > symbol.Addr+4096 {
148*333d2b36SAndroid Build Coastguard Worker					return maxUint64, maxUint64, fmt.Errorf("symbol end address does not seem valid, %x:%x", symbol.Addr, end)
149*333d2b36SAndroid Build Coastguard Worker				}
150*333d2b36SAndroid Build Coastguard Worker
151*333d2b36SAndroid Build Coastguard Worker				size = end - symbol.Addr
152*333d2b36SAndroid Build Coastguard Worker			}
153*333d2b36SAndroid Build Coastguard Worker
154*333d2b36SAndroid Build Coastguard Worker			offset := symbol.Section.Offset + symbol.Addr
155*333d2b36SAndroid Build Coastguard Worker
156*333d2b36SAndroid Build Coastguard Worker			return uint64(offset), uint64(size), nil
157*333d2b36SAndroid Build Coastguard Worker		}
158*333d2b36SAndroid Build Coastguard Worker	}
159*333d2b36SAndroid Build Coastguard Worker
160*333d2b36SAndroid Build Coastguard Worker	return maxUint64, maxUint64, fmt.Errorf("symbol not found")
161*333d2b36SAndroid Build Coastguard Worker}
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Workertype File struct {
164*333d2b36SAndroid Build Coastguard Worker	r           io.ReaderAt
165*333d2b36SAndroid Build Coastguard Worker	Symbols     []*Symbol
166*333d2b36SAndroid Build Coastguard Worker	Sections    []*Section
167*333d2b36SAndroid Build Coastguard Worker	IsMachoFile bool
168*333d2b36SAndroid Build Coastguard Worker}
169*333d2b36SAndroid Build Coastguard Worker
170*333d2b36SAndroid Build Coastguard Workertype Symbol struct {
171*333d2b36SAndroid Build Coastguard Worker	Name    string
172*333d2b36SAndroid Build Coastguard Worker	Addr    uint64 // Address of the symbol inside the section.
173*333d2b36SAndroid Build Coastguard Worker	Size    uint64 // Size of the symbol, if known.
174*333d2b36SAndroid Build Coastguard Worker	Section *Section
175*333d2b36SAndroid Build Coastguard Worker}
176*333d2b36SAndroid Build Coastguard Worker
177*333d2b36SAndroid Build Coastguard Workertype Section struct {
178*333d2b36SAndroid Build Coastguard Worker	Name   string
179*333d2b36SAndroid Build Coastguard Worker	Addr   uint64 // Virtual address of the start of the section.
180*333d2b36SAndroid Build Coastguard Worker	Offset uint64 // Offset into the file of the start of the section.
181*333d2b36SAndroid Build Coastguard Worker	Size   uint64
182*333d2b36SAndroid Build Coastguard Worker}
183*333d2b36SAndroid Build Coastguard Worker
184*333d2b36SAndroid Build Coastguard Workerfunc DumpSymbols(r io.ReaderAt) error {
185*333d2b36SAndroid Build Coastguard Worker	err := dumpElfSymbols(r)
186*333d2b36SAndroid Build Coastguard Worker	if elfError, ok := err.(cantParseError); ok {
187*333d2b36SAndroid Build Coastguard Worker		// Try as a mach-o file
188*333d2b36SAndroid Build Coastguard Worker		err = dumpMachoSymbols(r)
189*333d2b36SAndroid Build Coastguard Worker		if _, ok := err.(cantParseError); ok {
190*333d2b36SAndroid Build Coastguard Worker			// Try as a windows PE file
191*333d2b36SAndroid Build Coastguard Worker			err = dumpPESymbols(r)
192*333d2b36SAndroid Build Coastguard Worker			if _, ok := err.(cantParseError); ok {
193*333d2b36SAndroid Build Coastguard Worker				// Can't parse as elf, macho, or PE, return the elf error
194*333d2b36SAndroid Build Coastguard Worker				return elfError
195*333d2b36SAndroid Build Coastguard Worker			}
196*333d2b36SAndroid Build Coastguard Worker		}
197*333d2b36SAndroid Build Coastguard Worker	}
198*333d2b36SAndroid Build Coastguard Worker	return err
199*333d2b36SAndroid Build Coastguard Worker}
200