debuggers.hg

view xen/common/libelf/libelf-loader.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 eccfdeb41b80
children
line source
1 /*
2 * parse and load elf 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 <stdarg.h>
21 #include "libelf-private.h"
23 /* ------------------------------------------------------------------------ */
25 int elf_init(struct elf_binary *elf, const char *image, size_t size)
26 {
27 const elf_shdr *shdr;
28 uint64_t i, count, section, offset;
30 if ( !elf_is_elfbinary(image) )
31 {
32 elf_err(elf, "%s: not an ELF binary\n", __FUNCTION__);
33 return -1;
34 }
36 memset(elf, 0, sizeof(*elf));
37 elf->image = image;
38 elf->size = size;
39 elf->ehdr = (elf_ehdr *)image;
40 elf->class = elf->ehdr->e32.e_ident[EI_CLASS];
41 elf->data = elf->ehdr->e32.e_ident[EI_DATA];
43 /* Sanity check phdr. */
44 offset = elf_uval(elf, elf->ehdr, e_phoff) +
45 elf_uval(elf, elf->ehdr, e_phentsize) * elf_phdr_count(elf);
46 if ( offset > elf->size )
47 {
48 elf_err(elf, "%s: phdr overflow (off %" PRIx64 " > size %lx)\n",
49 __FUNCTION__, offset, (unsigned long)elf->size);
50 return -1;
51 }
53 /* Sanity check shdr. */
54 offset = elf_uval(elf, elf->ehdr, e_shoff) +
55 elf_uval(elf, elf->ehdr, e_shentsize) * elf_shdr_count(elf);
56 if ( offset > elf->size )
57 {
58 elf_err(elf, "%s: shdr overflow (off %" PRIx64 " > size %lx)\n",
59 __FUNCTION__, offset, (unsigned long)elf->size);
60 return -1;
61 }
63 /* Find section string table. */
64 section = elf_uval(elf, elf->ehdr, e_shstrndx);
65 shdr = elf_shdr_by_index(elf, section);
66 if ( shdr != NULL )
67 elf->sec_strtab = elf_section_start(elf, shdr);
69 /* Find symbol table and symbol string table. */
70 count = elf_shdr_count(elf);
71 for ( i = 0; i < count; i++ )
72 {
73 shdr = elf_shdr_by_index(elf, i);
74 if ( elf_uval(elf, shdr, sh_type) != SHT_SYMTAB )
75 continue;
76 elf->sym_tab = shdr;
77 shdr = elf_shdr_by_index(elf, elf_uval(elf, shdr, sh_link));
78 if ( shdr == NULL )
79 {
80 elf->sym_tab = NULL;
81 continue;
82 }
83 elf->sym_strtab = elf_section_start(elf, shdr);
84 break;
85 }
87 return 0;
88 }
90 #ifndef __XEN__
91 void elf_call_log_callback(struct elf_binary *elf, int iserr,
92 const char *fmt,...) {
93 va_list al;
95 if (!elf->log_callback)
96 return;
97 if (!(iserr || elf->verbose))
98 return;
100 va_start(al,fmt);
101 elf->log_callback(elf, elf->log_caller_data, iserr, fmt, al);
102 va_end(al);
103 }
105 void elf_set_log(struct elf_binary *elf, elf_log_callback *log_callback,
106 void *log_caller_data, int verbose)
107 {
108 elf->log_callback = log_callback;
109 elf->log_caller_data = log_caller_data;
110 elf->verbose = verbose;
111 }
112 #else
113 void elf_set_verbose(struct elf_binary *elf)
114 {
115 elf->verbose = 1;
116 }
117 #endif
119 /* Calculate the required additional kernel space for the elf image */
120 void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart)
121 {
122 uint64_t sz;
123 const elf_shdr *shdr;
124 int i, type;
126 if ( !elf->sym_tab )
127 return;
129 pstart = elf_round_up(elf, pstart);
131 /* Space to store the size of the elf image */
132 sz = sizeof(uint32_t);
134 /* Space for the elf and elf section headers */
135 sz += (elf_uval(elf, elf->ehdr, e_ehsize) +
136 elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize));
137 sz = elf_round_up(elf, sz);
139 /* Space for the symbol and string tables. */
140 for ( i = 0; i < elf_shdr_count(elf); i++ )
141 {
142 shdr = elf_shdr_by_index(elf, i);
143 type = elf_uval(elf, (elf_shdr *)shdr, sh_type);
144 if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
145 sz = elf_round_up(elf, sz + elf_uval(elf, shdr, sh_size));
146 }
148 elf->bsd_symtab_pstart = pstart;
149 elf->bsd_symtab_pend = pstart + sz;
150 }
152 static void elf_load_bsdsyms(struct elf_binary *elf)
153 {
154 elf_ehdr *sym_ehdr;
155 unsigned long sz;
156 char *maxva, *symbase, *symtab_addr;
157 elf_shdr *shdr;
158 int i, type;
160 if ( !elf->bsd_symtab_pstart )
161 return;
163 #define elf_hdr_elm(_elf, _hdr, _elm, _val) \
164 do { \
165 if ( elf_64bit(_elf) ) \
166 (_hdr)->e64._elm = _val; \
167 else \
168 (_hdr)->e32._elm = _val; \
169 } while ( 0 )
171 symbase = elf_get_ptr(elf, elf->bsd_symtab_pstart);
172 symtab_addr = maxva = symbase + sizeof(uint32_t);
174 /* Set up Elf header. */
175 sym_ehdr = (elf_ehdr *)symtab_addr;
176 sz = elf_uval(elf, elf->ehdr, e_ehsize);
177 memcpy(sym_ehdr, elf->ehdr, sz);
178 maxva += sz; /* no round up */
180 elf_hdr_elm(elf, sym_ehdr, e_phoff, 0);
181 elf_hdr_elm(elf, sym_ehdr, e_shoff, elf_uval(elf, elf->ehdr, e_ehsize));
182 elf_hdr_elm(elf, sym_ehdr, e_phentsize, 0);
183 elf_hdr_elm(elf, sym_ehdr, e_phnum, 0);
185 /* Copy Elf section headers. */
186 shdr = (elf_shdr *)maxva;
187 sz = elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize);
188 memcpy(shdr, elf->image + elf_uval(elf, elf->ehdr, e_shoff), sz);
189 maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz);
191 for ( i = 0; i < elf_shdr_count(elf); i++ )
192 {
193 type = elf_uval(elf, shdr, sh_type);
194 if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
195 {
196 elf_msg(elf, "%s: shdr %i at 0x%p -> 0x%p\n", __func__, i,
197 elf_section_start(elf, shdr), maxva);
198 sz = elf_uval(elf, shdr, sh_size);
199 memcpy(maxva, elf_section_start(elf, shdr), sz);
200 /* Mangled to be based on ELF header location. */
201 elf_hdr_elm(elf, shdr, sh_offset, maxva - symtab_addr);
202 maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz);
203 }
204 shdr = (elf_shdr *)((long)shdr +
205 (long)elf_uval(elf, elf->ehdr, e_shentsize));
206 }
208 /* Write down the actual sym size. */
209 *(uint32_t *)symbase = maxva - symtab_addr;
211 #undef elf_ehdr_elm
212 }
214 void elf_parse_binary(struct elf_binary *elf)
215 {
216 const elf_phdr *phdr;
217 uint64_t low = -1;
218 uint64_t high = 0;
219 uint64_t i, count, paddr, memsz;
221 count = elf_uval(elf, elf->ehdr, e_phnum);
222 for ( i = 0; i < count; i++ )
223 {
224 phdr = elf_phdr_by_index(elf, i);
225 if ( !elf_phdr_is_loadable(elf, phdr) )
226 continue;
227 paddr = elf_uval(elf, phdr, p_paddr);
228 memsz = elf_uval(elf, phdr, p_memsz);
229 elf_msg(elf, "%s: phdr: paddr=0x%" PRIx64
230 " memsz=0x%" PRIx64 "\n", __FUNCTION__, paddr, memsz);
231 if ( low > paddr )
232 low = paddr;
233 if ( high < paddr + memsz )
234 high = paddr + memsz;
235 }
236 elf->pstart = low;
237 elf->pend = high;
238 elf_msg(elf, "%s: memory: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
239 __FUNCTION__, elf->pstart, elf->pend);
240 }
242 void elf_load_binary(struct elf_binary *elf)
243 {
244 const elf_phdr *phdr;
245 uint64_t i, count, paddr, offset, filesz, memsz;
246 char *dest;
248 count = elf_uval(elf, elf->ehdr, e_phnum);
249 for ( i = 0; i < count; i++ )
250 {
251 phdr = elf_phdr_by_index(elf, i);
252 if ( !elf_phdr_is_loadable(elf, phdr) )
253 continue;
254 paddr = elf_uval(elf, phdr, p_paddr);
255 offset = elf_uval(elf, phdr, p_offset);
256 filesz = elf_uval(elf, phdr, p_filesz);
257 memsz = elf_uval(elf, phdr, p_memsz);
258 dest = elf_get_ptr(elf, paddr);
259 elf_msg(elf, "%s: phdr %" PRIu64 " at 0x%p -> 0x%p\n",
260 __func__, i, dest, dest + filesz);
261 memcpy(dest, elf->image + offset, filesz);
262 memset(dest + filesz, 0, memsz - filesz);
263 }
265 elf_load_bsdsyms(elf);
266 }
268 void *elf_get_ptr(struct elf_binary *elf, unsigned long addr)
269 {
270 return elf->dest + addr - elf->pstart;
271 }
273 uint64_t elf_lookup_addr(struct elf_binary * elf, const char *symbol)
274 {
275 const elf_sym *sym;
276 uint64_t value;
278 sym = elf_sym_by_name(elf, symbol);
279 if ( sym == NULL )
280 {
281 elf_err(elf, "%s: not found: %s\n", __FUNCTION__, symbol);
282 return -1;
283 }
285 value = elf_uval(elf, sym, st_value);
286 elf_msg(elf, "%s: symbol \"%s\" at 0x%" PRIx64 "\n", __FUNCTION__,
287 symbol, value);
288 return value;
289 }
291 /*
292 * Local variables:
293 * mode: C
294 * c-set-style: "BSD"
295 * c-basic-offset: 4
296 * tab-width: 4
297 * indent-tabs-mode: nil
298 * End:
299 */