/* * Converts a pointer into a function name and an offset from the start of * this function. Returns NULL if it doesn't know. * Wildly inefficient - we ought to use a binary search. */ static char *get_name(unsigned long laddr, unsigned long *diff, int *frameoffset) { unsigned long i; SYMR symbol; PDR procp; char *cp; static LDFILE *ldp = NULL; /* Read the LDFILE structure */ if (!ldp) { if (NULL == (ldp = ldopen(prog_name, NULL))) { return NULL; } } /* Maybe it's stripped */ if (!SYMTAB(ldp)) return NULL; /* Loop through the procedure data to find the correct address */ for (i = 0; i < SYMHEADER(ldp).ipdMax; i++) { if (FAILURE == ldgetpd(ldp, i, &procp)) continue; if (laddr < procp.adr) break; } if (--i < 0) return NULL; /* Read the symbol entry and then the name of this procedure */ ldgetpd(ldp, i, &procp); *diff = laddr - procp.adr; if (FAILURE == ldtbread(ldp, procp.isym, &symbol)) return NULL; *frameoffset = procp.frameoffset; cp = ldgetname(ldp, &symbol); /* printf("Function=%s frameoffset=%d, regoff=%d, fregoff=%d\n", cp, procp.frameoffset, procp.regoffset, procp.fregoffset); */ return cp; }
/* * Converts a pointer into a function name and an offset from the start of * this function. Returns NULL if it doesn't know. * Wildly inefficient - we ought to use a binary search. */ static char *get_name(unsigned long laddr, signed long *diff) { static LDFILE *ldp = NULL; unsigned long i; SYMR symbol; PDR procp; /* Read the LDFILE structure */ if (!ldp) { if (NULL == (ldp = ldopen(prog_name, NULL))) { return NULL; } } /* Maybe it's stripped */ if (!SYMTAB(ldp)) return NULL; /* Loop through the procedure data to find the correct address */ for (i = 0; i < SYMHEADER(ldp).ipdMax; i++) { if (FAILURE == ldgetpd(ldp, i, &procp)) continue; if (laddr < procp.adr) break; } if (--i < 0) return NULL; /* Read the symbol entry and then the name of this procedure */ ldgetpd(ldp, i, &procp); *diff = laddr - procp.adr; if (FAILURE == ldtbread(ldp, procp.isym, &symbol)) return NULL; return ldgetname(ldp, &symbol); }
/* * Read and process the relocations for one link object, we assume all * relocation sections for loadable segments are stored contiguously in * the file. */ int elf_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel) { ulong_t relbgn, relend, relsiz, basebgn, pltbgn, pltend; ulong_t _pltbgn, _pltend; ulong_t dsymndx, roffset, rsymndx, psymndx = 0; uchar_t rtype; long value, pvalue; Sym *symref, *psymref, *symdef, *psymdef; Syminfo *sip; char *name, *pname; Rt_map *_lmp, *plmp; int ret = 1, noplt = 0; int relacount = RELACOUNT(lmp), plthint = 0; Rel *rel; uint_t binfo, pbinfo; APlist *bound = NULL; /* * Although only necessary for lazy binding, initialize the first * global offset entry to go to elf_rtbndr(). dbx(1) seems * to find this useful. */ if ((plt == 0) && PLTGOT(lmp)) { mmapobj_result_t *mpp; /* * Make sure the segment is writable. */ if ((((mpp = find_segment((caddr_t)PLTGOT(lmp), lmp)) != NULL) && ((mpp->mr_prot & PROT_WRITE) == 0)) && ((set_prot(lmp, mpp, 1) == 0) || (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) return (0); elf_plt_init(PLTGOT(lmp), (caddr_t)lmp); } /* * Initialize the plt start and end addresses. */ if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0) pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp)); relsiz = (ulong_t)(RELENT(lmp)); basebgn = ADDR(lmp); if (PLTRELSZ(lmp)) plthint = PLTRELSZ(lmp) / relsiz; /* * If we've been called upon to promote an RTLD_LAZY object to an * RTLD_NOW then we're only interested in scaning the .plt table. * An uninitialized .plt is the case where the associated got entry * points back to the plt itself. Determine the range of the real .plt * entries using the _PROCEDURE_LINKAGE_TABLE_ symbol. */ if (plt) { Slookup sl; Sresult sr; relbgn = pltbgn; relend = pltend; if (!relbgn || (relbgn == relend)) return (1); /* * Initialize the symbol lookup, and symbol result, data * structures. */ SLOOKUP_INIT(sl, MSG_ORIG(MSG_SYM_PLT), lmp, lmp, ld_entry_cnt, elf_hash(MSG_ORIG(MSG_SYM_PLT)), 0, 0, 0, LKUP_DEFT); SRESULT_INIT(sr, MSG_ORIG(MSG_SYM_PLT)); if (elf_find_sym(&sl, &sr, &binfo, NULL) == 0) return (1); symdef = sr.sr_sym; _pltbgn = symdef->st_value; if (!(FLAGS(lmp) & FLG_RT_FIXED) && (symdef->st_shndx != SHN_ABS)) _pltbgn += basebgn; _pltend = _pltbgn + (((PLTRELSZ(lmp) / relsiz)) * M_PLT_ENTSIZE) + M_PLT_RESERVSZ; } else { /* * The relocation sections appear to the run-time linker as a * single table. Determine the address of the beginning and end * of this table. There are two different interpretations of * the ABI at this point: * * o The REL table and its associated RELSZ indicate the * concatenation of *all* relocation sections (this is the * model our link-editor constructs). * * o The REL table and its associated RELSZ indicate the * concatenation of all *but* the .plt relocations. These * relocations are specified individually by the JMPREL and * PLTRELSZ entries. * * Determine from our knowledege of the relocation range and * .plt range, the range of the total relocation table. Note * that one other ABI assumption seems to be that the .plt * relocations always follow any other relocations, the * following range checking drops that assumption. */ relbgn = (ulong_t)(REL(lmp)); relend = relbgn + (ulong_t)(RELSZ(lmp)); if (pltbgn) { if (!relbgn || (relbgn > pltbgn)) relbgn = pltbgn; if (!relbgn || (relend < pltend)) relend = pltend; } } if (!relbgn || (relbgn == relend)) { DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE)); return (1); } DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START)); /* * If we're processing a dynamic executable in lazy mode there is no * need to scan the .rel.plt table, however if we're processing a shared * object in lazy mode the .got addresses associated to each .plt must * be relocated to reflect the location of the shared object. */ if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0) && (FLAGS(lmp) & FLG_RT_FIXED)) noplt = 1; sip = SYMINFO(lmp); /* * Loop through relocations. */ while (relbgn < relend) { mmapobj_result_t *mpp; uint_t sb_flags = 0; rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH); /* * If this is a RELATIVE relocation in a shared object (the * common case), and if we are not debugging, then jump into a * tighter relocation loop (elf_reloc_relative). */ if ((rtype == R_386_RELATIVE) && ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) { if (relacount) { relbgn = elf_reloc_relative_count(relbgn, relacount, relsiz, basebgn, lmp, textrel, 0); relacount = 0; } else { relbgn = elf_reloc_relative(relbgn, relend, relsiz, basebgn, lmp, textrel, 0); } if (relbgn >= relend) break; rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info, M_MACH); } roffset = ((Rel *)relbgn)->r_offset; /* * If this is a shared object, add the base address to offset. */ if (!(FLAGS(lmp) & FLG_RT_FIXED)) { /* * If we're processing lazy bindings, we have to step * through the plt entries and add the base address * to the corresponding got entry. */ if (plthint && (plt == 0) && (rtype == R_386_JMP_SLOT) && ((MODE(lmp) & RTLD_NOW) == 0)) { relbgn = elf_reloc_relative_count(relbgn, plthint, relsiz, basebgn, lmp, textrel, 0); plthint = 0; continue; } roffset += basebgn; } rsymndx = ELF_R_SYM(((Rel *)relbgn)->r_info); rel = (Rel *)relbgn; relbgn += relsiz; /* * Optimizations. */ if (rtype == R_386_NONE) continue; if (noplt && ((ulong_t)rel >= pltbgn) && ((ulong_t)rel < pltend)) { relbgn = pltend; continue; } /* * If we're promoting plts, determine if this one has already * been written. */ if (plt && ((*(ulong_t *)roffset < _pltbgn) || (*(ulong_t *)roffset > _pltend))) continue; /* * If this relocation is not against part of the image * mapped into memory we skip it. */ if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL) { elf_reloc_bad(lmp, (void *)rel, rtype, roffset, rsymndx); continue; } binfo = 0; /* * If a symbol index is specified then get the symbol table * entry, locate the symbol definition, and determine its * address. */ if (rsymndx) { /* * If a Syminfo section is provided, determine if this * symbol is deferred, and if so, skip this relocation. */ if (sip && is_sym_deferred((ulong_t)rel, basebgn, lmp, textrel, sip, rsymndx)) continue; /* * Get the local symbol table entry. */ symref = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); /* * If this is a local symbol, just use the base address. * (we should have no local relocations in the * executable). */ if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) { value = basebgn; name = NULL; /* * Special case TLS relocations. */ if (rtype == R_386_TLS_DTPMOD32) { /* * Use the TLS modid. */ value = TLSMODID(lmp); } else if (rtype == R_386_TLS_TPOFF) { if ((value = elf_static_tls(lmp, symref, rel, rtype, 0, roffset, 0)) == 0) { ret = 0; break; } } } else { /* * If the symbol index is equal to the previous * symbol index relocation we processed then * reuse the previous values. (Note that there * have been cases where a relocation exists * against a copy relocation symbol, our ld(1) * should optimize this away, but make sure we * don't use the same symbol information should * this case exist). */ if ((rsymndx == psymndx) && (rtype != R_386_COPY)) { /* LINTED */ if (psymdef == 0) { DBG_CALL(Dbg_bind_weak(lmp, (Addr)roffset, (Addr) (roffset - basebgn), name)); continue; } /* LINTED */ value = pvalue; /* LINTED */ name = pname; /* LINTED */ symdef = psymdef; /* LINTED */ symref = psymref; /* LINTED */ _lmp = plmp; /* LINTED */ binfo = pbinfo; if ((LIST(_lmp)->lm_tflags | AFLAGS(_lmp)) & LML_TFLG_AUD_SYMBIND) { value = audit_symbind(lmp, _lmp, /* LINTED */ symdef, dsymndx, value, &sb_flags); } } else { Slookup sl; Sresult sr; /* * Lookup the symbol definition. * Initialize the symbol lookup, and * symbol result, data structures. */ name = (char *)(STRTAB(lmp) + symref->st_name); SLOOKUP_INIT(sl, name, lmp, 0, ld_entry_cnt, 0, rsymndx, symref, rtype, LKUP_STDRELOC); SRESULT_INIT(sr, name); symdef = NULL; if (lookup_sym(&sl, &sr, &binfo, in_nfavl)) { name = (char *)sr.sr_name; _lmp = sr.sr_dmap; symdef = sr.sr_sym; } /* * If the symbol is not found and the * reference was not to a weak symbol, * report an error. Weak references * may be unresolved. */ /* BEGIN CSTYLED */ if (symdef == 0) { if (sl.sl_bind != STB_WEAK) { if (elf_reloc_error(lmp, name, rel, binfo)) continue; ret = 0; break; } else { psymndx = rsymndx; psymdef = 0; DBG_CALL(Dbg_bind_weak(lmp, (Addr)roffset, (Addr) (roffset - basebgn), name)); continue; } } /* END CSTYLED */ /* * If symbol was found in an object * other than the referencing object * then record the binding. */ if ((lmp != _lmp) && ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) { if (aplist_test(&bound, _lmp, AL_CNT_RELBIND) == 0) { ret = 0; break; } } /* * Calculate the location of definition; * symbol value plus base address of * containing shared object. */ if (IS_SIZE(rtype)) value = symdef->st_size; else value = symdef->st_value; if (!(FLAGS(_lmp) & FLG_RT_FIXED) && !(IS_SIZE(rtype)) && (symdef->st_shndx != SHN_ABS) && (ELF_ST_TYPE(symdef->st_info) != STT_TLS)) value += ADDR(_lmp); /* * Retain this symbol index and the * value in case it can be used for the * subsequent relocations. */ if (rtype != R_386_COPY) { psymndx = rsymndx; pvalue = value; pname = name; psymdef = symdef; psymref = symref; plmp = _lmp; pbinfo = binfo; } if ((LIST(_lmp)->lm_tflags | AFLAGS(_lmp)) & LML_TFLG_AUD_SYMBIND) { dsymndx = (((uintptr_t)symdef - (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp)); value = audit_symbind(lmp, _lmp, symdef, dsymndx, value, &sb_flags); } } /* * If relocation is PC-relative, subtract * offset address. */ if (IS_PC_RELATIVE(rtype)) value -= roffset; /* * Special case TLS relocations. */ if (rtype == R_386_TLS_DTPMOD32) { /* * Relocation value is the TLS modid. */ value = TLSMODID(_lmp); } else if (rtype == R_386_TLS_TPOFF) { if ((value = elf_static_tls(_lmp, symdef, rel, rtype, name, roffset, value)) == 0) { ret = 0; break; } } } } else { /* * Special cases. */ if (rtype == R_386_TLS_DTPMOD32) { /* * TLS relocation value is the TLS modid. */ value = TLSMODID(lmp); } else value = basebgn; name = NULL; } DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, NULL, 0, name)); /* * Make sure the segment is writable. */ if (((mpp->mr_prot & PROT_WRITE) == 0) && ((set_prot(lmp, mpp, 1) == 0) || (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) { ret = 0; break; } /* * Call relocation routine to perform required relocation. */ switch (rtype) { case R_386_COPY: if (elf_copy_reloc(name, symref, lmp, (void *)roffset, symdef, _lmp, (const void *)value) == 0) ret = 0; break; case R_386_JMP_SLOT: if (((LIST(lmp)->lm_tflags | AFLAGS(lmp)) & (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && AUDINFO(lmp)->ai_dynplts) { int fail = 0; int pltndx = (((ulong_t)rel - (uintptr_t)JMPREL(lmp)) / relsiz); int symndx = (((uintptr_t)symdef - (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp)); (void) elf_plt_trace_write(roffset, lmp, _lmp, symdef, symndx, pltndx, (caddr_t)value, sb_flags, &fail); if (fail) ret = 0; } else { /* * Write standard PLT entry to jump directly * to newly bound function. */ DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD, (Xword)roffset, (Xword)value)); *(ulong_t *)roffset = value; } break; default: /* * Write the relocation out. */ if (do_reloc_rtld(rtype, (uchar_t *)roffset, (Word *)&value, name, NAME(lmp), LIST(lmp)) == 0) ret = 0; DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD, (Xword)roffset, (Xword)value)); } if ((ret == 0) && ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0)) break; if (binfo) { DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset, (Off)(roffset - basebgn), (Xword)(-1), PLT_T_FULL, _lmp, (Addr)value, symdef->st_value, name, binfo)); } } return (relocate_finish(lmp, bound, ret)); }
/* * Function binding routine - invoked on the first call to a function through * the procedure linkage table; * passes first through an assembly language interface. * * Takes the offset into the relocation table of the associated * relocation entry and the address of the link map (rt_private_map struct) * for the entry. * * Returns the address of the function referenced after re-writing the PLT * entry to invoke the function directly. * * On error, causes process to terminate with a signal. */ ulong_t elf_bndr(Rt_map *lmp, ulong_t reloff, caddr_t from) { Rt_map *nlmp, *llmp; ulong_t addr, symval, rsymndx; char *name; Rel *rptr; Sym *rsym, *nsym; uint_t binfo, sb_flags = 0, dbg_class; Slookup sl; Sresult sr; int entry, lmflags; Lm_list *lml; /* * For compatibility with libthread (TI_VERSION 1) we track the entry * value. A zero value indicates we have recursed into ld.so.1 to * further process a locking request. Under this recursion we disable * tsort and cleanup activities. */ entry = enter(0); lml = LIST(lmp); if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { dbg_class = dbg_desc->d_class; dbg_desc->d_class = 0; } /* * Perform some basic sanity checks. If we didn't get a load map or * the relocation offset is invalid then its possible someone has walked * over the .got entries or jumped to plt0 out of the blue. */ if (!lmp || ((reloff % sizeof (Rel)) != 0)) { Conv_inv_buf_t inv_buf; eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF), conv_reloc_386_type(R_386_JMP_SLOT, 0, &inv_buf), EC_NATPTR(lmp), EC_XWORD(reloff), EC_NATPTR(from)); rtldexit(lml, 1); } /* * Use relocation entry to get symbol table entry and symbol name. */ addr = (ulong_t)JMPREL(lmp); rptr = (Rel *)(addr + reloff); rsymndx = ELF_R_SYM(rptr->r_info); rsym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); name = (char *)(STRTAB(lmp) + rsym->st_name); /* * Determine the last link-map of this list, this'll be the starting * point for any tsort() processing. */ llmp = lml->lm_tail; /* * Find definition for symbol. Initialize the symbol lookup, and * symbol result, data structures. */ SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, rsymndx, rsym, 0, LKUP_DEFT); SRESULT_INIT(sr, name); if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) { eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), demangle(name)); rtldexit(lml, 1); } name = (char *)sr.sr_name; nlmp = sr.sr_dmap; nsym = sr.sr_sym; symval = nsym->st_value; if (!(FLAGS(nlmp) & FLG_RT_FIXED) && (nsym->st_shndx != SHN_ABS)) symval += ADDR(nlmp); if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { /* * Record that this new link map is now bound to the caller. */ if (bind_one(lmp, nlmp, BND_REFER) == 0) rtldexit(lml, 1); } if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_SYMBIND) { uint_t symndx = (((uintptr_t)nsym - (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); symval = audit_symbind(lmp, nlmp, nsym, symndx, symval, &sb_flags); } if (!(rtld_flags & RT_FL_NOBIND)) { addr = rptr->r_offset; if (!(FLAGS(lmp) & FLG_RT_FIXED)) addr += ADDR(lmp); if (((lml->lm_tflags | AFLAGS(lmp)) & (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && AUDINFO(lmp)->ai_dynplts) { int fail = 0; uint_t pltndx = reloff / sizeof (Rel); uint_t symndx = (((uintptr_t)nsym - (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); symval = (ulong_t)elf_plt_trace_write(addr, lmp, nlmp, nsym, symndx, pltndx, (caddr_t)symval, sb_flags, &fail); if (fail) rtldexit(lml, 1); } else { /* * Write standard PLT entry to jump directly * to newly bound function. */ *(ulong_t *)addr = symval; } } /* * Print binding information and rebuild PLT entry. */ DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)), (Xword)(reloff / sizeof (Rel)), PLT_T_FULL, nlmp, (Addr)symval, nsym->st_value, name, binfo)); /* * Complete any processing for newly loaded objects. Note we don't * know exactly where any new objects are loaded (we know the object * that supplied the symbol, but others may have been loaded lazily as * we searched for the symbol), so sorting starts from the last * link-map know on entry to this routine. */ if (entry) load_completion(llmp); /* * Some operations like dldump() or dlopen()'ing a relocatable object * result in objects being loaded on rtld's link-map, make sure these * objects are initialized also. */ if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init) load_completion(nlmp); /* * Make sure the object to which we've bound has had it's .init fired. * Cleanup before return to user code. */ if (entry) { is_dep_init(nlmp, lmp); leave(lml, 0); } if (lmflags & LML_FLG_RTLDLM) dbg_desc->d_class = dbg_class; return (symval); }
void Object::load_object(bool sharedLibrary) { char* file = strdup(file_.c_str()); bool did_open = false, success=true, text_read=false; LDFILE *ldptr = NULL; HDRR sym_hdr; pCHDRR sym_tab_ptr = NULL; long index=0; SYMR symbol; unsigned short sectindex=1; SCNHDR secthead; filehdr fhdr; unsigned nsymbols; pdvector<Symbol> allSymbols; pdvector<Address> all_addr(9, 0); pdvector<long> all_size(9, 0); pdvector<bool> all_dex(9, false); pdvector<long> all_disk(9, 0); if (!(ldptr = ldopen(file, ldptr))) { log_perror(err_func_, file); success = false; bperr("failed open\n"); free(file); return; } did_open = true; if (TYPE(ldptr) != ALPHAMAGIC) { bperr( "%s is not an alpha executable\n", file); success = false; bperr("failed magic region\n"); ldclose(ldptr); free(file); return; } // Read the text and data sections fhdr = HEADER(ldptr); unsigned short fmax = fhdr.f_nscns; dynamicallyLinked = false; // Life would be so much easier if there were a guaranteed order for // these sections. But the man page makes no mention of it. while (sectindex < fmax) { if (ldshread(ldptr, sectindex, §head) == SUCCESS) { // cout << "Section: " << secthead.s_name << "\tStart: " << secthead.s_vaddr // << "\tEnd: " << secthead.s_vaddr + secthead.s_size << endl; if (!P_strcmp(secthead.s_name, ".text")) { code_len_ = (Word) secthead.s_size; Word *buffer = new Word[code_len_+1]; code_ptr_ = buffer; code_off_ = (Address) secthead.s_vaddr; if (!obj_read_section(secthead, ldptr, buffer)) { success = false; bperr("failed text region\n"); ldclose(ldptr); free(file); return; } text_read = true; } else if (!P_strcmp(secthead.s_name, ".data")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_D_INDEX] = secthead.s_vaddr; all_size[K_D_INDEX] = secthead.s_size; all_dex[K_D_INDEX] = true; all_disk[K_D_INDEX] = secthead.s_scnptr; } else { bperr("failed data region\n"); success = false; ldclose(ldptr); free(file); return; } } else if (!P_strcmp(secthead.s_name, ".xdata")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_XD_INDEX] = secthead.s_vaddr; all_size[K_XD_INDEX] = secthead.s_size; all_dex[K_XD_INDEX] = true; all_disk[K_XD_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".sdata")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_SD_INDEX] = secthead.s_vaddr; all_size[K_SD_INDEX] = secthead.s_size; all_dex[K_SD_INDEX] = true; all_disk[K_SD_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".rdata")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_RD_INDEX] = secthead.s_vaddr; all_size[K_RD_INDEX] = secthead.s_size; all_dex[K_RD_INDEX] = true; all_disk[K_RD_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".lit4")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_L4_INDEX] = secthead.s_vaddr; all_size[K_L4_INDEX] = secthead.s_size; all_dex[K_L4_INDEX] = true; all_disk[K_L4_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".lita")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_LA_INDEX] = secthead.s_vaddr; all_size[K_LA_INDEX] = secthead.s_size; all_dex[K_LA_INDEX] = true; all_disk[K_LA_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".rconst")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_RC_INDEX] = secthead.s_vaddr; all_size[K_RC_INDEX] = secthead.s_size; all_dex[K_RC_INDEX] = true; all_disk[K_RC_INDEX] = secthead.s_scnptr; } } else if (!P_strcmp(secthead.s_name, ".lit8")) { if (secthead.s_vaddr && secthead.s_scnptr) { all_addr[K_L8_INDEX] = secthead.s_vaddr; all_size[K_L8_INDEX] = secthead.s_size; all_dex[K_L8_INDEX] = true; all_disk[K_L8_INDEX] = secthead.s_scnptr; } } else if (!P_strncmp(secthead.s_name, ".dynamic", 8)) { // a section .dynamic implies the program is dynamically linked dynamicallyLinked = true; } } else { success = false; bperr("failed header region\n"); ldclose(ldptr); free(file); return; } sectindex++; } if (!text_read) { success = false; bperr("failed text region\n"); ldclose(ldptr); free(file); return; } // I am assuming that .data comes before all other data sections // I will include all other contiguous data sections // Determine the size of the data section(s) if (all_disk[K_D_INDEX]) { if (!find_data_region(all_addr, all_size, all_disk, data_len_, data_off_)) { success = false; bperr("failed find data region\n"); ldclose(ldptr); free(file); return; } } // Now read in the data from the assorted data regions Word *buffer = new Word[data_len_+1]; data_ptr_ = buffer; if (!read_data_region(all_addr, all_size, all_disk, data_len_, data_off_, buffer, ldptr)) { success = false; bperr("failed read data region\n"); ldclose(ldptr); free(file); return; } // COFF doesn't have segments, so the entire code/data sections are valid code_vldS_ = code_off_; code_vldE_ = code_off_ + code_len_; data_vldS_ = data_off_; data_vldE_ = data_off_ + code_len_; // Check for the symbol table if (!(sym_tab_ptr = PSYMTAB(ldptr))) { success = false; bperr("failed check for symbol table - object may be strip'd!\n"); ldclose(ldptr); free(file); return; } // Read the symbol table sym_hdr = SYMHEADER(ldptr); if (sym_hdr.magic != magicSym) { success = false; bperr("failed check for magic symbol\n"); ldclose(ldptr); free(file); return; } if (!(sym_tab_ptr = SYMTAB(ldptr))) { success = false; bperr("failed read symbol table\n"); ldclose(ldptr); free(file); return; } if (LDSWAP(ldptr)) { // These bytes are swapped // supposedly libsex.a will unswap them assert(0); } pdstring module = "DEFAULT_MODULE"; if (sharedLibrary) { module = file_; allSymbols.push_back(Symbol(module, module, Symbol::PDST_MODULE, Symbol::SL_GLOBAL, (Address) 0, false)); } else { module = "DEFAULT_MODULE"; } pdstring name = "DEFAULT_SYMBOL"; int moduleEndIdx = -1; dictionary_hash<pdstring, int> fcnNames(pdstring::hash); while (ldtbread(ldptr, index, &symbol) == SUCCESS) { // TODO -- when global? Symbol::SymbolLinkage linkage = Symbol::SL_GLOBAL; Symbol::SymbolType type = Symbol::PDST_UNKNOWN; bool st_kludge = false; bool sym_use = true; char *name = ldgetname(ldptr, &symbol); char prettyName[1024]; switch(symbol.st) { case stProc: case stStaticProc: // Native C++ name demangling. MLD_demangle_string(name, prettyName, 1024, MLD_SHOW_DEMANGLED_NAME | MLD_NO_SPACES); if (strchr(prettyName, '(')) *strchr(prettyName, '(') = 0; name = prettyName; if (symbol.sc == scText && !fcnNames.defines(name)) { type = Symbol::PDST_FUNCTION; fcnNames[name] = 1; } else sym_use = false; break; case stGlobal: case stConstant: case stStatic: switch(symbol.sc) { case scData: case scSData: case scBss: case scSBss: case scRData: case scRConst: case scTlsData: case scTlsBss: type = Symbol::PDST_OBJECT; break; default: sym_use = false; } break; case stLocal: case stParam: linkage = Symbol::SL_LOCAL; switch(symbol.sc) { case scAbs: case scRegister: case scVar: case scVarRegister: case scUnallocated: type = Symbol::PDST_OBJECT; break; case scData: case scSData: case scBss: case scSBss: case scRConst: case scRData: //Parameter is static var. Don't know what to do if (symbol.st == stParam) type = Symbol::PDST_OBJECT; else sym_use = false; break; default: sym_use = false; } break; case stTypedef: case stBase: //Base class case stTag: //C++ class, structure or union if (symbol.sc == scInfo) type = Symbol::PDST_OBJECT; else sym_use = false; break; case stFile: if (!sharedLibrary) { module = ldgetname(ldptr, &symbol); assert(module.length()); type = Symbol::PDST_MODULE; moduleEndIdx = symbol.index - 1; //Detect the compiler type by searching libgcc. if (strstr(module.c_str(), "libgcc")) GCC_COMPILED = true; } break; case stLabel: // For stLabel/scText combinations, if the symbol address falls // within the text section and has a valid name, process it as // a function. if (symbol.sc == scText && code_vldS_ <= (unsigned) symbol.value && (unsigned) symbol.value < code_vldE_ && name && *name && !fcnNames.defines(name)) { // Native C++ name demangling. // Keep this in sync with stProc case above. MLD_demangle_string(name, prettyName, 1024, MLD_SHOW_DEMANGLED_NAME | MLD_NO_SPACES); if (strchr(prettyName, '(')) *strchr(prettyName, '(') = 0; name = prettyName; type = Symbol::PDST_FUNCTION; fcnNames[name] = 1; } else { sym_use = false; } break; case stEnd: if (index == moduleEndIdx) module = "DEFAULT_MODULE"; sym_use = false; break; default: sym_use = false; } // Skip eCoff encoded stab string. Functions and global variable // addresses will still be found via the external symbols. if (P_strchr(name, ':')) sym_use = false; // cout << index << "\t" << name << "\t" << StName(symbol.st) << "\t" << ScName(symbol.sc) << "\t" << symbol.value << "\n"; index++; if (sym_use) { // cout << index << "\t" << module << "\t" << name << "\t" << type << "\t" << symbol.value << "\n"; allSymbols.push_back(Symbol(name, module, type, linkage, (Address) symbol.value, st_kludge)); } } //while VECTOR_SORT(allSymbols,symbol_compare); // find the function boundaries nsymbols = allSymbols.size(); //Insert global symbols for (unsigned u = 0; u < nsymbols; u++) { unsigned size = 0; if (allSymbols[u].type() == Symbol::PDST_FUNCTION) { unsigned v = u+1; while (v < nsymbols) { // The .ef below is a special symbol that gcc puts in to // mark the end of a function. if (allSymbols[v].addr() != allSymbols[u].addr() && (allSymbols[v].type() == Symbol::PDST_FUNCTION || allSymbols[v].name() == ".ef")) break; v++; } if (v < nsymbols) { size = (unsigned)allSymbols[v].addr() - (unsigned)allSymbols[u].addr(); } else { size = (unsigned)(code_off_+code_len_) - (unsigned)allSymbols[u].addr(); } } if (allSymbols[u].linkage() != Symbol::SL_LOCAL) { symbols_[allSymbols[u].name()].push_back( Symbol(allSymbols[u].name(), allSymbols[u].module(), allSymbols[u].type(), allSymbols[u].linkage(), allSymbols[u].addr(), allSymbols[u].kludge(), size) ); } } //Insert local symbols (Do we need this?) for (unsigned u = 0; u < nsymbols; u++) { if ( (allSymbols[u].linkage() == Symbol::SL_LOCAL) && (!symbols_.defines(allSymbols[u].name())) ) { symbols_[allSymbols[u].name()].push_back( Symbol(allSymbols[u].name(), allSymbols[u].module(), allSymbols[u].type(), allSymbols[u].linkage(), allSymbols[u].addr(), allSymbols[u].kludge(), 0) ); } } if (did_open && (ldclose(ldptr) == FAILURE)) { log_perror(err_func_, "close"); } free(file); }
/* * Move data. Apply sparse initialization to data in zeroed bss. */ int move_data(Rt_map *lmp, APlist **textrel) { Lm_list *lml = LIST(lmp); Move *mv = MOVETAB(lmp); ulong_t num, mvnum = MOVESZ(lmp) / MOVEENT(lmp); int moves; /* * If these records are against the executable, and the executable was * built prior to Solaris 8, keep track of the move record symbol. See * comment in analyze.c:lookup_sym_interpose() in regards Solaris 8 * objects and DT_FLAGS. */ moves = (lmp == lml->lm_head) && ((FLAGS1(lmp) & FL1_RT_DTFLAGS) == 0); DBG_CALL(Dbg_move_data(lmp)); for (num = 0; num < mvnum; num++, mv++) { mmapobj_result_t *mpp; Addr addr, taddr; Half rep, repno, stride; Sym *sym; if ((sym = (Sym *)SYMTAB(lmp) + ELF_M_SYM(mv->m_info)) == 0) continue; stride = mv->m_stride + 1; addr = sym->st_value; /* * Determine the move data target, and verify the address is * writable. */ if ((FLAGS(lmp) & FLG_RT_FIXED) == 0) addr += ADDR(lmp); taddr = addr + mv->m_poffset; if ((mpp = find_segment((caddr_t)taddr, lmp)) == NULL) { elf_move_bad(lml, lmp, sym, num, taddr); continue; } if (((mpp->mr_prot & PROT_WRITE) == 0) && ((set_prot(lmp, mpp, 1) == 0) || (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) return (0); DBG_CALL(Dbg_move_entry2(lml, mv, sym->st_name, (const char *)(sym->st_name + STRTAB(lmp)))); for (rep = 0, repno = 0; rep < mv->m_repeat; rep++) { DBG_CALL(Dbg_move_expand(lml, mv, taddr)); switch (ELF_M_SIZE(mv->m_info)) { case 1: *((char *)taddr) = (char)mv->m_value; taddr += stride; repno++; break; case 2: /* LINTED */ *((Half *)taddr) = (Half)mv->m_value; taddr += 2 * stride; repno++; break; case 4: /* LINTED */ *((Word *)taddr) = (Word)mv->m_value; taddr += 4 * stride; repno++; break; case 8: /* LINTED */ *((unsigned long long *)taddr) = mv->m_value; taddr += 8 * stride; repno++; break; default: eprintf(lml, ERR_NONE, MSG_INTL(MSG_MOVE_ERR1)); break; } } /* * If any move records have been applied to this symbol, retain * the symbol address if required for backward compatibility * copy relocation processing. */ if (moves && repno && (aplist_append(&alp, (void *)addr, AL_CNT_MOVES) == NULL)) return (0); } /* * Binaries built in the early 1990's prior to Solaris 8, using the ild * incremental linker are known to have zero filled move sections * (presumably place holders for new, incoming move sections). If no * move records have been processed, remove the move identifier to * optimize the amount of backward compatibility copy relocation * processing that is needed. */ if (moves && (alp == NULL)) FLAGS(lmp) &= ~FLG_RT_MOVE; return (1); }