7 #define min(a,b) (((a) < (b)) ? (a) : (b))
10 SUFFIX (grub_macho_contains_macho
) (grub_macho_t macho
)
12 return macho
->offsetXX
!= -1;
16 SUFFIX (grub_macho_parse
) (grub_macho_t macho
, const char *filename
)
19 struct grub_macho_lzss_header lzss
;
20 grub_macho_header_t macho
;
23 /* Is there any candidate at all? */
24 if (macho
->offsetXX
== -1)
27 /* Read header and check magic. */
28 if (grub_file_seek (macho
->file
, macho
->offsetXX
) == (grub_off_t
) -1
29 || grub_file_read (macho
->file
, &head
, sizeof (head
))
33 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
38 if (grub_memcmp (head
.lzss
.magic
, GRUB_MACHO_LZSS_MAGIC
,
39 sizeof (head
.lzss
.magic
)) == 0)
41 macho
->compressed_sizeXX
= grub_be_to_cpu32 (head
.lzss
.compressed_size
);
42 macho
->uncompressed_sizeXX
43 = grub_be_to_cpu32 (head
.lzss
.uncompressed_size
);
44 if (macho
->uncompressed_sizeXX
< sizeof (head
.macho
))
46 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
51 /* Skip header check. */
52 macho
->compressedXX
= 1;
56 if (head
.macho
.magic
!= GRUB_MACHO_MAGIC
)
58 grub_error (GRUB_ERR_BAD_OS
, "invalid Mach-O header");
64 macho
->ncmdsXX
= head
.macho
.ncmds
;
65 macho
->cmdsizeXX
= head
.macho
.sizeofcmds
;
66 macho
->cmdsXX
= grub_malloc (macho
->cmdsizeXX
);
69 if (grub_file_seek (macho
->file
, macho
->offsetXX
70 + sizeof (grub_macho_header_t
)) == (grub_off_t
) -1
71 || grub_file_read (macho
->file
, macho
->cmdsXX
,
72 (grub_size_t
) macho
->cmdsizeXX
)
73 != (grub_ssize_t
) macho
->cmdsizeXX
)
76 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
82 typedef int (*grub_macho_iter_hook_t
)
83 (grub_macho_t
, struct grub_macho_cmd
*,
87 grub_macho_cmds_iterate (grub_macho_t macho
,
88 grub_macho_iter_hook_t hook
,
95 if (macho
->compressedXX
&& !macho
->uncompressedXX
)
98 grub_macho_header_t
*head
;
99 macho
->uncompressedXX
= grub_malloc (macho
->uncompressed_sizeXX
);
100 if (!macho
->uncompressedXX
)
102 tmp
= grub_malloc (macho
->compressed_sizeXX
);
105 grub_free (macho
->uncompressedXX
);
106 macho
->uncompressedXX
= 0;
109 if (grub_file_seek (macho
->file
, macho
->offsetXX
110 + GRUB_MACHO_LZSS_OFFSET
) == (grub_off_t
) -1
111 || grub_file_read (macho
->file
, tmp
,
112 (grub_size_t
) macho
->compressed_sizeXX
)
113 != (grub_ssize_t
) macho
->compressed_sizeXX
)
116 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
119 grub_free (macho
->uncompressedXX
);
120 macho
->uncompressedXX
= 0;
121 macho
->offsetXX
= -1;
124 if (grub_decompress_lzss (macho
->uncompressedXX
,
125 macho
->uncompressedXX
126 + macho
->uncompressed_sizeXX
,
127 tmp
, tmp
+ macho
->compressed_sizeXX
)
128 != macho
->uncompressed_sizeXX
)
131 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
134 grub_free (macho
->uncompressedXX
);
135 macho
->uncompressedXX
= 0;
136 macho
->offsetXX
= -1;
140 head
= (grub_macho_header_t
*) macho
->uncompressedXX
;
141 macho
->ncmdsXX
= head
->ncmds
;
142 macho
->cmdsizeXX
= head
->sizeofcmds
;
143 macho
->cmdsXX
= macho
->uncompressedXX
+ sizeof (grub_macho_header_t
);
144 if (sizeof (grub_macho_header_t
) + macho
->cmdsizeXX
145 >= macho
->uncompressed_sizeXX
)
147 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
149 grub_free (macho
->uncompressedXX
);
150 macho
->uncompressedXX
= 0;
151 macho
->offsetXX
= -1;
157 return grub_error (GRUB_ERR_BAD_OS
, "couldn't find Mach-O commands");
158 hdrs
= macho
->cmdsXX
;
159 for (i
= 0; i
< macho
->ncmdsXX
; i
++)
161 struct grub_macho_cmd
*hdr
= (struct grub_macho_cmd
*) hdrs
;
162 if (hook (macho
, hdr
, hook_arg
))
164 hdrs
+= hdr
->cmdsize
;
171 SUFFIX (grub_macho_filesize
) (grub_macho_t macho
)
173 if (SUFFIX (grub_macho_contains_macho
) (macho
))
174 return macho
->endXX
- macho
->offsetXX
;
179 SUFFIX (grub_macho_readfile
) (grub_macho_t macho
,
180 const char *filename
,
184 if (! SUFFIX (grub_macho_contains_macho
) (macho
))
185 return grub_error (GRUB_ERR_BAD_OS
,
186 "couldn't read architecture-specific part");
188 if (grub_file_seek (macho
->file
, macho
->offsetXX
) == (grub_off_t
) -1)
191 read
= grub_file_read (macho
->file
, dest
,
192 macho
->endXX
- macho
->offsetXX
);
193 if (read
!= (grub_ssize_t
) (macho
->endXX
- macho
->offsetXX
))
196 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
200 return GRUB_ERR_NONE
;
207 grub_macho_addr_t
*segments_start
;
208 grub_macho_addr_t
*segments_end
;
211 /* Run through the program headers to calculate the total memory size we
214 calcsize (grub_macho_t _macho
__attribute__ ((unused
)),
215 struct grub_macho_cmd
*hdr0
,
218 grub_macho_segment_t
*hdr
= (grub_macho_segment_t
*) hdr0
;
219 struct calcsize_ctx
*ctx
= _arg
;
220 if (hdr
->cmd
!= GRUB_MACHO_CMD_SEGMENT
)
226 if (! hdr
->filesize
&& (ctx
->flags
& GRUB_MACHO_NOBSS
))
230 if (hdr
->vmaddr
< *ctx
->segments_start
)
231 *ctx
->segments_start
= hdr
->vmaddr
;
232 if (hdr
->vmaddr
+ hdr
->vmsize
> *ctx
->segments_end
)
233 *ctx
->segments_end
= hdr
->vmaddr
+ hdr
->vmsize
;
237 /* Calculate the amount of memory spanned by the segments. */
239 SUFFIX (grub_macho_size
) (grub_macho_t macho
, grub_macho_addr_t
*segments_start
,
240 grub_macho_addr_t
*segments_end
, int flags
,
241 const char *filename
)
243 struct calcsize_ctx ctx
= {
246 .segments_start
= segments_start
,
247 .segments_end
= segments_end
,
250 *segments_start
= (grub_macho_addr_t
) -1;
253 grub_macho_cmds_iterate (macho
, calcsize
, &ctx
, filename
);
255 if (ctx
.nr_phdrs
== 0)
256 return grub_error (GRUB_ERR_BAD_OS
, "no program headers present");
258 if (*segments_end
< *segments_start
)
259 /* Very bad addresses. */
260 return grub_error (GRUB_ERR_BAD_OS
, "bad program header load addresses");
262 return GRUB_ERR_NONE
;
269 const char *filename
;
274 do_load(grub_macho_t _macho
,
275 struct grub_macho_cmd
*hdr0
,
278 grub_macho_segment_t
*hdr
= (grub_macho_segment_t
*) hdr0
;
279 struct do_load_ctx
*ctx
= _arg
;
281 if (hdr
->cmd
!= GRUB_MACHO_CMD_SEGMENT
)
284 if (! hdr
->filesize
&& (ctx
->flags
& GRUB_MACHO_NOBSS
))
291 grub_ssize_t read
, toread
= min (hdr
->filesize
, hdr
->vmsize
);
292 if (_macho
->uncompressedXX
)
294 if (hdr
->fileoff
+ (grub_size_t
) toread
295 > _macho
->uncompressed_sizeXX
)
300 grub_memcpy (ctx
->offset
+ hdr
->vmaddr
,
301 _macho
->uncompressedXX
+ hdr
->fileoff
, read
);
306 if (grub_file_seek (_macho
->file
, hdr
->fileoff
307 + _macho
->offsetXX
) == (grub_off_t
) -1)
309 read
= grub_file_read (_macho
->file
, ctx
->offset
+ hdr
->vmaddr
,
315 /* XXX How can we free memory from `load_hook'? */
317 grub_error (GRUB_ERR_BAD_OS
, N_("premature end of file %s"),
322 if (ctx
->darwin_version
)
324 const char *ptr
= ctx
->offset
+ hdr
->vmaddr
;
325 const char *end
= ptr
+ min (hdr
->filesize
, hdr
->vmsize
)
326 - (sizeof ("Darwin Kernel Version ") - 1);
327 for (; ptr
< end
; ptr
++)
328 if (grub_memcmp (ptr
, "Darwin Kernel Version ",
329 sizeof ("Darwin Kernel Version ") - 1) == 0)
331 ptr
+= sizeof ("Darwin Kernel Version ") - 1;
332 *ctx
->darwin_version
= 0;
333 end
+= (sizeof ("Darwin Kernel Version ") - 1);
334 while (ptr
< end
&& grub_isdigit (*ptr
))
335 *ctx
->darwin_version
= (*ptr
++ - '0') + *ctx
->darwin_version
* 10;
341 if (hdr
->filesize
< hdr
->vmsize
)
342 grub_memset (ctx
->offset
+ hdr
->vmaddr
+ hdr
->filesize
,
343 0, hdr
->vmsize
- hdr
->filesize
);
347 /* Load every loadable segment into memory specified by `_load_hook'. */
349 SUFFIX (grub_macho_load
) (grub_macho_t macho
, const char *filename
,
350 char *offset
, int flags
, int *darwin_version
)
352 struct do_load_ctx ctx
= {
355 .filename
= filename
,
356 .darwin_version
= darwin_version
362 grub_macho_cmds_iterate (macho
, do_load
, &ctx
, filename
);
368 find_entry_point (grub_macho_t _macho
__attribute__ ((unused
)),
369 struct grub_macho_cmd
*hdr
,
372 grub_macho_addr_t
*entry_point
= _arg
;
373 if (hdr
->cmd
== GRUB_MACHO_CMD_THREAD
)
374 *entry_point
= ((grub_macho_thread_t
*) hdr
)->entry_point
;
379 SUFFIX (grub_macho_get_entry_point
) (grub_macho_t macho
, const char *filename
)
381 grub_macho_addr_t entry_point
= 0;
382 grub_macho_cmds_iterate (macho
, find_entry_point
, &entry_point
, filename
);