Rewrite symbol_inject to be testable
Parse the machine-specific symbol tables into a custom symbol table
object and use a single function to find the offset and size of the
symbol in the custom table. Make the functions to convert a
machine-specific symbol table into the custom table also take mocks,
and provide functions to dump mocks from real files. Add tests
that take the mocks and verify they produce the right offset and
size.
Test: cmd/symbol_inject/*_test.go
Change-Id: I25654032b5017dd13a9a1fe29f8b8826ce5bc82b
diff --git a/cmd/symbol_inject/macho.go b/cmd/symbol_inject/macho.go
index 478e6de..be49f8b 100644
--- a/cmd/symbol_inject/macho.go
+++ b/cmd/symbol_inject/macho.go
@@ -19,52 +19,79 @@
"fmt"
"io"
"sort"
+ "strings"
)
-func findMachoSymbol(r io.ReaderAt, symbolName string) (uint64, uint64, error) {
+func machoSymbolsFromFile(r io.ReaderAt) (*File, error) {
machoFile, err := macho.NewFile(r)
if err != nil {
- return maxUint64, maxUint64, cantParseError{err}
+ return nil, cantParseError{err}
}
- // symbols in macho files seem to be prefixed with an underscore
- symbolName = "_" + symbolName
+ return extractMachoSymbols(machoFile)
+}
+func extractMachoSymbols(machoFile *macho.File) (*File, error) {
symbols := machoFile.Symtab.Syms
- sort.Slice(symbols, func(i, j int) bool {
+ sort.SliceStable(symbols, func(i, j int) bool {
if symbols[i].Sect != symbols[j].Sect {
return symbols[i].Sect < symbols[j].Sect
}
return symbols[i].Value < symbols[j].Value
})
+ file := &File{}
+
+ for _, section := range machoFile.Sections {
+ file.Sections = append(file.Sections, &Section{
+ Name: section.Name,
+ Addr: section.Addr,
+ Offset: uint64(section.Offset),
+ Size: section.Size,
+ })
+ }
+
for _, symbol := range symbols {
- if symbol.Name == symbolName && symbol.Sect != 0 {
- // Find the next symbol in the same section with a higher address
- n := sort.Search(len(symbols), func(i int) bool {
- return symbols[i].Sect == symbol.Sect &&
- symbols[i].Value > symbol.Value
+ if symbol.Sect > 0 {
+ section := file.Sections[symbol.Sect-1]
+ file.Symbols = append(file.Symbols, &Symbol{
+ // symbols in macho files seem to be prefixed with an underscore
+ Name: strings.TrimPrefix(symbol.Name, "_"),
+ // MachO symbol value is virtual address of the symbol, convert it to offset into the section.
+ Addr: symbol.Value - section.Addr,
+ // MachO symbols don't have size information.
+ Size: 0,
+ Section: section,
})
-
- section := machoFile.Sections[symbol.Sect-1]
-
- var end uint64
- if n < len(symbols) {
- end = symbols[n].Value
- } else {
- end = section.Addr + section.Size
- }
-
- if end <= symbol.Value && end > symbol.Value+4096 {
- return maxUint64, maxUint64, fmt.Errorf("symbol end address does not seem valid, %x:%x", symbol.Value, end)
- }
-
- size := end - symbol.Value - 1
- offset := uint64(section.Offset) + (symbol.Value - section.Addr)
-
- return offset, size, nil
}
}
- return maxUint64, maxUint64, fmt.Errorf("symbol not found")
+ return file, nil
+}
+
+func dumpMachoSymbols(r io.ReaderAt) error {
+ machoFile, err := macho.NewFile(r)
+ if err != nil {
+ return cantParseError{err}
+ }
+
+ fmt.Println("&macho.File{")
+
+ fmt.Println("\tSections: []*macho.Section{")
+ for _, section := range machoFile.Sections {
+ fmt.Printf("\t\t&macho.Section{SectionHeader: %#v},\n", section.SectionHeader)
+ }
+ fmt.Println("\t},")
+
+ fmt.Println("\tSymtab: &macho.Symtab{")
+ fmt.Println("\t\tSyms: []macho.Symbol{")
+ for _, symbol := range machoFile.Symtab.Syms {
+ fmt.Printf("\t\t\t%#v,\n", symbol)
+ }
+ fmt.Println("\t\t},")
+ fmt.Println("\t},")
+
+ fmt.Println("}")
+
+ return nil
}