feat: add support for --demangle to ipsw symbolicate for panics

This commit is contained in:
blacktop
2024-06-03 20:10:22 -06:00
parent adae985c4f
commit fc4393c037
2 changed files with 59 additions and 19 deletions
+11 -3
View File
@@ -43,6 +43,8 @@ func init() {
symbolicateCmd.Flags().BoolP("demangle", "d", false, "Demangle symbol names")
// symbolicateCmd.Flags().String("cache", "", "Path to .a2s addr to sym cache file (speeds up analysis)")
symbolicateCmd.MarkZshCompPositionalArgumentFile(2, "dyld_shared_cache*")
viper.BindPFlag("symbolicate.unslide", symbolicateCmd.Flags().Lookup("unslide"))
viper.BindPFlag("symbolicate.demangle", symbolicateCmd.Flags().Lookup("demangle"))
}
// TODO: handle all edge cases from `/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash` and handle spindumps etc
@@ -60,9 +62,9 @@ var symbolicateCmd = &cobra.Command{
}
color.NoColor = viper.GetBool("no-color")
unslide, _ := cmd.Flags().GetBool("unslide")
unslide := viper.GetBool("symbolicate.unslide")
// cacheFile, _ := cmd.Flags().GetString("cache")
demangleFlag, _ := cmd.Flags().GetBool("demangle")
demangleFlag := viper.GetBool("symbolicate.demangle")
hdr, err := crashlog.ParseHeader(args[0])
if err != nil {
@@ -84,7 +86,13 @@ var symbolicateCmd = &cobra.Command{
log.Warnf("please supply %s %s IPSW for symbolication", ips.Payload.Product, ips.Header.OsVersion)
} else {
if hdr.BugType == "210" {
if err := ips.Symbolicate210(filepath.Clean(args[1])); err != nil {
if err := ips.Symbolicate210(
filepath.Clean(args[1]),
&crashlog.Config{
Unslid: unslide,
Demangle: demangleFlag,
},
); err != nil {
return err
}
}
+48 -16
View File
@@ -19,7 +19,9 @@ import (
"github.com/blacktop/go-macho"
"github.com/blacktop/go-macho/types"
"github.com/blacktop/ipsw/internal/commands/dsc"
"github.com/blacktop/ipsw/internal/demangle"
"github.com/blacktop/ipsw/internal/search"
"github.com/blacktop/ipsw/internal/swift"
"github.com/fatih/color"
)
@@ -81,6 +83,11 @@ func GetLogTypes() (*LogTypes, error) {
return &db.LogTypes, nil
}
type Config struct {
Unslid bool
Demangle bool
}
type Ips struct {
Header IpsMetadata
Payload IPSPayload
@@ -367,7 +374,7 @@ type Frame struct {
ImageIndex uint64 `json:"imageIndex,omitempty"`
ImageOffset uint64 `json:"imageOffset,omitempty"`
Symbol string `json:"symbol,omitempty"`
SymbolLocation int `json:"symbolLocation,omitempty"`
SymbolLocation uint64 `json:"symbolLocation,omitempty"`
}
type PanicFrame struct {
@@ -375,7 +382,7 @@ type PanicFrame struct {
ImageName string `json:"imageName,omitempty"`
ImageOffset uint64 `json:"imageOffset,omitempty"`
Symbol string `json:"symbol,omitempty"`
SymbolLocation int `json:"symbolLocation,omitempty"`
SymbolLocation uint64 `json:"symbolLocation,omitempty"`
}
func (pf *PanicFrame) UnmarshalJSON(b []byte) error {
@@ -558,7 +565,7 @@ func OpenIPS(in string) (*Ips, error) {
return &ips, nil
}
func (i *Ips) Symbolicate210(ipswPath string) error {
func (i *Ips) Symbolicate210(ipswPath string, conf *Config) error {
total := len(i.Payload.BinaryImages)
// add default binary image names
@@ -635,14 +642,17 @@ func (i *Ips) Symbolicate210(ipswPath string) error {
for pid, proc := range i.Payload.ProcessByPid {
for tid, thread := range proc.ThreadByID {
for idx, frame := range thread.UserFrames {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset += i.Payload.BinaryImages[frame.ImageIndex].Base
if len(i.Payload.BinaryImages[frame.ImageIndex].Name) > 0 {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName = i.Payload.BinaryImages[frame.ImageIndex].Name
} else {
if strings.HasPrefix(i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName, "image_") {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName += fmt.Sprintf(" (probably %s)", proc.Name)
}
}
if i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName == "absolute" {
continue
}
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset += i.Payload.BinaryImages[frame.ImageIndex].Base
if i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName == "dyld_shared_cache" {
continue // skip absolute
} else if i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName == "dyld_shared_cache" {
// lookup symbol in DSC dylib
if img, err := f.GetImageContainingVMAddr(i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset); err == nil {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName = filepath.Base(img.Name)
@@ -654,11 +664,20 @@ func (i *Ips) Symbolicate210(ipswPath string) error {
}
if fn, err := m.GetFunctionForVMAddr(i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset); err == nil {
if sym, ok := f.AddressToSymbol[fn.StartAddr]; ok {
delta := ""
if conf.Demangle {
if strings.HasPrefix(sym, "_$s") || strings.HasPrefix(sym, "$s") { // TODO: better detect swift symbols
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol, _ = swift.Demangle(sym)
} else if strings.HasPrefix(sym, "__Z") || strings.HasPrefix(sym, "_Z") {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = demangle.Do(sym, false, false)
} else {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = sym
}
} else {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = sym
}
if i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset-fn.StartAddr != 0 {
delta = fmt.Sprintf(" + %d", i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset-fn.StartAddr)
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].SymbolLocation = i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset - fn.StartAddr
}
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = sym + delta
} else {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = fmt.Sprintf("func_%x", fn.StartAddr)
}
@@ -669,11 +688,20 @@ func (i *Ips) Symbolicate210(ipswPath string) error {
if funcs, ok := machoFuncMap[i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName]; ok {
for _, fn := range funcs {
if fn.StartAddr <= i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset && i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset < fn.EndAddr {
delta := ""
if conf.Demangle {
if strings.HasPrefix(fn.Name, "_$s") || strings.HasPrefix(fn.Name, "$s") { // TODO: better detect swift symbols
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol, _ = swift.Demangle(fn.Name)
} else if strings.HasPrefix(fn.Name, "__Z") || strings.HasPrefix(fn.Name, "_Z") {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = demangle.Do(fn.Name, false, false)
} else {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = fn.Name
}
} else {
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = fn.Name
}
if i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset-fn.StartAddr != 0 {
delta = fmt.Sprintf(" + %d", i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset-fn.StartAddr)
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].SymbolLocation = i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset - fn.StartAddr
}
i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].Symbol = fn.Name + delta
}
}
} else {
@@ -682,15 +710,15 @@ func (i *Ips) Symbolicate210(ipswPath string) error {
"thread": tid,
"frame": idx,
"img": i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageName,
}).Debugf("failed to find function for offset %#x", i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset)
}).Debugf("failed to find function for process offset %#x", i.Payload.ProcessByPid[pid].ThreadByID[tid].UserFrames[idx].ImageOffset)
}
}
}
for idx, frame := range thread.KernelFrames {
i.Payload.ProcessByPid[pid].ThreadByID[tid].KernelFrames[idx].ImageOffset += i.Payload.BinaryImages[frame.ImageIndex].Base
if len(i.Payload.BinaryImages[frame.ImageIndex].Name) > 0 {
i.Payload.ProcessByPid[pid].ThreadByID[tid].KernelFrames[idx].ImageName = i.Payload.BinaryImages[frame.ImageIndex].Name
}
i.Payload.ProcessByPid[pid].ThreadByID[tid].KernelFrames[idx].ImageOffset += i.Payload.BinaryImages[frame.ImageIndex].Base
}
}
}
@@ -882,7 +910,11 @@ func (i *Ips) String(verbose bool) string {
buf := bytes.NewBufferString("")
w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
for idx, f := range i.Payload.LastExceptionBacktrace {
fmt.Fprintf(w, " %02d: %s\t%s %s + %d\n", idx, colorImage(i.Payload.UsedImages[f.ImageIndex].Name), colorAddr("%#x", i.Payload.UsedImages[f.ImageIndex].Base+f.ImageOffset), colorField(f.Symbol), f.SymbolLocation)
symloc := ""
if f.SymbolLocation > 0 {
symloc = fmt.Sprintf(" + %d", f.SymbolLocation)
}
fmt.Fprintf(w, " %02d: %s\t%s %s%s\n", idx, colorImage(i.Payload.UsedImages[f.ImageIndex].Name), colorAddr("%#x", i.Payload.UsedImages[f.ImageIndex].Base+f.ImageOffset), colorField(f.Symbol), colorBold(symloc))
}
w.Flush()
out += buf.String() + "\n"