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