1160157Smarcel/*
2160157SmarcelCopyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3160157SmarcelPermission is hereby granted, free of charge, to any person
4160157Smarcelobtaining a copy of this software and associated documentation
5160157Smarcelfiles (the "Software"), to deal in the Software without
6160157Smarcelrestriction, including without limitation the rights to use,
7160157Smarcelcopy, modify, merge, publish, distribute, sublicense, and/or sell
8160157Smarcelcopies of the Software, and to permit persons to whom the
9160157SmarcelSoftware is furnished to do so, subject to the following
10160157Smarcelconditions:
11160157Smarcel
12160157SmarcelThe above copyright notice and this permission notice shall be
13160157Smarcelincluded in all copies or substantial portions of the Software.
14160157Smarcel
15160157SmarcelTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16160157SmarcelEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17160157SmarcelOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18160157SmarcelNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19160157SmarcelHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20160157SmarcelWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21160157SmarcelFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22160157SmarcelOTHER DEALINGS IN THE SOFTWARE.
23160157Smarcel*/
24160157Smarcel
25160157Smarcel#ifdef USE_CLEAN_NAMESPACE
26160157Smarcel#define fopen _fopen
27160157Smarcel#define fseek _fseek
28160157Smarcel#define fread _fread
29160157Smarcel#define fclose _fclose
30160157Smarcel#endif /* USE_CLEAN_NAMESPACE */
31160157Smarcel
32160157Smarcel#include <stdio.h>
33160157Smarcel#include <stdlib.h>
34160157Smarcel#include <string.h>
35160157Smarcel#include <inttypes.h>
36160157Smarcel#include <elf.h>
37160157Smarcel
38160157Smarcel#include "uwx.h"
39160157Smarcel#include "uwx_env.h"
40160157Smarcel
41160157Smarcel#ifdef USE_CLEAN_NAMESPACE
42160157Smarcel/*
43160157Smarcel * Moved the defines above the include of stdio.h,
44160157Smarcel * so we don't need these unless that causes problems
45160157Smarcel * and we have to move them back down here.
46160157Smarcel * #define fopen _fopen
47160157Smarcel * #define fseek _fseek
48160157Smarcel * #define fread _fread
49160157Smarcel * #define fclose _fclose
50160157Smarcel * extern FILE *_fopen(const char *, const char *);
51160157Smarcel * extern int _fseek(FILE *, long int, int);
52160157Smarcel * extern size_t _fread(void *, size_t, size_t, FILE *);
53160157Smarcel * extern int _fclose(FILE *);
54160157Smarcel */
55160157Smarcel#endif /* USE_CLEAN_NAMESPACE */
56160157Smarcel
57160157Smarcelstruct uwx_symbol_cache {
58160157Smarcel    char *module_name;
59160157Smarcel    int nsyms;
60160157Smarcel    uint64_t *sym_values;
61160157Smarcel    char **sym_names;
62160157Smarcel    char *strings;
63160157Smarcel};
64160157Smarcel
65160157Smarcel
66160157Smarcelint uwx_read_func_symbols(
67160157Smarcel    struct uwx_env *env,
68160157Smarcel    struct uwx_symbol_cache *cache,
69160157Smarcel    char *module_name);
70160157Smarcel
71160157Smarcel
72160157Smarcelint uwx_find_symbol(
73160157Smarcel    struct uwx_env *env,
74160157Smarcel    struct uwx_symbol_cache **symbol_cache_p,
75160157Smarcel    char *module_name,
76160157Smarcel    uint64_t relip,
77160157Smarcel    char **func_name_p,
78160157Smarcel    uint64_t *offset_p)
79160157Smarcel{
80160157Smarcel    int status;
81160157Smarcel    int i;
82160157Smarcel    uint64_t offset;
83160157Smarcel    uint64_t best_offset;
84160157Smarcel    char *best_name;
85160157Smarcel    struct symbol *sym;
86160157Smarcel    struct uwx_symbol_cache *cache = NULL;
87160157Smarcel
88160157Smarcel    /* Allocate a symbol cache on first call */
89160157Smarcel    if (symbol_cache_p != NULL)
90160157Smarcel	cache = *symbol_cache_p;
91160157Smarcel    if (cache == NULL) {
92160157Smarcel	cache = (struct uwx_symbol_cache *)
93160157Smarcel			(*env->allocate_cb)(sizeof(struct uwx_symbol_cache));
94160157Smarcel	if (cache == NULL)
95160157Smarcel	    return UWX_ERR_NOMEM;
96160157Smarcel	cache->module_name = NULL;
97160157Smarcel	cache->nsyms = 0;
98160157Smarcel	cache->sym_values = NULL;
99160157Smarcel	cache->sym_names = NULL;
100160157Smarcel	cache->strings = NULL;
101160157Smarcel	if (symbol_cache_p != NULL)
102160157Smarcel	    *symbol_cache_p = cache;
103160157Smarcel    }
104160157Smarcel
105160157Smarcel    /* Read function symbols from the object file */
106160157Smarcel    status = uwx_read_func_symbols(env, cache, module_name);
107160157Smarcel    if (status != UWX_OK)
108160157Smarcel	return status;
109160157Smarcel
110160157Smarcel    /* Search for best match */
111160157Smarcel    best_offset = ~(uint64_t)0;
112160157Smarcel    best_name = NULL;
113160157Smarcel    for (i = 0; i < cache->nsyms; i++) {
114160157Smarcel	if (cache->sym_values[i] == relip) {
115160157Smarcel	    *func_name_p = cache->sym_names[i];
116160157Smarcel	    *offset_p = 0;
117160157Smarcel	    if (symbol_cache_p == NULL)
118160157Smarcel		uwx_release_symbol_cache(env, cache);
119160157Smarcel	    return UWX_OK;
120160157Smarcel	}
121160157Smarcel	if (relip > cache->sym_values[i]) {
122160157Smarcel	    offset = relip - cache->sym_values[i];
123160157Smarcel	    if (offset < best_offset) {
124160157Smarcel		best_offset = offset;
125160157Smarcel		best_name = cache->sym_names[i];
126160157Smarcel	    }
127160157Smarcel	}
128160157Smarcel    }
129160157Smarcel    if (best_name == NULL)
130160157Smarcel	return UWX_ERR_NOSYM;
131160157Smarcel
132160157Smarcel    if (symbol_cache_p == NULL)
133160157Smarcel	uwx_release_symbol_cache(env, cache);
134160157Smarcel
135160157Smarcel    *func_name_p = best_name;
136160157Smarcel    *offset_p = best_offset;
137160157Smarcel    return UWX_OK;
138160157Smarcel}
139160157Smarcel
140160157Smarcel
141160157Smarcelvoid uwx_release_symbol_cache(
142160157Smarcel    struct uwx_env *env,
143160157Smarcel    struct uwx_symbol_cache *symbol_cache)
144160157Smarcel{
145160157Smarcel    if (symbol_cache->module_name != NULL)
146160157Smarcel	(*env->free_cb)(symbol_cache->module_name);
147160157Smarcel    if (symbol_cache->sym_values != NULL)
148160157Smarcel	(*env->free_cb)(symbol_cache->sym_values);
149160157Smarcel    if (symbol_cache->sym_names != NULL)
150160157Smarcel	(*env->free_cb)(symbol_cache->sym_names);
151160157Smarcel    if (symbol_cache->strings != NULL)
152160157Smarcel	(*env->free_cb)(symbol_cache->strings);
153160157Smarcel    (*env->free_cb)(symbol_cache);
154160157Smarcel}
155160157Smarcel
156160157Smarcel
157160157Smarcel#define ELF_ERR_NOMEM		UWX_ERR_NOMEM  /* Out of memory */
158160157Smarcel#define ELF_ERR_OPEN		UWX_ERR_NOSYM  /* Can't open file */
159160157Smarcel
160160157Smarcel#define ELF_ERR_NOHEADER	UWX_ERR_NOSYM  /* Can't read ELF header */
161160157Smarcel#define ELF_ERR_NOTELF		UWX_ERR_NOSYM  /* Not an ELF file */
162160157Smarcel#define ELF_ERR_HEADER_SIZE	UWX_ERR_NOSYM  /* Invalid e_ehsize */
163160157Smarcel#define ELF_ERR_INVALID_CLASS	UWX_ERR_NOSYM  /* Invalid EI_CLASS */
164160157Smarcel#define ELF_ERR_INVALID_DATA	UWX_ERR_NOSYM  /* Invalid EI_DATA */
165160157Smarcel
166160157Smarcel#define ELF_ERR_READ_SECTHDR	UWX_ERR_NOSYM  /* Can't read section headers */
167160157Smarcel#define ELF_ERR_SECTHDR_SIZE	UWX_ERR_NOSYM  /* Invalid e_shentsize */
168160157Smarcel
169160157Smarcel#define ELF_ERR_READ_PROGHDR	UWX_ERR_NOSYM  /* Can't read program headers */
170160157Smarcel#define ELF_ERR_PROGHDR_SIZE	UWX_ERR_NOSYM  /* Invalid e_phentsize */
171160157Smarcel
172160157Smarcel#define ELF_ERR_READ_SECTION	UWX_ERR_NOSYM  /* Can't read section contents */
173160157Smarcel
174160157Smarcel#define ELF_ERR_READ_SYMTAB	UWX_ERR_NOSYM  /* Can't read symbol table */
175160157Smarcel#define ELF_ERR_SYMTAB_SIZE	UWX_ERR_NOSYM  /* Invalid sh_entsize for symtab */
176160157Smarcel
177160157Smarcel
178160157Smarcelstruct elf_file {
179160157Smarcel    uint64_t phoff;
180160157Smarcel    uint64_t shoff;
181160157Smarcel    uint64_t text_base;
182160157Smarcel    uint64_t text_end;
183160157Smarcel    alloc_cb allocate_cb;
184160157Smarcel    free_cb free_cb;
185160157Smarcel    const char *filename;
186160157Smarcel    FILE *fd;
187160157Smarcel    struct elf_section *sections;
188160157Smarcel    struct elf_symbol *symbols;
189160157Smarcel    char *symbol_strings;
190160157Smarcel    int native_data;
191160157Smarcel    int source_class;
192160157Smarcel    int source_data;
193160157Smarcel    int ehsize;
194160157Smarcel    int phentsize;
195160157Smarcel    int phnum;
196160157Smarcel    int shentsize;
197160157Smarcel    int shnum;
198160157Smarcel    int nsyms;
199160157Smarcel};
200160157Smarcel
201160157Smarcelstruct elf_section {
202160157Smarcel    uint64_t flags;
203160157Smarcel    uint64_t addr;
204160157Smarcel    uint64_t offset;
205160157Smarcel    uint64_t size;
206160157Smarcel    uint64_t entsize;
207160157Smarcel    char *contents;
208160157Smarcel    struct elf_symbol *symbols;
209160157Smarcel    int type;
210160157Smarcel    int link;
211160157Smarcel    int info;
212160157Smarcel    int nelems;
213160157Smarcel};
214160157Smarcel
215160157Smarcelstruct elf_symbol {
216160157Smarcel    uint64_t value;
217160157Smarcel    char *namep;
218160157Smarcel    int name;
219160157Smarcel    int type;
220160157Smarcel    int shndx;
221160157Smarcel};
222160157Smarcel
223160157Smarcel
224160157Smarcelstatic void elf_swap_bytes(char *buf, char *template)
225160157Smarcel{
226160157Smarcel    int i;
227160157Smarcel    int sz;
228160157Smarcel    char temp[16];
229160157Smarcel
230160157Smarcel    while (sz = *template++) {
231160157Smarcel	if (sz > 16)
232160157Smarcel	    exit(1);
233160157Smarcel	for (i = 0; i < sz; i++)
234160157Smarcel	    temp[i] = buf[i];
235160157Smarcel	for (i = 0; i < sz; i++)
236160157Smarcel	    buf[i] = temp[sz-i-1];
237160157Smarcel	buf += sz;
238160157Smarcel    }
239160157Smarcel}
240160157Smarcel
241160157Smarcel
242160157Smarcelstatic int elf_read_section(struct elf_file *ef, int shndx)
243160157Smarcel{
244160157Smarcel    struct elf_section *sect;
245160157Smarcel
246160157Smarcel    if (shndx < 0 || shndx > ef->shnum)
247160157Smarcel	return 0;
248160157Smarcel
249160157Smarcel    sect = &ef->sections[shndx];
250160157Smarcel
251160157Smarcel    /* Return if section has already been read */
252160157Smarcel    if (sect->contents != NULL)
253160157Smarcel	return 0;
254160157Smarcel
255160157Smarcel    sect->contents = (*ef->allocate_cb)(sect->size);
256160157Smarcel    if (sect->contents == NULL)
257160157Smarcel	return ELF_ERR_NOMEM;
258160157Smarcel
259160157Smarcel    fseek(ef->fd, (long)sect->offset, SEEK_SET);
260160157Smarcel    if (fread(sect->contents, 1, sect->size, ef->fd) != sect->size)
261160157Smarcel	return ELF_ERR_READ_SECTION;
262160157Smarcel
263160157Smarcel    return 0;
264160157Smarcel}
265160157Smarcel
266160157Smarcel
267160157Smarcelstatic char template_elf32_sym[] = {4, 4, 4, 1, 1, 2, 0};
268160157Smarcelstatic char template_elf64_sym[] = {4, 1, 1, 2, 8, 8, 0};
269160157Smarcel
270160157Smarcelstatic int elf_read_symtab_section(struct elf_file *ef, int shndx)
271160157Smarcel{
272160157Smarcel    int i;
273160157Smarcel    int nsyms;
274160157Smarcel    long size;
275160157Smarcel    union {
276160157Smarcel	Elf32_Sym sym32;
277160157Smarcel	Elf64_Sym sym64;
278160157Smarcel    } sym;
279160157Smarcel    struct elf_section *sect;
280160157Smarcel    struct elf_symbol *syms;
281160157Smarcel    struct elf_symbol *symp;
282160157Smarcel    char *strtab;
283160157Smarcel
284160157Smarcel    sect = &ef->sections[shndx];
285160157Smarcel
286160157Smarcel    /* Return if section has already been read */
287160157Smarcel    if (sect->symbols != NULL)
288160157Smarcel	return 0;
289160157Smarcel
290160157Smarcel    if (ef->source_class == ELFCLASS32) {
291160157Smarcel	if (sect->entsize != sizeof(sym.sym32))
292160157Smarcel	    return ELF_ERR_SYMTAB_SIZE;
293160157Smarcel    }
294160157Smarcel    else {
295160157Smarcel	if (sect->entsize != sizeof(sym.sym64))
296160157Smarcel	    return ELF_ERR_SYMTAB_SIZE;
297160157Smarcel    }
298160157Smarcel
299160157Smarcel    nsyms = sect->nelems;
300160157Smarcel    syms = (struct elf_symbol *)
301160157Smarcel			(*ef->allocate_cb)(sizeof(struct elf_symbol) * nsyms);
302160157Smarcel    if (syms == NULL)
303160157Smarcel	return ELF_ERR_NOMEM;
304160157Smarcel
305160157Smarcel    /* Read the symbol table */
306160157Smarcel    fseek(ef->fd, (long)sect->offset, SEEK_SET);
307160157Smarcel    for (i = 0; i < nsyms; i++) {
308160157Smarcel
309160157Smarcel	symp = &syms[i];
310160157Smarcel
311160157Smarcel	/* Read the next symbol table entry */
312160157Smarcel	if (fread((char *)&sym, sect->entsize, 1, ef->fd) != 1) {
313160157Smarcel	    (*ef->free_cb)(syms);
314160157Smarcel	    return ELF_ERR_READ_SYMTAB;
315160157Smarcel	}
316160157Smarcel
317160157Smarcel	/* Get fields from appropriate structure */
318160157Smarcel	if (ef->source_class == ELFCLASS32) {
319160157Smarcel	    /* Swap bytes if necessary */
320160157Smarcel	    if (ef->source_data != ef->native_data)
321160157Smarcel		elf_swap_bytes((char *)&sym, template_elf32_sym);
322160157Smarcel	    symp->name = sym.sym32.st_name;
323160157Smarcel	    symp->type = sym.sym32.st_info & 0x0f;
324160157Smarcel	    symp->shndx = sym.sym32.st_shndx;
325160157Smarcel	    symp->value = sym.sym32.st_value;
326160157Smarcel	}
327160157Smarcel	else {
328160157Smarcel	    /* Swap bytes if necessary */
329160157Smarcel	    if (ef->source_data != ef->native_data)
330160157Smarcel		elf_swap_bytes((char *)&sym, template_elf64_sym);
331160157Smarcel	    symp->name = sym.sym64.st_name;
332160157Smarcel	    symp->type = sym.sym64.st_info & 0x0f;
333160157Smarcel	    symp->shndx = sym.sym64.st_shndx;
334160157Smarcel	    symp->value = sym.sym64.st_value;
335160157Smarcel	}
336160157Smarcel	symp->namep = NULL;
337160157Smarcel
338160157Smarcel    }
339160157Smarcel
340160157Smarcel    /* Read the symbol string table and convert section names */
341160157Smarcel    /* from string table offsets to pointers */
342160157Smarcel    if (sect->link > 0 && sect->link < ef->shnum) {
343160157Smarcel	if (elf_read_section(ef, sect->link) == 0) {
344160157Smarcel	    strtab = ef->sections[sect->link].contents;
345160157Smarcel	    for (i = 0; i < nsyms; i++) {
346160157Smarcel		symp = &syms[i];
347160157Smarcel		symp->namep = strtab + symp->name;
348160157Smarcel	    }
349160157Smarcel	    ef->symbol_strings = strtab;
350160157Smarcel	    ef->sections[sect->link].contents = NULL;
351160157Smarcel	}
352160157Smarcel    }
353160157Smarcel
354160157Smarcel    sect->symbols = syms;
355160157Smarcel    return 0;
356160157Smarcel}
357160157Smarcel
358160157Smarcel
359160157Smarcelstatic char template_elf32_phdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 0};
360160157Smarcelstatic char template_elf64_phdr[] = {4, 4, 8, 8, 8, 8, 8, 8, 0};
361160157Smarcel
362160157Smarcelstatic int elf_read_prog_hdrs(struct elf_file *ef)
363160157Smarcel{
364160157Smarcel    int i;
365160157Smarcel    union {
366160157Smarcel	Elf32_Phdr hdr32;
367160157Smarcel	Elf64_Phdr hdr64;
368160157Smarcel    } header;
369160157Smarcel    uint64_t vaddr;
370160157Smarcel    uint64_t memsz;
371160157Smarcel    uint64_t unwind_base;
372160157Smarcel    int type;
373160157Smarcel
374160157Smarcel    if (ef->phnum == 0)
375160157Smarcel	return 0;
376160157Smarcel
377160157Smarcel    if (ef->source_class == ELFCLASS32) {
378160157Smarcel	if (ef->phentsize != sizeof(header.hdr32))
379160157Smarcel	    return ELF_ERR_PROGHDR_SIZE;
380160157Smarcel    }
381160157Smarcel    else {
382160157Smarcel	if (ef->phentsize != sizeof(header.hdr64))
383160157Smarcel	    return ELF_ERR_PROGHDR_SIZE;
384160157Smarcel    }
385160157Smarcel
386160157Smarcel    /* Look for the PT_IA_64_UNWIND segment */
387160157Smarcel    /* (That will help us identify the text segment) */
388160157Smarcel
389160157Smarcel    fseek(ef->fd, (long)ef->phoff, SEEK_SET);
390160157Smarcel    for (i = 0; i < ef->phnum; i++) {
391160157Smarcel
392160157Smarcel	/* Read the next program header */
393160157Smarcel	if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
394160157Smarcel	    return ELF_ERR_READ_PROGHDR;
395160157Smarcel
396160157Smarcel	/* Get fields from appropriate structure */
397160157Smarcel	if (ef->source_class == ELFCLASS32) {
398160157Smarcel	    /* Swap bytes in header fields if necessary */
399160157Smarcel	    if (ef->source_data != ef->native_data)
400160157Smarcel		elf_swap_bytes((char *)&header, template_elf32_phdr);
401160157Smarcel	    type = header.hdr32.p_type;
402160157Smarcel	    vaddr = header.hdr32.p_vaddr;
403160157Smarcel	}
404160157Smarcel	else {
405160157Smarcel	    /* Swap bytes in header fields if necessary */
406160157Smarcel	    if (ef->source_data != ef->native_data)
407160157Smarcel		elf_swap_bytes((char *)&header, template_elf64_phdr);
408160157Smarcel	    type = header.hdr64.p_type;
409160157Smarcel	    vaddr = header.hdr64.p_vaddr;
410160157Smarcel	}
411160157Smarcel
412160157Smarcel	if (type == PT_IA_64_UNWIND) {
413160157Smarcel	    unwind_base = vaddr;
414160157Smarcel	    break;
415160157Smarcel	}
416160157Smarcel
417160157Smarcel    }
418160157Smarcel
419160157Smarcel    /* Now look for the PT_LOAD segment that includes the unwind segment */
420160157Smarcel
421160157Smarcel    fseek(ef->fd, (long)ef->phoff, SEEK_SET);
422160157Smarcel    for (i = 0; i < ef->phnum; i++) {
423160157Smarcel
424160157Smarcel	/* Read the next program header */
425160157Smarcel	if (fread((char *)&header, ef->phentsize, 1, ef->fd) != 1)
426160157Smarcel	    return ELF_ERR_READ_PROGHDR;
427160157Smarcel
428160157Smarcel	/* Get fields from appropriate structure */
429160157Smarcel	if (ef->source_class == ELFCLASS32) {
430160157Smarcel	    /* Swap bytes in header fields if necessary */
431160157Smarcel	    if (ef->source_data != ef->native_data)
432160157Smarcel		elf_swap_bytes((char *)&header, template_elf32_phdr);
433160157Smarcel	    type = header.hdr32.p_type;
434160157Smarcel	    vaddr = header.hdr32.p_vaddr;
435160157Smarcel	    memsz = header.hdr32.p_memsz;
436160157Smarcel	}
437160157Smarcel	else {
438160157Smarcel	    /* Swap bytes in header fields if necessary */
439160157Smarcel	    if (ef->source_data != ef->native_data)
440160157Smarcel		elf_swap_bytes((char *)&header, template_elf64_phdr);
441160157Smarcel	    type = header.hdr64.p_type;
442160157Smarcel	    vaddr = header.hdr64.p_vaddr;
443160157Smarcel	    memsz = header.hdr64.p_memsz;
444160157Smarcel	}
445160157Smarcel
446160157Smarcel	if (type == PT_LOAD &&
447160157Smarcel		vaddr <= unwind_base && unwind_base < vaddr + memsz) {
448160157Smarcel	    ef->text_base = vaddr;
449160157Smarcel	    ef->text_end = vaddr + memsz;
450160157Smarcel	    break;
451160157Smarcel	}
452160157Smarcel
453160157Smarcel    }
454160157Smarcel
455160157Smarcel    return 0;
456160157Smarcel}
457160157Smarcel
458160157Smarcel
459160157Smarcelstatic char template_elf32_shdr[] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0};
460160157Smarcelstatic char template_elf64_shdr[] = {4, 4, 8, 8, 8, 8, 4, 4, 8, 8, 0};
461160157Smarcel
462160157Smarcelstatic int elf_read_sect_hdrs(struct elf_file *ef)
463160157Smarcel{
464160157Smarcel    int i;
465160157Smarcel    long size;
466160157Smarcel    int err;
467160157Smarcel    union {
468160157Smarcel	Elf32_Shdr hdr32;
469160157Smarcel	Elf64_Shdr hdr64;
470160157Smarcel    } header;
471160157Smarcel    struct elf_section *sect;
472160157Smarcel    char *shstrtab;
473160157Smarcel
474160157Smarcel    if (ef->source_class == ELFCLASS32) {
475160157Smarcel	if (ef->shentsize != sizeof(header.hdr32))
476160157Smarcel	    return ELF_ERR_SECTHDR_SIZE;
477160157Smarcel    }
478160157Smarcel    else {
479160157Smarcel	if (ef->shentsize != sizeof(header.hdr64))
480160157Smarcel	    return ELF_ERR_SECTHDR_SIZE;
481160157Smarcel    }
482160157Smarcel
483160157Smarcel    fseek(ef->fd, (long)ef->shoff, SEEK_SET);
484160157Smarcel    ef->sections = (struct elf_section *)
485160157Smarcel		    (*ef->allocate_cb)(sizeof(struct elf_section) * ef->shnum);
486160157Smarcel    if (ef->sections == NULL)
487160157Smarcel	return ELF_ERR_NOMEM;
488160157Smarcel
489160157Smarcel    /* Read the section header table */
490160157Smarcel    for (i = 0; i < ef->shnum; i++) {
491160157Smarcel
492160157Smarcel	sect = &ef->sections[i];
493160157Smarcel
494160157Smarcel	/* Read the next section header */
495160157Smarcel	if (fread((char *)&header, ef->shentsize, 1, ef->fd) != 1) {
496160157Smarcel	    (*ef->free_cb)(ef->sections);
497160157Smarcel	    return ELF_ERR_READ_SECTHDR;
498160157Smarcel	}
499160157Smarcel
500160157Smarcel	/* Get fields from appropriate structure */
501160157Smarcel	if (ef->source_class == ELFCLASS32) {
502160157Smarcel	    /* Swap bytes in header fields if necessary */
503160157Smarcel	    if (ef->source_data != ef->native_data)
504160157Smarcel		elf_swap_bytes((char *)&header, template_elf32_shdr);
505160157Smarcel	    sect->type = header.hdr32.sh_type;
506160157Smarcel	    sect->flags = header.hdr32.sh_flags;
507160157Smarcel	    sect->addr = header.hdr32.sh_addr;
508160157Smarcel	    sect->offset = header.hdr32.sh_offset;
509160157Smarcel	    sect->size = header.hdr32.sh_size;
510160157Smarcel	    sect->link = header.hdr32.sh_link;
511160157Smarcel	    sect->info = header.hdr32.sh_info;
512160157Smarcel	    sect->entsize = header.hdr32.sh_entsize;
513160157Smarcel	}
514160157Smarcel	else {
515160157Smarcel	    /* Swap bytes in header fields if necessary */
516160157Smarcel	    if (ef->source_data != ef->native_data)
517160157Smarcel		elf_swap_bytes((char *)&header, template_elf64_shdr);
518160157Smarcel	    sect->type = header.hdr64.sh_type;
519160157Smarcel	    sect->flags = header.hdr64.sh_flags;
520160157Smarcel	    sect->addr = header.hdr64.sh_addr;
521160157Smarcel	    sect->offset = header.hdr64.sh_offset;
522160157Smarcel	    sect->size = header.hdr64.sh_size;
523160157Smarcel	    sect->link = header.hdr64.sh_link;
524160157Smarcel	    sect->info = header.hdr64.sh_info;
525160157Smarcel	    sect->entsize = header.hdr64.sh_entsize;
526160157Smarcel	}
527160157Smarcel	sect->contents = NULL;
528160157Smarcel	sect->symbols = NULL;
529160157Smarcel	if (sect->entsize > 0)
530160157Smarcel	    sect->nelems = sect->size / sect->entsize;
531160157Smarcel
532160157Smarcel    }
533160157Smarcel
534160157Smarcel    return 0;
535160157Smarcel}
536160157Smarcel
537160157Smarcel
538160157Smarcelstatic char template_elf32_ehdr[] = {2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 0};
539160157Smarcelstatic char template_elf64_ehdr[] = {2, 2, 4, 8, 8, 8, 4, 2, 2, 2, 2, 2, 2, 0};
540160157Smarcel
541160157Smarcelstatic int elf_read_header(struct elf_file *ef)
542160157Smarcel{
543160157Smarcel    union {
544160157Smarcel	char ident[EI_NIDENT];
545160157Smarcel	Elf32_Ehdr hdr32;
546160157Smarcel	Elf64_Ehdr hdr64;
547160157Smarcel    } header;
548160157Smarcel
549160157Smarcel    /* Read the ELF header */
550160157Smarcel    fseek(ef->fd, 0L, SEEK_SET);
551160157Smarcel    if (fread((char *)header.ident, EI_NIDENT, 1, ef->fd) != 1) {
552160157Smarcel	return ELF_ERR_NOHEADER;
553160157Smarcel    }
554160157Smarcel
555160157Smarcel    /* Verify that this is an ELF file */
556160157Smarcel    if (header.ident[EI_MAG0] != ELFMAG0 ||
557160157Smarcel	header.ident[EI_MAG1] != ELFMAG1 ||
558160157Smarcel	header.ident[EI_MAG2] != ELFMAG2 ||
559160157Smarcel	header.ident[EI_MAG3] != ELFMAG3) {
560160157Smarcel	return ELF_ERR_NOTELF;
561160157Smarcel    }
562160157Smarcel
563160157Smarcel    /* Get header fields from the byte array e_ident */
564160157Smarcel    /* (These are independent of EI_CLASS and EI_DATA) */
565160157Smarcel    ef->source_class = header.ident[EI_CLASS];
566160157Smarcel    ef->source_data = header.ident[EI_DATA];
567160157Smarcel
568160157Smarcel    /* Verify EI_CLASS and EI_DATA */
569160157Smarcel    if (header.ident[EI_CLASS] != ELFCLASS32 &&
570160157Smarcel	header.ident[EI_CLASS] != ELFCLASS64) {
571160157Smarcel	return ELF_ERR_INVALID_CLASS;
572160157Smarcel    }
573160157Smarcel    if (header.ident[EI_DATA] != ELFDATA2LSB &&
574160157Smarcel	header.ident[EI_DATA] != ELFDATA2MSB) {
575160157Smarcel	return ELF_ERR_INVALID_DATA;
576160157Smarcel    }
577160157Smarcel
578160157Smarcel    /* Get remaining header fields from appropriate structure */
579160157Smarcel    if (ef->source_class == ELFCLASS32) {
580160157Smarcel	if (fread((char *)&header.hdr32 + EI_NIDENT,
581160157Smarcel			sizeof(header.hdr32) - EI_NIDENT, 1, ef->fd) != 1)
582160157Smarcel	    return ELF_ERR_NOHEADER;
583160157Smarcel	/* Swap bytes in header fields if necessary */
584160157Smarcel	if (ef->source_data != ef->native_data)
585160157Smarcel	    elf_swap_bytes((char *)&header + EI_NIDENT, template_elf32_ehdr);
586160157Smarcel	ef->phoff = header.hdr32.e_phoff;
587160157Smarcel	ef->shoff = header.hdr32.e_shoff;
588160157Smarcel	ef->ehsize = header.hdr32.e_ehsize;
589160157Smarcel	ef->phentsize = header.hdr32.e_phentsize;
590160157Smarcel	ef->phnum = header.hdr32.e_phnum;
591160157Smarcel	ef->shentsize = header.hdr32.e_shentsize;
592160157Smarcel	ef->shnum = header.hdr32.e_shnum;
593160157Smarcel	if (ef->ehsize != sizeof(header.hdr32)) {
594160157Smarcel	    return ELF_ERR_HEADER_SIZE;
595160157Smarcel	}
596160157Smarcel    }
597160157Smarcel    else {
598160157Smarcel	if (fread((char *)&header.hdr64 + EI_NIDENT,
599160157Smarcel			sizeof(header.hdr64) - EI_NIDENT, 1, ef->fd) != 1)
600160157Smarcel	    return ELF_ERR_NOHEADER;
601160157Smarcel	/* Swap bytes in header fields if necessary */
602160157Smarcel	if (ef->source_data != ef->native_data)
603160157Smarcel	    elf_swap_bytes((char *)&header + EI_NIDENT, template_elf64_ehdr);
604160157Smarcel	ef->phoff = header.hdr64.e_phoff;
605160157Smarcel	ef->shoff = header.hdr64.e_shoff;
606160157Smarcel	ef->ehsize = header.hdr64.e_ehsize;
607160157Smarcel	ef->phentsize = header.hdr64.e_phentsize;
608160157Smarcel	ef->phnum = header.hdr64.e_phnum;
609160157Smarcel	ef->shentsize = header.hdr64.e_shentsize;
610160157Smarcel	ef->shnum = header.hdr64.e_shnum;
611160157Smarcel	if (ef->ehsize != sizeof(header.hdr64)) {
612160157Smarcel	    return ELF_ERR_HEADER_SIZE;
613160157Smarcel	}
614160157Smarcel    }
615160157Smarcel
616160157Smarcel    return 0;
617160157Smarcel}
618160157Smarcel
619160157Smarcel
620160157Smarcelstatic struct elf_file *elf_new(struct uwx_env *env)
621160157Smarcel{
622160157Smarcel    int native_be;
623160157Smarcel    char *p;
624160157Smarcel    struct elf_file *ef;
625160157Smarcel
626160157Smarcel    ef = (struct elf_file *)(*env->allocate_cb)(sizeof(struct elf_file));
627160157Smarcel    if (ef == NULL)
628160157Smarcel	return NULL;
629160157Smarcel
630160157Smarcel    /* Determine the native byte order */
631160157Smarcel    p = (char *)&native_be;
632160157Smarcel    native_be = 1;	/* Assume big-endian */
633160157Smarcel    *p = 0;		/* Sets be == 0 only if little-endian */
634160157Smarcel
635160157Smarcel    ef->allocate_cb = env->allocate_cb;
636160157Smarcel    ef->free_cb = env->free_cb;
637160157Smarcel    ef->filename = NULL;
638160157Smarcel    ef->native_data = (native_be ? ELFDATA2MSB : ELFDATA2LSB);
639160157Smarcel    ef->fd = NULL;
640160157Smarcel    ef->source_class = 0;
641160157Smarcel    ef->source_data = 0;
642160157Smarcel    ef->phoff = 0;
643160157Smarcel    ef->shoff = 0;
644160157Smarcel    ef->text_base = 0;
645160157Smarcel    ef->text_end = 0;
646160157Smarcel    ef->ehsize = 0;
647160157Smarcel    ef->phentsize = 0;
648160157Smarcel    ef->phnum = 0;
649160157Smarcel    ef->shentsize = 0;
650160157Smarcel    ef->shnum = 0;
651160157Smarcel    ef->sections = NULL;
652160157Smarcel    ef->symbols = NULL;
653160157Smarcel    ef->symbol_strings = NULL;
654160157Smarcel    ef->nsyms = 0;
655160157Smarcel    return ef;
656160157Smarcel}
657160157Smarcel
658160157Smarcel
659160157Smarcelstatic int elf_open(struct elf_file *ef, const char *filename)
660160157Smarcel{
661160157Smarcel    int err;
662160157Smarcel
663160157Smarcel    ef->filename = filename;
664160157Smarcel
665160157Smarcel    ef->fd = fopen(filename, "r");
666160157Smarcel    if (ef->fd == NULL)
667160157Smarcel	return ELF_ERR_OPEN;
668160157Smarcel
669160157Smarcel    if ((err = elf_read_header(ef)) != 0)
670160157Smarcel	return err;
671160157Smarcel
672160157Smarcel    if ((err = elf_read_sect_hdrs(ef)) != 0)
673160157Smarcel	return err;
674160157Smarcel
675160157Smarcel    if ((err = elf_read_prog_hdrs(ef)) != 0)
676160157Smarcel	return err;
677160157Smarcel
678160157Smarcel    return 0;
679160157Smarcel}
680160157Smarcel
681160157Smarcel
682160157Smarcelstatic void elf_free_sections(struct elf_file *ef)
683160157Smarcel{
684160157Smarcel    int i;
685160157Smarcel    struct elf_section *sect;
686160157Smarcel
687160157Smarcel    for (i = 0; i < ef->shnum; i++) {
688160157Smarcel	sect = &ef->sections[i];
689160157Smarcel	if (sect->contents != NULL)
690160157Smarcel	    (*ef->free_cb)(sect->contents);
691160157Smarcel	if ((sect->type == SHT_SYMTAB || sect->type == SHT_DYNSYM)
692160157Smarcel						&& sect->symbols != NULL)
693160157Smarcel	    (*ef->free_cb)(sect->symbols);
694160157Smarcel    }
695160157Smarcel    (*ef->free_cb)(ef->sections);
696160157Smarcel}
697160157Smarcel
698160157Smarcel
699160157Smarcelstatic void elf_close(struct elf_file *ef)
700160157Smarcel{
701160157Smarcel    if (ef->fd != NULL) {
702160157Smarcel	fclose(ef->fd);
703160157Smarcel	ef->fd = NULL;
704160157Smarcel    }
705160157Smarcel}
706160157Smarcel
707160157Smarcel
708160157Smarcelstatic void elf_free(struct elf_file *ef)
709160157Smarcel{
710160157Smarcel    elf_close(ef);
711160157Smarcel    if (ef->sections != NULL)
712160157Smarcel	elf_free_sections(ef);
713160157Smarcel    (*ef->free_cb)(ef);
714160157Smarcel}
715160157Smarcel
716160157Smarcel
717160157Smarcelstatic int elf_read_symbols(struct elf_file *ef)
718160157Smarcel{
719160157Smarcel    int i;
720160157Smarcel    int err;
721160157Smarcel    struct elf_section *sect;
722160157Smarcel
723160157Smarcel    for (i = 1; i < ef->shnum; i++) {
724160157Smarcel	sect = &ef->sections[i];
725160157Smarcel	if (sect->type == SHT_SYMTAB) {
726160157Smarcel	    if (elf_read_symtab_section(ef, i) == 0) {
727160157Smarcel		ef->symbols = sect->symbols;
728160157Smarcel		ef->nsyms = sect->nelems;
729160157Smarcel#ifdef DEBUG_SYMBOLS
730160157Smarcel		printf("Read %d symbols from SHT_SYMTAB section\n", ef->nsyms);
731160157Smarcel#endif /* DEBUG_SYMBOLS */
732160157Smarcel		return 0;
733160157Smarcel	    }
734160157Smarcel	}
735160157Smarcel    }
736160157Smarcel    for (i = 1; i < ef->shnum; i++) {
737160157Smarcel	sect = &ef->sections[i];
738160157Smarcel	if (sect->type == SHT_DYNSYM) {
739160157Smarcel	    if (elf_read_symtab_section(ef, i) == 0) {
740160157Smarcel		ef->symbols = sect->symbols;
741160157Smarcel		ef->nsyms = sect->nelems;
742160157Smarcel#ifdef DEBUG_SYMBOLS
743160157Smarcel		printf("Read %d symbols from SHT_DYNSYM section\n", ef->nsyms);
744160157Smarcel#endif /* DEBUG_SYMBOLS */
745160157Smarcel		return 0;
746160157Smarcel	    }
747160157Smarcel	}
748160157Smarcel    }
749160157Smarcel    return UWX_ERR_NOSYM;
750160157Smarcel}
751160157Smarcel
752160157Smarcel
753160157Smarcel#define SYM_IS_DEFINED(sym) \
754160157Smarcel		((sym)->shndx != SHN_UNDEF)
755160157Smarcel
756160157Smarcel#define SYM_IS_IN_TEXT_SEGMENT(value) \
757160157Smarcel		((value) >= ef->text_base && (value) < ef->text_end)
758160157Smarcel
759160157Smarcel#define SYM_HAS_INTERESTING_TYPE(type) ( \
760160157Smarcel		(type) == STT_FUNC || \
761160157Smarcel		(type) == STT_OBJECT || \
762160157Smarcel		(type) == STT_HP_STUB \
763160157Smarcel		)
764160157Smarcel
765160157Smarcel#define SYM_IS_INTERESTING(sym) ( \
766160157Smarcel		SYM_IS_DEFINED(sym) && \
767160157Smarcel		SYM_IS_IN_TEXT_SEGMENT((sym)->value) && \
768160157Smarcel		SYM_HAS_INTERESTING_TYPE((sym)->type) \
769160157Smarcel		)
770160157Smarcel
771160157Smarcelint uwx_read_func_symbols(
772160157Smarcel    struct uwx_env *env,
773160157Smarcel    struct uwx_symbol_cache *cache,
774160157Smarcel    char *module_name)
775160157Smarcel{
776160157Smarcel    int i, j;
777160157Smarcel    int status;
778160157Smarcel    struct elf_file *ef;
779160157Smarcel    struct elf_symbol *sym;
780160157Smarcel    int nfuncsyms;
781160157Smarcel    char **names;
782160157Smarcel    uint64_t *values;
783160157Smarcel
784160157Smarcel    if (module_name != NULL &&
785160157Smarcel	    cache->module_name != NULL &&
786160157Smarcel		strcmp(module_name, cache->module_name) == 0)
787160157Smarcel	return UWX_OK;
788160157Smarcel
789160157Smarcel    if (cache->sym_names != NULL)
790160157Smarcel	(*env->free_cb)(cache->sym_names);
791160157Smarcel    if (cache->sym_values != NULL)
792160157Smarcel	(*env->free_cb)(cache->sym_values);
793160157Smarcel    if (cache->strings != NULL)
794160157Smarcel	(*env->free_cb)(cache->strings);
795160157Smarcel
796160157Smarcel    ef = elf_new(env);
797160157Smarcel    if (ef == NULL)
798160157Smarcel	return UWX_ERR_NOMEM;
799160157Smarcel    status = elf_open(ef, module_name);
800160157Smarcel    if (status != 0)
801160157Smarcel	return UWX_ERR_NOSYM;
802160157Smarcel    status = elf_read_symbols(ef);
803160157Smarcel    if (status != 0)
804160157Smarcel	return UWX_ERR_NOSYM;
805160157Smarcel
806160157Smarcel    nfuncsyms = 0;
807160157Smarcel    for (i = 0; i < ef->nsyms; i++) {
808160157Smarcel	sym = &ef->symbols[i];
809160157Smarcel	if (SYM_IS_INTERESTING(sym))
810160157Smarcel	    nfuncsyms++;
811160157Smarcel    }
812160157Smarcel
813160157Smarcel    names = (char **)(*env->allocate_cb)(nfuncsyms * sizeof(char *));
814160157Smarcel    if (names == NULL)
815160157Smarcel	return UWX_ERR_NOMEM;
816160157Smarcel    values = (uint64_t *)(*env->allocate_cb)(nfuncsyms * sizeof(uint64_t));
817160157Smarcel    if (values == NULL)
818160157Smarcel	return UWX_ERR_NOMEM;
819160157Smarcel
820160157Smarcel    j = 0;
821160157Smarcel    for (i = 0; i < ef->nsyms; i++) {
822160157Smarcel	sym = &ef->symbols[i];
823160157Smarcel	if (SYM_IS_INTERESTING(sym)) {
824160157Smarcel	    if (j >= nfuncsyms) /* should not happen! */
825160157Smarcel		break;
826160157Smarcel	    names[j] = sym->namep;
827160157Smarcel	    values[j] = sym->value - ef->text_base;
828160157Smarcel	    j++;
829160157Smarcel	}
830160157Smarcel    }
831160157Smarcel
832160157Smarcel    cache->module_name = (char *)(*env->allocate_cb)(strlen(module_name)+1);
833160157Smarcel    if (cache->module_name != NULL) {
834160157Smarcel	strcpy(cache->module_name, module_name);
835160157Smarcel	cache->nsyms = nfuncsyms;
836160157Smarcel	cache->sym_names = names;
837160157Smarcel	cache->sym_values = values;
838160157Smarcel	cache->strings = ef->symbol_strings;
839160157Smarcel	ef->symbol_strings = NULL;
840160157Smarcel    }
841160157Smarcel
842160157Smarcel    elf_close(ef);
843160157Smarcel    elf_free(ef);
844160157Smarcel
845160157Smarcel#ifdef DEBUG_SYMBOLS
846160157Smarcel    printf("Cached %d interesting symbols\n", nfuncsyms);
847160157Smarcel#endif /* DEBUG_SYMBOLS */
848160157Smarcel
849160157Smarcel    return UWX_OK;
850160157Smarcel}
851