package action import ( "sort" "strings" // log "github.com/sirupsen/logrus" . "ios-wrapper/internal/wrapper/ofile" "ios-wrapper/pkg/protomodel" ) type saveImports struct { keepSymbols []string } func (action *saveImports) withMacho(mf *MachoFile) error { action.saveToInfo(mf) mc := mf.Context() if mc.Header().IsDylib() { mc.WriteInfoToData(mf.Info()) } return nil } func (action *saveImports) saveToInfo(mf *MachoFile) error { // calculateHash := func(name string) uint32 { // var h uint32 = 0x811c9dc5 // for _, s := range name { // h ^= uint32(s) // h *= 0x01000193 // } // return h // } mc := mf.Context() // symbols_storage := []*protomodel.MachoInfo_AllImportedSymbols{} symbols_raw := mc.CollectBindSymbols() sort.Slice(symbols_raw, func(i, j int) bool { orderedByLibrary := symbols_raw[i].Dylib() < symbols_raw[j].Dylib() if symbols_raw[i].Dylib() == symbols_raw[j].Dylib() { orderedBySymbol := symbols_raw[i].Name() < symbols_raw[j].Name() return orderedBySymbol } return orderedByLibrary }) libs := []string{} symbols := []string{} tables := []*protomodel.MachoInfo_LibraryImportedSymbols{} var current_table *protomodel.MachoInfo_LibraryImportedSymbols current_lib := "" current_symbol := "" current_lib_idx := -1 current_symbol_idx := -1 intlSymbols := []string{} for _, symbol := range symbols_raw { if symbol.Dylib() == "/usr/local/opt/gettext/lib/libintl.8.dylib" { intlSymbols = append(intlSymbols, symbol.Name()) } } action.keepSymbols = append(action.keepSymbols, intlSymbols...) // now we expect everything is sorted and easier to build strings tables // this is not fully optimized, there can be repeated symbol name in different libraries for _, symbol := range symbols_raw { if symbol.Type() != "lazy" { continue } skip := false for _, keep := range action.keepSymbols { name := keep lib := "" parts := strings.Split(keep, ",") if len(parts) == 2 { name = parts[0] lib = parts[1] } if symbol.Name() != name { continue } if lib == "" || lib == symbol.Dylib() { skip = true break } } if skip { continue } // dylib_hash := calculateHash(symbol.Dylib()) seg := mc.Segments()[symbol.Segment()] var offset uint64 if symbol.Address() >= seg.Vmaddr() { // this is virtual address offset = symbol.Address() - seg.Vmaddr() } else { // this is file address offset = symbol.Address() - seg.Fileoff() } if current_lib != symbol.Dylib() { current_lib_idx += len(current_lib) + 1 current_lib = symbol.Dylib() libs = append(libs, symbol.Dylib()) tables = append(tables, &protomodel.MachoInfo_LibraryImportedSymbols{ LibIndex: uint32(current_lib_idx), Nsymbols: 0, Symbols: []*protomodel.MachoInfo_SymbolTable{}, }) current_table = tables[len(tables)-1] } if current_symbol != symbol.Name() { current_symbol_idx += len(current_symbol) + 1 current_symbol = symbol.Name() symbols = append(symbols, symbol.Name()) } current_table.Nsymbols += 1 current_table.Symbols = append(current_table.Symbols, &protomodel.MachoInfo_SymbolTable{ SymbolIndex: uint32(current_symbol_idx), SegmentIndex: symbol.Segment(), Offset: uint32(offset), }) } mf.Info().Symbols = &protomodel.MachoInfo_AllImportedSymbols{ Libs: libs, Symbols: symbols, Tables: tables, } mf.Info().Main = mc.Main() return nil } func (action *saveImports) withFat(ff *FatFile) error { return defaultWithFat(action, ff) } func NewSaveImportsAction(keepSymbols []string) *saveImports { return &saveImports{ keepSymbols, } }