~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to grub-core/loader/machoXX.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-02-08 11:39:26 UTC
  • mfrom: (17.6.26 experimental)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 104.
  • Revision ID: james.westby@ubuntu.com-20110208113926-clfs90haboyk9zip
Tags: 1.99~rc1-2
* Merge 1.98+20100804-13 and 1.98+20100804-14, updating translations:
  - Kazakh (Baurzhan Muftakhidinov / Timur Birsh).
* mkconfig_skip_dmcrypt.patch: Refer to GRUB_PRELOAD_MODULES rather than
  suggesting people write a /etc/grub.d/01_modules script (thanks, Jordan
  Uggla).
* Handle empty dir passed to grub_find_root_device_from_mountinfo; fixes
  grub-mkrelpath on btrfs subvolumes (LP: #712029).
* Add rootflags=subvol=<name> if / is on a btrfs subvolume (LP: #712029).
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
#include <grub/file.h>
 
3
#include <grub/mm.h>
 
4
#include <grub/misc.h>
 
5
 
 
6
#define min(a,b) (((a) < (b)) ? (a) : (b))
 
7
 
 
8
int
 
9
SUFFIX (grub_macho_contains_macho) (grub_macho_t macho)
 
10
{
 
11
  return macho->offsetXX != -1;
 
12
}
 
13
 
 
14
void
 
15
SUFFIX (grub_macho_parse) (grub_macho_t macho)
 
16
{
 
17
  grub_macho_header_t head;
 
18
 
 
19
  /* Is there any candidate at all? */
 
20
  if (macho->offsetXX == -1)
 
21
    return;
 
22
 
 
23
  /* Read header and check magic*/
 
24
  if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1
 
25
      || grub_file_read (macho->file, &head, sizeof (head))
 
26
      != sizeof(head))
 
27
    {
 
28
      grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
 
29
      macho->offsetXX = -1;
 
30
      return;
 
31
    }
 
32
  if (head.magic != GRUB_MACHO_MAGIC)
 
33
    {
 
34
      grub_error (GRUB_ERR_BAD_OS, "invalid Mach-O " XX "-bit header");
 
35
      macho->offsetXX = -1;
 
36
      return;
 
37
    }
 
38
 
 
39
  /* Read commands. */
 
40
  macho->ncmdsXX = head.ncmds;
 
41
  macho->cmdsizeXX = head.sizeofcmds;
 
42
  macho->cmdsXX = grub_malloc(macho->cmdsizeXX);
 
43
  if (! macho->cmdsXX)
 
44
    {
 
45
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "not enough memory to read commands");
 
46
      return;
 
47
    }
 
48
  if (grub_file_read (macho->file, macho->cmdsXX,
 
49
                      (grub_size_t) macho->cmdsizeXX)
 
50
      != (grub_ssize_t) macho->cmdsizeXX)
 
51
    {
 
52
      grub_error (GRUB_ERR_READ_ERROR, "cannot read Mach-O header");
 
53
      macho->offsetXX = -1;
 
54
    }
 
55
}
 
56
 
 
57
typedef int NESTED_FUNC_ATTR (*grub_macho_iter_hook_t)
 
58
(grub_macho_t , struct grub_macho_cmd *,
 
59
               void *);
 
60
 
 
61
static grub_err_t
 
62
grub_macho_cmds_iterate (grub_macho_t macho,
 
63
                         grub_macho_iter_hook_t hook,
 
64
                         void *hook_arg)
 
65
{
 
66
  grub_uint8_t *hdrs = macho->cmdsXX;
 
67
  int i;
 
68
  if (! macho->cmdsXX)
 
69
    return grub_error (GRUB_ERR_BAD_OS, "couldn't find " XX "-bit Mach-O");
 
70
  for (i = 0; i < macho->ncmdsXX; i++)
 
71
    {
 
72
      struct grub_macho_cmd *hdr = (struct grub_macho_cmd *) hdrs;
 
73
      if (hook (macho, hdr, hook_arg))
 
74
        break;
 
75
      hdrs += hdr->cmdsize;
 
76
    }
 
77
 
 
78
  return grub_errno;
 
79
}
 
80
 
 
81
grub_size_t
 
82
SUFFIX (grub_macho_filesize) (grub_macho_t macho)
 
83
{
 
84
  if (SUFFIX (grub_macho_contains_macho) (macho))
 
85
    return macho->endXX - macho->offsetXX;
 
86
  return 0;
 
87
}
 
88
 
 
89
grub_err_t
 
90
SUFFIX (grub_macho_readfile) (grub_macho_t macho, void *dest)
 
91
{
 
92
  grub_ssize_t read;
 
93
  if (! SUFFIX (grub_macho_contains_macho) (macho))
 
94
    return grub_error (GRUB_ERR_BAD_OS,
 
95
                       "couldn't read architecture-specific part");
 
96
 
 
97
  if (grub_file_seek (macho->file, macho->offsetXX) == (grub_off_t) -1)
 
98
    {
 
99
      grub_error_push ();
 
100
      return grub_error (GRUB_ERR_BAD_OS,
 
101
                         "invalid offset in program header");
 
102
    }
 
103
 
 
104
  read = grub_file_read (macho->file, dest,
 
105
                         macho->endXX - macho->offsetXX);
 
106
  if (read != (grub_ssize_t) (macho->endXX - macho->offsetXX))
 
107
    {
 
108
      grub_error_push ();
 
109
      return grub_error (GRUB_ERR_BAD_OS,
 
110
                         "couldn't read architecture-specific part");
 
111
    }
 
112
  return GRUB_ERR_NONE;
 
113
}
 
114
 
 
115
/* Calculate the amount of memory spanned by the segments. */
 
116
grub_err_t
 
117
SUFFIX (grub_macho_size) (grub_macho_t macho, grub_macho_addr_t *segments_start,
 
118
                          grub_macho_addr_t *segments_end, int flags)
 
119
{
 
120
  int nr_phdrs = 0;
 
121
 
 
122
  /* Run through the program headers to calculate the total memory size we
 
123
     should claim.  */
 
124
  auto int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho,
 
125
                                      struct grub_macho_cmd *phdr, void *_arg);
 
126
  int NESTED_FUNC_ATTR calcsize (grub_macho_t _macho __attribute__ ((unused)),
 
127
                                 struct grub_macho_cmd *hdr0,
 
128
                                 void *_arg __attribute__ ((unused)))
 
129
    {
 
130
      grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
 
131
      if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
 
132
        return 0;
 
133
 
 
134
      if (! hdr->vmsize)
 
135
        return 0;
 
136
 
 
137
      if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
 
138
        return 0;
 
139
 
 
140
      nr_phdrs++;
 
141
      if (hdr->vmaddr < *segments_start)
 
142
        *segments_start = hdr->vmaddr;
 
143
      if (hdr->vmaddr + hdr->vmsize > *segments_end)
 
144
        *segments_end = hdr->vmaddr + hdr->vmsize;
 
145
      return 0;
 
146
    }
 
147
 
 
148
  *segments_start = (grub_macho_addr_t) -1;
 
149
  *segments_end = 0;
 
150
 
 
151
  grub_macho_cmds_iterate (macho, calcsize, 0);
 
152
 
 
153
  if (nr_phdrs == 0)
 
154
    return grub_error (GRUB_ERR_BAD_OS, "no program headers present");
 
155
 
 
156
  if (*segments_end < *segments_start)
 
157
    /* Very bad addresses.  */
 
158
    return grub_error (GRUB_ERR_BAD_OS, "bad program header load addresses");
 
159
 
 
160
  return GRUB_ERR_NONE;
 
161
}
 
162
 
 
163
/* Load every loadable segment into memory specified by `_load_hook'.  */
 
164
grub_err_t
 
165
SUFFIX (grub_macho_load) (grub_macho_t macho, char *offset, int flags)
 
166
{
 
167
  grub_err_t err = 0;
 
168
  auto int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
 
169
                               struct grub_macho_cmd *hdr0,
 
170
                               void *_arg __attribute__ ((unused)));
 
171
  int NESTED_FUNC_ATTR do_load(grub_macho_t _macho,
 
172
                               struct grub_macho_cmd *hdr0,
 
173
                               void *_arg __attribute__ ((unused)))
 
174
  {
 
175
    grub_macho_segment_t *hdr = (grub_macho_segment_t *) hdr0;
 
176
 
 
177
    if (hdr->cmd != GRUB_MACHO_CMD_SEGMENT)
 
178
      return 0;
 
179
 
 
180
    if (! hdr->filesize && (flags & GRUB_MACHO_NOBSS))
 
181
      return 0;
 
182
    if (! hdr->vmsize)
 
183
      return 0;
 
184
 
 
185
    if (grub_file_seek (_macho->file, hdr->fileoff
 
186
                        + _macho->offsetXX) == (grub_off_t) -1)
 
187
      {
 
188
        grub_error_push ();
 
189
        grub_error (GRUB_ERR_BAD_OS,
 
190
                    "invalid offset in program header");
 
191
        return 1;
 
192
      }
 
193
 
 
194
    if (hdr->filesize)
 
195
      {
 
196
        grub_ssize_t read;
 
197
        read = grub_file_read (_macho->file, offset + hdr->vmaddr,
 
198
                                   min (hdr->filesize, hdr->vmsize));
 
199
        if (read != (grub_ssize_t) min (hdr->filesize, hdr->vmsize))
 
200
          {
 
201
            /* XXX How can we free memory from `load_hook'? */
 
202
            grub_error_push ();
 
203
            err=grub_error (GRUB_ERR_BAD_OS,
 
204
                            "couldn't read segment from file: "
 
205
                            "wanted 0x%lx bytes; read 0x%lx bytes",
 
206
                            hdr->filesize, read);
 
207
            return 1;
 
208
          }
 
209
      }
 
210
 
 
211
    if (hdr->filesize < hdr->vmsize)
 
212
      grub_memset (offset + hdr->vmaddr + hdr->filesize,
 
213
                   0, hdr->vmsize - hdr->filesize);
 
214
    return 0;
 
215
  }
 
216
 
 
217
  grub_macho_cmds_iterate (macho, do_load, 0);
 
218
 
 
219
  return err;
 
220
}
 
221
 
 
222
grub_macho_addr_t
 
223
SUFFIX (grub_macho_get_entry_point) (grub_macho_t macho)
 
224
{
 
225
  grub_macho_addr_t entry_point = 0;
 
226
  auto int NESTED_FUNC_ATTR hook(grub_macho_t _macho,
 
227
                                 struct grub_macho_cmd *hdr,
 
228
                                 void *_arg __attribute__ ((unused)));
 
229
  int NESTED_FUNC_ATTR hook(grub_macho_t _macho __attribute__ ((unused)),
 
230
                            struct grub_macho_cmd *hdr,
 
231
                            void *_arg __attribute__ ((unused)))
 
232
  {
 
233
    if (hdr->cmd == GRUB_MACHO_CMD_THREAD)
 
234
      entry_point = ((grub_macho_thread_t *) hdr)->entry_point;
 
235
    return 0;
 
236
  }
 
237
  grub_macho_cmds_iterate (macho, hook, 0);
 
238
  return entry_point;
 
239
}