Skip to content

Commit 5a988ae

Browse files
committed
feat: support Swift auto demangling hooks
1 parent ca8aeaa commit 5a988ae

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

file.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type File struct {
4444
ledata *bytes.Buffer // tmp storage of linkedit data
4545

4646
sharedCacheRelativeSelectorBaseVMAddress uint64 // objc_opt version 16
47+
swiftAutoDemangle bool
4748

4849
mu sync.Mutex
4950
sr types.MachoReader
@@ -137,6 +138,7 @@ func NewFile(r io.ReaderAt, config ...FileConfig) (*File, error) {
137138

138139
f.objc = make(map[uint64]any)
139140
f.swift = make(map[uint64]any)
141+
f.swiftAutoDemangle = true
140142

141143
f.vma = &types.VMAddrConverter{
142144
Converter: f.convertToVMAddr,
@@ -3267,3 +3269,13 @@ func (f *File) FindAddressSymbols(addr uint64) ([]Symbol, error) {
32673269
}
32683270
return nil, fmt.Errorf("symbol(s) not found in macho symtab for addr %#x", addr)
32693271
}
3272+
3273+
// SetSwiftAutoDemangle toggles automatic demangling of Swift metadata strings when parsing structures.
3274+
func (f *File) SetSwiftAutoDemangle(enabled bool) {
3275+
f.swiftAutoDemangle = enabled
3276+
}
3277+
3278+
// SwiftAutoDemangle reports whether Swift metadata strings are automatically demangled.
3279+
func (f *File) SwiftAutoDemangle() bool {
3280+
return f.swiftAutoDemangle
3281+
}

swift.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"strings"
1212
"unicode"
1313

14+
swiftpkg "github.com/blacktop/go-macho/pkg/swift"
1415
"github.com/blacktop/go-macho/types"
1516
"github.com/blacktop/go-macho/types/swift"
1617
)
@@ -555,7 +556,7 @@ func (f *File) GetSwiftDynamicReplacementInfoForOpaqueTypes() (*swift.AutomaticD
555556
}
556557

557558
// GetSwiftAccessibleFunctions parses the __TEXT.__swift5_acfuncs section
558-
func (f *File) GetSwiftAccessibleFunctions() (funcs []swift.TargetAccessibleFunctionRecord, err error) {
559+
func (f *File) GetSwiftAccessibleFunctions() (funcs []swift.AccessibleFunction, err error) {
559560
if sec := f.Section("__TEXT", "__swift5_acfuncs"); sec != nil {
560561
off, err := f.vma.GetOffset(f.vma.Convert(sec.Addr))
561562
if err != nil {
@@ -579,7 +580,41 @@ func (f *File) GetSwiftAccessibleFunctions() (funcs []swift.TargetAccessibleFunc
579580
}
580581
return nil, fmt.Errorf("failed to read swift %T: %w", afr, err)
581582
}
582-
funcs = append(funcs, afr)
583+
584+
name := ""
585+
if afr.Name.IsSet() {
586+
if s, err := f.GetCString(afr.Name.GetAddress()); err == nil {
587+
name = f.demangleSwiftString(s)
588+
} else {
589+
name = fmt.Sprintf("(name %#x)", afr.Name.GetAddress())
590+
}
591+
}
592+
593+
functionType := ""
594+
if afr.FunctionType.IsSet() {
595+
if s, err := f.makeSymbolicMangledNameStringRef(afr.FunctionType.GetAddress()); err == nil {
596+
functionType = f.demangleSwiftString(s)
597+
} else if raw, err := f.GetCString(afr.FunctionType.GetAddress()); err == nil {
598+
functionType = f.demangleSwiftString(raw)
599+
} else {
600+
functionType = fmt.Sprintf("(type %#x)", afr.FunctionType.GetAddress())
601+
}
602+
}
603+
604+
fnAddr := afr.Function.GetAddress()
605+
if f.vma != nil {
606+
if converted := f.vma.Convert(fnAddr); converted != 0 {
607+
fnAddr = converted
608+
}
609+
}
610+
611+
funcs = append(funcs, swift.AccessibleFunction{
612+
Name: name,
613+
FunctionType: functionType,
614+
FunctionAddress: fnAddr,
615+
GenericEnvironment: afr.GenericEnvironment.GetAddress(),
616+
Flags: afr.Flags,
617+
})
583618
}
584619

585620
return funcs, nil
@@ -3051,3 +3086,36 @@ func (f *File) makeSymbolicMangledNameStringRef(addr uint64) (string, error) {
30513086

30523087
return strings.Join(out, " "), nil
30533088
}
3089+
3090+
func (f *File) demangleSwiftString(input string) string {
3091+
trimmed := strings.TrimSpace(input)
3092+
if trimmed == "" {
3093+
return input
3094+
}
3095+
if mapped, ok := swiftSpecialTypeTokens[trimmed]; ok {
3096+
return mapped
3097+
}
3098+
if !f.swiftAutoDemangle {
3099+
return trimmed
3100+
}
3101+
if out, err := swiftpkg.Demangle(trimmed); err == nil && out != "" {
3102+
return out
3103+
}
3104+
return swiftpkg.NormalizeIdentifier(trimmed)
3105+
}
3106+
3107+
func (f *File) normalizeSwiftIdentifier(name string) string {
3108+
if name == "" {
3109+
return name
3110+
}
3111+
if !f.swiftAutoDemangle {
3112+
return name
3113+
}
3114+
return swiftpkg.NormalizeIdentifier(name)
3115+
}
3116+
3117+
var swiftSpecialTypeTokens = map[string]string{
3118+
"_$sXDXMT": "@thick Self.Type",
3119+
"$sXDXMT": "@thick Self.Type",
3120+
"XDXMT": "@thick Self.Type",
3121+
}

types/swift/accessible_funcs.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package swift
22

33
import (
44
"encoding/binary"
5+
"fmt"
56
"io"
67
)
78

@@ -67,3 +68,15 @@ type AccessibleFunctionsState struct {
6768
Cache AccessibleFunctionCacheEntry
6869
SectionsToScan AccessibleFunctionsSection
6970
}
71+
72+
type AccessibleFunction struct {
73+
Name string
74+
FunctionType string
75+
FunctionAddress uint64
76+
GenericEnvironment uint64
77+
Flags AccessibleFunctionFlags
78+
}
79+
80+
func (af AccessibleFunction) String() string {
81+
return fmt.Sprintf("%s : %s (fn: %#x, env: %#x, flags: %#x)", af.Name, af.FunctionType, af.FunctionAddress, af.GenericEnvironment, uint32(af.Flags))
82+
}

0 commit comments

Comments
 (0)