@@ -85,126 +85,140 @@ func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
85
85
}
86
86
87
87
// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
88
+ // machoCombineDwarf returns true and skips merging if the input executable is for iOS.
89
+ //
88
90
// With internal linking, DWARF is embedded into the executable, this lets us do the
89
91
// same for external linking.
90
92
// inexe is the path to the executable with no DWARF. It must have enough room in the macho
91
93
// header to add the DWARF sections. (Use ld's -headerpad option)
92
94
// dsym is the path to the macho file containing DWARF from dsymutil.
93
95
// outexe is the path where the combined executable should be saved.
94
- func machoCombineDwarf (inexe , dsym , outexe string , buildmode BuildMode ) error {
96
+ func machoCombineDwarf (inexe , dsym , outexe string , buildmode BuildMode ) ( bool , error ) {
95
97
exef , err := os .Open (inexe )
96
98
if err != nil {
97
- return err
99
+ return false , err
100
+ }
101
+ exem , err := macho .NewFile (exef )
102
+ if err != nil {
103
+ return false , err
104
+ }
105
+ cmdOffset := unsafe .Sizeof (exem .FileHeader )
106
+ is64bit := exem .Magic == macho .Magic64
107
+ if is64bit {
108
+ // mach_header_64 has one extra uint32.
109
+ cmdOffset += unsafe .Sizeof (exem .Magic )
110
+ }
111
+ // Check for LC_VERSION_MIN_IPHONEOS.
112
+ reader := loadCmdReader {next : int64 (cmdOffset ), f : exef , order : exem .ByteOrder }
113
+ for i := uint32 (0 ); i < exem .Ncmd ; i ++ {
114
+ cmd , err := reader .Next ()
115
+ if err != nil {
116
+ return false , err
117
+ }
118
+ if cmd .Cmd == LC_VERSION_MIN_IPHONEOS {
119
+ // The executable is for iOS, which doesn't support unmapped
120
+ // segments such as our __DWARF segment. Skip combining.
121
+ return true , nil
122
+ }
98
123
}
99
124
dwarff , err := os .Open (dsym )
100
125
if err != nil {
101
- return err
126
+ return false , err
102
127
}
103
128
outf , err := os .Create (outexe )
104
129
if err != nil {
105
- return err
130
+ return false , err
106
131
}
107
132
outf .Chmod (0755 )
108
133
109
- exem , err := macho .NewFile (exef )
110
- if err != nil {
111
- return err
112
- }
113
134
dwarfm , err := macho .NewFile (dwarff )
114
135
if err != nil {
115
- return err
136
+ return false , err
116
137
}
117
138
118
139
// The string table needs to be the last thing in the file
119
140
// for code signing to work. So we'll need to move the
120
141
// linkedit section, but all the others can be copied directly.
121
142
linkseg = exem .Segment ("__LINKEDIT" )
122
143
if linkseg == nil {
123
- return fmt .Errorf ("missing __LINKEDIT segment" )
144
+ return false , fmt .Errorf ("missing __LINKEDIT segment" )
124
145
}
125
146
126
147
if _ , err = exef .Seek (0 , 0 ); err != nil {
127
- return err
148
+ return false , err
128
149
}
129
150
if _ , err := io .CopyN (outf , exef , int64 (linkseg .Offset )); err != nil {
130
- return err
151
+ return false , err
131
152
}
132
153
133
154
realdwarf = dwarfm .Segment ("__DWARF" )
134
155
if realdwarf == nil {
135
- return fmt .Errorf ("missing __DWARF segment" )
156
+ return false , fmt .Errorf ("missing __DWARF segment" )
136
157
}
137
158
138
159
// Now copy the dwarf data into the output.
139
160
// Kernel requires all loaded segments to be page-aligned in the file,
140
161
// even though we mark this one as being 0 bytes of virtual address space.
141
162
dwarfstart = machoCalcStart (realdwarf .Offset , linkseg .Offset , pageAlign )
142
163
if _ , err = outf .Seek (dwarfstart , 0 ); err != nil {
143
- return err
164
+ return false , err
144
165
}
145
166
dwarfaddr = int64 ((linkseg .Addr + linkseg .Memsz + 1 << pageAlign - 1 ) &^ (1 << pageAlign - 1 ))
146
167
147
168
if _ , err = dwarff .Seek (int64 (realdwarf .Offset ), 0 ); err != nil {
148
- return err
169
+ return false , err
149
170
}
150
171
if _ , err := io .CopyN (outf , dwarff , int64 (realdwarf .Filesz )); err != nil {
151
- return err
172
+ return false , err
152
173
}
153
174
154
175
// And finally the linkedit section.
155
176
if _ , err = exef .Seek (int64 (linkseg .Offset ), 0 ); err != nil {
156
- return err
177
+ return false , err
157
178
}
158
179
linkstart = machoCalcStart (linkseg .Offset , uint64 (dwarfstart )+ realdwarf .Filesz , pageAlign )
159
180
linkoffset = uint32 (linkstart - int64 (linkseg .Offset ))
160
181
if _ , err = outf .Seek (linkstart , 0 ); err != nil {
161
- return err
182
+ return false , err
162
183
}
163
184
if _ , err := io .Copy (outf , exef ); err != nil {
164
- return err
185
+ return false , err
165
186
}
166
187
167
188
// Now we need to update the headers.
168
- cmdOffset := unsafe .Sizeof (exem .FileHeader )
169
- is64bit := exem .Magic == macho .Magic64
170
- if is64bit {
171
- // mach_header_64 has one extra uint32.
172
- cmdOffset += unsafe .Sizeof (exem .Magic )
173
- }
174
-
175
189
textsect := exem .Section ("__text" )
176
190
if linkseg == nil {
177
- return fmt .Errorf ("missing __text section" )
191
+ return false , fmt .Errorf ("missing __text section" )
178
192
}
179
193
180
194
dwarfCmdOffset := int64 (cmdOffset ) + int64 (exem .FileHeader .Cmdsz )
181
195
availablePadding := int64 (textsect .Offset ) - dwarfCmdOffset
182
196
if availablePadding < int64 (realdwarf .Len ) {
183
- return fmt .Errorf ("No room to add dwarf info. Need at least %d padding bytes, found %d" , realdwarf .Len , availablePadding )
197
+ return false , fmt .Errorf ("No room to add dwarf info. Need at least %d padding bytes, found %d" , realdwarf .Len , availablePadding )
184
198
}
185
199
// First, copy the dwarf load command into the header
186
200
if _ , err = outf .Seek (dwarfCmdOffset , 0 ); err != nil {
187
- return err
201
+ return false , err
188
202
}
189
203
if _ , err := io .CopyN (outf , bytes .NewReader (realdwarf .Raw ()), int64 (realdwarf .Len )); err != nil {
190
- return err
204
+ return false , err
191
205
}
192
206
193
207
if _ , err = outf .Seek (int64 (unsafe .Offsetof (exem .FileHeader .Ncmd )), 0 ); err != nil {
194
- return err
208
+ return false , err
195
209
}
196
210
if err = binary .Write (outf , exem .ByteOrder , exem .Ncmd + 1 ); err != nil {
197
- return err
211
+ return false , err
198
212
}
199
213
if err = binary .Write (outf , exem .ByteOrder , exem .Cmdsz + realdwarf .Len ); err != nil {
200
- return err
214
+ return false , err
201
215
}
202
216
203
- reader : = loadCmdReader {next : int64 (cmdOffset ), f : outf , order : exem .ByteOrder }
217
+ reader = loadCmdReader {next : int64 (cmdOffset ), f : outf , order : exem .ByteOrder }
204
218
for i := uint32 (0 ); i < exem .Ncmd ; i ++ {
205
219
cmd , err := reader .Next ()
206
220
if err != nil {
207
- return err
221
+ return false , err
208
222
}
209
223
switch cmd .Cmd {
210
224
case macho .LoadCmdSegment64 :
@@ -227,10 +241,10 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) error {
227
241
err = fmt .Errorf ("Unknown load command 0x%x (%s)\n " , int (cmd .Cmd ), cmd .Cmd )
228
242
}
229
243
if err != nil {
230
- return err
244
+ return false , err
231
245
}
232
246
}
233
- return machoUpdateDwarfHeader (& reader , buildmode )
247
+ return false , machoUpdateDwarfHeader (& reader , buildmode )
234
248
}
235
249
236
250
// machoUpdateSegment updates the load command for a moved segment.
0 commit comments