Files
ipsw/internal/commands/dsc/diff.go

118 lines
2.7 KiB
Go

package dsc
import (
"sort"
"github.com/apex/log"
mcmd "github.com/blacktop/ipsw/internal/commands/macho"
"github.com/blacktop/ipsw/internal/utils"
"github.com/blacktop/ipsw/pkg/dyld"
)
// Diff compares two DSC files
func Diff(f1 *dyld.File, f2 *dyld.File, conf *mcmd.DiffConfig) (*mcmd.MachoDiff, error) {
diff := &mcmd.MachoDiff{
Updated: make(map[string]string),
}
// Build name->image lookup tables (cheap) so we can diff without
// materializing DiffInfo for every image at once.
prev := make(map[string]*dyld.CacheImage, len(f1.Images))
var prevKeys []string
for _, img := range f1.Images {
prev[img.Name] = img
prevKeys = append(prevKeys, img.Name)
}
next := make(map[string]*dyld.CacheImage, len(f2.Images))
var nextKeys []string
for _, img := range f2.Images {
next[img.Name] = img
nextKeys = append(nextKeys, img.Name)
}
sort.Strings(prevKeys)
sort.Strings(nextKeys)
diff.New = utils.Difference(nextKeys, prevKeys)
diff.Removed = utils.Difference(prevKeys, nextKeys)
// Keep output stable for callers
sort.Strings(diff.New)
sort.Strings(diff.Removed)
for _, name := range nextKeys {
img1, ok := prev[name]
if !ok {
continue
}
img2 := next[name]
m1, err := img1.GetMacho()
if err != nil {
log.Errorf("failed to parse MachO for image %s: %v", img1.Name, err)
continue
}
m2, err := img2.GetMacho()
if err != nil {
log.Errorf("failed to parse MachO for image %s: %v", img2.Name, err)
if m1 != nil {
m1.Close()
}
continue
}
// Parse local/private symbols for better symbol identity when available
if err := img1.ParseLocalSymbols(false); err != nil {
// non-fatal: continue using whatever public symbols we have
log.Debugf("failed to parse local symbols for image %s: %v", img1.Name, err)
} else {
if m1 != nil && m1.Symtab != nil {
m1.Symtab.Syms = append(m1.Symtab.Syms, img1.GetLocalSymbolsAsMachoSymbols()...)
}
}
if err := img2.ParseLocalSymbols(false); err != nil {
log.Debugf("failed to parse local symbols for image %s: %v", img2.Name, err)
} else {
if m2 != nil && m2.Symtab != nil {
m2.Symtab.Syms = append(m2.Symtab.Syms, img2.GetLocalSymbolsAsMachoSymbols()...)
}
}
info1 := mcmd.GenerateDiffInfo(m1, conf)
info2 := mcmd.GenerateDiffInfo(m2, conf)
if info2.Equal(*info1) {
if m1 != nil {
m1.Close()
}
if m2 != nil {
m2.Close()
}
continue
}
out, err := mcmd.FormatUpdatedDiff(info1, info2, conf)
if err != nil {
if m1 != nil {
m1.Close()
}
if m2 != nil {
m2.Close()
}
return nil, err
}
if out != "" {
diff.Updated[name] = out
}
if m1 != nil {
m1.Close()
}
if m2 != nil {
m2.Close()
}
}
return diff, nil
}