debuggers.hg

view xen/common/libelf/libelf-dominfo.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 7f3ccf376aad
children
line source
1 /*
2 * parse xen-specific informations out of elf kernel binaries.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation;
7 * version 2.1 of the License.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
19 #include "libelf-private.h"
21 /* ------------------------------------------------------------------------ */
22 /* xen features */
24 static const char *const elf_xen_feature_names[] = {
25 [XENFEAT_writable_page_tables] = "writable_page_tables",
26 [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
27 [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
28 [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
29 [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
30 };
31 static const int elf_xen_features =
32 sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
34 int elf_xen_parse_features(const char *features,
35 uint32_t *supported,
36 uint32_t *required)
37 {
38 char feature[64];
39 int pos, len, i;
41 if ( features == NULL )
42 return 0;
44 for ( pos = 0; features[pos] != '\0'; pos += len )
45 {
46 memset(feature, 0, sizeof(feature));
47 for ( len = 0;; len++ )
48 {
49 if ( len >= sizeof(feature)-1 )
50 break;
51 if ( features[pos + len] == '\0' )
52 break;
53 if ( features[pos + len] == '|' )
54 {
55 len++;
56 break;
57 }
58 feature[len] = features[pos + len];
59 }
61 for ( i = 0; i < elf_xen_features; i++ )
62 {
63 if ( !elf_xen_feature_names[i] )
64 continue;
65 if ( (required != NULL) && (feature[0] == '!') )
66 {
67 /* required */
68 if ( !strcmp(feature + 1, elf_xen_feature_names[i]) )
69 {
70 elf_xen_feature_set(i, supported);
71 elf_xen_feature_set(i, required);
72 break;
73 }
74 }
75 else
76 {
77 /* supported */
78 if ( !strcmp(feature, elf_xen_feature_names[i]) )
79 {
80 elf_xen_feature_set(i, supported);
81 break;
82 }
83 }
84 }
85 if ( i == elf_xen_features )
86 return -1;
87 }
89 return 0;
90 }
92 /* ------------------------------------------------------------------------ */
93 /* xen elf notes */
95 int elf_xen_parse_note(struct elf_binary *elf,
96 struct elf_dom_parms *parms,
97 const elf_note *note)
98 {
99 /* *INDENT-OFF* */
100 static const struct {
101 char *name;
102 int str;
103 } note_desc[] = {
104 [XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
105 [XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
106 [XEN_ELFNOTE_VIRT_BASE] = { "VIRT_BASE", 0},
107 [XEN_ELFNOTE_INIT_P2M] = { "INIT_P2M", 0},
108 [XEN_ELFNOTE_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
109 [XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
110 [XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
111 [XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
112 [XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
113 [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
114 [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
115 [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
116 [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
117 [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
118 [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 },
119 };
120 /* *INDENT-ON* */
122 const char *str = NULL;
123 uint64_t val = 0;
124 int type = elf_uval(elf, note, type);
126 if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
127 (note_desc[type].name == NULL) )
128 {
129 elf_msg(elf, "%s: unknown xen elf note (0x%x)\n",
130 __FUNCTION__, type);
131 return 0;
132 }
134 if ( note_desc[type].str )
135 {
136 str = elf_note_desc(elf, note);
137 elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
138 note_desc[type].name, str);
139 parms->elf_notes[type].type = XEN_ENT_STR;
140 parms->elf_notes[type].data.str = str;
141 }
142 else
143 {
144 val = elf_note_numeric(elf, note);
145 elf_msg(elf, "%s: %s = 0x%" PRIx64 "\n", __FUNCTION__,
146 note_desc[type].name, val);
147 parms->elf_notes[type].type = XEN_ENT_LONG;
148 parms->elf_notes[type].data.num = val;
149 }
150 parms->elf_notes[type].name = note_desc[type].name;
152 switch ( type )
153 {
154 case XEN_ELFNOTE_LOADER:
155 safe_strcpy(parms->loader, str);
156 break;
157 case XEN_ELFNOTE_GUEST_OS:
158 safe_strcpy(parms->guest_os, str);
159 break;
160 case XEN_ELFNOTE_GUEST_VERSION:
161 safe_strcpy(parms->guest_ver, str);
162 break;
163 case XEN_ELFNOTE_XEN_VERSION:
164 safe_strcpy(parms->xen_ver, str);
165 break;
166 case XEN_ELFNOTE_PAE_MODE:
167 if ( !strcmp(str, "yes") )
168 parms->pae = 2 /* extended_cr3 */;
169 if ( strstr(str, "bimodal") )
170 parms->pae = 3 /* bimodal */;
171 break;
172 case XEN_ELFNOTE_BSD_SYMTAB:
173 if ( !strcmp(str, "yes") )
174 parms->bsd_symtab = 1;
175 break;
177 case XEN_ELFNOTE_VIRT_BASE:
178 parms->virt_base = val;
179 break;
180 case XEN_ELFNOTE_ENTRY:
181 parms->virt_entry = val;
182 break;
183 case XEN_ELFNOTE_INIT_P2M:
184 parms->p2m_base = val;
185 break;
186 case XEN_ELFNOTE_PADDR_OFFSET:
187 parms->elf_paddr_offset = val;
188 break;
189 case XEN_ELFNOTE_HYPERCALL_PAGE:
190 parms->virt_hypercall = val;
191 break;
192 case XEN_ELFNOTE_HV_START_LOW:
193 parms->virt_hv_start_low = val;
194 break;
196 case XEN_ELFNOTE_FEATURES:
197 if ( elf_xen_parse_features(str, parms->f_supported,
198 parms->f_required) )
199 return -1;
200 break;
202 }
203 return 0;
204 }
206 static int elf_xen_parse_notes(struct elf_binary *elf,
207 struct elf_dom_parms *parms,
208 const void *start, const void *end)
209 {
210 int xen_elfnotes = 0;
211 const elf_note *note;
213 parms->elf_note_start = start;
214 parms->elf_note_end = end;
215 for ( note = parms->elf_note_start;
216 (void *)note < parms->elf_note_end;
217 note = elf_note_next(elf, note) )
218 {
219 if ( strcmp(elf_note_name(elf, note), "Xen") )
220 continue;
221 if ( elf_xen_parse_note(elf, parms, note) )
222 return -1;
223 xen_elfnotes++;
224 }
225 return xen_elfnotes;
226 }
228 /* ------------------------------------------------------------------------ */
229 /* __xen_guest section */
231 int elf_xen_parse_guest_info(struct elf_binary *elf,
232 struct elf_dom_parms *parms)
233 {
234 const char *h;
235 char name[32], value[128];
236 int len;
238 h = parms->guest_info;
239 while ( *h )
240 {
241 memset(name, 0, sizeof(name));
242 memset(value, 0, sizeof(value));
243 for ( len = 0;; len++, h++ )
244 {
245 if ( len >= sizeof(name)-1 )
246 break;
247 if ( *h == '\0' )
248 break;
249 if ( *h == ',' )
250 {
251 h++;
252 break;
253 }
254 if ( *h == '=' )
255 {
256 h++;
257 for ( len = 0;; len++, h++ )
258 {
259 if ( len >= sizeof(value)-1 )
260 break;
261 if ( *h == '\0' )
262 break;
263 if ( *h == ',' )
264 {
265 h++;
266 break;
267 }
268 value[len] = *h;
269 }
270 break;
271 }
272 name[len] = *h;
273 }
274 elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
276 /* strings */
277 if ( !strcmp(name, "LOADER") )
278 safe_strcpy(parms->loader, value);
279 if ( !strcmp(name, "GUEST_OS") )
280 safe_strcpy(parms->guest_os, value);
281 if ( !strcmp(name, "GUEST_VER") )
282 safe_strcpy(parms->guest_ver, value);
283 if ( !strcmp(name, "XEN_VER") )
284 safe_strcpy(parms->xen_ver, value);
285 if ( !strcmp(name, "PAE") )
286 {
287 if ( !strcmp(value, "yes[extended-cr3]") )
288 parms->pae = 2 /* extended_cr3 */;
289 else if ( !strncmp(value, "yes", 3) )
290 parms->pae = 1 /* yes */;
291 }
292 if ( !strcmp(name, "BSD_SYMTAB") )
293 parms->bsd_symtab = 1;
295 /* longs */
296 if ( !strcmp(name, "VIRT_BASE") )
297 parms->virt_base = strtoull(value, NULL, 0);
298 if ( !strcmp(name, "VIRT_ENTRY") )
299 parms->virt_entry = strtoull(value, NULL, 0);
300 if ( !strcmp(name, "ELF_PADDR_OFFSET") )
301 parms->elf_paddr_offset = strtoull(value, NULL, 0);
302 if ( !strcmp(name, "HYPERCALL_PAGE") )
303 parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
304 parms->virt_base;
306 /* other */
307 if ( !strcmp(name, "FEATURES") )
308 if ( elf_xen_parse_features(value, parms->f_supported,
309 parms->f_required) )
310 return -1;
311 }
312 return 0;
313 }
315 /* ------------------------------------------------------------------------ */
316 /* sanity checks */
318 static int elf_xen_note_check(struct elf_binary *elf,
319 struct elf_dom_parms *parms)
320 {
321 if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
322 {
323 int machine = elf_uval(elf, elf->ehdr, e_machine);
324 if ( (machine == EM_386) || (machine == EM_X86_64) )
325 {
326 elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
327 "No ELF notes or '__xen_guest' section found.\n",
328 __FUNCTION__);
329 return -1;
330 }
331 return 0;
332 }
334 /* Check the contents of the Xen notes or guest string. */
335 if ( ((strlen(parms->loader) == 0) ||
336 strncmp(parms->loader, "generic", 7)) &&
337 ((strlen(parms->guest_os) == 0) ||
338 strncmp(parms->guest_os, "linux", 5)) )
339 {
340 elf_err(elf, "%s: ERROR: Will only load images built for the generic "
341 "loader or Linux images", __FUNCTION__);
342 return -1;
343 }
345 if ( (strlen(parms->xen_ver) == 0) ||
346 strncmp(parms->xen_ver, "xen-3.0", 7) )
347 {
348 elf_err(elf, "%s: ERROR: Xen will only load images built "
349 "for Xen v3.0\n", __FUNCTION__);
350 return -1;
351 }
352 return 0;
353 }
355 static int elf_xen_addr_calc_check(struct elf_binary *elf,
356 struct elf_dom_parms *parms)
357 {
358 if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
359 (parms->virt_base == UNSET_ADDR) )
360 {
361 elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
362 __FUNCTION__);
363 return -1;
364 }
366 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
367 if ( parms->virt_base == UNSET_ADDR )
368 {
369 parms->virt_base = 0;
370 elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
371 __FUNCTION__, parms->virt_base);
372 }
374 /*
375 * If we are using the legacy __xen_guest section then elf_pa_off
376 * defaults to v_start in order to maintain compatibility with
377 * older hypervisors which set padd in the ELF header to
378 * virt_base.
379 *
380 * If we are using the modern ELF notes interface then the default
381 * is 0.
382 */
383 if ( parms->elf_paddr_offset == UNSET_ADDR )
384 {
385 if ( parms->elf_note_start )
386 parms->elf_paddr_offset = 0;
387 else
388 parms->elf_paddr_offset = parms->virt_base;
389 elf_msg(elf, "%s: ELF_PADDR_OFFSET unset, using 0x%" PRIx64 "\n",
390 __FUNCTION__, parms->elf_paddr_offset);
391 }
393 parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
394 parms->virt_kstart = elf->pstart + parms->virt_offset;
395 parms->virt_kend = elf->pend + parms->virt_offset;
397 if ( parms->virt_entry == UNSET_ADDR )
398 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
400 if ( parms->bsd_symtab )
401 {
402 elf_parse_bsdsyms(elf, parms->virt_kend);
403 if ( elf->bsd_symtab_pend )
404 parms->virt_kend = elf->bsd_symtab_pend + parms->virt_offset;
405 }
407 elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
408 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
409 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
410 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
411 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
412 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
413 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
414 elf_msg(elf, " p2m_base = 0x%" PRIx64 "\n", parms->p2m_base);
416 if ( (parms->virt_kstart > parms->virt_kend) ||
417 (parms->virt_entry < parms->virt_kstart) ||
418 (parms->virt_entry > parms->virt_kend) ||
419 (parms->virt_base > parms->virt_kstart) )
420 {
421 elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
422 __FUNCTION__);
423 return -1;
424 }
426 if ( (parms->p2m_base != UNSET_ADDR) &&
427 (parms->p2m_base >= parms->virt_kstart) &&
428 (parms->p2m_base < parms->virt_kend) )
429 {
430 elf_err(elf, "%s: ERROR: P->M table base is out of bounds.\n",
431 __FUNCTION__);
432 return -1;
433 }
435 return 0;
436 }
438 /* ------------------------------------------------------------------------ */
439 /* glue it all together ... */
441 int elf_xen_parse(struct elf_binary *elf,
442 struct elf_dom_parms *parms)
443 {
444 const elf_shdr *shdr;
445 const elf_phdr *phdr;
446 int xen_elfnotes = 0;
447 int i, count, rc;
449 memset(parms, 0, sizeof(*parms));
450 parms->virt_base = UNSET_ADDR;
451 parms->virt_entry = UNSET_ADDR;
452 parms->virt_hypercall = UNSET_ADDR;
453 parms->virt_hv_start_low = UNSET_ADDR;
454 parms->p2m_base = UNSET_ADDR;
455 parms->elf_paddr_offset = UNSET_ADDR;
457 /* Find and parse elf notes. */
458 count = elf_phdr_count(elf);
459 for ( i = 0; i < count; i++ )
460 {
461 phdr = elf_phdr_by_index(elf, i);
462 if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
463 continue;
465 /*
466 * Some versions of binutils do not correctly set p_offset for
467 * note segments.
468 */
469 if (elf_uval(elf, phdr, p_offset) == 0)
470 continue;
472 rc = elf_xen_parse_notes(elf, parms,
473 elf_segment_start(elf, phdr),
474 elf_segment_end(elf, phdr));
475 if ( rc == -1 )
476 return -1;
478 xen_elfnotes += rc;
479 }
481 /*
482 * Fall back to any SHT_NOTE sections if no valid note segments
483 * were found.
484 */
485 if ( xen_elfnotes == 0 )
486 {
487 count = elf_shdr_count(elf);
488 for ( i = 0; i < count; i++ )
489 {
490 shdr = elf_shdr_by_index(elf, i);
492 if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
493 continue;
495 rc = elf_xen_parse_notes(elf, parms,
496 elf_section_start(elf, shdr),
497 elf_section_end(elf, shdr));
499 if ( rc == -1 )
500 return -1;
502 if ( xen_elfnotes == 0 && rc > 0 )
503 elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
505 xen_elfnotes += rc;
506 }
508 }
510 /*
511 * Finally fall back to the __xen_guest section.
512 */
513 if ( xen_elfnotes == 0 )
514 {
515 count = elf_shdr_count(elf);
516 for ( i = 0; i < count; i++ )
517 {
518 shdr = elf_shdr_by_name(elf, "__xen_guest");
519 if ( shdr )
520 {
521 parms->guest_info = elf_section_start(elf, shdr);
522 parms->elf_note_start = NULL;
523 parms->elf_note_end = NULL;
524 elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
525 parms->guest_info);
526 elf_xen_parse_guest_info(elf, parms);
527 break;
528 }
529 }
530 }
532 if ( elf_xen_note_check(elf, parms) != 0 )
533 return -1;
534 if ( elf_xen_addr_calc_check(elf, parms) != 0 )
535 return -1;
536 return 0;
537 }
539 /*
540 * Local variables:
541 * mode: C
542 * c-set-style: "BSD"
543 * c-basic-offset: 4
544 * tab-width: 4
545 * indent-tabs-mode: nil
546 * End:
547 */