30
30
#include <grub/misc.h>
31
31
#include <grub/mm.h>
33
#define min(a,b) (((a) < (b)) ? (a) : (b))
38
grub_macho_contains_macho32 (grub_macho_t macho)
40
return macho->offset32 != -1;
44
grub_macho_parse32 (grub_macho_t macho)
46
struct grub_macho_header32 head;
48
/* Is there any candidate at all? */
49
if (macho->offset32 == -1)
52
/* Read header and check magic*/
53
if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1
54
|| grub_file_read (macho->file, &head, sizeof (head))
57
grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
61
if (head.magic != GRUB_MACHO_MAGIC32)
63
grub_error (GRUB_ERR_BAD_OS, "Invalid Mach-O 32-bit header.");
69
macho->ncmds32 = head.ncmds;
70
macho->cmdsize32 = head.sizeofcmds;
71
macho->cmds32 = grub_malloc(macho->cmdsize32);
74
grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
77
if (grub_file_read (macho->file, macho->cmds32,
78
(grub_size_t) macho->cmdsize32)
79
!= (grub_ssize_t) macho->cmdsize32)
81
grub_error (GRUB_ERR_READ_ERROR, "Cannot read Mach-O header.");
86
typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
87
(grub_macho_t , struct grub_macho_cmd *,
91
grub_macho32_cmds_iterate (grub_macho_t macho,
92
grub_macho_iter_hook_t hook,
95
grub_uint8_t *hdrs = macho->cmds32;
98
return grub_error (GRUB_ERR_BAD_OS, "Couldn't find 32-bit Mach-O");
99
for (i = 0; i < macho->ncmds32; i++)
101
struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
102
if (hook (macho, hdr, hook_arg))
104
hdrs += hdr->cmdsize;
111
grub_macho32_filesize (grub_macho_t macho)
113
if (grub_macho_contains_macho32 (macho))
114
return macho->end32 - macho->offset32;
119
grub_macho32_readfile (grub_macho_t macho, void *dest)
122
if (! grub_macho_contains_macho32 (macho))
123
return grub_error (GRUB_ERR_BAD_OS,
124
"Couldn't read architecture-specific part");
126
if (grub_file_seek (macho->file, macho->offset32) == (grub_off_t) -1)
129
return grub_error (GRUB_ERR_BAD_OS,
130
"Invalid offset in program header.");
133
read = grub_file_read (macho->file, dest,
134
macho->end32 - macho->offset32);
135
if (read != (grub_ssize_t) (macho->end32 - macho->offset32))
138
return grub_error (GRUB_ERR_BAD_OS,
139
"Couldn't read architecture-specific part");
141
return GRUB_ERR_NONE;
144
/* Calculate the amount of memory spanned by the segments. */
146
grub_macho32_size (grub_macho_t macho, grub_addr_t *segments_start,
147
grub_addr_t *segments_end, int flags)
151
/* Run through the program headers to calculate the total memory size we
153
auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
154
struct grub_macho_cmd *phdr, void *_arg);
155
int NESTED_FUNC_ATTR calcsize (grub_macho_t UNUSED _macho,
156
struct grub_macho_cmd *hdr0, void UNUSED *_arg)
158
struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
159
if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
161
if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
165
if (hdr->vmaddr < *segments_start)
166
*segments_start = hdr->vmaddr;
167
if (hdr->vmaddr + hdr->vmsize > *segments_end)
168
*segments_end = hdr->vmaddr + hdr->vmsize;
172
*segments_start = (grub_uint32_t) -1;
175
grub_macho32_cmds_iterate (macho, calcsize, 0);
178
return grub_error (GRUB_ERR_BAD_OS, "No program headers present");
180
if (*segments_end < *segments_start)
181
/* Very bad addresses. */
182
return grub_error (GRUB_ERR_BAD_OS, "Bad program header load addresses");
184
return GRUB_ERR_NONE;
187
/* Load every loadable segment into memory specified by `_load_hook'. */
189
grub_macho32_load (grub_macho_t macho, char *offset, int flags)
192
auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
193
struct grub_macho_cmd *hdr0,
195
int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
196
struct grub_macho_cmd *hdr0,
199
struct grub_macho_segment32 *hdr = (struct grub_macho_segment32 *) hdr0;
201
if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT32)
204
if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
209
if (grub_file_seek (_macho->file, hdr->fileoff
210
+ _macho->offset32) == (grub_off_t) -1)
213
grub_error (GRUB_ERR_BAD_OS,
214
"Invalid offset in program header.");
221
read = grub_file_read (_macho->file, offset + hdr->vmaddr,
222
min (hdr->filesize, hdr->vmsize));
223
if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
225
/* XXX How can we free memory from `load_hook'? */
227
err=grub_error (GRUB_ERR_BAD_OS,
228
"Couldn't read segment from file: "
229
"wanted 0x%lx bytes; read 0x%lx bytes.",
230
hdr->filesize, read);
235
if (hdr->filesize < hdr->vmsize)
236
grub_memset (offset + hdr->vmaddr + hdr->filesize,
237
0, hdr->vmsize - hdr->filesize);
241
grub_macho32_cmds_iterate (macho, do_load, 0);
247
grub_macho32_get_entry_point (grub_macho_t macho)
249
grub_uint32_t entry_point = 0;
250
auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
251
struct grub_macho_cmd *hdr,
253
int NESTED_FUNC_ATTR hook(grub_macho_t UNUSED _macho,
254
struct grub_macho_cmd *hdr,
257
if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
258
entry_point = ((struct grub_macho_thread32 *) hdr)->entry_point;
261
grub_macho32_cmds_iterate (macho, hook, 0);
267
34
grub_macho_close (grub_macho_t macho)