/* * Given a symbol index, look up the corresponding symbol from the * given symbol table. * * This function allows the caller to treat the symbol table as a single * logical entity even though there may be 2 actual ELF symbol tables * involved. See the comments in Pcontrol.h for details. */ static GElf_Sym * symtab_getsym(sym_tbl_t *symtab, int ndx, GElf_Sym *dst) { /* If index is in range of primary symtab, look it up there */ if (ndx >= symtab->st_symn_aux) { return (gelf_getsym(symtab->st_syms_pri, ndx - symtab->st_symn_aux, dst)); } /* Not in primary: Look it up in the auxiliary symtab */ return (gelf_getsym(symtab->st_syms_aux, ndx, dst)); }
void symtab_elf_foreach(library_info_t *lib, void (*callback)(const symbol_t *)) { for (int i = 0; i < lib->elf_symtab_count; ++i) { GElf_Sym sym; gelf_getsym(lib->elf_symtab_data, i, &sym); //if (ELF32_ST_TYPE(sym.st_info) != type) { // continue; //} symbol_t entry = { .lib = lib, .addr = sym.st_value, .size = sym.st_size, .name = elf_strptr(lib->elf, lib->elf_symtab_shdr.sh_link, sym.st_name), .name_demangled = try_demangle_noprefix(entry.name), }; callback(&entry); } } bool symtab_elf_lookup_addr(library_info_t *lib, symbol_t *entry, uintptr_t addr) { for (int i = 0; i < lib->elf_symtab_count; ++i) { GElf_Sym sym; gelf_getsym(lib->elf_symtab_data, i, &sym); //if (ELF32_ST_TYPE(sym.st_info) != type) { // continue; //} if (sym.st_value == addr) { entry->lib = lib; entry->addr = sym.st_value; entry->size = sym.st_size; entry->name = elf_strptr(lib->elf, lib->elf_symtab_shdr.sh_link, sym.st_name); entry->name_demangled = try_demangle_noprefix(entry->name); return true; } /*fprintf(stderr, "val %08x size %8x bind %2d type %2d name '%s'\n", val, size, bind, type, elf_strptr(lib->elf, shdr.sh_link, sym.st_name));*/ } return false; }
static void _dwarf_elf_apply_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data, Elf_Data *symtab_data, int endian) { Dwarf_Unsigned type; GElf_Rela rela; GElf_Sym sym; size_t symndx; uint64_t offset; int size, j; j = 0; while (gelf_getrela(rel_data, j++, &rela) != NULL) { symndx = GELF_R_SYM(rela.r_info); type = GELF_R_TYPE(rela.r_info); if (gelf_getsym(symtab_data, symndx, &sym) == NULL) continue; offset = rela.r_offset; size = _dwarf_get_reloc_size(dbg, type); if (endian == ELFDATA2MSB) _dwarf_write_msb(buf, &offset, rela.r_addend, size); else _dwarf_write_lsb(buf, &offset, rela.r_addend, size); } }
static void _dwarf_elf_write_reloc(Dwarf_Debug dbg, Elf_Data *symtab_data, int endian, void *buf, uint64_t offset, GElf_Xword r_info, GElf_Sxword r_addend, int is_rel) { GElf_Sym sym; int size; if (gelf_getsym(symtab_data, GELF_R_SYM(r_info), &sym) == NULL) return; if ((size = _dwarf_get_reloc_size(dbg, GELF_R_TYPE(r_info))) == 0) return; /* Unknown or non-absolute relocation. */ if (is_rel) { uint64_t roffset = offset; if (endian == ELFDATA2MSB) r_addend = _dwarf_read_msb(buf, &roffset, size); else r_addend = _dwarf_read_lsb(buf, &roffset, size); } if (endian == ELFDATA2MSB) _dwarf_write_msb(buf, &offset, sym.st_value + r_addend, size); else _dwarf_write_lsb(buf, &offset, sym.st_value + r_addend, size); }
static arch_addr_t _find_solib_break(struct mt_elf *mte, Elf_Data *symtab, const char *strtab, size_t size) { size_t i; unsigned int j; static const char * const solib_break_names[] = { "r_debug_state", "_r_debug_state", "_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity", "_rtld_debug_state" }; for (i = 0; i < size; ++i) { GElf_Sym sym; if (gelf_getsym(symtab, i, &sym) == NULL) { fprintf(stderr, "couldn't get symbol #%zd from %s: %s\n", i, mte->filename, elf_errmsg(-1)); continue; } if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || sym.st_value == 0 || sym.st_shndx == STN_UNDEF) continue; const char *name = strtab + sym.st_name; for(j = 0; j < ARRAY_SIZE(solib_break_names); j++) { if (!strcmp(name, solib_break_names[j])) return ARCH_ADDR_T(sym.st_value + mte->bias); } } return ARCH_ADDR_T(0); }
/** * @brief Search a single, particular ELF symbol table for a named symbol * * @param elf The open ELF object * @param symtab The ELF symbol table section * @param name The symbol name to find * * @returns The address to which the symbol points, 0 otherwise. */ static GElf_Addr elf_scn_getsymaddr_byname(Elf *elf, Elf_Scn *symtab, const char * name) { GElf_Shdr shdr; Elf_Data *data; uint32_t syms, i; GElf_Sym sym; if (gelf_getshdr(symtab, &shdr) == NULL || shdr.sh_type != SHT_SYMTAB) { return 0; } data = elf_getdata(symtab, NULL); if (data == NULL) { return 0; } syms = shdr.sh_size / shdr.sh_entsize; for(i=0; i<syms; i++) { gelf_getsym(data, i, &sym); if (strcmp(elf_strptr(elf, shdr.sh_link, sym.st_name), name) == 0) { return sym.st_value; } } return 0; }
static void readSymbols(Elf *e, Elf_Scn *scn, const GElf_Shdr &shdr, unsigned low, unsigned high, std::auto_ptr<CoreSymbolInfo> &SI) { Elf_Data *data = elf_getdata(scn, NULL); if (data == NULL) { return; } unsigned count = shdr.sh_size / shdr.sh_entsize; CoreSymbolInfoBuilder builder; for (unsigned i = 0; i < count; i++) { GElf_Sym sym; if (gelf_getsym(data, i, &sym) == NULL) { continue; } if (sym.st_shndx == SHN_ABS) continue; if (sym.st_value < low || sym.st_value >= high) continue; builder.addSymbol(elf_strptr(e, shdr.sh_link, sym.st_name), sym.st_value, sym.st_info); } SI = builder.getSymbolInfo(); }
static void parse_relocs(Elf *elf, Elf_Data *relocs, Elf_Data *symbols, unsigned symbol_sh_link, struct radeon_shader_binary *binary) { unsigned i; if (!relocs || !symbols || !binary->reloc_count) { return; } binary->relocs = CALLOC(binary->reloc_count, sizeof(struct radeon_shader_reloc)); for (i = 0; i < binary->reloc_count; i++) { GElf_Sym symbol; GElf_Rel rel; char *symbol_name; struct radeon_shader_reloc *reloc = &binary->relocs[i]; gelf_getrel(relocs, i, &rel); gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &symbol); symbol_name = elf_strptr(elf, symbol_sh_link, symbol.st_name); reloc->offset = rel.r_offset; reloc->name = strdup(symbol_name); } }
/* * Given the current symbol index (-1 to start at the beginning of the symbol * table) and the type of symbol to match, this function returns the index of * the next matching symbol (if any), and places the name of that symbol in * *namep. If no symbol is found, -1 is returned. */ static int next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype, char **namep) { int i; for (i = symidx + 1; i < cd->cd_nsyms; i++) { GElf_Sym sym; char *name; int type; if (gelf_getsym(cd->cd_symdata, i, &sym) == 0) return (-1); name = (char *)cd->cd_strdata->d_buf + sym.st_name; type = GELF_ST_TYPE(sym.st_info); /* * Skip various types of symbol table entries. */ if (type != matchtype || ignore_symbol(&sym, name)) continue; /* Found one */ *namep = name; return (i); } return (-1); }
/* * 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; }
/* * Look up the symbol at addr, returning a copy of the symbol and its name. */ static int lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, const char **name, GElf_Sym *symcopy) { GElf_Sym sym; Elf_Data *data; const char *s; uint64_t rsym; int i; if ((data = elf_getdata(scn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); return (1); } for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { rsym = off + sym.st_value; if (addr >= rsym && addr < rsym + sym.st_size) { s = elf_strptr(e, stridx, sym.st_name); if (s != NULL) { *name = s; memcpy(symcopy, &sym, sizeof(*symcopy)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; return (0); } } } return (1); }
/* Below code adapted from libelf tutorial example */ static u32 extract_functions_internal (const char *str, func_entry *func_list) { Elf *e; Elf_Kind ek; Elf_Scn *scn; Elf_Data *edata; u32 fd, i, symbol_count; GElf_Sym sym; GElf_Shdr shdr; u32 func_count = 0; if(elf_version(EV_CURRENT) == EV_NONE) { printf("Error initializing ELF: %s\n", elf_errmsg(-1)); return -1; } if ((fd = open(str, O_RDONLY, 0)) < 0) { printf("Unable to open %s\n", str); return -1; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { printf("elf_begin failed: %s\n", elf_errmsg(-1)); } ek = elf_kind(e); if(ek != ELF_K_ELF) { printf("not an ELF object"); } else { scn = NULL; edata = NULL; while((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); if(shdr.sh_type == SHT_SYMTAB) { edata = elf_getdata(scn, edata); symbol_count = shdr.sh_size / shdr.sh_entsize; for(i = 0; i < symbol_count; i++) { gelf_getsym(edata, i, &sym); if(ELF32_ST_TYPE(sym.st_info) != STT_FUNC) { check_for_end_marker(elf_strptr(e, shdr.sh_link, sym.st_name), sym.st_value); continue; } if(sym.st_size == 0) continue; func_list[func_count].offset = sym.st_value; func_list[func_count++].func_name = strdup(elf_strptr(e, shdr.sh_link, sym.st_name)); if(func_count >= MAXFNS) { printf("Func limit (%"PRId32") reached, please increase MAXFNS & rebuild\n", MAXFNS); raise(SIGABRT); } // printf("%08x %08x\t%s\n", sym.st_value, sym.st_size, elf_strptr(e, shdr.sh_link, sym.st_name)); } } } } elf_end(e); close(fd); return func_count; }
static int parse_relo_and_apply(Elf_Data *data, Elf_Data *symbols, GElf_Shdr *shdr, struct bpf_insn *insn) { int i, nrels; nrels = shdr->sh_size / shdr->sh_entsize; for (i = 0; i < nrels; i++) { GElf_Sym sym; GElf_Rel rel; unsigned int insn_idx; gelf_getrel(data, i, &rel); insn_idx = rel.r_offset / sizeof(struct bpf_insn); gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &sym); if (insn[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { printf("invalid relo for insn[%d].code 0x%x\n", insn_idx, insn[insn_idx].code); return 1; } insn[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; insn[insn_idx].imm = map_fd[sym.st_value / sizeof(struct bpf_map_def)]; } return 0; }
map_s *elf_set_breakpoints(proc_s *proc) { elf_info_s *elf = elf_symbols(proc->fd); map_s *brkp = map_init(32, cmp_addr); for (size_t i = 0; i < elf->replt_count; ++i) { void *ret; GElf_Rel rel; GElf_Rela rela; const char *name; GElf_Sym sym; GElf_Addr addr; /* local relocation entries */ if (elf->replt->d_type == ELF_T_REL) { ret = gelf_getrel(elf->replt, i, &rel); rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } /* external relocation entries */ else ret = gelf_getrela(elf->replt, i, &rela); gelf_getsym(elf->dynsym, ELF64_R_SYM(rela.r_info), &sym); name = elf->dynstr + sym.st_name; addr = elf->plt_addr + (i + 1) * 16; breakpoint_create(brkp, addr, name, proc->pid); } return brkp; }
GElf_Sym * gelf_getsymshndx(Elf_Data *d, Elf_Data *id, int ndx, GElf_Sym *dst, Elf32_Word *shindex) { int ec; Elf *e; size_t msz; Elf_Scn *scn; uint32_t sh_type; struct _Libelf_Data *ld, *lid; ld = (struct _Libelf_Data *) d; lid = (struct _Libelf_Data *) id; if (gelf_getsym(d, ndx, dst) == 0) return (NULL); if (lid == NULL || (scn = lid->d_scn) == NULL || (e = scn->s_elf) == NULL || (e != ld->d_scn->s_elf) || shindex == NULL) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } ec = e->e_class; assert(ec == ELFCLASS32 || ec == ELFCLASS64); if (ec == ELFCLASS32) sh_type = scn->s_shdr.s_shdr32.sh_type; else sh_type = scn->s_shdr.s_shdr64.sh_type; if (_libelf_xlate_shtype(sh_type) != ELF_T_WORD || id->d_type != ELF_T_WORD) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } msz = _libelf_msize(ELF_T_WORD, ec, e->e_version); assert(msz > 0); assert(ndx >= 0); if (msz * (size_t) ndx >= id->d_size) { LIBELF_SET_ERROR(ARGUMENT, 0); return (NULL); } *shindex = ((Elf32_Word *) id->d_buf)[ndx]; return (dst); }
static int populate_this_symtab(struct mt_elf *mte, struct libref *libref, Elf_Data *symtab, const char *strtab, size_t size) { size_t i; for (i = 0; i < size; ++i) { GElf_Sym sym; if (gelf_getsym(symtab, i, &sym) == NULL) { fprintf(stderr, "couldn't get symbol #%zd from %s: %s\n", i, mte->filename, elf_errmsg(-1)); continue; } if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || sym.st_value == 0 || sym.st_shndx == STN_UNDEF) continue; /* Find symbol name and snip version. */ const char *orig_name = strtab + sym.st_name; const char *version = strchr(orig_name, '@'); size_t len = version ? (size_t)(version - orig_name) : strlen(orig_name); char name[len + 1]; memcpy(name, orig_name, len); name[len] = 0; /* If the symbol is not matched, skip it. */ const struct function *func = flist_matches_symbol(name); if (!func) continue; arch_addr_t addr = ARCH_ADDR_T(sym.st_value + mte->bias); struct library_symbol *libsym = library_find_symbol(libref, addr); if (!libsym) { struct library_symbol *libsym = library_symbol_new(libref, addr, func); if (!libsym) { fprintf(stderr, "couldn't init symbol: %s%s\n", name, func->name); continue; } } else { /* handle symbol alias */ if (libsym->func->level > func->level) libsym->func = func; } if (unlikely(options.verbose > 1)) fprintf(stderr, "breakpoint for %s:%s at %#lx\n", libref->filename, func->demangled_name, addr); } return 0; }
static GElf_Sym FindSymbol(Elf *e, const char *name) { auto sym_scn = FindSectionByType(e, SHT_SYMTAB); auto sym_data = elf_getdata(sym_scn.first, nullptr); auto num_syms = sym_scn.second.sh_size / sym_scn.second.sh_entsize; for (size_t i = 0; i < num_syms; i++) { GElf_Sym sym; gelf_getsym(sym_data, i, &sym); auto sym_name = elf_strptr(e, sym_scn.second.sh_link, sym.st_name); if (strcmp(sym_name, name) == 0) return sym; } errx(EX_SOFTWARE, "Binary does not contain symbol:%s", name); return GElf_Sym(); }
static void parse_symbol_table(Elf_Data *symbol_table_data, const GElf_Shdr *symbol_table_header, struct radeon_shader_binary *binary) { GElf_Sym symbol; unsigned i = 0; unsigned symbol_count = symbol_table_header->sh_size / symbol_table_header->sh_entsize; /* We are over allocating this list, because symbol_count gives the * total number of symbols, and we will only be filling the list * with offsets of global symbols. The memory savings from * allocating the correct size of this list will be small, and * I don't think it is worth the cost of pre-computing the number * of global symbols. */ binary->global_symbol_offsets = CALLOC(symbol_count, sizeof(uint64_t)); while (gelf_getsym(symbol_table_data, i++, &symbol)) { unsigned i; if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL || symbol.st_shndx == 0 /* Undefined symbol */) { continue; } binary->global_symbol_offsets[binary->global_symbol_count] = symbol.st_value; /* Sort the list using bubble sort. This list will usually * be small. */ for (i = binary->global_symbol_count; i > 0; --i) { uint64_t lhs = binary->global_symbol_offsets[i - 1]; uint64_t rhs = binary->global_symbol_offsets[i]; if (lhs < rhs) { break; } binary->global_symbol_offsets[i] = lhs; binary->global_symbol_offsets[i - 1] = rhs; } ++binary->global_symbol_count; } }
static int symbol_matches(struct ltelf *lte, size_t lte_i, GElf_Sym *sym, size_t symidx, const char *name) { GElf_Sym tmp_sym; GElf_Sym *tmp; tmp = (sym) ? (sym) : (&tmp_sym); if (gelf_getsym(lte[lte_i].dynsym, symidx, tmp) == NULL) error(EXIT_FAILURE, 0, "Couldn't get symbol from .dynsym"); else { tmp->st_value += lte[lte_i].base_addr; debug(2, "symbol found: %s, %zd, %#" PRIx64, name, lte_i, tmp->st_value); } return tmp->st_value != 0 && tmp->st_shndx != SHN_UNDEF && strcmp(name, lte[lte_i].dynstr + tmp->st_name) == 0; }
static int bpf_object__init_maps_name(struct bpf_object *obj) { int i; Elf_Data *symbols = obj->efile.symbols; if (!symbols || obj->efile.maps_shndx < 0) return -EINVAL; for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { GElf_Sym sym; size_t map_idx; const char *map_name; if (!gelf_getsym(symbols, i, &sym)) continue; if (sym.st_shndx != obj->efile.maps_shndx) continue; map_name = elf_strptr(obj->efile.elf, obj->efile.strtabidx, sym.st_name); map_idx = sym.st_value / sizeof(struct bpf_map_def); if (map_idx >= obj->nr_maps) { pr_warning("index of map \"%s\" is buggy: %zu > %zu\n", map_name, map_idx, obj->nr_maps); continue; } obj->maps[map_idx].name = strdup(map_name); if (!obj->maps[map_idx].name) { pr_warning("failed to alloc map name\n"); return -ENOMEM; } pr_debug("map %zu is \"%s\"\n", map_idx, obj->maps[map_idx].name); } return 0; }
/* Given Elf header, Elf_Scn, and Elf32_Shdr * print out the symbol table */ static _Bool print_symbols(Elf *elf, Elf_Scn *scn, GElf_Shdr *shdr) { Elf_Data *data; char *name; char *stringName; data = 0; int number = 0; if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0) { /* error or no data */ fprintf(stderr, "Section had no data!\n"); exit(-1); } /*now print the symbols*/ unsigned count = symtab_shdr.sh_size / symtab_shdr.sh_entsize; //fprintf(stderr, "Total symbols count: %u\n", count); /* now loop through the symbol table and print it*/ for (unsigned i = 0; i < count; ++i) { //fprintf(stderr, "Index is %u\n", i); GElf_Sym esym; GElf_Sym *ret = gelf_getsym(data, i, &esym); if (ret == 0) { fprintf(stderr, "Error!\n"); return FALSE; } if ((esym.st_value == 0) || (GELF_ST_BIND(esym.st_info)== STB_WEAK) || (GELF_ST_BIND(esym.st_info)== STB_NUM)) continue; //fprintf(stderr, "Symbol has strtab offset %zu\n", (size_t)esym.st_name); name = elf_strptr(elf, shdr->sh_link, (size_t)esym.st_name); if(!name) { fprintf(stderr,"%s\n",elf_errmsg(elf_errno())); exit(-1); } printf("%d: %s\n", number++, name); } return TRUE; }
/* * Look up the symbol with the given name and return a copy of it. */ static int lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, GElf_Sym *symcopy, prsyminfo_t *si) { GElf_Sym sym; Elf_Data *data; char *s; int i; if ((data = elf_getdata(scn, NULL)) == NULL) { DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); return (1); } for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { s = elf_strptr(e, stridx, sym.st_name); if (s != NULL && strcmp(s, symbol) == 0) { memcpy(symcopy, &sym, sizeof(*symcopy)); if (si != NULL) si->prs_id = i; return (0); } } return (1); }
static void walk_symtab(Elf *elf, char *fname, ctf_file_t *fp, void (*callback)(ctf_file_t *, symtab_sym_t *)) { Elf_Scn *stab = NULL; Elf_Scn *text = NULL; Elf_Data *stabdata = NULL; Elf_Data *textdata = NULL; GElf_Ehdr ehdr; GElf_Shdr stabshdr; GElf_Shdr textshdr; int foundtext = 0, foundstab = 0; symtab_sym_t ss; if ((gelf_getehdr(elf, &ehdr)) == NULL) errx(1, "could not read ELF header from %s\n", fname); while ((stab = elf_nextscn(elf, stab)) != NULL) { (void) gelf_getshdr(stab, &stabshdr); if (stabshdr.sh_type == SHT_SYMTAB) { foundstab = 1; break; } } while ((text = elf_nextscn(elf, text)) != NULL) { (void) gelf_getshdr(text, &textshdr); if (strcmp(".text", elf_strptr(elf, ehdr.e_shstrndx, (size_t)textshdr.sh_name)) == 0) { foundtext = 1; break; } } if (!foundstab || !foundtext) return; stabdata = elf_getdata(stab, NULL); textdata = elf_rawdata(text, NULL); for (unsigned symdx = 0; symdx < (stabshdr.sh_size / stabshdr.sh_entsize); symdx++) { (void) gelf_getsym(stabdata, symdx, &ss.ss_sym); if ((GELF_ST_TYPE(ss.ss_sym.st_info) != STT_FUNC) || (ss.ss_sym.st_shndx == SHN_UNDEF)) continue; ss.ss_name = elf_strptr(elf, stabshdr.sh_link, ss.ss_sym.st_name); ss.ss_data = ((uint8_t *)(textdata->d_buf)) + (ss.ss_sym.st_value - textshdr.sh_addr); if (ctf_func_info(fp, symdx, &ss.ss_finfo) == CTF_ERR) { fprintf(stderr, "failed to get funcinfo for: %s\n", ss.ss_name); continue; } (void) callback(fp, &ss); } }
int proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, GElf_Sym *symcopy) { Elf *e; Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; GElf_Ehdr ehdr; int fd, error = -1; size_t i; prmap_t *map; char *s; unsigned long symtabstridx = 0, dynsymstridx = 0; if ((map = proc_name2map(p, object)) == NULL) { DPRINTF("ERROR: couldn't find object %s", object); goto err0; } if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { DPRINTF("ERROR: open %s failed", map->pr_mapname); goto err0; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warn("ERROR: elf_begin() failed"); goto err1; } if (gelf_getehdr(e, &ehdr) == NULL) { warn("ERROR: gelf_getehdr() failed"); goto err2; } /* * Find the index of the STRTAB and SYMTAB sections to locate * symbol names. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); switch (shdr.sh_type) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; default: break; } } /* * Iterate over the Dynamic Symbols table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if ((data = elf_getdata(dynsymscn, NULL))) { DPRINTF("ERROR: elf_getdata() failed"); i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { s = elf_strptr(e, dynsymstridx, sym.st_name); if (s && strcmp(s, symbol) == 0) { memcpy(symcopy, &sym, sizeof(sym)); symcopy->st_value = map->pr_vaddr + sym.st_value; error = 0; goto out; } } } /* * Iterate over the Symbols Table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if (symtabscn == NULL) goto err2; if ((data = elf_getdata(symtabscn, NULL))) { i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { s = elf_strptr(e, symtabstridx, sym.st_name); if (s && strcmp(s, symbol) == 0) { memcpy(symcopy, &sym, sizeof(sym)); error = 0; goto out; } } } out: err2: elf_end(e); err1: close(fd); err0: free(map); return (error); }
int proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, int mask, proc_sym_f *func, void *cd) { Elf *e; int i, fd; prmap_t *map; Elf_Scn *scn, *foundscn = NULL; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; unsigned long stridx = -1; char *s; int error = -1; if ((map = proc_name2map(p, object)) == NULL) return (-1); if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { warn("ERROR: open %s failed", map->pr_mapname); goto err0; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warn("ERROR: elf_begin() failed"); goto err1; } /* * Find the section we are looking for. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); if (which == PR_SYMTAB && shdr.sh_type == SHT_SYMTAB) { foundscn = scn; break; } else if (which == PR_DYNSYM && shdr.sh_type == SHT_DYNSYM) { foundscn = scn; break; } } if (!foundscn) return (-1); stridx = shdr.sh_link; if ((data = elf_getdata(foundscn, NULL)) == NULL) { DPRINTF("ERROR: elf_getdata() failed"); goto err2; } i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && (mask & BIND_LOCAL) == 0) continue; if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && (mask & BIND_GLOBAL) == 0) continue; if (GELF_ST_BIND(sym.st_info) == STB_WEAK && (mask & BIND_WEAK) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && (mask & TYPE_NOTYPE) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && (mask & TYPE_OBJECT) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && (mask & TYPE_FUNC) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && (mask & TYPE_SECTION) == 0) continue; if (GELF_ST_TYPE(sym.st_info) == STT_FILE && (mask & TYPE_FILE) == 0) continue; s = elf_strptr(e, stridx, sym.st_name); sym.st_value += map->pr_vaddr; (*func)(cd, &sym, s); } error = 0; err2: elf_end(e); err1: close(fd); err0: free(map); return (error); }
int proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, size_t namesz, GElf_Sym *symcopy) { Elf *e; Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; GElf_Ehdr ehdr; int fd, error = -1; size_t i; uint64_t rsym; prmap_t *map; char *s; unsigned long symtabstridx = 0, dynsymstridx = 0; if ((map = proc_addr2map(p, addr)) == NULL) return (-1); if (!map->pr_mapname || (fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { warn("ERROR: open %s failed", map->pr_mapname); goto err0; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warn("ERROR: elf_begin() failed"); goto err1; } if (gelf_getehdr(e, &ehdr) == NULL) { warn("ERROR: gelf_getehdr() failed"); goto err2; } /* * Find the index of the STRTAB and SYMTAB sections to locate * symbol names. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); switch (shdr.sh_type) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; default: break; } } /* * Iterate over the Dynamic Symbols table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { DPRINTF("ERROR: elf_getdata() failed"); goto symtab; } i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { /* * Calculate the address mapped to the virtual memory * by rtld. */ rsym = map->pr_vaddr + sym.st_value; if (addr >= rsym && addr <= (rsym + sym.st_size)) { s = elf_strptr(e, dynsymstridx, sym.st_name); if (s) { if (s[0] == '_' && s[1] == 'Z' && s[2]) demangle(s, name, namesz); else strlcpy(name, s, namesz); memcpy(symcopy, &sym, sizeof(sym)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; error = 0; goto out; } } } symtab: /* * Iterate over the Symbols Table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if (symtabscn == NULL) goto err2; if ((data = elf_getdata(symtabscn, NULL)) == NULL) { DPRINTF("ERROR: elf_getdata() failed"); goto err2; } i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { /* * Calculate the address mapped to the virtual memory * by rtld. */ if (ehdr.e_type != ET_EXEC) rsym = map->pr_vaddr + sym.st_value; else rsym = sym.st_value; if (addr >= rsym && addr <= (rsym + sym.st_size)) { s = elf_strptr(e, symtabstridx, sym.st_name); if (s) { if (s[0] == '_' && s[1] == 'Z' && s[2]) demangle(s, name, namesz); else strlcpy(name, s, namesz); memcpy(symcopy, &sym, sizeof(sym)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; error = 0; goto out; } } } out: err2: elf_end(e); err1: close(fd); err0: free(map); return (error); }
int main(int argc, char *argv[]) { int fd; // File Descriptor char *base_ptr; // ptr to our object in memory char *file = argv[1]; // filename struct stat elf_stats; // fstat struct if((fd = open(file, O_RDWR)) == ERR) { printf("couldnt open %s\n", file); return ERR; } if((fstat(fd, &elf_stats))) { printf("could not fstat %s\n", file); close(fd); return ERR; } if((base_ptr = (char *) malloc(elf_stats.st_size)) == NULL) { printf("could not malloc\n"); close(fd); return ERR; } if((read(fd, base_ptr, elf_stats.st_size)) < elf_stats.st_size) { printf("could not read %s\n", file); free(base_ptr); close(fd); return ERR; } /* Check libelf version first */ if(elf_version(EV_CURRENT) == EV_NONE) { printf("WARNING Elf Library is out of date!\n"); } printf("Doing great! \n"); elf_header = (Elf32_Ehdr *) base_ptr; // point elf_header at our object in memory elf = elf_begin(fd, ELF_C_READ, NULL); // Initialize 'elf' pointer to our file descriptor printf("%p, \n", elf_header); printf("%p, \n", elf); /* Iterate through section headers */ while((scn = elf_nextscn(elf, scn)) != 0) { // point shdr at this section header entry printf("%p, ....... \n", elf); gelf_getshdr(scn, &shdr); printf("%p, AAAAAAAAA \n", elf); // print the section header type printf("%p, AAAAAAAAA \n", elf); printf("Type: "); switch(shdr.sh_type) { case SHT_NULL: printf( "SHT_NULL\t"); break; case SHT_PROGBITS: printf( "SHT_PROGBITS"); break; case SHT_SYMTAB: printf( "SHT_SYMTAB"); break; case SHT_STRTAB: printf( "SHT_STRTAB"); break; case SHT_RELA: printf( "SHT_RELA\t"); break; case SHT_HASH: printf( "SHT_HASH\t"); break; case SHT_DYNAMIC: printf( "SHT_DYNAMIC"); break; case SHT_NOTE: printf( "SHT_NOTE\t"); break; case SHT_NOBITS: printf( "SHT_NOBITS"); break; case SHT_REL: printf( "SHT_REL\t"); break; case SHT_SHLIB: printf( "SHT_SHLIB"); break; case SHT_DYNSYM: printf( "SHT_DYNSYM"); break; case SHT_INIT_ARRAY: printf( "SHT_INIT_ARRAY"); break; case SHT_FINI_ARRAY: printf( "SHT_FINI_ARRAY"); break; case SHT_PREINIT_ARRAY: printf( "SHT_PREINIT_ARRAY"); break; case SHT_GROUP: printf( "SHT_GROUP"); break; case SHT_SYMTAB_SHNDX: printf( "SHT_SYMTAB_SHNDX"); break; case SHT_NUM: printf( "SHT_NUM\t"); break; case SHT_LOOS: printf( "SHT_LOOS\t"); break; case SHT_GNU_verdef: printf( "SHT_GNU_verdef"); break; case SHT_GNU_verneed: printf( "SHT_VERNEED"); break; case SHT_GNU_versym: printf( "SHT_GNU_versym"); break; default: printf( "(none) "); break; } // print the section header flags printf("\t("); if(shdr.sh_flags & SHF_WRITE) { printf("W"); } if(shdr.sh_flags & SHF_ALLOC) { printf("A"); } if(shdr.sh_flags & SHF_EXECINSTR) { printf("X"); } if(shdr.sh_flags & SHF_STRINGS) { printf("S"); } printf(")\t"); // the shdr name is in a string table, libelf uses elf_strptr() to find it // using the e_shstrndx value from the elf_header printf("%s\n", elf_strptr(elf, elf_header->e_shstrndx, shdr.sh_name)); } // Iterate through section headers again this time well stop when we find symbols elf = elf_begin(fd, ELF_C_READ, NULL); int symbol_count; int i; while((scn = elf_nextscn(elf, scn)) != NULL) { gelf_getshdr(scn, &shdr); // When we find a section header marked SHT_SYMTAB stop and get symbols if(shdr.sh_type == SHT_SYMTAB) { // edata points to our symbol table edata = elf_getdata(scn, edata); // how many symbols are there? this number comes from the size of // the section divided by the entry size symbol_count = shdr.sh_size / shdr.sh_entsize; // loop through to grab all symbols for(i = 0; i < symbol_count; i++) { // libelf grabs the symbol data using gelf_getsym() gelf_getsym(edata, i, &sym); // print out the value and size printf("%08x %08d ", sym.st_value, sym.st_size); // type of symbol binding switch(ELF32_ST_BIND(sym.st_info)) { case STB_LOCAL: printf("LOCAL"); break; case STB_GLOBAL: printf("GLOBAL"); break; case STB_WEAK: printf("WEAK"); break; case STB_NUM: printf("NUM"); break; case STB_LOOS: printf("LOOS"); break; case STB_HIOS: printf("HIOS"); break; case STB_LOPROC: printf("LOPROC"); break; case STB_HIPROC: printf("HIPROC"); break; default: printf("UNKNOWN"); break; } printf("\t"); // type of symbol switch(ELF32_ST_TYPE(sym.st_info)) { case STT_NOTYPE: printf("NOTYPE"); break; case STT_OBJECT: printf("OBJECT"); break; case STT_FUNC: printf("FUNC"); break; case STT_SECTION: printf("SECTION"); break; case STT_FILE: printf("FILE"); break; case STT_COMMON: printf("COMMON"); break; case STT_TLS: printf("TLS"); break; case STT_NUM: printf("NUM"); break; case STT_LOOS: printf("LOOS"); break; case STT_HIOS: printf("HIOS"); break; case STT_LOPROC: printf("LOPROC"); break; case STT_HIPROC: printf("HIPROC"); break; default: printf("UNKNOWN"); break; } printf("\t"); // the name of the symbol is somewhere in a string table // we know which one using the shdr.sh_link member // libelf grabs the string using elf_strptr() printf("%s\n", elf_strptr(elf, shdr.sh_link, sym.st_name)); } } } return 0; }
int main (void) { int result = 0; size_t cnt; AsmCtx_t *ctx; Elf *elf; int fd; elf_version (EV_CURRENT); Ebl *ebl = ebl_openbackend_machine (EM_386); if (ebl == NULL) { puts ("cannot open backend library"); return 1; } ctx = asm_begin (fname, ebl, false); if (ctx == NULL) { printf ("cannot create assembler context: %s\n", asm_errmsg (-1)); return 1; } if (asm_newcomsym (ctx, "commsym", 4, 16) == NULL) { printf ("cannot create common symbol: %s\n", asm_errmsg (-1)); asm_abort (ctx); return 1; } /* Create the output file. */ if (asm_end (ctx) != 0) { printf ("cannot create output file: %s\n", asm_errmsg (-1)); asm_abort (ctx); return 1; } /* Check the file. */ fd = open (fname, O_RDONLY); if (fd == -1) { printf ("cannot open generated file: %m\n"); result = 1; goto out; } elf = elf_begin (fd, ELF_C_READ, NULL); if (elf == NULL) { printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1)); result = 1; goto out_close; } if (elf_kind (elf) != ELF_K_ELF) { puts ("not a valid ELF file"); result = 1; goto out_close2; } for (cnt = 1; 1; ++cnt) { Elf_Scn *scn; GElf_Shdr shdr_mem; GElf_Shdr *shdr; scn = elf_getscn (elf, cnt); if (scn == NULL) { printf ("cannot get section %Zd: %s\n", cnt, elf_errmsg (-1)); result = 1; continue; } shdr = gelf_getshdr (scn, &shdr_mem); if (shdr == NULL) { printf ("cannot get section header for section %Zd: %s\n", cnt, elf_errmsg (-1)); result = 1; continue; } /* We are looking for the symbol table. */ if (shdr->sh_type != SHT_SYMTAB) continue; for (cnt = 1; cnt< (shdr->sh_size / gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT)); ++cnt) { GElf_Sym sym_mem; GElf_Sym *sym; if (cnt > 1) { puts ("too many symbol"); result = 1; break; } sym = gelf_getsym (elf_getdata (scn, NULL), cnt, &sym_mem); if (sym == NULL) { printf ("cannot get symbol %zu: %s\n", cnt, elf_errmsg (-1)); result = 1; } else { if (sym->st_shndx != SHN_COMMON) { printf ("expected common symbol, got section %u\n", (unsigned int) sym->st_shndx); result = 1; } if (sym->st_value != 16) { printf ("requested alignment 16, is %" PRIuMAX "\n", (uintmax_t) sym->st_value); result = 1; } if (sym->st_size != 4) { printf ("requested size 4, is %" PRIuMAX "\n", (uintmax_t) sym->st_value); result = 1; } } } break; } out_close2: elf_end (elf); out_close: close (fd); out: /* We don't need the file anymore. */ unlink (fname); ebl_closebackend (ebl); return result; }
static GHashTable* parse_plt(Elf *e, const char *filename) { GElf_Shdr shdr; Elf_Data *plt_data; uintptr_t plt_base; size_t plt_section_index = xelf_section_by_name(e, ".plt", filename, &plt_data, &shdr); if (plt_section_index == 0) { VERB1 log("No .plt section found for %s", filename); return NULL; } plt_base = shdr.sh_addr; /* Find the relocation section for .plt (typically .rela.plt), together * with its symbol and string table */ Elf_Data *rela_plt_data = NULL; Elf_Data *plt_symbols = NULL; size_t stringtable = 0; Elf_Scn *scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { VERB1 log_elf_error("gelf_getshdr", filename); continue; } if (shdr.sh_type == SHT_RELA && shdr.sh_info == plt_section_index) { rela_plt_data = elf_getdata(scn, NULL); if (rela_plt_data == NULL) { VERB1 log_elf_error("elf_getdata", filename); break; } /* Get symbol section for .rela.plt */ Elf_Scn *symscn = elf_getscn(e, shdr.sh_link); if (symscn == NULL) { VERB1 log_elf_error("elf_getscn", filename); break; } plt_symbols = elf_getdata(symscn, NULL); if (plt_symbols == NULL) { VERB1 log_elf_error("elf_getdata", filename); break; } /* Get string table for the symbol table. */ if (gelf_getshdr(symscn, &shdr) != &shdr) { VERB1 log_elf_error("gelf_getshdr", filename); break; } stringtable = shdr.sh_link; break; } } if (stringtable == 0) { VERB1 log("Unable to read symbol table for .plt for file %s", filename); return NULL; } /* Init hash table * keys are pointers to integers which we allocate with malloc * values are owned by libelf, so we don't need to free them */ GHashTable *hash = g_hash_table_new_full(g_int64_hash, g_int64_equal, free, NULL); /* PLT looks like this (see also AMD64 ABI, page 78): * * Disassembly of section .plt: * * 0000003463e01010 <attr_removef@plt-0x10>: * 3463e01010: ff 35 2a 2c 20 00 pushq 0x202c2a(%rip) <-- here is plt_base * 3463e01016: ff 25 2c 2c 20 00 jmpq *0x202c2c(%rip) each "slot" is 16B wide * 3463e0101c: 0f 1f 40 00 nopl 0x0(%rax) 0-th slot is skipped * * 0000003463e01020 <attr_removef@plt>: * 3463e01020: ff 25 2a 2c 20 00 jmpq *0x202c2a(%rip) * 3463e01026: 68 00 00 00 00 pushq $0x0 <-- this is the number we want * 3463e0102b: e9 e0 ff ff ff jmpq 3463e01010 <_init+0x18> * * 0000003463e01030 <fgetxattr@plt>: * 3463e01030: ff 25 22 2c 20 00 jmpq *0x202c22(%rip) * 3463e01036: 68 01 00 00 00 pushq $0x1 * 3463e0103b: e9 d0 ff ff ff jmpq 3463e01010 <_init+0x18> */ unsigned plt_offset; uint32_t *plt_index; GElf_Rela rela; GElf_Sym symb; for (plt_offset = 16; plt_offset < plt_data->d_size; plt_offset += 16) { plt_index = (uint32_t*)(plt_data->d_buf + plt_offset + 7); if(gelf_getrela(rela_plt_data, *plt_index, &rela) != &rela) { VERB1 log_elf_error("gelf_getrela", filename); continue; } if(gelf_getsym(plt_symbols, GELF_R_SYM(rela.r_info), &symb) != &symb) { VERB1 log_elf_error("gelf_getsym", filename); continue; } char *symbol = elf_strptr(e, stringtable, symb.st_name); uintptr_t *addr = addr_alloc((uintptr_t)(plt_base + plt_offset)); VERB3 log("[%02x] %jx: %s", *plt_index, (uintptr_t)(*addr), symbol); g_hash_table_insert(hash, addr, symbol); } return hash; }
static gboolean handle_dwarf2_section (DebuginfoData *data, GHashTable *files, GError **error) { Elf_Data *e_data; int i; debug_section_t *debug_sections; ptr_size = 0; if (data->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) { do_read_16 = buf_read_ule16; do_read_32 = buf_read_ule32; } else if (data->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) { do_read_16 = buf_read_ube16; do_read_32 = buf_read_ube32; } else { return flatpak_fail (error, "%s: Wrong ELF data encoding", data->filename); } debug_sections = data->debug_sections; if (debug_sections[DEBUG_INFO].data != NULL) { unsigned char *ptr, *endcu, *endsec; uint32_t value; struct abbrev_tag *t; g_autofree REL *relbuf = NULL; if (debug_sections[DEBUG_INFO].relsec) { Elf_Scn *scn; int ndx, maxndx; GElf_Rel rel; GElf_Rela rela; GElf_Sym sym; GElf_Addr base = data->shdr[debug_sections[DEBUG_INFO].sec].sh_addr; Elf_Data *symdata = NULL; int rtype; i = debug_sections[DEBUG_INFO].relsec; scn = data->scns[i]; e_data = elf_getdata (scn, NULL); g_assert (e_data != NULL && e_data->d_buf != NULL); g_assert (elf_getdata (scn, e_data) == NULL); g_assert (e_data->d_off == 0); g_assert (e_data->d_size == data->shdr[i].sh_size); maxndx = data->shdr[i].sh_size / data->shdr[i].sh_entsize; relbuf = g_malloc (maxndx * sizeof (REL)); reltype = data->shdr[i].sh_type; symdata = elf_getdata (data->scns[data->shdr[i].sh_link], NULL); g_assert (symdata != NULL && symdata->d_buf != NULL); g_assert (elf_getdata (data->scns[data->shdr[i].sh_link], symdata) == NULL); g_assert (symdata->d_off == 0); g_assert (symdata->d_size == data->shdr[data->shdr[i].sh_link].sh_size); for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx) { if (data->shdr[i].sh_type == SHT_REL) { gelf_getrel (e_data, ndx, &rel); rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } else { gelf_getrela (e_data, ndx, &rela); } gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym); /* Relocations against section symbols are uninteresting in REL. */ if (data->shdr[i].sh_type == SHT_REL && sym.st_value == 0) continue; /* Only consider relocations against .debug_str, .debug_line and .debug_abbrev. */ if (sym.st_shndx != debug_sections[DEBUG_STR].sec && sym.st_shndx != debug_sections[DEBUG_LINE].sec && sym.st_shndx != debug_sections[DEBUG_ABBREV].sec) continue; rela.r_addend += sym.st_value; rtype = ELF64_R_TYPE (rela.r_info); switch (data->ehdr.e_machine) { case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32) goto fail; break; case EM_386: if (rtype != R_386_32) goto fail; break; case EM_PPC: case EM_PPC64: if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32) goto fail; break; case EM_S390: if (rtype != R_390_32) goto fail; break; case EM_IA_64: if (rtype != R_IA64_SECREL32LSB) goto fail; break; case EM_X86_64: if (rtype != R_X86_64_32) goto fail; break; case EM_ALPHA: if (rtype != R_ALPHA_REFLONG) goto fail; break; #if defined(EM_AARCH64) && defined(R_AARCH64_ABS32) case EM_AARCH64: if (rtype != R_AARCH64_ABS32) goto fail; break; #endif case EM_68K: if (rtype != R_68K_32) goto fail; break; default: fail: return flatpak_fail (error, "%s: Unhandled relocation %d in .debug_info section", data->filename, rtype); } relend->ptr = debug_sections[DEBUG_INFO].data + (rela.r_offset - base); relend->addend = rela.r_addend; ++relend; } if (relbuf == relend) { g_free (relbuf); relbuf = NULL; relend = NULL; } else { qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp); } } ptr = debug_sections[DEBUG_INFO].data; relptr = relbuf; endsec = ptr + debug_sections[DEBUG_INFO].size; while (ptr != NULL && ptr < endsec) { g_autoptr(GHashTable) abbrev = NULL; if (ptr + 11 > endsec) return flatpak_fail (error, "%s: .debug_info CU header too small", data->filename); endcu = ptr + 4; endcu += read_32 (ptr); if (endcu == ptr + 0xffffffff) return flatpak_fail (error, "%s: 64-bit DWARF not supported", data->filename); if (endcu > endsec) return flatpak_fail (error, "%s: .debug_info too small", data->filename); cu_version = read_16 (ptr); if (cu_version != 2 && cu_version != 3 && cu_version != 4) return flatpak_fail (error, "%s: DWARF version %d unhandled", data->filename, cu_version); value = read_32_relocated (ptr); if (value >= debug_sections[DEBUG_ABBREV].size) { if (debug_sections[DEBUG_ABBREV].data == NULL) return flatpak_fail (error, "%s: .debug_abbrev not present", data->filename); else return flatpak_fail (error, "%s: DWARF CU abbrev offset too large", data->filename); } if (ptr_size == 0) { ptr_size = read_1 (ptr); if (ptr_size != 4 && ptr_size != 8) return flatpak_fail (error, "%s: Invalid DWARF pointer size %d", data->filename, ptr_size); } else if (read_1 (ptr) != ptr_size) { return flatpak_fail (error, "%s: DWARF pointer size differs between CUs", data->filename); } abbrev = read_abbrev (data, debug_sections[DEBUG_ABBREV].data + value); while (ptr < endcu) { guint entry = read_uleb128 (ptr); if (entry == 0) continue; t = g_hash_table_lookup (abbrev, GINT_TO_POINTER (entry)); if (t == NULL) { g_warning ("%s: Could not find DWARF abbreviation %d", data->filename, entry); } else { ptr = handle_attributes (data, ptr, t, files, error); if (ptr == NULL) return FALSE; } } } } return TRUE; }