/* * MIPS doesn't have traditional got.plt entries with corresponding * relocations. * * sym_index is an offset into the external GOT entries. Filter out * stuff that are not functions. */ int arch_get_sym_info(struct ltelf *lte, const char *filename, size_t sym_index, GElf_Rela *rela, GElf_Sym *sym) { const char *name; if (mips_elf_is_cpic(lte->ehdr.e_flags)) { return elf_get_sym_info(lte, filename, sym_index, rela, sym); } /* Fixup the offset. */ sym_index += lte->arch.mips_gotsym; if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL){ error(EXIT_FAILURE, 0, "Couldn't get relocation from \"%s\"", filename); } name = lte->dynstr + sym->st_name; if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) { debug(2, "sym %s not a function", name); return -1; } return 0; }
static uint_t dt_module_syminit64(dt_module_t *dmp) { const Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) asrsv++; /* reserve space in the address map */ dt_module_symhash_insert(dmp, name, i); } return (asrsv); }
static SYM64 * read_64_syms(Elf64_Sym *data, size_t num, Elf *elf, Elf64_Word link) { #ifdef HAVE_ELF64_GETEHDR SYM64 *s, *buf; size_t i; if( (buf = (SYM64 *)calloc(num, sizeof(SYM64)) ) == NULL) { return NULL; } s = buf; /* save pointer to head of array */ for(i=1; i<num; i++,data++,buf++) { buf->indx = i; buf->name = (char *)elf_strptr(elf, link, data->st_name); buf->value = data->st_value; buf->size = data->st_size; buf->type = ELF64_ST_TYPE(data->st_info); buf->bind = ELF64_ST_BIND(data->st_info); buf->other = data->st_other; buf->shndx = data->st_shndx; } /* end for loop */ return(s); #else return 0; #endif /* HAVE_ELF64_GETEHDR */ }
int prepare_mod_for_load(struct LKM_Module *lkm_mod, int sym_index, int str_index) { int i,ret=0, flag=0; struct Secthdr *secthdr = lkm_mod->sect_hdr; struct Symhdr *tsymhdr,*symhdr = (void *)(lkm_mod->tmp_buf + secthdr[sym_index].sh_offset); tsymhdr = symhdr; char *sttab = (void *)(lkm_mod->tmp_buf + secthdr[str_index].sh_offset); size_t sym_size = secthdr[sym_index].sh_size / (sizeof(struct Symhdr)); i=0; while(i < sym_size){ if(ELF64_ST_TYPE(tsymhdr->st_info) == STT_FUNC){ if((ret = strcmp("lkm_init", sttab + tsymhdr->st_name)) == 0){ modules_lkm[mod_num].init_mod = (void (*) (void))lkm_mod->text_addr + tsymhdr->st_value; flag++; }else if((ret = strcmp("lkm_exit", sttab + tsymhdr->st_name)) == 0){ modules_lkm[mod_num].unload_mod = (void (*) (void))lkm_mod->text_addr + tsymhdr->st_value; flag++; }else if((ret = strlen(sttab + tsymhdr->st_name)) != 0){ insert_symbol(sttab + tsymhdr->st_name, (uintptr_t)(lkm_mod->text_addr + tsymhdr->st_value), modules_lkm[mod_num].name); // cprintf("Inserting Symbol Name : %s Symbol addr: %x \n", sttab + tsymhdr->st_name, (uintptr_t)(lkm_mod->text_addr + tsymhdr->st_value)); } } i++; tsymhdr++; } if(flag != 2) return -1; return 0; }
/* * Given a symbol table index, return the type of the data object described * by the corresponding entry in the symbol table. */ ctf_id_t ctf_lookup_by_symbol(ctf_file_t *fp, ulong_t symidx) { const ctf_sect_t *sp = &fp->ctf_symtab; ctf_id_t type; if (sp->cts_data == NULL) return (ctf_set_errno(fp, ECTF_NOSYMTAB)); if (symidx >= fp->ctf_nsyms) return (ctf_set_errno(fp, EINVAL)); if (sp->cts_entsize == sizeof (Elf32_Sym)) { const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx; if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT) return (ctf_set_errno(fp, ECTF_NOTDATA)); } else { const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx; if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT) return (ctf_set_errno(fp, ECTF_NOTDATA)); } if (fp->ctf_sxlate[symidx] == -1u) return (ctf_set_errno(fp, ECTF_NOTYPEDAT)); type = *(ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); if (type == 0) return (ctf_set_errno(fp, ECTF_NOTYPEDAT)); return (type); }
int pmelf_getsym64(Elf_Stream s, Elf64_Sym *psym) { if ( 1 != SREAD(psym, sizeof(*psym), 1, s) ) { return -1; } if ( s->needswap ) { #ifdef PMELF_CONFIG_NO_SWAPSUPPORT return -2; #else elf_swap32( &psym->st_name); elf_swap16( &psym->st_shndx); elf_swap64( &psym->st_value); elf_swap64( &psym->st_size); #endif } #ifdef PARANOIA_ON { int x; if ( (x = ELF64_ST_TYPE( psym->st_info )) > STT_MAXSUP ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported type %i\n", x); return -1; } if ( (x = ELF64_ST_BIND( psym->st_info )) > STB_MAXSUP ) { PMELF_PRINTF( pmelf_err, PMELF_PRE"pmelf_getsym - paranoia: unsupported binding %i\n", x); return -1; } } #endif return 0; }
struct _list * elf64_entries (const struct _buffer * buffer) { if (elf64_check(buffer)) return NULL; Elf64_Ehdr * ehdr = elf64_ehdr(buffer); if (ehdr == NULL) return NULL; struct _list * entries = list_create(); struct _index * index = index_create(ehdr->e_entry); list_append(entries, index); object_delete(index); size_t shdr_i; for (shdr_i = 0; shdr_i < ehdr->e_shnum; shdr_i++) { size_t sym_i = 0; Elf64_Sym * sym; while ((sym = elf64_sym(buffer, shdr_i, sym_i++)) != NULL) { if ( (ELF64_ST_TYPE(sym->st_info) == STT_FUNC) && (sym->st_value != 0)) { struct _index * index = index_create(sym->st_value); list_append(entries, index); object_delete(index); } } } return entries; }
static int dls_get_external_syms(char *base, struct dls_external_symlist *out) { dls_shdr *s4 = dls_get_shdr_by_name(base, ".dynsym"); dls_shdr *s5 = dls_get_shdr_by_name(base, ".dynstr"); int nr_sym = s4->sh_size / sizeof(dls_sym); int i, count; dls_shdr *first_section = (dls_shdr *)(base + ((dls_ehdr*)base)->e_shoff); char *u = base + s5->sh_offset; dls_sym *sym = (dls_sym *)(base + s4->sh_offset); out->des_array = malloc(sizeof(struct dls_external_sym) * nr_sym); out->des_len = 0; for(i = 0; i < nr_sym; ++i, ++sym) { if(ELF64_ST_BIND(sym->st_info) == 1 && ELF64_ST_TYPE(sym->st_info) == 0) { out->des_array[out->des_len].de_sym = sym; out->des_array[out->des_len].de_name = u + sym->st_name; out->des_array[out->des_len].de_rel = (void*)dls_get_rel_sym(base, s4 - first_section, i); out->des_len++; } } out->des_array = realloc(out->des_array, out->des_len * sizeof(struct dls_external_sym)); return out->des_len; }
uint64_t find_symbol(struct LKM_Module *lkm_mod, struct Secthdr *secthdr, struct Symhdr *symhdr, struct Elf64_Rela *rela) { struct Symhdr *rela_sym = &symhdr[ELF64_R_SYM(rela->r_info)]; char *str_tab = lkm_mod->st_table; uint64_t sym_val; int ret=0,ret2=0; switch(rela_sym->st_shndx){ case ELF_SHN_UNDEF: // cprintf("Undefined Symbol:%s \n", (void *)((char *)lkm_mod->st_table + rela_sym->st_name)); sym_val = fetch_symbol_addr(rela_sym->st_name +str_tab); if(sym_val == 0){ cprintf("Unable to find %s(). Probably its Dependent on some Module which is not loaded.....\n",(void *)((char *)lkm_mod->st_table + rela_sym->st_name)); return 0; } dependencies_tmp[dependent_count]=fetch_symbol_tag(rela_sym->st_name +str_tab); if(((ret = strncmp("kernel", dependencies_tmp[dependent_count], strlen("kernel"))) != 0) && ((ret2=strlen(dependencies_tmp[dependent_count]))!=0)){ // cprintf("Symbol: %s Dependent on %s Dependent count = %d \n", rela_sym->st_name +str_tab, dependencies_tmp[dependent_count],dependent_count); lkm_mod->depd_count++; dependent_count++; }else{ memset(dependencies_tmp[dependent_count],'\0', sizeof(dependencies_tmp[dependent_count])); } sym_val = sym_val + rela->r_addend; break; case ELF_SHN_ABS: sym_val = rela_sym->st_value; break; case ELF_SHN_COMMON: sym_val = 0; break; default: if(rela_sym->st_shndx > lkm_mod->elf_hdr->e_shnum){ cprintf("Error while relocating..\n"); return 0; } struct Secthdr *tmp_sect = &lkm_mod->sect_hdr[rela_sym->st_shndx]; uint64_t addr; if(strcmp((lkm_mod->shname_st_table + tmp_sect->sh_name),".data") == 0){ addr = (uint64_t)lkm_mod->data_addr; }else if(strcmp((lkm_mod->shname_st_table + tmp_sect->sh_name),".text") == 0){ addr = (uint64_t)lkm_mod->text_addr; }else if(strcmp((lkm_mod->shname_st_table + tmp_sect->sh_name),".rodata") == 0){ addr = (uint64_t)lkm_mod->rodata_addr; }else if(strcmp((lkm_mod->shname_st_table + tmp_sect->sh_name),".bss") == 0){ addr = (uint64_t)lkm_mod->bss_addr; } sym_val = addr + rela_sym->st_value + rela->r_addend; if(ELF64_ST_TYPE(rela_sym->st_info) == STT_FUNC){ // cprintf("symbol name is %s symbol value is %x \n",(str_tab + rela_sym->st_name), sym_val); if((ret = strncmp(str_tab + rela_sym->st_name, "lkm_init", strlen("lkm_init")) != 0) && (ret = strncmp(str_tab + rela_sym->st_name, "lkm_exit", strlen("lkm_exit")))!= 0){ if((ret = strlen(str_tab + rela_sym->st_name)) != 0){ //new code insert_symbol(str_tab + rela_sym->st_name, sym_val, modules_lkm[mod_num].name); } } } break; } return sym_val; }
static void load_symtab(sym_strtab **list, Elf_Scn *sym_scn) { Elf_Data *data; size_t nb_symbols; sym_shdr = elf64_getshdr(sym_scn); data = elf_getdata(sym_scn, NULL); symtab = (Elf64_Sym*)data->d_buf; nb_symbols = sym_shdr->sh_size / sym_shdr->sh_entsize; for (size_t i = 0; i < nb_symbols; ++i) if (ELF64_ST_TYPE(symtab[i].st_info) == STT_FUNC || ELF64_ST_TYPE(symtab[i].st_info) == STT_NOTYPE) add_symbol(list, symtab[i].st_value, elf_strptr(e, sym_shdr->sh_link, symtab[i].st_name)); }
uintptr_t la_symbind64(Elf64_Sym *sym, unsigned idx, uintptr_t *refcook, uintptr_t *defcook, unsigned *flags, const char *symname) { /* Don't try to interpose on non-function relocations */ if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) return sym->st_value; if (audit_this_function(symname)) return (uintptr_t)allocate_trampoline(symname, (void *)sym->st_value); else return sym->st_value; }
/* Extract the list of source files, if present. The source files are * determined by loading the symbol table section (and its associated * string table) and looking up symbols of type STT_FILE. */ static int getsrcfiles(textline **plines) { Elf64_Sym *syms; char *nmstr; textline *lines; char *str; unsigned strtab, count, i; int j, n; if (!secthdrs) return 0; for (i = 0 ; i < elffhdr.e_shnum ; ++i) if (secthdr[i].sh_type == SHT_SYMTAB) break; if (i == elffhdr.e_shnum) return 0; count = secthdr[i].sh_size / secthdr[i].sh_entsize; strtab = secthdr[i].sh_link; if (!(syms = malloc(count * sizeof *syms))) nomem(); if (fseek(thefile, secthdr[i].sh_offset, SEEK_SET)) return err("%s: invalid symbol table offset.", thefilename); count = elfrw_read_Syms(thefile, syms, count); if (!count) return 0; nmstr = getarea(secthdr[strtab].sh_offset, secthdr[strtab].sh_size); if (!nmstr) { free(syms); return 0; } lines = gettextlines(count); n = 0; for (i = 0 ; i < count ; ++i) { if (ELF64_ST_TYPE(syms[i].st_info) != STT_FILE) continue; str = nmstr + syms[i].st_name; for (j = 0 ; j < n ; ++j) if (!strcmp(lines[j].str, str)) break; if (j == n) append(lines + n++, "%s", str); } free(syms); free(nmstr); if (n) *plines = lines; else free(lines); return n; }
static int _decode64_symtab(AsmFormatPlugin * format, Elf64_Ehdr * ehdr, Elf64_Shdr * shdr, size_t shdr_cnt, uint16_t ndx) { AsmFormatPluginHelper * helper = format->helper; char * strtab = NULL; size_t strtab_cnt = 0; Elf64_Sym sym; size_t i; off_t offset; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif if(ndx >= shdr_cnt || shdr[ndx].sh_entsize != sizeof(sym)) return -1; if(_decode64_strtab(format, shdr, shdr_cnt, shdr[ndx].sh_link, &strtab, &strtab_cnt) != 0) return -1; /* read and process symbols */ if((offset = helper->seek(helper->format, shdr[ndx].sh_offset, SEEK_SET)) < 0 || (unsigned long)offset != shdr[ndx].sh_offset) { free(strtab); return -1; } for(i = 0; i * sizeof(sym) < shdr[ndx].sh_size; i++) if(helper->read(helper->format, &sym, sizeof(sym)) != sizeof(sym)) break; else if(sym.st_name >= strtab_cnt) break; else if(ELF64_ST_TYPE(sym.st_info) == STT_FUNC) { offset = -1; if(ehdr->e_type == ET_REL || ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) offset = sym.st_value; /* record the function */ helper->set_function(helper->format, i, &strtab[sym.st_name], offset, sym.st_size); } if(i * sizeof(sym) != shdr[ndx].sh_size) { free(strtab); return -1; } return 0; }
/* * Sort comparison function for 64-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */ static int dt_module_symcomp64(const void *lp, const void *rp) { Elf64_Sym *lhs = *((Elf64_Sym **)lp); Elf64_Sym *rhs = *((Elf64_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name)); }
/* * Given a symbol table index, return the info for the function described * by the corresponding entry in the symbol table. */ int ctf_func_info(ctf_file_t *fp, ulong_t symidx, ctf_funcinfo_t *fip) { const ctf_sect_t *sp = &fp->ctf_symtab; const ushort_t *dp; ushort_t info, kind, n; if (sp->cts_data == NULL) return (ctf_set_errno(fp, ECTF_NOSYMTAB)); if (symidx >= fp->ctf_nsyms) return (ctf_set_errno(fp, EINVAL)); if (sp->cts_entsize == sizeof (Elf32_Sym)) { const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx; if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC) return (ctf_set_errno(fp, ECTF_NOTFUNC)); } else { const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx; if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC) return (ctf_set_errno(fp, ECTF_NOTFUNC)); } if (fp->ctf_sxlate[symidx] == -1u) return (ctf_set_errno(fp, ECTF_NOFUNCDAT)); dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); info = *dp++; kind = LCTF_INFO_KIND(fp, info); n = LCTF_INFO_VLEN(fp, info); if (kind == CTF_K_UNKNOWN && n == 0) return (ctf_set_errno(fp, ECTF_NOFUNCDAT)); if (kind != CTF_K_FUNCTION) return (ctf_set_errno(fp, ECTF_CORRUPT)); fip->ctc_return = *dp++; fip->ctc_argc = n; fip->ctc_flags = 0; if (n != 0 && dp[n - 1] == 0) { fip->ctc_flags |= CTF_FUNC_VARARG; fip->ctc_argc--; } return (0); }
static void get_info_sym(Elf64_Sym *sym) { int info; int bind; int type; int index; char c; info = sym->st_info; bind = ELF64_ST_BIND(info); type = ELF64_ST_TYPE(info); index = sym->st_shndx; c = get_carac(index, type, bind); printf("%c ", c); }
static uint_t dt_module_syminit64(dt_module_t *dmp) { #if STT_NUM != (STT_TLS + 1) #error "STT_NUM has grown. update dt_module_syminit64()" #endif Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; #if defined(__FreeBSD__) GElf_Ehdr ehdr; int is_elf_obj; gelf_getehdr(dmp->dm_elf, &ehdr); is_elf_obj = (ehdr.e_type == ET_REL); #endif for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { asrsv++; /* reserve space in the address map */ #if defined(__FreeBSD__) sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; if (is_elf_obj && sym->st_shndx != SHN_UNDEF && sym->st_shndx < ehdr.e_shnum) sym->st_value += dmp->dm_sec_offsets[sym->st_shndx]; #endif } dt_module_symhash_insert(dmp, name, i); } return (asrsv); }
static void display_symbol(t_dumper *dumper, Elf64_Sym *sym) { const char *name; char type; Elf64_Shdr *shdr; name = dumper_get_sym_name(dumper, sym); shdr = dumper_get_shdr_by_index(dumper, sym->st_shndx); type = get_symbol_type(dumper, sym); if (name[0] == '\0' || ELF64_ST_TYPE(sym->st_info) == STT_FILE) return ; if (type == 'U' || type == 'w') printf("%s", " "); else printf("%016lx", sym->st_value); printf(" %c %s\n", type, name); }
static void assign64(void *symp, CexpSym cesp, void *closure) { Elf64_Sym *sp=symp; CexpType t; int s=sp->st_size; cesp->size = s; t=TVoid; switch (ELF64_ST_TYPE(sp->st_info)) { case STT_OBJECT: /* determine the type of variable */ t = cexpTypeGuessFromSize(s); break; case STT_FUNC: t=TFuncP; break; case STT_NOTYPE: t=TVoid; break; case STT_SECTION: t=TVoid; cesp->flags|=CEXP_SYMFLG_SECT; break; default: break; } cesp->value.type = t; switch(ELF64_ST_BIND(sp->st_info)) { case STB_GLOBAL: cesp->flags|=CEXP_SYMFLG_GLBL; break; case STB_WEAK : cesp->flags|=CEXP_SYMFLG_WEAK; break; default: break; } cesp->value.ptv = (CexpVal)(uintptr_t)sp->st_value; }
char *symbol_type(unsigned char st_info) { switch (ELF64_ST_TYPE(st_info)) { case STT_NOTYPE: return "STT_NOTYPE"; case STT_OBJECT: return "STT_OBJECT"; case STT_FUNC: return "STT_FUNC"; case STT_SECTION: return "STT_SECTION"; case STT_FILE: return "STT_FILE"; case STT_COMMON: return "STT_COMMON"; case STT_TLS: return "STT_TLS"; case STT_NUM: return "STT_NUM"; case STT_LOOS: return "STT_LOOS STT_GNU_IFUNC"; case STT_HIOS: return "STT_HIOS"; case STT_LOPROC: return "STT_LOPROC"; case STT_HIPROC: return "STT_HIPROC"; default: return "unknown"; } }
static U8_T get_elf_symbol_address(Elf_Sym * x) { if (sCache->mFile->elf64) { Elf64_Sym * s = (Elf64_Sym *)x; switch (ELF64_ST_TYPE(s->st_info)) { case STT_OBJECT: case STT_FUNC: return s->st_value; } } else { Elf32_Sym * s = (Elf32_Sym *)x; switch (ELF32_ST_TYPE(s->st_info)) { case STT_OBJECT: case STT_FUNC: return s->st_value; } } return 0; }
const char * elf64_label (const struct _buffer * buffer, uint64_t address) { size_t shdr_i; Elf64_Shdr * shdr; for (shdr_i = 0; (shdr = elf64_shdr(buffer, shdr_i)) != NULL; shdr_i++) { size_t sym_i; Elf64_Sym * sym; for (sym_i = 0; (sym = elf64_sym(buffer, shdr_i, sym_i)) != NULL; sym_i++) { if ( (ELF64_ST_TYPE(sym->st_info) == STT_FUNC) && (sym->st_value == address)) { const char * symbol = elf64_strtab(buffer, shdr->sh_link, sym->st_name); if (symbol != NULL) return symbol; } } } return NULL; }
bool print(Elf64_Sym **tab, char *strtab) { int i; i = 0; while (tab[i]) { if (ELF64_ST_TYPE(tab[i]->st_info) != STT_FILE) { if (tab[i]->st_value) printf("%016x ", (unsigned int)tab[i]->st_value); else printf("\t\t "); get_info_sym(tab[i]); printf("%s\n", strtab + tab[i]->st_name); } i++; } return (true); }
static const char * filter64(void *ext_sym, void *closure) { Elf64_Sym *sp=ext_sym; char *strtab=closure; if ( STB_LOCAL == ELF64_ST_BIND(sp->st_info) ) return 0; switch (ELF64_ST_TYPE(sp->st_info)) { case STT_OBJECT: case STT_FUNC: case STT_NOTYPE: return strtab + sp->st_name; default: break; } return 0; }
/* * Initialize the symtab translation table by filling each entry with the * offset of the CTF type or function data corresponding to each STT_FUNC or * STT_OBJECT entry in the symbol table. */ static int init_symtab(ctf_file_t *fp, const ctf_header_t *hp, const ctf_sect_t *sp, const ctf_sect_t *strp) { const uchar_t *symp = sp->cts_data; uint_t *xp = fp->ctf_sxlate; uint_t *xend = xp + fp->ctf_nsyms; uint_t objtoff = hp->cth_objtoff; uint_t funcoff = hp->cth_funcoff; ushort_t info, vlen; Elf64_Sym sym, *gsp; const char *name; /* * The CTF data object and function type sections are ordered to match * the relative order of the respective symbol types in the symtab. * If no type information is available for a symbol table entry, a * pad is inserted in the CTF section. As a further optimization, * anonymous or undefined symbols are omitted from the CTF data. */ for (; xp < xend; xp++, symp += sp->cts_entsize) { if (sp->cts_entsize == sizeof (struct nlist)) { gsp = sym_to_gelf_macho(sp, (Elf32_Sym *)(uintptr_t)symp, &sym, (const char *)strp->cts_data); } else if (sp->cts_entsize == sizeof (struct nlist_64)) { gsp = sym_to_gelf_macho_64(sp, (Elf32_Sym *)(uintptr_t)symp, &sym, (const char *)strp->cts_data); } else if (sp->cts_entsize == sizeof (Elf32_Sym)) gsp = sym_to_gelf((Elf32_Sym *)(uintptr_t)symp, &sym); else gsp = (Elf64_Sym *)(uintptr_t)symp; if (gsp->st_name < strp->cts_size) name = (const char *)strp->cts_data + gsp->st_name; else name = _CTF_NULLSTR; if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF || strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0) { *xp = -1u; continue; } switch (ELF64_ST_TYPE(gsp->st_info)) { case STT_OBJECT: if (objtoff >= hp->cth_funcoff || (gsp->st_shndx == SHN_ABS && gsp->st_value == 0)) { *xp = -1u; break; } *xp = objtoff; objtoff += sizeof (ushort_t); break; case STT_FUNC: if (funcoff >= hp->cth_typeoff) { *xp = -1u; break; } *xp = funcoff; info = *(ushort_t *)((uintptr_t)fp->ctf_buf + funcoff); vlen = LCTF_INFO_VLEN(fp, info); /* * If we encounter a zero pad at the end, just skip it. * Otherwise skip over the function and its return type * (+2) and the argument list (vlen). */ if (LCTF_INFO_KIND(fp, info) == CTF_K_UNKNOWN && vlen == 0) funcoff += sizeof (ushort_t); /* skip pad */ else funcoff += sizeof (ushort_t) * (vlen + 2); break; default: *xp = -1u; break; } } ctf_dprintf("loaded %lu symtab entries\n", fp->ctf_nsyms); return (0); }
int vdso_fill_symtable(char *mem, size_t size, struct vdso_symtable *t) { Elf64_Phdr *dynamic = NULL, *load = NULL; Elf64_Ehdr *ehdr = (void *)mem; Elf64_Dyn *dyn_strtab = NULL; Elf64_Dyn *dyn_symtab = NULL; Elf64_Dyn *dyn_strsz = NULL; Elf64_Dyn *dyn_syment = NULL; Elf64_Dyn *dyn_hash = NULL; Elf64_Word *hash = NULL; Elf64_Phdr *phdr; Elf64_Dyn *d; Elf64_Word *bucket, *chain; Elf64_Word nbucket, nchain; /* * See Elf specification for this magic values. */ static const char elf_ident[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; char *dynsymbol_names; unsigned int i, j, k; BUILD_BUG_ON(sizeof(elf_ident) != sizeof(ehdr->e_ident)); pr_debug("Parsing at %lx %lx\n", (long)mem, (long)mem + (long)size); /* * Make sure it's a file we support. */ if (builtin_memcmp(ehdr->e_ident, elf_ident, sizeof(elf_ident))) { pr_err("Elf header magic mismatch\n"); return -EINVAL; } /* * We need PT_LOAD and PT_DYNAMIC here. Each once. */ phdr = (void *)&mem[ehdr->e_phoff]; for (i = 0; i < ehdr->e_phnum; i++, phdr++) { if (__ptr_oob(phdr, mem, size)) goto err_oob; switch (phdr->p_type) { case PT_DYNAMIC: if (dynamic) { pr_err("Second PT_DYNAMIC header\n"); return -EINVAL; } dynamic = phdr; break; case PT_LOAD: if (load) { pr_err("Second PT_LOAD header\n"); return -EINVAL; } load = phdr; break; } } if (!load || !dynamic) { pr_err("One of obligated program headers is missed\n"); return -EINVAL; } pr_debug("PT_LOAD p_vaddr: %lx\n", (unsigned long)load->p_vaddr); /* * Dynamic section tags should provide us the rest of information * needed. Note that we're interested in a small set of tags. */ d = (void *)&mem[dynamic->p_offset]; for (i = 0; i < dynamic->p_filesz / sizeof(*d); i++, d++) { if (__ptr_oob(d, mem, size)) goto err_oob; if (d->d_tag == DT_NULL) { break; } else if (d->d_tag == DT_STRTAB) { dyn_strtab = d; pr_debug("DT_STRTAB: %lx\n", (unsigned long)d->d_un.d_ptr); } else if (d->d_tag == DT_SYMTAB) { dyn_symtab = d; pr_debug("DT_SYMTAB: %lx\n", (unsigned long)d->d_un.d_ptr); } else if (d->d_tag == DT_STRSZ) { dyn_strsz = d; pr_debug("DT_STRSZ: %lx\n", (unsigned long)d->d_un.d_val); } else if (d->d_tag == DT_SYMENT) { dyn_syment = d; pr_debug("DT_SYMENT: %lx\n", (unsigned long)d->d_un.d_val); } else if (d->d_tag == DT_HASH) { dyn_hash = d; pr_debug("DT_HASH: %lx\n", (unsigned long)d->d_un.d_ptr); } } if (!dyn_strtab || !dyn_symtab || !dyn_strsz || !dyn_syment || !dyn_hash) { pr_err("Not all dynamic entries are present\n"); return -EINVAL; } dynsymbol_names = &mem[dyn_strtab->d_un.d_val - load->p_vaddr]; if (__ptr_oob(dynsymbol_names, mem, size)) goto err_oob; hash = (void *)&mem[(unsigned long)dyn_hash->d_un.d_ptr - (unsigned long)load->p_vaddr]; if (__ptr_oob(hash, mem, size)) goto err_oob; nbucket = hash[0]; nchain = hash[1]; bucket = &hash[2]; chain = &hash[nbucket + 2]; pr_debug("nbucket %lx nchain %lx bucket %lx chain %lx\n", (long)nbucket, (long)nchain, (unsigned long)bucket, (unsigned long)chain); for (i = 0; i < VDSO_SYMBOL_MAX; i++) { const char * symbol = vdso_symbols[i]; k = elf_hash((const unsigned char *)symbol); for (j = bucket[k % nbucket]; j < nchain && chain[j] != STN_UNDEF; j = chain[j]) { Elf64_Sym *sym = (void *)&mem[dyn_symtab->d_un.d_ptr - load->p_vaddr]; char *name; sym = &sym[j]; if (__ptr_oob(sym, mem, size)) continue; if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC && ELF64_ST_BIND(sym->st_info) != STB_GLOBAL) continue; name = &dynsymbol_names[sym->st_name]; if (__ptr_oob(name, mem, size)) continue; if (builtin_strcmp(name, symbol)) continue; builtin_memcpy(t->symbols[i].name, name, sizeof(t->symbols[i].name)); t->symbols[i].offset = (unsigned long)sym->st_value - load->p_vaddr; break; } } return 0; err_oob: pr_err("Corrupted Elf data\n"); return -EFAULT; }
STATIC BOOLEAN WriteSections64 ( SECTION_FILTER_TYPES FilterType ) { UINT32 Idx; Elf_Shdr *SecShdr; UINT32 SecOffset; BOOLEAN (*Filter)(Elf_Shdr *); // // Initialize filter pointer // switch (FilterType) { case SECTION_TEXT: Filter = IsTextShdr; break; case SECTION_HII: Filter = IsHiiRsrcShdr; break; case SECTION_DATA: Filter = IsDataShdr; break; default: return FALSE; } // // First: copy sections. // for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { Elf_Shdr *Shdr = GetShdrByIndex(Idx); if ((*Filter)(Shdr)) { switch (Shdr->sh_type) { case SHT_PROGBITS: /* Copy. */ memcpy(mCoffFile + mCoffSectionsOffset[Idx], (UINT8*)mEhdr + Shdr->sh_offset, (size_t) Shdr->sh_size); break; case SHT_NOBITS: memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size); break; default: // // Ignore for unkown section type. // VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type); break; } } } // // Second: apply relocations. // VerboseMsg ("Applying Relocations..."); for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) { // // Determine if this is a relocation section. // Elf_Shdr *RelShdr = GetShdrByIndex(Idx); if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) { continue; } // // Relocation section found. Now extract section information that the relocations // apply to in the ELF data and the new COFF data. // SecShdr = GetShdrByIndex(RelShdr->sh_info); SecOffset = mCoffSectionsOffset[RelShdr->sh_info]; // // Only process relocations for the current filter type. // if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) { UINT64 RelIdx; // // Determine the symbol table referenced by the relocation data. // Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link); UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset; // // Process all relocation entries for this section. // for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) { // // Set pointer to relocation entry // Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx); // // Set pointer to symbol table entry associated with the relocation entry. // Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize); Elf_Shdr *SymShdr; UINT8 *Targ; // // Check section header index found in symbol table and get the section // header location. // if (Sym->st_shndx == SHN_UNDEF || Sym->st_shndx == SHN_ABS || Sym->st_shndx > mEhdr->e_shnum) { Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName); } SymShdr = GetShdrByIndex(Sym->st_shndx); // // Convert the relocation data to a pointer into the coff file. // // Note: // r_offset is the virtual address of the storage unit to be relocated. // sh_addr is the virtual address for the base of the section. // // r_offset in a memory address. // Convert it to a pointer in the coff file. // Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr); // // Determine how to handle each relocation type based on the machine type. // if (mEhdr->e_machine == EM_X86_64) { switch (ELF_R_TYPE(Rel->r_info)) { case R_X86_64_NONE: break; case R_X86_64_64: // // Absolute relocation. // VerboseMsg ("R_X86_64_64"); VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), *(UINT64 *)Targ); *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ); break; case R_X86_64_32: VerboseMsg ("R_X86_64_32"); VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), *(UINT32 *)Targ); *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]); VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ); break; case R_X86_64_32S: VerboseMsg ("R_X86_64_32S"); VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), *(UINT32 *)Targ); *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]); VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ); break; case R_X86_64_PC32: // // Relative relocation: Symbol - Ip + Addend // VerboseMsg ("R_X86_64_PC32"); VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), *(UINT32 *)Targ); *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr) - (SecOffset - SecShdr->sh_addr)); VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); break; default: Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); } } else if (mEhdr->e_machine == EM_AARCH64) { // AARCH64 GCC uses RELA relocation, so all relocations have to be fixed up. // As opposed to ARM32 using REL. switch (ELF_R_TYPE(Rel->r_info)) { case R_AARCH64_ADR_PREL_LO21: if (Rel->r_addend != 0 ) { /* TODO */ Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_ADR_PREL_LO21 Need to fixup with addend!."); } break; case R_AARCH64_CONDBR19: if (Rel->r_addend != 0 ) { /* TODO */ Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_CONDBR19 Need to fixup with addend!."); } break; case R_AARCH64_LD_PREL_LO19: if (Rel->r_addend != 0 ) { /* TODO */ Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_LD_PREL_LO19 Need to fixup with addend!."); } break; case R_AARCH64_CALL26: case R_AARCH64_JUMP26: if (Rel->r_addend != 0 ) { // Some references to static functions sometime start at the base of .text + addend. // It is safe to ignore these relocations because they patch a `BL` instructions that // contains an offset from the instruction itself and there is only a single .text section. // So we check if the symbol is a "section symbol" if (ELF64_ST_TYPE (Sym->st_info) == STT_SECTION) { break; } Error (NULL, 0, 3000, "Invalid", "AArch64: R_AARCH64_JUMP26 Need to fixup with addend!."); } break; case R_AARCH64_ADR_PREL_PG_HI21: // TODO : AArch64 'small' memory model. Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADR_PREL_PG_HI21.", mInImageName); break; case R_AARCH64_ADD_ABS_LO12_NC: // TODO : AArch64 'small' memory model. Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation R_AARCH64_ADD_ABS_LO12_NC.", mInImageName); break; // Absolute relocations. case R_AARCH64_ABS64: *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]; break; default: Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); } } else { Error (NULL, 0, 3000, "Invalid", "Not a supported machine type"); } } } } return TRUE; }
int main(int argc, char* argv[]) { if(argc < 3) { printf("Usage: smap [kernel elf] [system map]\n"); return 0; } int fd = open(argv[1], O_RDONLY); if(fd < 0) { printf("Cannot open file: %s\n", argv[1]); return 1; } struct stat state; if(stat(argv[1], &state) != 0) { printf("Cannot get state of file: %s\n", argv[1]); return 2; } Elf64_Ehdr* ehdr = mmap(NULL, state.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(ehdr == (void*)-1) { printf("Cannot open file: %s\n", argv[1]); return 1; } if(ehdr->e_ident[0] != ELFMAG0 || ehdr->e_ident[1] != ELFMAG1 || ehdr->e_ident[2] != ELFMAG2 || ehdr->e_ident[3] != ELFMAG3) { printf("Illegal file format: %s\n", argv[1]); return 3; } Elf64_Shdr* shdr = (Elf64_Shdr*)((uint8_t*)ehdr + ehdr->e_shoff); char* strs = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset; Elf64_Shdr* get_shdr(char* name) { for(int i = 0; i < ehdr->e_shnum; i++) { if(strcmp(name, strs + shdr[i].sh_name) == 0) return &shdr[i]; } return NULL; } Elf64_Shdr* strtab = get_shdr(".strtab"); char* str = (char*)ehdr + strtab->sh_offset; char* name(int offset) { return str + offset; } int count = 0; int text_size = 0; Elf64_Shdr* symtab = get_shdr(".symtab"); Elf64_Sym* sym = (void*)ehdr + symtab->sh_offset; int size = symtab->sh_size / sizeof(Elf64_Sym); for(int i = 0; i < size; i++) { if(ELF64_ST_BIND(sym[i].st_info) != STB_GLOBAL) continue; int type = ELF64_ST_TYPE(sym[i].st_info); switch(type) { case STT_NOTYPE: case STT_OBJECT: case STT_FUNC: break; default: printf("Unknown symbol type: %d for %s\n", type, name(sym[i].st_name)); return 4; } count++; text_size += strlen(name(sym[i].st_name)) + 1; } // Make data structure int total = sizeof(Symbol) * (count + 1) + text_size; Symbol* symbols = malloc(total); char* text = (void*)symbols + total - text_size; int j = 0; for(int i = 0; i < size; i++) { if(ELF64_ST_BIND(sym[i].st_info) != STB_GLOBAL) continue; int type = ELF64_ST_TYPE(sym[i].st_info); switch(type) { case STT_NOTYPE: type = SYMBOL_TYPE_NONE; break; case STT_OBJECT: type = SYMBOL_TYPE_DATA; break; case STT_FUNC: type = SYMBOL_TYPE_FUNC; break; default: ;// Not possible } symbols[j].name = (void*)((void*)text - (void*)symbols); symbols[j].type = type; symbols[j].address = (void*)(uint64_t)sym[i].st_value; j++; char* symname = name(sym[i].st_name); int len = strlen(symname) + 1; memcpy(text, symname, len); text += len; } close(fd); // Write int fd2 = open(argv[2], O_RDWR | O_CREAT, 0644); if(fd2 < 0) { printf("Cannot open file: %s\n", argv[2]); return 1; } // Write symbols int len = write(fd2, symbols, total); if(len != total) { printf("Cannot write fully: %d < %d\n", len, total); return 5; } close(fd2); return 0; }
void _mapFuncNames(ThreadContext *context, FileSys::SeekableDescription *fdesc, VAddr addr, size_t len, off_t off){ typedef typename ElfDefs<mode>::Elf_Ehdr Elf_Ehdr; typedef typename ElfDefs<mode>::Elf_Shdr Elf_Shdr; typedef typename ElfDefs<mode>::Elf_Sym Elf_Sym; // Read in the ELF header Elf_Ehdr ehdr; ssize_t ehdrSiz=fdesc->pread(&ehdr,sizeof(Elf_Ehdr),0); I(ehdrSiz==sizeof(Elf_Ehdr)); cvtEndianEhdr<mode>(ehdr); // Read in section headers Elf_Shdr shdrs[ehdr.e_shnum]; ssize_t shdrsSiz=fdesc->pread(shdrs,sizeof(Elf_Shdr)*ehdr.e_shnum,ehdr.e_shoff); I(shdrsSiz==(ssize_t)(sizeof(Elf_Shdr)*ehdr.e_shnum)); I(shdrsSiz==(ssize_t)(sizeof(shdrs))); for(size_t sec=0;sec<ehdr.e_shnum;sec++) cvtEndianShdr<mode>(shdrs[sec]); // Read in section name strings I((ehdr.e_shstrndx>0)&&(ehdr.e_shstrndx<ehdr.e_shnum)); char secStrTab[shdrs[ehdr.e_shstrndx].sh_size]; ssize_t secStrTabSiz=fdesc->pread(secStrTab,shdrs[ehdr.e_shstrndx].sh_size,shdrs[ehdr.e_shstrndx].sh_offset); I(secStrTabSiz==(ssize_t)(shdrs[ehdr.e_shstrndx].sh_size)); // Iterate over all sections for(size_t sec=0;sec<ehdr.e_shnum;sec++){ switch(shdrs[sec].sh_type){ case SHT_PROGBITS: { if(!(shdrs[sec].sh_flags&SHF_EXECINSTR)) break; ssize_t loadBias=(addr-shdrs[sec].sh_addr)+(shdrs[sec].sh_offset-off); char *secNam=secStrTab+shdrs[sec].sh_name; size_t secNamLen=strlen(secNam); if((off_t(shdrs[sec].sh_offset)>=off)&&(shdrs[sec].sh_offset<off+len)){ char *begNam="SecBeg"; size_t begNamLen=strlen(begNam); char symNam[secNamLen+begNamLen+1]; strcpy(symNam,begNam); strcpy(symNam+begNamLen,secNam); VAddr symAddr=shdrs[sec].sh_addr+loadBias; context->getAddressSpace()->addFuncName(symAddr,symNam,fdesc->getName()); } if((off_t(shdrs[sec].sh_offset+shdrs[sec].sh_size)>off)&& (shdrs[sec].sh_offset+shdrs[sec].sh_size<=off+len)){ char *endNam="SecEnd"; size_t endNamLen=strlen(endNam); char symNam[secNamLen+endNamLen+1]; strcpy(symNam,endNam); strcpy(symNam+endNamLen,secNam); VAddr symAddr=shdrs[sec].sh_addr+shdrs[sec].sh_size+loadBias; context->getAddressSpace()->addFuncName(symAddr,symNam,fdesc->getName()); } } break; case SHT_SYMTAB: case SHT_DYNSYM: { I(shdrs[sec].sh_entsize==sizeof(Elf_Sym)); // Read in the symbols size_t symnum=shdrs[sec].sh_size/sizeof(Elf_Sym); Elf_Sym syms[symnum]; ssize_t symsSiz=fdesc->pread(syms,shdrs[sec].sh_size,shdrs[sec].sh_offset); I(symsSiz==(ssize_t)(sizeof(Elf_Sym)*symnum)); I(symsSiz==(ssize_t)(sizeof(syms))); for(size_t sym=0;sym<symnum;sym++) cvtEndianSym<mode>(syms[sym]); // Read in the symbol name strings char strTab[shdrs[shdrs[sec].sh_link].sh_size]; ssize_t strTabSiz=fdesc->pread(strTab,shdrs[shdrs[sec].sh_link].sh_size,shdrs[shdrs[sec].sh_link].sh_offset); I(strTabSiz==(ssize_t)(shdrs[shdrs[sec].sh_link].sh_size)); for(size_t sym=0;sym<symnum;sym++){ I(ELF32_ST_TYPE(syms[sym].st_info)==ELF64_ST_TYPE(syms[sym].st_info)); switch(ELF64_ST_TYPE(syms[sym].st_info)){ case STT_FUNC: { if(!syms[sym].st_shndx) break; ssize_t loadBias=(addr-shdrs[syms[sym].st_shndx].sh_addr)+ (shdrs[syms[sym].st_shndx].sh_offset-off); // printf("sh_type %s st_name %s st_value 0x%08x st_size 0x%08x st_shndx 0x%08x\n", // shdrs[sec].sh_type==SHT_SYMTAB?"SYMTAB":"DYNSYM", // strTab+syms[sym].st_name, // (int)(syms[sym].st_value),(int)(syms[sym].st_size),(int)(syms[sym].st_shndx)); char *symNam=strTab+syms[sym].st_name; VAddr symAddr=syms[sym].st_value+loadBias; if((symAddr<addr)||(symAddr>=addr+len)) break; context->getAddressSpace()->addFuncName(symAddr,symNam,fdesc->getName()); } break; } } } break; } } }
int apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *me) { Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr; unsigned long i, n = sechdrs[relsec].sh_size / sizeof(*rela); Elf64_Sym *symtab, *sym; void *base, *location; unsigned long got, gp; DEBUGP("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); base = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr; symtab = (Elf64_Sym *)sechdrs[symindex].sh_addr; /* The small sections were sorted to the end of the segment. The following should definitely cover them. */ gp = (u64)me->module_core + me->core_size - 0x8000; got = sechdrs[me->arch.gotsecindex].sh_addr; for (i = 0; i < n; i++) { unsigned long r_sym = ELF64_R_SYM (rela[i].r_info); unsigned long r_type = ELF64_R_TYPE (rela[i].r_info); unsigned long r_got_offset = r_type >> 8; unsigned long value, hi, lo; r_type &= 0xff; /* This is where to make the change. */ location = base + rela[i].r_offset; /* This is the symbol it is referring to. Note that all unresolved symbols have been resolved. */ sym = symtab + r_sym; value = sym->st_value + rela[i].r_addend; switch (r_type) { case R_ALPHA_NONE: break; case R_ALPHA_REFQUAD: /* BUG() can produce misaligned relocations. */ ((u32 *)location)[0] = value; ((u32 *)location)[1] = value >> 32; break; case R_ALPHA_GPREL32: value -= gp; if ((int)value != value) goto reloc_overflow; *(u32 *)location = value; break; case R_ALPHA_LITERAL: hi = got + r_got_offset; lo = hi - gp; if ((short)lo != lo) goto reloc_overflow; *(u16 *)location = lo; *(u64 *)hi = value; break; case R_ALPHA_LITUSE: break; case R_ALPHA_GPDISP: value = gp - (u64)location; lo = (short)value; hi = (int)(value - lo); if (hi + lo != value) goto reloc_overflow; *(u16 *)location = hi >> 16; *(u16 *)(location + rela[i].r_addend) = lo; break; case R_ALPHA_BRSGP: /* BRSGP is only allowed to bind to local symbols. If the section is undef, this means that the value was resolved from somewhere else. */ if (sym->st_shndx == SHN_UNDEF) goto reloc_overflow; if ((sym->st_other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD) /* Omit the prologue. */ value += 8; /* FALLTHRU */ case R_ALPHA_BRADDR: value -= (u64)location + 4; if (value & 3) goto reloc_overflow; value = (long)value >> 2; if (value + (1<<21) >= 1<<22) goto reloc_overflow; value &= 0x1fffff; value |= *(u32 *)location & ~0x1fffff; *(u32 *)location = value; break; case R_ALPHA_HINT: break; case R_ALPHA_SREL32: value -= (u64)location; if ((int)value != value) goto reloc_overflow; *(u32 *)location = value; break; case R_ALPHA_SREL64: value -= (u64)location; *(u64 *)location = value; break; case R_ALPHA_GPRELHIGH: value = (long)(value - gp + 0x8000) >> 16; if ((short) value != value) goto reloc_overflow; *(u16 *)location = value; break; case R_ALPHA_GPRELLOW: value -= gp; *(u16 *)location = value; break; case R_ALPHA_GPREL16: value -= gp; if ((short) value != value) goto reloc_overflow; *(u16 *)location = value; break; default: printk(KERN_ERR "module %s: Unknown relocation: %lu\n", me->name, r_type); return -ENOEXEC; reloc_overflow: if (ELF64_ST_TYPE (sym->st_info) == STT_SECTION) printk(KERN_ERR "module %s: Relocation (type %lu) overflow vs section %d\n", me->name, r_type, sym->st_shndx); else printk(KERN_ERR "module %s: Relocation (type %lu) overflow vs %s\n", me->name, r_type, strtab + sym->st_name); return -ENOEXEC; } } return 0; }