Skip to content

Commit 3b4f8c8

Browse files
committed
fix: ipsw kernel dwarf --type and --name flags to return ALL matches
1 parent d33802e commit 3b4f8c8

File tree

2 files changed

+141
-99
lines changed

2 files changed

+141
-99
lines changed

cmd/ipsw/cmd/kernel/kernel_dwarf.go

+38-24
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/AlecAivazis/survey/v2/terminal"
3333
"github.com/apex/log"
3434
"github.com/blacktop/ipsw/internal/commands/dwarf"
35+
"github.com/blacktop/ipsw/internal/demangle"
3536
"github.com/blacktop/ipsw/internal/utils"
3637
"github.com/fatih/color"
3738

@@ -243,30 +244,34 @@ var dwarfCmd = &cobra.Command{
243244
}
244245

245246
if len(viper.GetString("kernel.dwarf.type")) > 0 {
246-
t1, _, err := dwarf.GetType(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.type"), !noOffsets)
247+
t1, err := dwarf.GetType(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.type"), !noOffsets)
247248
if err != nil {
248249
return err
249250
}
250251

251-
t2, _, err := dwarf.GetType(filepath.Clean(args[1]), viper.GetString("kernel.dwarf.type"), !noOffsets)
252+
t2, err := dwarf.GetType(filepath.Clean(args[1]), viper.GetString("kernel.dwarf.type"), !noOffsets)
252253
if err != nil {
253254
return err
254255
}
255256

256-
if t1 == "" || t2 == "" {
257+
if len(t1) == 0 || len(t2) == 0 {
257258
return fmt.Errorf("could not find type '%s' in one or both of the files", viper.GetString("kernel.dwarf.type"))
258259
}
259260

260-
out, err := utils.GitDiff(t1, t2, &utils.GitDiffConfig{Color: viper.GetBool("color") && !viper.GetBool("no-color"), Tool: viper.GetString("diff-tool")})
261-
if err != nil {
262-
return err
263-
}
264-
265-
if len(out) == 0 {
266-
log.Info("No differences found")
267-
} else {
268-
log.Info("Differences found")
269-
fmt.Println(out)
261+
for file2, typ2 := range t2 {
262+
if typ1, found := t1[file2]; found {
263+
out, err := utils.GitDiff(typ1, typ2, &utils.GitDiffConfig{Color: viper.GetBool("color") && !viper.GetBool("no-color"), Tool: viper.GetString("diff-tool")})
264+
if err != nil {
265+
return err
266+
}
267+
268+
if len(out) == 0 {
269+
log.Info("No differences found")
270+
} else {
271+
log.Info("Differences found")
272+
fmt.Println(out)
273+
}
274+
}
270275
}
271276
} else { // diff ALL structs
272277
out, err := dwarf.DiffEnums(filepath.Clean(args[0]), filepath.Clean(args[1]), &dwarf.Config{
@@ -316,33 +321,42 @@ var dwarfCmd = &cobra.Command{
316321
}
317322

318323
if len(viper.GetString("kernel.dwarf.type")) > 0 {
319-
typstr, file, err := dwarf.GetType(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.type"), !noOffsets)
324+
typs, err := dwarf.GetType(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.type"), !noOffsets)
320325
if err != nil {
321326
return err
322327
}
323-
if len(file) > 0 {
324-
if _, after, ok := strings.Cut(file, "/Library/Caches/com.apple.xbs/Sources/"); ok {
325-
log.WithField("file", after).Info(viper.GetString("kernel.dwarf.type"))
326-
} else {
327-
log.WithField("file", file).Info(viper.GetString("kernel.dwarf.type"))
328+
for file, typ := range typs {
329+
if len(file) > 0 {
330+
if _, after, ok := strings.Cut(file, "/Library/Caches/com.apple.xbs/"); ok {
331+
log.WithField("file", after).Info(viper.GetString("kernel.dwarf.type"))
332+
} else {
333+
log.WithField("file", file).Info(viper.GetString("kernel.dwarf.type"))
334+
}
328335
}
336+
fmt.Println(utils.ClangFormat(typ, viper.GetString("kernel.dwarf.type")+".h", viper.GetBool("color") && !viper.GetBool("no-color")))
329337
}
330-
fmt.Println(utils.ClangFormat(typstr, viper.GetString("kernel.dwarf.type")+".h", viper.GetBool("color") && !viper.GetBool("no-color")))
331338
}
332339

333340
if len(viper.GetString("kernel.dwarf.name")) > 0 {
334-
n, file, err := dwarf.GetName(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.name"))
341+
names, err := dwarf.GetName(filepath.Clean(args[0]), viper.GetString("kernel.dwarf.name"))
335342
if err != nil {
336343
return err
337344
}
338-
if len(file) > 0 {
339-
if _, after, ok := strings.Cut(file, "/Library/Caches/com.apple.xbs/Sources/"); ok {
345+
for file, n := range names {
346+
if _, after, ok := strings.Cut(file, "/Library/Caches/com.apple.xbs/"); ok {
340347
log.WithField("file", after).Info(viper.GetString("kernel.dwarf.name"))
341348
} else {
342349
log.WithField("file", file).Info(viper.GetString("kernel.dwarf.name"))
343350
}
351+
if n.Name == "" {
352+
if strings.HasPrefix(n.LinkageName, "__Z") || strings.HasPrefix(n.LinkageName, "_Z") {
353+
n.LinkageName = demangle.Do("_"+n.LinkageName, false, false)
354+
}
355+
fmt.Printf("%#x: %s", n.LowPC, utils.ClangFormat(n.LinkageName, viper.GetString("kernel.dwarf.name")+".h", viper.GetBool("color") && !viper.GetBool("no-color")))
356+
} else {
357+
fmt.Printf("%#x: %s", n.LowPC, utils.ClangFormat(n.String(), viper.GetString("kernel.dwarf.name")+".h", viper.GetBool("color") && !viper.GetBool("no-color")))
358+
}
344359
}
345-
fmt.Printf("%#x: %s", n.LowPC, utils.ClangFormat(n.String(), viper.GetString("kernel.dwarf.name")+".h", viper.GetBool("color") && !viper.GetBool("no-color")))
346360
}
347361

348362
if viper.GetBool("kernel.dwarf.all") {

internal/commands/dwarf/dwarf.go

+103-75
Original file line numberDiff line numberDiff line change
@@ -99,28 +99,32 @@ func GetAllEnums(path string) (map[string]*dwf.EnumType, error) {
9999
return enums, nil
100100
}
101101

102-
func GetName(path, name string) (ft *dwf.FuncType, filename string, err error) {
102+
func GetName(path, name string) (nameMap map[string]*dwf.FuncType, err error) {
103+
nameMap = make(map[string]*dwf.FuncType)
104+
103105
m, err := macho.Open(path)
104106
if err != nil {
105-
return nil, "", err
107+
return nil, err
106108
}
107109
defer m.Close()
108110

109111
df, err := m.DWARF()
110112
if err != nil {
111-
return nil, "", err
113+
return nil, err
112114
}
113115

114116
r := df.Reader()
115117

118+
var nameOffs []dwf.Offset
119+
116120
off, err := df.LookupName(name)
117121
if err != nil {
118122
if !errors.Is(err, dwf.ErrHashNotFound) {
119-
return nil, "", fmt.Errorf("failed to find name %s: %v", name, err)
123+
return nil, fmt.Errorf("failed to find name %s: %v", name, err)
120124
}
121125
offs, err := df.LookupDebugName(name)
122126
if err != nil {
123-
return nil, "", fmt.Errorf("failed to find debug name %s: %v", name, err)
127+
return nil, fmt.Errorf("failed to find debug name %s: %v", name, err)
124128
}
125129
if len(offs) > 1 {
126130
log.Warnf("found multiple debug names entries for %s", name)
@@ -129,125 +133,149 @@ func GetName(path, name string) (ft *dwf.FuncType, filename string, err error) {
129133
switch o.Tag {
130134
case dwf.TagStructType, dwf.TagEnumerationType, dwf.TagUnionType, dwf.TagTypedef, dwf.TagArrayType, dwf.TagPointerType:
131135
default:
132-
r.Seek(o.CUOffset)
133-
r.Next()
134-
off = o.DIEOffset
136+
nameOffs = append(nameOffs, o.DIEOffset)
135137
}
136138
}
139+
} else {
140+
nameOffs = append(nameOffs, off)
137141
}
138142

139-
r.Seek(off)
143+
for _, off := range nameOffs {
144+
filename := "<unknown>"
140145

141-
entry, err := r.Next()
142-
if err != nil {
143-
return nil, "", err
144-
}
146+
r.Seek(off)
145147

146-
fs, err := df.FilesForEntry(entry)
147-
if err != nil {
148-
return nil, "", fmt.Errorf("failed to get files for entry: %v", err)
149-
}
150-
if idx, ok := entry.Val(dwf.AttrDeclFile).(int64); ok {
151-
if idx < int64(len(fs)) {
152-
filename = fs[idx].Name
148+
entry, err := r.Next()
149+
if err != nil {
150+
return nil, err
153151
}
154-
}
155152

156-
if entry.Tag == dwf.TagSubprogram || entry.Tag == dwf.TagSubroutineType || entry.Tag == dwf.TagInlinedSubroutine {
157-
typ, err := df.Type(entry.Offset)
153+
fs, err := df.FilesForEntry(entry)
158154
if err != nil {
159-
return nil, "", err
155+
return nil, fmt.Errorf("failed to get files for entry: %v", err)
160156
}
161-
ft = typ.(*dwf.FuncType)
162-
} else {
163-
typ, err := df.Type(entry.Offset)
164-
if err != nil {
165-
return nil, "", err
157+
if idx, ok := entry.Val(dwf.AttrDeclFile).(int64); ok {
158+
if idx < int64(len(fs)) {
159+
filename = fs[idx].Name
160+
}
161+
}
162+
if idx, ok := entry.Val(dwf.AttrCallFile).(int64); ok {
163+
if idx < int64(len(fs)) {
164+
filename = fs[idx].Name
165+
}
166+
}
167+
if line, ok := entry.Val(dwf.AttrDeclLine).(int64); ok {
168+
filename += fmt.Sprintf("#L%d", line)
169+
}
170+
if line, ok := entry.Val(dwf.AttrCallLine).(int64); ok {
171+
filename += fmt.Sprintf("#L%d", line)
172+
}
173+
174+
if entry.Tag == dwf.TagSubprogram || entry.Tag == dwf.TagSubroutineType || entry.Tag == dwf.TagInlinedSubroutine {
175+
typ, err := df.Type(entry.Offset)
176+
if err != nil {
177+
return nil, err
178+
}
179+
nameMap[filename] = typ.(*dwf.FuncType)
180+
} else {
181+
typ, err := df.Type(entry.Offset)
182+
if err != nil {
183+
return nil, err
184+
}
185+
return nil, fmt.Errorf("did not find tag func type: found %s; %s", entry.Tag, typ.String())
166186
}
167-
return nil, "", fmt.Errorf("did not find tag func type: found %s; %s", entry.Tag, typ.String())
168187
}
169188

170-
return
189+
return nameMap, nil
171190
}
172191

173-
func GetType(path, name string, showOffsets bool) (typeStr string, filename string, err error) {
192+
func GetType(path, name string, showOffsets bool) (typeMap map[string]string, err error) {
193+
typeMap = make(map[string]string)
194+
174195
m, err := macho.Open(path)
175196
if err != nil {
176-
return "", "", err
197+
return nil, err
177198
}
178199
defer m.Close()
179200

180201
df, err := m.DWARF()
181202
if err != nil {
182-
return "", "", err
203+
return nil, err
183204
}
184205

185206
r := df.Reader()
186207

208+
var typoffs []dwf.Offset
209+
187210
off, err := df.LookupType(name)
188211
if err != nil {
189212
if !errors.Is(err, dwf.ErrHashNotFound) {
190-
return "", "", fmt.Errorf("failed to find name %s: %v", name, err)
213+
return nil, fmt.Errorf("failed to find name %s: %v", name, err)
191214
}
192215
offs, err := df.LookupDebugName(name)
193216
if err != nil {
194-
return "", "", fmt.Errorf("failed to find debug name %s: %v", name, err)
217+
return nil, fmt.Errorf("failed to find debug name %s: %v", name, err)
195218
}
196219
if len(offs) > 1 {
197220
log.Warnf("found multiple debug names entries for %s", name)
198221
}
199222
for _, o := range offs {
200223
switch o.Tag {
201224
case dwf.TagStructType, dwf.TagEnumerationType, dwf.TagUnionType, dwf.TagTypedef, dwf.TagArrayType, dwf.TagPointerType:
202-
r.Seek(o.CUOffset)
203-
r.Next()
204-
off = o.DIEOffset
225+
typoffs = append(typoffs, o.DIEOffset)
205226
}
206227
}
228+
} else {
229+
typoffs = append(typoffs, off)
207230
}
208231

209-
r.Seek(off)
232+
for _, off := range typoffs {
233+
filename := "<unknown>"
210234

211-
entry, err := r.Next()
212-
if err != nil {
213-
return "", "", err
214-
}
235+
r.Seek(off)
215236

216-
fs, err := df.FilesForEntry(entry)
217-
if err != nil {
218-
return "", "", fmt.Errorf("failed to get files for entry: %v", err)
219-
}
220-
if idx, ok := entry.Val(dwf.AttrDeclFile).(int64); ok {
221-
if idx < int64(len(fs)) {
222-
filename = fs[idx].Name
237+
entry, err := r.Next()
238+
if err != nil {
239+
return nil, err
223240
}
224-
}
225241

226-
typ, err := df.Type(entry.Offset)
227-
if err != nil {
228-
return "", "", fmt.Errorf("failed to get type for entry: %v", err)
229-
}
242+
fs, err := df.FilesForEntry(entry)
243+
if err != nil {
244+
return nil, fmt.Errorf("failed to get files for entry: %v", err)
245+
}
246+
if idx, ok := entry.Val(dwf.AttrDeclFile).(int64); ok {
247+
if idx < int64(len(fs)) {
248+
filename = fs[idx].Name
249+
}
250+
}
251+
if line, ok := entry.Val(dwf.AttrDeclLine).(int64); ok {
252+
filename += fmt.Sprintf("#L%d", line)
253+
}
254+
255+
typ, err := df.Type(entry.Offset)
256+
if err != nil {
257+
return nil, fmt.Errorf("failed to get type for entry: %v", err)
258+
}
230259

231-
switch t := typ.(type) {
232-
case *dwf.StructType:
233-
if t.Incomplete {
234-
return "", "", fmt.Errorf("type %s is incomplete", name)
235-
}
236-
return t.Defn(showOffsets), filename, nil
237-
case *dwf.ArrayType:
238-
return t.String(), filename, nil
239-
case *dwf.PtrType:
240-
return t.String(), filename, nil
241-
case *dwf.EnumType:
242-
return t.String(), filename, nil
243-
case *dwf.TypedefType:
244-
if enum, ok := t.Type.(*dwf.EnumType); ok {
245-
return fmt.Sprintf("typedef %s %s;", enum.String(), t.Name), filename, nil
246-
}
247-
return fmt.Sprintf("typedef %s %s;", t.Type.Common().Name, t.Name), filename, nil
248-
default:
249-
return "", "", fmt.Errorf("did not find supported type: found %s; %s", entry.Tag, typ.String())
260+
switch t := typ.(type) {
261+
case *dwf.StructType:
262+
if t.Incomplete {
263+
continue
264+
}
265+
typeMap[filename] = t.Defn(showOffsets)
266+
case *dwf.ArrayType, *dwf.PtrType, *dwf.EnumType:
267+
typeMap[filename] = t.String()
268+
case *dwf.TypedefType:
269+
if enum, ok := t.Type.(*dwf.EnumType); ok {
270+
typeMap[filename] = fmt.Sprintf("typedef %s %s;", enum.String(), t.Name)
271+
}
272+
typeMap[filename] = fmt.Sprintf("typedef %s %s;", t.Type.Common().Name, t.Name)
273+
default:
274+
return nil, fmt.Errorf("did not find supported type: found %s; %s", entry.Tag, typ.String())
275+
}
250276
}
277+
278+
return typeMap, nil
251279
}
252280

253281
func DiffStructures(prevMachO, currMachO string, conf *Config) (string, error) {

0 commit comments

Comments
 (0)