int ldsize(dev_t dev) { struct ld_softc *sc; int part, unit, omask, size; unit = DISKUNIT(dev); if ((sc = device_lookup(&ld_cd, unit)) == NULL) return (ENODEV); if ((sc->sc_flags & LDF_ENABLED) == 0) return (ENODEV); part = DISKPART(dev); omask = sc->sc_dk.dk_openmask & (1 << part); if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0) return (-1); else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; else size = sc->sc_dk.dk_label->d_partitions[part].p_size * (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0) return (-1); return (size); }
/* * Build the export table from the XCOFF .loader section. */ static int readExports(ModulePtr mp) { LDFILE *ldp = NULL; SCNHDR sh, shdata; LDHDR *lhp; char *ldbuf; LDSYM *ls; int i; ExportPtr ep; if ((ldp = ldopen(mp->name, ldp)) == NULL) { struct ld_info *lp; char *buf; int size = 4*1024; if (errno != ENOENT) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } /* * The module might be loaded due to the LIBPATH * environment variable. Search for the loaded * module using L_GETINFO. */ if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) { free(buf); size += 4*1024; if ((buf = malloc(size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } } if (i == -1) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); free(buf); return -1; } /* * Traverse the list of loaded modules. The entry point * returned by load() does actually point to the data * segment origin. */ lp = (struct ld_info *)buf; while (lp) { if (lp->ldinfo_dataorg == mp->entry) { ldp = ldopen(lp->ldinfo_filename, ldp); break; } if (lp->ldinfo_next == 0) lp = NULL; else lp = (struct ld_info *)((char *)lp + lp->ldinfo_next); } free(buf); if (!ldp) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); return -1; } } if (TYPE(ldp) != U802TOCMAGIC) { errvalid++; strcpy(errbuf, "readExports: bad magic"); while(ldclose(ldp) == FAILURE) ; return -1; } /* * Get the padding for the data section. This is needed for * AIX 4.1 compilers. This is used when building the final * function pointer to the exported symbol. */ if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) { errvalid++; strcpy(errbuf, "readExports: cannot read data section header"); while(ldclose(ldp) == FAILURE) ; return -1; } if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) { errvalid++; strcpy(errbuf, "readExports: cannot read loader section header"); while(ldclose(ldp) == FAILURE) ; return -1; } /* * We read the complete loader section in one chunk, this makes * finding long symbol names residing in the string table easier. */ if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); while(ldclose(ldp) == FAILURE) ; return -1; } if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) { errvalid++; strcpy(errbuf, "readExports: cannot seek to loader section"); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) { errvalid++; strcpy(errbuf, "readExports: cannot read loader section"); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } lhp = (LDHDR *)ldbuf; ls = (LDSYM *)(ldbuf+LDHDRSZ); /* * Count the number of exports to include in our export table. */ for (i = lhp->l_nsyms; i; i--, ls++) { if (!LDR_EXPORT(*ls)) continue; mp->nExports++; } if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) { errvalid++; strcpy(errbuf, "readExports: "); strcat(errbuf, strerror(errno)); free(ldbuf); while(ldclose(ldp) == FAILURE) ; return -1; } /* * Fill in the export table. All entries are relative to * the entry point we got from load. */ ep = mp->exports; ls = (LDSYM *)(ldbuf+LDHDRSZ); for (i = lhp->l_nsyms; i; i--, ls++) { char *symname; char tmpsym[SYMNMLEN+1]; if (!LDR_EXPORT(*ls)) continue; if (ls->l_zeroes == 0) symname = ls->l_offset+lhp->l_stoff+ldbuf; else { /* * The l_name member is not zero terminated, we * must copy the first SYMNMLEN chars and make * sure we have a zero byte at the end. */ strncpy(tmpsym, ls->l_name, SYMNMLEN); tmpsym[SYMNMLEN] = '\0'; symname = tmpsym; } ep->name = malloc((unsigned) (strlen(symname) + 1)); strcpy(ep->name, symname); ep->addr = (void *)((unsigned long)mp->entry + ls->l_value - shdata.s_vaddr); ep++; } free(ldbuf); while(ldclose(ldp) == FAILURE) ; return 0; }
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); }