diff options
author | Vladimir Mezentsev <vladimir.mezentsev@oracle.com> | 2022-03-11 08:58:31 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2022-03-11 08:58:31 +0000 |
commit | bb368aad297fe3ad40cf397e6fc85aa471429a28 (patch) | |
tree | 0ab25909b8fe789d676bbdb00d501d4d485e4afe /gprofng/src/LoadObject.cc | |
parent | a655f19af95eb685ba64f48ee8fc2b3b7a3d886a (diff) | |
download | binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.zip binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.gz binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.bz2 |
gprofng: a new GNU profiler
top-level
* Makefile.def: Add gprofng module.
* configure.ac: Add --enable-gprofng option.
* src-release.sh: Add gprofng.
* Makefile.in: Regenerate.
* configure: Regenerate.
* gprofng: New directory.
binutils
* MAINTAINERS: Add gprofng maintainer.
* README-how-to-make-a-release: Add gprofng.
include.
* collectorAPI.h: New file.
* libcollector.h: New file.
* libfcollector.h: New file.
Diffstat (limited to 'gprofng/src/LoadObject.cc')
-rw-r--r-- | gprofng/src/LoadObject.cc | 1242 |
1 files changed, 1242 insertions, 0 deletions
diff --git a/gprofng/src/LoadObject.cc b/gprofng/src/LoadObject.cc new file mode 100644 index 0000000..d9ce3e8 --- /dev/null +++ b/gprofng/src/LoadObject.cc @@ -0,0 +1,1242 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <errno.h> + +#include "util.h" +#include "StringBuilder.h" +#include "Application.h" +#include "DbeSession.h" +#include "Experiment.h" +#include "Exp_Layout.h" +#include "DataObject.h" +#include "Elf.h" +#include "Function.h" +#include "Module.h" +#include "ClassFile.h" +#include "Stabs.h" +#include "LoadObject.h" +#include "dbe_types.h" +#include "DbeFile.h" +#include "ExpGroup.h" + +enum +{ + LO_InstHTableSize = 4096, + HTableSize = 1024 +}; + +LoadObject * +LoadObject::create_item (const char *nm, int64_t chksum) +{ + LoadObject *lo = new LoadObject (nm); + lo->checksum = chksum; + dbeSession->append (lo); + return lo; +} + +LoadObject * +LoadObject::create_item (const char *nm, const char *_runTimePath, DbeFile *df) +{ + LoadObject *lo = new LoadObject (nm); + lo->runTimePath = dbe_strdup (_runTimePath); + lo->dbeFile->orig_location = dbe_strdup (_runTimePath); + if (df) + { + if ((df->filetype & DbeFile::F_JAR_FILE) != 0) + { + if (lo->dbeFile->find_in_jar_file (nm, df->get_jar_file ())) + { + lo->dbeFile->inArchive = df->inArchive; + lo->dbeFile->container = df; + } + } + else + { + lo->dbeFile->set_location (df->get_location ()); + lo->dbeFile->sbuf = df->sbuf; + lo->dbeFile->inArchive = df->inArchive; + } + } + dbeSession->append (lo); + return lo; +} + +LoadObject::LoadObject (const char *loname) +{ + flags = 0; + size = 0; + type = SEG_UNKNOWN; + isReadStabs = false; + need_swap_endian = false; + instHTable = new DbeInstr*[LO_InstHTableSize]; + for (int i = 0; i < LO_InstHTableSize; i++) + instHTable[i] = NULL; + + functions = new Vector<Function*>; + funcHTable = new Function*[HTableSize]; + for (int i = 0; i < HTableSize; i++) + funcHTable[i] = NULL; + + seg_modules = new Vector<Module*>; + modules = new HashMap<char*, Module*>; + platform = Unknown; + noname = dbeSession->createUnknownModule (this); + modules->put (noname->get_name (), noname); + pathname = NULL; + arch_name = NULL; + runTimePath = NULL; + objStabs = NULL; + firstExp = NULL; + seg_modules_map = NULL; + comp_funcs = NULL; + warnq = new Emsgqueue (NTXT ("lo_warnq")); + commentq = new Emsgqueue (NTXT ("lo_commentq")); + elf_lo = NULL; + elf_inited = false; + checksum = 0; + isUsed = false; + h_function = NULL; + h_instr = NULL; + + char *nm = (char *) loname; + if (strncmp (nm, NTXT ("./"), 2) == 0) + nm += 2; + set_name (nm); + dbeFile = new DbeFile (nm); + dbeFile->filetype |= DbeFile::F_LOADOBJ | DbeFile::F_FILE; +} + +LoadObject::~LoadObject () +{ + delete seg_modules_map; + delete functions; + delete[] instHTable; + delete[] funcHTable; + delete seg_modules; + delete modules; + delete elf_lo; + free (pathname); + free (arch_name); + free (runTimePath); + delete objStabs; + delete warnq; + delete commentq; + delete h_instr; +} + +Elf * +LoadObject::get_elf () +{ + if (elf_lo == NULL) + { + if (dbeFile->get_need_refind ()) + elf_inited = false; + if (elf_inited) + return NULL; + elf_inited = true; + char *fnm = dbeFile->get_location (); + if (fnm == NULL) + { + append_msg (CMSG_ERROR, GTXT ("Cannot find file: `%s'"), + dbeFile->get_name ()); + return NULL; + } + Elf::Elf_status st = Elf::ELF_ERR_CANT_OPEN_FILE; + elf_lo = Elf::elf_begin (fnm, &st); + if (elf_lo == NULL) + switch (st) + { + case Elf::ELF_ERR_CANT_OPEN_FILE: + append_msg (CMSG_ERROR, GTXT ("Cannot open ELF file `%s'"), fnm); + break; + case Elf::ELF_ERR_BAD_ELF_FORMAT: + default: + append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"), + fnm); + break; + } + } + return elf_lo; +} + +Stabs * +LoadObject::openDebugInfo (char *fname, Stabs::Stab_status *stp) +{ + if (objStabs == NULL) + { + if (fname == NULL) + return NULL; + objStabs = new Stabs (fname, get_pathname ()); + Stabs::Stab_status st = objStabs->get_status (); + if ((st == Stabs::DBGD_ERR_NONE) && (checksum != 0)) + { + Elf *elf = get_elf (); + if (elf && (checksum != elf->elf_checksum ())) + { + char *buf = dbe_sprintf (GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"), + fname); + commentq->append (new Emsg (CMSG_ERROR, buf)); + delete buf; + st = Stabs::DBGD_ERR_CHK_SUM; + } + } + if (stp) + *stp = st; + if (st != Stabs::DBGD_ERR_NONE) + { + delete objStabs; + objStabs = NULL; + } + } + return objStabs; +} + +uint64_t +LoadObject::get_addr () +{ + return MAKE_ADDRESS (seg_idx, 0); +} + +bool +LoadObject::compare (const char *_path, int64_t _checksum) +{ + return _checksum == checksum && dbe_strcmp (_path, get_pathname ()) == 0; +} + +int +LoadObject::compare (const char *_path, const char *_runTimePath, DbeFile *df) +{ + int ret = 0; + if (dbe_strcmp (_path, get_pathname ()) != 0) + return ret; + ret |= CMP_PATH; + if (_runTimePath) + { + if (dbe_strcmp (_runTimePath, runTimePath) != 0) + return ret; + ret |= CMP_RUNTIMEPATH; + } + if (df && dbeFile->compare (df)) + ret |= CMP_CHKSUM; + return ret; +} + +void +LoadObject::set_platform (Platform_t pltf, int wsz) +{ + switch (pltf) + { + case Sparc: + case Sparcv9: + case Sparcv8plus: + platform = (wsz == W64) ? Sparcv9 : Sparc; + break; + case Intel: + case Amd64: + platform = (wsz == W64) ? Amd64 : Intel; + break; + default: + platform = pltf; + break; + } +}; + +void +LoadObject::set_name (char *string) +{ + char *p; + pathname = dbe_strdup (string); + + p = get_basename (pathname); + if (p[0] == '<') + name = dbe_strdup (p); + else // set a short name to "<basename>" + name = dbe_sprintf (NTXT ("<%s>"), p); +} + +void +LoadObject::dump_functions (FILE *out) +{ + int index; + Function *fitem; + char *sname, *mname; + if (platform == Java) + { + JMethod *jmthd; + Vector<JMethod*> *jmethods = (Vector<JMethod*>*)functions; + Vec_loop (JMethod*, jmethods, index, jmthd) + { + fprintf (out, "id %6llu, @0x%llx sz-%lld %s (module = %s)\n", + (unsigned long long) jmthd->id, (long long) jmthd->get_mid (), + (long long) jmthd->size, jmthd->get_name (), + jmthd->module ? jmthd->module->file_name : noname->file_name); + } + } + else + { + Vec_loop (Function*, functions, index, fitem) + { + if (fitem->alias && fitem->alias != fitem) + fprintf (out, "id %6llu, @0x%llx - %s == alias of '%s'\n", + (ull_t) fitem->id, (ull_t) fitem->img_offset, + fitem->get_name (), fitem->alias->get_name ()); + else + { + mname = fitem->module ? fitem->module->file_name : noname->file_name; + sname = fitem->getDefSrcName (); + fprintf (out, + "id %6llu, @0x%llx - 0x%llx [save 0x%llx] o-%lld sz-%lld %s (module = %s)", + (ull_t) fitem->id, (ull_t) fitem->img_offset, + (ull_t) (fitem->img_offset + fitem->size), + (ull_t) fitem->save_addr, (ull_t) fitem->img_offset, + (ll_t) fitem->size, fitem->get_name (), mname); + if (sname && !streq (sname, mname)) + fprintf (out, " (Source = %s)", sname); + fprintf (out, "\n"); + } + } + } +} + +int +LoadObject::get_index (Function *func) +{ + Function *fp; + uint64_t offset; + int x; + int left = 0; + int right = functions->size () - 1; + offset = func->img_offset; + while (left <= right) + { + x = (left + right) / 2; + fp = functions->fetch (x); + + if (left == right) + { + if (offset >= fp->img_offset + fp->size) + return -1; + if (offset >= fp->img_offset) + return x; + return -1; + } + if (offset < fp->img_offset) + right = x - 1; + else if (offset >= fp->img_offset + fp->size) + left = x + 1; + else + return x; + } + return -1; +} + +char * +LoadObject::get_alias (Function *func) +{ + Function *fp, *alias; + int index, nsize; + static char buf[1024]; + if (func->img_offset == 0 || func->alias == NULL) + return NULL; + int fid = get_index (func); + if (fid == -1) + return NULL; + + nsize = functions->size (); + alias = func->alias; + for (index = fid; index < nsize; index++) + { + fp = functions->fetch (index); + if (fp->alias != alias) + { + fid = index; + break; + } + } + + *buf = '\0'; + for (index--; index >= 0; index--) + { + fp = functions->fetch (index); + if (fp->alias != alias) + break; + if (fp != alias) + { + size_t len = strlen (buf); + if (*buf != '\0') + { + snprintf (buf + len, sizeof (buf) - len, NTXT (", ")); + len = strlen (buf); + } + snprintf (buf + len, sizeof (buf) - len, "%s", fp->get_name ()); + } + } + return buf; +} + +DbeInstr* +LoadObject::find_dbeinstr (uint64_t file_off) +{ + int hash = (((int) file_off) >> 2) & (LO_InstHTableSize - 1); + DbeInstr *instr = instHTable[hash]; + if (instr && instr->img_offset == file_off) + return instr; + Function *fp = find_function (file_off); + if (fp == NULL) + fp = dbeSession->get_Unknown_Function (); + uint64_t func_off = file_off - fp->img_offset; + instr = fp->find_dbeinstr (0, func_off); + instHTable[hash] = instr; + return instr; +} + +Function * +LoadObject::find_function (uint64_t foff) +{ + // Look up in the hash table + int hash = (((int) foff) >> 6) & (HTableSize - 1); + Function *func = funcHTable[hash]; + if (func && foff >= func->img_offset && foff < func->img_offset + func->size) + return func->alias ? func->alias : func; + + // Use binary search + func = NULL; + int left = 0; + int right = functions->size () - 1; + while (left <= right) + { + int x = (left + right) / 2; + Function *fp = functions->fetch (x); + assert (fp != NULL); + + if (foff < fp->img_offset) + right = x - 1; + else if (foff >= fp->img_offset + fp->size) + left = x + 1; + else + { + func = fp; + break; + } + } + + // Plug the hole with a static function + char *func_name = NULL; + Size low_bound = 0, high_bound = 0; + if (func == NULL) + { + int last = functions->size () - 1; + uint64_t usize = (uint64_t) size; + if (foff >= usize) + { + // Cannot map to this LoadObject. Probably LoadObject was changed. + if (last >= 0 && functions->fetch (last)->img_offset == usize) + { + // Function is already created + func = functions->fetch (last); + if (func->size < 0 || (uint64_t) func->size < foff - usize) + func->size = foff - usize; + } + else + { + low_bound = size; + high_bound = foff; + func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"), + low_bound, name); + } + } + else if (last < 0) + { + low_bound = 0; + high_bound = size; + func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) -- no functions found"), + low_bound, name); + } + else if (foff < functions->fetch (0)->img_offset) + { + low_bound = 0; + high_bound = functions->fetch (0)->img_offset; + } + else + { + Function *fp = functions->fetch (last); + if (foff >= fp->img_offset + fp->size) + { + low_bound = fp->img_offset + fp->size; + high_bound = size; + } + else + { + fp = functions->fetch (left); + if (foff >= fp->img_offset + fp->size) + { + low_bound = fp->img_offset + fp->size; + high_bound = functions->fetch (left + 1)->img_offset; + } + else + { + Function *fp1 = functions->fetch (left - 1); + low_bound = fp1->img_offset + fp1->size; + high_bound = fp->img_offset; + } + } + } + } + + if (func == NULL) + { + func = dbeSession->createFunction (); + func->size = (unsigned) (high_bound - low_bound); + func->module = noname; + func->img_fname = get_pathname (); + func->img_offset = (off_t) low_bound; + noname->functions->append (func); // unordered + if (func_name == NULL) + func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"), low_bound, + name); + func->set_name (func_name); + free (func_name); + + // now insert the function + functions->insert (left, func); + } + + // Update the hash table + funcHTable[hash] = func; + return func->alias ? func->alias : func; +} + +static void +fixFuncAlias (Vector<Function*> *SymLst) +{ + int ind, i, k; + int64_t len, bestLen, maxSize; + Function *sym, *bestAlias; + + // XXXX it is a clone of Stabs::fixSymtabAlias() + ind = SymLst->size () - 1; + for (i = 0; i < ind; i++) + { + bestAlias = SymLst->fetch (i); + if (bestAlias->img_offset == 0) // Ignore this bad symbol + continue; + sym = SymLst->fetch (i + 1); + if (bestAlias->img_offset != sym->img_offset) + { + if (bestAlias->size == 0 + || sym->img_offset < bestAlias->img_offset + bestAlias->size) + bestAlias->size = (int) (sym->img_offset - bestAlias->img_offset); + continue; + } + + // Find a "best" alias + bestLen = strlen (bestAlias->get_name ()); + maxSize = bestAlias->size; + for (k = i + 1; k <= ind; k++) + { + sym = SymLst->fetch (k); + if (bestAlias->img_offset != sym->img_offset) + { // no more aliases + if ((maxSize == 0) || + (sym->img_offset < bestAlias->img_offset + maxSize)) + maxSize = sym->img_offset - bestAlias->img_offset; + break; + } + if (maxSize < sym->size) + maxSize = sym->size; + len = strlen (sym->get_name ()); + if (len < bestLen) + { + bestAlias = sym; + bestLen = len; + } + } + for (; i < k; i++) + { + sym = SymLst->fetch (i); + sym->alias = bestAlias; + sym->size = maxSize; + } + i--; + } +} + +void +LoadObject::post_process_functions () +{ + if (flags & SEG_FLAG_DYNAMIC || platform == Java) + return; + + char *msg = GTXT ("Processing Load Object Data"); + if (dbeSession->is_interactive ()) + theApplication->set_progress (1, msg); + + // First sort the functions + functions->sort (func_compare); + fixFuncAlias (functions); + + Module *mitem; + int index; + Vec_loop (Module*, seg_modules, index, mitem) + { + mitem->functions->sort (func_compare); + } + + // Find any derived functions, and set their derivedNode + Function *fitem; + Vec_loop (Function*, functions, index, fitem) + { + if (dbeSession->is_interactive () && index % 5000 == 0) + { + int percent = (int) (100.0 * index / functions->size ()); + theApplication->set_progress (percent, (percent != 0) ? NULL : msg); + } + fitem->findDerivedFunctions (); + } + + // 4987698: get the alias name for MAIN_ + fitem = find_function (NTXT ("MAIN_")); + if (fitem) + fitem->module->read_stabs (); + fitem = find_function (NTXT ("@plt")); + if (fitem) + fitem->flags |= FUNC_FLAG_PLT; + if (dbeSession->is_interactive ()) + theApplication->set_progress (0, NTXT ("")); +} + +int +LoadObject::func_compare (const void *p1, const void *p2) +{ + Function *f1 = *(Function **) p1; + Function *f2 = *(Function **) p2; + if (f1->img_offset != f2->img_offset) + return f1->img_offset > f2->img_offset ? 1 : -1; + + // annotated source not available for weak symbols. + if ((f1->module->flags & MOD_FLAG_UNKNOWN) != 0) + { + if ((f2->module->flags & MOD_FLAG_UNKNOWN) == 0) + return -1; + } + else if ((f2->module->flags & MOD_FLAG_UNKNOWN) != 0) + return 1; + return strcoll (f1->get_name (), f2->get_name ()); +} + +Function * +LoadObject::find_function (char *fname) +{ + Function *fitem; + int index; + Vec_loop (Function*, functions, index, fitem) + { + if (strcmp (fitem->get_name (), fname) == 0) + return fitem; + } + return (Function *) NULL; +} + +Function * +LoadObject::find_function (char *fname, unsigned int chksum) +{ + Function *fitem; + int index; + Vec_loop (Function*, functions, index, fitem) + { + if (fitem->chksum == chksum && strcmp (fitem->get_name (), fname) == 0) + return fitem; + } + return (Function *) NULL; +} + +Module * +LoadObject::find_module (char *mname) +{ + for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++) + { + Module *module = seg_modules->fetch (i); + if (strcmp (module->get_name (), mname) == 0) + return module; + } + return (Module *) NULL; +} + +LoadObject::Arch_status +LoadObject::sync_read_stabs () +{ + Arch_status st = ARCHIVE_SUCCESS; + if (!isReadStabs) + { + aquireLock (); + if (!isReadStabs) + { + st = read_stabs (); + post_process_functions (); + isReadStabs = true; + } + releaseLock (); + } + return st; +} + +LoadObject::Arch_status +LoadObject::read_stabs () +{ + if ((dbeFile->filetype & DbeFile::F_FICTION) != 0) + return ARCHIVE_SUCCESS; + Arch_status stabs_status = ARCHIVE_ERR_OPEN; + if (platform == Java) + { + Module *cf = NULL; + for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++) + { + Module *mod = seg_modules->fetch (i); + if (mod->dbeFile + && (mod->dbeFile->filetype & DbeFile::F_JAVACLASS) != 0) + { + cf = mod; + break; + } + } + if (cf) + { + int status = cf->readFile (); + switch (status) + { + case Module::AE_OK: + stabs_status = ARCHIVE_SUCCESS; + break; + case Module::AE_NOSTABS: + stabs_status = ARCHIVE_NO_STABS; + break; + case Module::AE_NOTREAD: + default: + stabs_status = ARCHIVE_ERR_OPEN; + break; + } + } + } + else if (strchr (pathname, '`')) + return ARCHIVE_SUCCESS; + else + { + Arch_status st = ARCHIVE_WRONG_ARCH; + Elf *elf = get_elf (); + if (elf == NULL) + { + if (read_archive () == 0) + st = ARCHIVE_SUCCESS; + else + { + char *msg = dbe_sprintf (GTXT ("*** Warning: Can't open file: %s"), + dbeFile->get_name ()); + warnq->append (new Emsg (CMSG_ERROR, msg)); + delete msg; + } + } + else if (checksum != 0 && checksum != elf->elf_checksum ()) + { + if (read_archive () == 0) + st = ARCHIVE_SUCCESS; + else + { + char *msg = dbe_sprintf ( + GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"), + dbeFile->get_location ()); + commentq->append (new Emsg (CMSG_ERROR, msg)); + delete msg; + } + } + if (st == ARCHIVE_SUCCESS) // An old archive is used + return st; + + Stabs::Stab_status status = Stabs::DBGD_ERR_CANT_OPEN_FILE; + char *location = dbeFile->get_location (true); + if (location == NULL) + return ARCHIVE_ERR_OPEN; + + if (openDebugInfo (location, &status)) + { + status = objStabs->read_archive (this); + isRelocatable = objStabs->is_relocatable (); + size = objStabs->get_textsz (); + platform = objStabs->get_platform (); + wsize = objStabs->get_class (); + } + + switch (status) + { + case Stabs::DBGD_ERR_NONE: + stabs_status = ARCHIVE_SUCCESS; + break; + case Stabs::DBGD_ERR_CANT_OPEN_FILE: + stabs_status = ARCHIVE_ERR_OPEN; + break; + case Stabs::DBGD_ERR_BAD_ELF_LIB: + case Stabs::DBGD_ERR_BAD_ELF_FORMAT: + stabs_status = ARCHIVE_BAD_STABS; + break; + case Stabs::DBGD_ERR_NO_STABS: + stabs_status = ARCHIVE_NO_STABS; + break; + case Stabs::DBGD_ERR_NO_DWARF: + stabs_status = ARCHIVE_NO_DWARF; + break; + default: + stabs_status = ARCHIVE_BAD_STABS; + break; + } + } + return stabs_status; +} + +#define ARCH_STRLEN(s) ((strlen(s) + 4) & ~0x3 ) + +static int +offsetCmp (const void *a, const void *b) +{ + uint32_t o1 = ((inst_info_t *) a)->offset; + uint32_t o2 = ((inst_info_t *) b)->offset; + return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1); +} + +int +LoadObject::read_archive () +{ + if (arch_name == NULL) + return 1; + Module *mod = NULL; + Function *func = NULL; + char *buf; + Data_window *dwin = new Data_window (arch_name); + if (dwin->not_opened ()) + { + delete dwin; + buf = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s: %s"), + arch_name, strerror (errno)); + warnq->append (new Emsg (CMSG_ERROR, buf)); + delete buf; + return 1; + } + dwin->need_swap_endian = need_swap_endian; + + // Prevent reading earlier archive files, which didn't support versioning. + int64_t offset = 0; + ARCH_common *cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common)); + uint16_t v16; + if (cpkt) + { + v16 = (uint16_t) cpkt->type; + if (dwin->decode (v16) != ARCH_SEGMENT) + cpkt = NULL; + } + if (cpkt == NULL) + { + buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name); + warnq->append (new Emsg (CMSG_WARN, buf)); + delete buf; + return 1; + } + + char *msg = NULL; + unsigned long long pointer_invalid = 0; + for (int64_t last_offset = -5000;;) + { + cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common)); + if (cpkt == NULL) + break; + v16 = (uint16_t) cpkt->size; + uint32_t cpktsize = dwin->decode (v16); + cpkt = (ARCH_common*) dwin->bind (offset, cpktsize); + if ((cpkt == NULL) || (cpktsize == 0)) + { + buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name); + warnq->append (new Emsg (CMSG_WARN, buf)); + delete buf; + break; + } + + // Update the progress bar + if (dbeSession->is_interactive () && ((offset - last_offset) >= 5000)) + { + last_offset = offset; + int percent = (int) (100.0 * offset / dwin->get_fsize ()); + if (msg == NULL) + msg = dbe_sprintf (GTXT ("Reading Load Object Data: %s"), name); + theApplication->set_progress (percent, (percent != 0) ? NULL : msg); + } + char *ptr = (char *) cpkt; + v16 = (uint16_t) cpkt->type; + switch (dwin->decode (v16)) + { + case ARCH_SEGMENT: + { + ARCH_segment *aseg = (ARCH_segment*) cpkt; + if (dwin->decode (aseg->version) != ARCH_VERSION) + { + buf = dbe_sprintf (GTXT ("Archive file version mismatch for %s"), arch_name); + warnq->append (new Emsg (CMSG_ERROR, buf)); + delete buf; + if (dbeSession->is_interactive ()) + theApplication->set_progress (0, ""); + return 1; + } + if (size == 0) + size = dwin->decode (aseg->textsz); + Platform_t pltf = (Platform_t) dwin->decode (aseg->platform); + if (pltf != Unknown) + { + platform = pltf; // override if known + wsize = (platform == Sparcv9 || platform == Amd64) ? W64 : W32; + } + break; + } + case ARCH_MSG: + { + ARCH_message *amsg = (ARCH_message*) cpkt; + buf = status_str ((Arch_status) dwin->decode (amsg->errcode)); + commentq->append (new Emsg (CMSG_ARCHIVE, buf)); + free (buf); + break; + } + case ARCH_INF: + { + ARCH_info *ainf = (ARCH_info*) cpkt; + Emsg *m = new Emsg (CMSG_ARCHIVE, (char*) (ainf + 1)); + commentq->append (m); + break; + } + case ARCH_MODULE: + { + ARCH_module *amod = (ARCH_module*) cpkt; + char *str = ((char*) amod) + sizeof (ARCH_module); + if (streq (str, SP_UNKNOWN_NAME) && + streq (str + ARCH_STRLEN (str), SP_UNKNOWN_NAME)) + { + mod = noname; + break; + } + mod = dbeSession->createModule (this, str); + mod->lang_code = (Sp_lang_code) dwin->decode (amod->lang_code); + mod->fragmented = dwin->decode (amod->fragmented); + str += ARCH_STRLEN (str); + mod->set_file_name (dbe_strdup (str)); + modules->put (get_basename (str), mod); + break; + } + case ARCH_FUNCTION: + { + if (mod == NULL) + break; + ARCH_function *afnc = (ARCH_function*) cpkt; + func = dbeSession->createFunction (); + func->img_offset = dwin->decode (afnc->offset); + func->size = dwin->decode (afnc->size); + func->save_addr = dwin->decode (afnc->save_addr) + - dwin->decode (afnc->offset); + func->module = mod; + func->set_name (((char*) afnc) + sizeof (ARCH_function)); + mod->functions->append (func); + functions->append (func); + break; + } + case ARCH_LDINSTR: + if (mod == NULL) + break; + Dprintf (DEBUG_LOADOBJ, "LDINSTR list for %s\n", mod->get_name ()); + if (mod->infoList == NULL) + mod->infoList = new Vector<inst_info_t*>; + for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo)); + (char*) mp < ptr + cpktsize; mp++) + { + memop_info_t *memop = new memop_info_t; + memop->offset = dwin->decode (mp->offset); + memop->id = dwin->decode (mp->id); + memop->signature = dwin->decode (mp->signature); + memop->datatype_id = dwin->decode (mp->datatype_id); + mod->ldMemops.append (memop); + + inst_info_t *instop = new inst_info_t; + instop->type = CPF_INSTR_TYPE_LD; + instop->offset = memop->offset; + instop->memop = memop; + mod->infoList->incorporate (instop, offsetCmp); + Dprintf (DEBUG_LOADOBJ, + "ld: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n", + memop->offset, memop->id, memop->signature, + memop->datatype_id); + } + Dprintf (DEBUG_LOADOBJ, "LDINSTR list of %lld for %s\n", + (long long) mod->ldMemops.size (), mod->get_name ()); + break; + case ARCH_STINSTR: + if (mod == NULL) + break; + Dprintf (DEBUG_LOADOBJ, NTXT ("STINSTR list for %s\n"), mod->get_name ()); + if (mod->infoList == NULL) + mod->infoList = new Vector<inst_info_t*>; + for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo)); + ((char *) mp) < ptr + cpktsize; mp++) + { + memop_info_t *memop = new memop_info_t; + memop->offset = dwin->decode (mp->offset); + memop->id = dwin->decode (mp->id); + memop->signature = dwin->decode (mp->signature); + memop->datatype_id = dwin->decode (mp->datatype_id); + mod->stMemops.append (memop); + + inst_info_t *instop = new inst_info_t; + instop->type = CPF_INSTR_TYPE_ST; + instop->offset = memop->offset; + instop->memop = memop; + mod->infoList->incorporate (instop, offsetCmp); + Dprintf (DEBUG_LOADOBJ, + "st: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n", + memop->offset, memop->id, memop->signature, + memop->datatype_id); + } + Dprintf (DEBUG_LOADOBJ, "STINSTR list of %lld for %s\n", + (long long) mod->stMemops.size (), mod->get_name ()); + break; + case ARCH_PREFETCH: + if (mod == NULL) + break; + Dprintf (DEBUG_LOADOBJ, "PFINSTR list for %s\n", mod->get_name ()); + if (mod->infoList == NULL) + mod->infoList = new Vector<inst_info_t*>; + for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo)); + ((char*) mp) < ptr + cpkt->size; mp++) + { + memop_info_t *memop = new memop_info_t; + memop->offset = dwin->decode (mp->offset); + memop->id = dwin->decode (mp->id); + memop->signature = dwin->decode (mp->signature); + memop->datatype_id = dwin->decode (mp->datatype_id); + mod->pfMemops.append (memop); + + inst_info_t *instop = new inst_info_t; + instop->type = CPF_INSTR_TYPE_PREFETCH; + instop->offset = memop->offset; + instop->memop = memop; + mod->infoList->incorporate (instop, offsetCmp); + Dprintf (DEBUG_LOADOBJ, + "pf: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n", + memop->offset, memop->id, memop->signature, + memop->datatype_id); + } + Dprintf (DEBUG_LOADOBJ, "PFINSTR list of %lld for %s\n", + (long long) mod->pfMemops.size (), mod->get_name ()); + break; + case ARCH_BRTARGET: + if (mod == NULL) + break; + for (target_info_t *tp = (target_info_t*) (ptr + sizeof (ARCH_aninfo)); + ((char*) tp) < ptr + cpkt->size; tp++) + { + target_info_t *bTarget = new target_info_t; + bTarget->offset = dwin->decode (tp->offset); + mod->bTargets.append (bTarget); + } + Dprintf (DEBUG_LOADOBJ, "BRTARGET list of %lld for %s\n", + (long long) mod->infoList->size (), mod->get_name ()); + break; + default: + /* Check if the prointer is valid - should be even. */ + pointer_invalid = (unsigned long long) (offset + cpktsize) & 1; + break; // ignore unknown packets + } + if (pointer_invalid) + break; + offset += cpktsize; + } + delete msg; + delete dwin; + + if (dbeSession->is_interactive ()) + theApplication->set_progress (0, NTXT ("")); + return 0; +} + +char * +LoadObject::status_str (Arch_status rv, char */*arg*/) +{ + switch (rv) + { + case ARCHIVE_SUCCESS: + case ARCHIVE_EXIST: + return NULL; + case ARCHIVE_BAD_STABS: + return dbe_sprintf (GTXT ("Error: unable to read symbol table of %s"), + name); + case ARCHIVE_ERR_SEG: + return dbe_sprintf (GTXT ("Error: unable to read load object file %s"), + pathname); + case ARCHIVE_ERR_OPEN: + return dbe_sprintf (GTXT ("Error: unable to open file %s"), + pathname); + case ARCHIVE_ERR_MAP: + return dbe_sprintf (GTXT ("Error: unable to map file %s"), + pathname); + case ARCHIVE_WARN_CHECKSUM: + return dbe_sprintf (GTXT ("Note: checksum differs from that recorded in experiment for %s"), + name); + case ARCHIVE_WARN_MTIME: + return dbe_sprintf (GTXT ("Warning: last-modified time differs from that recorded in experiment for %s"), + name); + case ARCHIVE_WARN_HOST: + return dbe_sprintf (GTXT ("Try running er_archive -F on the experiment, on the host where it was recorded")); + case ARCHIVE_ERR_VERSION: + return dbe_sprintf (GTXT ("Error: Wrong version of archive for %s"), + pathname); + case ARCHIVE_NO_STABS: + return dbe_sprintf (GTXT ("Note: no stabs or dwarf information in %s"), + name); + case ARCHIVE_WRONG_ARCH: +#if ARCH(SPARC) + return dbe_sprintf (GTXT ("Error: file %s is built for Intel, and can't be read on SPARC"), + name); +#else + return dbe_sprintf (GTXT ("Error: file %s is built for SPARC, and can't be read on Intel"), + name); +#endif + case ARCHIVE_NO_LIBDWARF: + return dbe_strdup (GTXT ("Warning: no libdwarf found to read DWARF symbol tables")); + case ARCHIVE_NO_DWARF: + return dbe_sprintf (GTXT ("Note: no DWARF symbol table in %s"), name); + default: + return dbe_sprintf (GTXT ("Warning: unexpected archive error %d"), + (int) rv); + } +} + +uint32_t +LoadObject::get_checksum () +{ + char *errmsg = NULL; + uint32_t crcval = get_cksum (pathname, &errmsg); + if (0 == crcval && errmsg) + { + warnq->append (new Emsg (CMSG_ERROR, errmsg)); + free (errmsg); + } + return crcval; +} + +static char* +get_module_map_key (Module *mod) +{ + return mod->lang_code == Sp_lang_java ? mod->get_name () : mod->file_name; +} + +Module * +LoadObject::get_comparable_Module (Module *mod) +{ + if (mod->loadobject == this) + return mod; + if (get_module_map_key (mod) == NULL) + return NULL; + if (seg_modules_map == NULL) + { + seg_modules_map = new HashMap<char*, Module*>; + for (int i = 0; i < seg_modules->size (); i++) + { + Module *m = seg_modules->fetch (i); + char *key = get_module_map_key (m); + if (key) + { + seg_modules_map->put (m->file_name, m); + char *bname = get_basename (key); + if (bname != key) + seg_modules_map->put (bname, m); + } + } + } + + char *key = get_module_map_key (mod); + Module *cmpMod = seg_modules_map->get (key); + if (cmpMod && cmpMod->comparable_objs == NULL) + return cmpMod; + char *bname = get_basename (key); + if (bname != key) + { + cmpMod = seg_modules_map->get (bname); + if (cmpMod && cmpMod->comparable_objs == NULL) + return cmpMod; + } + return NULL; +} + +Vector<Histable*> * +LoadObject::get_comparable_objs () +{ + update_comparable_objs (); + if (comparable_objs || dbeSession->expGroups->size () <= 1) + return comparable_objs; + comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ()); + for (int i = 0, sz = dbeSession->expGroups->size (); i < sz; i++) + { + ExpGroup *gr = dbeSession->expGroups->fetch (i); + Histable *h = gr->get_comparable_loadObject (this); + comparable_objs->append (h); + if (h) + h->comparable_objs = comparable_objs; + } + dump_comparable_objs (); + return comparable_objs; +} + +void +LoadObject::append_module (Module *mod) +{ + seg_modules->append (mod); + if (seg_modules_map == NULL) + seg_modules_map = new HashMap<char*, Module*>; + char *key = get_module_map_key (mod); + if (key) + { + seg_modules_map->put (key, mod); + char *bname = get_basename (key); + if (bname != key) + seg_modules_map->put (bname, mod); + } +} + +// LIBRARY_VISIBILITY +Function * +LoadObject::get_hide_function () +{ + if (h_function == NULL) + h_function = dbeSession->create_hide_function (this); + return h_function; +} + +DbeInstr * +LoadObject::get_hide_instr (DbeInstr *instr) +{ + if (h_instr == NULL) + { + Function *hf = get_hide_function (); + h_instr = hf->create_hide_instr (instr); + } + return h_instr; +} |