debuggers.hg

view xen/common/libelf/libelf-dominfo.c @ 13699:1b32e279ddef

libelf cannot rely on the strlcpy() BSD-ism.
Make a private definition based on strncpy and strlen.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Jan 29 11:47:00 2007 +0000 (2007-01-29)
parents b2c1eeee2dcf
children bef7fbe25a9f
line source
1 /*
2 * parse xen-specific informations out of elf kernel binaries.
3 */
5 #include "libelf-private.h"
7 /* ------------------------------------------------------------------------ */
8 /* xen features */
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]);
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;
27 if (NULL == features)
28 return 0;
29 for (pos = 0; features[pos] != '\0'; pos += len)
30 {
31 memset(feature, 0, sizeof(feature));
32 for (len = 0;; len++)
33 {
34 if (len >= sizeof(feature)-1)
35 break;
36 if (features[pos + len] == '\0')
37 break;
38 if (features[pos + len] == '|')
39 {
40 len++;
41 break;
42 }
43 feature[len] = features[pos + len];
44 }
46 for (i = 0; i < elf_xen_features; i++)
47 {
48 if (!elf_xen_feature_names[i])
49 continue;
50 if (NULL != required && feature[0] == '!')
51 {
52 /* required */
53 if (0 == strcmp(feature + 1, elf_xen_feature_names[i]))
54 {
55 elf_xen_feature_set(i, supported);
56 elf_xen_feature_set(i, required);
57 break;
58 }
59 }
60 else
61 {
62 /* supported */
63 if (0 == strcmp(feature, elf_xen_feature_names[i]))
64 {
65 elf_xen_feature_set(i, supported);
66 break;
67 }
68 }
69 }
70 if (i == elf_xen_features)
71 return -1;
72 }
73 return 0;
74 }
76 /* ------------------------------------------------------------------------ */
77 /* xen elf notes */
79 int elf_xen_parse_note(struct elf_binary *elf,
80 struct elf_dom_parms *parms,
81 const elf_note *note)
82 {
83 /* *INDENT-OFF* */
84 static const struct {
85 char *name;
86 int str;
87 } note_desc[] = {
88 [XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
89 [XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
90 [XEN_ELFNOTE_VIRT_BASE] = { "VIRT_BASE", 0},
91 [XEN_ELFNOTE_PADDR_OFFSET] = { "PADDR_OFFSET", 0},
92 [XEN_ELFNOTE_HV_START_LOW] = { "HV_START_LOW", 0},
93 [XEN_ELFNOTE_XEN_VERSION] = { "XEN_VERSION", 1},
94 [XEN_ELFNOTE_GUEST_OS] = { "GUEST_OS", 1},
95 [XEN_ELFNOTE_GUEST_VERSION] = { "GUEST_VERSION", 1},
96 [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
97 [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
98 [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
99 [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
100 };
101 /* *INDENT-ON* */
103 const char *str = NULL;
104 uint64_t val = 0;
105 int type = elf_uval(elf, note, type);
107 if ((type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
108 (NULL == note_desc[type].name))
109 {
110 elf_err(elf, "%s: unknown xen elf note (0x%x)\n",
111 __FUNCTION__, type);
112 return -1;
113 }
115 if (note_desc[type].str)
116 {
117 str = elf_note_desc(elf, note);
118 elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
119 note_desc[type].name, str);
120 }
121 else
122 {
123 val = elf_note_numeric(elf, note);
124 elf_msg(elf, "%s: %s = 0x%" PRIx64 "\n", __FUNCTION__,
125 note_desc[type].name, val);
126 }
128 switch (type)
129 {
130 case XEN_ELFNOTE_LOADER:
131 elf_strlcpy(parms->loader, str, sizeof(parms->loader));
132 break;
133 case XEN_ELFNOTE_GUEST_OS:
134 elf_strlcpy(parms->guest_os, str, sizeof(parms->guest_os));
135 break;
136 case XEN_ELFNOTE_GUEST_VERSION:
137 elf_strlcpy(parms->guest_ver, str, sizeof(parms->guest_ver));
138 break;
139 case XEN_ELFNOTE_XEN_VERSION:
140 elf_strlcpy(parms->xen_ver, str, sizeof(parms->xen_ver));
141 break;
142 case XEN_ELFNOTE_PAE_MODE:
143 if (0 == strcmp(str, "yes"))
144 parms->pae = 2 /* extended_cr3 */;
145 if (strstr(str, "bimodal"))
146 parms->pae = 3 /* bimodal */;
147 break;
148 case XEN_ELFNOTE_BSD_SYMTAB:
149 if (0 == strcmp(str, "yes"))
150 parms->bsd_symtab = 1;
151 break;
153 case XEN_ELFNOTE_VIRT_BASE:
154 parms->virt_base = val;
155 break;
156 case XEN_ELFNOTE_ENTRY:
157 parms->virt_entry = val;
158 break;
159 case XEN_ELFNOTE_PADDR_OFFSET:
160 parms->elf_paddr_offset = val;
161 break;
162 case XEN_ELFNOTE_HYPERCALL_PAGE:
163 parms->virt_hypercall = val;
164 break;
165 case XEN_ELFNOTE_HV_START_LOW:
166 parms->virt_hv_start_low = val;
167 break;
169 case XEN_ELFNOTE_FEATURES:
170 if (0 != elf_xen_parse_features(str, parms->f_supported,
171 parms->f_required))
172 return -1;
173 break;
175 }
176 return 0;
177 }
179 /* ------------------------------------------------------------------------ */
180 /* __xen_guest section */
182 int elf_xen_parse_guest_info(struct elf_binary *elf,
183 struct elf_dom_parms *parms)
184 {
185 const char *h;
186 char name[32], value[128];
187 int len;
189 h = parms->guest_info;
190 while (*h)
191 {
192 memset(name, 0, sizeof(name));
193 memset(value, 0, sizeof(value));
194 for (len = 0;; len++, h++) {
195 if (len >= sizeof(name)-1)
196 break;
197 if (*h == '\0')
198 break;
199 if (*h == ',')
200 {
201 h++;
202 break;
203 }
204 if (*h == '=')
205 {
206 h++;
207 for (len = 0;; len++, h++) {
208 if (len >= sizeof(value)-1)
209 break;
210 if (*h == '\0')
211 break;
212 if (*h == ',')
213 {
214 h++;
215 break;
216 }
217 value[len] = *h;
218 }
219 break;
220 }
221 name[len] = *h;
222 }
223 elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
225 /* strings */
226 if (0 == strcmp(name, "LOADER"))
227 elf_strlcpy(parms->loader, value, sizeof(parms->loader));
228 if (0 == strcmp(name, "GUEST_OS"))
229 elf_strlcpy(parms->guest_os, value, sizeof(parms->guest_os));
230 if (0 == strcmp(name, "GUEST_VER"))
231 elf_strlcpy(parms->guest_ver, value, sizeof(parms->guest_ver));
232 if (0 == strcmp(name, "XEN_VER"))
233 elf_strlcpy(parms->xen_ver, value, sizeof(parms->xen_ver));
234 if (0 == strcmp(name, "PAE"))
235 {
236 if (0 == strcmp(value, "yes[extended-cr3]"))
237 parms->pae = 2 /* extended_cr3 */;
238 else if (0 == strncmp(value, "yes", 3))
239 parms->pae = 1 /* yes */;
240 }
241 if (0 == strcmp(name, "BSD_SYMTAB"))
242 parms->bsd_symtab = 1;
244 /* longs */
245 if (0 == strcmp(name, "VIRT_BASE"))
246 parms->virt_base = strtoull(value, NULL, 0);
247 if (0 == strcmp(name, "VIRT_ENTRY"))
248 parms->virt_entry = strtoull(value, NULL, 0);
249 if (0 == strcmp(name, "ELF_PADDR_OFFSET"))
250 parms->elf_paddr_offset = strtoull(value, NULL, 0);
251 if (0 == strcmp(name, "HYPERCALL_PAGE"))
252 parms->virt_hypercall = (strtoull(value, NULL, 0) << 12) +
253 parms->virt_base;
255 /* other */
256 if (0 == strcmp(name, "FEATURES"))
257 if (0 != elf_xen_parse_features(value, parms->f_supported,
258 parms->f_required))
259 return -1;
260 }
261 return 0;
262 }
264 /* ------------------------------------------------------------------------ */
265 /* sanity checks */
267 static int elf_xen_note_check(struct elf_binary *elf,
268 struct elf_dom_parms *parms)
269 {
270 if (NULL == parms->elf_note_start && NULL == parms->guest_info) {
271 int machine = elf_uval(elf, elf->ehdr, e_machine);
272 if (EM_386 == machine || EM_X86_64 == machine) {
273 elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
274 "No ELF notes or '__xen_guest' section found.\n",
275 __FUNCTION__);
276 return -1;
277 }
278 return 0;
279 }
281 /* Check the contents of the Xen notes or guest string. */
282 if ( ( 0 == strlen(parms->loader) || strncmp(parms->loader, "generic", 7) ) &&
283 ( 0 == strlen(parms->guest_os) || strncmp(parms->guest_os, "linux", 5) ) )
284 {
285 elf_err(elf, "%s: ERROR: Will only load images built for the generic "
286 "loader or Linux images", __FUNCTION__);
287 return -1;
288 }
290 if ( 0 == strlen(parms->xen_ver) || strncmp(parms->xen_ver, "xen-3.0", 7) )
291 {
292 elf_err(elf, "%s: ERROR: Xen will only load images built for Xen v3.0\n",
293 __FUNCTION__);
294 return -1;
295 }
296 return 0;
297 }
299 static int elf_xen_addr_calc_check(struct elf_binary *elf,
300 struct elf_dom_parms *parms)
301 {
302 if (UNSET_ADDR != parms->elf_paddr_offset &&
303 UNSET_ADDR == parms->virt_base )
304 {
305 elf_err(elf, "%s: ERROR: ELF_PADDR_OFFSET set, VIRT_BASE unset\n",
306 __FUNCTION__);
307 return -1;
308 }
310 /* Initial guess for virt_base is 0 if it is not explicitly defined. */
311 if (UNSET_ADDR == parms->virt_base)
312 {
313 parms->virt_base = 0;
314 elf_msg(elf, "%s: VIRT_BASE unset, using 0x%" PRIx64 "\n",
315 __FUNCTION__, parms->virt_base);
316 }
318 /*
319 * If we are using the legacy __xen_guest section then elf_pa_off
320 * defaults to v_start in order to maintain compatibility with
321 * older hypervisors which set padd in the ELF header to
322 * virt_base.
323 *
324 * If we are using the modern ELF notes interface then the default
325 * is 0.
326 */
327 if (UNSET_ADDR == parms->elf_paddr_offset)
328 {
329 if (parms->elf_note_start)
330 parms->elf_paddr_offset = 0;
331 else
332 parms->elf_paddr_offset = parms->virt_base;
333 elf_msg(elf, "%s: ELF_PADDR_OFFSET unset, using 0x%" PRIx64 "\n",
334 __FUNCTION__, parms->elf_paddr_offset);
335 }
337 parms->virt_offset = parms->virt_base - parms->elf_paddr_offset;
338 parms->virt_kstart = elf->pstart + parms->virt_offset;
339 parms->virt_kend = elf->pend + parms->virt_offset;
341 if (UNSET_ADDR == parms->virt_entry)
342 parms->virt_entry = elf_uval(elf, elf->ehdr, e_entry);
344 elf_msg(elf, "%s: addresses:\n", __FUNCTION__);
345 elf_msg(elf, " virt_base = 0x%" PRIx64 "\n", parms->virt_base);
346 elf_msg(elf, " elf_paddr_offset = 0x%" PRIx64 "\n", parms->elf_paddr_offset);
347 elf_msg(elf, " virt_offset = 0x%" PRIx64 "\n", parms->virt_offset);
348 elf_msg(elf, " virt_kstart = 0x%" PRIx64 "\n", parms->virt_kstart);
349 elf_msg(elf, " virt_kend = 0x%" PRIx64 "\n", parms->virt_kend);
350 elf_msg(elf, " virt_entry = 0x%" PRIx64 "\n", parms->virt_entry);
352 if ( (parms->virt_kstart > parms->virt_kend) ||
353 (parms->virt_entry < parms->virt_kstart) ||
354 (parms->virt_entry > parms->virt_kend) ||
355 (parms->virt_base > parms->virt_kstart) )
356 {
357 elf_err(elf, "%s: ERROR: ELF start or entries are out of bounds.\n",
358 __FUNCTION__);
359 return -1;
360 }
362 return 0;
363 }
365 /* ------------------------------------------------------------------------ */
366 /* glue it all together ... */
368 int elf_xen_parse(struct elf_binary *elf,
369 struct elf_dom_parms *parms)
370 {
371 const elf_note *note;
372 const elf_shdr *shdr;
373 int xen_elfnotes = 0;
374 int i, count;
376 memset(parms, 0, sizeof(*parms));
377 parms->virt_base = UNSET_ADDR;
378 parms->virt_entry = UNSET_ADDR;
379 parms->virt_hypercall = UNSET_ADDR;
380 parms->virt_hv_start_low = UNSET_ADDR;
381 parms->elf_paddr_offset = UNSET_ADDR;
383 /* find and parse elf notes */
384 count = elf_shdr_count(elf);
385 for (i = 0; i < count; i++)
386 {
387 shdr = elf_shdr_by_index(elf, i);
388 if (0 == strcmp(elf_section_name(elf, shdr), "__xen_guest"))
389 parms->guest_info = elf_section_start(elf, shdr);
390 if (elf_uval(elf, shdr, sh_type) != SHT_NOTE)
391 continue;
392 parms->elf_note_start = elf_section_start(elf, shdr);
393 parms->elf_note_end = elf_section_end(elf, shdr);
394 for (note = parms->elf_note_start;
395 (void *)note < parms->elf_note_end;
396 note = elf_note_next(elf, note))
397 {
398 if (0 != strcmp(elf_note_name(elf, note), "Xen"))
399 continue;
400 if (0 != elf_xen_parse_note(elf, parms, note))
401 return -1;
402 xen_elfnotes++;
403 }
404 }
406 if (!xen_elfnotes && parms->guest_info)
407 {
408 parms->elf_note_start = NULL;
409 parms->elf_note_end = NULL;
410 elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
411 parms->guest_info);
412 elf_xen_parse_guest_info(elf, parms);
413 }
415 if (0 != elf_xen_note_check(elf, parms))
416 return -1;
417 if (0 != elf_xen_addr_calc_check(elf, parms))
418 return -1;
419 return 0;
420 }