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