xref: /aosp_15_r20/build/soong/elf/elf.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2022 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 elf
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"debug/elf"
19*333d2b36SAndroid Build Coastguard Worker	"encoding/binary"
20*333d2b36SAndroid Build Coastguard Worker	"encoding/hex"
21*333d2b36SAndroid Build Coastguard Worker	"errors"
22*333d2b36SAndroid Build Coastguard Worker	"fmt"
23*333d2b36SAndroid Build Coastguard Worker	"io"
24*333d2b36SAndroid Build Coastguard Worker	"os"
25*333d2b36SAndroid Build Coastguard Worker)
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Workerconst gnuBuildID = "GNU\x00"
28*333d2b36SAndroid Build Coastguard Worker
29*333d2b36SAndroid Build Coastguard Worker// Identifier extracts the elf build ID from an elf file.  If allowMissing is true it returns
30*333d2b36SAndroid Build Coastguard Worker// an empty identifier if the file exists but the build ID note does not.
31*333d2b36SAndroid Build Coastguard Workerfunc Identifier(filename string, allowMissing bool) (string, error) {
32*333d2b36SAndroid Build Coastguard Worker	f, err := os.Open(filename)
33*333d2b36SAndroid Build Coastguard Worker	if err != nil {
34*333d2b36SAndroid Build Coastguard Worker		return "", fmt.Errorf("failed to open %s: %w", filename, err)
35*333d2b36SAndroid Build Coastguard Worker	}
36*333d2b36SAndroid Build Coastguard Worker	defer f.Close()
37*333d2b36SAndroid Build Coastguard Worker
38*333d2b36SAndroid Build Coastguard Worker	return elfIdentifierFromReaderAt(f, filename, allowMissing)
39*333d2b36SAndroid Build Coastguard Worker}
40*333d2b36SAndroid Build Coastguard Worker
41*333d2b36SAndroid Build Coastguard Worker// elfIdentifierFromReaderAt extracts the elf build ID from a ReaderAt.  If allowMissing is true it
42*333d2b36SAndroid Build Coastguard Worker// returns an empty identifier if the file exists but the build ID note does not.
43*333d2b36SAndroid Build Coastguard Workerfunc elfIdentifierFromReaderAt(r io.ReaderAt, filename string, allowMissing bool) (string, error) {
44*333d2b36SAndroid Build Coastguard Worker	f, err := elf.NewFile(r)
45*333d2b36SAndroid Build Coastguard Worker	if err != nil {
46*333d2b36SAndroid Build Coastguard Worker		if allowMissing {
47*333d2b36SAndroid Build Coastguard Worker			if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
48*333d2b36SAndroid Build Coastguard Worker				return "", nil
49*333d2b36SAndroid Build Coastguard Worker			}
50*333d2b36SAndroid Build Coastguard Worker			if _, ok := err.(*elf.FormatError); ok {
51*333d2b36SAndroid Build Coastguard Worker				// The file was not an elf file.
52*333d2b36SAndroid Build Coastguard Worker				return "", nil
53*333d2b36SAndroid Build Coastguard Worker			}
54*333d2b36SAndroid Build Coastguard Worker		}
55*333d2b36SAndroid Build Coastguard Worker		return "", fmt.Errorf("failed to parse elf file %s: %w", filename, err)
56*333d2b36SAndroid Build Coastguard Worker	}
57*333d2b36SAndroid Build Coastguard Worker	defer f.Close()
58*333d2b36SAndroid Build Coastguard Worker
59*333d2b36SAndroid Build Coastguard Worker	buildIDNote := f.Section(".note.gnu.build-id")
60*333d2b36SAndroid Build Coastguard Worker	if buildIDNote == nil {
61*333d2b36SAndroid Build Coastguard Worker		if allowMissing {
62*333d2b36SAndroid Build Coastguard Worker			return "", nil
63*333d2b36SAndroid Build Coastguard Worker		}
64*333d2b36SAndroid Build Coastguard Worker		return "", fmt.Errorf("failed to find .note.gnu.build-id in  %s", filename)
65*333d2b36SAndroid Build Coastguard Worker	}
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Worker	buildIDs, err := readNote(buildIDNote.Open(), f.ByteOrder)
68*333d2b36SAndroid Build Coastguard Worker	if err != nil {
69*333d2b36SAndroid Build Coastguard Worker		return "", fmt.Errorf("failed to read .note.gnu.build-id: %w", err)
70*333d2b36SAndroid Build Coastguard Worker	}
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker	for name, desc := range buildIDs {
73*333d2b36SAndroid Build Coastguard Worker		if name == gnuBuildID {
74*333d2b36SAndroid Build Coastguard Worker			return hex.EncodeToString(desc), nil
75*333d2b36SAndroid Build Coastguard Worker		}
76*333d2b36SAndroid Build Coastguard Worker	}
77*333d2b36SAndroid Build Coastguard Worker
78*333d2b36SAndroid Build Coastguard Worker	return "", nil
79*333d2b36SAndroid Build Coastguard Worker}
80*333d2b36SAndroid Build Coastguard Worker
81*333d2b36SAndroid Build Coastguard Worker// readNote reads the contents of a note section, returning it as a map from name to descriptor.
82*333d2b36SAndroid Build Coastguard Workerfunc readNote(note io.Reader, byteOrder binary.ByteOrder) (map[string][]byte, error) {
83*333d2b36SAndroid Build Coastguard Worker	var noteHeader struct {
84*333d2b36SAndroid Build Coastguard Worker		Namesz uint32
85*333d2b36SAndroid Build Coastguard Worker		Descsz uint32
86*333d2b36SAndroid Build Coastguard Worker		Type   uint32
87*333d2b36SAndroid Build Coastguard Worker	}
88*333d2b36SAndroid Build Coastguard Worker
89*333d2b36SAndroid Build Coastguard Worker	notes := make(map[string][]byte)
90*333d2b36SAndroid Build Coastguard Worker	for {
91*333d2b36SAndroid Build Coastguard Worker		err := binary.Read(note, byteOrder, &noteHeader)
92*333d2b36SAndroid Build Coastguard Worker		if err != nil {
93*333d2b36SAndroid Build Coastguard Worker			if err == io.EOF {
94*333d2b36SAndroid Build Coastguard Worker				return notes, nil
95*333d2b36SAndroid Build Coastguard Worker			}
96*333d2b36SAndroid Build Coastguard Worker			return nil, fmt.Errorf("failed to read note header: %w", err)
97*333d2b36SAndroid Build Coastguard Worker		}
98*333d2b36SAndroid Build Coastguard Worker
99*333d2b36SAndroid Build Coastguard Worker		nameBuf := make([]byte, align4(noteHeader.Namesz))
100*333d2b36SAndroid Build Coastguard Worker		err = binary.Read(note, byteOrder, &nameBuf)
101*333d2b36SAndroid Build Coastguard Worker		if err != nil {
102*333d2b36SAndroid Build Coastguard Worker			return nil, fmt.Errorf("failed to read note name: %w", err)
103*333d2b36SAndroid Build Coastguard Worker		}
104*333d2b36SAndroid Build Coastguard Worker		name := string(nameBuf[:noteHeader.Namesz])
105*333d2b36SAndroid Build Coastguard Worker
106*333d2b36SAndroid Build Coastguard Worker		descBuf := make([]byte, align4(noteHeader.Descsz))
107*333d2b36SAndroid Build Coastguard Worker		err = binary.Read(note, byteOrder, &descBuf)
108*333d2b36SAndroid Build Coastguard Worker		if err != nil {
109*333d2b36SAndroid Build Coastguard Worker			return nil, fmt.Errorf("failed to read note desc: %w", err)
110*333d2b36SAndroid Build Coastguard Worker		}
111*333d2b36SAndroid Build Coastguard Worker		notes[name] = descBuf[:noteHeader.Descsz]
112*333d2b36SAndroid Build Coastguard Worker	}
113*333d2b36SAndroid Build Coastguard Worker}
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Worker// align4 rounds the input up to the next multiple of 4.
116*333d2b36SAndroid Build Coastguard Workerfunc align4(i uint32) uint32 {
117*333d2b36SAndroid Build Coastguard Worker	return (i + 3) &^ 3
118*333d2b36SAndroid Build Coastguard Worker}
119